aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/PhysXVehicle
diff options
context:
space:
mode:
Diffstat (limited to 'PhysX_3.4/Source/PhysXVehicle')
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleAutoGeneratedMetaDataObjectNames.h231
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleAutoGeneratedMetaDataObjects.h1797
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleMetaDataObjects.h86
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/src/PxVehicleAutoGeneratedMetaDataObjects.cpp728
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/src/PxVehicleMetaDataObjects.cpp86
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleComponents.cpp222
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDefaults.h46
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDrive.cpp213
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDrive4W.cpp152
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDriveNW.cpp149
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDriveTank.cpp120
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleLinearMath.h433
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleMetaData.cpp540
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleNoDrive.cpp157
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSDK.cpp115
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSerialization.cpp203
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSerialization.h65
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspLimitConstraintShader.h305
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspWheelTire4.cpp191
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspWheelTire4.h393
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleTireFriction.cpp132
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleUpdate.cpp7641
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/PxVehicleWheels.cpp857
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilControl.cpp474
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilSetup.cpp246
-rw-r--r--PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilTelemetry.cpp577
26 files changed, 16159 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleAutoGeneratedMetaDataObjectNames.h b/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleAutoGeneratedMetaDataObjectNames.h
new file mode 100644
index 00000000..1c10d133
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleAutoGeneratedMetaDataObjectNames.h
@@ -0,0 +1,231 @@
+// 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.
+
+// This code is auto-generated by the PhysX Clang metadata generator. Do not edit or be
+// prepared for your edits to be quietly ignored next time the clang metadata generator is
+// run. You can find the most recent version of clang metadata generator by contacting
+// Chris Nuernberger <[email protected]> or Dilip or Adam.
+// The source code for the generate was at one time checked into:
+// physx/PhysXMetaDataGenerator/llvm/tools/clang/lib/Frontend/PhysXMetaDataAction.cpp
+#define THERE_IS_NO_INCLUDE_GUARD_HERE_FOR_A_REASON
+
+PxVehicleChassisData_PropertiesStart,
+PxVehicleChassisData_MMOI,
+PxVehicleChassisData_MMass,
+PxVehicleChassisData_MCMOffset,
+PxVehicleChassisData_PropertiesStop,
+PxVehicleEngineData_PropertiesStart,
+PxVehicleEngineData_RecipMOI,
+PxVehicleEngineData_RecipMaxOmega,
+PxVehicleEngineData_MTorqueCurve,
+PxVehicleEngineData_MMOI,
+PxVehicleEngineData_MPeakTorque,
+PxVehicleEngineData_MMaxOmega,
+PxVehicleEngineData_MDampingRateFullThrottle,
+PxVehicleEngineData_MDampingRateZeroThrottleClutchEngaged,
+PxVehicleEngineData_MDampingRateZeroThrottleClutchDisengaged,
+PxVehicleEngineData_PropertiesStop,
+PxVehicleGearsData_PropertiesStart,
+PxVehicleGearsData_GearRatio,
+PxVehicleGearsData_MFinalRatio,
+PxVehicleGearsData_MNbRatios,
+PxVehicleGearsData_MSwitchTime,
+PxVehicleGearsData_PropertiesStop,
+PxVehicleAutoBoxData_PropertiesStart,
+PxVehicleAutoBoxData_Latency,
+PxVehicleAutoBoxData_UpRatios,
+PxVehicleAutoBoxData_DownRatios,
+PxVehicleAutoBoxData_PropertiesStop,
+PxVehicleDifferential4WData_PropertiesStart,
+PxVehicleDifferential4WData_MFrontRearSplit,
+PxVehicleDifferential4WData_MFrontLeftRightSplit,
+PxVehicleDifferential4WData_MRearLeftRightSplit,
+PxVehicleDifferential4WData_MCentreBias,
+PxVehicleDifferential4WData_MFrontBias,
+PxVehicleDifferential4WData_MRearBias,
+PxVehicleDifferential4WData_MType,
+PxVehicleDifferential4WData_PropertiesStop,
+PxVehicleDifferentialNWData_PropertiesStart,
+PxVehicleDifferentialNWData_DrivenWheelStatus,
+PxVehicleDifferentialNWData_PropertiesStop,
+PxVehicleAckermannGeometryData_PropertiesStart,
+PxVehicleAckermannGeometryData_MAccuracy,
+PxVehicleAckermannGeometryData_MFrontWidth,
+PxVehicleAckermannGeometryData_MRearWidth,
+PxVehicleAckermannGeometryData_MAxleSeparation,
+PxVehicleAckermannGeometryData_PropertiesStop,
+PxVehicleClutchData_PropertiesStart,
+PxVehicleClutchData_MStrength,
+PxVehicleClutchData_MAccuracyMode,
+PxVehicleClutchData_MEstimateIterations,
+PxVehicleClutchData_PropertiesStop,
+PxVehicleTireLoadFilterData_PropertiesStart,
+PxVehicleTireLoadFilterData_Denominator,
+PxVehicleTireLoadFilterData_MMinNormalisedLoad,
+PxVehicleTireLoadFilterData_MMinFilteredNormalisedLoad,
+PxVehicleTireLoadFilterData_MMaxNormalisedLoad,
+PxVehicleTireLoadFilterData_MMaxFilteredNormalisedLoad,
+PxVehicleTireLoadFilterData_PropertiesStop,
+PxVehicleWheelData_PropertiesStart,
+PxVehicleWheelData_RecipRadius,
+PxVehicleWheelData_RecipMOI,
+PxVehicleWheelData_MRadius,
+PxVehicleWheelData_MWidth,
+PxVehicleWheelData_MMass,
+PxVehicleWheelData_MMOI,
+PxVehicleWheelData_MDampingRate,
+PxVehicleWheelData_MMaxBrakeTorque,
+PxVehicleWheelData_MMaxHandBrakeTorque,
+PxVehicleWheelData_MMaxSteer,
+PxVehicleWheelData_MToeAngle,
+PxVehicleWheelData_PropertiesStop,
+PxVehicleSuspensionData_PropertiesStart,
+PxVehicleSuspensionData_RecipMaxCompression,
+PxVehicleSuspensionData_RecipMaxDroop,
+PxVehicleSuspensionData_MassAndPreserveNaturalFrequency,
+PxVehicleSuspensionData_MSpringStrength,
+PxVehicleSuspensionData_MSpringDamperRate,
+PxVehicleSuspensionData_MMaxCompression,
+PxVehicleSuspensionData_MMaxDroop,
+PxVehicleSuspensionData_MSprungMass,
+PxVehicleSuspensionData_MCamberAtRest,
+PxVehicleSuspensionData_MCamberAtMaxCompression,
+PxVehicleSuspensionData_MCamberAtMaxDroop,
+PxVehicleSuspensionData_PropertiesStop,
+PxVehicleAntiRollBarData_PropertiesStart,
+PxVehicleAntiRollBarData_MWheel0,
+PxVehicleAntiRollBarData_MWheel1,
+PxVehicleAntiRollBarData_MStiffness,
+PxVehicleAntiRollBarData_PropertiesStop,
+PxVehicleTireData_PropertiesStart,
+PxVehicleTireData_RecipLongitudinalStiffnessPerUnitGravity,
+PxVehicleTireData_FrictionVsSlipGraphRecipx1Minusx0,
+PxVehicleTireData_FrictionVsSlipGraphRecipx2Minusx1,
+PxVehicleTireData_MLatStiffX,
+PxVehicleTireData_MLatStiffY,
+PxVehicleTireData_MLongitudinalStiffnessPerUnitGravity,
+PxVehicleTireData_MCamberStiffnessPerUnitGravity,
+PxVehicleTireData_MType,
+PxVehicleTireData_MFrictionVsSlipGraph,
+PxVehicleTireData_PropertiesStop,
+PxVehicleWheels4SimData_PropertiesStart,
+PxVehicleWheels4SimData_TireRestLoadsArray,
+PxVehicleWheels4SimData_RecipTireRestLoadsArray,
+PxVehicleWheels4SimData_PropertiesStop,
+PxVehicleWheelsSimData_PropertiesStart,
+PxVehicleWheelsSimData_ChassisMass,
+PxVehicleWheelsSimData_SuspensionData,
+PxVehicleWheelsSimData_WheelData,
+PxVehicleWheelsSimData_TireData,
+PxVehicleWheelsSimData_SuspTravelDirection,
+PxVehicleWheelsSimData_SuspForceAppPointOffset,
+PxVehicleWheelsSimData_TireForceAppPointOffset,
+PxVehicleWheelsSimData_WheelCentreOffset,
+PxVehicleWheelsSimData_WheelShapeMapping,
+PxVehicleWheelsSimData_SceneQueryFilterData,
+PxVehicleWheelsSimData_AntiRollBarData,
+PxVehicleWheelsSimData_TireLoadFilterData,
+PxVehicleWheelsSimData_MinLongSlipDenominator,
+PxVehicleWheelsSimData_ThresholdLongSpeed,
+PxVehicleWheelsSimData_LowForwardSpeedSubStepCount,
+PxVehicleWheelsSimData_HighForwardSpeedSubStepCount,
+PxVehicleWheelsSimData_WheelEnabledState,
+PxVehicleWheelsSimData_PropertiesStop,
+PxVehicleWheelsDynData_PropertiesStart,
+PxVehicleWheelsDynData_TireForceShaderFunction,
+PxVehicleWheelsDynData_WheelRotationSpeed,
+PxVehicleWheelsDynData_WheelRotationAngle,
+PxVehicleWheelsDynData_Wheel4DynData,
+PxVehicleWheelsDynData_PropertiesStop,
+PxVehicleWheels_PropertiesStart,
+PxVehicleWheels_VehicleType,
+PxVehicleWheels_RigidDynamicActor,
+PxVehicleWheels_ConcreteTypeName,
+PxVehicleWheels_MWheelsSimData,
+PxVehicleWheels_MWheelsDynData,
+PxVehicleWheels_PropertiesStop,
+PxVehicleDriveDynData_PropertiesStart,
+PxVehicleDriveDynData_AnalogInput,
+PxVehicleDriveDynData_GearUp,
+PxVehicleDriveDynData_GearDown,
+PxVehicleDriveDynData_UseAutoGears,
+PxVehicleDriveDynData_CurrentGear,
+PxVehicleDriveDynData_TargetGear,
+PxVehicleDriveDynData_EngineRotationSpeed,
+PxVehicleDriveDynData_GearChange,
+PxVehicleDriveDynData_GearSwitchTime,
+PxVehicleDriveDynData_AutoBoxSwitchTime,
+PxVehicleDriveDynData_MUseAutoGears,
+PxVehicleDriveDynData_MGearUpPressed,
+PxVehicleDriveDynData_MGearDownPressed,
+PxVehicleDriveDynData_MCurrentGear,
+PxVehicleDriveDynData_MTargetGear,
+PxVehicleDriveDynData_MEnginespeed,
+PxVehicleDriveDynData_MGearSwitchTime,
+PxVehicleDriveDynData_MAutoBoxSwitchTime,
+PxVehicleDriveDynData_PropertiesStop,
+PxVehicleDriveSimData_PropertiesStart,
+PxVehicleDriveSimData_EngineData,
+PxVehicleDriveSimData_GearsData,
+PxVehicleDriveSimData_ClutchData,
+PxVehicleDriveSimData_AutoBoxData,
+PxVehicleDriveSimData_PropertiesStop,
+PxVehicleDriveSimData4W_PropertiesStart,
+PxVehicleDriveSimData4W_DiffData,
+PxVehicleDriveSimData4W_AckermannGeometryData,
+PxVehicleDriveSimData4W_PropertiesStop,
+PxVehicleDrive_PropertiesStart,
+PxVehicleDrive_ConcreteTypeName,
+PxVehicleDrive_MDriveDynData,
+PxVehicleDrive_PropertiesStop,
+PxVehicleDrive4W_PropertiesStart,
+PxVehicleDrive4W_ConcreteTypeName,
+PxVehicleDrive4W_MDriveSimData,
+PxVehicleDrive4W_PropertiesStop,
+PxVehicleDriveTank_PropertiesStart,
+PxVehicleDriveTank_DriveModel,
+PxVehicleDriveTank_ConcreteTypeName,
+PxVehicleDriveTank_MDriveSimData,
+PxVehicleDriveTank_PropertiesStop,
+PxVehicleDriveSimDataNW_PropertiesStart,
+PxVehicleDriveSimDataNW_DiffData,
+PxVehicleDriveSimDataNW_PropertiesStop,
+PxVehicleDriveNW_PropertiesStart,
+PxVehicleDriveNW_ConcreteTypeName,
+PxVehicleDriveNW_MDriveSimData,
+PxVehicleDriveNW_PropertiesStop,
+PxVehicleNoDrive_PropertiesStart,
+PxVehicleNoDrive_BrakeTorque,
+PxVehicleNoDrive_DriveTorque,
+PxVehicleNoDrive_SteerAngle,
+PxVehicleNoDrive_ConcreteTypeName,
+PxVehicleNoDrive_PropertiesStop,
+
+
+#undef THERE_IS_NO_INCLUDE_GUARD_HERE_FOR_A_REASON
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleAutoGeneratedMetaDataObjects.h b/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleAutoGeneratedMetaDataObjects.h
new file mode 100644
index 00000000..1fe5cd40
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleAutoGeneratedMetaDataObjects.h
@@ -0,0 +1,1797 @@
+// 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.
+
+// This code is auto-generated by the PhysX Clang metadata generator. Do not edit or be
+// prepared for your edits to be quietly ignored next time the clang metadata generator is
+// run. You can find the most recent version of clang metadata generator by contacting
+// Chris Nuernberger <[email protected]> or Dilip or Adam.
+// The source code for the generate was at one time checked into:
+// physx/PhysXMetaDataGenerator/llvm/tools/clang/lib/Frontend/PhysXMetaDataAction.cpp
+#define THERE_IS_NO_INCLUDE_GUARD_HERE_FOR_A_REASON
+
+#define PX_PROPERTY_INFO_NAME PxVehiclePropertyInfoName
+ class PxVehicleChassisData;
+ struct PxVehicleChassisDataGeneratedValues
+ {
+ PxVec3 MMOI;
+ PxReal MMass;
+ PxVec3 MCMOffset;
+ PxVehicleChassisDataGeneratedValues( const PxVehicleChassisData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleChassisData, MMOI, PxVehicleChassisDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleChassisData, MMass, PxVehicleChassisDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleChassisData, MCMOffset, PxVehicleChassisDataGeneratedValues)
+ struct PxVehicleChassisDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleChassisData"; }
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleChassisData_MMOI, PxVehicleChassisData, PxVec3, PxVec3 > MMOI;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleChassisData_MMass, PxVehicleChassisData, PxReal, PxReal > MMass;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleChassisData_MCMOffset, PxVehicleChassisData, PxVec3, PxVec3 > MCMOffset;
+
+ PxVehicleChassisDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleChassisData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 3; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( MMOI, inStartIndex + 0 );;
+ inOperator( MMass, inStartIndex + 1 );;
+ inOperator( MCMOffset, inStartIndex + 2 );;
+ return 3 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleChassisData>
+ {
+ PxVehicleChassisDataGeneratedInfo Info;
+ const PxVehicleChassisDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ static PxU32ToName g_physx__PxEMPTYConversion[] = {
+ { "PxEmpty", static_cast<PxU32>( physx::PxEmpty ) },
+ { NULL, 0 }
+ };
+
+template<> struct PxEnumTraits< const physx::PxEMPTY > { PxEnumTraits() : NameConversion( g_physx__PxEMPTYConversion ) {} const PxU32ToName* NameConversion; };
+ class PxVehicleEngineData;
+ struct PxVehicleEngineDataGeneratedValues
+ {
+ PxReal RecipMOI;
+ PxReal RecipMaxOmega;
+ PxReal MMOI;
+ PxReal MPeakTorque;
+ PxReal MMaxOmega;
+ PxReal MDampingRateFullThrottle;
+ PxReal MDampingRateZeroThrottleClutchEngaged;
+ PxReal MDampingRateZeroThrottleClutchDisengaged;
+ PxVehicleEngineDataGeneratedValues( const PxVehicleEngineData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleEngineData, RecipMOI, PxVehicleEngineDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleEngineData, RecipMaxOmega, PxVehicleEngineDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleEngineData, MMOI, PxVehicleEngineDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleEngineData, MPeakTorque, PxVehicleEngineDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleEngineData, MMaxOmega, PxVehicleEngineDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleEngineData, MDampingRateFullThrottle, PxVehicleEngineDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleEngineData, MDampingRateZeroThrottleClutchEngaged, PxVehicleEngineDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleEngineData, MDampingRateZeroThrottleClutchDisengaged, PxVehicleEngineDataGeneratedValues)
+ struct PxVehicleEngineDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleEngineData"; }
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleEngineData_RecipMOI, PxVehicleEngineData, PxReal > RecipMOI;
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleEngineData_RecipMaxOmega, PxVehicleEngineData, PxReal > RecipMaxOmega;
+ MTorqueCurveProperty MTorqueCurve;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleEngineData_MMOI, PxVehicleEngineData, PxReal, PxReal > MMOI;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleEngineData_MPeakTorque, PxVehicleEngineData, PxReal, PxReal > MPeakTorque;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleEngineData_MMaxOmega, PxVehicleEngineData, PxReal, PxReal > MMaxOmega;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleEngineData_MDampingRateFullThrottle, PxVehicleEngineData, PxReal, PxReal > MDampingRateFullThrottle;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleEngineData_MDampingRateZeroThrottleClutchEngaged, PxVehicleEngineData, PxReal, PxReal > MDampingRateZeroThrottleClutchEngaged;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleEngineData_MDampingRateZeroThrottleClutchDisengaged, PxVehicleEngineData, PxReal, PxReal > MDampingRateZeroThrottleClutchDisengaged;
+
+ PxVehicleEngineDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleEngineData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 9; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( RecipMOI, inStartIndex + 0 );;
+ inOperator( RecipMaxOmega, inStartIndex + 1 );;
+ inOperator( MTorqueCurve, inStartIndex + 2 );;
+ inOperator( MMOI, inStartIndex + 3 );;
+ inOperator( MPeakTorque, inStartIndex + 4 );;
+ inOperator( MMaxOmega, inStartIndex + 5 );;
+ inOperator( MDampingRateFullThrottle, inStartIndex + 6 );;
+ inOperator( MDampingRateZeroThrottleClutchEngaged, inStartIndex + 7 );;
+ inOperator( MDampingRateZeroThrottleClutchDisengaged, inStartIndex + 8 );;
+ return 9 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleEngineData>
+ {
+ PxVehicleEngineDataGeneratedInfo Info;
+ const PxVehicleEngineDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ static PxU32ToName g_physx__PxVehicleGearsData__EnumConversion[] = {
+ { "eREVERSE", static_cast<PxU32>( physx::PxVehicleGearsData::eREVERSE ) },
+ { "eNEUTRAL", static_cast<PxU32>( physx::PxVehicleGearsData::eNEUTRAL ) },
+ { "eFIRST", static_cast<PxU32>( physx::PxVehicleGearsData::eFIRST ) },
+ { "eSECOND", static_cast<PxU32>( physx::PxVehicleGearsData::eSECOND ) },
+ { "eTHIRD", static_cast<PxU32>( physx::PxVehicleGearsData::eTHIRD ) },
+ { "eFOURTH", static_cast<PxU32>( physx::PxVehicleGearsData::eFOURTH ) },
+ { "eFIFTH", static_cast<PxU32>( physx::PxVehicleGearsData::eFIFTH ) },
+ { "eSIXTH", static_cast<PxU32>( physx::PxVehicleGearsData::eSIXTH ) },
+ { "eSEVENTH", static_cast<PxU32>( physx::PxVehicleGearsData::eSEVENTH ) },
+ { "eEIGHTH", static_cast<PxU32>( physx::PxVehicleGearsData::eEIGHTH ) },
+ { "eNINTH", static_cast<PxU32>( physx::PxVehicleGearsData::eNINTH ) },
+ { "eTENTH", static_cast<PxU32>( physx::PxVehicleGearsData::eTENTH ) },
+ { "eELEVENTH", static_cast<PxU32>( physx::PxVehicleGearsData::eELEVENTH ) },
+ { "eTWELFTH", static_cast<PxU32>( physx::PxVehicleGearsData::eTWELFTH ) },
+ { "eTHIRTEENTH", static_cast<PxU32>( physx::PxVehicleGearsData::eTHIRTEENTH ) },
+ { "eFOURTEENTH", static_cast<PxU32>( physx::PxVehicleGearsData::eFOURTEENTH ) },
+ { "eFIFTEENTH", static_cast<PxU32>( physx::PxVehicleGearsData::eFIFTEENTH ) },
+ { "eSIXTEENTH", static_cast<PxU32>( physx::PxVehicleGearsData::eSIXTEENTH ) },
+ { "eSEVENTEENTH", static_cast<PxU32>( physx::PxVehicleGearsData::eSEVENTEENTH ) },
+ { "eEIGHTEENTH", static_cast<PxU32>( physx::PxVehicleGearsData::eEIGHTEENTH ) },
+ { "eNINETEENTH", static_cast<PxU32>( physx::PxVehicleGearsData::eNINETEENTH ) },
+ { "eTWENTIETH", static_cast<PxU32>( physx::PxVehicleGearsData::eTWENTIETH ) },
+ { "eTWENTYFIRST", static_cast<PxU32>( physx::PxVehicleGearsData::eTWENTYFIRST ) },
+ { "eTWENTYSECOND", static_cast<PxU32>( physx::PxVehicleGearsData::eTWENTYSECOND ) },
+ { "eTWENTYTHIRD", static_cast<PxU32>( physx::PxVehicleGearsData::eTWENTYTHIRD ) },
+ { "eTWENTYFOURTH", static_cast<PxU32>( physx::PxVehicleGearsData::eTWENTYFOURTH ) },
+ { "eTWENTYFIFTH", static_cast<PxU32>( physx::PxVehicleGearsData::eTWENTYFIFTH ) },
+ { "eTWENTYSIXTH", static_cast<PxU32>( physx::PxVehicleGearsData::eTWENTYSIXTH ) },
+ { "eTWENTYSEVENTH", static_cast<PxU32>( physx::PxVehicleGearsData::eTWENTYSEVENTH ) },
+ { "eTWENTYEIGHTH", static_cast<PxU32>( physx::PxVehicleGearsData::eTWENTYEIGHTH ) },
+ { "eTWENTYNINTH", static_cast<PxU32>( physx::PxVehicleGearsData::eTWENTYNINTH ) },
+ { "eTHIRTIETH", static_cast<PxU32>( physx::PxVehicleGearsData::eTHIRTIETH ) },
+ { NULL, 0 }
+ };
+
+template<> struct PxEnumTraits< physx::PxVehicleGearsData::Enum > { PxEnumTraits() : NameConversion( g_physx__PxVehicleGearsData__EnumConversion ) {} const PxU32ToName* NameConversion; };
+ class PxVehicleGearsData;
+ struct PxVehicleGearsDataGeneratedValues
+ {
+ PxReal GearRatio[physx::PxVehicleGearsData::eGEARSRATIO_COUNT];
+ PxReal MFinalRatio;
+ PxU32 MNbRatios;
+ PxReal MSwitchTime;
+ PxVehicleGearsDataGeneratedValues( const PxVehicleGearsData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleGearsData, GearRatio, PxVehicleGearsDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleGearsData, MFinalRatio, PxVehicleGearsDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleGearsData, MNbRatios, PxVehicleGearsDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleGearsData, MSwitchTime, PxVehicleGearsDataGeneratedValues)
+ struct PxVehicleGearsDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleGearsData"; }
+ PxIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleGearsData_GearRatio, PxVehicleGearsData, PxVehicleGearsData::Enum, PxReal > GearRatio;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleGearsData_MFinalRatio, PxVehicleGearsData, PxReal, PxReal > MFinalRatio;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleGearsData_MNbRatios, PxVehicleGearsData, PxU32, PxU32 > MNbRatios;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleGearsData_MSwitchTime, PxVehicleGearsData, PxReal, PxReal > MSwitchTime;
+
+ PxVehicleGearsDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleGearsData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 4; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( GearRatio, inStartIndex + 0 );;
+ inOperator( MFinalRatio, inStartIndex + 1 );;
+ inOperator( MNbRatios, inStartIndex + 2 );;
+ inOperator( MSwitchTime, inStartIndex + 3 );;
+ return 4 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleGearsData>
+ {
+ PxVehicleGearsDataGeneratedInfo Info;
+ const PxVehicleGearsDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleAutoBoxData;
+ struct PxVehicleAutoBoxDataGeneratedValues
+ {
+ PxReal Latency;
+ PxReal UpRatios[physx::PxVehicleGearsData::eGEARSRATIO_COUNT];
+ PxReal DownRatios[physx::PxVehicleGearsData::eGEARSRATIO_COUNT];
+ PxVehicleAutoBoxDataGeneratedValues( const PxVehicleAutoBoxData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleAutoBoxData, Latency, PxVehicleAutoBoxDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleAutoBoxData, UpRatios, PxVehicleAutoBoxDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleAutoBoxData, DownRatios, PxVehicleAutoBoxDataGeneratedValues)
+ struct PxVehicleAutoBoxDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleAutoBoxData"; }
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleAutoBoxData_Latency, PxVehicleAutoBoxData, const PxReal, PxReal > Latency;
+ PxIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleAutoBoxData_UpRatios, PxVehicleAutoBoxData, PxVehicleGearsData::Enum, PxReal > UpRatios;
+ PxIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleAutoBoxData_DownRatios, PxVehicleAutoBoxData, PxVehicleGearsData::Enum, PxReal > DownRatios;
+
+ PxVehicleAutoBoxDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleAutoBoxData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 3; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( Latency, inStartIndex + 0 );;
+ inOperator( UpRatios, inStartIndex + 1 );;
+ inOperator( DownRatios, inStartIndex + 2 );;
+ return 3 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleAutoBoxData>
+ {
+ PxVehicleAutoBoxDataGeneratedInfo Info;
+ const PxVehicleAutoBoxDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ static PxU32ToName g_physx__PxVehicleDifferential4WData__EnumConversion[] = {
+ { "eDIFF_TYPE_LS_4WD", static_cast<PxU32>( physx::PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD ) },
+ { "eDIFF_TYPE_LS_FRONTWD", static_cast<PxU32>( physx::PxVehicleDifferential4WData::eDIFF_TYPE_LS_FRONTWD ) },
+ { "eDIFF_TYPE_LS_REARWD", static_cast<PxU32>( physx::PxVehicleDifferential4WData::eDIFF_TYPE_LS_REARWD ) },
+ { "eDIFF_TYPE_OPEN_4WD", static_cast<PxU32>( physx::PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_4WD ) },
+ { "eDIFF_TYPE_OPEN_FRONTWD", static_cast<PxU32>( physx::PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_FRONTWD ) },
+ { "eDIFF_TYPE_OPEN_REARWD", static_cast<PxU32>( physx::PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_REARWD ) },
+ { "eMAX_NB_DIFF_TYPES", static_cast<PxU32>( physx::PxVehicleDifferential4WData::eMAX_NB_DIFF_TYPES ) },
+ { NULL, 0 }
+ };
+
+template<> struct PxEnumTraits< physx::PxVehicleDifferential4WData::Enum > { PxEnumTraits() : NameConversion( g_physx__PxVehicleDifferential4WData__EnumConversion ) {} const PxU32ToName* NameConversion; };
+ class PxVehicleDifferential4WData;
+ struct PxVehicleDifferential4WDataGeneratedValues
+ {
+ PxReal MFrontRearSplit;
+ PxReal MFrontLeftRightSplit;
+ PxReal MRearLeftRightSplit;
+ PxReal MCentreBias;
+ PxReal MFrontBias;
+ PxReal MRearBias;
+ PxVehicleDifferential4WData::Enum MType;
+ PxVehicleDifferential4WDataGeneratedValues( const PxVehicleDifferential4WData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDifferential4WData, MFrontRearSplit, PxVehicleDifferential4WDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDifferential4WData, MFrontLeftRightSplit, PxVehicleDifferential4WDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDifferential4WData, MRearLeftRightSplit, PxVehicleDifferential4WDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDifferential4WData, MCentreBias, PxVehicleDifferential4WDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDifferential4WData, MFrontBias, PxVehicleDifferential4WDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDifferential4WData, MRearBias, PxVehicleDifferential4WDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDifferential4WData, MType, PxVehicleDifferential4WDataGeneratedValues)
+ struct PxVehicleDifferential4WDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleDifferential4WData"; }
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDifferential4WData_MFrontRearSplit, PxVehicleDifferential4WData, PxReal, PxReal > MFrontRearSplit;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDifferential4WData_MFrontLeftRightSplit, PxVehicleDifferential4WData, PxReal, PxReal > MFrontLeftRightSplit;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDifferential4WData_MRearLeftRightSplit, PxVehicleDifferential4WData, PxReal, PxReal > MRearLeftRightSplit;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDifferential4WData_MCentreBias, PxVehicleDifferential4WData, PxReal, PxReal > MCentreBias;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDifferential4WData_MFrontBias, PxVehicleDifferential4WData, PxReal, PxReal > MFrontBias;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDifferential4WData_MRearBias, PxVehicleDifferential4WData, PxReal, PxReal > MRearBias;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDifferential4WData_MType, PxVehicleDifferential4WData, PxVehicleDifferential4WData::Enum, PxVehicleDifferential4WData::Enum > MType;
+
+ PxVehicleDifferential4WDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleDifferential4WData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 7; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( MFrontRearSplit, inStartIndex + 0 );;
+ inOperator( MFrontLeftRightSplit, inStartIndex + 1 );;
+ inOperator( MRearLeftRightSplit, inStartIndex + 2 );;
+ inOperator( MCentreBias, inStartIndex + 3 );;
+ inOperator( MFrontBias, inStartIndex + 4 );;
+ inOperator( MRearBias, inStartIndex + 5 );;
+ inOperator( MType, inStartIndex + 6 );;
+ return 7 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleDifferential4WData>
+ {
+ PxVehicleDifferential4WDataGeneratedInfo Info;
+ const PxVehicleDifferential4WDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleDifferentialNWData;
+ struct PxVehicleDifferentialNWDataGeneratedValues
+ {
+ PxU32 DrivenWheelStatus;
+ PxVehicleDifferentialNWDataGeneratedValues( const PxVehicleDifferentialNWData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDifferentialNWData, DrivenWheelStatus, PxVehicleDifferentialNWDataGeneratedValues)
+ struct PxVehicleDifferentialNWDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleDifferentialNWData"; }
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDifferentialNWData_DrivenWheelStatus, PxVehicleDifferentialNWData, PxU32, PxU32 > DrivenWheelStatus;
+
+ PxVehicleDifferentialNWDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleDifferentialNWData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 1; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( DrivenWheelStatus, inStartIndex + 0 );;
+ return 1 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleDifferentialNWData>
+ {
+ PxVehicleDifferentialNWDataGeneratedInfo Info;
+ const PxVehicleDifferentialNWDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleAckermannGeometryData;
+ struct PxVehicleAckermannGeometryDataGeneratedValues
+ {
+ PxReal MAccuracy;
+ PxReal MFrontWidth;
+ PxReal MRearWidth;
+ PxReal MAxleSeparation;
+ PxVehicleAckermannGeometryDataGeneratedValues( const PxVehicleAckermannGeometryData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleAckermannGeometryData, MAccuracy, PxVehicleAckermannGeometryDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleAckermannGeometryData, MFrontWidth, PxVehicleAckermannGeometryDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleAckermannGeometryData, MRearWidth, PxVehicleAckermannGeometryDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleAckermannGeometryData, MAxleSeparation, PxVehicleAckermannGeometryDataGeneratedValues)
+ struct PxVehicleAckermannGeometryDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleAckermannGeometryData"; }
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleAckermannGeometryData_MAccuracy, PxVehicleAckermannGeometryData, PxReal, PxReal > MAccuracy;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleAckermannGeometryData_MFrontWidth, PxVehicleAckermannGeometryData, PxReal, PxReal > MFrontWidth;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleAckermannGeometryData_MRearWidth, PxVehicleAckermannGeometryData, PxReal, PxReal > MRearWidth;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleAckermannGeometryData_MAxleSeparation, PxVehicleAckermannGeometryData, PxReal, PxReal > MAxleSeparation;
+
+ PxVehicleAckermannGeometryDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleAckermannGeometryData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 4; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( MAccuracy, inStartIndex + 0 );;
+ inOperator( MFrontWidth, inStartIndex + 1 );;
+ inOperator( MRearWidth, inStartIndex + 2 );;
+ inOperator( MAxleSeparation, inStartIndex + 3 );;
+ return 4 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleAckermannGeometryData>
+ {
+ PxVehicleAckermannGeometryDataGeneratedInfo Info;
+ const PxVehicleAckermannGeometryDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ static PxU32ToName g_physx__PxVehicleClutchAccuracyMode__EnumConversion[] = {
+ { "eESTIMATE", static_cast<PxU32>( physx::PxVehicleClutchAccuracyMode::eESTIMATE ) },
+ { "eBEST_POSSIBLE", static_cast<PxU32>( physx::PxVehicleClutchAccuracyMode::eBEST_POSSIBLE ) },
+ { NULL, 0 }
+ };
+
+template<> struct PxEnumTraits< physx::PxVehicleClutchAccuracyMode::Enum > { PxEnumTraits() : NameConversion( g_physx__PxVehicleClutchAccuracyMode__EnumConversion ) {} const PxU32ToName* NameConversion; };
+ class PxVehicleClutchData;
+ struct PxVehicleClutchDataGeneratedValues
+ {
+ PxReal MStrength;
+ PxVehicleClutchAccuracyMode::Enum MAccuracyMode;
+ PxU32 MEstimateIterations;
+ PxVehicleClutchDataGeneratedValues( const PxVehicleClutchData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleClutchData, MStrength, PxVehicleClutchDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleClutchData, MAccuracyMode, PxVehicleClutchDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleClutchData, MEstimateIterations, PxVehicleClutchDataGeneratedValues)
+ struct PxVehicleClutchDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleClutchData"; }
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleClutchData_MStrength, PxVehicleClutchData, PxReal, PxReal > MStrength;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleClutchData_MAccuracyMode, PxVehicleClutchData, PxVehicleClutchAccuracyMode::Enum, PxVehicleClutchAccuracyMode::Enum > MAccuracyMode;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleClutchData_MEstimateIterations, PxVehicleClutchData, PxU32, PxU32 > MEstimateIterations;
+
+ PxVehicleClutchDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleClutchData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 3; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( MStrength, inStartIndex + 0 );;
+ inOperator( MAccuracyMode, inStartIndex + 1 );;
+ inOperator( MEstimateIterations, inStartIndex + 2 );;
+ return 3 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleClutchData>
+ {
+ PxVehicleClutchDataGeneratedInfo Info;
+ const PxVehicleClutchDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleTireLoadFilterData;
+ struct PxVehicleTireLoadFilterDataGeneratedValues
+ {
+ PxReal Denominator;
+ PxReal MMinNormalisedLoad;
+ PxReal MMinFilteredNormalisedLoad;
+ PxReal MMaxNormalisedLoad;
+ PxReal MMaxFilteredNormalisedLoad;
+ PxVehicleTireLoadFilterDataGeneratedValues( const PxVehicleTireLoadFilterData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireLoadFilterData, Denominator, PxVehicleTireLoadFilterDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireLoadFilterData, MMinNormalisedLoad, PxVehicleTireLoadFilterDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireLoadFilterData, MMinFilteredNormalisedLoad, PxVehicleTireLoadFilterDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireLoadFilterData, MMaxNormalisedLoad, PxVehicleTireLoadFilterDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireLoadFilterData, MMaxFilteredNormalisedLoad, PxVehicleTireLoadFilterDataGeneratedValues)
+ struct PxVehicleTireLoadFilterDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleTireLoadFilterData"; }
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireLoadFilterData_Denominator, PxVehicleTireLoadFilterData, PxReal > Denominator;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireLoadFilterData_MMinNormalisedLoad, PxVehicleTireLoadFilterData, PxReal, PxReal > MMinNormalisedLoad;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireLoadFilterData_MMinFilteredNormalisedLoad, PxVehicleTireLoadFilterData, PxReal, PxReal > MMinFilteredNormalisedLoad;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireLoadFilterData_MMaxNormalisedLoad, PxVehicleTireLoadFilterData, PxReal, PxReal > MMaxNormalisedLoad;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireLoadFilterData_MMaxFilteredNormalisedLoad, PxVehicleTireLoadFilterData, PxReal, PxReal > MMaxFilteredNormalisedLoad;
+
+ PxVehicleTireLoadFilterDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleTireLoadFilterData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 5; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( Denominator, inStartIndex + 0 );;
+ inOperator( MMinNormalisedLoad, inStartIndex + 1 );;
+ inOperator( MMinFilteredNormalisedLoad, inStartIndex + 2 );;
+ inOperator( MMaxNormalisedLoad, inStartIndex + 3 );;
+ inOperator( MMaxFilteredNormalisedLoad, inStartIndex + 4 );;
+ return 5 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleTireLoadFilterData>
+ {
+ PxVehicleTireLoadFilterDataGeneratedInfo Info;
+ const PxVehicleTireLoadFilterDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleWheelData;
+ struct PxVehicleWheelDataGeneratedValues
+ {
+ PxReal RecipRadius;
+ PxReal RecipMOI;
+ PxReal MRadius;
+ PxReal MWidth;
+ PxReal MMass;
+ PxReal MMOI;
+ PxReal MDampingRate;
+ PxReal MMaxBrakeTorque;
+ PxReal MMaxHandBrakeTorque;
+ PxReal MMaxSteer;
+ PxReal MToeAngle;
+ PxVehicleWheelDataGeneratedValues( const PxVehicleWheelData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelData, RecipRadius, PxVehicleWheelDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelData, RecipMOI, PxVehicleWheelDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelData, MRadius, PxVehicleWheelDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelData, MWidth, PxVehicleWheelDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelData, MMass, PxVehicleWheelDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelData, MMOI, PxVehicleWheelDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelData, MDampingRate, PxVehicleWheelDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelData, MMaxBrakeTorque, PxVehicleWheelDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelData, MMaxHandBrakeTorque, PxVehicleWheelDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelData, MMaxSteer, PxVehicleWheelDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelData, MToeAngle, PxVehicleWheelDataGeneratedValues)
+ struct PxVehicleWheelDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleWheelData"; }
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelData_RecipRadius, PxVehicleWheelData, PxReal > RecipRadius;
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelData_RecipMOI, PxVehicleWheelData, PxReal > RecipMOI;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelData_MRadius, PxVehicleWheelData, PxReal, PxReal > MRadius;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelData_MWidth, PxVehicleWheelData, PxReal, PxReal > MWidth;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelData_MMass, PxVehicleWheelData, PxReal, PxReal > MMass;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelData_MMOI, PxVehicleWheelData, PxReal, PxReal > MMOI;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelData_MDampingRate, PxVehicleWheelData, PxReal, PxReal > MDampingRate;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelData_MMaxBrakeTorque, PxVehicleWheelData, PxReal, PxReal > MMaxBrakeTorque;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelData_MMaxHandBrakeTorque, PxVehicleWheelData, PxReal, PxReal > MMaxHandBrakeTorque;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelData_MMaxSteer, PxVehicleWheelData, PxReal, PxReal > MMaxSteer;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelData_MToeAngle, PxVehicleWheelData, PxReal, PxReal > MToeAngle;
+
+ PxVehicleWheelDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleWheelData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 11; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( RecipRadius, inStartIndex + 0 );;
+ inOperator( RecipMOI, inStartIndex + 1 );;
+ inOperator( MRadius, inStartIndex + 2 );;
+ inOperator( MWidth, inStartIndex + 3 );;
+ inOperator( MMass, inStartIndex + 4 );;
+ inOperator( MMOI, inStartIndex + 5 );;
+ inOperator( MDampingRate, inStartIndex + 6 );;
+ inOperator( MMaxBrakeTorque, inStartIndex + 7 );;
+ inOperator( MMaxHandBrakeTorque, inStartIndex + 8 );;
+ inOperator( MMaxSteer, inStartIndex + 9 );;
+ inOperator( MToeAngle, inStartIndex + 10 );;
+ return 11 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleWheelData>
+ {
+ PxVehicleWheelDataGeneratedInfo Info;
+ const PxVehicleWheelDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleSuspensionData;
+ struct PxVehicleSuspensionDataGeneratedValues
+ {
+ PxReal RecipMaxCompression;
+ PxReal RecipMaxDroop;
+ PxReal MSpringStrength;
+ PxReal MSpringDamperRate;
+ PxReal MMaxCompression;
+ PxReal MMaxDroop;
+ PxReal MSprungMass;
+ PxReal MCamberAtRest;
+ PxReal MCamberAtMaxCompression;
+ PxReal MCamberAtMaxDroop;
+ PxVehicleSuspensionDataGeneratedValues( const PxVehicleSuspensionData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleSuspensionData, RecipMaxCompression, PxVehicleSuspensionDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleSuspensionData, RecipMaxDroop, PxVehicleSuspensionDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleSuspensionData, MSpringStrength, PxVehicleSuspensionDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleSuspensionData, MSpringDamperRate, PxVehicleSuspensionDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleSuspensionData, MMaxCompression, PxVehicleSuspensionDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleSuspensionData, MMaxDroop, PxVehicleSuspensionDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleSuspensionData, MSprungMass, PxVehicleSuspensionDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleSuspensionData, MCamberAtRest, PxVehicleSuspensionDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleSuspensionData, MCamberAtMaxCompression, PxVehicleSuspensionDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleSuspensionData, MCamberAtMaxDroop, PxVehicleSuspensionDataGeneratedValues)
+ struct PxVehicleSuspensionDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleSuspensionData"; }
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleSuspensionData_RecipMaxCompression, PxVehicleSuspensionData, PxReal > RecipMaxCompression;
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleSuspensionData_RecipMaxDroop, PxVehicleSuspensionData, PxReal > RecipMaxDroop;
+ PxWriteOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleSuspensionData_MassAndPreserveNaturalFrequency, PxVehicleSuspensionData, const PxReal > MassAndPreserveNaturalFrequency;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleSuspensionData_MSpringStrength, PxVehicleSuspensionData, PxReal, PxReal > MSpringStrength;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleSuspensionData_MSpringDamperRate, PxVehicleSuspensionData, PxReal, PxReal > MSpringDamperRate;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleSuspensionData_MMaxCompression, PxVehicleSuspensionData, PxReal, PxReal > MMaxCompression;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleSuspensionData_MMaxDroop, PxVehicleSuspensionData, PxReal, PxReal > MMaxDroop;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleSuspensionData_MSprungMass, PxVehicleSuspensionData, PxReal, PxReal > MSprungMass;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleSuspensionData_MCamberAtRest, PxVehicleSuspensionData, PxReal, PxReal > MCamberAtRest;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleSuspensionData_MCamberAtMaxCompression, PxVehicleSuspensionData, PxReal, PxReal > MCamberAtMaxCompression;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleSuspensionData_MCamberAtMaxDroop, PxVehicleSuspensionData, PxReal, PxReal > MCamberAtMaxDroop;
+
+ PxVehicleSuspensionDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleSuspensionData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 11; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( RecipMaxCompression, inStartIndex + 0 );;
+ inOperator( RecipMaxDroop, inStartIndex + 1 );;
+ inOperator( MassAndPreserveNaturalFrequency, inStartIndex + 2 );;
+ inOperator( MSpringStrength, inStartIndex + 3 );;
+ inOperator( MSpringDamperRate, inStartIndex + 4 );;
+ inOperator( MMaxCompression, inStartIndex + 5 );;
+ inOperator( MMaxDroop, inStartIndex + 6 );;
+ inOperator( MSprungMass, inStartIndex + 7 );;
+ inOperator( MCamberAtRest, inStartIndex + 8 );;
+ inOperator( MCamberAtMaxCompression, inStartIndex + 9 );;
+ inOperator( MCamberAtMaxDroop, inStartIndex + 10 );;
+ return 11 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleSuspensionData>
+ {
+ PxVehicleSuspensionDataGeneratedInfo Info;
+ const PxVehicleSuspensionDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleAntiRollBarData;
+ struct PxVehicleAntiRollBarDataGeneratedValues
+ {
+ PxU32 MWheel0;
+ PxU32 MWheel1;
+ PxF32 MStiffness;
+ PxVehicleAntiRollBarDataGeneratedValues( const PxVehicleAntiRollBarData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleAntiRollBarData, MWheel0, PxVehicleAntiRollBarDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleAntiRollBarData, MWheel1, PxVehicleAntiRollBarDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleAntiRollBarData, MStiffness, PxVehicleAntiRollBarDataGeneratedValues)
+ struct PxVehicleAntiRollBarDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleAntiRollBarData"; }
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleAntiRollBarData_MWheel0, PxVehicleAntiRollBarData, PxU32, PxU32 > MWheel0;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleAntiRollBarData_MWheel1, PxVehicleAntiRollBarData, PxU32, PxU32 > MWheel1;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleAntiRollBarData_MStiffness, PxVehicleAntiRollBarData, PxF32, PxF32 > MStiffness;
+
+ PxVehicleAntiRollBarDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleAntiRollBarData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 3; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( MWheel0, inStartIndex + 0 );;
+ inOperator( MWheel1, inStartIndex + 1 );;
+ inOperator( MStiffness, inStartIndex + 2 );;
+ return 3 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleAntiRollBarData>
+ {
+ PxVehicleAntiRollBarDataGeneratedInfo Info;
+ const PxVehicleAntiRollBarDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleTireData;
+ struct PxVehicleTireDataGeneratedValues
+ {
+ PxReal RecipLongitudinalStiffnessPerUnitGravity;
+ PxReal FrictionVsSlipGraphRecipx1Minusx0;
+ PxReal FrictionVsSlipGraphRecipx2Minusx1;
+ PxReal MLatStiffX;
+ PxReal MLatStiffY;
+ PxReal MLongitudinalStiffnessPerUnitGravity;
+ PxReal MCamberStiffnessPerUnitGravity;
+ PxU32 MType;
+ PxReal MFrictionVsSlipGraph[3][2];
+ PxVehicleTireDataGeneratedValues( const PxVehicleTireData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireData, RecipLongitudinalStiffnessPerUnitGravity, PxVehicleTireDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireData, FrictionVsSlipGraphRecipx1Minusx0, PxVehicleTireDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireData, FrictionVsSlipGraphRecipx2Minusx1, PxVehicleTireDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireData, MLatStiffX, PxVehicleTireDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireData, MLatStiffY, PxVehicleTireDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireData, MLongitudinalStiffnessPerUnitGravity, PxVehicleTireDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireData, MCamberStiffnessPerUnitGravity, PxVehicleTireDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireData, MType, PxVehicleTireDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleTireData, MFrictionVsSlipGraph, PxVehicleTireDataGeneratedValues)
+ struct PxVehicleTireDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleTireData"; }
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireData_RecipLongitudinalStiffnessPerUnitGravity, PxVehicleTireData, PxReal > RecipLongitudinalStiffnessPerUnitGravity;
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireData_FrictionVsSlipGraphRecipx1Minusx0, PxVehicleTireData, PxReal > FrictionVsSlipGraphRecipx1Minusx0;
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireData_FrictionVsSlipGraphRecipx2Minusx1, PxVehicleTireData, PxReal > FrictionVsSlipGraphRecipx2Minusx1;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireData_MLatStiffX, PxVehicleTireData, PxReal, PxReal > MLatStiffX;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireData_MLatStiffY, PxVehicleTireData, PxReal, PxReal > MLatStiffY;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireData_MLongitudinalStiffnessPerUnitGravity, PxVehicleTireData, PxReal, PxReal > MLongitudinalStiffnessPerUnitGravity;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireData_MCamberStiffnessPerUnitGravity, PxVehicleTireData, PxReal, PxReal > MCamberStiffnessPerUnitGravity;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleTireData_MType, PxVehicleTireData, PxU32, PxU32 > MType;
+ MFrictionVsSlipGraphProperty MFrictionVsSlipGraph;
+
+ PxVehicleTireDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleTireData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 9; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( RecipLongitudinalStiffnessPerUnitGravity, inStartIndex + 0 );;
+ inOperator( FrictionVsSlipGraphRecipx1Minusx0, inStartIndex + 1 );;
+ inOperator( FrictionVsSlipGraphRecipx2Minusx1, inStartIndex + 2 );;
+ inOperator( MLatStiffX, inStartIndex + 3 );;
+ inOperator( MLatStiffY, inStartIndex + 4 );;
+ inOperator( MLongitudinalStiffnessPerUnitGravity, inStartIndex + 5 );;
+ inOperator( MCamberStiffnessPerUnitGravity, inStartIndex + 6 );;
+ inOperator( MType, inStartIndex + 7 );;
+ inOperator( MFrictionVsSlipGraph, inStartIndex + 8 );;
+ return 9 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleTireData>
+ {
+ PxVehicleTireDataGeneratedInfo Info;
+ const PxVehicleTireDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleWheels4SimData;
+ struct PxVehicleWheels4SimDataGeneratedValues
+ {
+ const PxReal * TireRestLoadsArray;
+ const PxReal * RecipTireRestLoadsArray;
+ PxVehicleWheels4SimDataGeneratedValues( const PxVehicleWheels4SimData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheels4SimData, TireRestLoadsArray, PxVehicleWheels4SimDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheels4SimData, RecipTireRestLoadsArray, PxVehicleWheels4SimDataGeneratedValues)
+ struct PxVehicleWheels4SimDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleWheels4SimData"; }
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheels4SimData_TireRestLoadsArray, PxVehicleWheels4SimData, const PxReal * > TireRestLoadsArray;
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheels4SimData_RecipTireRestLoadsArray, PxVehicleWheels4SimData, const PxReal * > RecipTireRestLoadsArray;
+
+ PxVehicleWheels4SimDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleWheels4SimData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 2; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( TireRestLoadsArray, inStartIndex + 0 );;
+ inOperator( RecipTireRestLoadsArray, inStartIndex + 1 );;
+ return 2 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleWheels4SimData>
+ {
+ PxVehicleWheels4SimDataGeneratedInfo Info;
+ const PxVehicleWheels4SimDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleWheelsSimData;
+ struct PxVehicleWheelsSimDataGeneratedValues
+ {
+ PxVehicleTireLoadFilterData TireLoadFilterData;
+ PxF32 MinLongSlipDenominator;
+ PxF32 ThresholdLongSpeed;
+ PxU32 LowForwardSpeedSubStepCount;
+ PxU32 HighForwardSpeedSubStepCount;
+ PxVehicleWheelsSimDataGeneratedValues( const PxVehicleWheelsSimData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelsSimData, TireLoadFilterData, PxVehicleWheelsSimDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelsSimData, MinLongSlipDenominator, PxVehicleWheelsSimDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelsSimData, ThresholdLongSpeed, PxVehicleWheelsSimDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelsSimData, LowForwardSpeedSubStepCount, PxVehicleWheelsSimDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelsSimData, HighForwardSpeedSubStepCount, PxVehicleWheelsSimDataGeneratedValues)
+ struct PxVehicleWheelsSimDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleWheelsSimData"; }
+ PxWriteOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_ChassisMass, PxVehicleWheelsSimData, const PxF32 > ChassisMass;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_SuspensionData, PxVehicleWheelsSimData, const PxU32, PxVehicleSuspensionData > SuspensionData;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_WheelData, PxVehicleWheelsSimData, const PxU32, PxVehicleWheelData > WheelData;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_TireData, PxVehicleWheelsSimData, const PxU32, PxVehicleTireData > TireData;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_SuspTravelDirection, PxVehicleWheelsSimData, const PxU32, PxVec3 > SuspTravelDirection;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_SuspForceAppPointOffset, PxVehicleWheelsSimData, const PxU32, PxVec3 > SuspForceAppPointOffset;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_TireForceAppPointOffset, PxVehicleWheelsSimData, const PxU32, PxVec3 > TireForceAppPointOffset;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_WheelCentreOffset, PxVehicleWheelsSimData, const PxU32, PxVec3 > WheelCentreOffset;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_WheelShapeMapping, PxVehicleWheelsSimData, const PxU32, PxI32 > WheelShapeMapping;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_SceneQueryFilterData, PxVehicleWheelsSimData, const PxU32, PxFilterData > SceneQueryFilterData;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_AntiRollBarData, PxVehicleWheelsSimData, const PxU32, PxVehicleAntiRollBarData > AntiRollBarData;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_TireLoadFilterData, PxVehicleWheelsSimData, const PxVehicleTireLoadFilterData &, PxVehicleTireLoadFilterData > TireLoadFilterData;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_MinLongSlipDenominator, PxVehicleWheelsSimData, const PxReal, PxF32 > MinLongSlipDenominator;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_ThresholdLongSpeed, PxVehicleWheelsSimData, const PxF32, PxF32 > ThresholdLongSpeed;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_LowForwardSpeedSubStepCount, PxVehicleWheelsSimData, const PxU32, PxU32 > LowForwardSpeedSubStepCount;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_HighForwardSpeedSubStepCount, PxVehicleWheelsSimData, const PxU32, PxU32 > HighForwardSpeedSubStepCount;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsSimData_WheelEnabledState, PxVehicleWheelsSimData, const PxU32, _Bool > WheelEnabledState;
+
+ PxVehicleWheelsSimDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleWheelsSimData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 17; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( ChassisMass, inStartIndex + 0 );;
+ inOperator( SuspensionData, inStartIndex + 1 );;
+ inOperator( WheelData, inStartIndex + 2 );;
+ inOperator( TireData, inStartIndex + 3 );;
+ inOperator( SuspTravelDirection, inStartIndex + 4 );;
+ inOperator( SuspForceAppPointOffset, inStartIndex + 5 );;
+ inOperator( TireForceAppPointOffset, inStartIndex + 6 );;
+ inOperator( WheelCentreOffset, inStartIndex + 7 );;
+ inOperator( WheelShapeMapping, inStartIndex + 8 );;
+ inOperator( SceneQueryFilterData, inStartIndex + 9 );;
+ inOperator( AntiRollBarData, inStartIndex + 10 );;
+ inOperator( TireLoadFilterData, inStartIndex + 11 );;
+ inOperator( MinLongSlipDenominator, inStartIndex + 12 );;
+ inOperator( ThresholdLongSpeed, inStartIndex + 13 );;
+ inOperator( LowForwardSpeedSubStepCount, inStartIndex + 14 );;
+ inOperator( HighForwardSpeedSubStepCount, inStartIndex + 15 );;
+ inOperator( WheelEnabledState, inStartIndex + 16 );;
+ return 17 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleWheelsSimData>
+ {
+ PxVehicleWheelsSimDataGeneratedInfo Info;
+ const PxVehicleWheelsSimDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleWheelsDynData;
+ struct PxVehicleWheelsDynDataGeneratedValues
+ {
+ PxVehicleWheels4DynData * Wheel4DynData;
+ PxVehicleWheelsDynDataGeneratedValues( const PxVehicleWheelsDynData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheelsDynData, Wheel4DynData, PxVehicleWheelsDynDataGeneratedValues)
+ struct PxVehicleWheelsDynDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleWheelsDynData"; }
+ PxWriteOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsDynData_TireForceShaderFunction, PxVehicleWheelsDynData, PxVehicleComputeTireForce > TireForceShaderFunction;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsDynData_WheelRotationSpeed, PxVehicleWheelsDynData, const PxU32, PxReal > WheelRotationSpeed;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsDynData_WheelRotationAngle, PxVehicleWheelsDynData, const PxU32, PxReal > WheelRotationAngle;
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheelsDynData_Wheel4DynData, PxVehicleWheelsDynData, PxVehicleWheels4DynData * > Wheel4DynData;
+
+ PxVehicleWheelsDynDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleWheelsDynData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 4; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( TireForceShaderFunction, inStartIndex + 0 );;
+ inOperator( WheelRotationSpeed, inStartIndex + 1 );;
+ inOperator( WheelRotationAngle, inStartIndex + 2 );;
+ inOperator( Wheel4DynData, inStartIndex + 3 );;
+ return 4 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleWheelsDynData>
+ {
+ PxVehicleWheelsDynDataGeneratedInfo Info;
+ const PxVehicleWheelsDynDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleWheels;
+ struct PxVehicleWheelsGeneratedValues
+ {
+ PxU32 VehicleType;
+ const PxRigidDynamic * RigidDynamicActor;
+ const char * ConcreteTypeName;
+ PxVehicleWheelsSimData MWheelsSimData;
+ PxVehicleWheelsDynData MWheelsDynData;
+ PxVehicleWheelsGeneratedValues( const PxVehicleWheels* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheels, VehicleType, PxVehicleWheelsGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheels, RigidDynamicActor, PxVehicleWheelsGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheels, ConcreteTypeName, PxVehicleWheelsGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheels, MWheelsSimData, PxVehicleWheelsGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleWheels, MWheelsDynData, PxVehicleWheelsGeneratedValues)
+ struct PxVehicleWheelsGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleWheels"; }
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheels_VehicleType, PxVehicleWheels, PxU32 > VehicleType;
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheels_RigidDynamicActor, PxVehicleWheels, const PxRigidDynamic * > RigidDynamicActor;
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheels_ConcreteTypeName, PxVehicleWheels, const char * > ConcreteTypeName;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheels_MWheelsSimData, PxVehicleWheels, PxVehicleWheelsSimData, PxVehicleWheelsSimData > MWheelsSimData;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleWheels_MWheelsDynData, PxVehicleWheels, PxVehicleWheelsDynData, PxVehicleWheelsDynData > MWheelsDynData;
+
+ PxVehicleWheelsGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleWheels*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 5; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( VehicleType, inStartIndex + 0 );;
+ inOperator( RigidDynamicActor, inStartIndex + 1 );;
+ inOperator( ConcreteTypeName, inStartIndex + 2 );;
+ inOperator( MWheelsSimData, inStartIndex + 3 );;
+ inOperator( MWheelsDynData, inStartIndex + 4 );;
+ return 5 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleWheels>
+ {
+ PxVehicleWheelsGeneratedInfo Info;
+ const PxVehicleWheelsGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleDriveDynData;
+ struct PxVehicleDriveDynDataGeneratedValues
+ {
+ _Bool GearUp;
+ _Bool GearDown;
+ _Bool UseAutoGears;
+ PxU32 CurrentGear;
+ PxU32 TargetGear;
+ PxReal EngineRotationSpeed;
+ PxU32 GearChange;
+ PxReal GearSwitchTime;
+ PxReal AutoBoxSwitchTime;
+ _Bool MUseAutoGears;
+ _Bool MGearUpPressed;
+ _Bool MGearDownPressed;
+ PxU32 MCurrentGear;
+ PxU32 MTargetGear;
+ PxReal MEnginespeed;
+ PxReal MGearSwitchTime;
+ PxReal MAutoBoxSwitchTime;
+ PxVehicleDriveDynDataGeneratedValues( const PxVehicleDriveDynData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, GearUp, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, GearDown, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, UseAutoGears, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, CurrentGear, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, TargetGear, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, EngineRotationSpeed, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, GearChange, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, GearSwitchTime, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, AutoBoxSwitchTime, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, MUseAutoGears, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, MGearUpPressed, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, MGearDownPressed, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, MCurrentGear, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, MTargetGear, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, MEnginespeed, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, MGearSwitchTime, PxVehicleDriveDynDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveDynData, MAutoBoxSwitchTime, PxVehicleDriveDynDataGeneratedValues)
+ struct PxVehicleDriveDynDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleDriveDynData"; }
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_AnalogInput, PxVehicleDriveDynData, const PxU32, PxReal > AnalogInput;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_GearUp, PxVehicleDriveDynData, const _Bool, _Bool > GearUp;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_GearDown, PxVehicleDriveDynData, const _Bool, _Bool > GearDown;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_UseAutoGears, PxVehicleDriveDynData, const _Bool, _Bool > UseAutoGears;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_CurrentGear, PxVehicleDriveDynData, PxU32, PxU32 > CurrentGear;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_TargetGear, PxVehicleDriveDynData, PxU32, PxU32 > TargetGear;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_EngineRotationSpeed, PxVehicleDriveDynData, const PxF32, PxReal > EngineRotationSpeed;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_GearChange, PxVehicleDriveDynData, const PxU32, PxU32 > GearChange;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_GearSwitchTime, PxVehicleDriveDynData, const PxReal, PxReal > GearSwitchTime;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_AutoBoxSwitchTime, PxVehicleDriveDynData, const PxReal, PxReal > AutoBoxSwitchTime;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_MUseAutoGears, PxVehicleDriveDynData, _Bool, _Bool > MUseAutoGears;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_MGearUpPressed, PxVehicleDriveDynData, _Bool, _Bool > MGearUpPressed;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_MGearDownPressed, PxVehicleDriveDynData, _Bool, _Bool > MGearDownPressed;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_MCurrentGear, PxVehicleDriveDynData, PxU32, PxU32 > MCurrentGear;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_MTargetGear, PxVehicleDriveDynData, PxU32, PxU32 > MTargetGear;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_MEnginespeed, PxVehicleDriveDynData, PxReal, PxReal > MEnginespeed;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_MGearSwitchTime, PxVehicleDriveDynData, PxReal, PxReal > MGearSwitchTime;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveDynData_MAutoBoxSwitchTime, PxVehicleDriveDynData, PxReal, PxReal > MAutoBoxSwitchTime;
+
+ PxVehicleDriveDynDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleDriveDynData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 18; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( AnalogInput, inStartIndex + 0 );;
+ inOperator( GearUp, inStartIndex + 1 );;
+ inOperator( GearDown, inStartIndex + 2 );;
+ inOperator( UseAutoGears, inStartIndex + 3 );;
+ inOperator( CurrentGear, inStartIndex + 4 );;
+ inOperator( TargetGear, inStartIndex + 5 );;
+ inOperator( EngineRotationSpeed, inStartIndex + 6 );;
+ inOperator( GearChange, inStartIndex + 7 );;
+ inOperator( GearSwitchTime, inStartIndex + 8 );;
+ inOperator( AutoBoxSwitchTime, inStartIndex + 9 );;
+ inOperator( MUseAutoGears, inStartIndex + 10 );;
+ inOperator( MGearUpPressed, inStartIndex + 11 );;
+ inOperator( MGearDownPressed, inStartIndex + 12 );;
+ inOperator( MCurrentGear, inStartIndex + 13 );;
+ inOperator( MTargetGear, inStartIndex + 14 );;
+ inOperator( MEnginespeed, inStartIndex + 15 );;
+ inOperator( MGearSwitchTime, inStartIndex + 16 );;
+ inOperator( MAutoBoxSwitchTime, inStartIndex + 17 );;
+ return 18 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleDriveDynData>
+ {
+ PxVehicleDriveDynDataGeneratedInfo Info;
+ const PxVehicleDriveDynDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleDriveSimData;
+ struct PxVehicleDriveSimDataGeneratedValues
+ {
+ PxVehicleEngineData EngineData;
+ PxVehicleGearsData GearsData;
+ PxVehicleClutchData ClutchData;
+ PxVehicleAutoBoxData AutoBoxData;
+ PxVehicleDriveSimDataGeneratedValues( const PxVehicleDriveSimData* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveSimData, EngineData, PxVehicleDriveSimDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveSimData, GearsData, PxVehicleDriveSimDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveSimData, ClutchData, PxVehicleDriveSimDataGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveSimData, AutoBoxData, PxVehicleDriveSimDataGeneratedValues)
+ struct PxVehicleDriveSimDataGeneratedInfo
+
+ {
+ static const char* getClassName() { return "PxVehicleDriveSimData"; }
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveSimData_EngineData, PxVehicleDriveSimData, const PxVehicleEngineData &, PxVehicleEngineData > EngineData;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveSimData_GearsData, PxVehicleDriveSimData, const PxVehicleGearsData &, PxVehicleGearsData > GearsData;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveSimData_ClutchData, PxVehicleDriveSimData, const PxVehicleClutchData &, PxVehicleClutchData > ClutchData;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveSimData_AutoBoxData, PxVehicleDriveSimData, const PxVehicleAutoBoxData &, PxVehicleAutoBoxData > AutoBoxData;
+
+ PxVehicleDriveSimDataGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleDriveSimData*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 4; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( EngineData, inStartIndex + 0 );;
+ inOperator( GearsData, inStartIndex + 1 );;
+ inOperator( ClutchData, inStartIndex + 2 );;
+ inOperator( AutoBoxData, inStartIndex + 3 );;
+ return 4 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleDriveSimData>
+ {
+ PxVehicleDriveSimDataGeneratedInfo Info;
+ const PxVehicleDriveSimDataGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleDriveSimData4W;
+ struct PxVehicleDriveSimData4WGeneratedValues
+ : PxVehicleDriveSimDataGeneratedValues {
+ PxVehicleDifferential4WData DiffData;
+ PxVehicleAckermannGeometryData AckermannGeometryData;
+ PxVehicleDriveSimData4WGeneratedValues( const PxVehicleDriveSimData4W* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveSimData4W, DiffData, PxVehicleDriveSimData4WGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveSimData4W, AckermannGeometryData, PxVehicleDriveSimData4WGeneratedValues)
+ struct PxVehicleDriveSimData4WGeneratedInfo
+ : PxVehicleDriveSimDataGeneratedInfo
+ {
+ static const char* getClassName() { return "PxVehicleDriveSimData4W"; }
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveSimData4W_DiffData, PxVehicleDriveSimData4W, const PxVehicleDifferential4WData &, PxVehicleDifferential4WData > DiffData;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveSimData4W_AckermannGeometryData, PxVehicleDriveSimData4W, const PxVehicleAckermannGeometryData &, PxVehicleAckermannGeometryData > AckermannGeometryData;
+
+ PxVehicleDriveSimData4WGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleDriveSimData4W*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ inOperator( *static_cast<PxVehicleDriveSimDataGeneratedInfo*>( this ) );
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inStartIndex = PxVehicleDriveSimDataGeneratedInfo::visitBaseProperties( inOperator, inStartIndex );
+ inStartIndex = PxVehicleDriveSimDataGeneratedInfo::visitInstanceProperties( inOperator, inStartIndex );
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 2; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount()
+ + PxVehicleDriveSimDataGeneratedInfo::totalPropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( DiffData, inStartIndex + 0 );;
+ inOperator( AckermannGeometryData, inStartIndex + 1 );;
+ return 2 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleDriveSimData4W>
+ {
+ PxVehicleDriveSimData4WGeneratedInfo Info;
+ const PxVehicleDriveSimData4WGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleDrive;
+ struct PxVehicleDriveGeneratedValues
+ : PxVehicleWheelsGeneratedValues {
+ const char * ConcreteTypeName;
+ PxVehicleDriveDynData MDriveDynData;
+ PxVehicleDriveGeneratedValues( const PxVehicleDrive* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDrive, ConcreteTypeName, PxVehicleDriveGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDrive, MDriveDynData, PxVehicleDriveGeneratedValues)
+ struct PxVehicleDriveGeneratedInfo
+ : PxVehicleWheelsGeneratedInfo
+ {
+ static const char* getClassName() { return "PxVehicleDrive"; }
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDrive_ConcreteTypeName, PxVehicleDrive, const char * > ConcreteTypeName;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDrive_MDriveDynData, PxVehicleDrive, PxVehicleDriveDynData, PxVehicleDriveDynData > MDriveDynData;
+
+ PxVehicleDriveGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleDrive*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ inOperator( *static_cast<PxVehicleWheelsGeneratedInfo*>( this ) );
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inStartIndex = PxVehicleWheelsGeneratedInfo::visitBaseProperties( inOperator, inStartIndex );
+ inStartIndex = PxVehicleWheelsGeneratedInfo::visitInstanceProperties( inOperator, inStartIndex );
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 2; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount()
+ + PxVehicleWheelsGeneratedInfo::totalPropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( ConcreteTypeName, inStartIndex + 0 );;
+ inOperator( MDriveDynData, inStartIndex + 1 );;
+ return 2 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleDrive>
+ {
+ PxVehicleDriveGeneratedInfo Info;
+ const PxVehicleDriveGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleDrive4W;
+ struct PxVehicleDrive4WGeneratedValues
+ : PxVehicleDriveGeneratedValues {
+ const char * ConcreteTypeName;
+ PxVehicleDriveSimData4W MDriveSimData;
+ PxVehicleDrive4WGeneratedValues( const PxVehicleDrive4W* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDrive4W, ConcreteTypeName, PxVehicleDrive4WGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDrive4W, MDriveSimData, PxVehicleDrive4WGeneratedValues)
+ struct PxVehicleDrive4WGeneratedInfo
+ : PxVehicleDriveGeneratedInfo
+ {
+ static const char* getClassName() { return "PxVehicleDrive4W"; }
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDrive4W_ConcreteTypeName, PxVehicleDrive4W, const char * > ConcreteTypeName;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDrive4W_MDriveSimData, PxVehicleDrive4W, PxVehicleDriveSimData4W, PxVehicleDriveSimData4W > MDriveSimData;
+
+ PxVehicleDrive4WGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleDrive4W*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ inOperator( *static_cast<PxVehicleDriveGeneratedInfo*>( this ) );
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inStartIndex = PxVehicleDriveGeneratedInfo::visitBaseProperties( inOperator, inStartIndex );
+ inStartIndex = PxVehicleDriveGeneratedInfo::visitInstanceProperties( inOperator, inStartIndex );
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 2; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount()
+ + PxVehicleDriveGeneratedInfo::totalPropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( ConcreteTypeName, inStartIndex + 0 );;
+ inOperator( MDriveSimData, inStartIndex + 1 );;
+ return 2 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleDrive4W>
+ {
+ PxVehicleDrive4WGeneratedInfo Info;
+ const PxVehicleDrive4WGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ static PxU32ToName g_physx__PxVehicleDriveTankControlModel__EnumConversion[] = {
+ { "eSTANDARD", static_cast<PxU32>( physx::PxVehicleDriveTankControlModel::eSTANDARD ) },
+ { "eSPECIAL", static_cast<PxU32>( physx::PxVehicleDriveTankControlModel::eSPECIAL ) },
+ { NULL, 0 }
+ };
+
+template<> struct PxEnumTraits< physx::PxVehicleDriveTankControlModel::Enum > { PxEnumTraits() : NameConversion( g_physx__PxVehicleDriveTankControlModel__EnumConversion ) {} const PxU32ToName* NameConversion; };
+ class PxVehicleDriveTank;
+ struct PxVehicleDriveTankGeneratedValues
+ : PxVehicleDriveGeneratedValues {
+ PxVehicleDriveTankControlModel::Enum DriveModel;
+ const char * ConcreteTypeName;
+ PxVehicleDriveSimData MDriveSimData;
+ PxVehicleDriveTankGeneratedValues( const PxVehicleDriveTank* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveTank, DriveModel, PxVehicleDriveTankGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveTank, ConcreteTypeName, PxVehicleDriveTankGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveTank, MDriveSimData, PxVehicleDriveTankGeneratedValues)
+ struct PxVehicleDriveTankGeneratedInfo
+ : PxVehicleDriveGeneratedInfo
+ {
+ static const char* getClassName() { return "PxVehicleDriveTank"; }
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveTank_DriveModel, PxVehicleDriveTank, const PxVehicleDriveTankControlModel::Enum, PxVehicleDriveTankControlModel::Enum > DriveModel;
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveTank_ConcreteTypeName, PxVehicleDriveTank, const char * > ConcreteTypeName;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveTank_MDriveSimData, PxVehicleDriveTank, PxVehicleDriveSimData, PxVehicleDriveSimData > MDriveSimData;
+
+ PxVehicleDriveTankGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleDriveTank*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ inOperator( *static_cast<PxVehicleDriveGeneratedInfo*>( this ) );
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inStartIndex = PxVehicleDriveGeneratedInfo::visitBaseProperties( inOperator, inStartIndex );
+ inStartIndex = PxVehicleDriveGeneratedInfo::visitInstanceProperties( inOperator, inStartIndex );
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 3; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount()
+ + PxVehicleDriveGeneratedInfo::totalPropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( DriveModel, inStartIndex + 0 );;
+ inOperator( ConcreteTypeName, inStartIndex + 1 );;
+ inOperator( MDriveSimData, inStartIndex + 2 );;
+ return 3 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleDriveTank>
+ {
+ PxVehicleDriveTankGeneratedInfo Info;
+ const PxVehicleDriveTankGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleDriveSimDataNW;
+ struct PxVehicleDriveSimDataNWGeneratedValues
+ : PxVehicleDriveSimDataGeneratedValues {
+ PxVehicleDifferentialNWData DiffData;
+ PxVehicleDriveSimDataNWGeneratedValues( const PxVehicleDriveSimDataNW* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveSimDataNW, DiffData, PxVehicleDriveSimDataNWGeneratedValues)
+ struct PxVehicleDriveSimDataNWGeneratedInfo
+ : PxVehicleDriveSimDataGeneratedInfo
+ {
+ static const char* getClassName() { return "PxVehicleDriveSimDataNW"; }
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveSimDataNW_DiffData, PxVehicleDriveSimDataNW, const PxVehicleDifferentialNWData &, PxVehicleDifferentialNWData > DiffData;
+
+ PxVehicleDriveSimDataNWGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleDriveSimDataNW*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ inOperator( *static_cast<PxVehicleDriveSimDataGeneratedInfo*>( this ) );
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inStartIndex = PxVehicleDriveSimDataGeneratedInfo::visitBaseProperties( inOperator, inStartIndex );
+ inStartIndex = PxVehicleDriveSimDataGeneratedInfo::visitInstanceProperties( inOperator, inStartIndex );
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 1; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount()
+ + PxVehicleDriveSimDataGeneratedInfo::totalPropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( DiffData, inStartIndex + 0 );;
+ return 1 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleDriveSimDataNW>
+ {
+ PxVehicleDriveSimDataNWGeneratedInfo Info;
+ const PxVehicleDriveSimDataNWGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleDriveNW;
+ struct PxVehicleDriveNWGeneratedValues
+ : PxVehicleDriveGeneratedValues {
+ const char * ConcreteTypeName;
+ PxVehicleDriveSimDataNW MDriveSimData;
+ PxVehicleDriveNWGeneratedValues( const PxVehicleDriveNW* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveNW, ConcreteTypeName, PxVehicleDriveNWGeneratedValues)
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleDriveNW, MDriveSimData, PxVehicleDriveNWGeneratedValues)
+ struct PxVehicleDriveNWGeneratedInfo
+ : PxVehicleDriveGeneratedInfo
+ {
+ static const char* getClassName() { return "PxVehicleDriveNW"; }
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveNW_ConcreteTypeName, PxVehicleDriveNW, const char * > ConcreteTypeName;
+ PxPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleDriveNW_MDriveSimData, PxVehicleDriveNW, PxVehicleDriveSimDataNW, PxVehicleDriveSimDataNW > MDriveSimData;
+
+ PxVehicleDriveNWGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleDriveNW*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ inOperator( *static_cast<PxVehicleDriveGeneratedInfo*>( this ) );
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inStartIndex = PxVehicleDriveGeneratedInfo::visitBaseProperties( inOperator, inStartIndex );
+ inStartIndex = PxVehicleDriveGeneratedInfo::visitInstanceProperties( inOperator, inStartIndex );
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 2; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount()
+ + PxVehicleDriveGeneratedInfo::totalPropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( ConcreteTypeName, inStartIndex + 0 );;
+ inOperator( MDriveSimData, inStartIndex + 1 );;
+ return 2 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleDriveNW>
+ {
+ PxVehicleDriveNWGeneratedInfo Info;
+ const PxVehicleDriveNWGeneratedInfo* getInfo() { return &Info; }
+ };
+
+ class PxVehicleNoDrive;
+ struct PxVehicleNoDriveGeneratedValues
+ : PxVehicleWheelsGeneratedValues {
+ const char * ConcreteTypeName;
+ PxVehicleNoDriveGeneratedValues( const PxVehicleNoDrive* inSource );
+ };
+ DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( PxVehicleNoDrive, ConcreteTypeName, PxVehicleNoDriveGeneratedValues)
+ struct PxVehicleNoDriveGeneratedInfo
+ : PxVehicleWheelsGeneratedInfo
+ {
+ static const char* getClassName() { return "PxVehicleNoDrive"; }
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleNoDrive_BrakeTorque, PxVehicleNoDrive, const PxU32, PxReal > BrakeTorque;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleNoDrive_DriveTorque, PxVehicleNoDrive, const PxU32, PxReal > DriveTorque;
+ PxExtendedIndexedPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleNoDrive_SteerAngle, PxVehicleNoDrive, const PxU32, PxReal > SteerAngle;
+ PxReadOnlyPropertyInfo<PX_PROPERTY_INFO_NAME::PxVehicleNoDrive_ConcreteTypeName, PxVehicleNoDrive, const char * > ConcreteTypeName;
+
+ PxVehicleNoDriveGeneratedInfo();
+ template<typename TReturnType, typename TOperator>
+ TReturnType visitType( TOperator inOperator ) const
+ {
+ return inOperator( reinterpret_cast<PxVehicleNoDrive*>(NULL) );
+ }
+ template<typename TOperator>
+ void visitBases( TOperator inOperator )
+ {
+ PX_UNUSED(inOperator);
+ inOperator( *static_cast<PxVehicleWheelsGeneratedInfo*>( this ) );
+ }
+ template<typename TOperator>
+ PxU32 visitBaseProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inStartIndex = PxVehicleWheelsGeneratedInfo::visitBaseProperties( inOperator, inStartIndex );
+ inStartIndex = PxVehicleWheelsGeneratedInfo::visitInstanceProperties( inOperator, inStartIndex );
+ return inStartIndex;
+ }
+ static PxU32 instancePropertyCount() { return 4; }
+ static PxU32 totalPropertyCount() { return instancePropertyCount()
+ + PxVehicleWheelsGeneratedInfo::totalPropertyCount(); }
+ template<typename TOperator>
+ PxU32 visitInstanceProperties( TOperator inOperator, PxU32 inStartIndex = 0 ) const
+ {
+ PX_UNUSED(inOperator);
+ PX_UNUSED(inStartIndex);
+ inOperator( BrakeTorque, inStartIndex + 0 );;
+ inOperator( DriveTorque, inStartIndex + 1 );;
+ inOperator( SteerAngle, inStartIndex + 2 );;
+ inOperator( ConcreteTypeName, inStartIndex + 3 );;
+ return 4 + inStartIndex;
+ }
+ };
+ template<> struct PxClassInfoTraits<PxVehicleNoDrive>
+ {
+ PxVehicleNoDriveGeneratedInfo Info;
+ const PxVehicleNoDriveGeneratedInfo* getInfo() { return &Info; }
+ };
+
+
+
+#undef THERE_IS_NO_INCLUDE_GUARD_HERE_FOR_A_REASON
+#undef PX_PROPERTY_INFO_NAME
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleMetaDataObjects.h b/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleMetaDataObjects.h
new file mode 100644
index 00000000..77e92e2c
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/include/PxVehicleMetaDataObjects.h
@@ -0,0 +1,86 @@
+// 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 PX_VEHICLE_METADATAOBJECTS_H
+#define PX_VEHICLE_METADATAOBJECTS_H
+#include "PxPhysicsAPI.h"
+#include "extensions/PxExtensionsAPI.h"
+#include "PxMetaDataObjects.h"
+#include "PxExtensionMetaDataObjects.h"
+
+/** \addtogroup physics
+@{
+*/
+
+namespace physx
+{
+
+struct PxVehiclePropertyInfoName
+{
+ enum Enum
+ {
+ Unnamed = PxExtensionsPropertyInfoName::LastPxPropertyInfoName,
+#include "PxVehicleAutoGeneratedMetaDataObjectNames.h"
+ LastPxPropertyInfoName
+ };
+};
+
+#define DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP( type, prop, valueStruct ) \
+ template<> struct PxPropertyToValueStructMemberMap< PxVehiclePropertyInfoName::type##_##prop > \
+ { \
+ PxU32 Offset; \
+ PxPropertyToValueStructMemberMap< PxVehiclePropertyInfoName::type##_##prop >() : Offset( PX_OFFSET_OF_RT( valueStruct, prop ) ) {} \
+ template<typename TOperator> void visitProp( TOperator inOperator, valueStruct& inStruct ) { inOperator( inStruct.prop ); } \
+ };
+
+struct MFrictionVsSlipGraphProperty : public PxExtendedDualIndexedPropertyInfo<PxVehiclePropertyInfoName::PxVehicleTireData_MFrictionVsSlipGraph
+ , PxVehicleTireData
+ , PxU32
+ , PxU32
+ , PxReal>
+{
+ PX_PHYSX_CORE_API MFrictionVsSlipGraphProperty();
+};
+
+struct MTorqueCurveProperty : public PxFixedSizeLookupTablePropertyInfo<PxVehiclePropertyInfoName::PxVehicleEngineData_MTorqueCurve
+ , PxVehicleEngineData
+ , PxU32
+ , PxReal>
+{
+ PX_PHYSX_CORE_API MTorqueCurveProperty();
+};
+
+#include "PxVehicleAutoGeneratedMetaDataObjects.h"
+
+#undef DEFINE_PROPERTY_TO_VALUE_STRUCT_MAP
+
+}
+
+/** @} */
+#endif
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/src/PxVehicleAutoGeneratedMetaDataObjects.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/src/PxVehicleAutoGeneratedMetaDataObjects.cpp
new file mode 100644
index 00000000..7dff2130
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/src/PxVehicleAutoGeneratedMetaDataObjects.cpp
@@ -0,0 +1,728 @@
+// 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.
+
+// This code is auto-generated by the PhysX Clang metadata generator. Do not edit or be
+// prepared for your edits to be quietly ignored next time the clang metadata generator is
+// run. You can find the most recent version of clang metadata generator by contacting
+// Chris Nuernberger <[email protected]> or Dilip or Adam.
+// The source code for the generate was at one time checked into:
+// physx/PhysXMetaDataGenerator/llvm/tools/clang/lib/Frontend/PhysXMetaDataAction.cpp
+#include "PxVehicleMetaDataObjects.h"
+#include "PxPhysicsAPI.h"
+#include "PxMetaDataCppPrefix.h"
+#include "PxVehicleSuspWheelTire4.h"
+using namespace physx;
+inline PxVec3 getPxVehicleChassisDataMMOI( const PxVehicleChassisData* inOwner ) { return inOwner->mMOI; }
+inline void setPxVehicleChassisDataMMOI( PxVehicleChassisData* inOwner, PxVec3 inData) { inOwner->mMOI = inData; }
+inline PxReal getPxVehicleChassisDataMMass( const PxVehicleChassisData* inOwner ) { return inOwner->mMass; }
+inline void setPxVehicleChassisDataMMass( PxVehicleChassisData* inOwner, PxReal inData) { inOwner->mMass = inData; }
+inline PxVec3 getPxVehicleChassisDataMCMOffset( const PxVehicleChassisData* inOwner ) { return inOwner->mCMOffset; }
+inline void setPxVehicleChassisDataMCMOffset( PxVehicleChassisData* inOwner, PxVec3 inData) { inOwner->mCMOffset = inData; }
+ PxVehicleChassisDataGeneratedInfo::PxVehicleChassisDataGeneratedInfo()
+ : MMOI( "MMOI", setPxVehicleChassisDataMMOI, getPxVehicleChassisDataMMOI )
+ , MMass( "MMass", setPxVehicleChassisDataMMass, getPxVehicleChassisDataMMass )
+ , MCMOffset( "MCMOffset", setPxVehicleChassisDataMCMOffset, getPxVehicleChassisDataMCMOffset )
+{}
+ PxVehicleChassisDataGeneratedValues::PxVehicleChassisDataGeneratedValues( const PxVehicleChassisData* inSource )
+ :MMOI( inSource->mMOI )
+ ,MMass( inSource->mMass )
+ ,MCMOffset( inSource->mCMOffset )
+{
+ PX_UNUSED(inSource);
+}
+PxReal getPxVehicleEngineData_RecipMOI( const PxVehicleEngineData* inObj ) { return inObj->getRecipMOI(); }
+PxReal getPxVehicleEngineData_RecipMaxOmega( const PxVehicleEngineData* inObj ) { return inObj->getRecipMaxOmega(); }
+inline PxReal getPxVehicleEngineDataMMOI( const PxVehicleEngineData* inOwner ) { return inOwner->mMOI; }
+inline void setPxVehicleEngineDataMMOI( PxVehicleEngineData* inOwner, PxReal inData) { inOwner->mMOI = inData; }
+inline PxReal getPxVehicleEngineDataMPeakTorque( const PxVehicleEngineData* inOwner ) { return inOwner->mPeakTorque; }
+inline void setPxVehicleEngineDataMPeakTorque( PxVehicleEngineData* inOwner, PxReal inData) { inOwner->mPeakTorque = inData; }
+inline PxReal getPxVehicleEngineDataMMaxOmega( const PxVehicleEngineData* inOwner ) { return inOwner->mMaxOmega; }
+inline void setPxVehicleEngineDataMMaxOmega( PxVehicleEngineData* inOwner, PxReal inData) { inOwner->mMaxOmega = inData; }
+inline PxReal getPxVehicleEngineDataMDampingRateFullThrottle( const PxVehicleEngineData* inOwner ) { return inOwner->mDampingRateFullThrottle; }
+inline void setPxVehicleEngineDataMDampingRateFullThrottle( PxVehicleEngineData* inOwner, PxReal inData) { inOwner->mDampingRateFullThrottle = inData; }
+inline PxReal getPxVehicleEngineDataMDampingRateZeroThrottleClutchEngaged( const PxVehicleEngineData* inOwner ) { return inOwner->mDampingRateZeroThrottleClutchEngaged; }
+inline void setPxVehicleEngineDataMDampingRateZeroThrottleClutchEngaged( PxVehicleEngineData* inOwner, PxReal inData) { inOwner->mDampingRateZeroThrottleClutchEngaged = inData; }
+inline PxReal getPxVehicleEngineDataMDampingRateZeroThrottleClutchDisengaged( const PxVehicleEngineData* inOwner ) { return inOwner->mDampingRateZeroThrottleClutchDisengaged; }
+inline void setPxVehicleEngineDataMDampingRateZeroThrottleClutchDisengaged( PxVehicleEngineData* inOwner, PxReal inData) { inOwner->mDampingRateZeroThrottleClutchDisengaged = inData; }
+ PxVehicleEngineDataGeneratedInfo::PxVehicleEngineDataGeneratedInfo()
+ : RecipMOI( "RecipMOI", getPxVehicleEngineData_RecipMOI)
+ , RecipMaxOmega( "RecipMaxOmega", getPxVehicleEngineData_RecipMaxOmega)
+ , MMOI( "MMOI", setPxVehicleEngineDataMMOI, getPxVehicleEngineDataMMOI )
+ , MPeakTorque( "MPeakTorque", setPxVehicleEngineDataMPeakTorque, getPxVehicleEngineDataMPeakTorque )
+ , MMaxOmega( "MMaxOmega", setPxVehicleEngineDataMMaxOmega, getPxVehicleEngineDataMMaxOmega )
+ , MDampingRateFullThrottle( "MDampingRateFullThrottle", setPxVehicleEngineDataMDampingRateFullThrottle, getPxVehicleEngineDataMDampingRateFullThrottle )
+ , MDampingRateZeroThrottleClutchEngaged( "MDampingRateZeroThrottleClutchEngaged", setPxVehicleEngineDataMDampingRateZeroThrottleClutchEngaged, getPxVehicleEngineDataMDampingRateZeroThrottleClutchEngaged )
+ , MDampingRateZeroThrottleClutchDisengaged( "MDampingRateZeroThrottleClutchDisengaged", setPxVehicleEngineDataMDampingRateZeroThrottleClutchDisengaged, getPxVehicleEngineDataMDampingRateZeroThrottleClutchDisengaged )
+{}
+ PxVehicleEngineDataGeneratedValues::PxVehicleEngineDataGeneratedValues( const PxVehicleEngineData* inSource )
+ :RecipMOI( getPxVehicleEngineData_RecipMOI( inSource ) )
+ ,RecipMaxOmega( getPxVehicleEngineData_RecipMaxOmega( inSource ) )
+ ,MMOI( inSource->mMOI )
+ ,MPeakTorque( inSource->mPeakTorque )
+ ,MMaxOmega( inSource->mMaxOmega )
+ ,MDampingRateFullThrottle( inSource->mDampingRateFullThrottle )
+ ,MDampingRateZeroThrottleClutchEngaged( inSource->mDampingRateZeroThrottleClutchEngaged )
+ ,MDampingRateZeroThrottleClutchDisengaged( inSource->mDampingRateZeroThrottleClutchDisengaged )
+{
+ PX_UNUSED(inSource);
+}
+void setPxVehicleGearsData_GearRatio( PxVehicleGearsData* inObj, PxVehicleGearsData::Enum inIndex, PxReal inArg ){ inObj->setGearRatio( inIndex, inArg ); }
+PxReal getPxVehicleGearsData_GearRatio( const PxVehicleGearsData* inObj, PxVehicleGearsData::Enum inIndex ) { return inObj->getGearRatio( inIndex ); }
+inline PxReal getPxVehicleGearsDataMFinalRatio( const PxVehicleGearsData* inOwner ) { return inOwner->mFinalRatio; }
+inline void setPxVehicleGearsDataMFinalRatio( PxVehicleGearsData* inOwner, PxReal inData) { inOwner->mFinalRatio = inData; }
+inline PxU32 getPxVehicleGearsDataMNbRatios( const PxVehicleGearsData* inOwner ) { return inOwner->mNbRatios; }
+inline void setPxVehicleGearsDataMNbRatios( PxVehicleGearsData* inOwner, PxU32 inData) { inOwner->mNbRatios = inData; }
+inline PxReal getPxVehicleGearsDataMSwitchTime( const PxVehicleGearsData* inOwner ) { return inOwner->mSwitchTime; }
+inline void setPxVehicleGearsDataMSwitchTime( PxVehicleGearsData* inOwner, PxReal inData) { inOwner->mSwitchTime = inData; }
+ PxVehicleGearsDataGeneratedInfo::PxVehicleGearsDataGeneratedInfo()
+ : GearRatio( "GearRatio", setPxVehicleGearsData_GearRatio, getPxVehicleGearsData_GearRatio)
+ , MFinalRatio( "MFinalRatio", setPxVehicleGearsDataMFinalRatio, getPxVehicleGearsDataMFinalRatio )
+ , MNbRatios( "MNbRatios", setPxVehicleGearsDataMNbRatios, getPxVehicleGearsDataMNbRatios )
+ , MSwitchTime( "MSwitchTime", setPxVehicleGearsDataMSwitchTime, getPxVehicleGearsDataMSwitchTime )
+{}
+ PxVehicleGearsDataGeneratedValues::PxVehicleGearsDataGeneratedValues( const PxVehicleGearsData* inSource )
+ :MFinalRatio( inSource->mFinalRatio )
+ ,MNbRatios( inSource->mNbRatios )
+ ,MSwitchTime( inSource->mSwitchTime )
+{
+ PX_UNUSED(inSource);
+ for ( PxU32 idx = 0; idx < static_cast<PxU32>( physx::PxVehicleGearsData::eGEARSRATIO_COUNT ); ++idx )
+ GearRatio[idx] = getPxVehicleGearsData_GearRatio( inSource, static_cast< PxVehicleGearsData::Enum >( idx ) );
+}
+void setPxVehicleAutoBoxData_Latency( PxVehicleAutoBoxData* inObj, const PxReal inArg){ inObj->setLatency( inArg ); }
+PxReal getPxVehicleAutoBoxData_Latency( const PxVehicleAutoBoxData* inObj ) { return inObj->getLatency(); }
+void setPxVehicleAutoBoxData_UpRatios( PxVehicleAutoBoxData* inObj, PxVehicleGearsData::Enum inIndex, PxReal inArg ){ inObj->setUpRatios( inIndex, inArg ); }
+PxReal getPxVehicleAutoBoxData_UpRatios( const PxVehicleAutoBoxData* inObj, PxVehicleGearsData::Enum inIndex ) { return inObj->getUpRatios( inIndex ); }
+void setPxVehicleAutoBoxData_DownRatios( PxVehicleAutoBoxData* inObj, PxVehicleGearsData::Enum inIndex, PxReal inArg ){ inObj->setDownRatios( inIndex, inArg ); }
+PxReal getPxVehicleAutoBoxData_DownRatios( const PxVehicleAutoBoxData* inObj, PxVehicleGearsData::Enum inIndex ) { return inObj->getDownRatios( inIndex ); }
+ PxVehicleAutoBoxDataGeneratedInfo::PxVehicleAutoBoxDataGeneratedInfo()
+ : Latency( "Latency", setPxVehicleAutoBoxData_Latency, getPxVehicleAutoBoxData_Latency)
+ , UpRatios( "UpRatios", setPxVehicleAutoBoxData_UpRatios, getPxVehicleAutoBoxData_UpRatios)
+ , DownRatios( "DownRatios", setPxVehicleAutoBoxData_DownRatios, getPxVehicleAutoBoxData_DownRatios)
+{}
+ PxVehicleAutoBoxDataGeneratedValues::PxVehicleAutoBoxDataGeneratedValues( const PxVehicleAutoBoxData* inSource )
+ :Latency( getPxVehicleAutoBoxData_Latency( inSource ) )
+{
+ PX_UNUSED(inSource);
+ for ( PxU32 idx = 0; idx < static_cast<PxU32>( physx::PxVehicleGearsData::eGEARSRATIO_COUNT ); ++idx )
+ UpRatios[idx] = getPxVehicleAutoBoxData_UpRatios( inSource, static_cast< PxVehicleGearsData::Enum >( idx ) );
+ for ( PxU32 idx = 0; idx < static_cast<PxU32>( physx::PxVehicleGearsData::eGEARSRATIO_COUNT ); ++idx )
+ DownRatios[idx] = getPxVehicleAutoBoxData_DownRatios( inSource, static_cast< PxVehicleGearsData::Enum >( idx ) );
+}
+inline PxReal getPxVehicleDifferential4WDataMFrontRearSplit( const PxVehicleDifferential4WData* inOwner ) { return inOwner->mFrontRearSplit; }
+inline void setPxVehicleDifferential4WDataMFrontRearSplit( PxVehicleDifferential4WData* inOwner, PxReal inData) { inOwner->mFrontRearSplit = inData; }
+inline PxReal getPxVehicleDifferential4WDataMFrontLeftRightSplit( const PxVehicleDifferential4WData* inOwner ) { return inOwner->mFrontLeftRightSplit; }
+inline void setPxVehicleDifferential4WDataMFrontLeftRightSplit( PxVehicleDifferential4WData* inOwner, PxReal inData) { inOwner->mFrontLeftRightSplit = inData; }
+inline PxReal getPxVehicleDifferential4WDataMRearLeftRightSplit( const PxVehicleDifferential4WData* inOwner ) { return inOwner->mRearLeftRightSplit; }
+inline void setPxVehicleDifferential4WDataMRearLeftRightSplit( PxVehicleDifferential4WData* inOwner, PxReal inData) { inOwner->mRearLeftRightSplit = inData; }
+inline PxReal getPxVehicleDifferential4WDataMCentreBias( const PxVehicleDifferential4WData* inOwner ) { return inOwner->mCentreBias; }
+inline void setPxVehicleDifferential4WDataMCentreBias( PxVehicleDifferential4WData* inOwner, PxReal inData) { inOwner->mCentreBias = inData; }
+inline PxReal getPxVehicleDifferential4WDataMFrontBias( const PxVehicleDifferential4WData* inOwner ) { return inOwner->mFrontBias; }
+inline void setPxVehicleDifferential4WDataMFrontBias( PxVehicleDifferential4WData* inOwner, PxReal inData) { inOwner->mFrontBias = inData; }
+inline PxReal getPxVehicleDifferential4WDataMRearBias( const PxVehicleDifferential4WData* inOwner ) { return inOwner->mRearBias; }
+inline void setPxVehicleDifferential4WDataMRearBias( PxVehicleDifferential4WData* inOwner, PxReal inData) { inOwner->mRearBias = inData; }
+inline PxVehicleDifferential4WData::Enum getPxVehicleDifferential4WDataMType( const PxVehicleDifferential4WData* inOwner ) { return inOwner->mType; }
+inline void setPxVehicleDifferential4WDataMType( PxVehicleDifferential4WData* inOwner, PxVehicleDifferential4WData::Enum inData) { inOwner->mType = inData; }
+ PxVehicleDifferential4WDataGeneratedInfo::PxVehicleDifferential4WDataGeneratedInfo()
+ : MFrontRearSplit( "MFrontRearSplit", setPxVehicleDifferential4WDataMFrontRearSplit, getPxVehicleDifferential4WDataMFrontRearSplit )
+ , MFrontLeftRightSplit( "MFrontLeftRightSplit", setPxVehicleDifferential4WDataMFrontLeftRightSplit, getPxVehicleDifferential4WDataMFrontLeftRightSplit )
+ , MRearLeftRightSplit( "MRearLeftRightSplit", setPxVehicleDifferential4WDataMRearLeftRightSplit, getPxVehicleDifferential4WDataMRearLeftRightSplit )
+ , MCentreBias( "MCentreBias", setPxVehicleDifferential4WDataMCentreBias, getPxVehicleDifferential4WDataMCentreBias )
+ , MFrontBias( "MFrontBias", setPxVehicleDifferential4WDataMFrontBias, getPxVehicleDifferential4WDataMFrontBias )
+ , MRearBias( "MRearBias", setPxVehicleDifferential4WDataMRearBias, getPxVehicleDifferential4WDataMRearBias )
+ , MType( "MType", setPxVehicleDifferential4WDataMType, getPxVehicleDifferential4WDataMType )
+{}
+ PxVehicleDifferential4WDataGeneratedValues::PxVehicleDifferential4WDataGeneratedValues( const PxVehicleDifferential4WData* inSource )
+ :MFrontRearSplit( inSource->mFrontRearSplit )
+ ,MFrontLeftRightSplit( inSource->mFrontLeftRightSplit )
+ ,MRearLeftRightSplit( inSource->mRearLeftRightSplit )
+ ,MCentreBias( inSource->mCentreBias )
+ ,MFrontBias( inSource->mFrontBias )
+ ,MRearBias( inSource->mRearBias )
+ ,MType( inSource->mType )
+{
+ PX_UNUSED(inSource);
+}
+void setPxVehicleDifferentialNWData_DrivenWheelStatus( PxVehicleDifferentialNWData* inObj, PxU32 inArg){ inObj->setDrivenWheelStatus( inArg ); }
+PxU32 getPxVehicleDifferentialNWData_DrivenWheelStatus( const PxVehicleDifferentialNWData* inObj ) { return inObj->getDrivenWheelStatus(); }
+ PxVehicleDifferentialNWDataGeneratedInfo::PxVehicleDifferentialNWDataGeneratedInfo()
+ : DrivenWheelStatus( "DrivenWheelStatus", setPxVehicleDifferentialNWData_DrivenWheelStatus, getPxVehicleDifferentialNWData_DrivenWheelStatus)
+{}
+ PxVehicleDifferentialNWDataGeneratedValues::PxVehicleDifferentialNWDataGeneratedValues( const PxVehicleDifferentialNWData* inSource )
+ :DrivenWheelStatus( getPxVehicleDifferentialNWData_DrivenWheelStatus( inSource ) )
+{
+ PX_UNUSED(inSource);
+}
+inline PxReal getPxVehicleAckermannGeometryDataMAccuracy( const PxVehicleAckermannGeometryData* inOwner ) { return inOwner->mAccuracy; }
+inline void setPxVehicleAckermannGeometryDataMAccuracy( PxVehicleAckermannGeometryData* inOwner, PxReal inData) { inOwner->mAccuracy = inData; }
+inline PxReal getPxVehicleAckermannGeometryDataMFrontWidth( const PxVehicleAckermannGeometryData* inOwner ) { return inOwner->mFrontWidth; }
+inline void setPxVehicleAckermannGeometryDataMFrontWidth( PxVehicleAckermannGeometryData* inOwner, PxReal inData) { inOwner->mFrontWidth = inData; }
+inline PxReal getPxVehicleAckermannGeometryDataMRearWidth( const PxVehicleAckermannGeometryData* inOwner ) { return inOwner->mRearWidth; }
+inline void setPxVehicleAckermannGeometryDataMRearWidth( PxVehicleAckermannGeometryData* inOwner, PxReal inData) { inOwner->mRearWidth = inData; }
+inline PxReal getPxVehicleAckermannGeometryDataMAxleSeparation( const PxVehicleAckermannGeometryData* inOwner ) { return inOwner->mAxleSeparation; }
+inline void setPxVehicleAckermannGeometryDataMAxleSeparation( PxVehicleAckermannGeometryData* inOwner, PxReal inData) { inOwner->mAxleSeparation = inData; }
+ PxVehicleAckermannGeometryDataGeneratedInfo::PxVehicleAckermannGeometryDataGeneratedInfo()
+ : MAccuracy( "MAccuracy", setPxVehicleAckermannGeometryDataMAccuracy, getPxVehicleAckermannGeometryDataMAccuracy )
+ , MFrontWidth( "MFrontWidth", setPxVehicleAckermannGeometryDataMFrontWidth, getPxVehicleAckermannGeometryDataMFrontWidth )
+ , MRearWidth( "MRearWidth", setPxVehicleAckermannGeometryDataMRearWidth, getPxVehicleAckermannGeometryDataMRearWidth )
+ , MAxleSeparation( "MAxleSeparation", setPxVehicleAckermannGeometryDataMAxleSeparation, getPxVehicleAckermannGeometryDataMAxleSeparation )
+{}
+ PxVehicleAckermannGeometryDataGeneratedValues::PxVehicleAckermannGeometryDataGeneratedValues( const PxVehicleAckermannGeometryData* inSource )
+ :MAccuracy( inSource->mAccuracy )
+ ,MFrontWidth( inSource->mFrontWidth )
+ ,MRearWidth( inSource->mRearWidth )
+ ,MAxleSeparation( inSource->mAxleSeparation )
+{
+ PX_UNUSED(inSource);
+}
+inline PxReal getPxVehicleClutchDataMStrength( const PxVehicleClutchData* inOwner ) { return inOwner->mStrength; }
+inline void setPxVehicleClutchDataMStrength( PxVehicleClutchData* inOwner, PxReal inData) { inOwner->mStrength = inData; }
+inline PxVehicleClutchAccuracyMode::Enum getPxVehicleClutchDataMAccuracyMode( const PxVehicleClutchData* inOwner ) { return inOwner->mAccuracyMode; }
+inline void setPxVehicleClutchDataMAccuracyMode( PxVehicleClutchData* inOwner, PxVehicleClutchAccuracyMode::Enum inData) { inOwner->mAccuracyMode = inData; }
+inline PxU32 getPxVehicleClutchDataMEstimateIterations( const PxVehicleClutchData* inOwner ) { return inOwner->mEstimateIterations; }
+inline void setPxVehicleClutchDataMEstimateIterations( PxVehicleClutchData* inOwner, PxU32 inData) { inOwner->mEstimateIterations = inData; }
+ PxVehicleClutchDataGeneratedInfo::PxVehicleClutchDataGeneratedInfo()
+ : MStrength( "MStrength", setPxVehicleClutchDataMStrength, getPxVehicleClutchDataMStrength )
+ , MAccuracyMode( "MAccuracyMode", setPxVehicleClutchDataMAccuracyMode, getPxVehicleClutchDataMAccuracyMode )
+ , MEstimateIterations( "MEstimateIterations", setPxVehicleClutchDataMEstimateIterations, getPxVehicleClutchDataMEstimateIterations )
+{}
+ PxVehicleClutchDataGeneratedValues::PxVehicleClutchDataGeneratedValues( const PxVehicleClutchData* inSource )
+ :MStrength( inSource->mStrength )
+ ,MAccuracyMode( inSource->mAccuracyMode )
+ ,MEstimateIterations( inSource->mEstimateIterations )
+{
+ PX_UNUSED(inSource);
+}
+PxReal getPxVehicleTireLoadFilterData_Denominator( const PxVehicleTireLoadFilterData* inObj ) { return inObj->getDenominator(); }
+inline PxReal getPxVehicleTireLoadFilterDataMMinNormalisedLoad( const PxVehicleTireLoadFilterData* inOwner ) { return inOwner->mMinNormalisedLoad; }
+inline void setPxVehicleTireLoadFilterDataMMinNormalisedLoad( PxVehicleTireLoadFilterData* inOwner, PxReal inData) { inOwner->mMinNormalisedLoad = inData; }
+inline PxReal getPxVehicleTireLoadFilterDataMMinFilteredNormalisedLoad( const PxVehicleTireLoadFilterData* inOwner ) { return inOwner->mMinFilteredNormalisedLoad; }
+inline void setPxVehicleTireLoadFilterDataMMinFilteredNormalisedLoad( PxVehicleTireLoadFilterData* inOwner, PxReal inData) { inOwner->mMinFilteredNormalisedLoad = inData; }
+inline PxReal getPxVehicleTireLoadFilterDataMMaxNormalisedLoad( const PxVehicleTireLoadFilterData* inOwner ) { return inOwner->mMaxNormalisedLoad; }
+inline void setPxVehicleTireLoadFilterDataMMaxNormalisedLoad( PxVehicleTireLoadFilterData* inOwner, PxReal inData) { inOwner->mMaxNormalisedLoad = inData; }
+inline PxReal getPxVehicleTireLoadFilterDataMMaxFilteredNormalisedLoad( const PxVehicleTireLoadFilterData* inOwner ) { return inOwner->mMaxFilteredNormalisedLoad; }
+inline void setPxVehicleTireLoadFilterDataMMaxFilteredNormalisedLoad( PxVehicleTireLoadFilterData* inOwner, PxReal inData) { inOwner->mMaxFilteredNormalisedLoad = inData; }
+ PxVehicleTireLoadFilterDataGeneratedInfo::PxVehicleTireLoadFilterDataGeneratedInfo()
+ : Denominator( "Denominator", getPxVehicleTireLoadFilterData_Denominator)
+ , MMinNormalisedLoad( "MMinNormalisedLoad", setPxVehicleTireLoadFilterDataMMinNormalisedLoad, getPxVehicleTireLoadFilterDataMMinNormalisedLoad )
+ , MMinFilteredNormalisedLoad( "MMinFilteredNormalisedLoad", setPxVehicleTireLoadFilterDataMMinFilteredNormalisedLoad, getPxVehicleTireLoadFilterDataMMinFilteredNormalisedLoad )
+ , MMaxNormalisedLoad( "MMaxNormalisedLoad", setPxVehicleTireLoadFilterDataMMaxNormalisedLoad, getPxVehicleTireLoadFilterDataMMaxNormalisedLoad )
+ , MMaxFilteredNormalisedLoad( "MMaxFilteredNormalisedLoad", setPxVehicleTireLoadFilterDataMMaxFilteredNormalisedLoad, getPxVehicleTireLoadFilterDataMMaxFilteredNormalisedLoad )
+{}
+ PxVehicleTireLoadFilterDataGeneratedValues::PxVehicleTireLoadFilterDataGeneratedValues( const PxVehicleTireLoadFilterData* inSource )
+ :Denominator( getPxVehicleTireLoadFilterData_Denominator( inSource ) )
+ ,MMinNormalisedLoad( inSource->mMinNormalisedLoad )
+ ,MMinFilteredNormalisedLoad( inSource->mMinFilteredNormalisedLoad )
+ ,MMaxNormalisedLoad( inSource->mMaxNormalisedLoad )
+ ,MMaxFilteredNormalisedLoad( inSource->mMaxFilteredNormalisedLoad )
+{
+ PX_UNUSED(inSource);
+}
+PxReal getPxVehicleWheelData_RecipRadius( const PxVehicleWheelData* inObj ) { return inObj->getRecipRadius(); }
+PxReal getPxVehicleWheelData_RecipMOI( const PxVehicleWheelData* inObj ) { return inObj->getRecipMOI(); }
+inline PxReal getPxVehicleWheelDataMRadius( const PxVehicleWheelData* inOwner ) { return inOwner->mRadius; }
+inline void setPxVehicleWheelDataMRadius( PxVehicleWheelData* inOwner, PxReal inData) { inOwner->mRadius = inData; }
+inline PxReal getPxVehicleWheelDataMWidth( const PxVehicleWheelData* inOwner ) { return inOwner->mWidth; }
+inline void setPxVehicleWheelDataMWidth( PxVehicleWheelData* inOwner, PxReal inData) { inOwner->mWidth = inData; }
+inline PxReal getPxVehicleWheelDataMMass( const PxVehicleWheelData* inOwner ) { return inOwner->mMass; }
+inline void setPxVehicleWheelDataMMass( PxVehicleWheelData* inOwner, PxReal inData) { inOwner->mMass = inData; }
+inline PxReal getPxVehicleWheelDataMMOI( const PxVehicleWheelData* inOwner ) { return inOwner->mMOI; }
+inline void setPxVehicleWheelDataMMOI( PxVehicleWheelData* inOwner, PxReal inData) { inOwner->mMOI = inData; }
+inline PxReal getPxVehicleWheelDataMDampingRate( const PxVehicleWheelData* inOwner ) { return inOwner->mDampingRate; }
+inline void setPxVehicleWheelDataMDampingRate( PxVehicleWheelData* inOwner, PxReal inData) { inOwner->mDampingRate = inData; }
+inline PxReal getPxVehicleWheelDataMMaxBrakeTorque( const PxVehicleWheelData* inOwner ) { return inOwner->mMaxBrakeTorque; }
+inline void setPxVehicleWheelDataMMaxBrakeTorque( PxVehicleWheelData* inOwner, PxReal inData) { inOwner->mMaxBrakeTorque = inData; }
+inline PxReal getPxVehicleWheelDataMMaxHandBrakeTorque( const PxVehicleWheelData* inOwner ) { return inOwner->mMaxHandBrakeTorque; }
+inline void setPxVehicleWheelDataMMaxHandBrakeTorque( PxVehicleWheelData* inOwner, PxReal inData) { inOwner->mMaxHandBrakeTorque = inData; }
+inline PxReal getPxVehicleWheelDataMMaxSteer( const PxVehicleWheelData* inOwner ) { return inOwner->mMaxSteer; }
+inline void setPxVehicleWheelDataMMaxSteer( PxVehicleWheelData* inOwner, PxReal inData) { inOwner->mMaxSteer = inData; }
+inline PxReal getPxVehicleWheelDataMToeAngle( const PxVehicleWheelData* inOwner ) { return inOwner->mToeAngle; }
+inline void setPxVehicleWheelDataMToeAngle( PxVehicleWheelData* inOwner, PxReal inData) { inOwner->mToeAngle = inData; }
+ PxVehicleWheelDataGeneratedInfo::PxVehicleWheelDataGeneratedInfo()
+ : RecipRadius( "RecipRadius", getPxVehicleWheelData_RecipRadius)
+ , RecipMOI( "RecipMOI", getPxVehicleWheelData_RecipMOI)
+ , MRadius( "MRadius", setPxVehicleWheelDataMRadius, getPxVehicleWheelDataMRadius )
+ , MWidth( "MWidth", setPxVehicleWheelDataMWidth, getPxVehicleWheelDataMWidth )
+ , MMass( "MMass", setPxVehicleWheelDataMMass, getPxVehicleWheelDataMMass )
+ , MMOI( "MMOI", setPxVehicleWheelDataMMOI, getPxVehicleWheelDataMMOI )
+ , MDampingRate( "MDampingRate", setPxVehicleWheelDataMDampingRate, getPxVehicleWheelDataMDampingRate )
+ , MMaxBrakeTorque( "MMaxBrakeTorque", setPxVehicleWheelDataMMaxBrakeTorque, getPxVehicleWheelDataMMaxBrakeTorque )
+ , MMaxHandBrakeTorque( "MMaxHandBrakeTorque", setPxVehicleWheelDataMMaxHandBrakeTorque, getPxVehicleWheelDataMMaxHandBrakeTorque )
+ , MMaxSteer( "MMaxSteer", setPxVehicleWheelDataMMaxSteer, getPxVehicleWheelDataMMaxSteer )
+ , MToeAngle( "MToeAngle", setPxVehicleWheelDataMToeAngle, getPxVehicleWheelDataMToeAngle )
+{}
+ PxVehicleWheelDataGeneratedValues::PxVehicleWheelDataGeneratedValues( const PxVehicleWheelData* inSource )
+ :RecipRadius( getPxVehicleWheelData_RecipRadius( inSource ) )
+ ,RecipMOI( getPxVehicleWheelData_RecipMOI( inSource ) )
+ ,MRadius( inSource->mRadius )
+ ,MWidth( inSource->mWidth )
+ ,MMass( inSource->mMass )
+ ,MMOI( inSource->mMOI )
+ ,MDampingRate( inSource->mDampingRate )
+ ,MMaxBrakeTorque( inSource->mMaxBrakeTorque )
+ ,MMaxHandBrakeTorque( inSource->mMaxHandBrakeTorque )
+ ,MMaxSteer( inSource->mMaxSteer )
+ ,MToeAngle( inSource->mToeAngle )
+{
+ PX_UNUSED(inSource);
+}
+PxReal getPxVehicleSuspensionData_RecipMaxCompression( const PxVehicleSuspensionData* inObj ) { return inObj->getRecipMaxCompression(); }
+PxReal getPxVehicleSuspensionData_RecipMaxDroop( const PxVehicleSuspensionData* inObj ) { return inObj->getRecipMaxDroop(); }
+void setPxVehicleSuspensionData_MassAndPreserveNaturalFrequency( PxVehicleSuspensionData* inObj, const PxReal inArg){ inObj->setMassAndPreserveNaturalFrequency( inArg ); }
+inline PxReal getPxVehicleSuspensionDataMSpringStrength( const PxVehicleSuspensionData* inOwner ) { return inOwner->mSpringStrength; }
+inline void setPxVehicleSuspensionDataMSpringStrength( PxVehicleSuspensionData* inOwner, PxReal inData) { inOwner->mSpringStrength = inData; }
+inline PxReal getPxVehicleSuspensionDataMSpringDamperRate( const PxVehicleSuspensionData* inOwner ) { return inOwner->mSpringDamperRate; }
+inline void setPxVehicleSuspensionDataMSpringDamperRate( PxVehicleSuspensionData* inOwner, PxReal inData) { inOwner->mSpringDamperRate = inData; }
+inline PxReal getPxVehicleSuspensionDataMMaxCompression( const PxVehicleSuspensionData* inOwner ) { return inOwner->mMaxCompression; }
+inline void setPxVehicleSuspensionDataMMaxCompression( PxVehicleSuspensionData* inOwner, PxReal inData) { inOwner->mMaxCompression = inData; }
+inline PxReal getPxVehicleSuspensionDataMMaxDroop( const PxVehicleSuspensionData* inOwner ) { return inOwner->mMaxDroop; }
+inline void setPxVehicleSuspensionDataMMaxDroop( PxVehicleSuspensionData* inOwner, PxReal inData) { inOwner->mMaxDroop = inData; }
+inline PxReal getPxVehicleSuspensionDataMSprungMass( const PxVehicleSuspensionData* inOwner ) { return inOwner->mSprungMass; }
+inline void setPxVehicleSuspensionDataMSprungMass( PxVehicleSuspensionData* inOwner, PxReal inData) { inOwner->mSprungMass = inData; }
+inline PxReal getPxVehicleSuspensionDataMCamberAtRest( const PxVehicleSuspensionData* inOwner ) { return inOwner->mCamberAtRest; }
+inline void setPxVehicleSuspensionDataMCamberAtRest( PxVehicleSuspensionData* inOwner, PxReal inData) { inOwner->mCamberAtRest = inData; }
+inline PxReal getPxVehicleSuspensionDataMCamberAtMaxCompression( const PxVehicleSuspensionData* inOwner ) { return inOwner->mCamberAtMaxCompression; }
+inline void setPxVehicleSuspensionDataMCamberAtMaxCompression( PxVehicleSuspensionData* inOwner, PxReal inData) { inOwner->mCamberAtMaxCompression = inData; }
+inline PxReal getPxVehicleSuspensionDataMCamberAtMaxDroop( const PxVehicleSuspensionData* inOwner ) { return inOwner->mCamberAtMaxDroop; }
+inline void setPxVehicleSuspensionDataMCamberAtMaxDroop( PxVehicleSuspensionData* inOwner, PxReal inData) { inOwner->mCamberAtMaxDroop = inData; }
+ PxVehicleSuspensionDataGeneratedInfo::PxVehicleSuspensionDataGeneratedInfo()
+ : RecipMaxCompression( "RecipMaxCompression", getPxVehicleSuspensionData_RecipMaxCompression)
+ , RecipMaxDroop( "RecipMaxDroop", getPxVehicleSuspensionData_RecipMaxDroop)
+ , MassAndPreserveNaturalFrequency( "MassAndPreserveNaturalFrequency", setPxVehicleSuspensionData_MassAndPreserveNaturalFrequency)
+ , MSpringStrength( "MSpringStrength", setPxVehicleSuspensionDataMSpringStrength, getPxVehicleSuspensionDataMSpringStrength )
+ , MSpringDamperRate( "MSpringDamperRate", setPxVehicleSuspensionDataMSpringDamperRate, getPxVehicleSuspensionDataMSpringDamperRate )
+ , MMaxCompression( "MMaxCompression", setPxVehicleSuspensionDataMMaxCompression, getPxVehicleSuspensionDataMMaxCompression )
+ , MMaxDroop( "MMaxDroop", setPxVehicleSuspensionDataMMaxDroop, getPxVehicleSuspensionDataMMaxDroop )
+ , MSprungMass( "MSprungMass", setPxVehicleSuspensionDataMSprungMass, getPxVehicleSuspensionDataMSprungMass )
+ , MCamberAtRest( "MCamberAtRest", setPxVehicleSuspensionDataMCamberAtRest, getPxVehicleSuspensionDataMCamberAtRest )
+ , MCamberAtMaxCompression( "MCamberAtMaxCompression", setPxVehicleSuspensionDataMCamberAtMaxCompression, getPxVehicleSuspensionDataMCamberAtMaxCompression )
+ , MCamberAtMaxDroop( "MCamberAtMaxDroop", setPxVehicleSuspensionDataMCamberAtMaxDroop, getPxVehicleSuspensionDataMCamberAtMaxDroop )
+{}
+ PxVehicleSuspensionDataGeneratedValues::PxVehicleSuspensionDataGeneratedValues( const PxVehicleSuspensionData* inSource )
+ :RecipMaxCompression( getPxVehicleSuspensionData_RecipMaxCompression( inSource ) )
+ ,RecipMaxDroop( getPxVehicleSuspensionData_RecipMaxDroop( inSource ) )
+ ,MSpringStrength( inSource->mSpringStrength )
+ ,MSpringDamperRate( inSource->mSpringDamperRate )
+ ,MMaxCompression( inSource->mMaxCompression )
+ ,MMaxDroop( inSource->mMaxDroop )
+ ,MSprungMass( inSource->mSprungMass )
+ ,MCamberAtRest( inSource->mCamberAtRest )
+ ,MCamberAtMaxCompression( inSource->mCamberAtMaxCompression )
+ ,MCamberAtMaxDroop( inSource->mCamberAtMaxDroop )
+{
+ PX_UNUSED(inSource);
+}
+inline PxU32 getPxVehicleAntiRollBarDataMWheel0( const PxVehicleAntiRollBarData* inOwner ) { return inOwner->mWheel0; }
+inline void setPxVehicleAntiRollBarDataMWheel0( PxVehicleAntiRollBarData* inOwner, PxU32 inData) { inOwner->mWheel0 = inData; }
+inline PxU32 getPxVehicleAntiRollBarDataMWheel1( const PxVehicleAntiRollBarData* inOwner ) { return inOwner->mWheel1; }
+inline void setPxVehicleAntiRollBarDataMWheel1( PxVehicleAntiRollBarData* inOwner, PxU32 inData) { inOwner->mWheel1 = inData; }
+inline PxF32 getPxVehicleAntiRollBarDataMStiffness( const PxVehicleAntiRollBarData* inOwner ) { return inOwner->mStiffness; }
+inline void setPxVehicleAntiRollBarDataMStiffness( PxVehicleAntiRollBarData* inOwner, PxF32 inData) { inOwner->mStiffness = inData; }
+ PxVehicleAntiRollBarDataGeneratedInfo::PxVehicleAntiRollBarDataGeneratedInfo()
+ : MWheel0( "MWheel0", setPxVehicleAntiRollBarDataMWheel0, getPxVehicleAntiRollBarDataMWheel0 )
+ , MWheel1( "MWheel1", setPxVehicleAntiRollBarDataMWheel1, getPxVehicleAntiRollBarDataMWheel1 )
+ , MStiffness( "MStiffness", setPxVehicleAntiRollBarDataMStiffness, getPxVehicleAntiRollBarDataMStiffness )
+{}
+ PxVehicleAntiRollBarDataGeneratedValues::PxVehicleAntiRollBarDataGeneratedValues( const PxVehicleAntiRollBarData* inSource )
+ :MWheel0( inSource->mWheel0 )
+ ,MWheel1( inSource->mWheel1 )
+ ,MStiffness( inSource->mStiffness )
+{
+ PX_UNUSED(inSource);
+}
+PxReal getPxVehicleTireData_RecipLongitudinalStiffnessPerUnitGravity( const PxVehicleTireData* inObj ) { return inObj->getRecipLongitudinalStiffnessPerUnitGravity(); }
+PxReal getPxVehicleTireData_FrictionVsSlipGraphRecipx1Minusx0( const PxVehicleTireData* inObj ) { return inObj->getFrictionVsSlipGraphRecipx1Minusx0(); }
+PxReal getPxVehicleTireData_FrictionVsSlipGraphRecipx2Minusx1( const PxVehicleTireData* inObj ) { return inObj->getFrictionVsSlipGraphRecipx2Minusx1(); }
+inline PxReal getPxVehicleTireDataMLatStiffX( const PxVehicleTireData* inOwner ) { return inOwner->mLatStiffX; }
+inline void setPxVehicleTireDataMLatStiffX( PxVehicleTireData* inOwner, PxReal inData) { inOwner->mLatStiffX = inData; }
+inline PxReal getPxVehicleTireDataMLatStiffY( const PxVehicleTireData* inOwner ) { return inOwner->mLatStiffY; }
+inline void setPxVehicleTireDataMLatStiffY( PxVehicleTireData* inOwner, PxReal inData) { inOwner->mLatStiffY = inData; }
+inline PxReal getPxVehicleTireDataMLongitudinalStiffnessPerUnitGravity( const PxVehicleTireData* inOwner ) { return inOwner->mLongitudinalStiffnessPerUnitGravity; }
+inline void setPxVehicleTireDataMLongitudinalStiffnessPerUnitGravity( PxVehicleTireData* inOwner, PxReal inData) { inOwner->mLongitudinalStiffnessPerUnitGravity = inData; }
+inline PxReal getPxVehicleTireDataMCamberStiffnessPerUnitGravity( const PxVehicleTireData* inOwner ) { return inOwner->mCamberStiffnessPerUnitGravity; }
+inline void setPxVehicleTireDataMCamberStiffnessPerUnitGravity( PxVehicleTireData* inOwner, PxReal inData) { inOwner->mCamberStiffnessPerUnitGravity = inData; }
+inline PxU32 getPxVehicleTireDataMType( const PxVehicleTireData* inOwner ) { return inOwner->mType; }
+inline void setPxVehicleTireDataMType( PxVehicleTireData* inOwner, PxU32 inData) { inOwner->mType = inData; }
+ PxVehicleTireDataGeneratedInfo::PxVehicleTireDataGeneratedInfo()
+ : RecipLongitudinalStiffnessPerUnitGravity( "RecipLongitudinalStiffnessPerUnitGravity", getPxVehicleTireData_RecipLongitudinalStiffnessPerUnitGravity)
+ , FrictionVsSlipGraphRecipx1Minusx0( "FrictionVsSlipGraphRecipx1Minusx0", getPxVehicleTireData_FrictionVsSlipGraphRecipx1Minusx0)
+ , FrictionVsSlipGraphRecipx2Minusx1( "FrictionVsSlipGraphRecipx2Minusx1", getPxVehicleTireData_FrictionVsSlipGraphRecipx2Minusx1)
+ , MLatStiffX( "MLatStiffX", setPxVehicleTireDataMLatStiffX, getPxVehicleTireDataMLatStiffX )
+ , MLatStiffY( "MLatStiffY", setPxVehicleTireDataMLatStiffY, getPxVehicleTireDataMLatStiffY )
+ , MLongitudinalStiffnessPerUnitGravity( "MLongitudinalStiffnessPerUnitGravity", setPxVehicleTireDataMLongitudinalStiffnessPerUnitGravity, getPxVehicleTireDataMLongitudinalStiffnessPerUnitGravity )
+ , MCamberStiffnessPerUnitGravity( "MCamberStiffnessPerUnitGravity", setPxVehicleTireDataMCamberStiffnessPerUnitGravity, getPxVehicleTireDataMCamberStiffnessPerUnitGravity )
+ , MType( "MType", setPxVehicleTireDataMType, getPxVehicleTireDataMType )
+{}
+ PxVehicleTireDataGeneratedValues::PxVehicleTireDataGeneratedValues( const PxVehicleTireData* inSource )
+ :RecipLongitudinalStiffnessPerUnitGravity( getPxVehicleTireData_RecipLongitudinalStiffnessPerUnitGravity( inSource ) )
+ ,FrictionVsSlipGraphRecipx1Minusx0( getPxVehicleTireData_FrictionVsSlipGraphRecipx1Minusx0( inSource ) )
+ ,FrictionVsSlipGraphRecipx2Minusx1( getPxVehicleTireData_FrictionVsSlipGraphRecipx2Minusx1( inSource ) )
+ ,MLatStiffX( inSource->mLatStiffX )
+ ,MLatStiffY( inSource->mLatStiffY )
+ ,MLongitudinalStiffnessPerUnitGravity( inSource->mLongitudinalStiffnessPerUnitGravity )
+ ,MCamberStiffnessPerUnitGravity( inSource->mCamberStiffnessPerUnitGravity )
+ ,MType( inSource->mType )
+{
+ PX_UNUSED(inSource);
+ PxMemCopy( MFrictionVsSlipGraph, inSource->mFrictionVsSlipGraph, sizeof( MFrictionVsSlipGraph ) );
+}
+const PxReal * getPxVehicleWheels4SimData_TireRestLoadsArray( const PxVehicleWheels4SimData* inObj ) { return inObj->getTireRestLoadsArray(); }
+const PxReal * getPxVehicleWheels4SimData_RecipTireRestLoadsArray( const PxVehicleWheels4SimData* inObj ) { return inObj->getRecipTireRestLoadsArray(); }
+ PxVehicleWheels4SimDataGeneratedInfo::PxVehicleWheels4SimDataGeneratedInfo()
+ : TireRestLoadsArray( "TireRestLoadsArray", getPxVehicleWheels4SimData_TireRestLoadsArray)
+ , RecipTireRestLoadsArray( "RecipTireRestLoadsArray", getPxVehicleWheels4SimData_RecipTireRestLoadsArray)
+{}
+ PxVehicleWheels4SimDataGeneratedValues::PxVehicleWheels4SimDataGeneratedValues( const PxVehicleWheels4SimData* inSource )
+ :TireRestLoadsArray( getPxVehicleWheels4SimData_TireRestLoadsArray( inSource ) )
+ ,RecipTireRestLoadsArray( getPxVehicleWheels4SimData_RecipTireRestLoadsArray( inSource ) )
+{
+ PX_UNUSED(inSource);
+}
+void setPxVehicleWheelsSimData_ChassisMass( PxVehicleWheelsSimData* inObj, const PxF32 inArg){ inObj->setChassisMass( inArg ); }
+PxVehicleSuspensionData getPxVehicleWheelsSimData_SuspensionData( const PxVehicleWheelsSimData* inObj, const PxU32 index ) { return inObj->getSuspensionData( index ); }
+PxU32 getNbPxVehicleWheelsSimData_SuspensionData( const PxVehicleWheelsSimData* inObj ) { return inObj->getNbSuspensionData( ); }
+void setPxVehicleWheelsSimData_SuspensionData( PxVehicleWheelsSimData* inObj, const PxU32 inIndex, PxVehicleSuspensionData inValue ){ inObj->setSuspensionData( inIndex, inValue ); }
+PxVehicleWheelData getPxVehicleWheelsSimData_WheelData( const PxVehicleWheelsSimData* inObj, const PxU32 index ) { return inObj->getWheelData( index ); }
+PxU32 getNbPxVehicleWheelsSimData_WheelData( const PxVehicleWheelsSimData* inObj ) { return inObj->getNbWheelData( ); }
+void setPxVehicleWheelsSimData_WheelData( PxVehicleWheelsSimData* inObj, const PxU32 inIndex, PxVehicleWheelData inValue ){ inObj->setWheelData( inIndex, inValue ); }
+PxVehicleTireData getPxVehicleWheelsSimData_TireData( const PxVehicleWheelsSimData* inObj, const PxU32 index ) { return inObj->getTireData( index ); }
+PxU32 getNbPxVehicleWheelsSimData_TireData( const PxVehicleWheelsSimData* inObj ) { return inObj->getNbTireData( ); }
+void setPxVehicleWheelsSimData_TireData( PxVehicleWheelsSimData* inObj, const PxU32 inIndex, PxVehicleTireData inValue ){ inObj->setTireData( inIndex, inValue ); }
+PxVec3 getPxVehicleWheelsSimData_SuspTravelDirection( const PxVehicleWheelsSimData* inObj, const PxU32 index ) { return inObj->getSuspTravelDirection( index ); }
+PxU32 getNbPxVehicleWheelsSimData_SuspTravelDirection( const PxVehicleWheelsSimData* inObj ) { return inObj->getNbSuspTravelDirection( ); }
+void setPxVehicleWheelsSimData_SuspTravelDirection( PxVehicleWheelsSimData* inObj, const PxU32 inIndex, PxVec3 inValue ){ inObj->setSuspTravelDirection( inIndex, inValue ); }
+PxVec3 getPxVehicleWheelsSimData_SuspForceAppPointOffset( const PxVehicleWheelsSimData* inObj, const PxU32 index ) { return inObj->getSuspForceAppPointOffset( index ); }
+PxU32 getNbPxVehicleWheelsSimData_SuspForceAppPointOffset( const PxVehicleWheelsSimData* inObj ) { return inObj->getNbSuspForceAppPointOffset( ); }
+void setPxVehicleWheelsSimData_SuspForceAppPointOffset( PxVehicleWheelsSimData* inObj, const PxU32 inIndex, PxVec3 inValue ){ inObj->setSuspForceAppPointOffset( inIndex, inValue ); }
+PxVec3 getPxVehicleWheelsSimData_TireForceAppPointOffset( const PxVehicleWheelsSimData* inObj, const PxU32 index ) { return inObj->getTireForceAppPointOffset( index ); }
+PxU32 getNbPxVehicleWheelsSimData_TireForceAppPointOffset( const PxVehicleWheelsSimData* inObj ) { return inObj->getNbTireForceAppPointOffset( ); }
+void setPxVehicleWheelsSimData_TireForceAppPointOffset( PxVehicleWheelsSimData* inObj, const PxU32 inIndex, PxVec3 inValue ){ inObj->setTireForceAppPointOffset( inIndex, inValue ); }
+PxVec3 getPxVehicleWheelsSimData_WheelCentreOffset( const PxVehicleWheelsSimData* inObj, const PxU32 index ) { return inObj->getWheelCentreOffset( index ); }
+PxU32 getNbPxVehicleWheelsSimData_WheelCentreOffset( const PxVehicleWheelsSimData* inObj ) { return inObj->getNbWheelCentreOffset( ); }
+void setPxVehicleWheelsSimData_WheelCentreOffset( PxVehicleWheelsSimData* inObj, const PxU32 inIndex, PxVec3 inValue ){ inObj->setWheelCentreOffset( inIndex, inValue ); }
+PxI32 getPxVehicleWheelsSimData_WheelShapeMapping( const PxVehicleWheelsSimData* inObj, const PxU32 index ) { return inObj->getWheelShapeMapping( index ); }
+PxU32 getNbPxVehicleWheelsSimData_WheelShapeMapping( const PxVehicleWheelsSimData* inObj ) { return inObj->getNbWheelShapeMapping( ); }
+void setPxVehicleWheelsSimData_WheelShapeMapping( PxVehicleWheelsSimData* inObj, const PxU32 inIndex, PxI32 inValue ){ inObj->setWheelShapeMapping( inIndex, inValue ); }
+PxFilterData getPxVehicleWheelsSimData_SceneQueryFilterData( const PxVehicleWheelsSimData* inObj, const PxU32 index ) { return inObj->getSceneQueryFilterData( index ); }
+PxU32 getNbPxVehicleWheelsSimData_SceneQueryFilterData( const PxVehicleWheelsSimData* inObj ) { return inObj->getNbSceneQueryFilterData( ); }
+void setPxVehicleWheelsSimData_SceneQueryFilterData( PxVehicleWheelsSimData* inObj, const PxU32 inIndex, PxFilterData inValue ){ inObj->setSceneQueryFilterData( inIndex, inValue ); }
+PxVehicleAntiRollBarData getPxVehicleWheelsSimData_AntiRollBarData( const PxVehicleWheelsSimData* inObj, const PxU32 index ) { return inObj->getAntiRollBarData( index ); }
+PxU32 getNbPxVehicleWheelsSimData_AntiRollBarData( const PxVehicleWheelsSimData* inObj ) { return inObj->getNbAntiRollBarData( ); }
+void setPxVehicleWheelsSimData_AntiRollBarData( PxVehicleWheelsSimData* inObj, const PxU32 inIndex, PxVehicleAntiRollBarData inValue ){ inObj->setAntiRollBarData( inIndex, inValue ); }
+void setPxVehicleWheelsSimData_TireLoadFilterData( PxVehicleWheelsSimData* inObj, const PxVehicleTireLoadFilterData & inArg){ inObj->setTireLoadFilterData( inArg ); }
+PxVehicleTireLoadFilterData getPxVehicleWheelsSimData_TireLoadFilterData( const PxVehicleWheelsSimData* inObj ) { return inObj->getTireLoadFilterData(); }
+void setPxVehicleWheelsSimData_MinLongSlipDenominator( PxVehicleWheelsSimData* inObj, const PxReal inArg){ inObj->setMinLongSlipDenominator( inArg ); }
+PxF32 getPxVehicleWheelsSimData_MinLongSlipDenominator( const PxVehicleWheelsSimData* inObj ) { return inObj->getMinLongSlipDenominator(); }
+void setPxVehicleWheelsSimData_ThresholdLongSpeed( PxVehicleWheelsSimData* inObj, const PxF32 inArg){ inObj->setThresholdLongSpeed( inArg ); }
+PxF32 getPxVehicleWheelsSimData_ThresholdLongSpeed( const PxVehicleWheelsSimData* inObj ) { return inObj->getThresholdLongSpeed(); }
+void setPxVehicleWheelsSimData_LowForwardSpeedSubStepCount( PxVehicleWheelsSimData* inObj, const PxU32 inArg){ inObj->setLowForwardSpeedSubStepCount( inArg ); }
+PxU32 getPxVehicleWheelsSimData_LowForwardSpeedSubStepCount( const PxVehicleWheelsSimData* inObj ) { return inObj->getLowForwardSpeedSubStepCount(); }
+void setPxVehicleWheelsSimData_HighForwardSpeedSubStepCount( PxVehicleWheelsSimData* inObj, const PxU32 inArg){ inObj->setHighForwardSpeedSubStepCount( inArg ); }
+PxU32 getPxVehicleWheelsSimData_HighForwardSpeedSubStepCount( const PxVehicleWheelsSimData* inObj ) { return inObj->getHighForwardSpeedSubStepCount(); }
+_Bool getPxVehicleWheelsSimData_WheelEnabledState( const PxVehicleWheelsSimData* inObj, const PxU32 index ) { return inObj->getWheelEnabledState( index ); }
+PxU32 getNbPxVehicleWheelsSimData_WheelEnabledState( const PxVehicleWheelsSimData* inObj ) { return inObj->getNbWheelEnabledState( ); }
+void setPxVehicleWheelsSimData_WheelEnabledState( PxVehicleWheelsSimData* inObj, const PxU32 inIndex, _Bool inValue ){ inObj->setWheelEnabledState( inIndex, inValue ); }
+ PxVehicleWheelsSimDataGeneratedInfo::PxVehicleWheelsSimDataGeneratedInfo()
+ : ChassisMass( "ChassisMass", setPxVehicleWheelsSimData_ChassisMass)
+ , SuspensionData( "SuspensionData", getPxVehicleWheelsSimData_SuspensionData, getNbPxVehicleWheelsSimData_SuspensionData, setPxVehicleWheelsSimData_SuspensionData )
+ , WheelData( "WheelData", getPxVehicleWheelsSimData_WheelData, getNbPxVehicleWheelsSimData_WheelData, setPxVehicleWheelsSimData_WheelData )
+ , TireData( "TireData", getPxVehicleWheelsSimData_TireData, getNbPxVehicleWheelsSimData_TireData, setPxVehicleWheelsSimData_TireData )
+ , SuspTravelDirection( "SuspTravelDirection", getPxVehicleWheelsSimData_SuspTravelDirection, getNbPxVehicleWheelsSimData_SuspTravelDirection, setPxVehicleWheelsSimData_SuspTravelDirection )
+ , SuspForceAppPointOffset( "SuspForceAppPointOffset", getPxVehicleWheelsSimData_SuspForceAppPointOffset, getNbPxVehicleWheelsSimData_SuspForceAppPointOffset, setPxVehicleWheelsSimData_SuspForceAppPointOffset )
+ , TireForceAppPointOffset( "TireForceAppPointOffset", getPxVehicleWheelsSimData_TireForceAppPointOffset, getNbPxVehicleWheelsSimData_TireForceAppPointOffset, setPxVehicleWheelsSimData_TireForceAppPointOffset )
+ , WheelCentreOffset( "WheelCentreOffset", getPxVehicleWheelsSimData_WheelCentreOffset, getNbPxVehicleWheelsSimData_WheelCentreOffset, setPxVehicleWheelsSimData_WheelCentreOffset )
+ , WheelShapeMapping( "WheelShapeMapping", getPxVehicleWheelsSimData_WheelShapeMapping, getNbPxVehicleWheelsSimData_WheelShapeMapping, setPxVehicleWheelsSimData_WheelShapeMapping )
+ , SceneQueryFilterData( "SceneQueryFilterData", getPxVehicleWheelsSimData_SceneQueryFilterData, getNbPxVehicleWheelsSimData_SceneQueryFilterData, setPxVehicleWheelsSimData_SceneQueryFilterData )
+ , AntiRollBarData( "AntiRollBarData", getPxVehicleWheelsSimData_AntiRollBarData, getNbPxVehicleWheelsSimData_AntiRollBarData, setPxVehicleWheelsSimData_AntiRollBarData )
+ , TireLoadFilterData( "TireLoadFilterData", setPxVehicleWheelsSimData_TireLoadFilterData, getPxVehicleWheelsSimData_TireLoadFilterData)
+ , MinLongSlipDenominator( "MinLongSlipDenominator", setPxVehicleWheelsSimData_MinLongSlipDenominator, getPxVehicleWheelsSimData_MinLongSlipDenominator)
+ , ThresholdLongSpeed( "ThresholdLongSpeed", setPxVehicleWheelsSimData_ThresholdLongSpeed, getPxVehicleWheelsSimData_ThresholdLongSpeed)
+ , LowForwardSpeedSubStepCount( "LowForwardSpeedSubStepCount", setPxVehicleWheelsSimData_LowForwardSpeedSubStepCount, getPxVehicleWheelsSimData_LowForwardSpeedSubStepCount)
+ , HighForwardSpeedSubStepCount( "HighForwardSpeedSubStepCount", setPxVehicleWheelsSimData_HighForwardSpeedSubStepCount, getPxVehicleWheelsSimData_HighForwardSpeedSubStepCount)
+ , WheelEnabledState( "WheelEnabledState", getPxVehicleWheelsSimData_WheelEnabledState, getNbPxVehicleWheelsSimData_WheelEnabledState, setPxVehicleWheelsSimData_WheelEnabledState )
+{}
+ PxVehicleWheelsSimDataGeneratedValues::PxVehicleWheelsSimDataGeneratedValues( const PxVehicleWheelsSimData* inSource )
+ :TireLoadFilterData( getPxVehicleWheelsSimData_TireLoadFilterData( inSource ) )
+ ,MinLongSlipDenominator( getPxVehicleWheelsSimData_MinLongSlipDenominator( inSource ) )
+ ,ThresholdLongSpeed( getPxVehicleWheelsSimData_ThresholdLongSpeed( inSource ) )
+ ,LowForwardSpeedSubStepCount( getPxVehicleWheelsSimData_LowForwardSpeedSubStepCount( inSource ) )
+ ,HighForwardSpeedSubStepCount( getPxVehicleWheelsSimData_HighForwardSpeedSubStepCount( inSource ) )
+{
+ PX_UNUSED(inSource);
+}
+void setPxVehicleWheelsDynData_TireForceShaderFunction( PxVehicleWheelsDynData* inObj, PxVehicleComputeTireForce inArg){ inObj->setTireForceShaderFunction( inArg ); }
+PxReal getPxVehicleWheelsDynData_WheelRotationSpeed( const PxVehicleWheelsDynData* inObj, const PxU32 index ) { return inObj->getWheelRotationSpeed( index ); }
+PxU32 getNbPxVehicleWheelsDynData_WheelRotationSpeed( const PxVehicleWheelsDynData* inObj ) { return inObj->getNbWheelRotationSpeed( ); }
+void setPxVehicleWheelsDynData_WheelRotationSpeed( PxVehicleWheelsDynData* inObj, const PxU32 inIndex, PxReal inValue ){ inObj->setWheelRotationSpeed( inIndex, inValue ); }
+PxReal getPxVehicleWheelsDynData_WheelRotationAngle( const PxVehicleWheelsDynData* inObj, const PxU32 index ) { return inObj->getWheelRotationAngle( index ); }
+PxU32 getNbPxVehicleWheelsDynData_WheelRotationAngle( const PxVehicleWheelsDynData* inObj ) { return inObj->getNbWheelRotationAngle( ); }
+void setPxVehicleWheelsDynData_WheelRotationAngle( PxVehicleWheelsDynData* inObj, const PxU32 inIndex, PxReal inValue ){ inObj->setWheelRotationAngle( inIndex, inValue ); }
+PxVehicleWheels4DynData * getPxVehicleWheelsDynData_Wheel4DynData( const PxVehicleWheelsDynData* inObj ) { return inObj->getWheel4DynData(); }
+ PxVehicleWheelsDynDataGeneratedInfo::PxVehicleWheelsDynDataGeneratedInfo()
+ : TireForceShaderFunction( "TireForceShaderFunction", setPxVehicleWheelsDynData_TireForceShaderFunction)
+ , WheelRotationSpeed( "WheelRotationSpeed", getPxVehicleWheelsDynData_WheelRotationSpeed, getNbPxVehicleWheelsDynData_WheelRotationSpeed, setPxVehicleWheelsDynData_WheelRotationSpeed )
+ , WheelRotationAngle( "WheelRotationAngle", getPxVehicleWheelsDynData_WheelRotationAngle, getNbPxVehicleWheelsDynData_WheelRotationAngle, setPxVehicleWheelsDynData_WheelRotationAngle )
+ , Wheel4DynData( "Wheel4DynData", getPxVehicleWheelsDynData_Wheel4DynData)
+{}
+ PxVehicleWheelsDynDataGeneratedValues::PxVehicleWheelsDynDataGeneratedValues( const PxVehicleWheelsDynData* inSource )
+ :Wheel4DynData( getPxVehicleWheelsDynData_Wheel4DynData( inSource ) )
+{
+ PX_UNUSED(inSource);
+}
+PxU32 getPxVehicleWheels_VehicleType( const PxVehicleWheels* inObj ) { return inObj->getVehicleType(); }
+const PxRigidDynamic * getPxVehicleWheels_RigidDynamicActor( const PxVehicleWheels* inObj ) { return inObj->getRigidDynamicActor(); }
+const char * getPxVehicleWheels_ConcreteTypeName( const PxVehicleWheels* inObj ) { return inObj->getConcreteTypeName(); }
+inline PxVehicleWheelsSimData getPxVehicleWheelsMWheelsSimData( const PxVehicleWheels* inOwner ) { return inOwner->mWheelsSimData; }
+inline void setPxVehicleWheelsMWheelsSimData( PxVehicleWheels* inOwner, PxVehicleWheelsSimData inData) { inOwner->mWheelsSimData = inData; }
+inline PxVehicleWheelsDynData getPxVehicleWheelsMWheelsDynData( const PxVehicleWheels* inOwner ) { return inOwner->mWheelsDynData; }
+inline void setPxVehicleWheelsMWheelsDynData( PxVehicleWheels* inOwner, PxVehicleWheelsDynData inData) { inOwner->mWheelsDynData = inData; }
+ PxVehicleWheelsGeneratedInfo::PxVehicleWheelsGeneratedInfo()
+ : VehicleType( "VehicleType", getPxVehicleWheels_VehicleType)
+ , RigidDynamicActor( "RigidDynamicActor", getPxVehicleWheels_RigidDynamicActor)
+ , ConcreteTypeName( "ConcreteTypeName", getPxVehicleWheels_ConcreteTypeName)
+ , MWheelsSimData( "MWheelsSimData", setPxVehicleWheelsMWheelsSimData, getPxVehicleWheelsMWheelsSimData )
+ , MWheelsDynData( "MWheelsDynData", setPxVehicleWheelsMWheelsDynData, getPxVehicleWheelsMWheelsDynData )
+{}
+ PxVehicleWheelsGeneratedValues::PxVehicleWheelsGeneratedValues( const PxVehicleWheels* inSource )
+ :VehicleType( getPxVehicleWheels_VehicleType( inSource ) )
+ ,RigidDynamicActor( getPxVehicleWheels_RigidDynamicActor( inSource ) )
+ ,ConcreteTypeName( getPxVehicleWheels_ConcreteTypeName( inSource ) )
+ ,MWheelsSimData( inSource->mWheelsSimData )
+ ,MWheelsDynData( inSource->mWheelsDynData )
+{
+ PX_UNUSED(inSource);
+}
+PxReal getPxVehicleDriveDynData_AnalogInput( const PxVehicleDriveDynData* inObj, const PxU32 index ) { return inObj->getAnalogInput( index ); }
+PxU32 getNbPxVehicleDriveDynData_AnalogInput( const PxVehicleDriveDynData* inObj ) { return inObj->getNbAnalogInput( ); }
+void setPxVehicleDriveDynData_AnalogInput( PxVehicleDriveDynData* inObj, const PxU32 inIndex, PxReal inValue ){ inObj->setAnalogInput( inIndex, inValue ); }
+void setPxVehicleDriveDynData_GearUp( PxVehicleDriveDynData* inObj, const _Bool inArg){ inObj->setGearUp( inArg ); }
+_Bool getPxVehicleDriveDynData_GearUp( const PxVehicleDriveDynData* inObj ) { return inObj->getGearUp(); }
+void setPxVehicleDriveDynData_GearDown( PxVehicleDriveDynData* inObj, const _Bool inArg){ inObj->setGearDown( inArg ); }
+_Bool getPxVehicleDriveDynData_GearDown( const PxVehicleDriveDynData* inObj ) { return inObj->getGearDown(); }
+void setPxVehicleDriveDynData_UseAutoGears( PxVehicleDriveDynData* inObj, const _Bool inArg){ inObj->setUseAutoGears( inArg ); }
+_Bool getPxVehicleDriveDynData_UseAutoGears( const PxVehicleDriveDynData* inObj ) { return inObj->getUseAutoGears(); }
+void setPxVehicleDriveDynData_CurrentGear( PxVehicleDriveDynData* inObj, PxU32 inArg){ inObj->setCurrentGear( inArg ); }
+PxU32 getPxVehicleDriveDynData_CurrentGear( const PxVehicleDriveDynData* inObj ) { return inObj->getCurrentGear(); }
+void setPxVehicleDriveDynData_TargetGear( PxVehicleDriveDynData* inObj, PxU32 inArg){ inObj->setTargetGear( inArg ); }
+PxU32 getPxVehicleDriveDynData_TargetGear( const PxVehicleDriveDynData* inObj ) { return inObj->getTargetGear(); }
+void setPxVehicleDriveDynData_EngineRotationSpeed( PxVehicleDriveDynData* inObj, const PxF32 inArg){ inObj->setEngineRotationSpeed( inArg ); }
+PxReal getPxVehicleDriveDynData_EngineRotationSpeed( const PxVehicleDriveDynData* inObj ) { return inObj->getEngineRotationSpeed(); }
+void setPxVehicleDriveDynData_GearChange( PxVehicleDriveDynData* inObj, const PxU32 inArg){ inObj->setGearChange( inArg ); }
+PxU32 getPxVehicleDriveDynData_GearChange( const PxVehicleDriveDynData* inObj ) { return inObj->getGearChange(); }
+void setPxVehicleDriveDynData_GearSwitchTime( PxVehicleDriveDynData* inObj, const PxReal inArg){ inObj->setGearSwitchTime( inArg ); }
+PxReal getPxVehicleDriveDynData_GearSwitchTime( const PxVehicleDriveDynData* inObj ) { return inObj->getGearSwitchTime(); }
+void setPxVehicleDriveDynData_AutoBoxSwitchTime( PxVehicleDriveDynData* inObj, const PxReal inArg){ inObj->setAutoBoxSwitchTime( inArg ); }
+PxReal getPxVehicleDriveDynData_AutoBoxSwitchTime( const PxVehicleDriveDynData* inObj ) { return inObj->getAutoBoxSwitchTime(); }
+inline _Bool getPxVehicleDriveDynDataMUseAutoGears( const PxVehicleDriveDynData* inOwner ) { return inOwner->mUseAutoGears; }
+inline void setPxVehicleDriveDynDataMUseAutoGears( PxVehicleDriveDynData* inOwner, _Bool inData) { inOwner->mUseAutoGears = inData; }
+inline _Bool getPxVehicleDriveDynDataMGearUpPressed( const PxVehicleDriveDynData* inOwner ) { return inOwner->mGearUpPressed; }
+inline void setPxVehicleDriveDynDataMGearUpPressed( PxVehicleDriveDynData* inOwner, _Bool inData) { inOwner->mGearUpPressed = inData; }
+inline _Bool getPxVehicleDriveDynDataMGearDownPressed( const PxVehicleDriveDynData* inOwner ) { return inOwner->mGearDownPressed; }
+inline void setPxVehicleDriveDynDataMGearDownPressed( PxVehicleDriveDynData* inOwner, _Bool inData) { inOwner->mGearDownPressed = inData; }
+inline PxU32 getPxVehicleDriveDynDataMCurrentGear( const PxVehicleDriveDynData* inOwner ) { return inOwner->mCurrentGear; }
+inline void setPxVehicleDriveDynDataMCurrentGear( PxVehicleDriveDynData* inOwner, PxU32 inData) { inOwner->mCurrentGear = inData; }
+inline PxU32 getPxVehicleDriveDynDataMTargetGear( const PxVehicleDriveDynData* inOwner ) { return inOwner->mTargetGear; }
+inline void setPxVehicleDriveDynDataMTargetGear( PxVehicleDriveDynData* inOwner, PxU32 inData) { inOwner->mTargetGear = inData; }
+inline PxReal getPxVehicleDriveDynDataMEnginespeed( const PxVehicleDriveDynData* inOwner ) { return inOwner->mEnginespeed; }
+inline void setPxVehicleDriveDynDataMEnginespeed( PxVehicleDriveDynData* inOwner, PxReal inData) { inOwner->mEnginespeed = inData; }
+inline PxReal getPxVehicleDriveDynDataMGearSwitchTime( const PxVehicleDriveDynData* inOwner ) { return inOwner->mGearSwitchTime; }
+inline void setPxVehicleDriveDynDataMGearSwitchTime( PxVehicleDriveDynData* inOwner, PxReal inData) { inOwner->mGearSwitchTime = inData; }
+inline PxReal getPxVehicleDriveDynDataMAutoBoxSwitchTime( const PxVehicleDriveDynData* inOwner ) { return inOwner->mAutoBoxSwitchTime; }
+inline void setPxVehicleDriveDynDataMAutoBoxSwitchTime( PxVehicleDriveDynData* inOwner, PxReal inData) { inOwner->mAutoBoxSwitchTime = inData; }
+ PxVehicleDriveDynDataGeneratedInfo::PxVehicleDriveDynDataGeneratedInfo()
+ : AnalogInput( "AnalogInput", getPxVehicleDriveDynData_AnalogInput, getNbPxVehicleDriveDynData_AnalogInput, setPxVehicleDriveDynData_AnalogInput )
+ , GearUp( "GearUp", setPxVehicleDriveDynData_GearUp, getPxVehicleDriveDynData_GearUp)
+ , GearDown( "GearDown", setPxVehicleDriveDynData_GearDown, getPxVehicleDriveDynData_GearDown)
+ , UseAutoGears( "UseAutoGears", setPxVehicleDriveDynData_UseAutoGears, getPxVehicleDriveDynData_UseAutoGears)
+ , CurrentGear( "CurrentGear", setPxVehicleDriveDynData_CurrentGear, getPxVehicleDriveDynData_CurrentGear)
+ , TargetGear( "TargetGear", setPxVehicleDriveDynData_TargetGear, getPxVehicleDriveDynData_TargetGear)
+ , EngineRotationSpeed( "EngineRotationSpeed", setPxVehicleDriveDynData_EngineRotationSpeed, getPxVehicleDriveDynData_EngineRotationSpeed)
+ , GearChange( "GearChange", setPxVehicleDriveDynData_GearChange, getPxVehicleDriveDynData_GearChange)
+ , GearSwitchTime( "GearSwitchTime", setPxVehicleDriveDynData_GearSwitchTime, getPxVehicleDriveDynData_GearSwitchTime)
+ , AutoBoxSwitchTime( "AutoBoxSwitchTime", setPxVehicleDriveDynData_AutoBoxSwitchTime, getPxVehicleDriveDynData_AutoBoxSwitchTime)
+ , MUseAutoGears( "MUseAutoGears", setPxVehicleDriveDynDataMUseAutoGears, getPxVehicleDriveDynDataMUseAutoGears )
+ , MGearUpPressed( "MGearUpPressed", setPxVehicleDriveDynDataMGearUpPressed, getPxVehicleDriveDynDataMGearUpPressed )
+ , MGearDownPressed( "MGearDownPressed", setPxVehicleDriveDynDataMGearDownPressed, getPxVehicleDriveDynDataMGearDownPressed )
+ , MCurrentGear( "MCurrentGear", setPxVehicleDriveDynDataMCurrentGear, getPxVehicleDriveDynDataMCurrentGear )
+ , MTargetGear( "MTargetGear", setPxVehicleDriveDynDataMTargetGear, getPxVehicleDriveDynDataMTargetGear )
+ , MEnginespeed( "MEnginespeed", setPxVehicleDriveDynDataMEnginespeed, getPxVehicleDriveDynDataMEnginespeed )
+ , MGearSwitchTime( "MGearSwitchTime", setPxVehicleDriveDynDataMGearSwitchTime, getPxVehicleDriveDynDataMGearSwitchTime )
+ , MAutoBoxSwitchTime( "MAutoBoxSwitchTime", setPxVehicleDriveDynDataMAutoBoxSwitchTime, getPxVehicleDriveDynDataMAutoBoxSwitchTime )
+{}
+ PxVehicleDriveDynDataGeneratedValues::PxVehicleDriveDynDataGeneratedValues( const PxVehicleDriveDynData* inSource )
+ :GearUp( getPxVehicleDriveDynData_GearUp( inSource ) )
+ ,GearDown( getPxVehicleDriveDynData_GearDown( inSource ) )
+ ,UseAutoGears( getPxVehicleDriveDynData_UseAutoGears( inSource ) )
+ ,CurrentGear( getPxVehicleDriveDynData_CurrentGear( inSource ) )
+ ,TargetGear( getPxVehicleDriveDynData_TargetGear( inSource ) )
+ ,EngineRotationSpeed( getPxVehicleDriveDynData_EngineRotationSpeed( inSource ) )
+ ,GearChange( getPxVehicleDriveDynData_GearChange( inSource ) )
+ ,GearSwitchTime( getPxVehicleDriveDynData_GearSwitchTime( inSource ) )
+ ,AutoBoxSwitchTime( getPxVehicleDriveDynData_AutoBoxSwitchTime( inSource ) )
+ ,MUseAutoGears( inSource->mUseAutoGears )
+ ,MGearUpPressed( inSource->mGearUpPressed )
+ ,MGearDownPressed( inSource->mGearDownPressed )
+ ,MCurrentGear( inSource->mCurrentGear )
+ ,MTargetGear( inSource->mTargetGear )
+ ,MEnginespeed( inSource->mEnginespeed )
+ ,MGearSwitchTime( inSource->mGearSwitchTime )
+ ,MAutoBoxSwitchTime( inSource->mAutoBoxSwitchTime )
+{
+ PX_UNUSED(inSource);
+}
+void setPxVehicleDriveSimData_EngineData( PxVehicleDriveSimData* inObj, const PxVehicleEngineData & inArg){ inObj->setEngineData( inArg ); }
+PxVehicleEngineData getPxVehicleDriveSimData_EngineData( const PxVehicleDriveSimData* inObj ) { return inObj->getEngineData(); }
+void setPxVehicleDriveSimData_GearsData( PxVehicleDriveSimData* inObj, const PxVehicleGearsData & inArg){ inObj->setGearsData( inArg ); }
+PxVehicleGearsData getPxVehicleDriveSimData_GearsData( const PxVehicleDriveSimData* inObj ) { return inObj->getGearsData(); }
+void setPxVehicleDriveSimData_ClutchData( PxVehicleDriveSimData* inObj, const PxVehicleClutchData & inArg){ inObj->setClutchData( inArg ); }
+PxVehicleClutchData getPxVehicleDriveSimData_ClutchData( const PxVehicleDriveSimData* inObj ) { return inObj->getClutchData(); }
+void setPxVehicleDriveSimData_AutoBoxData( PxVehicleDriveSimData* inObj, const PxVehicleAutoBoxData & inArg){ inObj->setAutoBoxData( inArg ); }
+PxVehicleAutoBoxData getPxVehicleDriveSimData_AutoBoxData( const PxVehicleDriveSimData* inObj ) { return inObj->getAutoBoxData(); }
+ PxVehicleDriveSimDataGeneratedInfo::PxVehicleDriveSimDataGeneratedInfo()
+ : EngineData( "EngineData", setPxVehicleDriveSimData_EngineData, getPxVehicleDriveSimData_EngineData)
+ , GearsData( "GearsData", setPxVehicleDriveSimData_GearsData, getPxVehicleDriveSimData_GearsData)
+ , ClutchData( "ClutchData", setPxVehicleDriveSimData_ClutchData, getPxVehicleDriveSimData_ClutchData)
+ , AutoBoxData( "AutoBoxData", setPxVehicleDriveSimData_AutoBoxData, getPxVehicleDriveSimData_AutoBoxData)
+{}
+ PxVehicleDriveSimDataGeneratedValues::PxVehicleDriveSimDataGeneratedValues( const PxVehicleDriveSimData* inSource )
+ :EngineData( getPxVehicleDriveSimData_EngineData( inSource ) )
+ ,GearsData( getPxVehicleDriveSimData_GearsData( inSource ) )
+ ,ClutchData( getPxVehicleDriveSimData_ClutchData( inSource ) )
+ ,AutoBoxData( getPxVehicleDriveSimData_AutoBoxData( inSource ) )
+{
+ PX_UNUSED(inSource);
+}
+void setPxVehicleDriveSimData4W_DiffData( PxVehicleDriveSimData4W* inObj, const PxVehicleDifferential4WData & inArg){ inObj->setDiffData( inArg ); }
+PxVehicleDifferential4WData getPxVehicleDriveSimData4W_DiffData( const PxVehicleDriveSimData4W* inObj ) { return inObj->getDiffData(); }
+void setPxVehicleDriveSimData4W_AckermannGeometryData( PxVehicleDriveSimData4W* inObj, const PxVehicleAckermannGeometryData & inArg){ inObj->setAckermannGeometryData( inArg ); }
+PxVehicleAckermannGeometryData getPxVehicleDriveSimData4W_AckermannGeometryData( const PxVehicleDriveSimData4W* inObj ) { return inObj->getAckermannGeometryData(); }
+ PxVehicleDriveSimData4WGeneratedInfo::PxVehicleDriveSimData4WGeneratedInfo()
+ : DiffData( "DiffData", setPxVehicleDriveSimData4W_DiffData, getPxVehicleDriveSimData4W_DiffData)
+ , AckermannGeometryData( "AckermannGeometryData", setPxVehicleDriveSimData4W_AckermannGeometryData, getPxVehicleDriveSimData4W_AckermannGeometryData)
+{}
+ PxVehicleDriveSimData4WGeneratedValues::PxVehicleDriveSimData4WGeneratedValues( const PxVehicleDriveSimData4W* inSource )
+ :PxVehicleDriveSimDataGeneratedValues( inSource )
+ ,DiffData( getPxVehicleDriveSimData4W_DiffData( inSource ) )
+ ,AckermannGeometryData( getPxVehicleDriveSimData4W_AckermannGeometryData( inSource ) )
+{
+ PX_UNUSED(inSource);
+}
+const char * getPxVehicleDrive_ConcreteTypeName( const PxVehicleDrive* inObj ) { return inObj->getConcreteTypeName(); }
+inline PxVehicleDriveDynData getPxVehicleDriveMDriveDynData( const PxVehicleDrive* inOwner ) { return inOwner->mDriveDynData; }
+inline void setPxVehicleDriveMDriveDynData( PxVehicleDrive* inOwner, PxVehicleDriveDynData inData) { inOwner->mDriveDynData = inData; }
+ PxVehicleDriveGeneratedInfo::PxVehicleDriveGeneratedInfo()
+ : ConcreteTypeName( "ConcreteTypeName", getPxVehicleDrive_ConcreteTypeName)
+ , MDriveDynData( "MDriveDynData", setPxVehicleDriveMDriveDynData, getPxVehicleDriveMDriveDynData )
+{}
+ PxVehicleDriveGeneratedValues::PxVehicleDriveGeneratedValues( const PxVehicleDrive* inSource )
+ :PxVehicleWheelsGeneratedValues( inSource )
+ ,ConcreteTypeName( getPxVehicleDrive_ConcreteTypeName( inSource ) )
+ ,MDriveDynData( inSource->mDriveDynData )
+{
+ PX_UNUSED(inSource);
+}
+const char * getPxVehicleDrive4W_ConcreteTypeName( const PxVehicleDrive4W* inObj ) { return inObj->getConcreteTypeName(); }
+inline PxVehicleDriveSimData4W getPxVehicleDrive4WMDriveSimData( const PxVehicleDrive4W* inOwner ) { return inOwner->mDriveSimData; }
+inline void setPxVehicleDrive4WMDriveSimData( PxVehicleDrive4W* inOwner, PxVehicleDriveSimData4W inData) { inOwner->mDriveSimData = inData; }
+ PxVehicleDrive4WGeneratedInfo::PxVehicleDrive4WGeneratedInfo()
+ : ConcreteTypeName( "ConcreteTypeName", getPxVehicleDrive4W_ConcreteTypeName)
+ , MDriveSimData( "MDriveSimData", setPxVehicleDrive4WMDriveSimData, getPxVehicleDrive4WMDriveSimData )
+{}
+ PxVehicleDrive4WGeneratedValues::PxVehicleDrive4WGeneratedValues( const PxVehicleDrive4W* inSource )
+ :PxVehicleDriveGeneratedValues( inSource )
+ ,ConcreteTypeName( getPxVehicleDrive4W_ConcreteTypeName( inSource ) )
+ ,MDriveSimData( inSource->mDriveSimData )
+{
+ PX_UNUSED(inSource);
+}
+void setPxVehicleDriveTank_DriveModel( PxVehicleDriveTank* inObj, const PxVehicleDriveTankControlModel::Enum inArg){ inObj->setDriveModel( inArg ); }
+PxVehicleDriveTankControlModel::Enum getPxVehicleDriveTank_DriveModel( const PxVehicleDriveTank* inObj ) { return inObj->getDriveModel(); }
+const char * getPxVehicleDriveTank_ConcreteTypeName( const PxVehicleDriveTank* inObj ) { return inObj->getConcreteTypeName(); }
+inline PxVehicleDriveSimData getPxVehicleDriveTankMDriveSimData( const PxVehicleDriveTank* inOwner ) { return inOwner->mDriveSimData; }
+inline void setPxVehicleDriveTankMDriveSimData( PxVehicleDriveTank* inOwner, PxVehicleDriveSimData inData) { inOwner->mDriveSimData = inData; }
+ PxVehicleDriveTankGeneratedInfo::PxVehicleDriveTankGeneratedInfo()
+ : DriveModel( "DriveModel", setPxVehicleDriveTank_DriveModel, getPxVehicleDriveTank_DriveModel)
+ , ConcreteTypeName( "ConcreteTypeName", getPxVehicleDriveTank_ConcreteTypeName)
+ , MDriveSimData( "MDriveSimData", setPxVehicleDriveTankMDriveSimData, getPxVehicleDriveTankMDriveSimData )
+{}
+ PxVehicleDriveTankGeneratedValues::PxVehicleDriveTankGeneratedValues( const PxVehicleDriveTank* inSource )
+ :PxVehicleDriveGeneratedValues( inSource )
+ ,DriveModel( getPxVehicleDriveTank_DriveModel( inSource ) )
+ ,ConcreteTypeName( getPxVehicleDriveTank_ConcreteTypeName( inSource ) )
+ ,MDriveSimData( inSource->mDriveSimData )
+{
+ PX_UNUSED(inSource);
+}
+void setPxVehicleDriveSimDataNW_DiffData( PxVehicleDriveSimDataNW* inObj, const PxVehicleDifferentialNWData & inArg){ inObj->setDiffData( inArg ); }
+PxVehicleDifferentialNWData getPxVehicleDriveSimDataNW_DiffData( const PxVehicleDriveSimDataNW* inObj ) { return inObj->getDiffData(); }
+ PxVehicleDriveSimDataNWGeneratedInfo::PxVehicleDriveSimDataNWGeneratedInfo()
+ : DiffData( "DiffData", setPxVehicleDriveSimDataNW_DiffData, getPxVehicleDriveSimDataNW_DiffData)
+{}
+ PxVehicleDriveSimDataNWGeneratedValues::PxVehicleDriveSimDataNWGeneratedValues( const PxVehicleDriveSimDataNW* inSource )
+ :PxVehicleDriveSimDataGeneratedValues( inSource )
+ ,DiffData( getPxVehicleDriveSimDataNW_DiffData( inSource ) )
+{
+ PX_UNUSED(inSource);
+}
+const char * getPxVehicleDriveNW_ConcreteTypeName( const PxVehicleDriveNW* inObj ) { return inObj->getConcreteTypeName(); }
+inline PxVehicleDriveSimDataNW getPxVehicleDriveNWMDriveSimData( const PxVehicleDriveNW* inOwner ) { return inOwner->mDriveSimData; }
+inline void setPxVehicleDriveNWMDriveSimData( PxVehicleDriveNW* inOwner, PxVehicleDriveSimDataNW inData) { inOwner->mDriveSimData = inData; }
+ PxVehicleDriveNWGeneratedInfo::PxVehicleDriveNWGeneratedInfo()
+ : ConcreteTypeName( "ConcreteTypeName", getPxVehicleDriveNW_ConcreteTypeName)
+ , MDriveSimData( "MDriveSimData", setPxVehicleDriveNWMDriveSimData, getPxVehicleDriveNWMDriveSimData )
+{}
+ PxVehicleDriveNWGeneratedValues::PxVehicleDriveNWGeneratedValues( const PxVehicleDriveNW* inSource )
+ :PxVehicleDriveGeneratedValues( inSource )
+ ,ConcreteTypeName( getPxVehicleDriveNW_ConcreteTypeName( inSource ) )
+ ,MDriveSimData( inSource->mDriveSimData )
+{
+ PX_UNUSED(inSource);
+}
+PxReal getPxVehicleNoDrive_BrakeTorque( const PxVehicleNoDrive* inObj, const PxU32 index ) { return inObj->getBrakeTorque( index ); }
+PxU32 getNbPxVehicleNoDrive_BrakeTorque( const PxVehicleNoDrive* inObj ) { return inObj->getNbBrakeTorque( ); }
+void setPxVehicleNoDrive_BrakeTorque( PxVehicleNoDrive* inObj, const PxU32 inIndex, PxReal inValue ){ inObj->setBrakeTorque( inIndex, inValue ); }
+PxReal getPxVehicleNoDrive_DriveTorque( const PxVehicleNoDrive* inObj, const PxU32 index ) { return inObj->getDriveTorque( index ); }
+PxU32 getNbPxVehicleNoDrive_DriveTorque( const PxVehicleNoDrive* inObj ) { return inObj->getNbDriveTorque( ); }
+void setPxVehicleNoDrive_DriveTorque( PxVehicleNoDrive* inObj, const PxU32 inIndex, PxReal inValue ){ inObj->setDriveTorque( inIndex, inValue ); }
+PxReal getPxVehicleNoDrive_SteerAngle( const PxVehicleNoDrive* inObj, const PxU32 index ) { return inObj->getSteerAngle( index ); }
+PxU32 getNbPxVehicleNoDrive_SteerAngle( const PxVehicleNoDrive* inObj ) { return inObj->getNbSteerAngle( ); }
+void setPxVehicleNoDrive_SteerAngle( PxVehicleNoDrive* inObj, const PxU32 inIndex, PxReal inValue ){ inObj->setSteerAngle( inIndex, inValue ); }
+const char * getPxVehicleNoDrive_ConcreteTypeName( const PxVehicleNoDrive* inObj ) { return inObj->getConcreteTypeName(); }
+ PxVehicleNoDriveGeneratedInfo::PxVehicleNoDriveGeneratedInfo()
+ : BrakeTorque( "BrakeTorque", getPxVehicleNoDrive_BrakeTorque, getNbPxVehicleNoDrive_BrakeTorque, setPxVehicleNoDrive_BrakeTorque )
+ , DriveTorque( "DriveTorque", getPxVehicleNoDrive_DriveTorque, getNbPxVehicleNoDrive_DriveTorque, setPxVehicleNoDrive_DriveTorque )
+ , SteerAngle( "SteerAngle", getPxVehicleNoDrive_SteerAngle, getNbPxVehicleNoDrive_SteerAngle, setPxVehicleNoDrive_SteerAngle )
+ , ConcreteTypeName( "ConcreteTypeName", getPxVehicleNoDrive_ConcreteTypeName)
+{}
+ PxVehicleNoDriveGeneratedValues::PxVehicleNoDriveGeneratedValues( const PxVehicleNoDrive* inSource )
+ :PxVehicleWheelsGeneratedValues( inSource )
+ ,ConcreteTypeName( getPxVehicleNoDrive_ConcreteTypeName( inSource ) )
+{
+ PX_UNUSED(inSource);
+}
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/src/PxVehicleMetaDataObjects.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/src/PxVehicleMetaDataObjects.cpp
new file mode 100644
index 00000000..d0263a22
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PhysXMetaData/src/PxVehicleMetaDataObjects.cpp
@@ -0,0 +1,86 @@
+// 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 "PxPhysicsAPI.h"
+#include "extensions/PxExtensionsAPI.h"
+#include "PxVehicleMetaDataObjects.h"
+#include "PxExtensionMetaDataObjects.h"
+
+namespace physx
+{
+ inline void SetMFrictionVsSlipGraph( PxVehicleTireData* inTireData, PxU32 idx1, PxU32 idx2, PxReal val ) { inTireData->mFrictionVsSlipGraph[idx1][idx2] = val; }
+ inline PxReal GetMFrictionVsSlipGraph( const PxVehicleTireData* inTireData, PxU32 idx1, PxU32 idx2 )
+ {
+ return inTireData->mFrictionVsSlipGraph[idx1][idx2];
+ }
+ PX_PHYSX_CORE_API MFrictionVsSlipGraphProperty::MFrictionVsSlipGraphProperty()
+ : PxExtendedDualIndexedPropertyInfo<PxVehiclePropertyInfoName::PxVehicleTireData_MFrictionVsSlipGraph
+ , PxVehicleTireData
+ , PxU32
+ , PxU32
+ , PxReal> ( "MFrictionVsSlipGraph", SetMFrictionVsSlipGraph, GetMFrictionVsSlipGraph, 3, 2 )
+ {
+
+ }
+
+ inline PxU32 GetNbWheels( const PxVehicleWheels* inStats ) { return inStats->mWheelsSimData.getNbWheels(); }
+
+ inline PxU32 GetNbTorqueCurvePair( const PxVehicleEngineData* inStats ) { return inStats->mTorqueCurve.getNbDataPairs(); }
+
+
+ inline PxReal getXTorqueCurvePair( const PxVehicleEngineData* inStats, PxU32 index)
+ {
+ return inStats->mTorqueCurve.getX(index);
+ }
+ inline PxReal getYTorqueCurvePair( const PxVehicleEngineData* inStats, PxU32 index)
+ {
+ return inStats->mTorqueCurve.getY(index);
+ }
+
+ void addTorqueCurvePair(PxVehicleEngineData* inStats, const PxReal x, const PxReal y)
+ {
+ inStats->mTorqueCurve.addPair(x, y);
+ }
+
+ void clearTorqueCurvePair(PxVehicleEngineData* inStats)
+ {
+ inStats->mTorqueCurve.clear();
+ }
+
+ PX_PHYSX_CORE_API MTorqueCurveProperty::MTorqueCurveProperty()
+ : PxFixedSizeLookupTablePropertyInfo<PxVehiclePropertyInfoName::PxVehicleEngineData_MTorqueCurve
+ , PxVehicleEngineData
+ , PxU32
+ , PxReal>("MTorqueCurve", getXTorqueCurvePair, getYTorqueCurvePair, GetNbTorqueCurvePair, addTorqueCurvePair, clearTorqueCurvePair)
+ {
+ }
+
+
+}
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleComponents.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleComponents.cpp
new file mode 100644
index 00000000..2960d634
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleComponents.cpp
@@ -0,0 +1,222 @@
+// 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 "PxVehicleComponents.h"
+#include "PxVehicleDefaults.h"
+#include "CmPhysXCommon.h"
+#include "CmBitMap.h"
+#include "PsFoundation.h"
+
+namespace physx
+{
+
+bool PxVehicleChassisData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mMOI.x>0.0f && mMOI.y>0.0f && mMOI.z>0.0f, "Illegal PxVehicleChassisData.mMOI - each element of the chassis moi needs to non-zero", false);
+ PX_CHECK_AND_RETURN_VAL(mMass>0.0f, "Ilegal PxVehicleChassisData.mMass - chassis mass needs to be non-zero", false);
+ return true;
+}
+
+
+bool PxVehicleEngineData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mPeakTorque>0.0f, "PxVehicleEngineData.mPeakTorque must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mMaxOmega>0.0f, "PxVehicleEngineData.mMaxOmega must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mDampingRateFullThrottle>0.0f, "PxVehicleEngineData.mDampingRateFullThrottle must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mDampingRateZeroThrottleClutchEngaged>0.0f, "PxVehicleEngineData.mDampingRateZeroThrottleClutchEngaged must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mDampingRateZeroThrottleClutchDisengaged>0.0f, "PxVehicleEngineData.mDampingRateZeroThrottleClutchDisengaged must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mRecipMOI>0.0f, "PxVehicleEngineData.mRecipMOI must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mRecipMaxOmega>0.0f, "PxVehicleEngineData.mRecipMaxOmega must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(PxAbs((1.0f/mMaxOmega)-mRecipMaxOmega) <= 0.001f, "PxVehicleEngineData.mMaxOmega and PxVehicleEngineData.mRecipMaxOmega don't match", false);
+ return true;
+}
+
+bool PxVehicleGearsData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mFinalRatio>0, "PxVehicleGearsData.mFinalRatio must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mNbRatios>=1, "PxVehicleGearsData.mNbRatios must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mSwitchTime>=0.0f, "PxVehicleGearsData.mSwitchTime must be greater than or equal to zero", false);
+
+ PX_CHECK_AND_RETURN_VAL(mRatios[PxVehicleGearsData::eREVERSE]<0.0f, "PxVehicleGearsData.mRatios[PxVehicleGearsData::eREVERSE] must be less than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mRatios[PxVehicleGearsData::eNEUTRAL]==0.0f, "PxVehicleGearsData.mRatios[PxVehicleGearsData::eNEUTRAL] must be zero", false);
+ for(PxU32 i=PxVehicleGearsData::eFIRST;i<mNbRatios;i++)
+ {
+ PX_CHECK_AND_RETURN_VAL(mRatios[i]>0.0f, "Forward gear ratios must be greater than zero", false);
+ }
+ for(PxU32 i=PxVehicleGearsData::eSECOND;i<mNbRatios;i++)
+ {
+ PX_CHECK_AND_RETURN_VAL(mRatios[i]<mRatios[i-1], "Forward gear ratios must be a descending sequence of gear ratios", false);
+ }
+ return true;
+}
+
+bool PxVehicleAutoBoxData::isValid() const
+{
+ for(PxU32 i=0;i<PxVehicleGearsData::eGEARSRATIO_COUNT;i++)
+ {
+ PX_CHECK_AND_RETURN_VAL(mUpRatios[i]>=0.0f, "PxVehicleAutoBoxData.mUpRatios must be greater than or equal to zero", false);
+ PX_CHECK_AND_RETURN_VAL(mDownRatios[i]>=0.0f, "PxVehicleAutoBoxData.mDownRatios must be greater than or equal to zero", false);
+ }
+ return true;
+}
+
+bool PxVehicleDifferential4WData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mFrontRearSplit<=1.0f && mFrontRearSplit>=0.0f, "PxVehicleDifferential4WData.mFrontRearSplit must be in range (0,1)", false);
+ PX_CHECK_AND_RETURN_VAL(mFrontLeftRightSplit<=1.0f && mFrontLeftRightSplit>=0.0f, "PxVehicleDifferential4WData.mFrontLeftRightSplit must be in range (0,1)", false);
+ PX_CHECK_AND_RETURN_VAL(mRearLeftRightSplit<=1.0f || mRearLeftRightSplit>=0.0f, "PxVehicleDifferential4WData.mRearLeftRightSplit must be in range (0,1)", false);
+ PX_CHECK_AND_RETURN_VAL(mCentreBias>=1.0f, "PxVehicleDifferential4WData.mCentreBias must be greater than or equal to 1.0f", false);
+ PX_CHECK_AND_RETURN_VAL(mFrontBias>=1.0f, "PxVehicleDifferential4WData.mFrontBias must be greater than or equal to 1.0f", false);
+ PX_CHECK_AND_RETURN_VAL(mRearBias>=1.0f, "PxVehicleDifferential4WData.mRearBias must be greater than or equal to 1.0f", false);
+ PX_CHECK_AND_RETURN_VAL(mType<PxVehicleDifferential4WData::eMAX_NB_DIFF_TYPES, "PxVehicleDifferential4WData.mType has illegal value", false);
+ return true;
+}
+
+void PxVehicleDifferentialNWData::setDrivenWheel(const PxU32 wheelId, const bool drivenState)
+{
+ Cm::BitMap bitmap;
+ bitmap.setWords(mBitmapBuffer,((PX_MAX_NB_WHEELS + 31) & ~31) >> 5);
+ PxU32 numDrivenWheels=mNbDrivenWheels;
+ if(drivenState)
+ {
+ if(!bitmap.test(wheelId))
+ {
+ numDrivenWheels++;
+ bitmap.set(wheelId);
+ mInvNbDrivenWheels=1.0f/(1.0f*numDrivenWheels);
+ }
+ }
+ else if(bitmap.test(wheelId))
+ {
+ numDrivenWheels--;
+ bitmap.reset(wheelId);
+ mInvNbDrivenWheels = numDrivenWheels>0.0f ? 1.0f/(1.0f*numDrivenWheels) : 0.0f;
+ }
+ mNbDrivenWheels=numDrivenWheels;
+}
+
+bool PxVehicleDifferentialNWData::getIsDrivenWheel(const PxU32 wheelId) const
+{
+ Cm::BitMap bitmap;
+ bitmap.setWords(const_cast<PxU32*>(mBitmapBuffer),((PX_MAX_NB_WHEELS + 31) & ~31) >> 5);
+ return (bitmap.test(wheelId) ? true : false);
+}
+
+PxU32 PxVehicleDifferentialNWData::getDrivenWheelStatus() const
+{
+ PX_ASSERT(((PX_MAX_NB_WHEELS + 31) & ~31) >> 5 == 1);
+ return mBitmapBuffer[0];
+}
+
+void PxVehicleDifferentialNWData::setDrivenWheelStatus(PxU32 status)
+{
+ PX_ASSERT(((PX_MAX_NB_WHEELS + 31) & ~31) >> 5 == 1);
+
+ Cm::BitMap bitmap;
+ bitmap.setWords(&status, 1);
+
+ for(PxU32 i = 0; i < PX_MAX_NB_WHEELS; ++i)
+ {
+ setDrivenWheel(i, !!bitmap.test(i));
+ }
+}
+
+bool PxVehicleDifferentialNWData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mNbDrivenWheels<=PX_MAX_NB_WHEELS, "PxVehicleDifferentialNWData.mNbDrivenWheels must be in range (0,20)", false);
+ return true;
+}
+
+bool PxVehicleAckermannGeometryData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mAccuracy>=0.0f && mAccuracy<=1.0f, "PxVehicleAckermannGeometryData.mAccuracy must be in range (0,1)", false);
+ PX_CHECK_AND_RETURN_VAL(mFrontWidth>0.0f, "PxVehicleAckermannGeometryData.mFrontWidth must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mRearWidth>0.0f, "PxVehicleAckermannGeometryData.mRearWidth must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mAxleSeparation>0.0f, "PxVehicleAckermannGeometryData.mAxleSeparation must be greater than zero", false);
+ return true;
+}
+
+bool PxVehicleClutchData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mStrength>0, "PxVehicleClutchData.mStrength must be greater than zero", false);
+ return true;
+}
+
+bool PxVehicleTireLoadFilterData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mMaxNormalisedLoad>=mMinNormalisedLoad, "PxVehicleTireLoadFilterData.mMaxNormalisedLoad must be greater than or equal to PxVehicleTireLoadFilterData.mMinNormalisedLoad", false);
+ PX_CHECK_AND_RETURN_VAL(mMaxFilteredNormalisedLoad>0, "PxVehicleTireLoadFilterData.mMaxFilteredNormalisedLoad must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(PxAbs((1.0f/(mMaxNormalisedLoad - mMinNormalisedLoad)) - mDenominator) < 0.001f, "PxVehicleTireLoadFilterData.mMaxFilteredNormalisedLoad, PxVehicleTireLoadFilterData.mMinNormalisedLoad, and PxVehicleTireLoadFilterData.mDenominator don't match", false);
+ return true;
+}
+
+bool PxVehicleWheelData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mRadius>0.0f, "PxVehicleWheelData.mRadius must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mWidth>0.0f, "PxVehicleWheelData.mWidth must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mMass>0.0f, "PxVehicleWheelData.mMass must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mMOI>0.0f, "PxVehicleWheelData.mMOI must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mDampingRate>0.0f, "PxVehicleWheelData.mDampingRate must be greater than zero", false);
+ PX_CHECK_AND_RETURN_VAL(mMaxBrakeTorque>=0.0f, "PxVehicleWheelData.mMaxBrakeTorque must be greater than or equal to zero", false);
+ PX_CHECK_AND_RETURN_VAL(mMaxHandBrakeTorque>=0.0f, "PxVehicleWheelData.mMaxHandBrakeTorque must be greater than or equal to zero", false);
+ PX_CHECK_AND_RETURN_VAL(mToeAngle<=PxPi, "PxVehicleWheelData.mToeAngle must be less than Pi", false);
+ PX_CHECK_AND_RETURN_VAL(PxAbs((1.0f/mRadius) - mRecipRadius) < 0.001f, "PxVehicleWheelData.mRadius and PxVehicleWheelData.mRecipRadius don't match", false);
+ PX_CHECK_AND_RETURN_VAL(PxAbs((1.0f/mMOI) - mRecipMOI) < 0.001f, "PxVehicleWheelData.mMOI and PxVehicleWheelData.mRecipMOI don't match", false);
+ return true;
+}
+
+bool PxVehicleSuspensionData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mSpringStrength>=0.0f, "PxVehicleSuspensionData.mSpringStrength must be greater than or equal to zero", false);
+ PX_CHECK_AND_RETURN_VAL(mSpringDamperRate>=0.0f, "PxVehicleSuspensionData.mSpringDamperRate must be greater than or equal to zero", false);
+ PX_CHECK_AND_RETURN_VAL(mMaxCompression>=0.0f, "PxVehicleSuspensionData.mMaxCompression must be greater than or equal to zero", false);
+ PX_CHECK_AND_RETURN_VAL(mMaxDroop>=0.0f, "PxVehicleSuspensionData.mMaxDroop must be greater than or equal to zero", false);
+ PX_CHECK_AND_RETURN_VAL(mSprungMass>=0.0f, "PxVehicleSuspensionData.mSprungMass must be greater than or equal to zero", false);
+ return true;
+}
+
+bool PxVehicleAntiRollBarData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(((mWheel0< PX_MAX_NB_WHEELS) && (mWheel1 < PX_MAX_NB_WHEELS)), "PxVehicleAntiRoll.mWheel0 and PxVehicleAntiRoll.mWheel1 are an illegal pair", false);
+ PX_CHECK_AND_RETURN_VAL((mWheel0 != mWheel1), "PxVehicleAntiRoll.mWheel0 == PxVehicleAntiRoll.mWheel1", false);
+ PX_CHECK_AND_RETURN_VAL(mStiffness>=0, "PxVehicleAntiRoll::mStiffness must be greater than or equal to zero", false);
+ return true;
+}
+
+bool PxVehicleTireData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mFrictionVsSlipGraph[0][0]>=0.0f && mFrictionVsSlipGraph[0][1]>=0.0f, "Illegal values for mFrictionVsSlipGraph[0]", false);
+ PX_CHECK_AND_RETURN_VAL(mFrictionVsSlipGraph[1][0]>=0.0f && mFrictionVsSlipGraph[1][1]>=0.0f, "Illegal values for mFrictionVsSlipGraph[1]", false);
+ PX_CHECK_AND_RETURN_VAL(mFrictionVsSlipGraph[2][0]>=0.0f && mFrictionVsSlipGraph[2][1]>=0.0f, "Illegal values for mFrictionVsSlipGraph[2]", false);
+ PX_CHECK_AND_RETURN_VAL(PxAbs((1.0f/(mFrictionVsSlipGraph[1][0]-mFrictionVsSlipGraph[0][0])) - mFrictionVsSlipGraphRecipx1Minusx0) < 0.001f, "PxVehicleTireData.mFrictionVsSlipGraphRecipx1Minusx0 not set up", false);
+ PX_CHECK_AND_RETURN_VAL(PxAbs((1.0f/(mFrictionVsSlipGraph[2][0]-mFrictionVsSlipGraph[1][0])) - mFrictionVsSlipGraphRecipx2Minusx1) < 0.001f, "PxVehicleTireData.mFrictionVsSlipGraphRecipx2Minusx1 not set up", false);
+ return true;
+}
+} //namespace physx
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDefaults.h b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDefaults.h
new file mode 100644
index 00000000..6cf87b24
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDefaults.h
@@ -0,0 +1,46 @@
+// 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 PX_VEHICLE_DEFAULTS_H
+#define PX_VEHICLE_DEFAULTS_H
+/** \addtogroup vehicle
+ @{
+*/
+
+#if !PX_DOXYGEN
+namespace physx
+{
+#endif
+
+#if !PX_DOXYGEN
+} // namespace physx
+#endif
+
+/** @} */
+#endif //PX_VEHICLE_DEFAULTS_H
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDrive.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDrive.cpp
new file mode 100644
index 00000000..d26b67fd
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDrive.cpp
@@ -0,0 +1,213 @@
+// 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 "PxVehicleDrive.h"
+#include "PxVehicleSDK.h"
+#include "PxVehicleDefaults.h"
+#include "PxRigidDynamic.h"
+#include "PsFoundation.h"
+#include "PsUtilities.h"
+#include "CmPhysXCommon.h"
+
+namespace physx
+{
+
+bool PxVehicleDriveSimData::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mEngine.isValid(), "Invalid PxVehicleCoreSimulationData.mEngine", false);
+ PX_CHECK_AND_RETURN_VAL(mGears.isValid(), "Invalid PxVehicleCoreSimulationData.mGears", false);
+ PX_CHECK_AND_RETURN_VAL(mClutch.isValid(), "Invalid PxVehicleCoreSimulationData.mClutch", false);
+ PX_CHECK_AND_RETURN_VAL(mAutoBox.isValid(), "Invalid PxVehicleCoreSimulationData.mAutoBox", false);
+ return true;
+}
+
+void PxVehicleDriveSimData::setEngineData(const PxVehicleEngineData& engine)
+{
+ PX_CHECK_AND_RETURN(engine.mTorqueCurve.getNbDataPairs()>0, "Engine torque curve must specify at least one entry");
+ PX_CHECK_AND_RETURN(engine.mPeakTorque>0, "Engine peak torque must be greater than zero");
+ PX_CHECK_AND_RETURN(engine.mMaxOmega>0, "Engine max omega must be greater than zero");
+ PX_CHECK_AND_RETURN(engine.mDampingRateFullThrottle>=0, "Full throttle damping rate must be greater than or equal to zero");
+ PX_CHECK_AND_RETURN(engine.mDampingRateZeroThrottleClutchEngaged>=0, "Zero throttle clutch engaged damping rate must be greater than or equal to zero");
+ PX_CHECK_AND_RETURN(engine.mDampingRateZeroThrottleClutchDisengaged>=0, "Zero throttle clutch disengaged damping rate must be greater than or equal to zero");
+
+ mEngine=engine;
+ mEngine.mRecipMOI=1.0f/engine.mMOI;
+ mEngine.mRecipMaxOmega=1.0f/engine.mMaxOmega;
+}
+
+void PxVehicleDriveSimData::setGearsData(const PxVehicleGearsData& gears)
+{
+ PX_CHECK_AND_RETURN(gears.mRatios[PxVehicleGearsData::eREVERSE]<0, "Reverse gear ratio must be negative");
+ PX_CHECK_AND_RETURN(gears.mRatios[PxVehicleGearsData::eNEUTRAL]==0, "Neutral gear ratio must be zero");
+ PX_CHECK_AND_RETURN(gears.mRatios[PxVehicleGearsData::eFIRST]>0, "First gear ratio must be positive");
+ PX_CHECK_AND_RETURN(PxVehicleGearsData::eSECOND>=gears.mNbRatios || (gears.mRatios[PxVehicleGearsData::eSECOND]>0 && gears.mRatios[PxVehicleGearsData::eSECOND] < gears.mRatios[PxVehicleGearsData::eFIRST]), "Second gear ratio must be positive and less than first gear ratio");
+ PX_CHECK_AND_RETURN(PxVehicleGearsData::eTHIRD>=gears.mNbRatios || (gears.mRatios[PxVehicleGearsData::eTHIRD]>0 && gears.mRatios[PxVehicleGearsData::eTHIRD] < gears.mRatios[PxVehicleGearsData::eSECOND]), "Third gear ratio must be positive and less than second gear ratio");
+ PX_CHECK_AND_RETURN(PxVehicleGearsData::eFOURTH>=gears.mNbRatios || (gears.mRatios[PxVehicleGearsData::eFOURTH]>0 && gears.mRatios[PxVehicleGearsData::eFOURTH] < gears.mRatios[PxVehicleGearsData::eTHIRD]), "Fourth gear ratio must be positive and less than third gear ratio");
+ PX_CHECK_AND_RETURN(PxVehicleGearsData::eFIFTH>=gears.mNbRatios || (gears.mRatios[PxVehicleGearsData::eFIFTH]>0 && gears.mRatios[PxVehicleGearsData::eFIFTH] < gears.mRatios[PxVehicleGearsData::eFOURTH]), "Fifth gear ratio must be positive and less than fourth gear ratio");
+ PX_CHECK_AND_RETURN(PxVehicleGearsData::eSIXTH>=gears.mNbRatios || (gears.mRatios[PxVehicleGearsData::eSIXTH]>0 && gears.mRatios[PxVehicleGearsData::eSIXTH] < gears.mRatios[PxVehicleGearsData::eFIFTH]), "Sixth gear ratio must be positive and less than fifth gear ratio");
+ PX_CHECK_AND_RETURN(gears.mFinalRatio>0, "Final gear ratio must be greater than zero");
+ PX_CHECK_AND_RETURN(gears.mNbRatios>=3, "Number of gear ratios must be at least 3 - we need at least reverse, neutral, and a forward gear");
+
+ mGears=gears;
+}
+
+void PxVehicleDriveSimData::setClutchData(const PxVehicleClutchData& clutch)
+{
+ PX_CHECK_AND_RETURN(clutch.mStrength>0, "Clutch strength must be greater than zero");
+ PX_CHECK_AND_RETURN(PxVehicleClutchAccuracyMode::eBEST_POSSIBLE==clutch.mAccuracyMode || clutch.mEstimateIterations > 0, "Clutch mEstimateIterations must be greater than zero in eESTIMATE mode.");
+
+ mClutch=clutch;
+}
+
+void PxVehicleDriveSimData::setAutoBoxData(const PxVehicleAutoBoxData& autobox)
+{
+ PX_CHECK_AND_RETURN(autobox.mUpRatios[PxVehicleGearsData::eREVERSE]>=0, "Autobox gearup ratio in reverse must be greater than or equal to zero");
+ PX_CHECK_AND_RETURN(autobox.mUpRatios[PxVehicleGearsData::eNEUTRAL]>=0, "Autobox gearup ratio in neutral must be greater than zero");
+ PX_CHECK_AND_RETURN(autobox.mUpRatios[PxVehicleGearsData::eFIRST]>=0, "Autobox gearup ratio in first must be greater than or equal to zero");
+ PX_CHECK_AND_RETURN(autobox.mUpRatios[PxVehicleGearsData::eSECOND]>=0, "Autobox gearup ratio in second must be greater than zero");
+ PX_CHECK_AND_RETURN(autobox.mUpRatios[PxVehicleGearsData::eTHIRD]>=0, "Autobox gearup ratio in third must be greater than zero");
+ PX_CHECK_AND_RETURN(autobox.mUpRatios[PxVehicleGearsData::eFOURTH]>=0, "Autobox gearup ratio in fourth must be greater than zero");
+ PX_CHECK_AND_RETURN(autobox.mUpRatios[PxVehicleGearsData::eFIFTH]>=0, "Autobox gearup ratio in fifth must be greater than zero");
+ PX_CHECK_AND_RETURN(autobox.mDownRatios[PxVehicleGearsData::eREVERSE]>=0, "Autobox geardown ratio in reverse must be greater than or equal to zero");
+ PX_CHECK_AND_RETURN(autobox.mDownRatios[PxVehicleGearsData::eNEUTRAL]>=0, "Autobox geardown ratio in neutral must be greater than zero");
+ PX_CHECK_AND_RETURN(autobox.mDownRatios[PxVehicleGearsData::eFIRST]>=0, "Autobox geardown ratio in first must be greater than or equal to zero");
+ PX_CHECK_AND_RETURN(autobox.mDownRatios[PxVehicleGearsData::eSECOND]>=0, "Autobox geardown ratio in second must be greater than zero");
+ PX_CHECK_AND_RETURN(autobox.mDownRatios[PxVehicleGearsData::eTHIRD]>=0, "Autobox geardown ratio in third must be greater than zero");
+ PX_CHECK_AND_RETURN(autobox.mDownRatios[PxVehicleGearsData::eFOURTH]>=0, "Autobox geardown ratio in fourth must be greater than zero");
+ PX_CHECK_AND_RETURN(autobox.mDownRatios[PxVehicleGearsData::eFIFTH]>=0, "Autobox geardown ratio in fifth must be greater than zero");
+ PX_CHECK_AND_RETURN(autobox.mDownRatios[PxVehicleGearsData::eSIXTH]>=0, "Autobox geardown ratio in fifth must be greater than zero");
+
+ mAutoBox=autobox;
+}
+
+///////////////////////////////////
+
+PxVehicleDriveDynData::PxVehicleDriveDynData()
+ : mUseAutoGears(false),
+ mGearUpPressed(false),
+ mGearDownPressed(false),
+ mCurrentGear(PxVehicleGearsData::eNEUTRAL),
+ mTargetGear(PxVehicleGearsData::eNEUTRAL),
+ mEnginespeed(0.0f),
+ mGearSwitchTime(0.0f),
+ mAutoBoxSwitchTime(0.0f)
+{
+ for(PxU32 i=0;i<eMAX_NB_ANALOG_INPUTS;i++)
+ {
+ mControlAnalogVals[i]=0.0f;
+ }
+}
+
+void PxVehicleDriveDynData::setToRestState()
+{
+ //Set analog inputs to zero so the vehicle starts completely at rest.
+ for(PxU32 i=0;i<eMAX_NB_ANALOG_INPUTS;i++)
+ {
+ mControlAnalogVals[i]=0.0f;
+ }
+ mGearUpPressed=false;
+ mGearDownPressed=false;
+
+ //Set the vehicle to neutral gear.
+ mCurrentGear=PxVehicleGearsData::eNEUTRAL;
+ mTargetGear=PxVehicleGearsData::eNEUTRAL;
+ mGearSwitchTime=0.0f;
+ mAutoBoxSwitchTime=0.0f;
+
+ //Set internal dynamics to zero so the vehicle starts completely at rest.
+ mEnginespeed=0.0f;
+}
+
+bool PxVehicleDriveDynData::isValid() const
+{
+ return true;
+}
+
+void PxVehicleDriveDynData::setAnalogInput(const PxU32 type, const PxReal analogVal)
+{
+ PX_CHECK_AND_RETURN(analogVal>=-1.01f && analogVal<=1.01f, "PxVehicleDriveDynData::setAnalogInput - analogVal must be in range (-1,1)");
+ PX_CHECK_AND_RETURN(type<eMAX_NB_ANALOG_INPUTS, "PxVehicleDriveDynData::setAnalogInput - illegal type");
+ mControlAnalogVals[type]=analogVal;
+}
+
+PxReal PxVehicleDriveDynData::getAnalogInput(const PxU32 type) const
+{
+ PX_CHECK_AND_RETURN_VAL(type<eMAX_NB_ANALOG_INPUTS, "PxVehicleDriveDynData::getAnalogInput - illegal type", 0.0f);
+ return mControlAnalogVals[type];
+}
+
+///////////////////////////////////
+
+bool PxVehicleDrive::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(PxVehicleWheels::isValid(), "invalid PxVehicleWheels", false);
+ PX_CHECK_AND_RETURN_VAL(mDriveDynData.isValid(), "Invalid PxVehicleDrive.mCoreSimData", false);
+ return true;
+}
+
+PxU32 PxVehicleDrive::computeByteSize(const PxU32 numWheels)
+{
+ return PxVehicleWheels::computeByteSize(numWheels);
+}
+
+PxU8* PxVehicleDrive::patchupPointers( const PxU32 numWheels, PxVehicleDrive* veh, PxU8* ptr)
+{
+ return PxVehicleWheels::patchupPointers(numWheels, veh, ptr);
+}
+
+void PxVehicleDrive::init(const PxU32 numWheels)
+{
+ PxVehicleWheels::init(numWheels);
+}
+
+void PxVehicleDrive::free()
+{
+ PxVehicleWheels::free();
+}
+
+void PxVehicleDrive::setup
+(PxPhysics* physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData,
+ const PxU32 numDrivenWheels, const PxU32 numNonDrivenWheels)
+{
+ //Set up the wheels.
+ PxVehicleWheels::setup(physics,vehActor,wheelsData,numDrivenWheels,numNonDrivenWheels);
+}
+
+void PxVehicleDrive::setToRestState()
+{
+ //Set core to rest state.
+ PxVehicleWheels::setToRestState();
+
+ //Set dynamics data to rest state.
+ mDriveDynData.setToRestState();
+}
+
+} //namespace physx
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDrive4W.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDrive4W.cpp
new file mode 100644
index 00000000..87e9cf6b
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDrive4W.cpp
@@ -0,0 +1,152 @@
+// 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 "PxVehicleDrive4W.h"
+#include "PxVehicleDrive.h"
+#include "PxVehicleSDK.h"
+#include "PxVehicleSuspWheelTire4.h"
+#include "PxVehicleSuspLimitConstraintShader.h"
+#include "PxVehicleDefaults.h"
+#include "PxRigidDynamic.h"
+#include "PxShape.h"
+#include "PsFoundation.h"
+#include "PsUtilities.h"
+#include "CmPhysXCommon.h"
+#include "PxScene.h"
+#include "CmUtils.h"
+
+namespace physx
+{
+
+extern PxF32 gToleranceScaleLength;
+
+bool PxVehicleDriveSimData4W::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(PxVehicleDriveSimData::isValid(), "Invalid PxVehicleDriveSimData4W", false);
+ PX_CHECK_AND_RETURN_VAL(mDiff.isValid(), "Invalid PxVehicleCoreSimulationData.mDiff", false);
+ PX_CHECK_AND_RETURN_VAL(mAckermannGeometry.isValid(), "Invalid PxVehicleCoreSimulationData.mAckermannGeometry", false);
+ return true;
+}
+
+void PxVehicleDriveSimData4W::setDiffData(const PxVehicleDifferential4WData& diff)
+{
+ PX_CHECK_AND_RETURN(diff.mType!=PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD || (diff.mFrontRearSplit>=0 && diff.mFrontRearSplit<=1.0f), "Diff torque split between front and rear must be in range (0,1)");
+ PX_CHECK_AND_RETURN(diff.mType!=PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD || (diff.mCentreBias>=1), "Diff centre bias must be greater than or equal to 1");
+ PX_CHECK_AND_RETURN((diff.mType!=PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD && diff.mType!=PxVehicleDifferential4WData::eDIFF_TYPE_LS_FRONTWD) || (diff.mFrontBias>=1), "Diff front bias must be greater than or equal to 1");
+ PX_CHECK_AND_RETURN((diff.mType!=PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD && diff.mType!=PxVehicleDifferential4WData::eDIFF_TYPE_LS_REARWD) || (diff.mRearBias>=1), "Diff rear bias must be greater than or equal to 1");
+ PX_CHECK_AND_RETURN(diff.mType<PxVehicleDifferential4WData::eMAX_NB_DIFF_TYPES, "Illegal differential type");
+
+ mDiff=diff;
+}
+
+void PxVehicleDriveSimData4W::setAckermannGeometryData(const PxVehicleAckermannGeometryData& ackermannData)
+{
+ PX_CHECK_AND_RETURN(ackermannData.mFrontWidth > 0, "Illegal ackermannData.mFrontWidth - must be greater than zero");
+ PX_CHECK_AND_RETURN(ackermannData.mRearWidth > 0, "Illegal ackermannData.mRearWidth - must be greater than zero");
+ PX_CHECK_AND_RETURN(ackermannData.mAxleSeparation > 0, "Illegal ackermannData.mAxleSeparation - must be greater than zero");
+
+ mAckermannGeometry = ackermannData;
+}
+
+///////////////////////////////////
+
+bool PxVehicleDrive4W::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(PxVehicleDrive::isValid(), "invalid PxVehicleDrive", false);
+ PX_CHECK_AND_RETURN_VAL(mDriveSimData.isValid(), "Invalid PxVehicleNW.mCoreSimData", false);
+ return true;
+}
+
+PxVehicleDrive4W* PxVehicleDrive4W::allocate(const PxU32 numWheels)
+{
+ PX_CHECK_AND_RETURN_NULL(numWheels>=4, "PxVehicleDrive4W::allocate - needs to have at least 4 wheels");
+ PX_CHECK_AND_RETURN_NULL(gToleranceScaleLength > 0, "PxVehicleDrive4W::allocate - need to call PxInitVehicleSDK");
+
+ //Compute the bytes needed.
+ const PxU32 byteSize = sizeof(PxVehicleDrive4W) + PxVehicleDrive::computeByteSize(numWheels);
+
+ //Allocate the memory.
+ PxVehicleDrive4W* veh = static_cast<PxVehicleDrive4W*>(PX_ALLOC(byteSize, "PxVehicleDrive4W"));
+ Cm::markSerializedMem(veh, byteSize);
+ new(veh) PxVehicleDrive4W();
+
+ //Patch up the pointers.
+ PxU8* ptr = reinterpret_cast<PxU8*>(veh) + sizeof(PxVehicleDrive4W);
+ ptr=PxVehicleDrive::patchupPointers(numWheels, veh, ptr);
+
+ //Initialise wheels.
+ veh->init(numWheels);
+
+ //Set the vehicle type.
+ veh->mType = PxVehicleTypes::eDRIVE4W;
+
+ return veh;
+}
+
+void PxVehicleDrive4W::free()
+{
+ PxVehicleDrive::free();
+}
+
+void PxVehicleDrive4W::setup
+(PxPhysics* physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData, const PxVehicleDriveSimData4W& driveData,
+ const PxU32 numNonDrivenWheels)
+{
+ PX_CHECK_AND_RETURN(driveData.isValid(), "PxVehicleDrive4W::setup - invalid driveData");
+ PX_CHECK_AND_RETURN(wheelsData.getNbWheels() >= 4, "PxVehicleDrive4W::setup - needs to have at least 4 wheels");
+
+ //Set up the wheels.
+ PxVehicleDrive::setup(physics,vehActor,wheelsData,4,numNonDrivenWheels);
+
+ //Start setting up the drive.
+ PX_CHECK_MSG(driveData.isValid(), "PxVehicle4WDrive - invalid driveData");
+
+ //Copy the simulation data.
+ mDriveSimData = driveData;
+}
+
+PxVehicleDrive4W* PxVehicleDrive4W::create
+(PxPhysics* physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData, const PxVehicleDriveSimData4W& driveData,
+ const PxU32 numNonDrivenWheels)
+{
+ PxVehicleDrive4W* veh4W=PxVehicleDrive4W::allocate(4+numNonDrivenWheels);
+ veh4W->setup(physics,vehActor,wheelsData,driveData,numNonDrivenWheels);
+ return veh4W;
+}
+
+
+void PxVehicleDrive4W::setToRestState()
+{
+ //Set core to rest state.
+ PxVehicleDrive::setToRestState();
+}
+} //namespace physx
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDriveNW.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDriveNW.cpp
new file mode 100644
index 00000000..fadda3ad
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDriveNW.cpp
@@ -0,0 +1,149 @@
+// 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 "PxVehicleDriveNW.h"
+#include "PxVehicleDrive.h"
+#include "PxVehicleSDK.h"
+#include "PxVehicleSuspWheelTire4.h"
+#include "PxVehicleSuspLimitConstraintShader.h"
+#include "PxVehicleDefaults.h"
+#include "PxRigidDynamic.h"
+#include "PxShape.h"
+#include "PsFoundation.h"
+#include "PsUtilities.h"
+#include "CmPhysXCommon.h"
+#include "PxScene.h"
+#include "CmUtils.h"
+
+
+namespace physx
+{
+
+extern PxF32 gToleranceScaleLength;
+
+void PxVehicleDriveSimDataNW::setDiffData(const PxVehicleDifferentialNWData& diff)
+{
+ PX_CHECK_AND_RETURN(diff.isValid(), "Invalid PxVehicleCoreSimulationData.mDiff");
+ mDiff=diff;
+}
+
+bool PxVehicleDriveSimDataNW::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mDiff.isValid(), "Invalid PxVehicleDifferentialNWData", false);
+ PX_CHECK_AND_RETURN_VAL(PxVehicleDriveSimData::isValid(), "Invalid PxVehicleDriveSimDataNW", false);
+ return true;
+}
+
+///////////////////////////////////
+
+bool PxVehicleDriveNW::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(PxVehicleDrive::isValid(), "invalid PxVehicleDrive", false);
+ PX_CHECK_AND_RETURN_VAL(mDriveSimData.isValid(), "Invalid PxVehicleNW.mCoreSimData", false);
+ return true;
+}
+
+PxVehicleDriveNW* PxVehicleDriveNW::allocate(const PxU32 numWheels)
+{
+ PX_CHECK_AND_RETURN_NULL(numWheels>0, "Cars with zero wheels are illegal");
+ PX_CHECK_AND_RETURN_NULL(gToleranceScaleLength > 0, "PxVehicleDriveNW::allocate - need to call PxInitVehicleSDK");
+
+ //Compute the bytes needed.
+ const PxU32 byteSize = sizeof(PxVehicleDriveNW) + PxVehicleDrive::computeByteSize(numWheels);
+
+ //Allocate the memory.
+ PxVehicleDriveNW* veh = static_cast<PxVehicleDriveNW*>(PX_ALLOC(byteSize, "PxVehicleDriveNW"));
+ Cm::markSerializedMem(veh, byteSize);
+ new(veh) PxVehicleDriveNW();
+
+ //Patch up the pointers.
+ PxU8* ptr = reinterpret_cast<PxU8*>(veh) + sizeof(PxVehicleDriveNW);
+ ptr=PxVehicleDrive::patchupPointers(numWheels, veh, ptr);
+
+ //Initialise
+ veh->init(numWheels);
+
+ //Set the vehicle type.
+ veh->mType = PxVehicleTypes::eDRIVENW;
+
+ return veh;
+}
+
+void PxVehicleDriveNW::free()
+{
+ PxVehicleDrive::free();
+}
+
+void PxVehicleDriveNW::setup
+(PxPhysics* physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData, const PxVehicleDriveSimDataNW& driveData,
+ const PxU32 numWheels)
+{
+ PX_CHECK_AND_RETURN(driveData.isValid(), "PxVehicleDriveNW::setup - invalid driveData");
+
+ //Set up the wheels.
+ PxVehicleDrive::setup(physics,vehActor,wheelsData,numWheels,0);
+
+ //Start setting up the drive.
+ PX_CHECK_MSG(driveData.isValid(), "PxVehicleNWDrive - invalid driveData");
+
+ //Copy the simulation data.
+ mDriveSimData = driveData;
+}
+
+PxVehicleDriveNW* PxVehicleDriveNW::create
+(PxPhysics* physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData, const PxVehicleDriveSimDataNW& driveData,
+ const PxU32 numWheels)
+{
+ PxVehicleDriveNW* vehNW=PxVehicleDriveNW::allocate(numWheels);
+ vehNW->setup(physics,vehActor,wheelsData,driveData,numWheels);
+ return vehNW;
+}
+
+
+void PxVehicleDriveNW::setToRestState()
+{
+ //Set core to rest state.
+ PxVehicleDrive::setToRestState();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+} //namespace physx
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDriveTank.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDriveTank.cpp
new file mode 100644
index 00000000..4aa0a66b
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleDriveTank.cpp
@@ -0,0 +1,120 @@
+// 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 "PxVehicleDriveTank.h"
+#include "PxVehicleWheels.h"
+#include "PxVehicleSDK.h"
+#include "PxVehicleDefaults.h"
+#include "PxRigidDynamic.h"
+#include "CmPhysXCommon.h"
+#include "CmUtils.h"
+#include "PsFoundation.h"
+
+namespace physx
+{
+
+extern PxF32 gToleranceScaleLength;
+
+bool PxVehicleDriveTank::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(PxVehicleDrive::isValid(), "invalid PxVehicleDrive", false);
+ PX_CHECK_AND_RETURN_VAL(mDriveSimData.isValid(), "Invalid PxVehicleDriveTank.mCoreSimData", false);
+ return true;
+}
+
+PxVehicleDriveTank* PxVehicleDriveTank::allocate(const PxU32 numWheels)
+{
+ PX_CHECK_AND_RETURN_NULL(numWheels>0, "Cars with zero wheels are illegal");
+ PX_CHECK_AND_RETURN_NULL(0 == (numWheels % 2), "PxVehicleDriveTank::allocate - needs to have even number of wheels");
+ PX_CHECK_AND_RETURN_NULL(gToleranceScaleLength > 0, "PxVehicleDriveTank::allocate - need to call PxInitVehicleSDK");
+
+ //Compute the bytes needed.
+ const PxU32 byteSize = sizeof(PxVehicleDriveTank) + PxVehicleDrive::computeByteSize(numWheels);
+
+ //Allocate the memory.
+ PxVehicleDriveTank* veh = static_cast<PxVehicleDriveTank*>(PX_ALLOC(byteSize, "PxVehicleDriveTank"));
+ Cm::markSerializedMem(veh, byteSize);
+ new(veh) PxVehicleDriveTank();
+
+ //Patch up the pointers.
+ PxU8* ptr = reinterpret_cast<PxU8*>(veh) + sizeof(PxVehicleDriveTank);
+ PxVehicleDrive::patchupPointers(numWheels, veh, ptr);
+
+ //Initialise.
+ veh->init(numWheels);
+
+ //Set the vehicle type.
+ veh->mType = PxVehicleTypes::eDRIVETANK;
+
+ //Set the default drive model.
+ veh->mDriveModel = PxVehicleDriveTankControlModel::eSTANDARD;
+
+ return veh;
+}
+
+void PxVehicleDriveTank::free()
+{
+ PxVehicleDrive::free();
+}
+
+void PxVehicleDriveTank::setup
+(PxPhysics* physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData, const PxVehicleDriveSimData& driveData,
+ const PxU32 numDrivenWheels)
+{
+ PX_CHECK_AND_RETURN(driveData.isValid(), "PxVehicleDriveTank::setup - illegal drive data");
+
+ //Set up the wheels.
+ PxVehicleDrive::setup(physics,vehActor,wheelsData,numDrivenWheels,0);
+
+ //Start setting up the drive.
+ PX_CHECK_MSG(driveData.isValid(), "PxVehicle4WDrive - invalid driveData");
+
+ //Copy the simulation data.
+ mDriveSimData = driveData;
+}
+
+PxVehicleDriveTank* PxVehicleDriveTank::create
+(PxPhysics* physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData, const PxVehicleDriveSimData& driveData,
+ const PxU32 numDrivenWheels)
+{
+ PxVehicleDriveTank* tank=PxVehicleDriveTank::allocate(numDrivenWheels);
+ tank->setup(physics,vehActor,wheelsData,driveData,numDrivenWheels);
+ return tank;
+}
+
+
+void PxVehicleDriveTank::setToRestState()
+{
+ //Set core to rest state.
+ PxVehicleDrive::setToRestState();
+}
+} //namespace physx
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleLinearMath.h b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleLinearMath.h
new file mode 100644
index 00000000..87a1ad69
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleLinearMath.h
@@ -0,0 +1,433 @@
+// 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 PX_VEHICLE_LINEAR_MATH_H
+#define PX_VEHICLE_LINEAR_MATH_H
+/** \addtogroup vehicle
+ @{
+*/
+
+#include "PxVehicleSDK.h"
+
+#if !PX_DOXYGEN
+namespace physx
+{
+#endif
+
+#define MAX_VECTORN_SIZE (PX_MAX_NB_WHEELS+3)
+
+class VectorN
+{
+public:
+
+ VectorN(const PxU32 size)
+ : mSize(size)
+ {
+ PX_ASSERT(mSize <= MAX_VECTORN_SIZE);
+ }
+ ~VectorN()
+ {
+ }
+
+ VectorN(const VectorN& src)
+ {
+ for(PxU32 i = 0; i < src.mSize; i++)
+ {
+ mValues[i] = src.mValues[i];
+ }
+ mSize = src.mSize;
+ }
+
+ PX_FORCE_INLINE VectorN& operator=(const VectorN& src)
+ {
+ for(PxU32 i = 0; i < src.mSize; i++)
+ {
+ mValues[i] = src.mValues[i];
+ }
+ mSize = src.mSize;
+ return *this;
+ }
+
+ PX_FORCE_INLINE PxF32& operator[] (const PxU32 i)
+ {
+ PX_ASSERT(i < mSize);
+ return (mValues[i]);
+ }
+
+ PX_FORCE_INLINE const PxF32& operator[] (const PxU32 i) const
+ {
+ PX_ASSERT(i < mSize);
+ return (mValues[i]);
+ }
+
+ PX_FORCE_INLINE PxU32 getSize() const {return mSize;}
+
+private:
+
+ PxF32 mValues[MAX_VECTORN_SIZE];
+ PxU32 mSize;
+};
+
+class MatrixNN
+{
+public:
+
+ MatrixNN()
+ : mSize(0)
+ {
+ }
+ MatrixNN(const PxU32 size)
+ : mSize(size)
+ {
+ PX_ASSERT(mSize <= MAX_VECTORN_SIZE);
+ }
+ MatrixNN(const MatrixNN& src)
+ {
+ for(PxU32 i = 0; i < src.mSize; i++)
+ {
+ for(PxU32 j = 0; j < src.mSize; j++)
+ {
+ mValues[i][j] = src.mValues[i][j];
+ }
+ }
+ mSize=src.mSize;
+ }
+ ~MatrixNN()
+ {
+ }
+
+ PX_FORCE_INLINE MatrixNN& operator=(const MatrixNN& src)
+ {
+ for(PxU32 i = 0;i < src.mSize; i++)
+ {
+ for(PxU32 j = 0;j < src.mSize; j++)
+ {
+ mValues[i][j] = src.mValues[i][j];
+ }
+ }
+ mSize = src.mSize;
+ return *this;
+ }
+
+ PX_FORCE_INLINE PxF32 get(const PxU32 i, const PxU32 j) const
+ {
+ PX_ASSERT(i < mSize);
+ PX_ASSERT(j < mSize);
+ return mValues[i][j];
+ }
+ PX_FORCE_INLINE void set(const PxU32 i, const PxU32 j, const PxF32 val)
+ {
+ PX_ASSERT(i < mSize);
+ PX_ASSERT(j < mSize);
+ mValues[i][j] = val;
+ }
+
+ PX_FORCE_INLINE PxU32 getSize() const {return mSize;}
+
+ PX_FORCE_INLINE void setSize(const PxU32 size)
+ {
+ PX_ASSERT(size <= MAX_VECTORN_SIZE);
+ mSize = size;
+ }
+
+public:
+
+ PxF32 mValues[MAX_VECTORN_SIZE][MAX_VECTORN_SIZE];
+ PxU32 mSize;
+};
+
+
+/*
+ LUPQ decomposition
+
+ Based upon "Outer Product LU with Complete Pivoting," from Matrix Computations (4th Edition), Golub and Van Loan
+
+ Solve A*x = b using:
+
+ MatrixNNLUSolver solver;
+ solver.decomposeLU(A);
+ solver.solve(b, x);
+*/
+class MatrixNNLUSolver
+{
+private:
+
+ MatrixNN mLU;
+ PxU32 mP[MAX_VECTORN_SIZE-1]; // Row permutation
+ PxU32 mQ[MAX_VECTORN_SIZE-1]; // Column permutation
+ PxF32 mdetM;
+
+public:
+
+ MatrixNNLUSolver(){}
+ ~MatrixNNLUSolver(){}
+
+ PxF32 getDet() const {return mdetM;}
+
+ void decomposeLU(const MatrixNN& A)
+ {
+ const PxU32 D = A.mSize;
+
+ mLU = A;
+
+ mdetM = 1.0f;
+
+ for (PxU32 k = 0; k < D-1; ++k)
+ {
+ PxU32 pivot_row = k;
+ PxU32 pivot_col = k;
+ float abs_pivot_elem = 0.0f;
+ for (PxU32 c = k; c < D; ++c)
+ {
+ for (PxU32 r = k; r < D; ++r)
+ {
+ const PxF32 abs_elem = PxAbs(mLU.get(r,c));
+ if (abs_elem > abs_pivot_elem)
+ {
+ abs_pivot_elem = abs_elem;
+ pivot_row = r;
+ pivot_col = c;
+ }
+ }
+ }
+
+ mP[k] = pivot_row;
+ if (pivot_row != k)
+ {
+ mdetM = -mdetM;
+ for (PxU32 c = 0; c < D; ++c)
+ {
+ //swap(m_LU(k,c), m_LU(pivot_row,c));
+ const PxF32 pivotrowc = mLU.get(pivot_row, c);
+ mLU.set(pivot_row, c, mLU.get(k, c));
+ mLU.set(k, c, pivotrowc);
+ }
+ }
+
+ mQ[k] = pivot_col;
+ if (pivot_col != k)
+ {
+ mdetM = -mdetM;
+ for (PxU32 r = 0; r < D; ++r)
+ {
+ //swap(m_LU(r,k), m_LU(r,pivot_col));
+ const PxF32 rpivotcol = mLU.get(r, pivot_col);
+ mLU.set(r,pivot_col, mLU.get(r,k));
+ mLU.set(r, k, rpivotcol);
+ }
+ }
+
+ mdetM *= mLU.get(k,k);
+
+ if (mLU.get(k,k) != 0.0f)
+ {
+ for (PxU32 r = k+1; r < D; ++r)
+ {
+ mLU.set(r, k, mLU.get(r,k) / mLU.get(k,k));
+ for (PxU32 c = k+1; c < D; ++c)
+ {
+ //m_LU(r,c) -= m_LU(r,k)*m_LU(k,c);
+ const PxF32 rc = mLU.get(r, c);
+ const PxF32 rk = mLU.get(r, k);
+ const PxF32 kc = mLU.get(k, c);
+ mLU.set(r, c, rc - rk*kc);
+ }
+ }
+ }
+ }
+
+ mdetM *= mLU.get(D-1,D-1);
+ }
+
+ //Given a matrix A and a vector b find x that satisfies Ax = b, where the matrix A is the matrix that was passed to decomposeLU.
+ //Returns true if the lu decomposition indicates that the matrix has an inverse and x was successfully computed.
+ //Returns false if the lu decomposition resulted in zero determinant ie the matrix has no inverse and no solution exists for x.
+ //Returns false if the size of either b or x doesn't match the size of the matrix passed to decomposeLU.
+ //If false is returned then each relevant element of x is set to zero.
+ bool solve(const VectorN& b, VectorN& x) const
+ {
+ const PxU32 D = x.getSize();
+
+ if((b.getSize() != x.getSize()) || (b.getSize() != mLU.getSize()) || (0.0f == mdetM))
+ {
+ for(PxU32 i = 0; i < D; i++)
+ {
+ x[i] = 0.0f;
+ }
+ return false;
+ }
+
+ x = b;
+
+ // Perform row permutation to get Pb
+ for(PxU32 i = 0; i < D-1; ++i)
+ {
+ //swap(x(i), x(m_P[i]));
+ const PxF32 xp = x[mP[i]];
+ x[mP[i]] = x[i];
+ x[i] = xp;
+ }
+
+ // Forward substitute to get (L^-1)Pb
+ for (PxU32 r = 1; r < D; ++r)
+ {
+ for (PxU32 i = 0; i < r; ++i)
+ {
+ x[r] -= mLU.get(r,i)*x[i];
+ }
+ }
+
+ // Back substitute to get (U^-1)(L^-1)Pb
+ for (PxU32 r = D; r-- > 0;)
+ {
+ for (PxU32 i = r+1; i < D; ++i)
+ {
+ x[r] -= mLU.get(r,i)*x[i];
+ }
+ x[r] /= mLU.get(r,r);
+ }
+
+ // Perform column permutation to get the solution (Q^T)(U^-1)(L^-1)Pb
+ for (PxU32 i = D-1; i-- > 0;)
+ {
+ //swap(x(i), x(m_Q[i]));
+ const PxF32 xq = x[mQ[i]];
+ x[mQ[i]] = x[i];
+ x[i] = xq;
+ }
+
+ return true;
+ }
+
+};
+
+
+class MatrixNGaussSeidelSolver
+{
+public:
+
+ void solve(const PxU32 maxIterations, const PxF32 tolerance, const MatrixNN& A, const VectorN& b, VectorN& result) const
+ {
+ const PxU32 N = A.getSize();
+
+ VectorN DInv(N);
+ PxF32 bLength2 = 0.0f;
+ for(PxU32 i = 0; i < N; i++)
+ {
+ DInv[i] = 1.0f/A.get(i,i);
+ bLength2 += (b[i] * b[i]);
+ }
+
+ PxU32 iteration = 0;
+ PxF32 error = PX_MAX_F32;
+ while(iteration < maxIterations && tolerance < error)
+ {
+ for(PxU32 i = 0; i < N; i++)
+ {
+ PxF32 l = 0.0f;
+ for(PxU32 j = 0; j < i; j++)
+ {
+ l += A.get(i,j) * result[j];
+ }
+
+ PxF32 u = 0.0f;
+ for(PxU32 j = i + 1; j < N; j++)
+ {
+ u += A.get(i,j) * result[j];
+ }
+
+ result[i] = DInv[i] * (b[i] - l - u);
+ }
+
+ //Compute the error.
+ PxF32 rLength2 = 0;
+ for(PxU32 i = 0; i < N; i++)
+ {
+ PxF32 e = -b[i];
+ for(PxU32 j = 0; j < N; j++)
+ {
+ e += A.get(i,j) * result[j];
+ }
+ rLength2 += e * e;
+ }
+ error = (rLength2 / (bLength2 + 1e-10f));
+
+ iteration++;
+ }
+ }
+};
+
+class Matrix33Solver
+{
+public:
+
+ bool solve(const MatrixNN& _A_, const VectorN& _b_, VectorN& result) const
+ {
+ const PxF32 a = _A_.get(0,0);
+ const PxF32 b = _A_.get(0,1);
+ const PxF32 c = _A_.get(0,2);
+
+ const PxF32 d = _A_.get(1,0);
+ const PxF32 e = _A_.get(1,1);
+ const PxF32 f = _A_.get(1,2);
+
+ const PxF32 g = _A_.get(2,0);
+ const PxF32 h = _A_.get(2,1);
+ const PxF32 k = _A_.get(2,2);
+
+ const PxF32 detA = a*(e*k - f*h) - b*(k*d - f*g) + c*(d*h - e*g);
+ if(0.0f == detA)
+ {
+ return false;
+ }
+ const PxF32 detAInv = 1.0f/detA;
+
+ const PxF32 A = (e*k - f*h);
+ const PxF32 D = -(b*k - c*h);
+ const PxF32 G = (b*f - c*e);
+ const PxF32 B = -(d*k - f*g);
+ const PxF32 E = (a*k - c*g);
+ const PxF32 H = -(a*f - c*d);
+ const PxF32 C = (d*h - e*g);
+ const PxF32 F = -(a*h - b*g);
+ const PxF32 K = (a*e - b*d);
+
+ result[0] = detAInv*(A*_b_[0] + D*_b_[1] + G*_b_[2]);
+ result[1] = detAInv*(B*_b_[0] + E*_b_[1] + H*_b_[2]);
+ result[2] = detAInv*(C*_b_[0] + F*_b_[1] + K*_b_[2]);
+
+ return true;
+ }
+};
+
+#if !PX_DOXYGEN
+} // namespace physx
+#endif
+
+#endif //PX_VEHICLE_LINEAR_MATH_H
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleMetaData.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleMetaData.cpp
new file mode 100644
index 00000000..518c60af
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleMetaData.cpp
@@ -0,0 +1,540 @@
+// 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 "PxVehicleComponents.h"
+#include "PxVehicleDrive.h"
+#include "PxVehicleNoDrive.h"
+#include "PxVehicleDrive4W.h"
+#include "PxVehicleDriveNW.h"
+#include "PxVehicleDriveTank.h"
+#include "PxVehicleSuspWheelTire4.h"
+#include "PxVehicleSuspLimitConstraintShader.h"
+
+#include "PxMetaData.h"
+
+using namespace physx;
+
+namespace
+{
+ typedef PxFixedSizeLookupTable<PxVehicleEngineData::eMAX_NB_ENGINE_TORQUE_CURVE_ENTRIES> PxVehicleEngineTable;
+ class ShadowLookupTable : public PxVehicleEngineTable
+ {
+ public:
+ static void getBinaryMetaData(PxOutputStream& stream_)
+ {
+ PX_DEF_BIN_METADATA_CLASS(stream_, ShadowLookupTable)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream_, PxVehicleEngineTable, PxReal, mDataPairs, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream_, PxVehicleEngineTable, PxU32, mNbDataPairs, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream_, PxVehicleEngineTable, PxU32, mPad, PxMetaDataFlag::ePADDING)
+ }
+ };
+}
+
+static void getBinaryMetaData_PxFixedSizeLookupTable(PxOutputStream& stream)
+{
+ ShadowLookupTable::getBinaryMetaData(stream);
+ PX_DEF_BIN_METADATA_TYPEDEF(stream, PxFixedSizeLookupTable<PxVehicleEngineData::eMAX_NB_ENGINE_TORQUE_CURVE_ENTRIES>, ShadowLookupTable)
+}
+
+void PxVehicleDriveSimData::getBinaryMetaData(PxOutputStream& stream)
+{
+ getBinaryMetaData_PxFixedSizeLookupTable(stream);
+ PX_DEF_BIN_METADATA_TYPEDEF(stream, PxVehicleClutchAccuracyMode::Enum, PxU32)
+
+ //PxVehicleEngineData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleEngineData)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleEngineData, ShadowLookupTable, mTorqueCurve, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleEngineData, PxReal, mMOI, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleEngineData, PxReal, mPeakTorque, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleEngineData, PxReal, mMaxOmega, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleEngineData, PxReal, mDampingRateFullThrottle, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleEngineData, PxReal, mDampingRateZeroThrottleClutchEngaged, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleEngineData, PxReal, mDampingRateZeroThrottleClutchDisengaged, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleEngineData, PxReal, mRecipMOI, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleEngineData, PxReal, mRecipMaxOmega, 0)
+
+
+ //PxVehicleGearsData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleGearsData)
+
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleGearsData, PxReal, mRatios, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleGearsData, PxReal, mFinalRatio, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleGearsData, PxU32, mNbRatios, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleGearsData, PxReal, mSwitchTime, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleGearsData, PxReal, mPad, PxMetaDataFlag::ePADDING)
+
+ //PxVehicleClutchData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleClutchData)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleClutchData, PxReal, mStrength, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleClutchData, PxVehicleClutchAccuracyMode::Enum, mAccuracyMode, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleClutchData, PxU32, mEstimateIterations, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleClutchData, PxU8, mPad, PxMetaDataFlag::ePADDING)
+
+ //PxVehicleAutoBoxData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleAutoBoxData)
+
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleAutoBoxData, PxReal, mUpRatios, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleAutoBoxData, PxReal, mDownRatios, 0)
+
+ //PxVehicleDriveSimData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleDriveSimData)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveSimData, PxVehicleEngineData, mEngine, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveSimData, PxVehicleGearsData, mGears, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveSimData, PxVehicleClutchData, mClutch, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveSimData, PxVehicleAutoBoxData, mAutoBox, 0)
+}
+
+void PxVehicleDrive::getBinaryMetaData(PxOutputStream& stream)
+{
+ //PxVehicleDriveDynData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleDriveDynData)
+
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleDriveDynData, PxReal, mControlAnalogVals, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveDynData, bool, mUseAutoGears, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveDynData, bool, mGearUpPressed, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveDynData, bool, mGearDownPressed, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveDynData, PxU32, mCurrentGear, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveDynData, PxU32, mTargetGear, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveDynData, PxReal, mEnginespeed, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveDynData, PxReal, mGearSwitchTime, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveDynData, PxReal, mAutoBoxSwitchTime, 0)
+
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleDriveDynData, PxU32, mPad, PxMetaDataFlag::ePADDING)
+
+ //PxVehicleDrive
+ PX_DEF_BIN_METADATA_VCLASS(stream, PxVehicleDrive)
+ PX_DEF_BIN_METADATA_BASE_CLASS(stream, PxVehicleDrive, PxVehicleWheels)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDrive, PxVehicleDriveDynData, mDriveDynData, 0)
+}
+
+void PxVehicleDriveSimData4W::getBinaryMetaData(PxOutputStream& stream)
+{
+ //PxVehicleDifferential4WData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleDifferential4WData)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDifferential4WData, PxReal, mFrontRearSplit, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDifferential4WData, PxReal, mFrontLeftRightSplit, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDifferential4WData, PxReal, mRearLeftRightSplit, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDifferential4WData, PxReal, mCentreBias, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDifferential4WData, PxReal, mFrontBias, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDifferential4WData, PxReal, mRearBias, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDifferential4WData, PxU32, mType, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleDifferential4WData, PxReal, mPad, PxMetaDataFlag::ePADDING)
+
+ //PxVehicleAckermannGeometryData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleAckermannGeometryData)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleAckermannGeometryData, PxReal, mAccuracy, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleAckermannGeometryData, PxReal, mFrontWidth, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleAckermannGeometryData, PxReal, mRearWidth, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleAckermannGeometryData, PxReal, mAxleSeparation, 0)
+
+ //PxVehicleDriveSimData4W
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleDriveSimData4W)
+ PX_DEF_BIN_METADATA_BASE_CLASS(stream, PxVehicleDriveSimData4W, PxVehicleDriveSimData)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveSimData4W, PxVehicleDifferential4WData, mDiff, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveSimData4W, PxVehicleAckermannGeometryData, mAckermannGeometry, 0)
+}
+
+void PxVehicleDriveSimDataNW::getBinaryMetaData(PxOutputStream& stream)
+{
+ //PxVehicleDifferentialWData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleDifferentialNWData)
+
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleDifferentialNWData, PxU32, mBitmapBuffer, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDifferentialNWData, PxU32, mNbDrivenWheels, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDifferentialNWData, PxReal, mInvNbDrivenWheels, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDifferentialNWData, PxU32, mPad, 0)
+
+ //PxVehicleDriveSimDataNW
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleDriveSimDataNW)
+ PX_DEF_BIN_METADATA_BASE_CLASS(stream, PxVehicleDriveSimDataNW, PxVehicleDriveSimData)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveSimDataNW, PxVehicleDifferentialNWData, mDiff, 0)
+}
+
+void PxVehicleNoDrive::getBinaryMetaData(PxOutputStream& stream)
+{
+ PxVehicleDrive::getBinaryMetaData(stream);
+ PxVehicleWheels::getBinaryMetaData(stream);
+ PxVehicleDriveSimData::getBinaryMetaData(stream);
+
+ PX_DEF_BIN_METADATA_VCLASS(stream, PxVehicleNoDrive)
+ PX_DEF_BIN_METADATA_BASE_CLASS(stream, PxVehicleNoDrive, PxVehicleWheels)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleNoDrive, PxReal, mSteerAngles, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleNoDrive, PxReal, mDriveTorques, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleNoDrive, PxReal, mBrakeTorques, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleNoDrive, PxU32, mPad, PxMetaDataFlag::ePADDING)
+
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mSteerAngles, mWheelsSimData.mNbWheels4, 0, PX_SERIAL_ALIGN)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mSteerAngles, mWheelsSimData.mNbWheels4, 0, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mSteerAngles, mWheelsSimData.mNbWheels4, 0, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mSteerAngles, mWheelsSimData.mNbWheels4, 0, 0)
+
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mDriveTorques, mWheelsSimData.mNbWheels4, 0, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mDriveTorques, mWheelsSimData.mNbWheels4, 0, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mDriveTorques, mWheelsSimData.mNbWheels4, 0, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mDriveTorques, mWheelsSimData.mNbWheels4, 0, 0)
+
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mBrakeTorques, mWheelsSimData.mNbWheels4, 0, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mBrakeTorques, mWheelsSimData.mNbWheels4, 0, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mBrakeTorques, mWheelsSimData.mNbWheels4, 0, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleNoDrive, PxReal, mBrakeTorques, mWheelsSimData.mNbWheels4, 0, 0)
+}
+
+void PxVehicleNoDrive::exportExtraData(PxSerializationContext& stream)
+{
+ PxVehicleWheels::exportExtraData(stream);
+
+ PxU32 size = sizeof(PxReal)*4*mWheelsSimData.mNbWheels4;
+ stream.alignData();
+ stream.writeData(mSteerAngles, size);
+ stream.writeData(mDriveTorques, size);
+ stream.writeData(mBrakeTorques, size);
+}
+
+void PxVehicleNoDrive::importExtraData(PxDeserializationContext& context)
+{
+ PxVehicleWheels::importExtraData(context);
+
+ context.alignExtraData();
+ mSteerAngles = context.readExtraData<PxReal>(4*mWheelsSimData.mNbWheels4);
+ mDriveTorques = context.readExtraData<PxReal>(4*mWheelsSimData.mNbWheels4);
+ mBrakeTorques = context.readExtraData<PxReal>(4*mWheelsSimData.mNbWheels4);
+}
+
+PxVehicleNoDrive* PxVehicleNoDrive::createObject(PxU8*& address, PxDeserializationContext& context)
+{
+ PxVehicleNoDrive* obj = new (address) PxVehicleNoDrive(PxBaseFlag::eIS_RELEASABLE);
+ address += sizeof(PxVehicleNoDrive);
+ obj->importExtraData(context);
+ obj->resolveReferences(context);
+ return obj;
+}
+
+void PxVehicleDrive4W::getBinaryMetaData(PxOutputStream& stream)
+{
+ PxVehicleDrive::getBinaryMetaData(stream);
+ PxVehicleWheels::getBinaryMetaData(stream);
+ PxVehicleDriveSimData::getBinaryMetaData(stream);
+ PxVehicleDriveSimData4W::getBinaryMetaData(stream);
+
+ PX_DEF_BIN_METADATA_VCLASS(stream, PxVehicleDrive4W)
+ PX_DEF_BIN_METADATA_BASE_CLASS(stream, PxVehicleDrive4W, PxVehicleDrive)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDrive4W, PxVehicleDriveSimData4W, mDriveSimData, 0)
+}
+
+PxVehicleDrive4W* PxVehicleDrive4W::createObject(PxU8*& address, PxDeserializationContext& context)
+{
+ PxVehicleDrive4W* obj = new (address) PxVehicleDrive4W(PxBaseFlag::eIS_RELEASABLE);
+ address += sizeof(PxVehicleDrive4W);
+ obj->importExtraData(context);
+ obj->resolveReferences(context);
+ return obj;
+}
+
+void PxVehicleDriveNW::getBinaryMetaData(PxOutputStream& stream)
+{
+ PxVehicleDriveSimDataNW::getBinaryMetaData(stream);
+
+ PX_DEF_BIN_METADATA_VCLASS(stream, PxVehicleDriveNW)
+ PX_DEF_BIN_METADATA_BASE_CLASS(stream, PxVehicleDriveNW, PxVehicleDrive)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveNW, PxVehicleDriveSimDataNW, mDriveSimData, 0)
+}
+
+PxVehicleDriveNW* PxVehicleDriveNW::createObject(PxU8*& address, PxDeserializationContext& context)
+{
+ PxVehicleDriveNW* obj = new (address) PxVehicleDriveNW(PxBaseFlag::eIS_RELEASABLE);
+ address += sizeof(PxVehicleDriveNW);
+ obj->importExtraData(context);
+ obj->resolveReferences(context);
+ return obj;
+}
+
+void PxVehicleDriveTank::getBinaryMetaData(PxOutputStream& stream)
+{
+ PX_DEF_BIN_METADATA_VCLASS(stream, PxVehicleDriveTank)
+ PX_DEF_BIN_METADATA_BASE_CLASS(stream, PxVehicleDriveTank, PxVehicleDrive)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveTank, PxVehicleDriveSimData, mDriveSimData, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleDriveTank, PxU32, mDriveModel, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleDriveTank, PxU32, mPad, PxMetaDataFlag::ePADDING)
+}
+
+PxVehicleDriveTank* PxVehicleDriveTank::createObject(PxU8*& address, PxDeserializationContext& context)
+{
+ PxVehicleDriveTank* obj = new (address) PxVehicleDriveTank(PxBaseFlag::eIS_RELEASABLE);
+ address += sizeof(PxVehicleDriveTank);
+ obj->importExtraData(context);
+ obj->resolveReferences(context);
+ return obj;
+}
+
+void PxVehicleWheelsSimData::getBinaryMetaData(PxOutputStream& stream)
+{
+ PxVehicleWheels4SimData::getBinaryMetaData(stream);
+ //PxVehicleTireLoadFilterData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleTireLoadFilterData)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireLoadFilterData, PxReal, mMinNormalisedLoad, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireLoadFilterData, PxReal, mMinFilteredNormalisedLoad, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireLoadFilterData, PxReal, mMaxNormalisedLoad, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireLoadFilterData, PxReal, mMaxFilteredNormalisedLoad, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireLoadFilterData, PxReal, mDenominator, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleTireLoadFilterData, PxU32, mPad, PxMetaDataFlag::ePADDING)
+
+ //Add anti-roll here to save us having to add an extra function.
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleAntiRollBarData)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleAntiRollBarData, PxU32, mWheel0, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleAntiRollBarData, PxU32, mWheel1, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleAntiRollBarData, PxReal, mStiffness, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleAntiRollBarData, PxU32, mPad, PxMetaDataFlag::ePADDING)
+
+ //PxVehicleWheelsSimData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleWheelsSimData)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxVehicleTireLoadFilterData, mNormalisedLoadFilter, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxVehicleWheels4SimData, mWheels4SimData, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxU32, mNbWheels4, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxU32, mNbActiveWheels, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxVehicleAntiRollBarData, mAntiRollBars, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxU32, mNbAntiRollBars4, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxU32, mNbActiveAntiRollBars, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxU32, mActiveWheelsBitmapBuffer, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxReal, mThresholdLongitudinalSpeed, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxU32, mLowForwardSpeedSubStepCount, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxU32, mHighForwardSpeedSubStepCount, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsSimData, PxU32, mMinLongSlipDenominator, 0)
+
+#if PX_P64_FAMILY
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheelsSimData, PxU32, mPad, PxMetaDataFlag::ePADDING)
+#else
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheelsSimData, PxU32, mPad, PxMetaDataFlag::ePADDING)
+#endif
+
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsSimData, PxVehicleWheels4SimData, mWheels4SimData, mNbWheels4, 0, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsSimData, PxVehicleAntiRollBarData, mAntiRollBars, mNbAntiRollBars4, 0, 0)
+}
+
+void PxVehicleWheelsDynData::getBinaryMetaData(PxOutputStream& stream)
+{
+ PxVehicleWheels4DynData::getBinaryMetaData(stream);
+ PxVehicleConstraintShader::getBinaryMetaData(stream);
+
+ //PxVehicleTireForceCalculator
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleTireForceCalculator)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireForceCalculator, void*, mShaderData, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireForceCalculator, PxU32, mShader, PxMetaDataFlag::ePTR)
+
+#if !PX_P64_FAMILY
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleTireForceCalculator, PxU32, mPad, PxMetaDataFlag::ePADDING)
+#endif
+
+ //PxVehicleWheelsDynData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleWheelsDynData)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsDynData, PxVehicleWheels4DynData, mWheels4DynData, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsDynData, PxVehicleTireForceCalculator, mTireForceCalculators, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsDynData, PxU32, mUserDatas, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsDynData, PxU32, mNbWheels4, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelsDynData, PxU32, mNbActiveWheels, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheelsDynData, PxU32, mPad, PxMetaDataFlag::ePADDING)
+
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsDynData, PxVehicleWheels4DynData, mWheels4DynData, mNbWheels4, 0, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEM(stream, PxVehicleWheelsDynData, PxVehicleTireForceCalculator, mTireForceCalculators, 0)
+
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsDynData, void, mTireForceCalculators, mNbWheels4, PxMetaDataFlag::ePTR, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsDynData, void, mTireForceCalculators, mNbWheels4, PxMetaDataFlag::ePTR, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsDynData, void, mTireForceCalculators, mNbWheels4, PxMetaDataFlag::ePTR, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsDynData, void, mTireForceCalculators, mNbWheels4, PxMetaDataFlag::ePTR, 0)
+
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsDynData, void, mUserDatas, mNbWheels4, PxMetaDataFlag::ePTR, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsDynData, void, mUserDatas, mNbWheels4, PxMetaDataFlag::ePTR, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsDynData, void, mUserDatas, mNbWheels4, PxMetaDataFlag::ePTR, 0)
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsDynData, void, mUserDatas, mNbWheels4, PxMetaDataFlag::ePTR, 0)
+
+ PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, PxVehicleWheelsDynData, PxVehicleConstraintShader, mWheels4DynData, mNbWheels4, 0, 0)
+}
+
+void PxVehicleWheels::exportExtraData(PxSerializationContext& stream)
+{
+ PxU32 size = computeByteSize(mWheelsSimData.mNbActiveWheels);
+ stream.alignData();
+ stream.writeData(mWheelsSimData.mWheels4SimData, size);
+}
+
+void PxVehicleWheels::importExtraData(PxDeserializationContext& context)
+{
+ PxU32 size = computeByteSize(mWheelsSimData.mNbActiveWheels);
+ PxU8* ptr = context.readExtraData<PxU8, PX_SERIAL_ALIGN>(size);
+ patchupPointers(mWheelsSimData.mNbActiveWheels, this, ptr);
+}
+
+void PxVehicleWheels::getBinaryMetaData(PxOutputStream& stream)
+{
+ PxVehicleWheelsSimData::getBinaryMetaData(stream);
+ PxVehicleWheelsDynData::getBinaryMetaData(stream);
+
+ //PxVehicleWheels
+ PX_DEF_BIN_METADATA_VCLASS(stream, PxVehicleWheels)
+ PX_DEF_BIN_METADATA_BASE_CLASS(stream, PxVehicleWheels, PxBase)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheels, PxVehicleWheelsSimData, mWheelsSimData, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheels, PxVehicleWheelsDynData, mWheelsDynData, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheels, PxRigidDynamic, mActor, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheels, PxU32, mNbNonDrivenWheels, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheels, PxU8, mOnConstraintReleaseCounter, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheels, PxU8, mType, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels, PxU8, mPad, PxMetaDataFlag::ePADDING)
+}
+
+void PxVehicleConstraintShader::getBinaryMetaData(PxOutputStream& stream)
+{
+ //SuspLimitConstraintData
+ PX_DEF_BIN_METADATA_CLASS(stream, SuspLimitConstraintData)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, SuspLimitConstraintData, PxVec3, mCMOffsets, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, SuspLimitConstraintData, PxVec3, mDirs, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, SuspLimitConstraintData, PxReal, mErrors, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, SuspLimitConstraintData, bool, mActiveFlags, 0)
+
+ //StickyTireConstraintData
+ PX_DEF_BIN_METADATA_CLASS(stream, StickyTireConstraintData)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, StickyTireConstraintData, PxVec3, mCMOffsets, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, StickyTireConstraintData, PxVec3, mDirs, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, StickyTireConstraintData, PxReal, mTargetSpeeds, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, StickyTireConstraintData, bool, mActiveFlags, 0)
+
+ //VehicleConstraintData
+ PX_DEF_BIN_METADATA_CLASS(stream, VehicleConstraintData)
+ PX_DEF_BIN_METADATA_ITEM(stream, VehicleConstraintData, SuspLimitConstraintData, mSuspLimitData, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, VehicleConstraintData, StickyTireConstraintData, mStickyTireForwardData, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, VehicleConstraintData, StickyTireConstraintData, mStickyTireSideData, 0)
+
+ //PxVehicleConstraintShader
+ PX_DEF_BIN_METADATA_VCLASS(stream, PxVehicleConstraintShader)
+ PX_DEF_BIN_METADATA_BASE_CLASS(stream, PxVehicleConstraintShader, PxConstraintConnector)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleConstraintShader, VehicleConstraintData, mData, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleConstraintShader, PxConstraint, mConstraint, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleConstraintShader, PxVehicleWheels, mVehicle, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleConstraintShader, PxU32, mPad, PxMetaDataFlag::ePADDING)
+}
+
+void PxVehicleWheels4SimData::getBinaryMetaData(PxOutputStream& stream)
+{
+ //PxVehicleSuspensionData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleSuspensionData)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleSuspensionData, PxReal, mSpringStrength, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleSuspensionData, PxReal, mSpringDamperRate, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleSuspensionData, PxReal, mMaxCompression, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleSuspensionData, PxReal, mMaxDroop, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleSuspensionData, PxReal, mSprungMass, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleSuspensionData, PxReal, mCamberAtRest, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleSuspensionData, PxReal, mCamberAtMaxCompression, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleSuspensionData, PxReal, mCamberAtMaxDroop, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleSuspensionData, PxReal, mRecipMaxCompression, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleSuspensionData, PxReal, mRecipMaxDroop, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleSuspensionData, PxU32, mPad, PxMetaDataFlag::ePADDING)
+
+ //PxVehicleWheelData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleWheelData)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelData, PxReal, mRadius, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelData, PxReal, mWidth, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelData, PxReal, mMass, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelData, PxReal, mMOI, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelData, PxReal, mDampingRate, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelData, PxReal, mMaxBrakeTorque, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelData, PxReal, mMaxHandBrakeTorque, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelData, PxReal, mMaxSteer, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelData, PxReal, mToeAngle, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelData, PxReal, mRecipRadius, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheelData, PxReal, mRecipMOI, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheelData, PxReal, mPad, PxMetaDataFlag::ePADDING)
+
+ //PxVehicleTireData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleTireData)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireData, PxReal, mLatStiffX, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireData, PxReal, mLatStiffY, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireData, PxReal, mLongitudinalStiffnessPerUnitGravity, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireData, PxReal, mCamberStiffnessPerUnitGravity, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleTireData, PxReal, mFrictionVsSlipGraph, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireData, PxU32, mType, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireData, PxReal, mRecipLongitudinalStiffnessPerUnitGravity, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireData, PxReal, mFrictionVsSlipGraphRecipx1Minusx0, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleTireData, PxReal, mFrictionVsSlipGraphRecipx2Minusx1, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleTireData, PxReal, mPad, PxMetaDataFlag::ePADDING)
+
+ //PxVehicleWheels4SimData
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleWheels4SimData)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxVehicleSuspensionData, mSuspensions, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxVehicleWheelData, mWheels, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxVehicleTireData, mTires, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxVec3, mSuspDownwardTravelDirections, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxVec3, mSuspForceAppPointOffsets, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxVec3, mTireForceAppPointOffsets, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxVec3, mWheelCentreOffsets, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxReal, mTireRestLoads, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxReal, mRecipTireRestLoads, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxFilterData, mSqFilterData, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxU8, mWheelShapeMap, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4SimData, PxU32, mPad, PxMetaDataFlag::ePADDING)
+}
+
+/*
+void PxVehicleAntiRollBar::getBinaryMetaData(PxOutputStream& stream)
+{
+}
+*/
+
+void PxVehicleWheels4DynData::getBinaryMetaData(PxOutputStream& stream)
+{
+ PX_DEF_BIN_METADATA_CLASS(stream, PxVehicleWheels4DynData)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4DynData, PxReal, mWheelSpeeds, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4DynData, PxReal, mCorrectedWheelSpeeds, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4DynData, PxReal, mWheelRotationAngles, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4DynData, PxReal, mTireLowForwardSpeedTimers, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4DynData, PxReal, mTireLowSideSpeedTimers, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4DynData, PxU8, mQueryOrCachedHitResults, 0)
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4DynData, PxReal, mJounces, 0)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheels4DynData, PxVehicleConstraintShader, mVehicleConstraints, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheels4DynData, PxRaycastQueryResult, mRaycastResults, PxMetaDataFlag::ePTR)
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheels4DynData, PxSweepQueryResult, mSweepResults, PxMetaDataFlag::ePTR)
+
+ PX_DEF_BIN_METADATA_ITEM(stream, PxVehicleWheels4DynData, bool, mHasCachedRaycastHitPlane, 0)
+#if PX_P64_FAMILY
+ PX_DEF_BIN_METADATA_ITEMS_AUTO(stream, PxVehicleWheels4DynData, PxU32, mPad, PxMetaDataFlag::ePADDING)
+#endif
+}
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleNoDrive.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleNoDrive.cpp
new file mode 100644
index 00000000..cac7cc77
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleNoDrive.cpp
@@ -0,0 +1,157 @@
+// 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 "foundation/PxMemory.h"
+#include "PxVehicleNoDrive.h"
+#include "PxVehicleWheels.h"
+#include "PxVehicleDefaults.h"
+#include "PxRigidDynamic.h"
+#include "CmPhysXCommon.h"
+#include "CmUtils.h"
+#include "PsFoundation.h"
+
+namespace physx
+{
+
+extern PxF32 gToleranceScaleLength;
+
+bool PxVehicleNoDrive::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(PxVehicleWheels::isValid(), "invalid PxVehicleDrive", false);
+ return true;
+}
+
+PxVehicleNoDrive* PxVehicleNoDrive::allocate(const PxU32 numWheels)
+{
+ PX_CHECK_AND_RETURN_NULL(numWheels>0, "Cars with zero wheels are illegal");
+ PX_CHECK_AND_RETURN_NULL(gToleranceScaleLength > 0, "PxVehicleNoDrive::allocate - need to call PxInitVehicleSDK");
+
+ //Compute the bytes needed.
+ const PxU32 numWheels4 = (((numWheels + 3) & ~3) >> 2);
+ const PxU32 inputByteSize16 = sizeof(PxReal)*numWheels4*4;
+ const PxU32 byteSize = sizeof(PxVehicleNoDrive) + 3*inputByteSize16 + PxVehicleWheels::computeByteSize(numWheels);
+
+ //Allocate the memory.
+ PxVehicleNoDrive* veh = static_cast<PxVehicleNoDrive*>(PX_ALLOC(byteSize, "PxVehicleNoDrive"));
+ Cm::markSerializedMem(veh, byteSize);
+ new(veh) PxVehicleNoDrive();
+
+ //Patch up the pointers.
+ PxU8* ptr = reinterpret_cast<PxU8*>(veh) + sizeof(PxVehicleNoDrive);
+ veh->mSteerAngles = reinterpret_cast<PxReal*>(ptr);
+ ptr += inputByteSize16;
+ veh->mDriveTorques = reinterpret_cast<PxReal*>(ptr);
+ ptr += inputByteSize16;
+ veh->mBrakeTorques = reinterpret_cast<PxReal*>(ptr);
+ ptr += inputByteSize16;
+ ptr = PxVehicleWheels::patchupPointers(numWheels, veh, ptr);
+
+ //Initialise.
+ PxMemZero(veh->mSteerAngles, inputByteSize16);
+ PxMemZero(veh->mDriveTorques, inputByteSize16);
+ PxMemZero(veh->mBrakeTorques, inputByteSize16);
+ veh->init(numWheels);
+
+ //Set the vehicle type.
+ veh->mType = PxVehicleTypes::eNODRIVE;
+
+ return veh;
+}
+
+void PxVehicleNoDrive::free()
+{
+ PxVehicleWheels::free();
+}
+
+void PxVehicleNoDrive::setup
+(PxPhysics* physics, PxRigidDynamic* vehActor, const PxVehicleWheelsSimData& wheelsData)
+{
+ //Set up the wheels.
+ PxVehicleWheels::setup(physics,vehActor,wheelsData,0,wheelsData.getNbWheels());
+}
+
+PxVehicleNoDrive* PxVehicleNoDrive::create
+(PxPhysics* physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData)
+{
+ PxVehicleNoDrive* veh=PxVehicleNoDrive::allocate(wheelsData.getNbWheels());
+ veh->setup(physics,vehActor,wheelsData);
+ return veh;
+}
+
+void PxVehicleNoDrive::setToRestState()
+{
+ const PxU32 numWheels4 = (((mWheelsSimData.getNbWheels() + 3) & ~3) >> 2);
+ const PxU32 inputByteSize = sizeof(PxReal)*numWheels4*4;
+ const PxU32 inputByteSize16 = (inputByteSize + 15) & ~15;
+ PxMemZero(mSteerAngles, 3*inputByteSize16);
+
+ //Set core to rest state.
+ PxVehicleWheels::setToRestState();
+}
+
+void PxVehicleNoDrive::setBrakeTorque(const PxU32 id, const PxReal brakeTorque)
+{
+ PX_CHECK_AND_RETURN(id < mWheelsSimData.getNbWheels(), "PxVehicleNoDrive::setBrakeTorque - Illegal wheel");
+ PX_CHECK_AND_RETURN(brakeTorque>=0, "PxVehicleNoDrive::setBrakeTorque - negative brake torques are illegal");
+ mBrakeTorques[id] = brakeTorque;
+}
+
+void PxVehicleNoDrive::setDriveTorque(const PxU32 id, const PxReal driveTorque)
+{
+ PX_CHECK_AND_RETURN(id < mWheelsSimData.getNbWheels(), "PxVehicleNoDrive::setDriveTorque - Illegal wheel");
+ mDriveTorques[id] = driveTorque;
+}
+
+void PxVehicleNoDrive::setSteerAngle(const PxU32 id, const PxReal steerAngle)
+{
+ PX_CHECK_AND_RETURN(id < mWheelsSimData.getNbWheels(), "PxVehicleNoDrive::setSteerAngle - Illegal wheel");
+ mSteerAngles[id] = steerAngle;
+}
+
+PxReal PxVehicleNoDrive::getBrakeTorque(const PxU32 id) const
+{
+ PX_CHECK_AND_RETURN_VAL(id < mWheelsSimData.getNbWheels(), "PxVehicleNoDrive::getBrakeTorque - Illegal wheel", 0);
+ return mBrakeTorques[id];
+}
+
+PxReal PxVehicleNoDrive::getDriveTorque(const PxU32 id) const
+{
+ PX_CHECK_AND_RETURN_VAL(id < mWheelsSimData.getNbWheels(), "PxVehicleNoDrive::getDriveTorque - Illegal wheel",0);
+ return mDriveTorques[id];
+}
+
+PxReal PxVehicleNoDrive::getSteerAngle(const PxU32 id) const
+{
+ PX_CHECK_AND_RETURN_VAL(id < mWheelsSimData.getNbWheels(), "PxVehicleNoDrive::getSteerAngle - Illegal wheel",0);
+ return mSteerAngles[id];
+}
+
+} //namespace physx
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSDK.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSDK.cpp
new file mode 100644
index 00000000..37003503
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSDK.cpp
@@ -0,0 +1,115 @@
+// 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 "PxVehicleSDK.h"
+#include "PxPhysics.h"
+#include "PxTolerancesScale.h"
+#include "CmPhysXCommon.h"
+#include "PsFoundation.h"
+#include "PsUtilities.h"
+#include "PxVehicleDrive4W.h"
+#include "PxVehicleMetaDataObjects.h"
+#include "PxVehicleSerialization.h"
+#include "SnRepXSerializerImpl.h"
+#include "PxSerializer.h"
+#include "PxVehicleDriveTank.h"
+#include "PxVehicleNoDrive.h"
+#include "PxVehicleDriveNW.h"
+
+namespace physx
+{
+
+void setVehicleToleranceScale(const PxTolerancesScale& ts);
+void resetVehicleToleranceScale();
+void setSerializationRegistryPtr(const PxSerializationRegistry* sr);
+const PxSerializationRegistry* resetSerializationRegistryPtr();
+void setVehicleDefaults();
+
+bool PxInitVehicleSDK(PxPhysics& physics, PxSerializationRegistry* sr)
+{
+ PX_ASSERT(static_cast<Ps::Foundation*>(&physics.getFoundation()) == &Ps::Foundation::getInstance());
+ Ps::Foundation::incRefCount();
+ setVehicleToleranceScale(physics.getTolerancesScale());
+
+ setVehicleDefaults();
+
+ setSerializationRegistryPtr(sr);
+ if(sr)
+ {
+ sr->registerRepXSerializer(PxVehicleConcreteType::eVehicleDrive4W, PX_NEW_REPX_SERIALIZER(PxVehicleRepXSerializer<PxVehicleDrive4W>));
+ sr->registerRepXSerializer(PxVehicleConcreteType::eVehicleDriveTank, PX_NEW_REPX_SERIALIZER(PxVehicleRepXSerializer<PxVehicleDriveTank>));
+ sr->registerRepXSerializer(PxVehicleConcreteType::eVehicleDriveNW, PX_NEW_REPX_SERIALIZER(PxVehicleRepXSerializer<PxVehicleDriveNW>));
+ sr->registerRepXSerializer(PxVehicleConcreteType::eVehicleNoDrive, PX_NEW_REPX_SERIALIZER(PxVehicleRepXSerializer<PxVehicleNoDrive>));
+
+ sr->registerSerializer(PxVehicleConcreteType::eVehicleDrive4W, PX_NEW_SERIALIZER_ADAPTER(PxVehicleDrive4W));
+ sr->registerSerializer(PxVehicleConcreteType::eVehicleDriveTank, PX_NEW_SERIALIZER_ADAPTER(PxVehicleDriveTank));
+ sr->registerSerializer(PxVehicleConcreteType::eVehicleNoDrive, PX_NEW_SERIALIZER_ADAPTER(PxVehicleNoDrive));
+ sr->registerSerializer(PxVehicleConcreteType::eVehicleDriveNW, PX_NEW_SERIALIZER_ADAPTER(PxVehicleDriveNW));
+
+ sr->registerBinaryMetaDataCallback(PxVehicleDrive4W::getBinaryMetaData);
+ sr->registerBinaryMetaDataCallback(PxVehicleDriveTank::getBinaryMetaData);
+ sr->registerBinaryMetaDataCallback(PxVehicleNoDrive::getBinaryMetaData);
+ sr->registerBinaryMetaDataCallback(PxVehicleDriveNW::getBinaryMetaData);
+ }
+ return true;
+}
+
+void PxCloseVehicleSDK(PxSerializationRegistry* sr)
+{
+ Ps::Foundation::decRefCount();
+ resetVehicleToleranceScale();
+
+ setVehicleDefaults();
+
+ if (sr != resetSerializationRegistryPtr())
+ {
+ Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxCloseVehicleSDK called with different PxSerializationRegistry instance than PxInitVehicleSDK.");
+ return;
+ }
+
+ if(sr)
+ {
+ PX_DELETE_SERIALIZER_ADAPTER(sr->unregisterSerializer(PxVehicleConcreteType::eVehicleDrive4W));
+ PX_DELETE_SERIALIZER_ADAPTER(sr->unregisterSerializer(PxVehicleConcreteType::eVehicleDriveTank));
+ PX_DELETE_SERIALIZER_ADAPTER(sr->unregisterSerializer(PxVehicleConcreteType::eVehicleNoDrive));
+ PX_DELETE_SERIALIZER_ADAPTER(sr->unregisterSerializer(PxVehicleConcreteType::eVehicleDriveNW));
+
+ PX_DELETE_REPX_SERIALIZER(sr->unregisterRepXSerializer(PxVehicleConcreteType::eVehicleDrive4W));
+ PX_DELETE_REPX_SERIALIZER(sr->unregisterRepXSerializer(PxVehicleConcreteType::eVehicleDriveTank));
+ PX_DELETE_REPX_SERIALIZER(sr->unregisterRepXSerializer(PxVehicleConcreteType::eVehicleNoDrive));
+ PX_DELETE_REPX_SERIALIZER(sr->unregisterRepXSerializer(PxVehicleConcreteType::eVehicleDriveNW));
+ }
+}
+/////////////////////////
+
+
+
+
+}//physx
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSerialization.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSerialization.cpp
new file mode 100644
index 00000000..c3c6d66f
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSerialization.cpp
@@ -0,0 +1,203 @@
+// 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 "PxRepXSimpleType.h"
+#include "PxBase.h"
+#include "PxCollection.h"
+#include "PxVehicleMetaDataObjects.h"
+#include "SnRepXSerializerImpl.h"
+#include "PxVehicleSerialization.h"
+#include "PxVehicleSuspWheelTire4.h"
+#include "PxVehicleSuspLimitConstraintShader.h"
+#include "PsFPU.h"
+
+
+namespace physx
+{
+ using namespace Sn;
+
+ template<typename TVehicleType>
+ inline void* createVehicle( PxPhysics& physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData, const PxVehicleDriveSimData4W& driveData, const PxVehicleDriveSimDataNW& driveDataNW,
+ const PxU32 numWheels, const PxU32 numNonDrivenWheels)
+ {
+ PX_UNUSED(physics);
+ PX_UNUSED(vehActor);
+ PX_UNUSED(wheelsData);
+ PX_UNUSED(driveData);
+ PX_UNUSED(driveDataNW);
+ PX_UNUSED(numWheels);
+ PX_UNUSED(numNonDrivenWheels);
+ return NULL;
+ }
+
+ template<>
+ inline void* createVehicle<PxVehicleDrive4W>(PxPhysics& physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData, const PxVehicleDriveSimData4W& driveData, const PxVehicleDriveSimDataNW& /*driveDataNW*/,
+ const PxU32 numWheels, const PxU32 numNonDrivenWheels)
+ {
+ PxVehicleDrive4W* vehDrive4W = PxVehicleDrive4W::allocate(numWheels);
+ vehDrive4W->setup(&physics, vehActor->is<PxRigidDynamic>(), wheelsData, driveData, numNonDrivenWheels);
+ return vehDrive4W;
+ }
+
+ template<>
+ inline void* createVehicle<PxVehicleDriveTank>(PxPhysics& physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData, const PxVehicleDriveSimData4W& driveData, const PxVehicleDriveSimDataNW& /*driveDataNW*/,
+ const PxU32 numWheels, const PxU32 numNonDrivenWheels)
+ {
+ PxVehicleDriveTank* tank = PxVehicleDriveTank::allocate(numWheels);
+ tank->setup(&physics, vehActor->is<PxRigidDynamic>(), wheelsData, driveData, numWheels - numNonDrivenWheels);
+ return tank;
+ }
+
+ template<>
+ inline void* createVehicle<PxVehicleDriveNW>(PxPhysics& physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData, const PxVehicleDriveSimData4W& /*driveData*/, const PxVehicleDriveSimDataNW& driveDataNW,
+ const PxU32 numWheels, const PxU32 numNonDrivenWheels)
+ {
+ PxVehicleDriveNW* vehDriveNW = PxVehicleDriveNW::allocate(numWheels);
+ vehDriveNW->setup(&physics, vehActor->is<PxRigidDynamic>(), wheelsData, driveDataNW, numWheels - numNonDrivenWheels);
+ return vehDriveNW;
+ }
+
+ template<>
+ inline void* createVehicle<PxVehicleNoDrive>(PxPhysics& physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData, const PxVehicleDriveSimData4W& /*driveData*/, const PxVehicleDriveSimDataNW& /*driveDataNW*/,
+ const PxU32 numWheels, const PxU32 /*numNonDrivenWheels*/)
+ {
+ PxVehicleNoDrive* vehNoDrive = PxVehicleNoDrive::allocate(numWheels);
+ vehNoDrive->setup(&physics, vehActor->is<PxRigidDynamic>(), wheelsData);
+ return vehNoDrive;
+ }
+
+ template<typename TVehicleType>
+ PxRepXObject PxVehicleRepXSerializer<TVehicleType>::fileToObject( XmlReader& inReader, XmlMemoryAllocator& inAllocator, PxRepXInstantiationArgs& inArgs, PxCollection* inCollection )
+ {
+ PxRigidActor* vehActor = NULL;
+ readReference<PxRigidActor>( inReader, *inCollection, "PxRigidDynamicRef", vehActor );
+ if ( vehActor == NULL )
+ return PxRepXObject();
+
+ PxU32 numWheels = 0;
+ readProperty( inReader, "NumWheels", numWheels );
+ if( numWheels == 0)
+ {
+ Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
+ "PxSerialization::createCollectionFromXml: PxVehicleRepXSerializer: Xml field NumWheels is zero!");
+ return PxRepXObject();
+ }
+
+ PxU32 numNonDrivenWheels = 0;
+ readProperty( inReader, "NumNonDrivenWheels", numNonDrivenWheels );
+
+ //change to numwheel
+ PxVehicleWheelsSimData* wheelsSimData=PxVehicleWheelsSimData::allocate(numWheels);
+ {
+ inReader.pushCurrentContext();
+ if ( inReader.gotoChild( "MWheelsSimData" ) )
+ {
+ readAllProperties( inArgs, inReader, wheelsSimData, inAllocator, *inCollection );
+ }
+
+ inReader.popCurrentContext();
+ }
+
+ PxVehicleDriveSimData4W driveSimData;
+ {
+ inReader.pushCurrentContext();
+ if ( inReader.gotoChild( "MDriveSimData" ) )
+ {
+ readAllProperties( inArgs, inReader, &driveSimData, inAllocator, *inCollection );
+ }
+
+ inReader.popCurrentContext();
+ }
+
+ PxVehicleDriveSimDataNW nmSimData;
+ {
+ inReader.pushCurrentContext();
+ if ( inReader.gotoChild( "MDriveSimDataNW" ) )
+ {
+ readAllProperties( inArgs, inReader, &driveSimData, inAllocator, *inCollection );
+ }
+ inReader.popCurrentContext();
+ }
+ TVehicleType* drive = static_cast<TVehicleType*>(createVehicle<TVehicleType>(inArgs.physics, vehActor->is<PxRigidDynamic>(), *wheelsSimData, driveSimData, nmSimData, numWheels, numNonDrivenWheels));
+ readAllProperties( inArgs, inReader, drive, inAllocator, *inCollection );
+
+ PxVehicleWheels4DynData* wheel4DynData = drive->mWheelsDynData.getWheel4DynData();
+ PX_ASSERT( wheel4DynData );
+ for(PxU32 i=0;i<wheelsSimData->getNbWheels4();i++)
+ {
+ PxConstraint* constraint = wheel4DynData[i].getVehicletConstraintShader().getPxConstraint();
+ if( constraint )
+ inCollection->add(*constraint);
+ }
+
+ if( wheelsSimData )
+ wheelsSimData->free();
+
+ return PxCreateRepXObject(drive);
+ }
+
+ template<typename TVehicleType>
+ void PxVehicleRepXSerializer<TVehicleType>::objectToFileImpl( const TVehicleType* drive, PxCollection* inCollection, XmlWriter& inWriter, MemoryBuffer& inTempBuffer, PxRepXInstantiationArgs& /*inArgs*/ )
+ {
+ PX_SIMD_GUARD; // denorm exception triggered in PxVehicleGearsDataGeneratedInfo::visitInstanceProperties on osx
+ writeReference( inWriter, *inCollection, "PxRigidDynamicRef", drive->getRigidDynamicActor() );
+ writeProperty( inWriter, *inCollection, inTempBuffer, "NumWheels", drive->mWheelsSimData.getNbWheels() );
+ writeProperty( inWriter, *inCollection, inTempBuffer, "NumNonDrivenWheels", drive->getNbNonDrivenWheels());
+ writeAllProperties( drive, inWriter, inTempBuffer, *inCollection );
+ }
+
+ PxVehicleNoDrive::PxVehicleNoDrive()
+ : PxVehicleWheels(PxVehicleConcreteType::eVehicleNoDrive, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
+ {}
+
+ PxVehicleDrive4W::PxVehicleDrive4W()
+ : PxVehicleDrive(PxVehicleConcreteType::eVehicleDrive4W, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
+ {}
+
+ PxVehicleDriveNW::PxVehicleDriveNW()
+ : PxVehicleDrive(PxVehicleConcreteType::eVehicleDriveNW, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
+ {}
+
+ PxVehicleDriveTank::PxVehicleDriveTank()
+ : PxVehicleDrive(PxVehicleConcreteType::eVehicleDriveTank, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
+ , mDriveModel(PxVehicleDriveTankControlModel::eSTANDARD)
+ {}
+
+ // explicit instantiations
+ template struct PxVehicleRepXSerializer<PxVehicleDrive4W>;
+ template struct PxVehicleRepXSerializer<PxVehicleDriveTank>;
+ template struct PxVehicleRepXSerializer<PxVehicleDriveNW>;
+ template struct PxVehicleRepXSerializer<PxVehicleNoDrive>;
+
+}
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSerialization.h b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSerialization.h
new file mode 100644
index 00000000..ccefe65d
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSerialization.h
@@ -0,0 +1,65 @@
+// 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 PX_VEHICLE_SERIALIZATION_H
+#define PX_VEHICLE_SERIALIZATION_H
+
+#include "extensions/PxRepXSimpleType.h"
+
+namespace physx
+{
+ class PxRepXSerializer;
+ class PxSerializationRegistry;
+
+ template<typename TLiveType>
+ struct RepXSerializerImpl;
+
+ class XmlReader;
+ class XmlMemoryAllocator;
+ class XmlWriter;
+ class MemoryBuffer;
+
+ PX_DEFINE_TYPEINFO(PxVehicleNoDrive, PxVehicleConcreteType::eVehicleNoDrive)
+ PX_DEFINE_TYPEINFO(PxVehicleDrive4W, PxVehicleConcreteType::eVehicleDrive4W)
+ PX_DEFINE_TYPEINFO(PxVehicleDriveNW, PxVehicleConcreteType::eVehicleDriveNW)
+ PX_DEFINE_TYPEINFO(PxVehicleDriveTank, PxVehicleConcreteType::eVehicleDriveTank)
+
+ template<typename TVehicleType>
+ struct PxVehicleRepXSerializer : public RepXSerializerImpl<TVehicleType>
+ {
+ PxVehicleRepXSerializer( PxAllocatorCallback& inCallback ) : RepXSerializerImpl<TVehicleType>( inCallback ) {}
+ virtual PxRepXObject fileToObject( XmlReader& inReader, XmlMemoryAllocator& inAllocator, PxRepXInstantiationArgs& inArgs, PxCollection* inCollection );
+ virtual void objectToFileImpl( const TVehicleType* , PxCollection* , XmlWriter& , MemoryBuffer& , PxRepXInstantiationArgs& );
+ virtual TVehicleType* allocateObject( PxRepXInstantiationArgs& ) { return NULL; }
+ };
+
+}
+
+
+#endif//PX_VEHICLE_REPX_SERIALIZER_H
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspLimitConstraintShader.h b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspLimitConstraintShader.h
new file mode 100644
index 00000000..ba5db531
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspLimitConstraintShader.h
@@ -0,0 +1,305 @@
+// 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 PX_VEHICLE_SUSP_LIMIT_CONSTRAINT_SHADER_H
+#define PX_VEHICLE_SUSP_LIMIT_CONSTRAINT_SHADER_H
+/** \addtogroup vehicle
+ @{
+*/
+
+#include "foundation/PxTransform.h"
+#include "extensions/PxConstraintExt.h"
+#include "PxConstraintDesc.h"
+#include "PxConstraint.h"
+#include "PsAllocator.h"
+
+#if !PX_DOXYGEN
+namespace physx
+{
+#endif
+
+class PxVehicleConstraintShader : public PxConstraintConnector
+{
+//= ATTENTION! =====================================================================================
+// Changing the data layout of this class breaks the binary serialization format. See comments for
+// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData
+// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION
+// accordingly.
+//==================================================================================================
+public:
+
+ friend class PxVehicleWheels;
+
+ PxVehicleConstraintShader(PxVehicleWheels* vehicle, PxConstraint* constraint = NULL)
+ : mConstraint(constraint),
+ mVehicle(vehicle)
+ {
+ }
+ PxVehicleConstraintShader(){}
+ ~PxVehicleConstraintShader()
+ {
+ }
+
+ static void getBinaryMetaData(PxOutputStream& stream);
+
+ void release()
+ {
+ if(mConstraint)
+ {
+ mConstraint->release();
+ }
+ }
+
+ virtual void onComShift(PxU32 actor) { PX_UNUSED(actor); }
+
+ virtual void onOriginShift(const PxVec3& shift) { PX_UNUSED(shift); }
+
+ virtual void* prepareData()
+ {
+ return &mData;
+ }
+
+ virtual bool updatePvdProperties(pvdsdk::PvdDataStream& pvdConnection,
+ const PxConstraint* c,
+ PxPvdUpdateType::Enum updateType) const { PX_UNUSED(c); PX_UNUSED(updateType); PX_UNUSED(&pvdConnection); return true;}
+
+ virtual void onConstraintRelease()
+ {
+ mVehicle->mOnConstraintReleaseCounter--;
+ if(0==mVehicle->mOnConstraintReleaseCounter)
+ {
+ PX_FREE(mVehicle);
+ }
+ }
+
+ virtual void* getExternalReference(PxU32& typeID) { typeID = PxConstraintExtIDs::eVEHICLE_SUSP_LIMIT; return this; }
+ virtual PxBase* getSerializable() { return NULL; }
+
+
+ static PxU32 vehicleSuspLimitConstraintSolverPrep(
+ Px1DConstraint* constraints,
+ PxVec3& body0WorldOffset,
+ PxU32 maxConstraints,
+ PxConstraintInvMassScale&,
+ const void* constantBlock,
+ const PxTransform& bodyAToWorld,
+ const PxTransform& bodyBToWorld
+ )
+ {
+ PX_UNUSED(maxConstraints);
+ PX_UNUSED(body0WorldOffset);
+ PX_UNUSED(bodyBToWorld);
+ PX_ASSERT(bodyAToWorld.isValid()); PX_ASSERT(bodyBToWorld.isValid());
+
+ const VehicleConstraintData* data = static_cast<const VehicleConstraintData*>(constantBlock);
+ PxU32 numActive=0;
+
+ //Susp limit constraints.
+ for(PxU32 i=0;i<4;i++)
+ {
+ if(data->mSuspLimitData.mActiveFlags[i])
+ {
+ Px1DConstraint& p=constraints[numActive];
+ p.linear0=bodyAToWorld.q.rotate(data->mSuspLimitData.mDirs[i]);
+ p.angular0=bodyAToWorld.q.rotate(data->mSuspLimitData.mCMOffsets[i].cross(data->mSuspLimitData.mDirs[i]));
+ p.geometricError=data->mSuspLimitData.mErrors[i];
+ p.linear1=PxVec3(0);
+ p.angular1=PxVec3(0);
+ p.minImpulse=-FLT_MAX;
+ p.maxImpulse=0;
+ p.velocityTarget=0;
+ numActive++;
+ }
+ }
+
+ //Sticky tire friction constraints.
+ for(PxU32 i=0;i<4;i++)
+ {
+ if(data->mStickyTireForwardData.mActiveFlags[i])
+ {
+ Px1DConstraint& p=constraints[numActive];
+ p.linear0=data->mStickyTireForwardData.mDirs[i];
+ p.angular0=data->mStickyTireForwardData.mCMOffsets[i].cross(data->mStickyTireForwardData.mDirs[i]);
+ p.geometricError=0.0f;
+ p.linear1=PxVec3(0);
+ p.angular1=PxVec3(0);
+ p.minImpulse=-FLT_MAX;
+ p.maxImpulse=FLT_MAX;
+ p.velocityTarget=data->mStickyTireForwardData.mTargetSpeeds[i];
+ p.mods.spring.damping = 1000.0f;
+ p.flags = Px1DConstraintFlag::eSPRING | Px1DConstraintFlag::eACCELERATION_SPRING;
+ numActive++;
+ }
+ }
+
+ //Sticky tire friction constraints.
+ for(PxU32 i=0;i<4;i++)
+ {
+ if(data->mStickyTireSideData.mActiveFlags[i])
+ {
+ Px1DConstraint& p=constraints[numActive];
+ p.linear0=data->mStickyTireSideData.mDirs[i];
+ p.angular0=data->mStickyTireSideData.mCMOffsets[i].cross(data->mStickyTireSideData.mDirs[i]);
+ p.geometricError=0.0f;
+ p.linear1=PxVec3(0);
+ p.angular1=PxVec3(0);
+ p.minImpulse=-FLT_MAX;
+ p.maxImpulse=FLT_MAX;
+ p.velocityTarget=data->mStickyTireSideData.mTargetSpeeds[i];
+ p.mods.spring.damping = 1000.0f;
+ p.flags = Px1DConstraintFlag::eSPRING | Px1DConstraintFlag::eACCELERATION_SPRING;
+ numActive++;
+ }
+ }
+
+
+ return numActive;
+ }
+
+ static void visualiseConstraint(PxConstraintVisualizer &viz,
+ const void* constantBlock,
+ const PxTransform& body0Transform,
+ const PxTransform& body1Transform,
+ PxU32 flags){ PX_UNUSED(&viz); PX_UNUSED(constantBlock); PX_UNUSED(body0Transform);
+ PX_UNUSED(body1Transform); PX_UNUSED(flags);
+ PX_ASSERT(body0Transform.isValid()); PX_ASSERT(body1Transform.isValid()); }
+
+public:
+
+ struct SuspLimitConstraintData
+ {
+ PxVec3 mCMOffsets[4];
+ PxVec3 mDirs[4];
+ PxReal mErrors[4];
+ bool mActiveFlags[4];
+ };
+ struct StickyTireConstraintData
+ {
+ PxVec3 mCMOffsets[4];
+ PxVec3 mDirs[4];
+ PxReal mTargetSpeeds[4];
+ bool mActiveFlags[4];
+ };
+
+ struct VehicleConstraintData
+ {
+ SuspLimitConstraintData mSuspLimitData;
+ StickyTireConstraintData mStickyTireForwardData;
+ StickyTireConstraintData mStickyTireSideData;
+ };
+ VehicleConstraintData mData;
+
+ PxConstraint* mConstraint;
+
+ PX_INLINE void setPxConstraint(PxConstraint* pxConstraint)
+ {
+ mConstraint = pxConstraint;
+ }
+
+ PX_INLINE PxConstraint* getPxConstraint()
+ {
+ return mConstraint;
+ }
+
+ PxConstraintConnector* getConnector()
+ {
+ return this;
+ }
+
+ virtual PxConstraintSolverPrep getPrep()const { return NULL; /*KS - TODO. Figure out what to return here. Probably nothing is OK*/ }
+ virtual const void* getConstantBlock()const { return NULL; /*KS - TODO. Figure out what to return here. Probably nothing is OK*/ }
+
+private:
+
+ PxVehicleWheels* mVehicle;
+
+#if !PX_P64_FAMILY
+ PxU32 mPad[2];
+#else
+ PxU32 mPad[1];
+#endif
+};
+PX_COMPILE_TIME_ASSERT(0==(sizeof(PxVehicleConstraintShader)& 0x0f));
+
+
+/**
+\brief Default implementation of PxVehicleComputeTireForce
+@see PxVehicleComputeTireForce, PxVehicleTireForceCalculator
+*/
+void PxVehicleComputeTireForceDefault
+ (const void* shaderData,
+ const PxF32 tireFriction,
+ const PxF32 longSlip, const PxF32 latSlip, const PxF32 camber,
+ const PxF32 wheelOmega, const PxF32 wheelRadius, const PxF32 recipWheelRadius,
+ const PxF32 restTireLoad, const PxF32 normalisedTireLoad, const PxF32 tireLoad,
+ const PxF32 gravity, const PxF32 recipGravity,
+ PxF32& wheelTorque, PxF32& tireLongForceMag, PxF32& tireLatForceMag, PxF32& tireAlignMoment);
+
+
+/**
+\brief Structure containing shader data for each tire of a vehicle and a shader function that computes individual tire forces
+*/
+class PxVehicleTireForceCalculator
+{
+public:
+
+ PxVehicleTireForceCalculator()
+ : mShader(PxVehicleComputeTireForceDefault)
+ {
+ }
+
+ /**
+ \brief Array of shader data - one data entry per tire.
+ Default values are pointers to PxVehicleTireData (stored in PxVehicleWheelsSimData) and are set in PxVehicleDriveTank::setup or PxVehicleDrive4W::setup
+ @see PxVehicleComputeTireForce, PxVehicleComputeTireForceDefault, PxVehicleWheelsSimData, PxVehicleDriveTank::setup, PxVehicleDrive4W::setup
+ */
+ const void** mShaderData;
+
+ /**
+ \brief Shader function.
+ Default value is PxVehicleComputeTireForceDefault and is set in PxVehicleDriveTank::setup or PxVehicleDrive4W::setup
+ @see PxVehicleComputeTireForce, PxVehicleComputeTireForceDefault, PxVehicleWheelsSimData, PxVehicleDriveTank::setup, PxVehicleDrive4W::setup
+ */
+ PxVehicleComputeTireForce mShader;
+
+#if !PX_P64_FAMILY
+ PxU32 mPad[2];
+#endif
+};
+
+PX_COMPILE_TIME_ASSERT(0==(sizeof(PxVehicleTireForceCalculator) & 15));
+
+
+#if !PX_DOXYGEN
+} // namespace physx
+#endif
+
+
+/** @} */
+#endif //PX_VEHICLE_SUSP_LIMIT_CONSTRAINT_SHADER_H
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspWheelTire4.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspWheelTire4.cpp
new file mode 100644
index 00000000..fb4540d6
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspWheelTire4.cpp
@@ -0,0 +1,191 @@
+// 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 "PxVehicleSuspWheelTire4.h"
+#include "PxVehicleDefaults.h"
+#include "PsFoundation.h"
+#include "CmPhysXCommon.h"
+#include "PsUtilities.h"
+
+namespace physx
+{
+
+PxVehicleWheels4SimData::PxVehicleWheels4SimData()
+{
+ for(PxU32 i=0;i<4;i++)
+ {
+ mSuspDownwardTravelDirections[i]=PxVec3(0,0,0); //Must be filled out
+ mSuspForceAppPointOffsets[i]=PxVec3(0,0,0); //Must be filled out
+ mTireForceAppPointOffsets[i]=PxVec3(0,0,0); //Must be filled out
+ mWheelCentreOffsets[i]=PxVec3(0,0,0); //Must be filled out
+
+ mTireRestLoads[i]=20.0f + 1500.0f;
+ mRecipTireRestLoads[i]=1.0f/mTireRestLoads[i];
+ }
+}
+
+bool PxVehicleWheels4SimData::isValid(const PxU32 id) const
+{
+ PX_ASSERT(id<4);
+ PX_CHECK_AND_RETURN_VAL(mSuspensions[id].isValid(), "Invalid PxVehicleSuspWheelTire4SimulationData.mSuspensions", false);
+ PX_CHECK_AND_RETURN_VAL(mWheels[id].isValid(), "Invalid PxVehicleSuspWheelTire4SimulationData.mWheels", false);
+ PX_CHECK_AND_RETURN_VAL(mTires[id].isValid(), "Invalid PxVehicleSuspWheelTire4SimulationData.mTires", false);
+ PX_CHECK_AND_RETURN_VAL(mSuspDownwardTravelDirections[id].magnitude()>=0.999f && mSuspDownwardTravelDirections[id].magnitude()<=1.001f, "Invalid PxVehicleSuspWheelTire4SimulationData.mSuspDownwardTravelDirections", false);
+ PX_CHECK_AND_RETURN_VAL(mSuspForceAppPointOffsets[id].magnitude()!=0.0f, "Invalid PxVehicleSuspWheelTire4SimulationData.mSuspForceAppPointOffsets.mSuspForceAppPointOffsets", false);
+ PX_CHECK_AND_RETURN_VAL(mTireForceAppPointOffsets[id].magnitude()!=0.0f, "Invalid PxVehicleSuspWheelTire4SimulationData.mTireForceAppPointOffsets.mTireForceAppPointOffsets", false);
+ PX_CHECK_AND_RETURN_VAL(mWheelCentreOffsets[id].magnitude()!=0.0f, "Invalid PxVehicleSuspWheelTire4SimulationData.mWheelCentreOffsets.mWheelCentreOffsets", false);
+ PX_CHECK_AND_RETURN_VAL(mTireRestLoads[id]>0.0f, "Invalid PxVehicleSuspWheelTire4SimulationData.mTireRestLoads", false);
+ PX_CHECK_AND_RETURN_VAL(PxAbs((1.0f/mTireRestLoads[id]) - mRecipTireRestLoads[id]) <= 0.001f, "Invalid PxVehicleSuspWheelTire4SimulationData.mRecipTireRestLoads", false);
+ PX_UNUSED(id);
+ return true;
+}
+
+void PxVehicleWheels4SimData::setSuspensionData(const PxU32 id, const PxVehicleSuspensionData& susp)
+{
+ PX_CHECK_AND_RETURN(id<4, "Illegal suspension id");
+ PX_CHECK_AND_RETURN(susp.mSpringStrength>0, "Susp spring strength must be greater than zero");
+ PX_CHECK_AND_RETURN(susp.mSpringDamperRate>=0, "Susp spring damper rate must be greater than or equal to zero");
+ PX_CHECK_AND_RETURN(susp.mMaxCompression>=0, "Susp max compression must be greater than or equal to zero");
+ PX_CHECK_AND_RETURN(susp.mMaxDroop>=0, "Susp max droop must be greater than or equal to zero");
+ PX_CHECK_AND_RETURN(susp.mMaxDroop>0 || susp.mMaxCompression>0, "Either one of max droop or max compression must be greater than zero");
+ PX_CHECK_AND_RETURN(susp.mSprungMass>0, "Susp spring mass must be greater than zero");
+
+ mSuspensions[id]=susp;
+ mSuspensions[id].mRecipMaxCompression = 1.0f/((susp.mMaxCompression > 0.0f) ? susp.mMaxCompression : 1.0f);
+ mSuspensions[id].mRecipMaxDroop = 1.0f/((susp.mMaxDroop > 0.0f) ? susp.mMaxDroop : 1.0f);
+
+ mTireRestLoads[id]=mWheels[id].mMass+mSuspensions[id].mSprungMass;
+ mRecipTireRestLoads[id]=1.0f/mTireRestLoads[id];
+}
+
+/////////////////////////////
+
+void PxVehicleWheels4SimData::setWheelData(const PxU32 id, const PxVehicleWheelData& wheel)
+{
+ PX_CHECK_AND_RETURN(id<4, "Illegal wheel id");
+ PX_CHECK_AND_RETURN(wheel.mRadius>0, "Wheel radius must be greater than zero");
+ PX_CHECK_AND_RETURN(wheel.mMaxBrakeTorque>=0, "Wheel brake torque must be zero or be a positive value");
+ PX_CHECK_AND_RETURN(wheel.mMaxHandBrakeTorque>=0, "Wheel handbrake torque must be zero or be a positive value");
+ PX_CHECK_AND_RETURN(PxAbs(wheel.mMaxSteer)<PxHalfPi, "Wheel max steer must be in range (-Pi/2,Pi/2)");
+ PX_CHECK_AND_RETURN(wheel.mMass>0, "Wheel mass must be greater than zero");
+ PX_CHECK_AND_RETURN(wheel.mMOI>0, "Wheel moi must be greater than zero");
+ PX_CHECK_AND_RETURN(wheel.mToeAngle>-PxHalfPi && wheel.mToeAngle<PxHalfPi, "Wheel toe angle must be in range (-Pi/2,Pi/2)");
+ PX_CHECK_AND_RETURN(wheel.mWidth>0, "Wheel width must be greater than zero");
+ PX_CHECK_AND_RETURN(wheel.mDampingRate>=0, "Wheel damping rate must be greater than or equal to zero");
+
+ mWheels[id]=wheel;
+ mWheels[id].mRecipRadius=1.0f/mWheels[id].mRadius;
+ mWheels[id].mRecipMOI=1.0f/mWheels[id].mMOI;
+
+ mTireRestLoads[id]=mWheels[id].mMass+mSuspensions[id].mSprungMass;
+ mRecipTireRestLoads[id]=1.0f/mTireRestLoads[id];
+}
+
+/////////////////////////////
+
+void PxVehicleWheels4SimData::setTireData(const PxU32 id, const PxVehicleTireData& tire)
+{
+ PX_CHECK_AND_RETURN(id<4, "Illegal tire id");
+ PX_CHECK_AND_RETURN(tire.mLatStiffX>0, "Tire mLatStiffX must greater than zero");
+ PX_CHECK_AND_RETURN(tire.mLatStiffY>0, "Tire mLatStiffY must greater than zero");
+ PX_CHECK_AND_RETURN(tire.mLongitudinalStiffnessPerUnitGravity>0, "Tire longitudinal stiffness must greater than zero");
+ PX_CHECK_AND_RETURN(tire.mCamberStiffnessPerUnitGravity>=0, "Tire camber stiffness must greater than or equal to zero");
+ PX_CHECK_AND_RETURN(tire.mFrictionVsSlipGraph[0][0]==0, "mFrictionVsSlipGraph[0][0] must be zero");
+ PX_CHECK_AND_RETURN(tire.mFrictionVsSlipGraph[0][1]>0, "mFrictionVsSlipGraph[0][0] must be greater than zero");
+ PX_CHECK_AND_RETURN(tire.mFrictionVsSlipGraph[1][0]>0, "mFrictionVsSlipGraph[1][0] must be greater than zero");
+ PX_CHECK_AND_RETURN(tire.mFrictionVsSlipGraph[1][1]>=tire.mFrictionVsSlipGraph[0][1], "mFrictionVsSlipGraph[1][1] must be greater than mFrictionVsSlipGraph[0][1]");
+ PX_CHECK_AND_RETURN(tire.mFrictionVsSlipGraph[2][0]> tire.mFrictionVsSlipGraph[1][0], "mFrictionVsSlipGraph[2][0] must be greater than mFrictionVsSlipGraph[1][0]");
+ PX_CHECK_AND_RETURN(tire.mFrictionVsSlipGraph[2][1]<=tire.mFrictionVsSlipGraph[1][1], "mFrictionVsSlipGraph[2][1] must be less than or equal to mFrictionVsSlipGraph[1][1]");
+
+ mTires[id]=tire;
+ mTires[id].mRecipLongitudinalStiffnessPerUnitGravity=1.0f/mTires[id].mLongitudinalStiffnessPerUnitGravity;
+ mTires[id].mFrictionVsSlipGraphRecipx1Minusx0=1.0f/(mTires[id].mFrictionVsSlipGraph[1][0]-mTires[id].mFrictionVsSlipGraph[0][0]);
+ mTires[id].mFrictionVsSlipGraphRecipx2Minusx1=1.0f/(mTires[id].mFrictionVsSlipGraph[2][0]-mTires[id].mFrictionVsSlipGraph[1][0]);
+}
+
+/////////////////////////////
+
+void PxVehicleWheels4SimData::setSuspTravelDirection(const PxU32 id, const PxVec3& dir)
+{
+ PX_CHECK_AND_RETURN(id<4, "Illegal suspension id");
+ PX_CHECK_AND_RETURN(dir.magnitude()>0.999f && dir.magnitude()<1.0001f, "Suspension travel dir must be unit vector");
+
+ mSuspDownwardTravelDirections[id]=dir;
+}
+
+/////////////////////////////
+
+void PxVehicleWheels4SimData::setSuspForceAppPointOffset(const PxU32 id, const PxVec3& offset)
+{
+ PX_CHECK_AND_RETURN(id<4, "Illegal suspension id");
+ PX_CHECK_AND_RETURN(offset.magnitude()>0, "Susp force app point must be offset from centre of mass");
+
+ mSuspForceAppPointOffsets[id]=offset;
+}
+
+/////////////////////////////
+
+void PxVehicleWheels4SimData::setTireForceAppPointOffset(const PxU32 id, const PxVec3& offset)
+{
+ PX_CHECK_AND_RETURN(id<4, "Illegal tire id");
+ PX_CHECK_AND_RETURN(offset.magnitude()>0, "Tire force app point must be offset from centre of mass");
+
+ mTireForceAppPointOffsets[id]=offset;
+}
+
+/////////////////////////////
+
+void PxVehicleWheels4SimData::setWheelCentreOffset(const PxU32 id, const PxVec3& offset)
+{
+ PX_CHECK_AND_RETURN(id<4, "Illegal wheel id");
+ PX_CHECK_AND_RETURN(offset.magnitude()>0, "Tire force app point must be offset from centre of mass");
+
+ mWheelCentreOffsets[id]=offset;
+}
+
+/////////////////////////////
+
+void PxVehicleWheels4SimData::setWheelShapeMapping(const PxU32 id, const PxI32 shapeId)
+{
+ PX_CHECK_AND_RETURN(id<4, "Illegal wheel id");
+ PX_CHECK_AND_RETURN((-1==shapeId) || (PxU32(shapeId) < PX_MAX_U8), "Illegal shapeId: must be -1 or less than PX_MAX_U8");
+ mWheelShapeMap[id] = Ps::to8(-1!=shapeId ? shapeId : PX_MAX_U8);
+}
+
+/////////////////////////////
+
+void PxVehicleWheels4SimData::setSceneQueryFilterData(const PxU32 id, const PxFilterData& sqFilterData)
+{
+ PX_CHECK_AND_RETURN(id<4, "Illegal wheel id");
+ mSqFilterData[id]=sqFilterData;
+}
+
+
+} //namespace physx
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspWheelTire4.h b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspWheelTire4.h
new file mode 100644
index 00000000..5f289ce5
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleSuspWheelTire4.h
@@ -0,0 +1,393 @@
+// 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 PX_VEHICLE_SUSPWHEELTIRE_H
+#define PX_VEHICLE_SUSPWHEELTIRE_H
+/** \addtogroup vehicle
+ @{
+*/
+
+#include "foundation/PxSimpleTypes.h"
+#include "foundation/PxVec3.h"
+#include "foundation/PxVec4.h"
+#include "foundation/PxTransform.h"
+#include "foundation/PxIO.h"
+#include "PxVehicleComponents.h"
+#include "PxBatchQueryDesc.h"
+#include "PxGeometryHelpers.h"
+
+#if !PX_DOXYGEN
+namespace physx
+{
+#endif
+
+class PxVehicleConstraintShader;
+class PxMaterial;
+class PxShape;
+
+
+
+class PxVehicleWheels4SimData
+{
+//= ATTENTION! =====================================================================================
+// Changing the data layout of this class breaks the binary serialization format. See comments for
+// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData
+// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION
+// accordingly.
+//==================================================================================================
+public:
+
+ friend class PxVehicleUpdate;
+
+ PxVehicleWheels4SimData();
+
+ bool isValid(const PxU32 id) const;
+
+ static void getBinaryMetaData(PxOutputStream& stream);
+
+public:
+
+ PX_FORCE_INLINE const PxVehicleSuspensionData& getSuspensionData(const PxU32 id) const {return mSuspensions[id];}
+ PX_FORCE_INLINE const PxVehicleWheelData& getWheelData(const PxU32 id) const {return mWheels[id];}
+ PX_FORCE_INLINE const PxVehicleTireData& getTireData(const PxU32 id) const {return mTires[id];}
+ PX_FORCE_INLINE const PxVec3& getSuspTravelDirection(const PxU32 id) const {return mSuspDownwardTravelDirections[id];}
+ PX_FORCE_INLINE const PxVec3& getSuspForceAppPointOffset(const PxU32 id) const {return mSuspForceAppPointOffsets[id];}
+ PX_FORCE_INLINE const PxVec3& getTireForceAppPointOffset(const PxU32 id) const {return mTireForceAppPointOffsets[id];}
+ PX_FORCE_INLINE const PxVec3& getWheelCentreOffset(const PxU32 id) const {return mWheelCentreOffsets[id];}
+ PX_FORCE_INLINE PxI32 getWheelShapeMapping(const PxU32 id) const {return (PX_MAX_U8 != mWheelShapeMap[id]) ? mWheelShapeMap[id] : -1;}
+ PX_FORCE_INLINE const PxFilterData& getSceneQueryFilterData(const PxU32 id) const {return mSqFilterData[id];}
+ PX_FORCE_INLINE const PxReal* getTireRestLoadsArray() const {return mTireRestLoads;}
+ PX_FORCE_INLINE const PxReal* getRecipTireRestLoadsArray() const {return mRecipTireRestLoads;}
+
+ void setSuspensionData (const PxU32 id, const PxVehicleSuspensionData& susp);
+ void setWheelData (const PxU32 id, const PxVehicleWheelData& susp);
+ void setTireData (const PxU32 id, const PxVehicleTireData& tire);
+ void setSuspTravelDirection (const PxU32 id, const PxVec3& dir);
+ void setSuspForceAppPointOffset (const PxU32 id, const PxVec3& offset);
+ void setTireForceAppPointOffset (const PxU32 id, const PxVec3& offset);
+ void setWheelCentreOffset (const PxU32 id, const PxVec3& offset);
+ void setWheelShapeMapping (const PxU32 id, const PxI32 shapeId);
+ void setSceneQueryFilterData (const PxU32 id, const PxFilterData& sqFilterData);
+
+private:
+
+ /**
+ \brief Suspension simulation data
+ @see setSuspensionData, getSuspensionData
+ */
+ PxVehicleSuspensionData mSuspensions[4];
+
+ /**
+ \brief Wheel simulation data
+ @see setWheelData, getWheelData
+ */
+ PxVehicleWheelData mWheels[4];
+
+ /**
+ \brief Tire simulation data
+ @see setTireData, getTireData
+ */
+ PxVehicleTireData mTires[4];
+
+ /**
+ \brief Direction of suspension travel, pointing downwards.
+ */
+ PxVec3 mSuspDownwardTravelDirections[4];
+
+ /**
+ \brief Application point of suspension force specified as an offset from the rigid body centre of mass.
+ */
+ PxVec3 mSuspForceAppPointOffsets[4]; //Offset from cm
+
+ /**
+ \brief Application point of tire forces specified as an offset from the rigid body centre of mass.
+ */
+ PxVec3 mTireForceAppPointOffsets[4]; //Offset from cm
+
+ /**
+ \brief Position of wheel center specified as an offset from the rigid body centre of mass.
+ */
+ PxVec3 mWheelCentreOffsets[4]; //Offset from cm
+
+ /**
+ \brief Normalized tire load on each tire (load/rest load) at zero suspension jounce under gravity.
+ */
+ PxReal mTireRestLoads[4];
+
+ /**
+ \brief Reciprocal normalized tire load on each tire at zero suspension jounce under gravity.
+ */
+ PxReal mRecipTireRestLoads[4];
+
+ /**
+ \brief Scene query filter data used by each suspension line.
+ Anything relating to the actor belongs in PxVehicleWheels.
+ */
+ PxFilterData mSqFilterData[4];
+
+ /**
+ \brief Mapping between wheel id and shape id.
+ The PxShape that corresponds to the ith wheel can be found with
+ If mWheelShapeMap[i]<0 then the wheel has no corresponding shape.
+ Otherwise, the shape corresponds to:
+ PxShape* shapeBuffer[1];
+ mActor->getShapes(shapeBuffer,1,mWheelShapeMap[i]);
+ Anything relating to the actor belongs in PxVehicleWheels.
+ */
+ PxU8 mWheelShapeMap[4];
+
+ PxU32 mPad[3];
+};
+PX_COMPILE_TIME_ASSERT(0 == (sizeof(PxVehicleWheels4SimData) & 15));
+
+class PxVehicleWheels4DynData
+{
+//= ATTENTION! =====================================================================================
+// Changing the data layout of this class breaks the binary serialization format. See comments for
+// PX_BINARY_SERIAL_VERSION. If a modification is required, please adjust the getBinaryMetaData
+// function. If the modification is made on a custom branch, please change PX_BINARY_SERIAL_VERSION
+// accordingly.
+//==================================================================================================
+public:
+
+ friend class PxVehicleUpdate;
+
+ PxVehicleWheels4DynData()
+ : mRaycastResults(NULL),
+ mSweepResults(NULL)
+ {
+ setToRestState();
+ }
+ ~PxVehicleWheels4DynData()
+ {
+ }
+
+ bool isValid() const {return true;}
+
+ static void getBinaryMetaData(PxOutputStream& stream);
+
+ void setToRestState()
+ {
+ for(PxU32 i=0;i<4;i++)
+ {
+ mWheelSpeeds[i]=0.0f;
+ mCorrectedWheelSpeeds[i]=0.0f;
+ mWheelRotationAngles[i]=0.0f;
+ mTireLowForwardSpeedTimers[i]=0.0f;
+ mTireLowSideSpeedTimers[i]=0.0f;
+ mJounces[i] = PX_MAX_F32;
+ }
+ PxMemZero(mQueryOrCachedHitResults, sizeof(SuspLineSweep));
+
+ mRaycastResults = NULL;
+ mSweepResults = NULL;
+ mHasCachedRaycastHitPlane = false;
+ }
+
+ void setInternalDynamicsToZero()
+ {
+ for(PxU32 i=0;i<4;i++)
+ {
+ mWheelSpeeds[i] = 0.0f;
+ mCorrectedWheelSpeeds[i] = 0.0f;
+ mJounces[i] = PX_MAX_F32; //Ensure that the jounce speed is zero when the car wakes up again.
+ }
+ }
+
+ /**
+ \brief Rotation speeds of wheels
+ @see PxVehicle4WSetToRestState, PxVehicle4WGetWheelRotationSpeed, PxVehicle4WGetEngineRotationSpeed
+ */
+ PxReal mWheelSpeeds[4];
+
+ /**
+ \brief Rotation speeds of wheels used to update the wheel rotation angles.
+ */
+ PxReal mCorrectedWheelSpeeds[4];
+
+ /**
+ \brief Reported rotation angle about rolling axis.
+ @see PxVehicle4WSetToRestState, PxVehicle4WGetWheelRotationAngle
+ */
+ PxReal mWheelRotationAngles[4];
+
+ /**
+ \brief Timers used to trigger sticky friction to hold the car perfectly at rest.
+ \note Used only internally.
+ */
+ PxReal mTireLowForwardSpeedTimers[4];
+
+ /**
+ \brief Timers used to trigger sticky friction to hold the car perfectly at rest.
+ \note Used only internally.
+ */
+ PxReal mTireLowSideSpeedTimers[4];
+
+ /**
+ \brief Previous suspension jounce.
+ \note Used only internally to compute the jounce speed by comparing cached jounce and latest jounce.
+ */
+ PxReal mJounces[4];
+
+ struct SuspLineSweep
+ {
+ /**
+ \brief Geometry suspension line sweep used in most recent scene query.
+ @see PxVehicleSuspensionSweeps
+ */
+ PxGeometryHolder mGometries[4];
+
+ /**
+ \brief Start poses of suspension line sweep used in most recent scene query.
+ @see PxVehicleSuspensionSweeps
+ */
+ PxTransform mStartPose[4];
+
+ /**
+ \brief Directions of suspension line sweeps used in most recent scene query.
+ @see PxVehicleSuspensionSweeps
+ */
+ PxVec3 mDirs[4];
+
+ /**
+ \brief Lengths of suspension line sweeps used in most recent scene query.
+ @see PxVehicleSuspensionSweeps
+ */
+ PxReal mLengths[4];
+ };
+
+ struct SuspLineRaycast
+ {
+ /**
+ \brief Start point of suspension line raycasts used in most recent scene query.
+ @see PxVehicleSuspensionRaycasts
+ */
+ PxVec3 mStarts[4];
+
+ /**
+ \brief Directions of suspension line raycasts used in most recent scene query.
+ @see PxVehicleSuspensionRaycasts
+ */
+ PxVec3 mDirs[4];
+
+ /**
+ \brief Lengths of suspension line raycasts used in most recent scene query.
+ @see PxVehicleSuspensionRaycasts
+ */
+ PxReal mLengths[4];
+
+ PxU32 mPad[16];
+ };
+
+ struct CachedSuspLineSceneQuerytHitResult
+ {
+ /**
+ \brief Cached raycast hit planes. These are the planes found from the last scene queries.
+ @see PxVehicleSuspensionRaycasts, PxVehicleSuspensionSweeps
+ */
+ PxVec4 mPlanes[4];
+
+ /**
+ \brief Cached friction.
+ @see PxVehicleSuspensionRaycasts, PxVehicleSuspensionSweeps
+ */
+ PxF32 mFrictionMultipliers[4];
+
+ /**
+ \brief Cached raycast hit distance. These are the hit distances found from the last scene queries.
+ */
+ PxF32 mDistances[4];
+
+ /**
+ \brief Cached raycast hit counts. These are the hit counts found from the last scene queries.
+ @see PxVehicleSuspensionRaycasts, , PxVehicleSuspensionSweeps
+ */
+ PxU16 mCounts[4];
+
+ /**
+ \brief Store 0 if cached results are from raycasts, store 1 if cached results are from sweeps.
+ */
+ PxU16 mQueryTypes[4];
+
+ PxU32 mPad1[16];
+ };
+
+ /**
+ \brief We either have a fresh raycast that was just performed or a cached raycast result that will be used if no raycast was just performed.
+ */
+ PxU8 mQueryOrCachedHitResults[sizeof(SuspLineSweep)];
+
+ /**
+ \brief Used only internally.
+ */
+ void setVehicleConstraintShader(PxVehicleConstraintShader* shader) {mVehicleConstraints=shader;}
+ PxVehicleConstraintShader& getVehicletConstraintShader() const {return *mVehicleConstraints;}
+
+private:
+
+ //Susp limits and sticky tire friction for all wheels.
+ PxVehicleConstraintShader* mVehicleConstraints;
+
+public:
+
+ /**
+ \brief Set by PxVehicleSuspensionRaycasts
+ @see PxVehicleSuspensionRaycasts
+ */
+ const PxRaycastQueryResult* mRaycastResults;
+
+ /**
+ \brief Set by PxVehicleSuspensionSweeps
+ @see PxVehicleSuspensionSweeps
+ */
+ const PxSweepQueryResult* mSweepResults;
+
+ /**
+ \brief Set true if a raycast hit plane has been recorded and cached.
+ This requires a raycast to be performed and then followed by PxVehicleUpdates
+ at least once. Reset to false in setToRestState.
+ */
+ bool mHasCachedRaycastHitPlane;
+
+
+#if PX_P64_FAMILY
+ PxU32 mPad[12];
+#endif
+};
+PX_COMPILE_TIME_ASSERT(0==(sizeof(PxVehicleWheels4DynData) & 15));
+PX_COMPILE_TIME_ASSERT((0 == (sizeof(PxVehicleWheels4DynData::SuspLineSweep) & 0x0f)));
+PX_COMPILE_TIME_ASSERT(sizeof(PxVehicleWheels4DynData::SuspLineRaycast) <= sizeof(PxVehicleWheels4DynData::SuspLineSweep));
+PX_COMPILE_TIME_ASSERT(sizeof(PxVehicleWheels4DynData::CachedSuspLineSceneQuerytHitResult) <= sizeof(PxVehicleWheels4DynData::SuspLineSweep));
+
+#if !PX_DOXYGEN
+} // namespace physx
+#endif
+
+/** @} */
+#endif //PX_VEHICLE_SUSPWHEELTIRE_H
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleTireFriction.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleTireFriction.cpp
new file mode 100644
index 00000000..2622a698
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleTireFriction.cpp
@@ -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.
+
+#include "foundation/PxMemory.h"
+#include "PxVehicleTireFriction.h"
+#include "CmPhysXCommon.h"
+#include "PsFoundation.h"
+
+namespace physx
+{
+
+PX_FORCE_INLINE PxU32 computeByteSize(const PxU32 maxNbTireTypes, const PxU32 maxNbSurfaceTypes)
+{
+ PxU32 byteSize = ((sizeof(PxU32)*(maxNbTireTypes*maxNbSurfaceTypes) + 15) & ~15);
+ byteSize += ((sizeof(PxMaterial*)*maxNbSurfaceTypes + 15) & ~15);
+ byteSize += ((sizeof(PxVehicleDrivableSurfaceType)*maxNbSurfaceTypes + 15) & ~15);
+ byteSize += ((sizeof(PxVehicleDrivableSurfaceToTireFrictionPairs) + 15) & ~ 15);
+ return byteSize;
+}
+
+PxVehicleDrivableSurfaceToTireFrictionPairs* PxVehicleDrivableSurfaceToTireFrictionPairs::allocate
+(const PxU32 maxNbTireTypes, const PxU32 maxNbSurfaceTypes)
+{
+ PX_CHECK_AND_RETURN_VAL(maxNbSurfaceTypes <= eMAX_NB_SURFACE_TYPES, "maxNbSurfaceTypes must be less than eMAX_NB_SURFACE_TYPES", NULL);
+
+ PxU32 byteSize = computeByteSize(maxNbTireTypes, maxNbSurfaceTypes);
+ PxU8* ptr = static_cast<PxU8*>(PX_ALLOC(byteSize, "PxVehicleDrivableSurfaceToTireFrictionPairs"));
+ PxMemSet(ptr, 0, byteSize);
+ PxVehicleDrivableSurfaceToTireFrictionPairs* pairs = reinterpret_cast<PxVehicleDrivableSurfaceToTireFrictionPairs*>(ptr);
+
+ pairs->mPairs = NULL;
+ pairs->mDrivableSurfaceMaterials = NULL;
+ pairs->mDrivableSurfaceTypes = NULL;
+ pairs->mNbTireTypes = 0;
+ pairs->mMaxNbTireTypes = maxNbTireTypes;
+ pairs->mNbSurfaceTypes = 0;
+ pairs->mMaxNbSurfaceTypes = maxNbSurfaceTypes;
+
+ return pairs;
+}
+
+void PxVehicleDrivableSurfaceToTireFrictionPairs::setup
+(const PxU32 numTireTypes, const PxU32 numSurfaceTypes, const PxMaterial** drivableSurfaceMaterials, const PxVehicleDrivableSurfaceType* drivableSurfaceTypes)
+{
+ PX_CHECK_AND_RETURN(numTireTypes <= mMaxNbTireTypes, "numTireTypes must be less than mMaxNumSurfaceTypes");
+ PX_CHECK_AND_RETURN(numSurfaceTypes <= mMaxNbSurfaceTypes, "numSurfaceTypes must be less than mMaxNumSurfaceTypes");
+
+ PxU8* ptr = reinterpret_cast<PxU8*>(this);
+
+ const PxU32 maxNbTireTypes = mMaxNbTireTypes;
+ const PxU32 maxNbSurfaceTypes = mMaxNbSurfaceTypes;
+ PxU32 byteSize = computeByteSize(mMaxNbTireTypes, mMaxNbSurfaceTypes);
+ PxMemSet(ptr, 0, byteSize);
+ mMaxNbTireTypes = maxNbTireTypes;
+ mMaxNbSurfaceTypes = maxNbSurfaceTypes;
+
+ PxVehicleDrivableSurfaceToTireFrictionPairs* pairs = reinterpret_cast<PxVehicleDrivableSurfaceToTireFrictionPairs*>(ptr);
+ ptr += ((sizeof(PxVehicleDrivableSurfaceToTireFrictionPairs) + 15) & ~ 15);
+
+ mPairs = reinterpret_cast<PxReal*>(ptr);
+ ptr += ((sizeof(PxU32)*(numTireTypes*numSurfaceTypes) + 15) & ~15);
+ mDrivableSurfaceMaterials = reinterpret_cast<const PxMaterial**>(ptr);
+ ptr += ((sizeof(PxMaterial*)*numSurfaceTypes + 15) & ~15);
+ mDrivableSurfaceTypes = reinterpret_cast<PxVehicleDrivableSurfaceType*>(ptr);
+ ptr += ((sizeof(PxVehicleDrivableSurfaceType)*numSurfaceTypes +15) & ~15);
+
+ for(PxU32 i=0;i<numSurfaceTypes;i++)
+ {
+ mDrivableSurfaceTypes[i] = drivableSurfaceTypes[i];
+ mDrivableSurfaceMaterials[i] = drivableSurfaceMaterials[i];
+ }
+ for(PxU32 i=0;i<numTireTypes*numSurfaceTypes;i++)
+ {
+ mPairs[i]=1.0f;
+ }
+
+ pairs->mNbTireTypes=numTireTypes;
+ pairs->mNbSurfaceTypes=numSurfaceTypes;
+}
+
+void PxVehicleDrivableSurfaceToTireFrictionPairs::release()
+{
+ PX_FREE(this);
+}
+
+void PxVehicleDrivableSurfaceToTireFrictionPairs::setTypePairFriction(const PxU32 surfaceType, const PxU32 tireType, const PxReal value)
+{
+ PX_CHECK_AND_RETURN(tireType<mNbTireTypes, "Invalid tireType");
+ PX_CHECK_AND_RETURN(surfaceType<mNbSurfaceTypes, "Invalid surfaceType");
+
+ *(mPairs + mNbTireTypes*surfaceType + tireType) = value;
+}
+
+PxReal PxVehicleDrivableSurfaceToTireFrictionPairs::getTypePairFriction(const PxU32 surfaceType, const PxU32 tireType) const
+{
+ PX_CHECK_AND_RETURN_VAL(tireType<mNbTireTypes, "Invalid tireType", 0.0f);
+ PX_CHECK_AND_RETURN_VAL(surfaceType<mNbSurfaceTypes, "Invalid surfaceType", 0.0f);
+
+ return *(mPairs + mNbTireTypes*surfaceType + tireType);
+}
+
+
+
+
+}//physx
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleUpdate.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleUpdate.cpp
new file mode 100644
index 00000000..56758d8e
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleUpdate.cpp
@@ -0,0 +1,7641 @@
+// 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 "foundation/PxProfiler.h"
+#include "foundation/PxQuat.h"
+#include "PxVehicleUpdate.h"
+#include "PxVehicleSuspWheelTire4.h"
+#include "PxVehicleDrive4W.h"
+#include "PxVehicleDriveNW.h"
+#include "PxVehicleDriveTank.h"
+#include "PxVehicleNoDrive.h"
+#include "PxVehicleSuspLimitConstraintShader.h"
+#include "PxVehicleDefaults.h"
+#include "PxVehicleUtil.h"
+#include "PxVehicleUtilTelemetry.h"
+#include "PxVehicleLinearMath.h"
+#include "PxShape.h"
+#include "PxRigidDynamic.h"
+#include "PxBatchQuery.h"
+#include "PxMaterial.h"
+#include "PxTolerancesScale.h"
+#include "PxRigidBodyExt.h"
+#include "PsFoundation.h"
+#include "PsUtilities.h"
+#include "CmBitMap.h"
+#include "CmUtils.h"
+#include "PxContactModifyCallback.h"
+#include "PsFPU.h"
+
+using namespace physx;
+using namespace Cm;
+
+
+//TODO: lsd - handle case where wheels are spinning in different directions.
+//TODO: ackermann - use faster approximate functions for PxTan/PxATan because the results don't need to be too accurate here.
+//TODO: tire lat slip - do we really use PxAbs(vz) as denominator, that's not in the paper?
+//TODO: toe vs jounce table.
+//TODO: pneumatic trail.
+//TODO: we probably need to have a graphics jounce and a physics jounce and
+//TODO: expose sticky friction values in api.
+//TODO: blend the graphics jounce towards the physics jounce to avoid graphical pops at kerbs etc.
+//TODO: better graph of friction vs slip. Need to account for negative slip and positive slip differences.
+
+namespace physx
+{
+
+////////////////////////////////////////////////////////////////////////////
+//Implementation of public api function PxVehicleSetBasisVectors
+////////////////////////////////////////////////////////////////////////////
+
+PxVec3 gRightDefault(1.f,0,0);
+PxVec3 gUpDefault(0,1.f,0);
+PxVec3 gForwardDefault(0,0,1.f);
+PxVec3 gRight;
+PxVec3 gUp;
+PxVec3 gForward;
+
+void PxVehicleSetBasisVectors(const PxVec3& up, const PxVec3& forward)
+{
+ gRight=up.cross(forward);
+ gUp=up;
+ gForward=forward;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Implementation of public api function PxVehicleSetUpdateMode
+////////////////////////////////////////////////////////////////////////////
+
+const bool gApplyForcesDefault = false;
+bool gApplyForces;
+
+void PxVehicleSetUpdateMode(PxVehicleUpdateMode::Enum vehicleUpdateMode)
+{
+ switch(vehicleUpdateMode)
+ {
+ case PxVehicleUpdateMode::eVELOCITY_CHANGE:
+ gApplyForces=false;
+ break;
+ case PxVehicleUpdateMode::eACCELERATION:
+ gApplyForces=true;
+ break;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Implementation of public api function PxVehicleSetSweepHitRejectionAngles
+////////////////////////////////////////////////////////////////////////////
+
+const PxF32 gPointRejectAngleThresholdDefault = 0.707f; //PxCos(PxPi*0.25f);
+const PxF32 gNormalRejectAngleThresholdDefault = 0.707f; //PxCos(PxPi*0.25f);
+PxF32 gPointRejectAngleThreshold;
+PxF32 gNormalRejectAngleThreshold;
+
+void PxVehicleSetSweepHitRejectionAngles(const PxF32 pointRejectAngle, const PxF32 normalRejectAngle)
+{
+ PX_CHECK_AND_RETURN(pointRejectAngle > 0.0f && pointRejectAngle < PxPi, "PxVehicleSetSweepHitRejectionAngles - pointRejectAngle must be in range (0, Pi)");
+ PX_CHECK_AND_RETURN(normalRejectAngle > 0.0f && normalRejectAngle < PxPi, "PxVehicleSetSweepHitRejectionAngles - normalRejectAngle must be in range (0, Pi)");
+ gPointRejectAngleThreshold = PxCos(pointRejectAngle);
+ gNormalRejectAngleThreshold = PxCos(normalRejectAngle);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Implementation of public api function PxVehicleSetSweepHitRejectionAngles
+////////////////////////////////////////////////////////////////////////////
+
+const PxF32 gMaxHitActorAccelerationDefault = PX_MAX_REAL;
+PxF32 gMaxHitActorAcceleration;
+
+void PxVehicleSetMaxHitActorAcceleration(const PxF32 maxHitActorAcceleration)
+{
+ PX_CHECK_AND_RETURN(maxHitActorAcceleration >= 0.0f, "PxVehicleSetMaxHitActorAcceleration - maxHitActorAcceleration must be greater than or equal to zero");
+ gMaxHitActorAcceleration = maxHitActorAcceleration;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Set all defaults from PxVehicleInitSDK
+////////////////////////////////////////////////////////////////////////////
+
+void setVehicleDefaults()
+{
+ gRight = gRightDefault;
+ gUp = gUpDefault;
+ gForward = gForwardDefault;
+
+ gApplyForces = gApplyForcesDefault;
+
+ gPointRejectAngleThreshold = gPointRejectAngleThresholdDefault;
+ gNormalRejectAngleThreshold = gNormalRejectAngleThresholdDefault;
+
+ gMaxHitActorAcceleration = gMaxHitActorAccelerationDefault;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Called from PxVehicleInitSDK/PxCloseVehicleSDK
+////////////////////////////////////////////////////////////////////////////
+
+//***********************
+
+PxF32 gThresholdForwardSpeedForWheelAngleIntegration=0;
+PxF32 gRecipThresholdForwardSpeedForWheelAngleIntegration=0;
+PxF32 gMinLatSpeedForTireModel=0;
+PxF32 gStickyTireFrictionThresholdSpeed=0;
+PxF32 gToleranceScaleLength=0;
+PxF32 gMinimumSlipThreshold=0;
+
+void setVehicleToleranceScale(const PxTolerancesScale& ts)
+{
+ gThresholdForwardSpeedForWheelAngleIntegration=5.0f*ts.length;
+ gRecipThresholdForwardSpeedForWheelAngleIntegration=1.0f/gThresholdForwardSpeedForWheelAngleIntegration;
+
+ gMinLatSpeedForTireModel=1.0f*ts.length;
+
+ gStickyTireFrictionThresholdSpeed=0.2f*ts.length;
+
+ gToleranceScaleLength=ts.length;
+
+ gMinimumSlipThreshold = 1e-5f;
+}
+
+void resetVehicleToleranceScale()
+{
+ gThresholdForwardSpeedForWheelAngleIntegration=0;
+ gRecipThresholdForwardSpeedForWheelAngleIntegration=0;
+
+ gMinLatSpeedForTireModel=0;
+
+ gStickyTireFrictionThresholdSpeed=0;
+
+ gToleranceScaleLength=0;
+
+ gMinimumSlipThreshold=0;
+}
+
+//***********************
+
+const PxSerializationRegistry* gSerializationRegistry=NULL;
+
+void setSerializationRegistryPtr(const PxSerializationRegistry* sr)
+{
+ gSerializationRegistry = sr;
+}
+
+const PxSerializationRegistry* resetSerializationRegistryPtr()
+{
+ const PxSerializationRegistry* tmp = gSerializationRegistry;
+ gSerializationRegistry = NULL;
+ return tmp;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Global values used to trigger and control sticky tire friction constraints.
+////////////////////////////////////////////////////////////////////////////
+
+const PxF32 gStickyTireFrictionForwardDamping=0.01f;
+const PxF32 gStickyTireFrictionSideDamping=0.1f;
+const PxF32 gLowForwardSpeedThresholdTime=1.0f;
+const PxF32 gLowSideSpeedThresholdTime=1.0f;
+
+////////////////////////////////////////////////////////////////////////////
+//Global values used to control max iteration count if estimate mode is chosen
+////////////////////////////////////////////////////////////////////////////
+
+const PxF32 gSolverTolerance = 1e-10f;
+
+////////////////////////////////////////////////////////////////////////////
+//Compute the sprung masses that satisfy the centre of mass and sprung mass coords.
+////////////////////////////////////////////////////////////////////////////
+
+#define DETERMINANT_THRESHOLD (1e-6f)
+
+void computeSprungMasses(const PxU32 numSprungMasses, const PxVec3* sprungMassCoordinates, const PxVec3& centreOfMass, const PxReal totalMass, const PxU32 gravityDirection, PxReal* sprungMasses)
+{
+#if PX_CHECKED
+ PX_CHECK_AND_RETURN(numSprungMasses > 0, "PxVehicleComputeSprungMasses: numSprungMasses must be greater than zero");
+ PX_CHECK_AND_RETURN(numSprungMasses <= PX_MAX_NB_WHEELS, "PxVehicleComputeSprungMasses: numSprungMasses must be less than or equal to 20");
+ for(PxU32 i=0;i<numSprungMasses;i++)
+ {
+ PX_CHECK_AND_RETURN(sprungMassCoordinates[i].isFinite(), "PxVehicleComputeSprungMasses: sprungMassCoordinates must all be valid coordinates");
+ }
+ PX_CHECK_AND_RETURN(totalMass > 0.0f, "PxVehicleComputeSprungMasses: totalMass must be greater than zero");
+ PX_CHECK_AND_RETURN(gravityDirection<=2, "PxVehicleComputeSprungMasses: gravityDirection must be 0 or 1 or 2");
+ PX_CHECK_AND_RETURN(sprungMasses, "PxVehicleComputeSprungMasses: sprungMasses must be a non-null pointer");
+#endif
+
+ if(1==numSprungMasses)
+ {
+ sprungMasses[0]=totalMass;
+ }
+ else if(2==numSprungMasses)
+ {
+ PxVec3 v=sprungMassCoordinates[0];
+ v[gravityDirection]=0;
+ PxVec3 w=sprungMassCoordinates[1]-sprungMassCoordinates[0];
+ w[gravityDirection]=0;
+ w.normalize();
+
+ PxVec3 cm=centreOfMass;
+ cm[gravityDirection]=0;
+ PxF32 t=w.dot(cm-v);
+ PxVec3 p=v+w*t;
+
+ PxVec3 x0=sprungMassCoordinates[0];
+ x0[gravityDirection]=0;
+ PxVec3 x1=sprungMassCoordinates[1];
+ x1[gravityDirection]=0;
+ const PxF32 r0=(x0-p).dot(w);
+ const PxF32 r1=(x1-p).dot(w);
+
+ PX_CHECK_AND_RETURN(PxAbs(r0-r1) > DETERMINANT_THRESHOLD, "PxVehicleComputeSprungMasses: Unable to determine sprung masses. Please check the values in sprungMassCoordinates.");
+
+ const PxF32 m0=totalMass*r1/(r1-r0);
+ const PxF32 m1=totalMass-m0;
+
+ sprungMasses[0]=m0;
+ sprungMasses[1]=m1;
+ }
+ else if(3==numSprungMasses)
+ {
+ const PxU32 d0=(gravityDirection+1)%3;
+ const PxU32 d1=(gravityDirection+2)%3;
+
+ MatrixNN A(3);
+ VectorN b(3);
+ A.set(0,0,sprungMassCoordinates[0][d0]);
+ A.set(0,1,sprungMassCoordinates[1][d0]);
+ A.set(0,2,sprungMassCoordinates[2][d0]);
+ A.set(1,0,sprungMassCoordinates[0][d1]);
+ A.set(1,1,sprungMassCoordinates[1][d1]);
+ A.set(1,2,sprungMassCoordinates[2][d1]);
+ A.set(2,0,1.f);
+ A.set(2,1,1.f);
+ A.set(2,2,1.f);
+ b[0]=totalMass*centreOfMass[d0];
+ b[1]=totalMass*centreOfMass[d1];
+ b[2]=totalMass;
+
+ VectorN result(3);
+ MatrixNNLUSolver solver;
+ solver.decomposeLU(A);
+ PX_CHECK_AND_RETURN(PxAbs(solver.getDet()) > DETERMINANT_THRESHOLD, "PxVehicleComputeSprungMasses: Unable to determine sprung masses. Please check the values in sprungMassCoordinates.");
+ solver.solve(b,result);
+
+ sprungMasses[0]=result[0];
+ sprungMasses[1]=result[1];
+ sprungMasses[2]=result[2];
+ }
+ else if(numSprungMasses>=4)
+ {
+ const PxU32 d0=(gravityDirection+1)%3;
+ const PxU32 d1=(gravityDirection+2)%3;
+
+ const PxF32 mbar = totalMass/(numSprungMasses*1.0f);
+
+ //See http://en.wikipedia.org/wiki/Lagrange_multiplier
+ //particularly the section on multiple constraints.
+
+ //3 Constraint equations.
+ //g0 = sum_ xi*mi=xcm
+ //g1 = sum_ zi*mi=zcm
+ //g2 = sum_ mi = totalMass
+ //Minimisation function to achieve solution with minimum mass variance.
+ //f = sum_ (mi - mave)^2
+ //Lagrange terms (N equations, N+3 unknowns)
+ //2*mi - xi*lambda0 - zi*lambda1 - 1*lambda2 = 2*mave
+
+ MatrixNN A(numSprungMasses+3);
+ VectorN b(numSprungMasses+3);
+
+ //g0, g1, g2
+ for(PxU32 i=0;i<numSprungMasses;i++)
+ {
+ A.set(0,i,sprungMassCoordinates[i][d0]); //g0
+ A.set(1,i,sprungMassCoordinates[i][d1]); //g1
+ A.set(2,i,1.0f); //g2
+ }
+ for(PxU32 i=numSprungMasses;i<numSprungMasses+3;i++)
+ {
+ A.set(0,i,0); //g0 independent of lambda0,lambda1,lambda2
+ A.set(1,i,0); //g1 independent of lambda0,lambda1,lambda2
+ A.set(2,i,0); //g2 independent of lambda0,lambda1,lambda2
+ }
+ b[0] = totalMass*(centreOfMass[d0]); //g0
+ b[1] = totalMass*(centreOfMass[d1]); //g1
+ b[2] = totalMass; //g2
+
+ //Lagrange terms.
+ for(PxU32 i=0;i<numSprungMasses;i++)
+ {
+ //Off-diagonal terms from the derivative of f
+ for(PxU32 j=0;j<numSprungMasses;j++)
+ {
+ A.set(i+3,j,0);
+ }
+ //Diagonal term from the derivative of f
+ A.set(i+3,i,2.f);
+
+ //Derivative of g
+ A.set(i+3,numSprungMasses+0,sprungMassCoordinates[i][d0]);
+ A.set(i+3,numSprungMasses+1,sprungMassCoordinates[i][d1]);
+ A.set(i+3,numSprungMasses+2,1.0f);
+
+ //rhs.
+ b[i+3] = 2*mbar;
+ }
+
+ //Solve Ax=b
+ VectorN result(numSprungMasses+3);
+ MatrixNNLUSolver solver;
+ solver.decomposeLU(A);
+ solver.solve(b,result);
+ PX_CHECK_AND_RETURN(PxAbs(solver.getDet()) > DETERMINANT_THRESHOLD, "PxVehicleComputeSprungMasses: Unable to determine sprung masses. Please check the values in sprungMassCoordinates.");
+
+ for(PxU32 i=0;i<numSprungMasses;i++)
+ {
+ sprungMasses[i]=result[i];
+ }
+ }
+
+#if PX_CHECKED
+ PxVec3 cm(0,0,0);
+ PxF32 m = 0;
+ for(PxU32 i=0;i<numSprungMasses;i++)
+ {
+ PX_CHECK_AND_RETURN(sprungMasses[i] >= 0, "PxVehicleComputeSprungMasses: Unable to determine sprung masses. Please check the values in sprungMassCoordinates.");
+ cm += sprungMassCoordinates[i]*sprungMasses[i];
+ m += sprungMasses[i];
+ }
+ cm *= (1.0f/totalMass);
+ PX_CHECK_AND_RETURN((PxAbs(totalMass - m)/totalMass) < 1e-3f, "PxVehicleComputeSprungMasses: Unable to determine sprung masses. Please check the values in sprungMassCoordinates.");
+ PxVec3 diff = cm - centreOfMass;
+ diff[gravityDirection]=0;
+ const PxF32 diffMag = diff.magnitude();
+ PX_CHECK_AND_RETURN(numSprungMasses <=2 || diffMag < 1e-3f, "PxVehicleComputeSprungMasses: Unable to determine sprung masses. Please check the values in sprungMassCoordinates.");
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Work out if all wheels are in the air.
+////////////////////////////////////////////////////////////////////////////
+
+bool PxVehicleIsInAir(const PxVehicleWheelQueryResult& vehWheelQueryResults)
+{
+ if(!vehWheelQueryResults.wheelQueryResults)
+ {
+ return true;
+ }
+
+ for(PxU32 i=0;i<vehWheelQueryResults.nbWheelQueryResults;i++)
+ {
+ if(!vehWheelQueryResults.wheelQueryResults[i].isInAir)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Reject wheel contact points
+////////////////////////////////////////////////////////////////////////////
+
+PxU32 PxVehicleModifyWheelContacts
+(const PxVehicleWheels& vehicle, const PxU32 wheelId,
+ const PxF32 wheelTangentVelocityMultiplier, const PxReal maxImpulse,
+ PxContactModifyPair& contactModifyPair)
+{
+ const bool rejectPoints = true;
+ const bool rejectNormals = true;
+
+ PxU32 numIgnoredContacts = 0;
+
+ const PxRigidDynamic* vehActor = vehicle.getRigidDynamicActor();
+
+ //Is the vehicle represented by actor[0] or actor[1]?
+ PxTransform vehActorTransform;
+ PxTransform vehWheelTransform;
+ PxF32 normalMultiplier;
+ PxF32 targetVelMultiplier;
+ bool isOtherDynamic = false;
+ if(contactModifyPair.actor[0] == vehActor)
+ {
+ normalMultiplier = 1.0f;
+ targetVelMultiplier = 1.0f;
+ vehActorTransform = contactModifyPair.actor[0]->getGlobalPose();
+ vehWheelTransform = contactModifyPair.transform[0];
+ isOtherDynamic = contactModifyPair.actor[1] && contactModifyPair.actor[1]->is<PxRigidDynamic>();
+ }
+ else
+ {
+ PX_ASSERT(contactModifyPair.actor[1] == vehActor);
+ normalMultiplier = -1.0f;
+ targetVelMultiplier = -1.0f;
+ vehActorTransform = contactModifyPair.actor[1]->getGlobalPose();
+ vehWheelTransform = contactModifyPair.transform[1];
+ isOtherDynamic = contactModifyPair.actor[0] && contactModifyPair.actor[0]->is<PxRigidDynamic>();
+ }
+
+ //Compute the "right" vector of the transform.
+ const PxVec3 right = vehWheelTransform.q.rotate(gRight);
+
+ //The wheel transform includes rotation about the rolling axis.
+ //We want to compute the wheel transform at zero wheel rotation angle.
+ PxTransform correctedWheelShapeTransform;
+ {
+ const PxF32 wheelRotationAngle = vehicle.mWheelsDynData.getWheelRotationAngle(wheelId);
+ const PxQuat wheelRotateQuat(-wheelRotationAngle, right);
+ correctedWheelShapeTransform = PxTransform(vehWheelTransform.p, wheelRotateQuat*vehWheelTransform.q);
+ }
+
+ //Construct a plane for the wheel
+ //n.p + d = 0
+ PxPlane wheelPlane;
+ wheelPlane.n = right;
+ wheelPlane.d = -(right.dot(correctedWheelShapeTransform.p));
+
+ //Compute the suspension travel vector.
+ const PxVec3 suspTravelDir = correctedWheelShapeTransform.rotate(vehicle.mWheelsSimData.getSuspTravelDirection(wheelId));
+
+ //Get the wheel centre.
+ const PxVec3 wheelCentre = correctedWheelShapeTransform.p;
+
+ //Test each point.
+ PxContactSet& contactSet = contactModifyPair.contacts;
+ const PxU32 numContacts = contactSet.size();
+ for(PxU32 i = 0; i < numContacts; i++)
+ {
+ //Get the next contact point to analyse.
+ const PxVec3& contactPoint = contactSet.getPoint(i);
+ bool ignorePoint = false;
+
+ //Project the contact point on to the wheel plane.
+ const PxF32 distanceToPlane = wheelPlane.n.dot(contactPoint) + wheelPlane.d;
+ const PxVec3 contactPointOnPlane = contactPoint - wheelPlane.n*distanceToPlane;
+
+ //Construct a vector from the wheel centre to the contact point on the plane.
+ PxVec3 dir = contactPointOnPlane - wheelCentre;
+ const PxF32 effectiveRadius = dir.normalize();
+
+ if(!ignorePoint && rejectPoints)
+ {
+ //Work out the dot product of the suspension direction and the direction from wheel centre to contact point.
+ const PxF32 dotProduct = dir.dot(suspTravelDir);
+ if (dotProduct > gPointRejectAngleThreshold)
+ {
+ ignorePoint = true;
+ numIgnoredContacts++;
+ contactSet.ignore(i);
+ }
+ }
+
+ //Ignore contact normals that are near the raycast direction.
+ if(!ignorePoint && rejectNormals)
+ {
+ const PxVec3& contactNormal = contactSet.getNormal(i) * normalMultiplier;
+ const PxF32 dotProduct = -(contactNormal.dot(suspTravelDir));
+ if(dotProduct > gNormalRejectAngleThreshold)
+ {
+ ignorePoint = true;
+ numIgnoredContacts++;
+ contactSet.ignore(i);
+ }
+ }
+
+ //For points that remain we want to modify the contact speed to account for the spinning wheel.
+ //We also want the applied impulse to go through the suspension geometry so we set the contact point to be the suspension force
+ //application point.
+ if(!ignorePoint)
+ {
+ //Compute the tangent velocity.
+ //Retain only the component that lies perpendicular to the contact normal.
+ const PxF32 wheelRotationSpeed = vehicle.mWheelsDynData.getWheelRotationSpeed(wheelId);
+ const PxVec3 tangentVelocityDir = right.cross(dir);
+ PxVec3 tangentVelocity = tangentVelocityDir*(effectiveRadius*wheelRotationSpeed);
+ tangentVelocity -= contactSet.getNormal(i)*(tangentVelocity.dot(contactSet.getNormal(i)));
+
+ //We want to add velocity in the opposite direction to the tangent velocity.
+ const PxVec3 targetTangentVelocity = -wheelTangentVelocityMultiplier*tangentVelocity;
+
+ //Relative velocity is computed from actor0 - actor1
+ //If vehicle is actor 0 we want to add to the target velocity: targetVelocity = [(vel0 + targetTangentVelocity) - vel1] = vel0 - vel1 + targetTangentVelocity
+ //If vehicle is actor 1 we want to subtract from the target velocity: targetVelocity = [vel0 - (vel1 + targetTangentVelocity)] = vel0 - vel1 - targetTangentVelocity
+ const PxVec3 targetVelocity = targetTangentVelocity*targetVelMultiplier;
+
+ //Add the target velocity.
+ contactSet.setTargetVelocity(i, targetVelocity);
+
+ //Set the max impulse that can be applied.
+ //Only apply this if the wheel has hit a dynamic.
+ if (isOtherDynamic)
+ {
+ contactSet.setMaxImpulse(i, maxImpulse);
+ }
+
+ //Set the contact point to be the suspension force application point because all forces applied through the wheel go through the suspension geometry.
+ const PxVec3 suspAppPoint = vehActorTransform.transform(vehActor->getCMassLocalPose().p + vehicle.mWheelsSimData.getSuspForceAppPointOffset(wheelId));
+ contactSet.setPoint(i, suspAppPoint);
+ }
+ }
+
+ return numIgnoredContacts;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Enable a 4W vehicle in either tadpole or delta configuration.
+////////////////////////////////////////////////////////////////////////////
+
+void computeDirection(PxU32& rightDirection, PxU32& upDirection)
+{
+ //Work out the up and right vectors.
+ rightDirection = 0xffffffff;
+ if(gRight == PxVec3(1.f,0,0) || gRight == PxVec3(-1.f,0,0))
+ {
+ rightDirection = 0;
+ }
+ else if(gRight == PxVec3(0,1.f,0) || gRight == PxVec3(0,-1.f,0))
+ {
+ rightDirection = 1;
+ }
+ else if(gRight == PxVec3(0,0,1.f) || gRight == PxVec3(0,0,-1.f))
+ {
+ rightDirection = 2;
+ }
+ upDirection = 0xffffffff;
+ if(gUp== PxVec3(1.f,0,0) || gUp == PxVec3(-1.f,0,0))
+ {
+ upDirection = 0;
+ }
+ else if(gUp == PxVec3(0,1.f,0) || gUp == PxVec3(0,-1.f,0))
+ {
+ upDirection = 1;
+ }
+ else if(gUp == PxVec3(0,0,1.f) || gUp == PxVec3(0,0,-1.f))
+ {
+ upDirection = 2;
+ }
+}
+
+void enable3WMode(const PxU32 rightDirection, const PxU32 upDirection, const bool removeFrontWheel, PxVehicleWheelsSimData& wheelsSimData, PxVehicleWheelsDynData& wheelsDynData, PxVehicleDriveSimData4W& driveSimData)
+{
+ PX_ASSERT(rightDirection < 3);
+ PX_ASSERT(upDirection < 3);
+
+ const PxU32 wheelToRemove = removeFrontWheel ? PxVehicleDrive4WWheelOrder::eFRONT_LEFT : PxVehicleDrive4WWheelOrder::eREAR_LEFT;
+ const PxU32 wheelToModify = removeFrontWheel ? PxVehicleDrive4WWheelOrder::eFRONT_RIGHT : PxVehicleDrive4WWheelOrder::eREAR_RIGHT;
+
+ //Disable the wheel.
+ wheelsSimData.disableWheel(wheelToRemove);
+
+ //Make sure the wheel's corresponding PxShape does not get posed again.
+ wheelsSimData.setWheelShapeMapping(wheelToRemove, -1);
+
+ //Set the angular speed to 0.0f
+ wheelsDynData.setWheelRotationSpeed(wheelToRemove, 0.0f);
+
+ //Disable Ackermann steering.
+ //If the front wheel is to be removed and the front wheels can steer then disable Ackermann correction.
+ //If the rear wheel is to be removed and the rear wheels can steer then disable Ackermann correction.
+ if(removeFrontWheel &&
+ (wheelsSimData.getWheelData(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT).mMaxSteer!=0.0f ||
+ wheelsSimData.getWheelData(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).mMaxSteer!=0.0f))
+ {
+ PxVehicleAckermannGeometryData ackermannData=driveSimData.getAckermannGeometryData();
+ ackermannData.mAccuracy=0.0f;
+ driveSimData.setAckermannGeometryData(ackermannData);
+ }
+ if(!removeFrontWheel &&
+ (wheelsSimData.getWheelData(PxVehicleDrive4WWheelOrder::eREAR_RIGHT).mMaxSteer!=0.0f ||
+ wheelsSimData.getWheelData(PxVehicleDrive4WWheelOrder::eREAR_LEFT).mMaxSteer!=0.0f))
+ {
+ PxVehicleAckermannGeometryData ackermannData=driveSimData.getAckermannGeometryData();
+ ackermannData.mAccuracy=0.0f;
+ driveSimData.setAckermannGeometryData(ackermannData);
+ }
+
+ //We need to set up the differential to make sure that no drive torque is delivered to the disabled wheel.
+ PxVehicleDifferential4WData diffData =driveSimData.getDiffData();
+ if(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT==wheelToModify)
+ {
+ diffData.mFrontBias=PX_MAX_F32;
+ diffData.mFrontLeftRightSplit=0.0f;
+ }
+ else
+ {
+ diffData.mRearBias=PX_MAX_F32;
+ diffData.mRearLeftRightSplit=0.0f;
+ }
+ driveSimData.setDiffData(diffData);
+
+ //Now reposition the disabled wheel so that it lies at the center of its axle.
+ //The following assumes that the front and rear axles lie along the x-axis.
+ {
+ PxVec3 wheelCentreOffset=wheelsSimData.getWheelCentreOffset(wheelToModify);
+ wheelCentreOffset[rightDirection]=0.0f;
+ wheelsSimData.setWheelCentreOffset(wheelToModify,wheelCentreOffset);
+
+ PxVec3 suspOffset=wheelsSimData.getSuspForceAppPointOffset(wheelToModify);
+ suspOffset[rightDirection]=0;
+ wheelsSimData.setSuspForceAppPointOffset(wheelToModify,suspOffset);
+
+ PxVec3 tireOffset=wheelsSimData.getTireForceAppPointOffset(wheelToModify);
+ tireOffset[rightDirection]=0;
+ wheelsSimData.setTireForceAppPointOffset(wheelToModify,tireOffset);
+ }
+
+ //Redistribute the mass supported by 4 wheels among the 3 remaining enabled wheels.
+ //Compute the total mass supported by all 4 wheels.
+ const PxF32 totalMass =
+ wheelsSimData.getSuspensionData(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).mSprungMass +
+ wheelsSimData.getSuspensionData(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT).mSprungMass +
+ wheelsSimData.getSuspensionData(PxVehicleDrive4WWheelOrder::eREAR_LEFT).mSprungMass +
+ wheelsSimData.getSuspensionData(PxVehicleDrive4WWheelOrder::eREAR_RIGHT).mSprungMass;
+ //Get the wheel cm offsets of the 3 enabled wheels.
+ PxVec3 cmOffsets[3]=
+ {
+ wheelsSimData.getWheelCentreOffset((wheelToRemove+1) % 4),
+ wheelsSimData.getWheelCentreOffset((wheelToRemove+2) % 4),
+ wheelsSimData.getWheelCentreOffset((wheelToRemove+3) % 4),
+ };
+ //Re-compute the sprung masses.
+ PxF32 sprungMasses[3];
+ computeSprungMasses(3, cmOffsets, PxVec3(0,0,0), totalMass, upDirection, sprungMasses);
+
+ //Now set the new sprung masses.
+ //Do this in a way that preserves the natural frequency and damping ratio of the spring.
+ for(PxU32 i=0;i<3;i++)
+ {
+ PxVehicleSuspensionData suspData = wheelsSimData.getSuspensionData((wheelToRemove+1+i) % 4);
+
+ const PxF32 oldSprungMass = suspData.mSprungMass;
+ const PxF32 oldStrength = suspData.mSpringStrength;
+ const PxF32 oldDampingRate = suspData.mSpringDamperRate;
+ const PxF32 oldNaturalFrequency = PxSqrt(oldStrength/oldSprungMass);
+
+ const PxF32 newSprungMass = sprungMasses[i];
+ const PxF32 newStrength = oldNaturalFrequency*oldNaturalFrequency*newSprungMass;
+ const PxF32 newDampingRate = oldDampingRate;
+
+ suspData.mSprungMass = newSprungMass;
+ suspData.mSpringStrength = newStrength;
+ suspData.mSpringDamperRate = newDampingRate;
+ wheelsSimData.setSuspensionData((wheelToRemove+1+i) % 4, suspData);
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+//Maximum number of allowed blocks of 4 wheels
+////////////////////////////////////////////////////////////////////////////
+
+#define PX_MAX_NB_SUSPWHEELTIRE4 (PX_MAX_NB_WHEELS >>2)
+
+
+////////////////////////////////////////////////////////////////////////////
+//Pointers to telemetry data.
+//Set to NULL if no telemetry data is to be recorded during a vehicle update.
+//Functions used throughout vehicle update to record specific vehicle data.
+////////////////////////////////////////////////////////////////////////////
+
+#if PX_DEBUG_VEHICLE_ON
+
+//Render data.
+PxVec3* gCarTireForceAppPoints=NULL;
+PxVec3* gCarSuspForceAppPoints=NULL;
+
+//Graph data
+PxF32* gCarWheelGraphData[PX_MAX_NB_WHEELS]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+PxF32* gCarEngineGraphData=NULL;
+
+PX_FORCE_INLINE void updateGraphDataInternalWheelDynamics(const PxU32 startIndex, const PxF32* carWheelSpeeds)
+{
+ //Grab the internal rotation speeds for graphing before we update them.
+ if(gCarWheelGraphData[startIndex])
+ {
+ for(PxU32 i=0;i<4;i++)
+ {
+ PX_ASSERT((startIndex+i) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+i]);
+ gCarWheelGraphData[startIndex+i][PxVehicleWheelGraphChannel::eWHEEL_OMEGA]=carWheelSpeeds[i];
+ }
+ }
+}
+
+PX_FORCE_INLINE void updateGraphDataInternalEngineDynamics(const PxF32 carEngineSpeed)
+{
+ if(gCarEngineGraphData)
+ gCarEngineGraphData[PxVehicleDriveGraphChannel::eENGINE_REVS]=carEngineSpeed;
+}
+
+PX_FORCE_INLINE void updateGraphDataControlInputs(const PxF32 accel, const PxF32 brake, const PxF32 handbrake, const PxF32 steerLeft, const PxF32 steerRight)
+{
+ if(gCarEngineGraphData)
+ {
+ gCarEngineGraphData[PxVehicleDriveGraphChannel::eACCEL_CONTROL]=accel;
+ gCarEngineGraphData[PxVehicleDriveGraphChannel::eBRAKE_CONTROL]=brake;
+ gCarEngineGraphData[PxVehicleDriveGraphChannel::eHANDBRAKE_CONTROL]=handbrake;
+ gCarEngineGraphData[PxVehicleDriveGraphChannel::eSTEER_LEFT_CONTROL]=steerLeft;
+ gCarEngineGraphData[PxVehicleDriveGraphChannel::eSTEER_RIGHT_CONTROL]=steerRight;
+ }
+}
+PX_FORCE_INLINE void updateGraphDataGearRatio(const PxF32 G)
+{
+ if(gCarEngineGraphData)
+ gCarEngineGraphData[PxVehicleDriveGraphChannel::eGEAR_RATIO]=G;
+}
+PX_FORCE_INLINE void updateGraphDataEngineDriveTorque(const PxF32 engineDriveTorque)
+{
+ if(gCarEngineGraphData)
+ gCarEngineGraphData[PxVehicleDriveGraphChannel::eENGINE_DRIVE_TORQUE]=engineDriveTorque;
+}
+PX_FORCE_INLINE void updateGraphDataClutchSlip(const PxF32* wheelSpeeds, const PxF32* aveWheelSpeedContributions, const PxF32 engineSpeed, const PxF32 G)
+{
+ if(gCarEngineGraphData)
+ {
+ PxF32 averageWheelSpeed=0;
+ for(PxU32 i=0;i<4;i++)
+ {
+ averageWheelSpeed+=wheelSpeeds[i]*aveWheelSpeedContributions[i];
+ }
+ averageWheelSpeed*=G;
+ gCarEngineGraphData[PxVehicleDriveGraphChannel::eCLUTCH_SLIP]=averageWheelSpeed-engineSpeed;
+ }
+}
+PX_FORCE_INLINE void updateGraphDataClutchSlipNW(const PxU32 numWheels4, const PxVehicleWheels4DynData* wheelsDynData, const PxF32* aveWheelSpeedContributions, const PxF32 engineSpeed, const PxF32 G)
+{
+ if(gCarEngineGraphData)
+ {
+ PxF32 averageWheelSpeed=0;
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ averageWheelSpeed+=wheelsDynData[i].mWheelSpeeds[0]*aveWheelSpeedContributions[4*i+0];
+ averageWheelSpeed+=wheelsDynData[i].mWheelSpeeds[1]*aveWheelSpeedContributions[4*i+1];
+ averageWheelSpeed+=wheelsDynData[i].mWheelSpeeds[2]*aveWheelSpeedContributions[4*i+2];
+ averageWheelSpeed+=wheelsDynData[i].mWheelSpeeds[3]*aveWheelSpeedContributions[4*i+3];
+ }
+ averageWheelSpeed*=G;
+ gCarEngineGraphData[PxVehicleDriveGraphChannel::eCLUTCH_SLIP]=averageWheelSpeed-engineSpeed;
+ }
+}
+
+PX_FORCE_INLINE void zeroGraphDataWheels(const PxU32 startIndex, const PxU32 type)
+{
+ if(gCarWheelGraphData[0])
+ {
+ for(PxU32 i=0;i<4;i++)
+ {
+ PX_ASSERT((startIndex+i) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+i]);
+ gCarWheelGraphData[startIndex+i][type]=0.0f;
+ }
+ }
+}
+PX_FORCE_INLINE void updateGraphDataSuspJounce(const PxU32 startIndex, const PxU32 wheel, const PxF32 jounce)
+{
+ if(gCarWheelGraphData[0])
+ {
+ PX_ASSERT((startIndex+wheel) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+wheel]);
+ gCarWheelGraphData[startIndex+wheel][PxVehicleWheelGraphChannel::eJOUNCE]=jounce;
+ }
+}
+PX_FORCE_INLINE void updateGraphDataSuspForce(const PxU32 startIndex, const PxU32 wheel, const PxF32 springForce)
+{
+ if(gCarWheelGraphData[0])
+ {
+ PX_ASSERT((startIndex+wheel) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+wheel]);
+ gCarWheelGraphData[startIndex+wheel][PxVehicleWheelGraphChannel::eSUSPFORCE]=springForce;
+ }
+}
+PX_FORCE_INLINE void updateGraphDataTireLoad(const PxU32 startIndex, const PxU32 wheel, const PxF32 filteredTireLoad)
+{
+ if(gCarWheelGraphData[0])
+ {
+ PX_ASSERT((startIndex+wheel) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+wheel]);
+ gCarWheelGraphData[startIndex+wheel][PxVehicleWheelGraphChannel::eTIRELOAD]=filteredTireLoad;
+ }
+}
+PX_FORCE_INLINE void updateGraphDataNormTireLoad(const PxU32 startIndex, const PxU32 wheel, const PxF32 filteredNormalisedTireLoad)
+{
+ if(gCarWheelGraphData[0])
+ {
+ PX_ASSERT((startIndex+wheel) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+wheel]);
+ gCarWheelGraphData[startIndex+wheel][PxVehicleWheelGraphChannel::eNORMALIZED_TIRELOAD]=filteredNormalisedTireLoad;
+ }
+}
+PX_FORCE_INLINE void updateGraphDataNormLongTireForce(const PxU32 startIndex, const PxU32 wheel, const PxF32 normForce)
+{
+ if(gCarWheelGraphData[0])
+ {
+ PX_ASSERT((startIndex+wheel) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+wheel]);
+ gCarWheelGraphData[startIndex+wheel][PxVehicleWheelGraphChannel::eNORM_TIRE_LONG_FORCE]=normForce;
+ }
+}
+PX_FORCE_INLINE void updateGraphDataNormLatTireForce(const PxU32 startIndex, const PxU32 wheel, const PxF32 normForce)
+{
+ if(gCarWheelGraphData[0])
+ {
+ PX_ASSERT((startIndex+wheel) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+wheel]);
+ gCarWheelGraphData[startIndex+wheel][PxVehicleWheelGraphChannel::eNORM_TIRE_LAT_FORCE]=normForce;
+ }
+}
+PX_FORCE_INLINE void updateGraphDataLatTireSlip(const PxU32 startIndex, const PxU32 wheel, const PxF32 latSlip)
+{
+ if(gCarWheelGraphData[0])
+ {
+ PX_ASSERT((startIndex+wheel) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+wheel]);
+ gCarWheelGraphData[startIndex+wheel][PxVehicleWheelGraphChannel::eTIRE_LAT_SLIP]=latSlip;
+ }
+}
+PX_FORCE_INLINE void updateGraphDataLongTireSlip(const PxU32 startIndex, const PxU32 wheel, const PxF32 longSlip)
+{
+ if(gCarWheelGraphData[0])
+ {
+ PX_ASSERT((startIndex+wheel) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+wheel]);
+ gCarWheelGraphData[startIndex+wheel][PxVehicleWheelGraphChannel::eTIRE_LONG_SLIP]=longSlip;
+ }
+}
+PX_FORCE_INLINE void updateGraphDataTireFriction(const PxU32 startIndex, const PxU32 wheel, const PxF32 friction)
+{
+ if(gCarWheelGraphData[0])
+ {
+ PX_ASSERT((startIndex+wheel) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+wheel]);
+ gCarWheelGraphData[startIndex+wheel][PxVehicleWheelGraphChannel::eTIRE_FRICTION]=friction;
+ }
+}
+PX_FORCE_INLINE void updateGraphDataNormTireAligningMoment(const PxU32 startIndex, const PxU32 wheel, const PxF32 normAlignMoment)
+{
+ if(gCarWheelGraphData[0])
+ {
+ PX_ASSERT((startIndex+wheel) < PX_MAX_NB_WHEELS);
+ PX_ASSERT(gCarWheelGraphData[startIndex+wheel]);
+ gCarWheelGraphData[startIndex+wheel][PxVehicleWheelGraphChannel::eNORM_TIRE_ALIGNING_MOMENT]=normAlignMoment;
+ }
+}
+
+#endif //DEBUG_VEHICLE_ON
+
+
+////////////////////////////////////////////////////////////////////////////
+//Profile data structures.
+////////////////////////////////////////////////////////////////////////////
+
+
+#define PX_VEHICLE_PROFILE 0
+
+enum
+{
+ TIMER_ADMIN=0,
+ TIMER_GRAPHS,
+ TIMER_COMPONENTS_UPDATE,
+ TIMER_WHEELS,
+ TIMER_INTERNAL_DYNAMICS_SOLVER,
+ TIMER_POSTUPDATE1,
+ TIMER_POSTUPDATE2,
+ TIMER_POSTUPDATE3,
+ TIMER_ALL,
+ TIMER_RAYCASTS,
+ TIMER_SWEEPS,
+ MAX_NB_TIMERS
+};
+
+#if PX_VEHICLE_PROFILE
+
+bool gTimerStates[MAX_NB_TIMERS]={false,false,false,false,false,false,false,false,false,false,false};
+PxU64 gTimers[MAX_NB_TIMERS]={0,0,0,0,0,0,0,0,0,0,0};
+PxU64 gStartTimers[MAX_NB_TIMERS]={0,0,0,0,0,0,0,0,0,0,0};
+PxU64 gEndTimers[MAX_NB_TIMERS]={0,0,0,0,0,0,0,0,0,0,0};
+PxU32 gTimerCount=0;
+physx::Ps::Time gTimer;
+
+PX_FORCE_INLINE void START_TIMER(const PxU32 id)
+{
+ PX_ASSERT(!gTimerStates[id]);
+ gStartTimers[id]=gTimer.getCurrentCounterValue();
+ gTimerStates[id]=true;
+}
+
+PX_FORCE_INLINE void END_TIMER(const PxU32 id)
+{
+ PX_ASSERT(gTimerStates[id]);
+ gTimerStates[id]=false;
+ gEndTimers[id]=gTimer.getCurrentCounterValue();
+ gTimers[id]+=(gEndTimers[id]-gStartTimers[id]);
+}
+
+PX_FORCE_INLINE PxF32 getTimerFraction(const PxU32 id)
+{
+ return gTimers[id]/(1.0f*gTimers[TIMER_ALL]);
+}
+
+PX_FORCE_INLINE PxReal getTimerInMilliseconds(const PxU32 id)
+{
+ const PxU64 time=gTimers[id];
+ const PxU64 timein10sOfNs = gTimer.getBootCounterFrequency().toTensOfNanos(time);
+ return (timein10sOfNs/(gTimerCount*100*1.0f));
+}
+
+#else
+
+PX_FORCE_INLINE void START_TIMER(const PxU32)
+{
+}
+
+PX_FORCE_INLINE void END_TIMER(const PxU32)
+{
+}
+
+#endif
+
+
+////////////////////////////////////////////////////////////////////////////
+//Hash table of PxMaterial pointers used to associate each PxMaterial pointer
+//with a unique PxDrivableSurfaceType. PxDrivableSurfaceType is just an integer
+//representing an id but introducing this type allows different PxMaterial pointers
+//to be associated with the same surface type. The friction of a specific tire
+//touching a specific PxMaterial is found from a 2D table using the integers for
+//the tire type (stored in the tire) and drivable surface type (from the hash table).
+//It would be great to use PsHashSet for the hash table of PxMaterials but
+//PsHashSet will never, ever work on spu so this will need to do instead.
+//Perf isn't really critical so this will do in the meantime.
+//It is probably wasteful to compute the hash table each update
+//but this is really not an expensive operation so keeping the api as
+//simple as possible wins out at the cost of a relatively very small number of wasted cycles.
+////////////////////////////////////////////////////////////////////////////
+
+class VehicleSurfaceTypeHashTable
+{
+public:
+
+ VehicleSurfaceTypeHashTable(const PxVehicleDrivableSurfaceToTireFrictionPairs& pairs)
+ : mNbEntries(pairs.mNbSurfaceTypes),
+ mMaterials(pairs.mDrivableSurfaceMaterials),
+ mDrivableSurfaceTypes(pairs.mDrivableSurfaceTypes)
+ {
+ for(PxU32 i=0;i<eHASH_SIZE;i++)
+ {
+ mHeadIds[i]=PX_MAX_U32;
+ }
+ for(PxU32 i=0;i<eMAX_NB_KEYS;i++)
+ {
+ mNextIds[i]=PX_MAX_U32;
+ }
+
+ if(mNbEntries>0)
+ {
+ //Compute the number of bits to right-shift that gives the maximum number of unique hashes.
+ //Keep searching until we find either a set of completely unique hashes or a peak count of unique hashes.
+ PxU32 prevShift=0;
+ PxU32 shift=2;
+ PxU32 prevNumUniqueHashes=0;
+ PxU32 currNumUniqueHashes=0;
+ while( ((currNumUniqueHashes=computeNumUniqueHashes(shift)) > prevNumUniqueHashes) && currNumUniqueHashes!=mNbEntries)
+ {
+ prevNumUniqueHashes=currNumUniqueHashes;
+ prevShift=shift;
+ shift = (shift << 1);
+ }
+ if(currNumUniqueHashes!=mNbEntries)
+ {
+ //Stopped searching because we have gone past the peak number of unqiue hashes.
+ mShift = prevShift;
+ }
+ else
+ {
+ //Stopped searching because we found a unique hash for each key.
+ mShift = shift;
+ }
+
+ //Compute the hash values with the optimum shift.
+ for(PxU32 i=0;i<mNbEntries;i++)
+ {
+ const PxMaterial* const material=mMaterials[i];
+ const PxU32 hash=computeHash(material,mShift);
+ if(PX_MAX_U32==mHeadIds[hash])
+ {
+ mNextIds[i]=PX_MAX_U32;
+ mHeadIds[hash]=i;
+ }
+ else
+ {
+ mNextIds[i]=mHeadIds[hash];
+ mHeadIds[hash]=i;
+ }
+ }
+ }
+ }
+ ~VehicleSurfaceTypeHashTable()
+ {
+ }
+
+ PX_FORCE_INLINE PxU32 get(const PxMaterial* const key) const
+ {
+ PX_ASSERT(key);
+ const PxU32 hash=computeHash(key, mShift);
+ PxU32 id=mHeadIds[hash];
+ while(PX_MAX_U32!=id)
+ {
+ const PxMaterial* const mat=mMaterials[id];
+ if(key==mat)
+ {
+ return mDrivableSurfaceTypes[id].mType;
+ }
+ id=mNextIds[id];
+ }
+
+ return 0;
+ }
+
+private:
+
+ PxU32 mNbEntries;
+ const PxMaterial* const* mMaterials;
+ const PxVehicleDrivableSurfaceType* mDrivableSurfaceTypes;
+
+ static PX_FORCE_INLINE PxU32 computeHash(const PxMaterial* const key, const PxU32 shift)
+ {
+ const uintptr_t ptr = ((uintptr_t(key)) >> shift);
+ const uintptr_t hash = (ptr & (eHASH_SIZE-1));
+ return PxU32(hash);
+ }
+
+ PxU32 computeNumUniqueHashes(const PxU32 shift) const
+ {
+ PxU32 words[eHASH_SIZE >>5];
+ PxU8* bitmapBuffer[sizeof(BitMap)];
+ BitMap* bitmap=reinterpret_cast<BitMap*>(bitmapBuffer);
+ bitmap->setWords(words, eHASH_SIZE >>5);
+
+ PxU32 numUniqueHashes=0;
+ PxMemZero(words, sizeof(PxU32)*(eHASH_SIZE >>5));
+ for(PxU32 i=0;i<mNbEntries;i++)
+ {
+ const PxMaterial* const material=mMaterials[i];
+ const PxU32 hash=computeHash(material, shift);
+ if(!bitmap->test(hash))
+ {
+ bitmap->set(hash);
+ numUniqueHashes++;
+ }
+ }
+ return numUniqueHashes;
+ }
+
+ enum
+ {
+ eHASH_SIZE=PxVehicleDrivableSurfaceToTireFrictionPairs::eMAX_NB_SURFACE_TYPES
+ };
+ PxU32 mHeadIds[eHASH_SIZE];
+ enum
+ {
+ eMAX_NB_KEYS=PxVehicleDrivableSurfaceToTireFrictionPairs::eMAX_NB_SURFACE_TYPES
+ };
+ PxU32 mNextIds[eMAX_NB_KEYS];
+
+ PxU32 mShift;
+};
+
+
+////////////////////////////////////////////////////////////////////////////
+//Compute the suspension line raycast start point and direction.
+////////////////////////////////////////////////////////////////////////////
+
+PX_INLINE void computeSuspensionRaycast
+(const PxTransform& carChassisTrnsfm, const PxVec3& bodySpaceWheelCentreOffset, const PxVec3& bodySpaceSuspTravelDir, const PxF32 radius, const PxF32 maxBounce,
+ PxVec3& suspLineStart, PxVec3& suspLineDir)
+{
+ //Direction of raycast.
+ suspLineDir=carChassisTrnsfm.rotate(bodySpaceSuspTravelDir);
+
+ //Position at top of wheel at maximum compression.
+ suspLineStart=carChassisTrnsfm.transform(bodySpaceWheelCentreOffset);
+ suspLineStart-=suspLineDir*(radius+maxBounce);
+}
+
+PX_INLINE void computeSuspensionSweep
+(const PxTransform& carChassisTrnsfm,
+ const PxQuat& wheelLocalPoseRotation, const PxF32 wheelTheta,
+ const PxVec3 bodySpaceWheelCentreOffset, const PxVec3& bodySpaceSuspTravelDir, const PxF32 radius, const PxF32 maxBounce,
+ PxTransform& suspStartPose, PxVec3& suspLineDir)
+{
+ //Direction of raycast.
+ suspLineDir=carChassisTrnsfm.rotate(bodySpaceSuspTravelDir);
+
+ //Position of wheel at maximum compression.
+ suspStartPose.p = carChassisTrnsfm.transform(bodySpaceWheelCentreOffset);
+ suspStartPose.p -= suspLineDir*(radius + maxBounce);
+
+ //Rotation of wheel.
+ const PxVec3 right = wheelLocalPoseRotation.rotate(gRight);
+ const PxQuat negativeRotation(-wheelTheta, right);
+ suspStartPose.q = carChassisTrnsfm.q*(negativeRotation*wheelLocalPoseRotation);
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+//Functions used to integrate rigid body transform and velocity.
+//The sub-step system divides a specified timestep into N equal sub-steps
+//and integrates the velocity and transform each sub-step.
+//After all sub-steps are complete the velocity required to move the
+//associated PxRigidBody from the start transform to the transform at the end
+//of the timestep is computed and set. If the update mode is chosen to be
+//acceleration then the acceleration is computed/set that will move the rigid body
+//from the start to end transform. The PxRigidBody never actually has its transform
+//updated and only has its velocity or acceleration set at the very end of the timestep.
+////////////////////////////////////////////////////////////////////////////
+
+PX_INLINE void integrateBody
+(const PxF32 inverseMass, const PxVec3& invInertia, const PxVec3& force, const PxVec3& torque, const PxF32 dt,
+ PxVec3& v, PxVec3& w, PxTransform& t)
+{
+ //Integrate linear velocity.
+ v+=force*(inverseMass*dt);
+
+ //Integrate angular velocity.
+ PxMat33 inverseInertia;
+ transformInertiaTensor(invInertia, PxMat33(t.q), inverseInertia);
+ w+=inverseInertia*(torque*dt);
+
+ //Integrate position.
+ t.p+=v*dt;
+
+ //Integrate quaternion.
+ PxQuat wq(w.x,w.y,w.z,0.0f);
+ PxQuat q=t.q;
+ PxQuat qdot=wq*q*(dt*0.5f);
+ q+=qdot;
+ q.normalize();
+ t.q=q;
+}
+
+/*
+PX_INLINE void computeVelocity(const PxTransform& t1, const PxTransform& t2, const PxF32 invDT, PxVec3& v, PxVec3& w)
+{
+ //Linear velocity.
+ v = (t2.p - t1.p)*invDT;
+
+ //Angular velocity.
+ PxQuat qw = (t2.q - t1.q)*t1.q.getConjugate()*(2.0f*invDT);
+ w.x=qw.x;
+ w.y=qw.y;
+ w.z=qw.z;
+}
+*/
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//Use fsel to compute the sign of a float: +1 for positive values, -1 for negative values
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PX_FORCE_INLINE PxF32 computeSign(const PxF32 f)
+{
+ return physx::intrinsics::fsel(f, physx::intrinsics::fsel(-f, 0.0f, 1.0f), -1.0f);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//Get the accel/brake/handbrake as floats in range (0,1) from the inputs stored in the vehicle.
+//Equivalent for tank involving thrustleft/thrustright and brakeleft/brakeright.
+/////////////////////////////////////////////////////////////////////////////////////////
+
+
+PX_FORCE_INLINE void getVehicle4WControlValues(const PxVehicleDriveDynData& driveDynData, PxF32& accel, PxF32& brake, PxF32& handbrake, PxF32& steerLeft, PxF32& steerRight)
+{
+ accel=driveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL];
+ brake=driveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE];
+ handbrake=driveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE];
+ steerLeft=driveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT];
+ steerRight=driveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT];
+}
+
+PX_FORCE_INLINE void getVehicleNWControlValues(const PxVehicleDriveDynData& driveDynData, PxF32& accel, PxF32& brake, PxF32& handbrake, PxF32& steerLeft, PxF32& steerRight)
+{
+ accel=driveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_ACCEL];
+ brake=driveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_BRAKE];
+ handbrake=driveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_HANDBRAKE];
+ steerLeft=driveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_STEER_LEFT];
+ steerRight=driveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_STEER_RIGHT];
+}
+
+PX_FORCE_INLINE void getTankControlValues(const PxVehicleDriveDynData& driveDynData, PxF32& accel, PxF32& brakeLeft, PxF32& brakeRight, PxF32& thrustLeft, PxF32& thrustRight)
+{
+ accel=driveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL];
+ brakeLeft=driveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT];
+ brakeRight=driveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT];
+ thrustLeft=driveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT];
+ thrustRight=driveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT];
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+//Process autobox to initiate automatic gear changes.
+//The autobox can be turned off and simulated externally by setting
+//the target gear as required prior to calling PxVehicleUpdates.
+////////////////////////////////////////////////////////////////////////////
+
+
+PX_FORCE_INLINE PxF32 processAutoBox(const PxU32 accelIndex, const PxF32 timestep, const PxVehicleDriveSimData& vehCoreSimData, PxVehicleDriveDynData& vehDynData)
+{
+ PX_ASSERT(vehDynData.getUseAutoGears());
+
+ PxF32 autoboxCompensatedAnalogAccel = vehDynData.mControlAnalogVals[accelIndex];
+
+ //If still undergoing a gear change triggered by the autobox
+ //then turn off the accelerator pedal. This happens in autoboxes
+ //to stop the driver revving the engine crazily then damaging the
+ //clutch when the clutch re-engages at the end of the gear change.
+ const PxU32 currentGear=vehDynData.getCurrentGear();
+ const PxU32 targetGear=vehDynData.getTargetGear();
+ if(targetGear!=currentGear && PxVehicleGearsData::eNEUTRAL==currentGear)
+ {
+ autoboxCompensatedAnalogAccel = 0;
+ }
+
+ //Only process the autobox if no gear change is underway and the time passed since the last autobox
+ //gear change is greater than the autobox latency.
+ PxF32 autoBoxSwitchTime=vehDynData.getAutoBoxSwitchTime();
+ const PxF32 autoBoxLatencyTime=vehCoreSimData.getAutoBoxData().mDownRatios[PxVehicleGearsData::eREVERSE];
+ if(targetGear==currentGear && autoBoxSwitchTime > autoBoxLatencyTime)
+ {
+ //Work out if the autobox wants to switch up or down.
+ const PxF32 normalisedEngineOmega=vehDynData.getEngineRotationSpeed()*vehCoreSimData.getEngineData().getRecipMaxOmega();
+ const PxVehicleAutoBoxData& autoBoxData=vehCoreSimData.getAutoBoxData();
+
+ bool gearUp=false;
+ if(normalisedEngineOmega > autoBoxData.mUpRatios[currentGear] && PxVehicleGearsData::eREVERSE!=currentGear)
+ {
+ //If revs too high and not in reverse and not undergoing a gear change then switch up.
+ gearUp=true;
+ }
+
+ bool gearDown=false;
+ if(normalisedEngineOmega < autoBoxData.mDownRatios[currentGear] && currentGear > PxVehicleGearsData::eFIRST)
+ {
+ //If revs too low and in gear greater than first and not undergoing a gear change then change down.
+ gearDown=true;
+ }
+
+ //Start the gear change and reset the time since the last autobox gear change.
+ if(gearUp || gearDown)
+ {
+ vehDynData.setGearUp(gearUp);
+ vehDynData.setGearDown(gearDown);
+ vehDynData.setAutoBoxSwitchTime(0.f);
+ }
+ }
+ else
+ {
+ autoBoxSwitchTime+=timestep;
+ vehDynData.setAutoBoxSwitchTime(autoBoxSwitchTime);
+ }
+
+ return autoboxCompensatedAnalogAccel;
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+//Process gear changes.
+//If target gear not equal to current gear then a gear change needs to start.
+//The gear change process begins by switching immediately in neutral and
+//staying there for a specified time. The process ends by setting current
+//gear equal to target gear when the gear switch time has passed.
+//This can be bypassed by always forcing target gear = current gear and then
+//externally managing gear changes prior to calling PxVehicleUpdates.
+////////////////////////////////////////////////////////////////////////////
+
+void processGears(const PxF32 timestep, const PxVehicleGearsData& gears, PxVehicleDriveDynData& car)
+{
+ //const PxVehicleGearsData& gears=car.mVehicleSimData.getGearsData();
+
+ //Process the gears.
+ if(car.getGearUp() && gears.mNbRatios-1!=car.getCurrentGear() && car.getCurrentGear()==car.getTargetGear())
+ {
+ //Car wants to go up a gear and can go up a gear and not already undergoing a gear change.
+ if(PxVehicleGearsData::eREVERSE==car.getCurrentGear())
+ {
+ //In reverse so switch to first through neutral.
+ car.setGearSwitchTime(0);
+ car.setTargetGear(PxVehicleGearsData::eFIRST);
+ car.setCurrentGear(PxVehicleGearsData::eNEUTRAL);
+ }
+ else if(PxVehicleGearsData::eNEUTRAL==car.getCurrentGear())
+ {
+ //In neutral so switch to first and stay in neutral.
+ car.setGearSwitchTime(0);
+ car.setTargetGear(PxVehicleGearsData::eFIRST);
+ car.setCurrentGear(PxVehicleGearsData::eNEUTRAL);
+ }
+ else
+ {
+ //Switch up a gear through neutral.
+ car.setGearSwitchTime(0);
+ car.setTargetGear(car.getCurrentGear() + 1);
+ car.setCurrentGear(PxVehicleGearsData::eNEUTRAL);
+ }
+ }
+ if(car.getGearDown() && PxVehicleGearsData::eREVERSE!=car.getCurrentGear() && car.getCurrentGear()==car.getTargetGear())
+ {
+ //Car wants to go down a gear and can go down a gear and not already undergoing a gear change
+ if(PxVehicleGearsData::eFIRST==car.getCurrentGear())
+ {
+ //In first so switch to reverse through neutral.
+ car.setGearSwitchTime(0);
+ car.setTargetGear(PxVehicleGearsData::eREVERSE);
+ car.setCurrentGear(PxVehicleGearsData::eNEUTRAL);
+ }
+ else if(PxVehicleGearsData::eNEUTRAL==car.getCurrentGear())
+ {
+ //In neutral so switch to reverse and stay in neutral.
+ car.setGearSwitchTime(0);
+ car.setTargetGear(PxVehicleGearsData::eREVERSE);
+ car.setCurrentGear(PxVehicleGearsData::eNEUTRAL);
+ }
+ else
+ {
+ //Switch down a gear through neutral.
+ car.setGearSwitchTime(0);
+ car.setTargetGear(car.getCurrentGear() - 1);
+ car.setCurrentGear(PxVehicleGearsData::eNEUTRAL);
+ }
+ }
+ if(car.getCurrentGear()!=car.getTargetGear())
+ {
+ if(car.getGearSwitchTime()>gears.mSwitchTime)
+ {
+ car.setCurrentGear(car.getTargetGear());
+ car.setGearSwitchTime(0);
+ car.setGearDown(false);
+ car.setGearUp(false);
+ }
+ else
+ {
+ car.setGearSwitchTime(car.getGearSwitchTime() + timestep);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Helper functions to compute
+//1. the gear ratio from the current gear.
+//2. the drive torque from the state of the accelerator pedal and torque curve of available torque against engine speed.
+//3. engine damping rate (a blend between a rate when not accelerating and a rate when fully accelerating).
+//4. clutch strength (rate at which clutch will regulate difference between engine and averaged wheel speed).
+////////////////////////////////////////////////////////////////////////////
+
+PX_FORCE_INLINE PxF32 computeGearRatio(const PxVehicleGearsData& gearsData, const PxU32 currentGear)
+{
+ const PxF32 gearRatio=gearsData.mRatios[currentGear]*gearsData.mFinalRatio;
+ return gearRatio;
+}
+
+PX_FORCE_INLINE PxF32 computeEngineDriveTorque(const PxVehicleEngineData& engineData, const PxF32 omega, const PxF32 accel)
+{
+ const PxF32 engineDriveTorque=accel*engineData.mPeakTorque*engineData.mTorqueCurve.getYVal(omega*engineData.getRecipMaxOmega());
+ return engineDriveTorque;
+}
+
+PX_FORCE_INLINE PxF32 computeEngineDampingRate(const PxVehicleEngineData& engineData, const PxU32 gear, const PxF32 accel)
+{
+ const PxF32 fullThrottleDamping = engineData.mDampingRateFullThrottle;
+ const PxF32 zeroThrottleDamping = (PxVehicleGearsData::eNEUTRAL!=gear) ? engineData.mDampingRateZeroThrottleClutchEngaged : engineData.mDampingRateZeroThrottleClutchDisengaged;
+ const PxF32 engineDamping = zeroThrottleDamping + (fullThrottleDamping-zeroThrottleDamping)*accel;
+ return engineDamping;
+}
+
+PX_FORCE_INLINE PxF32 computeClutchStrength(const PxVehicleClutchData& clutchData, const PxU32 currentGear)
+{
+ return ((PxVehicleGearsData::eNEUTRAL!=currentGear) ? clutchData.mStrength : 0.0f);
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+//Limited slip differential.
+//Split the available drive torque as a fraction of the total between up to 4 driven wheels.
+//Compute the fraction that each wheel contributes to the averages wheel speed at the clutch.
+////////////////////////////////////////////////////////////////////////////
+
+PX_FORCE_INLINE void splitTorque
+(const PxF32 w1, const PxF32 w2, const PxF32 diffBias, const PxF32 defaultSplitRatio,
+ PxF32* t1, PxF32* t2)
+{
+ PX_ASSERT(computeSign(w1)==computeSign(w2) && 0.0f!=computeSign(w1));
+ const PxF32 w1Abs=PxAbs(w1);
+ const PxF32 w2Abs=PxAbs(w2);
+ const PxF32 omegaMax=PxMax(w1Abs,w2Abs);
+ const PxF32 omegaMin=PxMin(w1Abs,w2Abs);
+ const PxF32 delta=omegaMax-diffBias*omegaMin;
+ const PxF32 deltaTorque=physx::intrinsics::fsel(delta, delta/omegaMax , 0.0f);
+ const PxF32 f1=physx::intrinsics::fsel(w1Abs-w2Abs, defaultSplitRatio*(1.0f-deltaTorque), defaultSplitRatio*(1.0f+deltaTorque));
+ const PxF32 f2=physx::intrinsics::fsel(w1Abs-w2Abs, (1.0f-defaultSplitRatio)*(1.0f+deltaTorque), (1.0f-defaultSplitRatio)*(1.0f-deltaTorque));
+ const PxF32 denom=1.0f/(f1+f2);
+ *t1=f1*denom;
+ *t2=f2*denom;
+ PX_ASSERT((*t1 + *t2) >=0.999f && (*t1 + *t2) <=1.001f);
+}
+
+PX_FORCE_INLINE void computeDiffTorqueRatios
+(const PxVehicleDifferential4WData& diffData, const PxF32 handbrake, const PxF32* PX_RESTRICT wheelOmegas, PxF32* PX_RESTRICT diffTorqueRatios)
+{
+ //If the handbrake is on only deliver torque to the front wheels.
+ PxU32 type=diffData.mType;
+ if(handbrake>0)
+ {
+ switch(diffData.mType)
+ {
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD:
+ type=PxVehicleDifferential4WData::eDIFF_TYPE_LS_FRONTWD;
+ break;
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_4WD:
+ type=PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_FRONTWD;
+ break;
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_FRONTWD:
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_REARWD:
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_FRONTWD:
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_REARWD:
+ case PxVehicleDifferential4WData::eMAX_NB_DIFF_TYPES:
+ break;
+ }
+ }
+
+ const PxF32 wfl=wheelOmegas[PxVehicleDrive4WWheelOrder::eFRONT_LEFT];
+ const PxF32 wfr=wheelOmegas[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT];
+ const PxF32 wrl=wheelOmegas[PxVehicleDrive4WWheelOrder::eREAR_LEFT];
+ const PxF32 wrr=wheelOmegas[PxVehicleDrive4WWheelOrder::eREAR_RIGHT];
+
+ const PxF32 centreBias=diffData.mCentreBias;
+ const PxF32 frontBias=diffData.mFrontBias;
+ const PxF32 rearBias=diffData.mRearBias;
+
+ const PxF32 frontRearSplit=diffData.mFrontRearSplit;
+ const PxF32 frontLeftRightSplit=diffData.mFrontLeftRightSplit;
+ const PxF32 rearLeftRightSplit=diffData.mRearLeftRightSplit;
+
+ const PxF32 oneMinusFrontRearSplit=1.0f-diffData.mFrontRearSplit;
+ const PxF32 oneMinusFrontLeftRightSplit=1.0f-diffData.mFrontLeftRightSplit;
+ const PxF32 oneMinusRearLeftRightSplit=1.0f-diffData.mRearLeftRightSplit;
+
+ const PxF32 swfl=computeSign(wfl);
+
+ //Split a torque of 1 between front and rear.
+ //Then split that torque between left and right.
+ PxF32 torqueFrontLeft=0;
+ PxF32 torqueFrontRight=0;
+ PxF32 torqueRearLeft=0;
+ PxF32 torqueRearRight=0;
+ switch(type)
+ {
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD:
+ if(0.0f!=swfl && swfl==computeSign(wfr) && swfl==computeSign(wrl) && swfl==computeSign(wrr))
+ {
+ PxF32 torqueFront,torqueRear;
+ const PxF32 omegaFront=PxAbs(wfl+wfr);
+ const PxF32 omegaRear=PxAbs(wrl+wrr);
+ splitTorque(omegaFront,omegaRear,centreBias,frontRearSplit,&torqueFront,&torqueRear);
+ splitTorque(wfl,wfr,frontBias,frontLeftRightSplit,&torqueFrontLeft,&torqueFrontRight);
+ splitTorque(wrl,wrr,rearBias,rearLeftRightSplit,&torqueRearLeft,&torqueRearRight);
+ torqueFrontLeft*=torqueFront;
+ torqueFrontRight*=torqueFront;
+ torqueRearLeft*=torqueRear;
+ torqueRearRight*=torqueRear;
+ }
+ else
+ {
+ //TODO: need to handle this case.
+ torqueFrontLeft=frontRearSplit*frontLeftRightSplit;
+ torqueFrontRight=frontRearSplit*oneMinusFrontLeftRightSplit;
+ torqueRearLeft=oneMinusFrontRearSplit*rearLeftRightSplit;
+ torqueRearRight=oneMinusFrontRearSplit*oneMinusRearLeftRightSplit;
+ }
+ break;
+
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_FRONTWD:
+ if(0.0f!=swfl && swfl==computeSign(wfr))
+ {
+ splitTorque(wfl,wfr,frontBias,frontLeftRightSplit,&torqueFrontLeft,&torqueFrontRight);
+ }
+ else
+ {
+ torqueFrontLeft=frontLeftRightSplit;
+ torqueFrontRight=oneMinusFrontLeftRightSplit;
+ }
+ break;
+
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_REARWD:
+
+ if(0.0f!=computeSign(wrl) && computeSign(wrl)==computeSign(wrr))
+ {
+ splitTorque(wrl,wrr,rearBias,rearLeftRightSplit,&torqueRearLeft,&torqueRearRight);
+ }
+ else
+ {
+ torqueRearLeft=rearLeftRightSplit;
+ torqueRearRight=oneMinusRearLeftRightSplit;
+ }
+ break;
+
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_4WD:
+ torqueFrontLeft=frontRearSplit*frontLeftRightSplit;
+ torqueFrontRight=frontRearSplit*oneMinusFrontLeftRightSplit;
+ torqueRearLeft=oneMinusFrontRearSplit*rearLeftRightSplit;
+ torqueRearRight=oneMinusFrontRearSplit*oneMinusRearLeftRightSplit;
+ break;
+
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_FRONTWD:
+ torqueFrontLeft=frontLeftRightSplit;
+ torqueFrontRight=oneMinusFrontLeftRightSplit;
+ break;
+
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_REARWD:
+ torqueRearLeft=rearLeftRightSplit;
+ torqueRearRight=oneMinusRearLeftRightSplit;
+ break;
+
+ default:
+ PX_ASSERT(false);
+ break;
+ }
+
+ diffTorqueRatios[PxVehicleDrive4WWheelOrder::eFRONT_LEFT]=torqueFrontLeft;
+ diffTorqueRatios[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT]=torqueFrontRight;
+ diffTorqueRatios[PxVehicleDrive4WWheelOrder::eREAR_LEFT]=torqueRearLeft;
+ diffTorqueRatios[PxVehicleDrive4WWheelOrder::eREAR_RIGHT]=torqueRearRight;
+
+ PX_ASSERT(((torqueFrontLeft+torqueFrontRight+torqueRearLeft+torqueRearRight) >= 0.999f) && ((torqueFrontLeft+torqueFrontRight+torqueRearLeft+torqueRearRight) <= 1.001f));
+}
+
+PX_FORCE_INLINE void computeDiffAveWheelSpeedContributions
+(const PxVehicleDifferential4WData& diffData, const PxF32 handbrake, PxF32* PX_RESTRICT diffAveWheelSpeedContributions)
+{
+ PxU32 type=diffData.mType;
+
+ //If the handbrake is on only deliver torque to the front wheels.
+ if(handbrake>0)
+ {
+ switch(diffData.mType)
+ {
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD:
+ type=PxVehicleDifferential4WData::eDIFF_TYPE_LS_FRONTWD;
+ break;
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_4WD:
+ type=PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_FRONTWD;
+ break;
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_REARWD:
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_FRONTWD:
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_REARWD:
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_FRONTWD:
+ case PxVehicleDifferential4WData::eMAX_NB_DIFF_TYPES:
+ break;
+ }
+ }
+
+ const PxF32 frontRearSplit=diffData.mFrontRearSplit;
+ const PxF32 frontLeftRightSplit=diffData.mFrontLeftRightSplit;
+ const PxF32 rearLeftRightSplit=diffData.mRearLeftRightSplit;
+
+ const PxF32 oneMinusFrontRearSplit=1.0f-diffData.mFrontRearSplit;
+ const PxF32 oneMinusFrontLeftRightSplit=1.0f-diffData.mFrontLeftRightSplit;
+ const PxF32 oneMinusRearLeftRightSplit=1.0f-diffData.mRearLeftRightSplit;
+
+ switch(type)
+ {
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_4WD:
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_4WD:
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eFRONT_LEFT]=frontRearSplit*frontLeftRightSplit;
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT]=frontRearSplit*oneMinusFrontLeftRightSplit;
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eREAR_LEFT]=oneMinusFrontRearSplit*rearLeftRightSplit;
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eREAR_RIGHT]=oneMinusFrontRearSplit*oneMinusRearLeftRightSplit;
+ break;
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_FRONTWD:
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_FRONTWD:
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eFRONT_LEFT]=frontLeftRightSplit;
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT]=oneMinusFrontLeftRightSplit;
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eREAR_LEFT]=0.0f;
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eREAR_RIGHT]=0.0f;
+ break;
+ case PxVehicleDifferential4WData::eDIFF_TYPE_LS_REARWD:
+ case PxVehicleDifferential4WData::eDIFF_TYPE_OPEN_REARWD:
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eFRONT_LEFT]=0.0f;
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT]=0.0f;
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eREAR_LEFT]=rearLeftRightSplit;
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eREAR_RIGHT]=oneMinusRearLeftRightSplit;
+ break;
+ default:
+ PX_ASSERT(false);
+ break;
+ }
+
+ PX_ASSERT((diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eFRONT_LEFT] +
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT] +
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eREAR_LEFT] +
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eREAR_RIGHT]) >= 0.999f &&
+ (diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eFRONT_LEFT] +
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT] +
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eREAR_LEFT] +
+ diffAveWheelSpeedContributions[PxVehicleDrive4WWheelOrder::eREAR_RIGHT]) <= 1.001f);
+}
+
+
+///////////////////////////////////////////////////////
+//Tank differential
+///////////////////////////////////////////////////////
+
+void computeTankDiff
+(const PxF32 thrustLeft, const PxF32 thrustRight,
+ const PxU32 numActiveWheels, const bool* activeWheelStates,
+ PxF32* aveWheelSpeedContributions, PxF32* diffTorqueRatios, PxF32* wheelGearings)
+{
+ const PxF32 thrustLeftAbs=PxAbs(thrustLeft);
+ const PxF32 thrustRightAbs=PxAbs(thrustRight);
+
+ //Work out now many left wheels are enabled.
+ PxF32 numLeftWheels=0.0f;
+ for(PxU32 i=0;i<numActiveWheels;i+=2)
+ {
+ if(activeWheelStates[i])
+ {
+ numLeftWheels+=1.0f;
+ }
+ }
+ const PxF32 invNumEnabledWheelsLeft = numLeftWheels > 0 ? 1.0f/numLeftWheels : 0.0f;
+
+ //Work out now many right wheels are enabled.
+ PxF32 numRightWheels=0.0f;
+ for(PxU32 i=1;i<numActiveWheels;i+=2)
+ {
+ if(activeWheelStates[i])
+ {
+ numRightWheels+=1.0f;
+ }
+ }
+ const PxF32 invNumEnabledWheelsRight = numRightWheels > 0 ? 1.0f/numRightWheels : 0.0f;
+
+ //Split the diff torque between left and right.
+ PxF32 diffTorqueRatioLeft=0.5f;
+ PxF32 diffTorqueRatioRight=0.5f;
+ if((thrustLeftAbs + thrustRightAbs) > 1e-3f)
+ {
+ const PxF32 thrustDiff = 0.5f*(thrustLeftAbs - thrustRightAbs)/(thrustLeftAbs + thrustRightAbs);
+ diffTorqueRatioLeft += thrustDiff;
+ diffTorqueRatioRight -= thrustDiff;
+
+ }
+ diffTorqueRatioLeft *= invNumEnabledWheelsLeft;
+ diffTorqueRatioRight *= invNumEnabledWheelsRight;
+
+ //Compute the per wheel gearing.
+ PxF32 wheelGearingLeft=1.0f;
+ PxF32 wheelGearingRight=1.0f;
+ if((thrustLeftAbs + thrustRightAbs) > 1e-3f)
+ {
+ wheelGearingLeft=computeSign(thrustLeft);
+ wheelGearingRight=computeSign(thrustRight);
+ }
+
+ //Compute the contribution of each wheel to the average speed at the clutch.
+ const PxF32 aveWheelSpeedContributionLeft = 0.5f*invNumEnabledWheelsLeft;
+ const PxF32 aveWheelSpeedContributionRight = 0.5f*invNumEnabledWheelsRight;
+
+ //Set all the left wheels.
+ for(PxU32 i=0;i<numActiveWheels;i+=2)
+ {
+ if(activeWheelStates[i])
+ {
+ aveWheelSpeedContributions[i]=aveWheelSpeedContributionLeft;
+ diffTorqueRatios[i]=diffTorqueRatioLeft;
+ wheelGearings[i]=wheelGearingLeft;
+ }
+ }
+ //Set all the right wheels.
+ for(PxU32 i=1;i<numActiveWheels;i+=2)
+ {
+ if(activeWheelStates[i])
+ {
+ aveWheelSpeedContributions[i]=aveWheelSpeedContributionRight;
+ diffTorqueRatios[i]=diffTorqueRatioRight;
+ wheelGearings[i]=wheelGearingRight;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Compute a per-wheel accelerator pedal value.
+//These values are to blend the denominator normalised longitudinal slip at low speed
+//between a low value for wheels under drive torque and a high value for wheels with no
+//drive torque.
+//Using a high value allows the vehicle to come to rest smoothly.
+//Using a low value gives better thrust.
+////////////////////////////////////////////////////////////////////////////
+
+void computeIsAccelApplied(const PxF32* aveWheelSpeedContributions, bool* isAccelApplied)
+{
+ isAccelApplied[0] = aveWheelSpeedContributions[0] != 0.0f ? true : false;
+ isAccelApplied[1] = aveWheelSpeedContributions[1] != 0.0f ? true : false;
+ isAccelApplied[2] = aveWheelSpeedContributions[2] != 0.0f ? true : false;
+ isAccelApplied[3] = aveWheelSpeedContributions[3] != 0.0f ? true : false;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Ackermann correction to steer angles.
+////////////////////////////////////////////////////////////////////////////
+
+PX_FORCE_INLINE void computeAckermannSteerAngles
+(const PxF32 steer, const PxF32 steerGain,
+ const PxF32 ackermannAccuracy, const PxF32 width, const PxF32 axleSeparation,
+ PxF32* PX_RESTRICT leftAckermannSteerAngle, PxF32* PX_RESTRICT rightAckermannSteerAngle)
+{
+ PX_ASSERT(steer>=-1.01f && steer<=1.01f);
+ PX_ASSERT(steerGain<PxPi);
+
+ const PxF32 steerAngle=steer*steerGain;
+
+ if(0==steerAngle)
+ {
+ *leftAckermannSteerAngle=0;
+ *rightAckermannSteerAngle=0;
+ return;
+ }
+
+ //Work out the ackermann steer for +ve steer then swap and negate the steer angles if the steer is -ve.
+ //TODO: use faster approximate functions for PxTan/PxATan because the results don't need to be too accurate here.
+ const PxF32 rightSteerAngle=PxAbs(steerAngle);
+ const PxF32 dz=axleSeparation;
+ const PxF32 dx=width + dz/PxTan(rightSteerAngle);
+ const PxF32 leftSteerAnglePerfect=PxAtan(dz/dx);
+ const PxF32 leftSteerAngle=rightSteerAngle + ackermannAccuracy*(leftSteerAnglePerfect-rightSteerAngle);
+ *rightAckermannSteerAngle=physx::intrinsics::fsel(steerAngle, rightSteerAngle, -leftSteerAngle);
+ *leftAckermannSteerAngle=physx::intrinsics::fsel(steerAngle, leftSteerAngle, -rightSteerAngle);
+}
+
+PX_FORCE_INLINE void computeAckermannCorrectedSteerAngles
+(const PxVehicleDriveSimData4W& driveSimData, const PxVehicleWheels4SimData& wheelsSimData, const PxF32 steer,
+ PxF32* PX_RESTRICT steerAngles)
+{
+ const PxVehicleAckermannGeometryData& ackermannData=driveSimData.getAckermannGeometryData();
+ const PxF32 ackermannAccuracy=ackermannData.mAccuracy;
+ const PxF32 axleSeparation=ackermannData.mAxleSeparation;
+
+ {
+ const PxVehicleWheelData& wheelDataFL=wheelsSimData.getWheelData(PxVehicleDrive4WWheelOrder::eFRONT_LEFT);
+ const PxVehicleWheelData& wheelDataFR=wheelsSimData.getWheelData(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT);
+ const PxF32 steerGainFront=PxMax(wheelDataFL.mMaxSteer,wheelDataFR.mMaxSteer);
+ const PxF32 frontWidth=ackermannData.mFrontWidth;
+ PxF32 frontLeftSteer,frontRightSteer;
+ computeAckermannSteerAngles(steer,steerGainFront,ackermannAccuracy,frontWidth,axleSeparation,&frontLeftSteer,&frontRightSteer);
+ steerAngles[PxVehicleDrive4WWheelOrder::eFRONT_LEFT]=wheelDataFL.mToeAngle+frontLeftSteer;
+ steerAngles[PxVehicleDrive4WWheelOrder::eFRONT_RIGHT]=wheelDataFR.mToeAngle+frontRightSteer;
+ }
+
+ {
+ const PxVehicleWheelData& wheelDataRL=wheelsSimData.getWheelData(PxVehicleDrive4WWheelOrder::eREAR_LEFT);
+ const PxVehicleWheelData& wheelDataRR=wheelsSimData.getWheelData(PxVehicleDrive4WWheelOrder::eREAR_RIGHT);
+ const PxF32 steerGainRear=PxMax(wheelDataRL.mMaxSteer,wheelDataRR.mMaxSteer);
+ const PxF32 rearWidth=ackermannData.mRearWidth;
+ PxF32 rearLeftSteer,rearRightSteer;
+ computeAckermannSteerAngles(steer,steerGainRear,ackermannAccuracy,rearWidth,axleSeparation,&rearLeftSteer,&rearRightSteer);
+ steerAngles[PxVehicleDrive4WWheelOrder::eREAR_LEFT]=wheelDataRL.mToeAngle-rearLeftSteer;
+ steerAngles[PxVehicleDrive4WWheelOrder::eREAR_RIGHT]=wheelDataRR.mToeAngle-rearRightSteer;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Compute the wheel active states
+////////////////////////////////////////////////////////////////////////////
+
+PX_FORCE_INLINE void computeWheelActiveStates(const PxU32 startId, PxU32* bitmapBuffer, bool* activeStates)
+{
+ PX_ASSERT(!activeStates[0] && !activeStates[1] && !activeStates[2] && !activeStates[3]);
+
+ BitMap bm;
+ bm.setWords(bitmapBuffer, ((PX_MAX_NB_WHEELS + 31) & ~31) >> 5);
+
+ if(bm.test(startId + 0))
+ {
+ activeStates[0]=true;
+ }
+ if(bm.test(startId + 1))
+ {
+ activeStates[1]=true;
+ }
+ if(bm.test(startId + 2))
+ {
+ activeStates[2]=true;
+ }
+ if(bm.test(startId + 3))
+ {
+ activeStates[3]=true;
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+//Compute the brake and handbrake torques for different vehicle types.
+//Also compute a boolean for each tire to know if the brake is applied or not.
+//Can't use a single function for all types because not all vehicle types have
+//handbrakes and the brake control mechanism is different for different vehicle
+//types.
+////////////////////////////////////////////////////////////////////////////
+
+PX_FORCE_INLINE void computeNoDriveBrakeTorques
+(const PxVehicleWheelData* PX_RESTRICT wheelDatas, const PxF32* PX_RESTRICT wheelOmegas, const PxF32* PX_RESTRICT rawBrakeTroques,
+ PxF32* PX_RESTRICT brakeTorques, bool* PX_RESTRICT isBrakeApplied)
+{
+ PX_UNUSED(wheelDatas);
+
+ const PxF32 sign0=computeSign(wheelOmegas[0]);
+ brakeTorques[0]=(-sign0*rawBrakeTroques[0]);
+ isBrakeApplied[0]=(rawBrakeTroques[0]!=0);
+
+ const PxF32 sign1=computeSign(wheelOmegas[1]);
+ brakeTorques[1]=(-sign1*rawBrakeTroques[1]);
+ isBrakeApplied[1]=(rawBrakeTroques[1]!=0);
+
+ const PxF32 sign2=computeSign(wheelOmegas[2]);
+ brakeTorques[2]=(-sign2*rawBrakeTroques[2]);
+ isBrakeApplied[2]=(rawBrakeTroques[2]!=0);
+
+ const PxF32 sign3=computeSign(wheelOmegas[3]);
+ brakeTorques[3]=(-sign3*rawBrakeTroques[3]);
+ isBrakeApplied[3]=(rawBrakeTroques[3]!=0);
+}
+
+PX_FORCE_INLINE void computeBrakeAndHandBrakeTorques
+(const PxVehicleWheelData* PX_RESTRICT wheelDatas, const PxF32* PX_RESTRICT wheelOmegas, const PxF32 brake, const PxF32 handbrake,
+ PxF32* PX_RESTRICT brakeTorques, bool* isBrakeApplied)
+{
+ //At zero speed offer no brake torque allowed.
+
+ const PxF32 sign0=computeSign(wheelOmegas[0]);
+ brakeTorques[0]=(-brake*sign0*wheelDatas[0].mMaxBrakeTorque-handbrake*sign0*wheelDatas[0].mMaxHandBrakeTorque);
+ isBrakeApplied[0]=((brake*wheelDatas[0].mMaxBrakeTorque+handbrake*wheelDatas[0].mMaxHandBrakeTorque)!=0);
+
+ const PxF32 sign1=computeSign(wheelOmegas[1]);
+ brakeTorques[1]=(-brake*sign1*wheelDatas[1].mMaxBrakeTorque-handbrake*sign1*wheelDatas[1].mMaxHandBrakeTorque);
+ isBrakeApplied[1]=((brake*wheelDatas[1].mMaxBrakeTorque+handbrake*wheelDatas[1].mMaxHandBrakeTorque)!=0);
+
+ const PxF32 sign2=computeSign(wheelOmegas[2]);
+ brakeTorques[2]=(-brake*sign2*wheelDatas[2].mMaxBrakeTorque-handbrake*sign2*wheelDatas[2].mMaxHandBrakeTorque);
+ isBrakeApplied[2]=((brake*wheelDatas[2].mMaxBrakeTorque+handbrake*wheelDatas[2].mMaxHandBrakeTorque)!=0);
+
+ const PxF32 sign3=computeSign(wheelOmegas[3]);
+ brakeTorques[3]=(-brake*sign3*wheelDatas[3].mMaxBrakeTorque-handbrake*sign3*wheelDatas[3].mMaxHandBrakeTorque);
+ isBrakeApplied[3]=((brake*wheelDatas[3].mMaxBrakeTorque+handbrake*wheelDatas[3].mMaxHandBrakeTorque)!=0);
+}
+
+PX_FORCE_INLINE void computeTankBrakeTorques
+(const PxVehicleWheelData* PX_RESTRICT wheelDatas, const PxF32* PX_RESTRICT wheelOmegas, const PxF32 brakeLeft, const PxF32 brakeRight,
+ PxF32* PX_RESTRICT brakeTorques, bool* isBrakeApplied)
+{
+ //At zero speed offer no brake torque allowed.
+
+ const PxF32 sign0=computeSign(wheelOmegas[0]);
+ brakeTorques[0]=(-brakeLeft*sign0*wheelDatas[0].mMaxBrakeTorque);
+ isBrakeApplied[0]=((brakeLeft*wheelDatas[0].mMaxBrakeTorque)!=0);
+
+ const PxF32 sign1=computeSign(wheelOmegas[1]);
+ brakeTorques[1]=(-brakeRight*sign1*wheelDatas[1].mMaxBrakeTorque);
+ isBrakeApplied[1]=((brakeRight*wheelDatas[1].mMaxBrakeTorque)!=0);
+
+ const PxF32 sign2=computeSign(wheelOmegas[2]);
+ brakeTorques[2]=(-brakeLeft*sign2*wheelDatas[2].mMaxBrakeTorque);
+ isBrakeApplied[2]=((brakeLeft*wheelDatas[2].mMaxBrakeTorque)!=0);
+
+ const PxF32 sign3=computeSign(wheelOmegas[3]);
+ brakeTorques[3]=(-brakeRight*sign3*wheelDatas[3].mMaxBrakeTorque);
+ isBrakeApplied[3]=((brakeRight*wheelDatas[3].mMaxBrakeTorque)!=0);
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+//Functions to compute inputs to tire force calculation.
+//1. Filter the normalised tire load to smooth any spikes in load.
+//2. Compute the tire lat and long directions in the ground plane.
+//3. Compute the tire lat and long slips.
+//4. Compute the friction from a graph of friction vs slip.
+////////////////////////////////////////////////////////////////////////////
+
+PX_FORCE_INLINE PxF32 computeFilteredNormalisedTireLoad(const PxVehicleTireLoadFilterData& filterData, const PxF32 normalisedLoad)
+{
+ if(normalisedLoad <= filterData.mMinNormalisedLoad)
+ {
+ return filterData.mMinFilteredNormalisedLoad;
+ }
+ else if(normalisedLoad >= filterData.mMaxNormalisedLoad)
+ {
+ return filterData.mMaxFilteredNormalisedLoad;
+ }
+ else
+ {
+ const PxF32 x=normalisedLoad;
+ const PxF32 xmin=filterData.mMinNormalisedLoad;
+ const PxF32 ymin=filterData.mMinFilteredNormalisedLoad;
+ const PxF32 ymax=filterData.mMaxFilteredNormalisedLoad;
+ const PxF32 recipXmaxMinusXMin=filterData.getDenominator();
+ return (ymin + (x-xmin)*(ymax-ymin)*recipXmaxMinusXMin);
+ }
+}
+
+PX_FORCE_INLINE void computeTireDirs(const PxVec3& chassisLatDir, const PxVec3& hitNorm, const PxF32 wheelSteerAngle, PxVec3& tireLongDir, PxVec3& tireLatDir)
+{
+ PX_ASSERT(chassisLatDir.magnitude()>0.999f && chassisLatDir.magnitude()<1.001f);
+ PX_ASSERT(hitNorm.magnitude()>0.999f && hitNorm.magnitude()<1.001f);
+
+ //Compute the tire axes in the ground plane.
+ PxVec3 tzRaw=chassisLatDir.cross(hitNorm);
+ PxVec3 txRaw=hitNorm.cross(tzRaw);
+ tzRaw.normalize();
+ txRaw.normalize();
+ //Rotate the tire using the steer angle.
+ const PxF32 cosWheelSteer=PxCos(wheelSteerAngle);
+ const PxF32 sinWheelSteer=PxSin(wheelSteerAngle);
+ const PxVec3 tz=tzRaw*cosWheelSteer + txRaw*sinWheelSteer;
+ const PxVec3 tx=txRaw*cosWheelSteer - tzRaw*sinWheelSteer;
+ tireLongDir=tz;
+ tireLatDir=tx;
+}
+
+PX_FORCE_INLINE void computeTireSlips
+(const PxF32 longSpeed, const PxF32 latSpeed, const PxF32 wheelOmega, const PxF32 wheelRadius, const PxF32 maxDenominator,
+ const bool isAccelApplied, const bool isBrakeApplied,
+ const bool isTank,
+ PxF32& longSlip, PxF32& latSlip)
+{
+ PX_ASSERT(maxDenominator>=0.0f);
+
+ const PxF32 longSpeedAbs=PxAbs(longSpeed);
+ const PxF32 wheelSpeed=wheelOmega*wheelRadius;
+ const PxF32 wheelSpeedAbs=PxAbs(wheelSpeed);
+
+ //Lateral slip is easy.
+ latSlip = PxAtan(latSpeed/(longSpeedAbs+gMinLatSpeedForTireModel));//TODO: do we really use PxAbs(vz) as denominator?
+
+ //If nothing is moving just avoid a divide by zero and set the long slip to zero.
+ if(longSpeed==0 && wheelOmega==0)
+ {
+ longSlip=0.0f;
+ return;
+ }
+
+ //Longitudinal slip is a bit harder because we can end up wtih zero on the denominator.
+ if(isTank)
+ {
+ if(isBrakeApplied || isAccelApplied)
+ {
+ //Wheel experiencing an applied torque.
+ //Use the raw denominator value plus an offset to avoid anything approaching a divide by zero.
+ //When accelerating from rest the small denominator will generate really quite large
+ //slip values, which will, in turn, generate large longitudinal forces. With large
+ //time-steps this might lead to a temporary oscillation in longSlip direction and an
+ //oscillation in wheel speed direction. The amplitude of the oscillation should be low
+ //unless the timestep is really large.
+ //There's not really an obvious solution to this without setting the denominator offset higher
+ //(or decreasing the timestep). Setting the denominator higher affects handling everywhere so
+ //settling for a potential temporary oscillation is probably the least worst compromise.
+ //Note that we always use longSpeedAbs as denominator because in order to turn on the spot the
+ //tank needs to get strong longitudinal force when it isn't moving but the wheels are slipping.
+ longSlip = (wheelSpeed - longSpeed)/(longSpeedAbs + 0.1f*gToleranceScaleLength);
+ }
+ else
+ {
+ //Wheel not experiencing an applied torque.
+ //If the denominator becomes too small then the longSlip becomes large and the longitudinal force
+ //can overshoot zero at large timesteps. This can be really noticeable so it's harder to justify
+ //not taking action. Further, the car isn't being actually driven so there is a strong case to fiddle
+ //with the denominator because it doesn't really affect active handling.
+ //Don't let the denominator fall below a user-specified value. This can be tuned upwards until the
+ //oscillation in the sign of longSlip disappears.
+ longSlip = (wheelSpeed - longSpeed)/(PxMax(maxDenominator, PxMax(longSpeedAbs,wheelSpeedAbs)));
+ }
+ }
+ else
+ {
+ if(isBrakeApplied || isAccelApplied)
+ {
+ //Wheel experiencing an applied torque.
+ //Use the raw denominator value plus an offset to avoid anything approaching a divide by zero.
+ //When accelerating from rest the small denominator will generate really quite large
+ //slip values, which will, in turn, generate large longitudinal forces. With large
+ //time-steps this might lead to a temporary oscillation in longSlip direction and an
+ //oscillation in wheel speed direction. The amplitude of the oscillation should be low
+ //unless the timestep is really large.
+ //There's not really an obvious solution to this without setting the denominator offset higher
+ //(or decreasing the timestep). Setting the denominator higher affects handling everywhere so
+ //settling for a potential temporary oscillation is probably the least worst compromise.
+ longSlip = (wheelSpeed - longSpeed)/(PxMax(longSpeedAbs,wheelSpeedAbs)+0.1f*gToleranceScaleLength);
+ }
+ else
+ {
+ //Wheel not experiencing an applied torque.
+ //If the denominator becomes too small then the longSlip becomes large and the longitudinal force
+ //can overshoot zero at large timesteps. This can be really noticeable so it's harder to justify
+ //not taking action. Further, the car isn't being actually driven so there is a strong case to fiddle
+ //with the denominator because it doesn't really affect active handling.
+ //Don't let the denominator fall below a user-specified value. This can be tuned upwards until the
+ //oscillation in the sign of longSlip disappears.
+ longSlip = (wheelSpeed - longSpeed)/(PxMax(maxDenominator,PxMax(longSpeedAbs,wheelSpeedAbs)));
+ }
+ }
+}
+
+PX_FORCE_INLINE void computeTireFriction(const PxVehicleTireData& tireData, const PxF32 longSlip, const PxF32 frictionMultiplier, PxF32& friction)
+{
+ const PxF32 x0=tireData.mFrictionVsSlipGraph[0][0];
+ const PxF32 y0=tireData.mFrictionVsSlipGraph[0][1];
+ const PxF32 x1=tireData.mFrictionVsSlipGraph[1][0];
+ const PxF32 y1=tireData.mFrictionVsSlipGraph[1][1];
+ const PxF32 x2=tireData.mFrictionVsSlipGraph[2][0];
+ const PxF32 y2=tireData.mFrictionVsSlipGraph[2][1];
+ const PxF32 recipx1Minusx0=tireData.getFrictionVsSlipGraphRecipx1Minusx0();
+ const PxF32 recipx2Minusx1=tireData.getFrictionVsSlipGraphRecipx2Minusx1();
+ const PxF32 longSlipAbs=PxAbs(longSlip);
+ PxF32 mu;
+ if(longSlipAbs<x1)
+ {
+ mu=y0 + (y1-y0)*(longSlipAbs-x0)*recipx1Minusx0;
+ }
+ else if(longSlipAbs<x2)
+ {
+ mu=y1 + (y2-y1)*(longSlipAbs-x1)*recipx2Minusx1;
+ }
+ else
+ {
+ mu=y2;
+ }
+ PX_ASSERT(mu>=0);
+ friction=mu*frictionMultiplier;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Sticky tire constraints.
+//Increment a timer each update that a tire has a very low longitudinal speed.
+//Activate a sticky constraint when the tire has had an unbroken low long speed
+//for at least a threshold time.
+//The longer the sticky constraint is active, the slower the target constraint speed
+//along the long dir. Quickly tends towards zero.
+//When the sticky constraint is activated set the long slip to zero and let
+//the sticky constraint take over.
+////////////////////////////////////////////////////////////////////////////
+
+PX_FORCE_INLINE void updateLowForwardSpeedTimer
+(const PxF32 longSpeed, const PxF32 wheelOmega, const PxF32 wheelRadius, const PxF32 recipWheelRadius, const bool isIntentionToAccelerate,
+ const PxF32 timestep, PxF32& lowForwardSpeedTime)
+{
+ PX_UNUSED(wheelRadius);
+ PX_UNUSED(recipWheelRadius);
+
+ //If the tire is rotating slowly and the forward speed is slow then increment the slow forward speed timer.
+ //If the intention of the driver is to accelerate the vehicle then reset the timer because the intention has been signalled NOT to bring
+ //the wheel to rest.
+ PxF32 longSpeedAbs=PxAbs(longSpeed);
+ if((longSpeedAbs<gStickyTireFrictionThresholdSpeed) && (PxAbs(wheelOmega)< gStickyTireFrictionThresholdSpeed*recipWheelRadius) && !isIntentionToAccelerate)
+ {
+ lowForwardSpeedTime+=timestep;
+ }
+ else
+ {
+ lowForwardSpeedTime=0;
+ }
+}
+
+PX_FORCE_INLINE void updateLowSideSpeedTimer
+(const PxF32 latSpeed, const bool isIntentionToAccelerate, const PxF32 timestep, PxF32& lowSideSpeedTime)
+{
+ //If the side speed is slow then increment the slow side speed timer.
+ //If the intention of the driver is to accelerate the vehicle then reset the timer because the intention has been signalled NOT to bring
+ //the wheel to rest.
+ PxF32 latSpeedAbs=PxAbs(latSpeed);
+ if((latSpeedAbs<gStickyTireFrictionThresholdSpeed) && !isIntentionToAccelerate)
+ {
+ lowSideSpeedTime+=timestep;
+ }
+ else
+ {
+ lowSideSpeedTime=0;
+ }
+}
+
+
+PX_FORCE_INLINE void activateStickyFrictionForwardConstraint
+(const PxF32 longSpeed, const PxF32 wheelOmega, const PxF32 lowForwardSpeedTime, const bool isIntentionToAccelerate,
+ bool& stickyTireActiveFlag, PxF32& stickyTireTargetSpeed)
+{
+ //Setup the sticky friction constraint to bring the vehicle to rest at the tire contact point.
+ //The idea here is to resolve the singularity of the tire long slip at low vz by replacing the long force with a velocity constraint.
+ //Only do this if we can guarantee that the intention is to bring the car to rest (no accel pedal applied).
+ //Smoothly reduce error to zero to avoid bringing car immediately to rest. This avoids graphical glitchiness.
+ //We're going to replace the longitudinal tire force with the sticky friction so set the long slip to zero to ensure zero long force.
+ //Apply sticky friction to this tire if
+ //(1) the wheel is locked (this means the brake/handbrake must be on) and the forward speed at the tire contact point is vanishingly small and
+ // the drive of vehicle has no intention to accelerate the vehicle.
+ //(2) the accumulated time of low forward speed is greater than a threshold.
+ PxF32 longSpeedAbs=PxAbs(longSpeed);
+ stickyTireActiveFlag=false;
+ stickyTireTargetSpeed=0.0f;
+ if((longSpeedAbs < gStickyTireFrictionThresholdSpeed && 0.0f==wheelOmega && !isIntentionToAccelerate) || lowForwardSpeedTime>gLowForwardSpeedThresholdTime)
+ {
+ stickyTireActiveFlag=true;
+ stickyTireTargetSpeed=longSpeed*gStickyTireFrictionForwardDamping;
+ }
+}
+
+PX_FORCE_INLINE void activateStickyFrictionSideConstraint
+(const PxF32 latSpeed, const PxF32 lowSpeedForwardTimer, const PxF32 lowSideSpeedTimer, const bool isIntentionToAccelerate,
+ bool& stickyTireActiveFlag, PxF32& stickyTireTargetSpeed)
+{
+ PX_UNUSED(latSpeed);
+ PX_UNUSED(isIntentionToAccelerate);
+
+ //Setup the sticky friction constraint to bring the vehicle to rest at the tire contact point.
+ //Only do this if we can guarantee that the intention is to bring the car to rest (no accel pedal applied).
+ //Smoothly reduce error to zero to avoid bringing car immediately to rest. This avoids graphical glitchiness.
+ //We're going to replace the lateral tire force with the sticky friction so set the lat slip to zero to ensure zero lat force.
+ //Apply sticky friction to this tire if
+ //(1) the low forward speed timer is > 0.
+ //(2) the accumulated time of low forward speed is greater than a threshold.
+ stickyTireActiveFlag=false;
+ stickyTireTargetSpeed=0.0f;
+ if((lowSpeedForwardTimer > 0) && lowSideSpeedTimer>gLowSideSpeedThresholdTime)
+ {
+ stickyTireActiveFlag=true;
+ stickyTireTargetSpeed=latSpeed*gStickyTireFrictionSideDamping;
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////
+//Default tire force shader function.
+//Taken from Michigan tire model.
+//Computes tire long and lat forces plus the aligning moment arising from
+//the lat force and the torque to apply back to the wheel arising from the
+//long force (application of Newton's 3rd law).
+////////////////////////////////////////////////////////////////////////////
+
+
+#define ONE_TWENTYSEVENTH 0.037037f
+#define ONE_THIRD 0.33333f
+PX_FORCE_INLINE PxF32 smoothingFunction1(const PxF32 K)
+{
+ //Equation 20 in CarSimEd manual Appendix F.
+ //Looks a bit like a curve of sqrt(x) for 0<x<1 but reaching 1.0 on y-axis at K=3.
+ PX_ASSERT(K>=0.0f);
+ return PxMin(1.0f, K - ONE_THIRD*K*K + ONE_TWENTYSEVENTH*K*K*K);
+}
+PX_FORCE_INLINE PxF32 smoothingFunction2(const PxF32 K)
+{
+ //Equation 21 in CarSimEd manual Appendix F.
+ //Rises to a peak at K=0.75 and falls back to zero by K=3
+ PX_ASSERT(K>=0.0f);
+ return (K - K*K + ONE_THIRD*K*K*K - ONE_TWENTYSEVENTH*K*K*K*K);
+}
+
+void PxVehicleComputeTireForceDefault
+(const void* tireShaderData,
+ const PxF32 tireFriction,
+ const PxF32 longSlipUnClamped, const PxF32 latSlipUnClamped, const PxF32 camberUnclamped,
+ const PxF32 wheelOmega, const PxF32 wheelRadius, const PxF32 recipWheelRadius,
+ const PxF32 restTireLoad, const PxF32 normalisedTireLoad, const PxF32 tireLoad,
+ const PxF32 gravity, const PxF32 recipGravity,
+ PxF32& wheelTorque, PxF32& tireLongForceMag, PxF32& tireLatForceMag, PxF32& tireAlignMoment)
+{
+ PX_UNUSED(wheelOmega);
+ PX_UNUSED(recipWheelRadius);
+
+ const PxVehicleTireData& tireData=*reinterpret_cast<const PxVehicleTireData*>(tireShaderData);
+
+ PX_ASSERT(tireFriction>0);
+ PX_ASSERT(tireLoad>0);
+
+ wheelTorque=0.0f;
+ tireLongForceMag=0.0f;
+ tireLatForceMag=0.0f;
+ tireAlignMoment=0.0f;
+
+ //Clamp the slips to a minimum value.
+ const PxF32 latSlip = PxAbs(latSlipUnClamped) >= gMinimumSlipThreshold ? latSlipUnClamped : 0.0f;
+ const PxF32 longSlip = PxAbs(longSlipUnClamped) >= gMinimumSlipThreshold ? longSlipUnClamped : 0.0f;
+ const PxF32 camber = PxAbs(camberUnclamped) >= gMinimumSlipThreshold ? camberUnclamped : 0.0f;
+
+ //If long slip/lat slip/camber are all zero than there will be zero tire force.
+ if((0==latSlip)&&(0==longSlip)&&(0==camber))
+ {
+ return;
+ }
+
+ //Compute the lateral stiffness
+ const PxF32 latStiff=restTireLoad*tireData.mLatStiffY*smoothingFunction1(normalisedTireLoad*3.0f/tireData.mLatStiffX);
+
+ //Get the longitudinal stiffness
+ const PxF32 longStiff=tireData.mLongitudinalStiffnessPerUnitGravity*gravity;
+ const PxF32 recipLongStiff=tireData.getRecipLongitudinalStiffnessPerUnitGravity()*recipGravity;
+
+ //Get the camber stiffness.
+ const PxF32 camberStiff=tireData.mCamberStiffnessPerUnitGravity*gravity;
+
+ //Carry on and compute the forces.
+ const PxF32 TEff = PxTan(latSlip - camber*camberStiff/latStiff);
+ const PxF32 K = PxSqrt(latStiff*TEff*latStiff*TEff + longStiff*longSlip*longStiff*longSlip) /(tireFriction*tireLoad);
+ //const PxF32 KAbs=PxAbs(K);
+ PxF32 FBar = smoothingFunction1(K);//K - ONE_THIRD*PxAbs(K)*K + ONE_TWENTYSEVENTH*K*K*K;
+ PxF32 MBar = smoothingFunction2(K); //K - KAbs*K + ONE_THIRD*K*K*K - ONE_TWENTYSEVENTH*KAbs*K*K*K;
+ //Mbar = PxMin(Mbar, 1.0f);
+ PxF32 nu=1;
+ if(K <= 2.0f*PxPi)
+ {
+ const PxF32 latOverlLong=latStiff*recipLongStiff;
+ nu = 0.5f*(1.0f + latOverlLong - (1.0f - latOverlLong)*PxCos(K*0.5f));
+ }
+ const PxF32 FZero = tireFriction*tireLoad / (PxSqrt(longSlip*longSlip + nu*TEff*nu*TEff));
+ const PxF32 fz = longSlip*FBar*FZero;
+ const PxF32 fx = -nu*TEff*FBar*FZero;
+ //TODO: pneumatic trail.
+ const PxF32 pneumaticTrail=1.0f;
+ const PxF32 fMy= nu * pneumaticTrail * TEff * MBar * FZero;
+
+ //We can add the torque to the wheel.
+ wheelTorque=-fz*wheelRadius;
+ tireLongForceMag=fz;
+ tireLatForceMag=fx;
+ tireAlignMoment=fMy;
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+//Functions required to intersect the wheel with the hit plane
+//We support raycasts and sweeps.
+////////////////////////////////////////////////////////////////////////////
+
+bool intersectRayPlane
+(const PxTransform& carChassisTrnsfm,
+ const PxVec3& bodySpaceWheelCentreOffset, const PxVec3& bodySpaceSuspTravelDir,
+ const PxF32 width, const PxF32 radius, const PxF32 maxCompression,
+ const PxVec4& hitPlane,
+ PxF32& jounce, PxVec3& wheelBottomPos)
+{
+ const PxVec3 hitNorm = PxVec3(hitPlane.x, hitPlane.y, hitPlane.z);
+
+ //Compute the raycast start pos and direction.
+ PxVec3 v, w;
+ computeSuspensionRaycast(carChassisTrnsfm, bodySpaceWheelCentreOffset, bodySpaceSuspTravelDir, radius, maxCompression, v, w);
+
+ //If the raycast starts inside the hit plane then return false
+ if(hitPlane.x*v.x + hitPlane.y*v.y + hitPlane.z*v.z + hitPlane.w < 0.0f)
+ {
+ return false;
+ }
+
+ //Store a point through the centre of the wheel.
+ //We'll use this later to compute a position at the bottom of the wheel.
+ const PxVec3 pos = v;
+
+ //Work out if the inner or outer disc is deeper in the plane.
+ const PxVec3 latDir = carChassisTrnsfm.rotate(gRight);
+ const PxF32 signDot = computeSign(hitNorm.dot(latDir));
+ v -= latDir*(signDot*0.5f*width);
+
+ //Work out the point on the susp line that touches the intersection plane.
+ //n.(v+wt)+d=0 where n,d describe the plane; v,w describe the susp ray; t is the point on the susp line.
+ //t=-(n.v + d)/n.w
+ const PxF32 hitD = hitPlane.w;
+ const PxVec3& n = hitNorm;
+ const PxF32 d = hitD;
+ const PxF32 T=-(n.dot(v) + d)/(n.dot(w));
+
+ //The rest pos of the susp line is 2*radius + maxBounce.
+ const PxF32 restT = 2.0f*radius+maxCompression;
+
+ //Compute the spring compression ie the difference between T and restT.
+ //+ve means that the spring is compressed
+ //-ve means that the spring is elongated.
+ jounce = restT-T;
+
+ //Compute the bottom of the wheel.
+ //Always choose a point through the centre of the wheel.
+ wheelBottomPos = pos + w*(restT - jounce);
+
+ return true;
+}
+
+bool intersectPlanes(const PxVec4& a, const PxVec4& b, PxVec3& v, PxVec3& w)
+{
+ const PxF32 n1x = a.x;
+ const PxF32 n1y = a.y;
+ const PxF32 n1z = a.z;
+ const PxF32 n1d = a.w;
+
+ const PxF32 n2x = b.x;
+ const PxF32 n2y = b.y;
+ const PxF32 n2z = b.z;
+ const PxF32 n2d = b.w;
+
+ PxF32 dx = (n1y * n2z) - (n1z * n2y);
+ PxF32 dy = (n1z * n2x) - (n1x * n2z);
+ PxF32 dz = (n1x * n2y) - (n1y * n2x);
+
+ const PxF32 dx2 = dx * dx;
+ const PxF32 dy2 = dy * dy;
+ const PxF32 dz2 = dz * dz;
+
+ PxF32 px, py, pz;
+ bool success = true;
+ if ((dz2 > dy2) && (dz2 > dx2) && (dz2 > 0))
+ {
+ px = ((n1y * n2d) - (n2y * n1d)) / dz;
+ py = ((n2x * n1d) - (n1x * n2d)) / dz;
+ pz = 0;
+ }
+ else if ((dy2 > dx2) && (dy2 > 0))
+ {
+ px = -((n1z * n2d) - (n2z * n1d)) / dy;
+ py = 0;
+ pz = -((n2x * n1d) - (n1x * n2d)) / dy;
+ }
+ else if (dx2 > 0)
+ {
+ px = 0;
+ py = ((n1z * n2d) - (n2z * n1d)) / dx;
+ pz = ((n2y * n1d) - (n1y * n2d)) / dx;
+ }
+ else
+ {
+ px=0;
+ py=0;
+ pz=0;
+ success=false;
+ }
+
+ const PxF32 ld = PxSqrt(dx2 + dy2 + dz2);
+
+ dx /= ld;
+ dy /= ld;
+ dz /= ld;
+
+ w = PxVec3(dx,dy,dz);
+ v = PxVec3(px,py,pz);
+
+ return success;
+}
+
+bool intersectCylinderPlane
+(const PxTransform& wheelPoseAtZeroJounce, const PxVec3 suspDir,
+ const PxF32 width, const PxF32 radius, const PxF32 maxCompression,
+ const PxVec4& hitPlane,
+ const bool rejectFromThresholds,
+ PxF32& jounce, PxVec3& wheelBottomPos)
+{
+ PX_UNUSED(maxCompression);
+ PX_UNUSED(width);
+
+ //Reject based on the contact normal.
+ if (rejectFromThresholds)
+ {
+ if (suspDir.dot(-hitPlane.getXYZ()) < gNormalRejectAngleThreshold)
+ {
+ return false;
+ }
+ }
+
+ //Construct the wheel plane that contains the wheel disc.
+ PxVec4 wheelPlane;
+ {
+ const PxVec3 n = wheelPoseAtZeroJounce.rotate(gRight);
+ const PxF32 d = - n.dot(wheelPoseAtZeroJounce.p);
+ wheelPlane.x = n.x;
+ wheelPlane.y = n.y;
+ wheelPlane.z = n.z;
+ wheelPlane.w = d;
+ }
+
+ //Intersect the plane of the wheel with the hit plane.
+ //This generates an intersection edge.
+ PxVec3 intersectionEdgeV, intersectionEdgeW;
+ const bool intersectPlaneSuccess = intersectPlanes(wheelPlane, hitPlane, intersectionEdgeV, intersectionEdgeW);
+ if(!intersectPlaneSuccess)
+ {
+ jounce = 0.0f;
+ wheelBottomPos = PxVec3(0,0,0);
+ return false;
+ }
+
+ //Compute the position on the intersection edge that is closest to the wheel centre.
+ PxVec3 closestPointOnIntersectionEdge;
+ {
+ const PxVec3& p = wheelPoseAtZeroJounce.p;
+ const PxVec3& w = intersectionEdgeW;
+ const PxVec3& v = intersectionEdgeV;
+ const PxF32 t = (p - v).dot(w);
+ closestPointOnIntersectionEdge = v + w*t;
+ }
+
+ //Compute the vector that joins the wheel centre to the intersection edge;
+ PxVec3 dir;
+ {
+ const PxF32 wheelCentreD = hitPlane.x*wheelPoseAtZeroJounce.p.x + hitPlane.y*wheelPoseAtZeroJounce.p.y + hitPlane.z*wheelPoseAtZeroJounce.p.z + hitPlane.w;
+ dir = ((wheelCentreD >= 0) ? closestPointOnIntersectionEdge - wheelPoseAtZeroJounce.p : wheelPoseAtZeroJounce.p - closestPointOnIntersectionEdge);
+ dir.normalize();
+ }
+
+ //Now work out if we accept the hit.
+ //Compare dir with the suspension direction.
+ if (rejectFromThresholds)
+ {
+ if (suspDir.dot(dir) < gPointRejectAngleThreshold)
+ {
+ return false;
+ }
+ }
+
+ //Compute the point on the disc diameter that will be the closest to the hit plane or the deepest inside the hit plane.
+ PxVec3 pos;
+ {
+ pos = wheelPoseAtZeroJounce.p + dir*radius;
+ }
+
+ //If the sweep started inside the hit plane then return false
+ const PxVec3 startPos = pos - suspDir*(radius + maxCompression);
+ if(hitPlane.x*startPos.x + hitPlane.y*startPos.y + hitPlane.z*startPos.z + hitPlane.w < 0.0f)
+ {
+ return false;
+ }
+
+ //Now compute the maximum depth of the inside and outside discs against the plane.
+ PxF32 depth;
+ {
+ const PxVec3 latDir = wheelPoseAtZeroJounce.rotate(gRight);
+ const PxF32 signDot = computeSign(hitPlane.x*latDir.x + hitPlane.y*latDir.y + hitPlane.z*latDir.z);
+ const PxVec3 deepestPos = pos - latDir*(signDot*0.5f*width);
+ depth = hitPlane.x*deepestPos.x + hitPlane.y*deepestPos.y + hitPlane.z*deepestPos.z + hitPlane.w;
+ }
+
+
+ //How far along the susp dir do we have to move to place the wheel exactly on the plane.
+ const PxF32 t = -depth/(hitPlane.x*suspDir.x + hitPlane.y*suspDir.y + hitPlane.z*suspDir.z);
+
+ //+ve means that the spring is compressed
+ //-ve means that the spring is elongated.
+ jounce = -t;
+
+ //Compute a point at the bottom of the wheel that is at the centre.
+ wheelBottomPos = pos + suspDir*t;
+
+ //Finished.
+ return true;
+}
+
+bool intersectCylinderPlane
+(const PxTransform& carChassisTrnsfm,
+ const PxQuat& wheelLocalPoseRotation, const PxF32 wheelTheta,
+ const PxVec3& bodySpaceWheelCentreOffset, const PxVec3& bodySpaceSuspTravelDir, const PxF32 width, const PxF32 radius, const PxF32 maxCompression,
+ const PxVec4& hitPlane,
+ const bool rejectFromThresholds,
+ PxF32& jounce, PxVec3& wheelBottomPos)
+{
+ //Compute the pose of the wheel
+ PxTransform wheelPostsAtZeroJounce;
+ PxVec3 suspDir;
+ computeSuspensionSweep(
+ carChassisTrnsfm,
+ wheelLocalPoseRotation, wheelTheta,
+ bodySpaceWheelCentreOffset, bodySpaceSuspTravelDir, 0.0f, 0.0f,
+ wheelPostsAtZeroJounce, suspDir);
+
+ //Perform the intersection.
+ return intersectCylinderPlane
+ (wheelPostsAtZeroJounce, suspDir,
+ width, radius, maxCompression,
+ hitPlane,
+ rejectFromThresholds,
+ jounce, wheelBottomPos);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Structures used to process blocks of 4 wheels: process the raycast result,
+//compute the suspension and tire force, store a number of report variables
+//such as tire slip, hit shape, hit material, friction etc.
+////////////////////////////////////////////////////////////////////////////
+
+class PxVehicleTireForceCalculator4
+{
+public:
+
+ const void* mShaderData[4];
+ PxVehicleComputeTireForce mShader;
+private:
+};
+
+//This data structure is passed to processSuspTireWheels
+//and represents the data that is logically constant across all sub-steps of each dt update.
+struct ProcessSuspWheelTireConstData
+{
+ //We are integrating dt over N sub-steps.
+ //timeFraction is 1/N.
+ PxF32 timeFraction;
+ //We are integrating dt over N sub-steps.
+ //subTimeStep is dt/N.
+ PxF32 subTimeStep;
+ PxF32 recipSubTimeStep;
+
+ //Gravitational acceleration vector
+ PxVec3 gravity;
+ //Length of gravitational acceleration vector (saves a square root each time we need it)
+ PxF32 gravityMagnitude;
+ //Reciprocal length of gravitational acceleration vector (saves a square root and divide each time we need it).
+ PxF32 recipGravityMagnitude;
+
+ //True for tanks, false for all other vehicle types.
+ //Used when computing the longitudinal and lateral slips.
+ bool isTank;
+
+ //Minimum denominator allowed in longitudinal slip computation.
+ PxF32 minLongSlipDenominator;
+
+ //Pointer to physx actor that represents the vehicle.
+ const PxRigidDynamic* vehActor;
+
+ //Pointer to table of friction values for each combination of material and tire type.
+ const PxVehicleDrivableSurfaceToTireFrictionPairs* frictionPairs;
+};
+
+//This data structure is passed to processSuspTireWheels
+//and represents the data that is physically constant across each sub-steps of each dt update.
+struct ProcessSuspWheelTireInputData
+{
+public:
+
+ //True if the driver intends to pass drive torque to any wheel of the vehicle,
+ //even if none of the wheels in the block of 4 wheels processed in processSuspTireWheels are given drive torque.
+ //False if the driver does not intend the vehicle to accelerate.
+ //If the player intends to accelerate then no wheel will be given a sticky tire constraint.
+ //This data is actually logically constant.
+ bool isIntentionToAccelerate;
+
+ //True if a wheel has a non-zero diff torque, false if a wheel has zero diff torque.
+ //This data is actually logically constant.
+ const bool* isAccelApplied;
+
+ //True if a wheel has a non-zero brake torque, false if a wheel has zero brake torque.
+ //This data is actually logically constant.
+ const bool* isBrakeApplied;
+
+ //Steer angles of each wheel in radians.
+ //This data is actually logically constant.
+ const PxF32* steerAngles;
+
+ //True if the wheel is not disabled, false if wheel is disabled.
+ //This data is actually logically constant.
+ bool* activeWheelStates;
+
+ //Properties of the rigid body - transform.
+ //This data is actually logically constant.
+ PxTransform carChassisTrnsfm;
+ //Properties of the rigid body - linear velocity.
+ //This data is actually logically constant.
+ PxVec3 carChassisLinVel;
+ //Properties of the rigid body - angular velocity
+ //This data is actually logically constant.
+ PxVec3 carChassisAngVel;
+
+ //Properties of the wheel shapes at the last sweep.
+ const PxQuat* wheelLocalPoseRotations;
+ const PxF32* wheelThetas;
+
+ //Simulation data for the 4 wheels being processed in processSuspTireWheels
+ //This data is actually logically constant.
+ const PxVehicleWheels4SimData* vehWheels4SimData;
+
+ //Dynamics data for the 4 wheels being processed in processSuspTireWheels
+ //This data is a mixture of logically and physically constant.
+ //We could update some of the data in vehWheels4DynData in processSuspTireWheels
+ //but we choose to do it after. By specifying the non-constant data members explicitly
+ //in ProcessSuspWheelTireOutputData we are able to more easily keep a track of the
+ //constant and non-constant data members. After processSuspTireWheels is complete
+ //we explicitly transfer the updated data in ProcessSuspWheelTireOutputData to vehWheels4DynData.
+ //Examples are low long and lat forward speed timers.
+ const PxVehicleWheels4DynData* vehWheels4DynData;
+
+ //Shaders to calculate the tire forces.
+ //This data is actually logically constant.
+ const PxVehicleTireForceCalculator4* vehWheels4TireForceCalculator;
+
+ //Filter function to filter tire load.
+ //This data is actually logically constant.
+ const PxVehicleTireLoadFilterData* vehWheels4TireLoadFilterData;
+
+ //How many of the 4 wheels are real wheels (eg a 6-wheeled car has a
+ //block of 4 wheels then a 2nd block of 4 wheels with only 2 active wheels)
+ //This data is actually logically constant.
+ PxU32 numActiveWheels;
+};
+
+struct ProcessSuspWheelTireOutputData
+{
+public:
+
+ ProcessSuspWheelTireOutputData()
+ {
+ PxMemZero(this, sizeof(ProcessSuspWheelTireOutputData));
+ for(PxU32 i=0;i<4;i++)
+ {
+ isInAir[i]=true;
+ tireSurfaceTypes[i]=PxU32(PxVehicleDrivableSurfaceType::eSURFACE_TYPE_UNKNOWN);
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //The following data is stored so that it may be later passed to PxVehicleWheelQueryResult
+ /////////////////////////////////////////////////////////////////////////////////////////////
+
+ //Raycast start [most recent raycast start coord or (0,0,0) if using a cached raycast]
+ PxVec3 suspLineStarts[4];
+ //Raycast start [most recent raycast direction or (0,0,0) if using a cached raycast]
+ PxVec3 suspLineDirs[4];
+ //Raycast start [most recent raycast length or 0 if using a cached raycast]
+ PxF32 suspLineLengths[4];
+ //False if wheel cannot touch the ground.
+ bool isInAir[4];
+ //Actor hit by most recent raycast, NULL if using a cached raycast.
+ PxActor* tireContactActors[4];
+ //Shape hit by most recent raycast, NULL if using a cached raycast.
+ PxShape* tireContactShapes[4];
+ //Material hit by most recent raycast, NULL if using a cached raycast.
+ PxMaterial* tireSurfaceMaterials[4];
+ //Surface type of material hit by most recent raycast, eSURFACE_TYPE_UNKNOWN if using a cached raycast.
+ PxU32 tireSurfaceTypes[4];
+ //Contact point of raycast against either fresh contact plane from fresh raycast or cached contact plane.
+ PxVec3 tireContactPoints[4];
+ //Contact normal of raycast against either fresh contact plane from fresh raycast or cached contact plane.
+ PxVec3 tireContactNormals[4];
+ //Friction experienced by tire (value from friction table for surface/tire type combos multiplied by friction vs slip graph)
+ PxF32 frictions[4];
+ //Jounce experienced by suspension against fresh or cached contact plane.
+ PxF32 jounces[4];
+ //Suspension force to be applied to rigid body.
+ PxF32 suspensionSpringForces[4];
+ //Longitudinal direction of tire in the ground contact plane.
+ PxVec3 tireLongitudinalDirs[4];
+ //Lateral direction of tire in the ground contact plane.
+ PxVec3 tireLateralDirs[4];
+ //Longitudinal slip.
+ PxF32 longSlips[4];
+ //Lateral slip.
+ PxF32 latSlips[4];
+
+ //Forward speed of rigid body along tire longitudinal direction at tire base.
+ //Used later to blend the integrated wheel rotation angle between rolling speed and computed speed
+ //when the wheel rotation speeds become unreliable at low forward speeds.
+ PxF32 forwardSpeeds[4];
+
+ //Torque to be applied to wheel as 1d rigid body. Taken from the longitudinal tire force.
+ //(Newton's 3rd law means the longitudinal tire force must have an equal and opposite force).
+ //(The lateral tire force is assumed to be absorbed by the suspension geometry).
+ PxF32 tireTorques[4];
+
+ //Force to be applied to rigid body (accumulated across all 4 wheels/tires/suspensions).
+ PxVec3 chassisForce;
+ //Torque to be applied to rigid body (accumulated across all 4 wheels/tires/suspensions).
+ PxVec3 chassisTorque;
+
+ //Updated time spend at low forward speed.
+ //Needs copied back to vehWheels4DynData
+ PxF32 newLowForwardSpeedTimers[4];
+ //Updated time spend at low lateral speed.
+ //Needs copied back to vehWheels4DynData
+ PxF32 newLowSideSpeedTimers[4];
+
+ //Constraint data for sticky tire constraints and suspension limit constraints.
+ //Needs copied back to vehWheels4DynData
+ PxVehicleConstraintShader::VehicleConstraintData vehConstraintData;
+
+ //Store the details of the raycast hit results so that they may be re-used
+ //next update in the event that no raycast is performed.
+ //If no raycast was performed then the cached values are just re-copied here
+ //so that they can be recycled without having to do further tests on whether
+ //raycasts were performed or not.
+ //Needs copied back to vehWheels4DynData after the last call to processSuspTireWheels.
+ //The union of cached hit data and susp raycast data means we don't want to overwrite the
+ //raycast data until we don't need it any more.
+ PxU32 cachedHitCounts[4];
+ PxVec4 cachedHitPlanes[4];
+ PxF32 cachedHitDistances[4];
+ PxF32 cachedFrictionMultipliers[4];
+ PxU16 cachedHitQueryTypes[4];
+
+ //Store the details of the force applied to any dynamic actor hit by wheel raycasts.
+ PxRigidDynamic* hitActors[4];
+ PxVec3 hitActorForces[4];
+ PxVec3 hitActorForcePositions[4];
+};
+
+
+
+////////////////////////////////////////////////////////////////////////////
+//Monster function to
+//1. compute the tire/susp forces
+//2. compute the torque to apply to the 1D rigid body wheel arising from the long tire force
+//3. process the sticky tire friction constraints
+// (monitor and increment the low long + lat speed timers, compute data for the sticky tire constraint if necessary)
+//4. process the suspension limit constraints
+// (monitor the suspension jounce versus the suspension travel limit, compute the data for the suspension limit constraint if necessary).
+//5. record the contact plane so that it may be re-used in future updates in the absence of fresh raycasts.
+//6. record telemetry data (if necessary) and record data for reporting such as hit material, hit normal etc.
+////////////////////////////////////////////////////////////////////////////
+
+
+void storeHit
+(const ProcessSuspWheelTireConstData& constData, const ProcessSuspWheelTireInputData& inputData,
+ const PxU16 hitQueryType,
+ const PxLocationHit& hit, const PxVec4& hitPlane,
+ const PxU32 i,
+ PxU32* hitCounts4,
+ PxF32* hitDistances4,
+ PxVec4* hitPlanes4,
+ PxF32* hitFrictionMultipliers4,
+ PxU16* hitQueryTypes4,
+ PxShape** hitContactShapes4,
+ PxRigidActor** hitContactActors4,
+ PxMaterial** hitContactMaterials4,
+ PxU32* hitSurfaceTypes4,
+ PxVec3* hitContactPoints4,
+ PxVec3* hitContactNormals4,
+ PxU32* cachedHitCounts,
+ PxVec4* cachedHitPlanes,
+ PxF32* cachedHitDistances,
+ PxF32* cachedFrictionMultipliers,
+ PxU16* cachedHitQueryTypes)
+{
+ //Hit count.
+ hitCounts4[i] = 1;
+
+ //Hit distance.
+ hitDistances4[i] = hit.distance;
+
+ //Hit plane.
+ hitPlanes4[i] = hitPlane;
+
+ //Hit friction.
+ PxU32 surfaceType = 0;
+ PxMaterial* material = NULL;
+ {
+ //Only get the material if the raycast started outside the hit shape.
+ material = (hit.distance != 0.0f) ? hit.shape->getMaterialFromInternalFaceIndex(hit.faceIndex) : NULL;
+ }
+ //Hash table for quick lookup of drivable surface type from material.
+ const PxVehicleDrivableSurfaceToTireFrictionPairs* PX_RESTRICT frictionPairs = constData.frictionPairs;
+ VehicleSurfaceTypeHashTable surfaceTypeHashTable(*constData.frictionPairs);
+ if (NULL != material)
+ {
+ surfaceType = surfaceTypeHashTable.get(material);
+ }
+ const PxVehicleTireData& tire = inputData.vehWheels4SimData->getTireData(i);
+ const PxF32 frictionMultiplier = frictionPairs->getTypePairFriction(surfaceType, tire.mType);
+ PX_ASSERT(frictionMultiplier >= 0);
+ hitFrictionMultipliers4[i] = frictionMultiplier;
+
+ //Hit type.
+ hitQueryTypes4[i] = hitQueryType;
+
+ //Hit report.
+ hitContactShapes4[i] = hit.shape;
+ hitContactActors4[i] = hit.actor;
+ hitContactMaterials4[i] = material;
+ hitSurfaceTypes4[i] = surfaceType;
+ hitContactPoints4[i] = hit.position;
+ hitContactNormals4[i] = hit.normal;
+
+ //When we're finished here we need to copy this back to the vehicle.
+ cachedHitCounts[i] = 1;
+ cachedHitPlanes[i] = hitPlane;
+ cachedHitDistances[i] = hit.distance;
+ cachedFrictionMultipliers[i] = frictionMultiplier;
+ cachedHitQueryTypes[i] = hitQueryType;
+}
+
+void processSuspTireWheels
+(const PxU32 startWheelIndex,
+ const ProcessSuspWheelTireConstData& constData, const ProcessSuspWheelTireInputData& inputData,
+ ProcessSuspWheelTireOutputData& outputData)
+{
+ PX_SIMD_GUARD; //tzRaw.normalize(); in computeTireDirs threw a denorm exception on osx
+
+#if PX_DEBUG_VEHICLE_ON
+ PX_ASSERT(0==(startWheelIndex & 3));
+#endif
+
+#if PX_DEBUG_VEHICLE_ON
+ zeroGraphDataWheels(startWheelIndex,PxVehicleWheelGraphChannel::eJOUNCE);
+ zeroGraphDataWheels(startWheelIndex,PxVehicleWheelGraphChannel::eSUSPFORCE);
+ zeroGraphDataWheels(startWheelIndex,PxVehicleWheelGraphChannel::eTIRELOAD);
+ zeroGraphDataWheels(startWheelIndex,PxVehicleWheelGraphChannel::eNORMALIZED_TIRELOAD);
+ zeroGraphDataWheels(startWheelIndex,PxVehicleWheelGraphChannel::eNORM_TIRE_LONG_FORCE);
+ zeroGraphDataWheels(startWheelIndex,PxVehicleWheelGraphChannel::eNORM_TIRE_LAT_FORCE);
+ zeroGraphDataWheels(startWheelIndex,PxVehicleWheelGraphChannel::eTIRE_LONG_SLIP);
+ zeroGraphDataWheels(startWheelIndex,PxVehicleWheelGraphChannel::eTIRE_LAT_SLIP);
+ zeroGraphDataWheels(startWheelIndex,PxVehicleWheelGraphChannel::eTIRE_FRICTION);
+#endif
+
+ //Unpack the logically constant data.
+ const PxVec3& gravity=constData.gravity;
+ const PxF32 timeFraction=constData.timeFraction;
+ const PxF32 timeStep=constData.subTimeStep;
+ const PxF32 recipTimeStep=constData.recipSubTimeStep;
+ const PxF32 recipGravityMagnitude=constData.recipGravityMagnitude;
+ const PxF32 gravityMagnitude=constData.gravityMagnitude;
+ const bool isTank=constData.isTank;
+ const PxF32 minLongSlipDenominator=constData.minLongSlipDenominator;
+
+ //Unpack the input data (physically constant data).
+ const PxVehicleWheels4SimData& wheelsSimData=*inputData.vehWheels4SimData;
+ const PxVehicleWheels4DynData& wheelsDynData=*inputData.vehWheels4DynData;
+ const PxVehicleTireForceCalculator4& tireForceCalculator=*inputData.vehWheels4TireForceCalculator;
+ const PxVehicleTireLoadFilterData& tireLoadFilterData=*inputData.vehWheels4TireLoadFilterData;
+ //More constant data describing the 4 wheels under consideration.
+ const PxF32* PX_RESTRICT tireRestLoads=wheelsSimData.getTireRestLoadsArray();
+ const PxF32* PX_RESTRICT recipTireRestLoads=wheelsSimData.getRecipTireRestLoadsArray();
+ //Compute the right direction for later.
+ const PxTransform& carChassisTrnsfm=inputData.carChassisTrnsfm;
+ const PxVec3 latDir=inputData.carChassisTrnsfm.rotate(gRight);
+ //Unpack the linear and angular velocity of the rigid body.
+ const PxVec3& carChassisLinVel=inputData.carChassisLinVel;
+ const PxVec3& carChassisAngVel=inputData.carChassisAngVel;
+ //Wheel local poses
+ const PxQuat* PX_RESTRICT wheelLocalPoseRotations = inputData.wheelLocalPoseRotations;
+ const PxF32* PX_RESTRICT wheelThetas = inputData.wheelThetas;
+ //Inputs (accel, steer, brake).
+ const bool isIntentionToAccelerate=inputData.isIntentionToAccelerate;
+ const PxF32* steerAngles=inputData.steerAngles;
+ const bool* isBrakeApplied=inputData.isBrakeApplied;
+ const bool* isAccelApplied=inputData.isAccelApplied;
+ //Disabled/enabled wheel states.
+ const bool* activeWheelStates=inputData.activeWheelStates;
+ //Current low forward/side speed timers. Note that the updated timers
+ //are stored in newLowForwardSpeedTimers and newLowSideSpeedTimers.
+ const PxF32* PX_RESTRICT lowForwardSpeedTimers=wheelsDynData.mTireLowForwardSpeedTimers;
+ const PxF32* PX_RESTRICT lowSideSpeedTimers=wheelsDynData.mTireLowSideSpeedTimers;
+ //Susp jounces and speeds from previous call to processSuspTireWheels.
+ const PxF32* PX_RESTRICT prevJounces=wheelsDynData.mJounces;
+
+ //Unpack the output data (the data we are going to compute).
+ //Start with the data stored for reporting to PxVehicleWheelQueryResult.
+ //PxVec3* suspLineStarts=outputData.suspLineStarts;
+ //PxVec3* suspLineDirs=outputData.suspLineDirs;
+ //PxF32* suspLineLengths=outputData.suspLineLengths;
+ bool* isInAirs=outputData.isInAir;
+ PxActor** tireContactActors=outputData.tireContactActors;
+ PxShape** tireContactShapes=outputData.tireContactShapes;
+ PxMaterial** tireSurfaceMaterials=outputData.tireSurfaceMaterials;
+ PxU32* tireSurfaceTypes=outputData.tireSurfaceTypes;
+ PxVec3* tireContactPoints=outputData.tireContactPoints;
+ PxVec3* tireContactNormals=outputData.tireContactNormals;
+ PxF32* frictions=outputData.frictions;
+ PxF32* jounces=outputData.jounces;
+ PxF32* suspensionSpringForces=outputData.suspensionSpringForces;
+ PxVec3* tireLongitudinalDirs=outputData.tireLongitudinalDirs;
+ PxVec3* tireLateralDirs=outputData.tireLateralDirs;
+ PxF32* longSlips=outputData.longSlips;
+ PxF32* latSlips=outputData.latSlips;
+ //Now unpack the forward speeds that are used later to blend the integrated wheel
+ //rotation angle between rolling speed and computed speed when the wheel rotation
+ //speeds become unreliable at low forward speeds.
+ PxF32* forwardSpeeds=outputData.forwardSpeeds;
+ //Unpack the real outputs of this function (wheel torques to apply to 1d rigid body wheel and forces/torques
+ //to apply to 3d rigid body chassis).
+ PxF32* tireTorques=outputData.tireTorques;
+ PxVec3& chassisForce=outputData.chassisForce;
+ PxVec3& chassisTorque=outputData.chassisTorque;
+ //Unpack the low speed timers that will be computed.
+ PxF32* newLowForwardSpeedTimers=outputData.newLowForwardSpeedTimers;
+ PxF32* newLowSideSpeedTimers=outputData.newLowSideSpeedTimers;
+ //Unpack the constraint data for suspensions limit and sticky tire constraints.
+ //Susp limits.
+ bool* suspLimitActiveFlags=outputData.vehConstraintData.mSuspLimitData.mActiveFlags;
+ PxVec3* suspLimitDirs=outputData.vehConstraintData.mSuspLimitData.mDirs;
+ PxVec3* suspLimitCMOffsets=outputData.vehConstraintData.mSuspLimitData.mCMOffsets;
+ PxF32* suspLimitErrors=outputData.vehConstraintData.mSuspLimitData.mErrors;
+ //Longitudinal sticky tires.
+ bool* stickyTireForwardActiveFlags=outputData.vehConstraintData.mStickyTireForwardData.mActiveFlags;
+ PxVec3* stickyTireForwardDirs=outputData.vehConstraintData.mStickyTireForwardData.mDirs;
+ PxVec3* stickyTireForwardCMOffsets=outputData.vehConstraintData.mStickyTireForwardData.mCMOffsets;
+ PxF32* stickyTireForwardTargetSpeeds=outputData.vehConstraintData.mStickyTireForwardData.mTargetSpeeds;
+ //Lateral sticky tires.
+ bool* stickyTireSideActiveFlags=outputData.vehConstraintData.mStickyTireSideData.mActiveFlags;
+ PxVec3* stickyTireSideDirs=outputData.vehConstraintData.mStickyTireSideData.mDirs;
+ PxVec3* stickyTireSideCMOffsets=outputData.vehConstraintData.mStickyTireSideData.mCMOffsets;
+ PxF32* stickyTireSideTargetSpeeds=outputData.vehConstraintData.mStickyTireSideData.mTargetSpeeds;
+ //Hit data. Store the contact data so it can be reused.
+ PxU32* cachedHitCounts=outputData.cachedHitCounts;
+ PxVec4* cachedHitPlanes=outputData.cachedHitPlanes;
+ PxF32* cachedHitDistances=outputData.cachedHitDistances;
+ PxF32* cachedFrictionMultipliers=outputData.cachedFrictionMultipliers;
+ PxU16* cachedHitQueryTypes=outputData.cachedHitQueryTypes;
+ //Hit actor data.
+ PxRigidDynamic** hitActors=outputData.hitActors;
+ PxVec3* hitActorForces=outputData.hitActorForces;
+ PxVec3* hitActorForcePositions=outputData.hitActorForcePositions;
+
+ //Compute all the hit data (counts, distances, planes, frictions, actors, shapes, materials etc etc).
+ //If we just did a raycast/sweep then we need to compute all this from the hit reports.
+ //If we are using cached raycast/sweep results then just copy the cached hit result data.
+ PxU32 hitCounts4[4];
+ PxF32 hitDistances4[4];
+ PxVec4 hitPlanes4[4];
+ PxF32 hitFrictionMultipliers4[4];
+ PxU16 hitQueryTypes4[4];
+ PxShape* hitContactShapes4[4];
+ PxRigidActor* hitContactActors4[4];
+ PxMaterial* hitContactMaterials4[4];
+ PxU32 hitSurfaceTypes4[4];
+ PxVec3 hitContactPoints4[4];
+ PxVec3 hitContactNormals4[4];
+ const PxRaycastQueryResult* PX_RESTRICT raycastResults=inputData.vehWheels4DynData->mRaycastResults;
+ const PxSweepQueryResult* PX_RESTRICT sweepResults=inputData.vehWheels4DynData->mSweepResults;
+ if(raycastResults || sweepResults)
+ {
+ const PxU16 queryType = raycastResults ? 0u : 1u;
+
+ //If we have a blocking hit then always take that.
+ //If we don't have a blocking hit then search for the "best" hit from all the touches.
+ for(PxU32 i=0;i<inputData.numActiveWheels;i++)
+ {
+ //Test that raycasts issue blocking hits.
+ PX_CHECK_AND_RETURN(!raycastResults || (0 == raycastResults[i].nbTouches), "Raycasts must generate blocking hits");
+
+ PxU32 hitCount = 0;
+ if ((raycastResults && raycastResults[i].hasBlock) || (sweepResults && sweepResults[i].hasBlock))
+ {
+ //We have a blocking it so use that.
+ const PxLocationHit& hit = raycastResults ? static_cast<const PxLocationHit&>(raycastResults[i].block) : static_cast<const PxLocationHit&>(sweepResults[i].block);
+
+ //Test that the hit actor isn't the vehicle itself.
+ PX_CHECK_AND_RETURN(constData.vehActor != hit.actor, "Vehicle raycast has hit itself. Please check the filter data to avoid this.");
+
+ //Reject if the sweep started inside the hit shape.
+ if (hit.distance != 0)
+ {
+ //Compute the plane of the hit.
+ const PxVec3 hitPos = hit.position;
+ const PxVec3 hitNorm = hit.normal;
+ const PxF32 hitD = -hitNorm.dot(hitPos);
+ PxVec4 hitPlane(hitNorm, hitD);
+
+ //Store the hit data in the various arrays.
+ storeHit(constData, inputData,
+ queryType,
+ hit, hitPlane,
+ i,
+ hitCounts4,
+ hitDistances4,
+ hitPlanes4,
+ hitFrictionMultipliers4,
+ hitQueryTypes4,
+ hitContactShapes4,
+ hitContactActors4,
+ hitContactMaterials4,
+ hitSurfaceTypes4,
+ hitContactPoints4,
+ hitContactNormals4,
+ cachedHitCounts,
+ cachedHitPlanes,
+ cachedHitDistances,
+ cachedFrictionMultipliers,
+ cachedHitQueryTypes);
+
+ hitCount = 1;
+ }
+ }
+ else if (sweepResults && sweepResults[i].nbTouches)
+ {
+ //We need wheel info so that we can analyse the hit and reject/accept it.
+ //Get what we need now.
+ const PxVehicleWheelData& wheel = wheelsSimData.getWheelData(i);
+ const PxVehicleSuspensionData& susp = wheelsSimData.getSuspensionData(i);
+ const PxVec3& bodySpaceWheelCentreOffset = wheelsSimData.getWheelCentreOffset(i);
+ const PxVec3& bodySpaceSuspTravelDir = wheelsSimData.getSuspTravelDirection(i);
+ const PxQuat& wheelLocalPoseRotation = wheelLocalPoseRotations[i];
+ const PxF32 wheelTheta = wheelThetas[i];
+ const PxF32 width = wheel.mWidth;
+ const PxF32 radius = wheel.mRadius;
+ const PxF32 maxBounce = susp.mMaxCompression;
+
+ //Compute the global pose of the wheel at zero jounce.
+ PxTransform suspPose;
+ PxVec3 suspDir;
+ computeSuspensionSweep(
+ carChassisTrnsfm,
+ wheelLocalPoseRotation, wheelTheta,
+ bodySpaceWheelCentreOffset, bodySpaceSuspTravelDir, 0.0f, 0.0f,
+ suspPose, suspDir);
+
+ //Iterate over all touches and cache the deepest hit that we accept.
+ PxF32 bestTouchDistance = -PX_MAX_F32;
+ for (PxU32 j = 0; j < sweepResults[i].nbTouches; j++)
+ {
+ //Get the next candidate hit.
+ const PxLocationHit& hit = sweepResults[i].touches[j];
+
+ //Test that the hit actor isn't the vehicle itself.
+ PX_CHECK_AND_RETURN(constData.vehActor != hit.actor, "Vehicle raycast has hit itself. Please check the filter data to avoid this.");
+
+ //Reject if the sweep started inside the hit shape.
+ if (hit.distance != 0.0f)
+ {
+ //Compute the plane of the hit.
+ const PxVec3 hitPos = hit.position;
+ const PxVec3 hitNorm = hit.normal;
+ const PxF32 hitD = -hitNorm.dot(hitPos);
+ PxVec4 hitPlane(hitNorm, hitD);
+
+ //Intersect the wheel disc with the hit plane and compute the jounce required to move the wheel free of the hit plane.
+ PxF32 dx;
+ PxVec3 wheelBottomPos;
+ bool successIntersection =
+ intersectCylinderPlane
+ (suspPose, suspDir,
+ width, radius, maxBounce,
+ hitPlane,
+ true,
+ dx, wheelBottomPos);
+
+ //If we accept the intersection and it requires more jounce than previously encountered then
+ //store the hit.
+ if (successIntersection && dx > bestTouchDistance)
+ {
+ storeHit(constData, inputData,
+ queryType,
+ hit, hitPlane,
+ i,
+ hitCounts4,
+ hitDistances4,
+ hitPlanes4,
+ hitFrictionMultipliers4,
+ hitQueryTypes4,
+ hitContactShapes4,
+ hitContactActors4,
+ hitContactMaterials4,
+ hitSurfaceTypes4,
+ hitContactPoints4,
+ hitContactNormals4,
+ cachedHitCounts,
+ cachedHitPlanes,
+ cachedHitDistances,
+ cachedFrictionMultipliers,
+ cachedHitQueryTypes);
+
+ bestTouchDistance = dx;
+
+ hitCount = 1;
+ }
+ }
+ }
+ }
+
+ if(0 == hitCount)
+ {
+ hitCounts4[i]=0;
+ hitDistances4[i]=0;
+ hitPlanes4[i]=PxVec4(0,0,0,0);
+ hitFrictionMultipliers4[i]=0;
+ hitQueryTypes4[i]=0u;
+ hitContactShapes4[i]=NULL;
+ hitContactActors4[i]=NULL;
+ hitContactMaterials4[i]=NULL;
+ hitSurfaceTypes4[i]=PxU32(PxVehicleDrivableSurfaceType::eSURFACE_TYPE_UNKNOWN);
+ hitContactPoints4[i]=PxVec3(0,0,0);
+ hitContactNormals4[i]=PxVec3(0,0,0);
+
+ //When we're finished here we need to copy this back to the vehicle.
+ cachedHitCounts[i]=0;
+ cachedHitPlanes[i]=PxVec4(0,0,0,0);
+ cachedHitDistances[i]=0;
+ cachedFrictionMultipliers[i]=0;
+ cachedHitQueryTypes[i] = 0u;
+ }
+ }
+ }
+ else
+ {
+ //If we have no sq results then we must have a cached raycast hit result.
+ const PxVehicleWheels4DynData::CachedSuspLineSceneQuerytHitResult& cachedHitResult =
+ reinterpret_cast<const PxVehicleWheels4DynData::CachedSuspLineSceneQuerytHitResult&>(inputData.vehWheels4DynData->mQueryOrCachedHitResults);
+
+ for(PxU32 i=0;i<inputData.numActiveWheels;i++)
+ {
+ hitCounts4[i]=cachedHitResult.mCounts[i];
+ hitDistances4[i]=cachedHitResult.mDistances[i];
+ hitPlanes4[i]=cachedHitResult.mPlanes[i];
+ hitFrictionMultipliers4[i]=cachedHitResult.mFrictionMultipliers[i];
+ hitQueryTypes4[i] = cachedHitResult.mQueryTypes[i];
+ hitContactShapes4[i]=NULL;
+ hitContactActors4[i]=NULL;
+ hitContactMaterials4[i]=NULL;
+ hitSurfaceTypes4[i]=PxU32(PxVehicleDrivableSurfaceType::eSURFACE_TYPE_UNKNOWN);
+ hitContactPoints4[i]=PxVec3(0,0,0);
+ hitContactNormals4[i]=PxVec3(0,0,0);
+
+ //When we're finished here we need to copy this back to the vehicle.
+ cachedHitCounts[i]=cachedHitResult.mCounts[i];
+ cachedHitPlanes[i]=cachedHitResult.mPlanes[i];
+ cachedHitDistances[i]=cachedHitResult.mDistances[i];
+ cachedFrictionMultipliers[i]=cachedHitResult.mFrictionMultipliers[i];
+ cachedHitQueryTypes[i]=cachedHitResult.mQueryTypes[i];
+ }
+ }
+
+ //Iterate over all 4 wheels.
+ for(PxU32 i=0;i<4;i++)
+ {
+ //Constant data of the ith wheel.
+ const PxVehicleWheelData& wheel=wheelsSimData.getWheelData(i);
+ const PxVehicleSuspensionData& susp=wheelsSimData.getSuspensionData(i);
+ const PxVehicleTireData& tire=wheelsSimData.getTireData(i);
+ const PxVec3& bodySpaceWheelCentreOffset=wheelsSimData.getWheelCentreOffset(i);
+ const PxVec3& bodySpaceSuspTravelDir=wheelsSimData.getSuspTravelDirection(i);
+
+ //Take a copy of the low forward/side speed timer of the ith wheel (time spent at low forward/side speed)
+ //Do this so we can quickly tell if the low/side forward speed timer changes.
+ newLowForwardSpeedTimers[i]=lowForwardSpeedTimers[i];
+ newLowSideSpeedTimers[i]=lowSideSpeedTimers[i];
+
+ //Reset the graph of the jounce to max droop.
+ //This will get updated as we learn more about the suspension.
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataSuspJounce(startWheelIndex, i,-susp.mMaxDroop);
+#endif
+
+ //Reset the jounce to max droop.
+ //This will get updated as we learn more about the suspension and tire.
+ PxF32 jounce=-susp.mMaxDroop;
+ jounces[i]=jounce;
+
+ //Deactivate the sticky tire and susp limit constraint.
+ //These will get updated as we learn more about the suspension and tire.
+ suspLimitActiveFlags[i]=false;
+ suspLimitErrors[i]=0.0f;
+ stickyTireForwardActiveFlags[i]=false;
+ stickyTireForwardTargetSpeeds[i]=0;
+ stickyTireSideActiveFlags[i]=false;
+ stickyTireSideTargetSpeeds[i]=0;
+
+ //The vehicle is in the air until we know otherwise.
+ isInAirs[i]=true;
+
+ //If there has been a hit then compute the suspension force and tire load.
+ //Ignore the hit if the raycast starts inside the hit shape (eg wheel completely underneath surface of a heightfield).
+ const bool activeWheelState=activeWheelStates[i];
+ const PxU32 numHits=hitCounts4[i];
+ const PxVec3 hitNorm(hitPlanes4[i].x, hitPlanes4[i].y,hitPlanes4[i].z);
+ const PxVec3 w = carChassisTrnsfm.q.rotate(bodySpaceSuspTravelDir);
+ if(activeWheelState && numHits > 0 && hitDistances4[i] != 0.0f && hitNorm.dot(w) < 0.0f)
+ {
+ //Get the friction multiplier from the combination of surface type and tire type.
+ const PxF32 frictionMultiplier=hitFrictionMultipliers4[i];
+ PX_ASSERT(frictionMultiplier>=0);
+
+ PxF32 dx;
+ PxVec3 wheelBottomPos;
+ bool successIntersection = true;
+ if(0 == hitQueryTypes4[i])
+ {
+ successIntersection = intersectRayPlane
+ (carChassisTrnsfm,
+ bodySpaceWheelCentreOffset, bodySpaceSuspTravelDir, wheel.mWidth, wheel.mRadius, susp.mMaxCompression,
+ hitPlanes4[i],
+ dx, wheelBottomPos);
+ }
+ else
+ {
+ PX_ASSERT(1 == hitQueryTypes4[i]);
+ successIntersection = intersectCylinderPlane
+ (carChassisTrnsfm,
+ wheelLocalPoseRotations[i], wheelThetas[i],
+ bodySpaceWheelCentreOffset, bodySpaceSuspTravelDir, wheel.mWidth, wheel.mRadius, susp.mMaxCompression,
+ hitPlanes4[i],
+ false,
+ dx, wheelBottomPos);
+ }
+
+ //If the spring is elongated past its max droop then the wheel isn't touching the ground.
+ //In this case the spring offers zero force and provides no support for the chassis/sprung mass.
+ //Only carry on computing the spring force if the wheel is touching the ground.
+ PX_ASSERT(susp.mMaxCompression>=0);
+ PX_ASSERT(susp.mMaxDroop>=0);
+ if(dx > -susp.mMaxDroop && successIntersection)
+ {
+ //We can record the hit shape, hit actor, hit material, hit surface type, hit point, and hit normal now because we've got a hit.
+ tireContactShapes[i]=hitContactShapes4[i];
+ tireContactActors[i]=hitContactActors4[i];
+ tireSurfaceMaterials[i]=hitContactMaterials4[i];
+ tireSurfaceTypes[i]=hitSurfaceTypes4[i];
+ tireContactPoints[i]=hitContactPoints4[i];
+ tireContactNormals[i]=hitContactNormals4[i];
+
+ //We know that the vehicle is not in the air.
+ isInAirs[i]=false;
+
+ //Clamp the spring compression so that it is never greater than the max bounce.
+ //Apply the susp limit constraint if the spring compression is greater than the max bounce.
+ suspLimitErrors[i] = dx - susp.mMaxCompression;
+ suspLimitActiveFlags[i] = (dx > susp.mMaxCompression);
+ suspLimitCMOffsets[i] = bodySpaceWheelCentreOffset;
+ suspLimitDirs[i] = bodySpaceSuspTravelDir;
+ jounce=PxMin(dx,susp.mMaxCompression);
+
+ //Store the jounce (having a local copy avoids lhs).
+ jounces[i]=jounce;
+
+ //Store the jounce in the graph.
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataSuspJounce(startWheelIndex, i,jounce);
+#endif
+
+ //Compute the speed of the rigid body along the suspension travel dir at the
+ //bottom of the wheel.
+ const PxVec3 r=wheelBottomPos-carChassisTrnsfm.p;
+ PxVec3 wheelBottomVel=carChassisLinVel;
+ wheelBottomVel+=carChassisAngVel.cross(r);
+
+ //Modify the relative velocity at the wheel contact point if the hit actor is a dynamic.
+ PxRigidDynamic* dynamicHitActor=NULL;
+ PxVec3 hitActorVelocity(0,0,0);
+ if(hitContactActors4[i] && ((dynamicHitActor = hitContactActors4[i]->is<PxRigidDynamic>()) != NULL))
+ {
+ hitActorVelocity = PxRigidBodyExt::getVelocityAtPos(*dynamicHitActor,wheelBottomPos);
+ wheelBottomVel -= hitActorVelocity;
+ }
+
+ //Get the speed of the jounce.
+ const PxF32 jounceSpeed = (PX_MAX_F32 != prevJounces[i]) ? (jounce - prevJounces[i])*recipTimeStep : 0.0f;
+
+ //Decompose gravity into a term along w and a term perpendicular to w
+ //gravity = w*alpha + T*beta
+ //where T is a unit vector perpendicular to w; alpha and beta are scalars.
+ //The vector w*alpha*mass is the component of gravitational force that acts along the spring direction.
+ //The vector T*beta*mass is the component of gravitational force that will be resisted by the spring
+ //because the spring only supports a single degree of freedom along w.
+ //We only really need to know T*beta so don't bother calculating T or beta.
+ const PxF32 alpha = PxMax(0.0f, gravity.dot(w));
+ const PxVec3 TTimesBeta = (0.0f != alpha) ? gravity - w*alpha : PxVec3(0,0,0);
+ //Compute the magnitude of the force along w.
+ PxF32 suspensionForceW =
+ PxMax(0.0f,
+ susp.mSprungMass*alpha + //force to support sprung mass at zero jounce
+ susp.mSpringStrength*jounce); //linear spring
+ suspensionForceW += susp.mSpringDamperRate*jounceSpeed; //damping
+ //Compute the total force acting on the suspension.
+ //Remember that the spring force acts along -w.
+ //Remember to account for the term perpendicular to w and that it acts along -TTimesBeta
+ PxF32 suspensionForceMag = hitNorm.dot(-w*suspensionForceW - TTimesBeta*susp.mSprungMass);
+
+ //Apply the opposite force to the hit object.
+ //Clamp suspensionForceMag if required.
+ if (dynamicHitActor && !(dynamicHitActor->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC))
+ {
+ const PxF32 dynamicActorInvMass = dynamicHitActor->getInvMass();
+ const PxF32 dynamicActorMass = dynamicHitActor->getMass();
+ const PxF32 forceSign = computeSign(suspensionForceMag);
+ const PxF32 forceMag = PxAbs(suspensionForceMag);
+ const PxF32 clampedAccelMag = PxMin(forceMag*dynamicActorInvMass, gMaxHitActorAcceleration);
+ const PxF32 clampedForceMag = clampedAccelMag*dynamicActorMass*forceSign;
+ PX_ASSERT(clampedForceMag*suspensionForceMag >= 0.0f);
+
+ suspensionForceMag = clampedForceMag;
+
+ hitActors[i] = dynamicHitActor;
+ hitActorForces[i] = hitNorm*(-clampedForceMag*timeFraction);
+ hitActorForcePositions[i] = hitContactPoints4[i];
+ }
+
+ //Store the spring force now (having a local copy avoids lhs).
+ suspensionSpringForces[i] = suspensionForceMag;
+
+ //Store the spring force in the graph.
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataSuspForce(startWheelIndex, i, suspensionForceMag);
+#endif
+
+ //Suspension force can be computed now.
+ const PxVec3 suspensionForce = hitNorm*suspensionForceMag;
+
+ //Torque from spring force.
+ const PxVec3 suspForceCMOffset = carChassisTrnsfm.rotate(wheelsSimData.getSuspForceAppPointOffset(i));
+ const PxVec3 suspensionTorque = suspForceCMOffset.cross(suspensionForce);
+
+ //Add the suspension force/torque to the chassis force/torque.
+ chassisForce+=suspensionForce;
+ chassisTorque+=suspensionTorque;
+
+ //Now compute the tire load.
+ const PxF32 tireLoad = suspensionForceMag;
+
+ //Normalize the tire load
+ //Now work out the normalized tire load.
+ const PxF32 normalisedTireLoad=tireLoad*recipGravityMagnitude*recipTireRestLoads[i];
+ //Filter the normalized tire load and compute the filtered tire load too.
+ const PxF32 filteredNormalisedTireLoad=computeFilteredNormalisedTireLoad(tireLoadFilterData,normalisedTireLoad);
+ const PxF32 filteredTireLoad=filteredNormalisedTireLoad*gravityMagnitude*tireRestLoads[i];
+
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataTireLoad(startWheelIndex,i,filteredTireLoad);
+ updateGraphDataNormTireLoad(startWheelIndex,i,filteredNormalisedTireLoad);
+#endif
+
+ //Compute the lateral and longitudinal tire axes in the ground plane.
+ PxVec3 tireLongDir;
+ PxVec3 tireLatDir;
+ computeTireDirs(latDir,hitNorm,steerAngles[i],tireLongDir,tireLatDir);
+
+ //Store the tire long and lat dirs now (having a local copy avoids lhs).
+ tireLongitudinalDirs[i]= tireLongDir;
+ tireLateralDirs[i]=tireLatDir;
+
+ //Now compute the speeds along each of the tire axes.
+ const PxF32 tireLongSpeed=wheelBottomVel.dot(tireLongDir);
+ const PxF32 tireLatSpeed=wheelBottomVel.dot(tireLatDir);
+
+ //Store the forward speed (having a local copy avoids lhs).
+ forwardSpeeds[i]=tireLongSpeed;
+
+ //Now compute the slips along each axes.
+ const bool hasAccel=isAccelApplied[i];
+ const bool hasBrake=isBrakeApplied[i];
+ const PxF32 wheelOmega=wheelsDynData.mWheelSpeeds[i];
+ const PxF32 wheelRadius=wheel.mRadius;
+ PxF32 longSlip;
+ PxF32 latSlip;
+ computeTireSlips
+ (tireLongSpeed,tireLatSpeed,wheelOmega,wheelRadius,minLongSlipDenominator,
+ hasAccel,hasBrake,
+ isTank,
+ longSlip,latSlip);
+
+ //Store the lat and long slip (having local copies avoids lhs).
+ longSlips[i]=longSlip;
+ latSlips[i]=latSlip;
+
+ //Camber angle.
+ PxF32 camber=susp.mCamberAtRest;
+ if(jounce>0)
+ {
+ camber += jounce*susp.mCamberAtMaxCompression*susp.getRecipMaxCompression();
+ }
+ else
+ {
+ camber -= jounce*susp.mCamberAtMaxDroop*susp.getRecipMaxDroop();
+ }
+
+ //Compute the friction that will be experienced by the tire.
+ PxF32 friction;
+ computeTireFriction(tire,longSlip,frictionMultiplier,friction);
+
+ //Store the friction (having a local copy avoids lhs).
+ frictions[i]=friction;
+
+ if(filteredTireLoad*frictionMultiplier>0)
+ {
+ //Either tire forces or sticky tire friction constraint will be applied here.
+ const PxVec3 tireForceCMOffset = carChassisTrnsfm.rotate(wheelsSimData.getTireForceAppPointOffset(i));
+
+ PxF32 newLowForwardSpeedTimer;
+ {
+ //check the accel value here
+ //Update low forward speed timer.
+ const PxF32 recipWheelRadius=wheel.getRecipRadius();
+ newLowForwardSpeedTimer=newLowForwardSpeedTimers[i];
+ updateLowForwardSpeedTimer(tireLongSpeed,wheelOmega,wheelRadius,recipWheelRadius,isIntentionToAccelerate,timeStep,newLowForwardSpeedTimer);
+
+ //Activate sticky tire forward friction constraint if required.
+ //If sticky tire friction is active then set the longitudinal slip to zero because
+ //the sticky tire constraint will take care of the longitudinal component of motion.
+ bool stickyTireForwardActiveFlag=false;
+ PxF32 stickyTireForwardTargetSpeed=0.0f;
+ activateStickyFrictionForwardConstraint(tireLongSpeed,wheelOmega,newLowForwardSpeedTimer,isIntentionToAccelerate,stickyTireForwardActiveFlag,stickyTireForwardTargetSpeed);
+ stickyTireForwardTargetSpeed += hitActorVelocity.dot(tireLongDir);
+
+ //Store the sticky tire data (having local copies avoids lhs).
+ newLowForwardSpeedTimers[i] = newLowForwardSpeedTimer;
+ stickyTireForwardActiveFlags[i]=stickyTireForwardActiveFlag;
+ stickyTireForwardTargetSpeeds[i]=stickyTireForwardTargetSpeed;
+ stickyTireForwardDirs[i]=tireLongDir;
+ stickyTireForwardCMOffsets[i]=tireForceCMOffset;
+
+ //Deactivate the long slip if sticky tire constraint is active.
+ longSlip=(!stickyTireForwardActiveFlag ? longSlip : 0.0f);
+
+ //Store the long slip (having local copies avoids lhs).
+ longSlips[i]=longSlip;
+ }
+
+ PxF32 newLowSideSpeedTimer;
+ {
+ //check the accel value here
+ //Update low side speed timer.
+ newLowSideSpeedTimer=newLowSideSpeedTimers[i];
+ updateLowSideSpeedTimer(tireLatSpeed,isIntentionToAccelerate,timeStep,newLowSideSpeedTimer);
+
+ //Activate sticky tire side friction constraint if required.
+ //If sticky tire friction is active then set the lateral slip to zero because
+ //the sticky tire constraint will take care of the lateral component of motion.
+ bool stickyTireSideActiveFlag=false;
+ PxF32 stickyTireSideTargetSpeed=0.0f;
+ activateStickyFrictionSideConstraint(tireLatSpeed,newLowForwardSpeedTimer,newLowSideSpeedTimer,isIntentionToAccelerate,stickyTireSideActiveFlag,stickyTireSideTargetSpeed);
+ stickyTireSideTargetSpeed += hitActorVelocity.dot(tireLatDir);
+
+ //Store the sticky tire data (having local copies avoids lhs).
+ newLowSideSpeedTimers[i] = newLowSideSpeedTimer;
+ stickyTireSideActiveFlags[i]=stickyTireSideActiveFlag;
+ stickyTireSideTargetSpeeds[i]=stickyTireSideTargetSpeed;
+ stickyTireSideDirs[i]=tireLatDir;
+ stickyTireSideCMOffsets[i]=tireForceCMOffset;
+
+ //Deactivate the lat slip if sticky tire constraint is active.
+ latSlip=(!stickyTireSideActiveFlag ? latSlip : 0.0f);
+
+ //Store the long slip (having local copies avoids lhs).
+ latSlips[i]=latSlip;
+ }
+
+ //Compute the various tire torques.
+ PxF32 wheelTorque=0;
+ PxF32 tireLongForceMag=0;
+ PxF32 tireLatForceMag=0;
+ PxF32 tireAlignMoment=0;
+ const PxF32 restTireLoad=gravityMagnitude*tireRestLoads[i];
+ const PxF32 recipWheelRadius=wheel.getRecipRadius();
+ tireForceCalculator.mShader(
+ tireForceCalculator.mShaderData[i],
+ friction,
+ longSlip,latSlip,camber,
+ wheelOmega,wheelRadius,recipWheelRadius,
+ restTireLoad,filteredNormalisedTireLoad,filteredTireLoad,
+ gravityMagnitude, recipGravityMagnitude,
+ wheelTorque,tireLongForceMag,tireLatForceMag,tireAlignMoment);
+
+ //Store the tire torque ((having a local copy avoids lhs).
+ tireTorques[i]=wheelTorque;
+
+ //Apply the torque to the chassis.
+ //Compute the tire force to apply to the chassis.
+ const PxVec3 tireLongForce=tireLongDir*tireLongForceMag;
+ const PxVec3 tireLatForce=tireLatDir*tireLatForceMag;
+ const PxVec3 tireForce=tireLongForce+tireLatForce;
+ //Compute the torque to apply to the chassis.
+ const PxVec3 tireTorque=tireForceCMOffset.cross(tireForce);
+ //Add all the forces/torques together.
+ chassisForce+=tireForce;
+ chassisTorque+=tireTorque;
+
+ //Graph all the data we just computed.
+#if PX_DEBUG_VEHICLE_ON
+ if(gCarTireForceAppPoints)
+ gCarTireForceAppPoints[i]=carChassisTrnsfm.p + tireForceCMOffset;
+ if(gCarSuspForceAppPoints)
+ gCarSuspForceAppPoints[i]=carChassisTrnsfm.p + suspForceCMOffset;
+
+ if(gCarWheelGraphData[0])
+ {
+ updateGraphDataNormLongTireForce(startWheelIndex, i, PxAbs(tireLongForceMag)*normalisedTireLoad/tireLoad);
+ updateGraphDataNormLatTireForce(startWheelIndex, i, PxAbs(tireLatForceMag)*normalisedTireLoad/tireLoad);
+ updateGraphDataNormTireAligningMoment(startWheelIndex, i, tireAlignMoment*normalisedTireLoad/tireLoad);
+ updateGraphDataLongTireSlip(startWheelIndex, i,longSlips[i]);
+ updateGraphDataLatTireSlip(startWheelIndex, i,latSlips[i]);
+ updateGraphDataTireFriction(startWheelIndex, i,frictions[i]);
+ }
+#endif
+ }//filteredTireLoad*frictionMultiplier>0
+ }//if(dx > -susp.mMaxCompression)
+ }//if(numHits>0)
+ }//i
+}
+
+
+void procesAntiRollSuspension
+(const PxVehicleWheelsSimData& wheelsSimData,
+ const PxTransform& carChassisTransform, const PxWheelQueryResult* wheelQueryResults,
+ PxVec3& chassisTorque)
+{
+ const PxU32 numAntiRollBars = wheelsSimData.getNbAntiRollBars();
+ for(PxU32 i = 0; i < numAntiRollBars; i++)
+ {
+ const PxVehicleAntiRollBarData& antiRoll = wheelsSimData.getAntiRollBarData(i);
+ const PxU32 w0 = antiRoll.mWheel0;
+ const PxU32 w1 = antiRoll.mWheel1;
+
+ //At least one wheel must be on the ground for the anti-roll to work.
+ const bool w0InAir = wheelQueryResults[w0].isInAir;
+ const bool w1InAir = wheelQueryResults[w1].isInAir;
+ if(!w0InAir || !w1InAir)
+ {
+ //Compute the difference in jounce and compute the force.
+ const PxF32 w0Jounce = wheelQueryResults[w0].suspJounce;
+ const PxF32 w1Jounce = wheelQueryResults[w1].suspJounce;
+ const PxF32 antiRollForceMag = (w0Jounce - w1Jounce)*antiRoll.mStiffness;
+
+ //Apply the antiRollForce postiviely to wheel0, negatively to wheel 1
+ PxU32 wheelIds[2] = {0xffffffff, 0xffffffff};
+ PxF32 antiRollForceMags[2];
+ PxU32 numWheelIds = 0;
+ if(!w0InAir)
+ {
+ wheelIds[numWheelIds] = w0;
+ antiRollForceMags[numWheelIds] = -antiRollForceMag;
+ numWheelIds++;
+ }
+ if(!w1InAir)
+ {
+ wheelIds[numWheelIds] = w1;
+ antiRollForceMags[numWheelIds] = +antiRollForceMag;
+ numWheelIds++;
+ }
+
+ for(PxU32 j = 0; j < numWheelIds; j++)
+ {
+ const PxU32 wheelId = wheelIds[j];
+
+ //Force
+ const PxVec3 suspDir = carChassisTransform.q.rotate(wheelsSimData.getSuspTravelDirection(wheelId));
+ const PxVec3 antiRollForce = suspDir*antiRollForceMags[j];
+ //Torque
+ const PxVec3 r = carChassisTransform.q.rotate(wheelsSimData.getSuspForceAppPointOffset(wheelId));
+ const PxVec3 antiRollTorque = r.cross(antiRollForce);
+ chassisTorque += antiRollTorque;
+ }
+ }
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////
+//Set the low long speed timers computed in processSuspTireWheels
+//Call immediately after completing processSuspTireWheels.
+////////////////////////////////////////////////////////////////////////////
+
+void updateLowSpeedTimers(const PxF32* PX_RESTRICT newLowSpeedTimers, PxF32* PX_RESTRICT lowSpeedTimers)
+{
+ for(PxU32 i=0;i<4;i++)
+ {
+ lowSpeedTimers[i]=(newLowSpeedTimers[i]!=lowSpeedTimers[i] ? newLowSpeedTimers[i] : 0.0f);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Set the jounce values computed in processSuspTireWheels
+//Call immediately after completing processSuspTireWheels.
+////////////////////////////////////////////////////////////////////////////
+void updateJounces(const PxF32* PX_RESTRICT jounces, PxF32* PX_RESTRICT prevJounces)
+{
+ for(PxU32 i=0;i<4;i++)
+ {
+ prevJounces[i] = jounces[i];
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//Set the hit plane, hit distance and hit friction multplier computed in processSuspTireWheels
+//Call immediately after completing processSuspTireWheels.
+////////////////////////////////////////////////////////////////////////////
+
+void updateCachedHitData
+(const PxU32* PX_RESTRICT cachedHitCounts, const PxVec4* PX_RESTRICT cachedHitPlanes, const PxF32* PX_RESTRICT cachedHitDistances, const PxF32* PX_RESTRICT cachedFrictionMultipliers, const PxU16* cachedQueryTypes,
+ PxVehicleWheels4DynData* wheels4DynData)
+{
+ if(wheels4DynData->mRaycastResults || wheels4DynData->mSweepResults)
+ {
+ wheels4DynData->mHasCachedRaycastHitPlane = true;
+ }
+
+ PxVehicleWheels4DynData::CachedSuspLineSceneQuerytHitResult* cachedRaycastHitResults =
+ reinterpret_cast<PxVehicleWheels4DynData::CachedSuspLineSceneQuerytHitResult*>(wheels4DynData->mQueryOrCachedHitResults);
+
+
+ for(PxU32 i=0;i<4;i++)
+ {
+ cachedRaycastHitResults->mCounts[i]=Ps::to16(cachedHitCounts[i]);
+ cachedRaycastHitResults->mPlanes[i]=cachedHitPlanes[i];
+ cachedRaycastHitResults->mDistances[i]=cachedHitDistances[i];
+ cachedRaycastHitResults->mFrictionMultipliers[i]=cachedFrictionMultipliers[i];
+ cachedRaycastHitResults->mQueryTypes[i] = cachedQueryTypes[i];
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////
+//Solve the system of engine speed + wheel rotation speeds using an implicit integrator.
+//The following functions only compute the speed of wheels connected to the diff.
+//Worth going to the length of the implicit integrator because after gear changes
+//the difference in speed at the clutch can be hard to integrate.
+//Separate functions for 4W, NW and tank because the differential works in slightly
+//different ways. With driveNW we end up with (N+1)*(N+1) problem, with drive4W we end up
+//with 5*5 and with tanks we end up with just 3*3. Tanks use the method of least squares
+//to apply the rule that all left/right wheels have the same speed.
+//Remember that the following functions don't integrate wheels not connected to the diff
+//so these need integrated separately.
+////////////////////////////////////////////////////////////////////////////
+
+#if PX_CHECKED
+bool isValid(const MatrixNN& A, const VectorN& b, const VectorN& result)
+{
+ PX_ASSERT(A.getSize()==b.getSize());
+ PX_ASSERT(A.getSize()==result.getSize());
+ const PxU32 size=A.getSize();
+
+ //r=A*result-b
+ VectorN r(size);
+ for(PxU32 i=0;i<size;i++)
+ {
+ r[i]=-b[i];
+ for(PxU32 j=0;j<size;j++)
+ {
+ r[i]+=A.get(i,j)*result[j];
+ }
+ }
+
+ PxF32 rLength=0;
+ PxF32 bLength=0;
+ for(PxU32 i=0;i<size;i++)
+ {
+ rLength+=r[i]*r[i];
+ bLength+=b[i]*b[i];
+ }
+ const PxF32 error=PxSqrt(rLength/(bLength+1e-5f));
+ return (error<1e-5f);
+}
+#endif
+
+
+struct ImplicitSolverInput
+{
+ //dt/numSubSteps
+ PxF32 subTimeStep;
+
+ //Brake control value in range (0,1)
+ PxF32 brake;
+
+ //Handbrake control value in range (0,1)
+ PxF32 handBrake;
+
+ //Clutch strength
+ PxF32 K;
+
+ //Gear ratio.
+ PxF32 G;
+
+ PxVehicleClutchAccuracyMode::Enum accuracyMode;
+ PxU32 maxNumIterations;
+
+ //Engine drive torque
+ PxF32 engineDriveTorque;
+
+ //Engine damping rate.
+ PxF32 engineDampingRate;
+
+ //Fraction of available clutch torque to be delivered to each wheel.
+ const PxF32* diffTorqueRatios;
+
+ //Fractional contribution of each wheel to average wheel speed at clutch.
+ const PxF32* aveWheelSpeedContributions;
+
+ //Braking torque at each wheel (inlcudes handbrake torque).
+ const PxF32* brakeTorques;
+
+ //True per wheel brakeTorques[i] > 0, false if brakeTorques[i]==0
+ const bool* isBrakeApplied;
+
+ //Tire torques to apply to each 1d rigid body wheel.
+ const PxF32* tireTorques;
+
+ //Sim and dyn data.
+ PxU32 numWheels4;
+ PxU32 numActiveWheels;
+ const PxVehicleWheels4SimData* wheels4SimData;
+ const PxVehicleDriveSimData* driveSimData;
+};
+
+struct ImplicitSolverOutput
+{
+ PxVehicleWheels4DynData* wheelsDynData;
+ PxVehicleDriveDynData* driveDynData;
+};
+
+void solveDrive4WInternaDynamicsEnginePlusDrivenWheels
+(const ImplicitSolverInput& input, ImplicitSolverOutput* output)
+{
+ const PxF32 subTimestep = input.subTimeStep;
+ const PxF32 K = input.K;
+ const PxF32 G = input.G;
+ const PxVehicleClutchAccuracyMode::Enum accuracyMode = input.accuracyMode;
+ const PxU32 maxIterations = input.maxNumIterations;
+ const PxF32 engineDriveTorque = input.engineDriveTorque;
+ const PxF32 engineDampingRate = input.engineDampingRate;
+ const PxF32* PX_RESTRICT diffTorqueRatios = input.diffTorqueRatios;
+ const PxF32* PX_RESTRICT aveWheelSpeedContributions = input.aveWheelSpeedContributions;
+ const PxF32* PX_RESTRICT brakeTorques = input.brakeTorques;
+ const bool* PX_RESTRICT isBrakeApplied = input.isBrakeApplied;
+ const PxF32* PX_RESTRICT tireTorques = input.tireTorques;
+ const PxVehicleWheels4SimData& wheels4SimData = *input.wheels4SimData;
+ const PxVehicleDriveSimData4W& driveSimData = *static_cast<const PxVehicleDriveSimData4W*>(input.driveSimData);
+
+ PxVehicleDriveDynData* driveDynData = output->driveDynData;
+ PxVehicleWheels4DynData* wheels4DynData = output->wheelsDynData;
+
+ const PxF32 KG=K*G;
+ const PxF32 KGG=K*G*G;
+
+ MatrixNN A(4+1);
+ VectorN b(4+1);
+ VectorN result(4+1);
+
+ const PxVehicleEngineData& engineData=driveSimData.getEngineData();
+
+ const PxF32* PX_RESTRICT wheelSpeeds=wheels4DynData->mWheelSpeeds;
+ const PxF32 engineOmega=driveDynData->getEngineRotationSpeed();
+
+ //
+ //torque at clutch:
+ //tc = K*{G*[alpha0*w0 + alpha1*w1 + alpha2*w2 + ..... alpha(N-1)*w(N-1)] - wEng}
+ //where
+ //(i) G is the gearing ratio,
+ //(ii) alphai is the fractional contribution of the ith wheel to the average wheel speed at the clutch (alpha(i) is zero for undriven wheels)
+ //(iii) wi is the angular speed of the ith wheel
+ //(iv) K is the clutch strength
+ //(v) wEng is the angular speed of the engine
+
+ //torque applied to ith wheel is
+ //ti = G*gammai*tc + bt(i) + tt(i)
+ //where
+ //gammai is the fractional proportion of the clutch torque that the differential delivers to the ith wheel
+ //bt(i) is the brake torque applied to the ith wheel
+ //tt(i) is the tire torque applied to the ith wheel
+
+ //acceleration applied to ith wheel is
+ //ai = G*gammai*K*{G*[alpha0*w0 + alpha1*w1 alpha2*w2 + ..... alpha(N-1)*w(N-1)] - wEng}/Ii + (bt(i) + tt(i))/Ii
+ //wheer Ii is the moi of the ith wheel
+
+ //express ai as
+ //ai = [wi(t+dt) - wi(t)]/dt
+ //and rearrange
+ //wi(t+dt) - wi(t)] = dt*G*gammai*K*{G*[alpha0*w0(t+dt) + alpha1*w1(t+dt) + alpha2*w2(t+dt) + ..... alpha(N-1)*w(N-1)(t+dt)] - wEng(t+dt)}/Ii + dt*(bt(i) + tt(i))/Ii
+
+ //Do the same for tEng (torque applied to engine)
+ //tEng = -tc + engineDriveTorque
+ //where engineDriveTorque is the drive torque applied to the engine
+ //Assuming the engine has unit mass then
+ //wEng(t+dt) -wEng(t) = -dt*K*{G*[alpha0*w0(t+dt) + alpha1*w1(t+dt) + alpha2*w2(t+dt) + ..... alpha(N-1)*w(N-1(t+dt))] - wEng(t+dt)}/Ieng + dt*engineDriveTorque]/IEng
+
+ //Introduce the vector w=(w0,w1,w2....w(N-1), wEng)
+ //and re-express as a matrix after collecting all unknowns at (t+dt) and knowns at time t.
+ //A*w(t+dt)=b(t);
+
+ //Wheels.
+ {
+ for(PxU32 i=0;i<4;i++)
+ {
+ const PxF32 dt=subTimestep*wheels4SimData.getWheelData(i).getRecipMOI();
+ const PxF32 R=diffTorqueRatios[i];
+ const PxF32 dtKGGR=dt*KGG*R;
+ A.set(i,0,dtKGGR*aveWheelSpeedContributions[0]);
+ A.set(i,1,dtKGGR*aveWheelSpeedContributions[1]);
+ A.set(i,2,dtKGGR*aveWheelSpeedContributions[2]);
+ A.set(i,3,dtKGGR*aveWheelSpeedContributions[3]);
+ A.set(i,i,1.0f+dtKGGR*aveWheelSpeedContributions[i]+dt*wheels4SimData.getWheelData(i).mDampingRate);
+ A.set(i,4,-dt*KG*R);
+ b[i] = wheelSpeeds[i] + dt*(brakeTorques[i]+tireTorques[i]);
+ result[i] = wheelSpeeds[i];
+ }
+ }
+
+ //Engine.
+ {
+ const PxF32 dt=subTimestep*driveSimData.getEngineData().getRecipMOI();
+ const PxF32 dtKG=dt*K*G;
+ A.set(4,0,-dtKG*aveWheelSpeedContributions[0]);
+ A.set(4,1,-dtKG*aveWheelSpeedContributions[1]);
+ A.set(4,2,-dtKG*aveWheelSpeedContributions[2]);
+ A.set(4,3,-dtKG*aveWheelSpeedContributions[3]);
+ A.set(4,4,1.0f + dt*(K+engineDampingRate));
+ b[4] = engineOmega + dt*engineDriveTorque;
+ result[4] = engineOmega;
+ }
+
+ //Solve Aw=b
+ if(PxVehicleClutchAccuracyMode::eBEST_POSSIBLE == accuracyMode)
+ {
+ MatrixNNLUSolver solver;
+ solver.decomposeLU(A);
+ solver.solve(b,result);
+ PX_WARN_ONCE_IF(!isValid(A,b,result), "Unable to compute new PxVehicleDrive4W internal rotation speeds. Please check vehicle sim data, especially clutch strength; engine moi and damping; wheel moi and damping");
+ }
+ else
+ {
+ MatrixNGaussSeidelSolver solver;
+ solver.solve(maxIterations, gSolverTolerance, A, b, result);
+ }
+
+ //Check for sanity in the resultant internal rotation speeds.
+ //If the brakes are on and the wheels have switched direction then lock them at zero.
+ //A consequence of this quick fix is that locked wheels remain locked until the brake is entirely released.
+ //This isn't strictly mathematically or physically correct - a more accurate solution would either formulate the
+ //brake as a lcp problem or repeatedly solve with constraints that locked wheels remain at zero rotation speed.
+ //The physically correct solution will certainly be more expensive so let's live with the restriction that
+ //locked wheels remain locked until the brake is released.
+ //newOmega=result[i], oldOmega=wheelSpeeds[i], if newOmega*oldOmega<=0 and isBrakeApplied then lock wheel.
+ result[0]=(isBrakeApplied[0] && (wheelSpeeds[0]*result[0]<=0)) ? 0.0f : result[0];
+ result[1]=(isBrakeApplied[1] && (wheelSpeeds[1]*result[1]<=0)) ? 0.0f : result[1];
+ result[2]=(isBrakeApplied[2] && (wheelSpeeds[2]*result[2]<=0)) ? 0.0f : result[2];
+ result[3]=(isBrakeApplied[3] && (wheelSpeeds[3]*result[3]<=0)) ? 0.0f : result[3];
+ //Clamp the engine revs.
+ //Again, this is not physically or mathematically correct but the loss in behaviour will be hard to notice.
+ //The alternative would be to add constraints to the solver, which would be much more expensive.
+ result[4]=PxClamp(result[4],0.0f,engineData.mMaxOmega);
+
+ //Copy back to the car's internal rotation speeds.
+ wheels4DynData->mWheelSpeeds[0]=result[0];
+ wheels4DynData->mWheelSpeeds[1]=result[1];
+ wheels4DynData->mWheelSpeeds[2]=result[2];
+ wheels4DynData->mWheelSpeeds[3]=result[3];
+ driveDynData->setEngineRotationSpeed(result[4]);
+}
+
+void solveDriveNWInternalDynamicsEnginePlusDrivenWheels
+(const ImplicitSolverInput& input, ImplicitSolverOutput* output)
+{
+ const PxF32 subTimestep = input.subTimeStep;
+ //const PxF32 brake = input.brake;
+ //const PxF32 handbrake = input.handBrake;
+ const PxF32 K = input.K;
+ const PxF32 G = input.G;
+ const PxVehicleClutchAccuracyMode::Enum accuracyMode = input.accuracyMode;
+ const PxU32 maxIterations = input.maxNumIterations;
+ const PxF32 engineDriveTorque = input.engineDriveTorque;
+ const PxF32 engineDampingRate = input.engineDampingRate;
+ const PxF32* PX_RESTRICT diffTorqueRatios = input.diffTorqueRatios;
+ const PxF32* PX_RESTRICT aveWheelSpeedContributions = input.aveWheelSpeedContributions;
+ const PxF32* PX_RESTRICT brakeTorques = input.brakeTorques;
+ const bool* PX_RESTRICT isBrakeApplied = input.isBrakeApplied;
+ const PxF32* PX_RESTRICT tireTorques = input.tireTorques;
+ //const PxU32 numWheels4 = input.numWheels4;
+ const PxU32 numActiveWheels = input.numActiveWheels;
+ const PxVehicleWheels4SimData* PX_RESTRICT wheels4SimDatas = input.wheels4SimData;
+ const PxVehicleDriveSimDataNW& driveSimData = *static_cast<const PxVehicleDriveSimDataNW*>(input.driveSimData);
+
+ PxVehicleDriveDynData* driveDynData = output->driveDynData;
+ PxVehicleWheels4DynData* wheels4DynDatas = output->wheelsDynData;
+
+ const PxF32 KG=K*G;
+ const PxF32 KGG=K*G*G;
+
+ MatrixNN A(numActiveWheels+1);
+ VectorN b(numActiveWheels+1);
+ VectorN result(numActiveWheels+1);
+
+ const PxVehicleEngineData& engineData=driveSimData.getEngineData();
+ const PxF32 engineOmega=driveDynData->getEngineRotationSpeed();
+
+ //
+ //torque at clutch:
+ //tc = K*{G*[alpha0*w0 + alpha1*w1 + alpha2*w2 + ..... alpha(N-1)*w(N-1)] - wEng}
+ //where
+ //(i) G is the gearing ratio,
+ //(ii) alphai is the fractional contribution of the ith wheel to the average wheel speed at the clutch (alpha(i) is zero for undriven wheels)
+ //(iii) wi is the angular speed of the ith wheel
+ //(iv) K is the clutch strength
+ //(v) wEng is the angular speed of the engine
+
+ //torque applied to ith wheel is
+ //ti = G*gammai*tc + bt(i) + tt(i)
+ //where
+ //gammai is the fractional proportion of the clutch torque that the differential delivers to the ith wheel
+ //bt(i) is the brake torque applied to the ith wheel
+ //tt(i) is the tire torque applied to the ith wheel
+
+ //acceleration applied to ith wheel is
+ //ai = G*gammai*K*{G*[alpha0*w0 + alpha1*w1 alpha2*w2 + ..... alpha(N-1)*w(N-1)] - wEng}/Ii + (bt(i) + tt(i))/Ii
+ //wheer Ii is the moi of the ith wheel.
+
+ //express ai as
+ //ai = [wi(t+dt) - wi(t)]/dt
+ //and rearrange
+ //wi(t+dt) - wi(t)] = dt*G*gammai*K*{G*[alpha0*w0(t+dt) + alpha1*w1(t+dt) + alpha2*w2(t+dt) + ..... alpha(N-1)*w(N-1)(t+dt)] - wEng(t+dt)}/Ii + dt*(bt(i) + tt(i))/Ii
+
+ //Do the same for tEng (torque applied to engine)
+ //tEng = -tc + engineDriveTorque
+ //where engineDriveTorque is the drive torque applied to the engine
+ //Assuming the engine has unit mass then
+ //wEng(t+dt) -wEng(t) = -dt*K*{G*[alpha0*w0(t+dt) + alpha1*w1(t+dt) + alpha2*w2(t+dt) + ..... alpha(N-1)*w(N-1(t+dt))] - wEng(t+dt)}/Ieng + dt*engineDriveTorque/Ieng
+
+ //Introduce the vector w=(w0,w1,w2....w(N-1), wEng)
+ //and re-express as a matrix after collecting all unknowns at (t+dt) and knowns at time t.
+ //A*w(t+dt)=b(t);
+
+ //Wheels.
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ const PxF32 dt=subTimestep*wheels4SimDatas[i>>2].getWheelData(i&3).getRecipMOI();
+ const PxF32 R=diffTorqueRatios[i];
+ const PxF32 dtKGGR=dt*KGG*R;
+
+ for(PxU32 j=0;j<numActiveWheels;j++)
+ {
+ A.set(i,j,dtKGGR*aveWheelSpeedContributions[j]);
+ }
+
+ A.set(i,i,1.0f+dtKGGR*aveWheelSpeedContributions[i]+dt*wheels4SimDatas[i>>2].getWheelData(i&3).mDampingRate);
+ A.set(i,numActiveWheels,-dt*KG*R);
+ b[i] = wheels4DynDatas[i>>2].mWheelSpeeds[i&3] + dt*(brakeTorques[i]+tireTorques[i]);
+ result[i] = wheels4DynDatas[i>>2].mWheelSpeeds[i&3];
+ }
+
+ //Engine.
+ {
+ const PxF32 dt=subTimestep*driveSimData.getEngineData().getRecipMOI();
+ const PxF32 dtKG=dt*K*G;
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ A.set(numActiveWheels,i,-dtKG*aveWheelSpeedContributions[i]);
+ }
+ A.set(numActiveWheels,numActiveWheels,1.0f + dt*(K+engineDampingRate));
+ b[numActiveWheels] = engineOmega + dt*engineDriveTorque;
+ result[numActiveWheels] = engineOmega;
+ }
+
+ //Solve Aw=b
+ if(PxVehicleClutchAccuracyMode::eBEST_POSSIBLE == accuracyMode)
+ {
+ MatrixNNLUSolver solver;
+ solver.decomposeLU(A);
+ solver.solve(b,result);
+ PX_WARN_ONCE_IF(!isValid(A,b,result), "Unable to compute new PxVehicleDriveNW internal rotation speeds. Please check vehicle sim data, especially clutch strength; engine moi and damping; wheel moi and damping");
+ }
+ else
+ {
+ MatrixNGaussSeidelSolver solver;
+ solver.solve(maxIterations, gSolverTolerance, A, b, result);
+ }
+
+ //Check for sanity in the resultant internal rotation speeds.
+ //If the brakes are on and the wheels have switched direction then lock them at zero.
+ //A consequence of this quick fix is that locked wheels remain locked until the brake is entirely released.
+ //This isn't strictly mathematically or physically correct - a more accurate solution would either formulate the
+ //brake as a lcp problem or repeatedly solve with constraints that locked wheels remain at zero rotation speed.
+ //The physically correct solution will certainly be more expensive so let's live with the restriction that
+ //locked wheels remain locked until the brake is released.
+ //newOmega=result[i], oldOmega=wheelSpeeds[i], if newOmega*oldOmega<=0 and isBrakeApplied then lock wheel.
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ result[i]=(isBrakeApplied[i] && (wheels4DynDatas[i>>2].mWheelSpeeds[i&3]*result[i]<=0)) ? 0.0f : result[i];
+ }
+ //Clamp the engine revs.
+ //Again, this is not physically or mathematically correct but the loss in behaviour will be hard to notice.
+ result[numActiveWheels]=PxClamp(result[numActiveWheels],0.0f,engineData.mMaxOmega);
+
+ //Copy back to the car's internal rotation speeds.
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ wheels4DynDatas[i>>2].mWheelSpeeds[i&3]=result[i];
+ }
+ driveDynData->setEngineRotationSpeed(result[numActiveWheels]);
+}
+
+
+void solveTankInternaDynamicsEnginePlusDrivenWheels
+(const ImplicitSolverInput& input, const bool* PX_RESTRICT activeWheelStates, const PxF32* PX_RESTRICT wheelGearings, ImplicitSolverOutput* output)
+{
+ PX_SIMD_GUARD; // denormal exception triggered at oldOmega*newOmega on osx
+ const PxF32 subTimestep = input.subTimeStep;
+ const PxF32 K = input.K;
+ const PxF32 G = input.G;
+ const PxF32 engineDriveTorque = input.engineDriveTorque;
+ const PxF32 engineDampingRate = input.engineDampingRate;
+ const PxF32* PX_RESTRICT diffTorqueRatios = input.diffTorqueRatios;
+ const PxF32* PX_RESTRICT aveWheelSpeedContributions = input.aveWheelSpeedContributions;
+ const PxF32* PX_RESTRICT brakeTorques = input.brakeTorques;
+ const bool* PX_RESTRICT isBrakeApplied = input.isBrakeApplied;
+ const PxF32* PX_RESTRICT tireTorques = input.tireTorques;
+ const PxU32 numWheels4 = input.numWheels4;
+ const PxU32 numActiveWheels = input.numActiveWheels;
+ const PxVehicleWheels4SimData* PX_RESTRICT wheels4SimDatas = input.wheels4SimData;
+ const PxVehicleDriveSimData& driveSimData = *input.driveSimData;
+
+ PxVehicleWheels4DynData* PX_RESTRICT wheels4DynDatas = output->wheelsDynData;
+ PxVehicleDriveDynData* driveDynData = output->driveDynData;
+
+ const PxF32 KG=K*G;
+ const PxF32 KGG=K*G*G;
+
+ //Rearrange data in a single array rather than scattered in blocks of 4.
+ //This makes it easier later on.
+ PxF32 recipMOI[PX_MAX_NB_WHEELS];
+ PxF32 dampingRates[PX_MAX_NB_WHEELS];
+ PxF32 wheelSpeeds[PX_MAX_NB_WHEELS];
+ PxF32 wheelRecipRadii[PX_MAX_NB_WHEELS];
+
+ for(PxU32 i=0;i<numWheels4-1;i++)
+ {
+ const PxVehicleWheelData& wheelData0=wheels4SimDatas[i].getWheelData(0);
+ const PxVehicleWheelData& wheelData1=wheels4SimDatas[i].getWheelData(1);
+ const PxVehicleWheelData& wheelData2=wheels4SimDatas[i].getWheelData(2);
+ const PxVehicleWheelData& wheelData3=wheels4SimDatas[i].getWheelData(3);
+
+ recipMOI[4*i+0]=wheelData0.getRecipMOI();
+ recipMOI[4*i+1]=wheelData1.getRecipMOI();
+ recipMOI[4*i+2]=wheelData2.getRecipMOI();
+ recipMOI[4*i+3]=wheelData3.getRecipMOI();
+
+ dampingRates[4*i+0]=wheelData0.mDampingRate;
+ dampingRates[4*i+1]=wheelData1.mDampingRate;
+ dampingRates[4*i+2]=wheelData2.mDampingRate;
+ dampingRates[4*i+3]=wheelData3.mDampingRate;
+
+ wheelRecipRadii[4*i+0]=wheelData0.getRecipRadius();
+ wheelRecipRadii[4*i+1]=wheelData1.getRecipRadius();
+ wheelRecipRadii[4*i+2]=wheelData2.getRecipRadius();
+ wheelRecipRadii[4*i+3]=wheelData3.getRecipRadius();
+
+ const PxVehicleWheels4DynData& suspWheelTire4=wheels4DynDatas[i];
+ wheelSpeeds[4*i+0]=suspWheelTire4.mWheelSpeeds[0];
+ wheelSpeeds[4*i+1]=suspWheelTire4.mWheelSpeeds[1];
+ wheelSpeeds[4*i+2]=suspWheelTire4.mWheelSpeeds[2];
+ wheelSpeeds[4*i+3]=suspWheelTire4.mWheelSpeeds[3];
+ }
+ const PxU32 numInLastBlock = 4 - (4*numWheels4 - numActiveWheels);
+ for(PxU32 i=0;i<numInLastBlock;i++)
+ {
+ const PxVehicleWheelData& wheelData=wheels4SimDatas[numWheels4-1].getWheelData(i);
+ recipMOI[4*(numWheels4-1)+i]=wheelData.getRecipMOI();
+ dampingRates[4*(numWheels4-1)+i]=wheelData.mDampingRate;
+ wheelRecipRadii[4*(numWheels4-1)+i]=wheelData.getRecipRadius();
+
+ const PxVehicleWheels4DynData& suspWheelTire4=wheels4DynDatas[numWheels4-1];
+ wheelSpeeds[4*(numWheels4-1)+i]=suspWheelTire4.mWheelSpeeds[i];
+ }
+ const PxF32 wheelRadius0=wheels4SimDatas[0].getWheelData(0).mRadius;
+ const PxF32 wheelRadius1=wheels4SimDatas[0].getWheelData(1).mRadius;
+
+ //
+ //torque at clutch:
+ //tc = K*{G*[alpha0*w0 + alpha1*w1 + alpha2*w2 + ..... alpha(N-1)*w(N-1)] - wEng}
+ //where
+ //(i) G is the gearing ratio,
+ //(ii) alphai is the fractional contribution of the ith wheel to the average wheel speed at the clutch (alpha(i) is zero for undriven wheels)
+ //(iii) wi is the angular speed of the ith wheel
+ //(iv) K is the clutch strength
+ //(v) wEng is the angular speed of the engine
+
+ //torque applied to ith wheel is
+ //ti = G*gammai*tc + bt(i) + tt(i)
+ //where
+ //gammai is the fractional proportion of the clutch torque that the differential delivers to the ith wheel
+ //bt(i) is the brake torque applied to the ith wheel
+ //tt(i) is the tire torque applied to the ith wheel
+
+ //acceleration applied to ith wheel is
+ //ai = G*gammai*K*{G*[alpha0*w0 + alpha1*w1 alpha2*w2 + ..... alpha(N-1)*w(N-1)] - wEng}/Ii + (bt(i) + tt(i))/Ii
+ //wheer Ii is the moi of the ith wheel.
+
+ //express ai as
+ //ai = [wi(t+dt) - wi(t)]/dt
+ //and rearrange
+ //wi(t+dt) - wi(t)] = dt*G*gammai*K*{G*[alpha0*w0(t+dt) + alpha1*w1(t+dt) + alpha2*w2(t+dt) + ..... alpha(N-1)*w(N-1)(t+dt)] - wEng(t+dt)}/Ii + dt*(bt(i) + tt(i))/Ii
+
+ //Do the same for tEng (torque applied to engine)
+ //tEng = -tc + engineDriveTorque
+ //where engineDriveTorque is the drive torque applied to the engine
+ //Assuming the engine has unit mass then
+ //wEng(t+dt) -wEng(t) = -dt*K*{G*[alpha0*w0(t+dt) + alpha1*w1(t+dt) + alpha2*w2(t+dt) + ..... alpha(N-1)*w(N-1(t+dt))] - wEng(t+dt)}/Ieng + dt*engineDriveTorque/Ieng
+
+ //Introduce the vector w=(w0,w1,w2....w(N-1), wEng)
+ //and re-express as a matrix after collecting all unknowns at (t+dt) and knowns at time t.
+ //M*w(t+dt)=b(t);
+
+ //Matrix M and rhs vector b that we use to solve Mw=b.
+ MatrixNN M(numActiveWheels+1);
+ VectorN b(numActiveWheels+1);
+
+ //Wheels.
+ {
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ const PxF32 dt=subTimestep*recipMOI[i];
+ const PxF32 R=diffTorqueRatios[i];
+ const PxF32 g=wheelGearings[i];
+ const PxF32 dtKGGRg=dt*KGG*R*g;
+ for(PxU32 j=0;j<numActiveWheels;j++)
+ {
+ M.set(i,j,dtKGGRg*aveWheelSpeedContributions[j]*wheelGearings[j]);
+ }
+ M.set(i,i,1.0f+dtKGGRg*aveWheelSpeedContributions[i]*wheelGearings[i]+dt*dampingRates[i]);
+ M.set(i,numActiveWheels,-dt*KG*R*g);
+ b[i] = wheelSpeeds[i] + dt*(brakeTorques[i]+tireTorques[i]);
+ }
+ }
+
+ //Engine.
+ {
+ const PxF32 engineOmega=driveDynData->getEngineRotationSpeed();
+
+ const PxF32 dt=subTimestep*driveSimData.getEngineData().getRecipMOI();
+ const PxF32 dtKG=dt*K*G;
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ M.set(numActiveWheels,i,-dtKG*aveWheelSpeedContributions[i]*wheelGearings[i]);
+ }
+ M.set(numActiveWheels,numActiveWheels,1.0f + dt*(K+engineDampingRate));
+ b[numActiveWheels] = engineOmega + dt*engineDriveTorque;
+ }
+
+ //Now apply the constraints that all the odd numbers are equal and all the even numbers are equal.
+ //ie w2,w4,w6 are all equal to w0 and w3,w5,w7 are all equal to w1.
+ //That leaves (4*N+1) equations but only 3 unknowns: two wheels speeds and the engine speed.
+ //Substitute these extra constraints into the matrix.
+ MatrixNN A(numActiveWheels+1);
+ for(PxU32 i=0;i<numActiveWheels+1;i++)
+ {
+ PxF32 sum0=M.get(i,0+0);
+ PxF32 sum1=M.get(i,0+1);
+ for(PxU32 j=2;j<numActiveWheels;j+=2)
+ {
+ sum0+=M.get(i,j+0)*wheelRadius0*wheelRecipRadii[j+0];
+ sum1+=M.get(i,j+1)*wheelRadius1*wheelRecipRadii[j+1];
+ }
+ A.set(i,0,sum0);
+ A.set(i,1,sum1);
+ A.set(i,2,M.get(i,numActiveWheels));
+ }
+
+ //We have an over-determined problem because of the extra constraints
+ //on equal wheel speeds. Solve using the least squares method as in
+ //http://s-mat-pcs.oulu.fi/~mpa/matreng/ematr5_5.htm
+
+ //Compute A^T*A
+ //No longer using M.
+ MatrixNN& ATA = M;
+ ATA.setSize(3);
+ for(PxU32 i=0;i<3;i++)
+ {
+ for(PxU32 j=0;j<3;j++)
+ {
+ PxF32 sum=0.0f;
+ for(PxU32 k=0;k<numActiveWheels+1;k++)
+ {
+ //sum+=AT.get(i,k)*A.get(k,j);
+ sum+=A.get(k,i)*A.get(k,j);
+ }
+ ATA.set(i,j,sum);
+ }
+ }
+
+ //Compute A^T*b;
+ VectorN ATb(3);
+ for(PxU32 i=0;i<3;i++)
+ {
+ PxF32 sum=0;
+ for(PxU32 j=0;j<numActiveWheels+1;j++)
+ {
+ //sum+=AT.get(i,j)*b[j];
+ sum+=A.get(j,i)*b[j];
+ }
+ ATb[i]=sum;
+ }
+
+ //Solve (A^T*A)*x = A^T*b
+ VectorN result(3);
+ Matrix33Solver solver;
+ bool successfulSolver = solver.solve(ATA, ATb, result);
+ if(!successfulSolver)
+ {
+ PX_WARN_ONCE("Unable to compute new PxVehicleDriveTank internal rotation speeds. Please check vehicle sim data, especially clutch strength; engine moi and damping; wheel moi and damping");
+ return;
+ }
+
+ //Clamp the engine revs between zero and maxOmega
+ const PxF32 maxEngineOmega=driveSimData.getEngineData().mMaxOmega;
+ const PxF32 newEngineOmega=PxClamp(result[2],0.0f,maxEngineOmega);
+
+ //Apply the constraints on each of the equal wheel speeds.
+ PxF32 wheelSpeedResults[PX_MAX_NB_WHEELS];
+ wheelSpeedResults[0]=result[0];
+ wheelSpeedResults[1]=result[1];
+ for(PxU32 i=2;i<numActiveWheels;i+=2)
+ {
+ wheelSpeedResults[i+0]=result[0];
+ wheelSpeedResults[i+1]=result[1];
+ }
+
+ //Check for sanity in the resultant internal rotation speeds.
+ //If the brakes are on and the wheels have switched direction then lock them at zero.
+ //A consequence of this quick fix is that locked wheels remain locked until the brake is entirely released.
+ //This isn't strictly mathematically or physically correct - a more accurate solution would either formulate the
+ //brake as a lcp problem or repeatedly solve with constraints that locked wheels remain at zero rotation speed.
+ //The physically correct solution will certainly be more expensive so let's live with the restriction that
+ //locked wheels remain locked until the brake is released.
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ const PxF32 oldOmega=wheelSpeeds[i];
+ const PxF32 newOmega=wheelSpeedResults[i];
+ const bool hasBrake=isBrakeApplied[i];
+ if(hasBrake && (oldOmega*newOmega <= 0))
+ {
+ wheelSpeedResults[i]=0.0f;
+ }
+ }
+
+
+ //Copy back to the car's internal rotation speeds.
+ for(PxU32 i=0;i<numWheels4-1;i++)
+ {
+ wheels4DynDatas[i].mWheelSpeeds[0] = activeWheelStates[4*i+0] ? wheelSpeedResults[4*i+0] : 0.0f;
+ wheels4DynDatas[i].mWheelSpeeds[1] = activeWheelStates[4*i+1] ? wheelSpeedResults[4*i+1] : 0.0f;
+ wheels4DynDatas[i].mWheelSpeeds[2] = activeWheelStates[4*i+2] ? wheelSpeedResults[4*i+2] : 0.0f;
+ wheels4DynDatas[i].mWheelSpeeds[3] = activeWheelStates[4*i+3] ? wheelSpeedResults[4*i+3] : 0.0f;
+ }
+ for(PxU32 i=0;i<numInLastBlock;i++)
+ {
+ wheels4DynDatas[numWheels4-1].mWheelSpeeds[i] = activeWheelStates[4*(numWheels4-1)+i] ? wheelSpeedResults[4*(numWheels4-1)+i] : 0.0f;
+ }
+ driveDynData->setEngineRotationSpeed(newEngineOmega);
+}
+
+////////////////////////////////////////////////////////////////////////////
+//Integrate wheel rotation speeds of wheels not connected to the differential.
+//Obviously, no wheels in a PxVehicleNoDrive are connected to a diff so all require
+//direct integration.
+//Only the first 4 wheels of a PxVehicleDrive4W are connected to the diff so
+//any extra wheels need direct integration.
+//All tank wheels are connected to the diff so none need integrated in a separate pass.
+//What about undriven wheels in a PxVehicleDriveNW? This vehicle type treats all
+//wheels as being connected to the diff but sets the diff contribution to zero for
+//all undriven wheels. No wheels from a PxVehicleNW need integrated in a separate pass.
+////////////////////////////////////////////////////////////////////////////
+
+void integrateNoDriveWheelSpeeds
+(const PxF32 subTimestep,
+ const PxF32* PX_RESTRICT brakeTorques, const bool* PX_RESTRICT isBrakeApplied, const PxF32* driveTorques, const PxF32* PX_RESTRICT tireTorques, const PxF32* PX_RESTRICT dampingRates,
+ const PxVehicleWheels4SimData& vehSuspWheelTire4SimData, PxVehicleWheels4DynData& vehSuspWheelTire4)
+{
+ //w(t+dt) = w(t) + (1/inertia)*(brakeTorque + driveTorque + tireTorque)*dt - (1/inertia)*damping*w(t)*dt ) (1)
+ //Apply implicit trick and rearrange.
+ //w(t+dt)[1 + (1/inertia)*damping*dt] = w(t) + (1/inertia)*(brakeTorque + driveTorque + tireTorque)*dt (2)
+
+ //Introduce (1/inertia)*dt to avoid duplication in (2)
+ PxF32 subTimeSteps[4] =
+ {
+ subTimestep*vehSuspWheelTire4SimData.getWheelData(0).getRecipMOI(),
+ subTimestep*vehSuspWheelTire4SimData.getWheelData(1).getRecipMOI(),
+ subTimestep*vehSuspWheelTire4SimData.getWheelData(2).getRecipMOI(),
+ subTimestep*vehSuspWheelTire4SimData.getWheelData(3).getRecipMOI()
+ };
+
+ //Integrate.
+ //w += torque*dt/inertia - damping*dt*w
+ //Use implicit integrate trick and rearrange
+ //w(t+dt) = [w(t) + torque*dt/inertia]/[1 + damping*dt]
+ const PxF32* PX_RESTRICT wheelSpeeds=vehSuspWheelTire4.mWheelSpeeds;
+ PxF32 result[4]=
+ {
+ (wheelSpeeds[0] + subTimeSteps[0]*(tireTorques[0] + driveTorques[0] + brakeTorques[0]))/(1.0f + dampingRates[0]*subTimeSteps[0]),
+ (wheelSpeeds[1] + subTimeSteps[1]*(tireTorques[1] + driveTorques[1] + brakeTorques[1]))/(1.0f + dampingRates[1]*subTimeSteps[1]),
+ (wheelSpeeds[2] + subTimeSteps[2]*(tireTorques[2] + driveTorques[2] + brakeTorques[2]))/(1.0f + dampingRates[2]*subTimeSteps[2]),
+ (wheelSpeeds[3] + subTimeSteps[3]*(tireTorques[3] + driveTorques[3] + brakeTorques[3]))/(1.0f + dampingRates[3]*subTimeSteps[3]),
+ };
+
+ //Check for sanity in the resultant internal rotation speeds.
+ //If the brakes are on and the wheels have switched direction then lock them at zero.
+ //newOmega=result[i], oldOmega=wheelSpeeds[i], if newOmega*oldOmega<=0 and isBrakeApplied then lock wheel.
+ result[0]=(isBrakeApplied[0] && (wheelSpeeds[0]*result[0]<=0)) ? 0.0f : result[0];
+ result[1]=(isBrakeApplied[1] && (wheelSpeeds[1]*result[1]<=0)) ? 0.0f : result[1];
+ result[2]=(isBrakeApplied[2] && (wheelSpeeds[2]*result[2]<=0)) ? 0.0f : result[2];
+ result[3]=(isBrakeApplied[3] && (wheelSpeeds[3]*result[3]<=0)) ? 0.0f : result[3];
+
+ //Copy back to the car's internal rotation speeds.
+ vehSuspWheelTire4.mWheelSpeeds[0]=result[0];
+ vehSuspWheelTire4.mWheelSpeeds[1]=result[1];
+ vehSuspWheelTire4.mWheelSpeeds[2]=result[2];
+ vehSuspWheelTire4.mWheelSpeeds[3]=result[3];
+}
+
+void integrateUndriveWheelRotationSpeeds
+(const PxF32 subTimestep,
+ const PxF32 brake, const PxF32 handbrake, const PxF32* PX_RESTRICT tireTorques, const PxF32* PX_RESTRICT brakeTorques,
+ const PxVehicleWheels4SimData& vehSuspWheelTire4SimData, PxVehicleWheels4DynData& vehSuspWheelTire4)
+{
+ for(PxU32 i=0;i<4;i++)
+ {
+ //Compute the new angular speed of the wheel.
+ const PxF32 oldOmega=vehSuspWheelTire4.mWheelSpeeds[i];
+ const PxF32 dtI = subTimestep*vehSuspWheelTire4SimData.getWheelData(i).getRecipMOI();
+ const PxF32 gamma = vehSuspWheelTire4SimData.getWheelData(i).mDampingRate;
+ const PxF32 newOmega=(oldOmega+dtI*(tireTorques[i]+brakeTorques[i]))/(1.0f + gamma*dtI);
+
+ //Has the brake been applied? It's hard to tell from brakeTorques[j] because that
+ //will be zero if the wheel is locked. Work it out from the brake and handbrake data.
+ const PxF32 brakeGain=vehSuspWheelTire4SimData.getWheelData(i).mMaxBrakeTorque;
+ const PxF32 handbrakeGain=vehSuspWheelTire4SimData.getWheelData(i).mMaxHandBrakeTorque;
+
+ //Work out if the wheel should be locked.
+ const bool brakeApplied=((brake*brakeGain + handbrake*handbrakeGain)!=0.0f);
+ const bool wheelReversed=(oldOmega*newOmega <=0);
+ const bool wheelLocked=(brakeApplied && wheelReversed);
+
+ //Lock the wheel or apply its new angular speed.
+ if(!wheelLocked)
+ {
+ vehSuspWheelTire4.mWheelSpeeds[i]=newOmega;
+ }
+ else
+ {
+ vehSuspWheelTire4.mWheelSpeeds[i]=0.0f;
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+//Pose the wheels.
+//First integrate the wheel rotation angles and clamp them to a range (-10*pi, 10*pi)
+//PxVehicleNoDrive has a different way of telling if a wheel is driven by a drive torque so has a separate function.
+//Use the wheel steer/rotation/camber angle and suspension jounce to compute the local transform of each wheel.
+////////////////////////////////////////////////////////////////////////////
+
+void integrateWheelRotationAngles
+(const PxF32 timestep,
+ const PxF32 K, const PxF32 G, const PxF32 engineDriveTorque,
+ const PxF32* PX_RESTRICT jounces, const PxF32* PX_RESTRICT diffTorqueRatios, const PxF32* PX_RESTRICT forwardSpeeds, const bool* isBrakeApplied,
+ const PxVehicleDriveSimData& vehCoreSimData, const PxVehicleWheels4SimData& vehSuspWheelTire4SimData,
+ PxVehicleDriveDynData& vehCore, PxVehicleWheels4DynData& vehSuspWheelTire4)
+{
+ PX_SIMD_GUARD; //denorm exception on newRotAngle=wheelRotationAngles[j]+wheelOmega*timestep; on osx
+
+ PX_UNUSED(vehCore);
+ PX_UNUSED(vehCoreSimData);
+
+ const PxF32 KG=K*G;
+
+ PxF32* PX_RESTRICT wheelSpeeds=vehSuspWheelTire4.mWheelSpeeds;
+ PxF32* PX_RESTRICT wheelRotationAngles=vehSuspWheelTire4.mWheelRotationAngles;
+ PxF32* PX_RESTRICT correctedWheelSpeeds = vehSuspWheelTire4.mCorrectedWheelSpeeds;
+
+ for(PxU32 j=0;j<4;j++)
+ {
+ //At low vehicle forward speeds we have some numerical difficulties getting the
+ //wheel rotation speeds to be correct due to the tire model's difficulties at low vz.
+ //The solution is to blend between the rolling speed at the wheel and the wheel's actual rotation speed.
+ //If the wheel is
+ //(i) in the air or,
+ //(ii) under braking torque or,
+ //(iii) driven by the engine through the gears and diff
+ //then always use the wheel's actual rotation speed.
+ //Just to be clear, this means we will blend when the wheel
+ //(i) is on the ground and
+ //(ii) has no brake applied and
+ //(iii) has no drive torque applied from the clutch and
+ //(iv) is at low forward speed
+ PxF32 wheelOmega=wheelSpeeds[j];
+ if(jounces[j] > -vehSuspWheelTire4SimData.getSuspensionData(j).mMaxDroop && //(i) wheel touching ground
+ false==isBrakeApplied[j] && //(ii) no brake applied
+ 0.0f==diffTorqueRatios[j]*KG*engineDriveTorque && //(iii) no drive torque applied
+ PxAbs(forwardSpeeds[j])<gThresholdForwardSpeedForWheelAngleIntegration) //(iv) low speed
+ {
+ const PxF32 recipWheelRadius=vehSuspWheelTire4SimData.getWheelData(j).getRecipRadius();
+ const PxF32 alpha=PxAbs(forwardSpeeds[j])*gRecipThresholdForwardSpeedForWheelAngleIntegration;
+ wheelOmega = (forwardSpeeds[j]*recipWheelRadius)*(1.0f-alpha) + wheelOmega*alpha;
+ }
+
+ PxF32 newRotAngle=wheelRotationAngles[j]+wheelOmega*timestep;
+ //Clamp the wheel rotation angle to a range (-10*pi,10*pi) to stop it getting crazily big.
+ newRotAngle=physx::intrinsics::fsel(newRotAngle-10*PxPi, newRotAngle-10*PxPi, physx::intrinsics::fsel(-newRotAngle-10*PxPi, newRotAngle + 10*PxPi, newRotAngle));
+ wheelRotationAngles[j]=newRotAngle;
+ correctedWheelSpeeds[j]=wheelOmega;
+ }
+}
+
+void integrateNoDriveWheelRotationAngles
+(const PxF32 timestep,
+ const PxF32* PX_RESTRICT driveTorques,
+ const PxF32* PX_RESTRICT jounces, const PxF32* PX_RESTRICT forwardSpeeds, const bool* isBrakeApplied,
+ const PxVehicleWheels4SimData& vehSuspWheelTire4SimData,
+ PxVehicleWheels4DynData& vehSuspWheelTire4)
+{
+ PxF32* PX_RESTRICT wheelSpeeds=vehSuspWheelTire4.mWheelSpeeds;
+ PxF32* PX_RESTRICT wheelRotationAngles=vehSuspWheelTire4.mWheelRotationAngles;
+ PxF32* PX_RESTRICT correctedWheelSpeeds=vehSuspWheelTire4.mCorrectedWheelSpeeds;
+
+ for(PxU32 j=0;j<4;j++)
+ {
+ //At low vehicle forward speeds we have some numerical difficulties getting the
+ //wheel rotation speeds to be correct due to the tire model's difficulties at low vz.
+ //The solution is to blend between the rolling speed at the wheel and the wheel's actual rotation speed.
+ //If the wheel is
+ //(i) in the air or,
+ //(ii) under braking torque or,
+ //(iii) driven by a drive torque
+ //then always use the wheel's actual rotation speed.
+ //Just to be clear, this means we will blend when the wheel
+ //(i) is on the ground and
+ //(ii) has no brake applied and
+ //(iii) has no drive torque and
+ //(iv) is at low forward speed
+ PxF32 wheelOmega=wheelSpeeds[j];
+ if(jounces[j] > -vehSuspWheelTire4SimData.getSuspensionData(j).mMaxDroop && //(i) wheel touching ground
+ false==isBrakeApplied[j] && //(ii) no brake applied
+ 0.0f==driveTorques[j] && //(iii) no drive torque applied
+ PxAbs(forwardSpeeds[j])<gThresholdForwardSpeedForWheelAngleIntegration) //(iv) low speed
+ {
+ const PxF32 recipWheelRadius=vehSuspWheelTire4SimData.getWheelData(j).getRecipRadius();
+ const PxF32 alpha=PxAbs(forwardSpeeds[j])*gRecipThresholdForwardSpeedForWheelAngleIntegration;
+ wheelOmega = (forwardSpeeds[j]*recipWheelRadius)*(1.0f-alpha) + wheelOmega*alpha;
+
+ //TODO: maybe just set the car wheel omega to the blended value?
+ //Not sure about this bit.
+ //Turned this off because it added energy to the car at very small timesteps.
+ //wheelSpeeds[j]=wheelOmega;
+ }
+
+ PxF32 newRotAngle=wheelRotationAngles[j]+wheelOmega*timestep;
+ //Clamp the wheel rotation angle to a range (-10*pi,10*pi) to stop it getting crazily big.
+ newRotAngle=physx::intrinsics::fsel(newRotAngle-10*PxPi, newRotAngle-10*PxPi, physx::intrinsics::fsel(-newRotAngle-10*PxPi, newRotAngle + 10*PxPi, newRotAngle));
+ wheelRotationAngles[j]=newRotAngle;
+ correctedWheelSpeeds[j]=wheelOmega;
+ }
+}
+
+void computeWheelLocalPoses
+(const PxVehicleWheels4SimData& wheelsSimData,
+ const PxVehicleWheels4DynData& wheelsDynData,
+ const PxWheelQueryResult* wheelQueryResults,
+ const PxU32 numWheelsToPose,
+ const PxTransform& vehChassisCMLocalPose,
+ PxTransform* localPoses)
+{
+ const PxF32* PX_RESTRICT rotAngles=wheelsDynData.mWheelRotationAngles;
+
+ const PxVec3 cmOffset=vehChassisCMLocalPose.p;
+
+ const PxVec3 forward = gRight.cross(gUp);
+
+ for(PxU32 i=0;i<numWheelsToPose;i++)
+ {
+ const PxF32 jounce=wheelQueryResults[i].suspJounce;
+
+ //Compute the camber angle.
+ const PxVehicleSuspensionData& suspData=wheelsSimData.getSuspensionData(i);
+ PxF32 camberAngle=suspData.mCamberAtRest;
+ if(jounce > 0.0f)
+ {
+ camberAngle += jounce*suspData.mCamberAtMaxCompression*suspData.getRecipMaxCompression();
+ }
+ else
+ {
+ camberAngle -= jounce*suspData.mCamberAtMaxDroop*suspData.getRecipMaxDroop();
+ }
+
+ //Compute the transform of the wheel shapes.
+ const PxVec3 pos=cmOffset+wheelsSimData.getWheelCentreOffset(i)-wheelsSimData.getSuspTravelDirection(i)*jounce;
+ const PxQuat quat(wheelQueryResults[i].steerAngle, gUp);
+ const PxQuat quat2(camberAngle, quat.rotate(forward));
+ const PxQuat quat3=quat2*quat;
+ const PxQuat quat4(rotAngles[i],quat3.rotate(gRight));
+ const PxTransform t(pos,quat4*quat3);
+ localPoses[i] = t;
+ }
+}
+
+void poseWheels
+(const PxVehicleWheels4SimData& wheelsSimData,
+ const PxTransform* localPoses,
+ const PxU32 numWheelsToPose,
+ PxRigidDynamic* vehActor)
+{
+ PxShape* shapeBuffer[128];
+ vehActor->getShapes(shapeBuffer,128,0);
+
+ for(PxU32 i=0;i<numWheelsToPose;i++)
+ {
+ const PxI32 shapeIndex = wheelsSimData.getWheelShapeMapping(i);
+ if(shapeIndex != -1)
+ {
+ PxShape* currShape = NULL;
+ if(shapeIndex < 128)
+ {
+ currShape = shapeBuffer[shapeIndex];
+ }
+ else
+ {
+ PxShape* shapeBuffer2[1];
+ vehActor->getShapes(shapeBuffer2,1,PxU32(shapeIndex));
+ currShape = shapeBuffer2[0];
+ }
+ PX_ASSERT(currShape);
+ currShape->setLocalPose(localPoses[i]);
+ }
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////
+//Update each vehicle type with a special function
+////////////////////////////////////////////////////////////////////////////
+
+class PxVehicleUpdate
+{
+public:
+
+#if PX_DEBUG_VEHICLE_ON
+ static void updateSingleVehicleAndStoreTelemetryData(
+ const PxF32 timestep, const PxVec3& gravity, const PxVehicleDrivableSurfaceToTireFrictionPairs& vehicleDrivableSurfaceToTireFrictionPairs,
+ PxVehicleWheels* focusVehicle, PxVehicleWheelQueryResult* vehWheelQueryResults, PxVehicleTelemetryData& telemetryData);
+#endif
+
+ static void update(
+ const PxF32 timestep, const PxVec3& gravity, const PxVehicleDrivableSurfaceToTireFrictionPairs& vehicleDrivableSurfaceToTireFrictionPairs,
+ const PxU32 numVehicles, PxVehicleWheels** vehicles, PxVehicleWheelQueryResult* wheelQueryResults, PxVehicleConcurrentUpdateData* vehicleConcurrentUpdates);
+
+ static void updatePost(
+ const PxVehicleConcurrentUpdateData* vehicleConcurrentUpdates, const PxU32 numVehicles, PxVehicleWheels** vehicles);
+
+ static void suspensionRaycasts(
+ PxBatchQuery* batchQuery,
+ const PxU32 numVehicles, PxVehicleWheels** vehicles, const PxU32 numSceneQueryResults, PxRaycastQueryResult* sceneQueryResults,
+ const bool* vehiclesToRaycast);
+
+ static void suspensionSweeps(
+ PxBatchQuery* batchQuery,
+ const PxU32 numVehicles, PxVehicleWheels** vehicles,
+ const PxU32 numSceneQueryResults, PxSweepQueryResult* sceneQueryResults, const PxU16 nbHitsPerQuery,
+ const bool* vehiclesToRaycast,
+ const PxF32 sweepWidthScale, const PxF32 sweepRadiusScale);
+
+ static void updateDrive4W(
+ const PxF32 timestep,
+ const PxVec3& gravity, const PxF32 gravityMagnitude, const PxF32 recipGravityMagnitude,
+ const PxVehicleDrivableSurfaceToTireFrictionPairs& drivableSurfaceToTireFrictionPairs,
+ PxVehicleDrive4W* vehDrive4W, PxVehicleWheelQueryResult* vehWheelQueryResults, PxVehicleConcurrentUpdateData* vehConcurrentUpdates);
+
+ static void updateDriveNW(
+ const PxF32 timestep,
+ const PxVec3& gravity, const PxF32 gravityMagnitude, const PxF32 recipGravityMagnitude,
+ const PxVehicleDrivableSurfaceToTireFrictionPairs& drivableSurfaceToTireFrictionPairs,
+ PxVehicleDriveNW* vehDriveNW, PxVehicleWheelQueryResult* vehWheelQueryResults, PxVehicleConcurrentUpdateData* vehConcurrentUpdates);
+
+ static void updateTank(
+ const PxF32 timestep,
+ const PxVec3& gravity, const PxF32 gravityMagnitude, const PxF32 recipGravityMagnitude,
+ const PxVehicleDrivableSurfaceToTireFrictionPairs& drivableSurfaceToTireFrictionPairs,
+ PxVehicleDriveTank* vehDriveTank, PxVehicleWheelQueryResult* vehWheelQueryResults, PxVehicleConcurrentUpdateData* vehConcurrentUpdates);
+
+ static void updateNoDrive(
+ const PxF32 timestep,
+ const PxVec3& gravity, const PxF32 gravityMagnitude, const PxF32 recipGravityMagnitude,
+ const PxVehicleDrivableSurfaceToTireFrictionPairs& drivableSurfaceToTireFrictionPairs,
+ PxVehicleNoDrive* vehDriveTank, PxVehicleWheelQueryResult* vehWheelQueryResults, PxVehicleConcurrentUpdateData* vehConcurrentUpdates);
+
+ static PxU32 computeNumberOfSubsteps(const PxVehicleWheelsSimData& wheelsSimData, const PxVec3& linVel, const PxTransform& globalPose, const PxVec3& forward)
+ {
+ const PxVec3 z=globalPose.q.rotate(forward);
+ const PxF32 vz=PxAbs(linVel.dot(z));
+ const PxF32 thresholdVz=wheelsSimData.mThresholdLongitudinalSpeed;
+ const PxU32 lowCount=wheelsSimData.mLowForwardSpeedSubStepCount;
+ const PxU32 highCount=wheelsSimData.mHighForwardSpeedSubStepCount;
+ const PxU32 count=(vz<thresholdVz ? lowCount : highCount);
+ return count;
+ }
+
+ PX_INLINE static void setInternalDynamicsToZero(PxVehicleWheelsDynData& wheels)
+ {
+ const PxU32 nbWheels4 = (wheels.mNbActiveWheels + 3) >> 2;
+ PxVehicleWheels4DynData* wheels4 = wheels.getWheel4DynData();
+ for(PxU32 i = 0; i < nbWheels4; i++)
+ {
+ wheels4[i].setInternalDynamicsToZero();
+ }
+ }
+
+ PX_INLINE static void setInternalDynamicsToZero(PxVehicleDriveDynData& drive)
+ {
+ drive.setEngineRotationSpeed(0.0f);
+ }
+
+ PX_INLINE static void setInternalDynamicsToZero(PxVehicleNoDrive* veh)
+ {
+ setInternalDynamicsToZero(veh->mWheelsDynData);
+ }
+
+ PX_INLINE static void setInternalDynamicsToZero(PxVehicleDrive4W* veh)
+ {
+ setInternalDynamicsToZero(veh->mWheelsDynData);
+ setInternalDynamicsToZero(veh->mDriveDynData);
+ }
+
+ PX_INLINE static void setInternalDynamicsToZero(PxVehicleDriveNW* veh)
+ {
+ veh->mDriveDynData.setEngineRotationSpeed(0.0f);
+ setInternalDynamicsToZero(veh->mWheelsDynData);
+ setInternalDynamicsToZero(veh->mDriveDynData);
+ }
+
+ PX_INLINE static void setInternalDynamicsToZero(PxVehicleDriveTank* veh)
+ {
+ setInternalDynamicsToZero(veh->mWheelsDynData);
+ setInternalDynamicsToZero(veh->mDriveDynData);
+ }
+
+
+ PX_INLINE static bool isOnDynamicActor(const PxVehicleWheelsSimData& wheelsSimData, const PxVehicleWheelsDynData& wheelsDynData)
+ {
+ const PxU32 numWheels4 = wheelsSimData.mNbWheels4;
+ const PxVehicleWheels4DynData* PX_RESTRICT wheels4DynDatas = wheelsDynData.mWheels4DynData;
+
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ const PxRaycastQueryResult* raycastResults = wheels4DynDatas[i].mRaycastResults;
+ const PxSweepQueryResult* sweepResults = wheels4DynDatas[i].mSweepResults;
+
+ for(PxU32 j=0;j<4;j++)
+ {
+ if(!wheelsSimData.getIsWheelDisabled(4*i + j))
+ {
+ const PxU32 hitCount = PxU32(raycastResults ? raycastResults[j].hasBlock : sweepResults[j].hasBlock);
+ const PxLocationHit& hit = raycastResults ? static_cast<const PxLocationHit&>(raycastResults[j].block) : static_cast<const PxLocationHit&>(sweepResults[j].block);
+ if(hitCount && hit.actor && hit.actor->is<PxRigidDynamic>())
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ PX_INLINE static void storeRaycasts(const PxVehicleWheels4DynData& dynData, PxWheelQueryResult* wheelQueryResults)
+ {
+ if(dynData.mRaycastResults)
+ {
+ for(PxU32 i=0;i<4;i++)
+ {
+ const PxVehicleWheels4DynData::SuspLineRaycast& raycast =
+ reinterpret_cast<const PxVehicleWheels4DynData::SuspLineRaycast&>(dynData.mQueryOrCachedHitResults);
+
+ wheelQueryResults[i].suspLineStart=raycast.mStarts[i];
+ wheelQueryResults[i].suspLineDir=raycast.mDirs[i];
+ wheelQueryResults[i].suspLineLength=raycast.mLengths[i];
+ }
+ }
+ else if(dynData.mSweepResults)
+ {
+ for(PxU32 i=0;i<4;i++)
+ {
+ const PxVehicleWheels4DynData::SuspLineSweep& sweep =
+ reinterpret_cast<const PxVehicleWheels4DynData::SuspLineSweep&>(dynData.mQueryOrCachedHitResults);
+
+ wheelQueryResults[i].suspLineStart=sweep.mStartPose[i].p;
+ wheelQueryResults[i].suspLineDir=sweep.mDirs[i];
+ wheelQueryResults[i].suspLineLength=sweep.mLengths[i];
+ }
+ }
+ else
+ {
+ for(PxU32 i=0;i<4;i++)
+ {
+ wheelQueryResults[i].suspLineStart=PxVec3(0,0,0);
+ wheelQueryResults[i].suspLineDir=PxVec3(0,0,0);
+ wheelQueryResults[i].suspLineLength=0;
+ }
+ }
+ }
+
+ PX_INLINE static void storeSuspWheelTireResults
+ (const ProcessSuspWheelTireOutputData& outputData, const PxF32* steerAngles, PxWheelQueryResult* wheelQueryResults, const PxU32 numWheels)
+ {
+ for(PxU32 i=0;i<numWheels;i++)
+ {
+ wheelQueryResults[i].isInAir=outputData.isInAir[i];
+ wheelQueryResults[i].tireContactActor=outputData.tireContactActors[i];
+ wheelQueryResults[i].tireContactShape=outputData.tireContactShapes[i];
+ wheelQueryResults[i].tireSurfaceMaterial=outputData.tireSurfaceMaterials[i];
+ wheelQueryResults[i].tireSurfaceType=outputData.tireSurfaceTypes[i];
+ wheelQueryResults[i].tireContactPoint=outputData.tireContactPoints[i];
+ wheelQueryResults[i].tireContactNormal=outputData.tireContactNormals[i];
+ wheelQueryResults[i].tireFriction=outputData.frictions[i];
+ wheelQueryResults[i].suspJounce=outputData.jounces[i];
+ wheelQueryResults[i].suspSpringForce=outputData.suspensionSpringForces[i];
+ wheelQueryResults[i].tireLongitudinalDir=outputData.tireLongitudinalDirs[i];
+ wheelQueryResults[i].tireLateralDir=outputData.tireLateralDirs[i];
+ wheelQueryResults[i].longitudinalSlip=outputData.longSlips[i];
+ wheelQueryResults[i].lateralSlip=outputData.latSlips[i];
+ wheelQueryResults[i].steerAngle=steerAngles[i];
+ }
+ }
+
+ PX_INLINE static void storeHitActorForces(const ProcessSuspWheelTireOutputData& outputData, PxVehicleWheelConcurrentUpdateData* wheelConcurrentUpdates, const PxU32 numWheels)
+ {
+ for(PxU32 i=0;i<numWheels;i++)
+ {
+ wheelConcurrentUpdates[i].hitActor=outputData.hitActors[i];
+ wheelConcurrentUpdates[i].hitActorForce+=outputData.hitActorForces[i];
+ wheelConcurrentUpdates[i].hitActorForcePosition=outputData.hitActorForcePositions[i];
+ }
+ }
+
+
+ static void shiftOrigin(const PxVec3& shift, const PxU32 numVehicles, PxVehicleWheels** vehicles);
+};
+
+void PxVehicleUpdate::updateDrive4W(
+const PxF32 timestep,
+const PxVec3& gravity, const PxF32 gravityMagnitude, const PxF32 recipGravityMagnitude,
+const PxVehicleDrivableSurfaceToTireFrictionPairs& drivableSurfaceToTireFrictionPairs,
+PxVehicleDrive4W* vehDrive4W, PxVehicleWheelQueryResult* vehWheelQueryResults, PxVehicleConcurrentUpdateData* vehConcurrentUpdates)
+{
+ PX_SIMD_GUARD; // denorm exception in transformInertiaTensor() on osx
+
+ START_TIMER(TIMER_ADMIN);
+
+ PX_CHECK_AND_RETURN(
+ vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL]>-0.01f &&
+ vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL]<1.01f,
+ "Illegal vehicle control value - accel must be in range (0,1)");
+ PX_CHECK_AND_RETURN(
+ vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE]>-0.01f &&
+ vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE]<1.01f,
+ "Illegal vehicle control value - brake must be in range (0,1)");
+ PX_CHECK_AND_RETURN(
+ vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE]>-0.01f &&
+ vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE]<1.01f,
+ "Illegal vehicle control value - handbrake must be in range (0,1)");
+ PX_CHECK_AND_RETURN(
+ vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT]>-1.01f &&
+ vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT]<1.01f,
+ "Illegal vehicle control value - left steer must be in range (-1,1)");
+ PX_CHECK_AND_RETURN(
+ vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT]>-1.01f &&
+ vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT]<1.01f,
+ "Illegal vehicle control value - right steer must be in range (-1,1)");
+ PX_CHECK_AND_RETURN(
+ PxAbs(vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT]-
+ vehDrive4W->mDriveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT])<1.01f,
+ "Illegal vehicle control value - right steer value minus left steer value must be in range (-1,1)");
+ PX_CHECK_AND_RETURN(
+ !(vehDrive4W->getRigidDynamicActor()->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC),
+ "Attempting to update a drive4W with a kinematic actor - this isn't allowed");
+ PX_CHECK_AND_RETURN(
+ NULL==vehWheelQueryResults || vehWheelQueryResults->nbWheelQueryResults >= vehDrive4W->mWheelsSimData.getNbWheels(),
+ "nbWheelQueryResults must always be greater than or equal to number of wheels in corresponding vehicle");
+ PX_CHECK_AND_RETURN(
+ NULL==vehConcurrentUpdates || vehConcurrentUpdates->nbConcurrentWheelUpdates >= vehDrive4W->mWheelsSimData.getNbWheels(),
+ "vehConcurrentUpdates->nbConcurrentWheelUpdates must always be greater than or equal to number of wheels in corresponding vehicle");
+
+#if PX_CHECKED
+ {
+ //Check that the sense of left/right and forward/rear is true.
+ const PxVec3 fl=vehDrive4W->mWheelsSimData.mWheels4SimData[0].getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT);
+ const PxVec3 fr=vehDrive4W->mWheelsSimData.mWheels4SimData[0].getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT);
+ const PxVec3 rl=vehDrive4W->mWheelsSimData.mWheels4SimData[0].getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT);
+ const PxVec3 rr=vehDrive4W->mWheelsSimData.mWheels4SimData[0].getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_RIGHT);
+ const PxVec3 right=gRight;
+ const PxF32 s0=computeSign((fr-fl).dot(right));
+ const PxF32 s1=computeSign((rr-rl).dot(right));
+ PX_CHECK_AND_RETURN(0==s0 || 0==s1 || s0==s1, "PxVehicle4W does not obey the rule that the eFRONT_RIGHT/eREAR_RIGHT wheels are to the right of the eFRONT_LEFT/eREAR_LEFT wheels");
+ }
+#endif
+
+ END_TIMER(TIMER_ADMIN);
+ START_TIMER(TIMER_GRAPHS);
+
+#if PX_DEBUG_VEHICLE_ON
+ for(PxU32 i=0;i<vehDrive4W->mWheelsSimData.mNbWheels4;i++)
+ {
+ updateGraphDataInternalWheelDynamics(4*i,vehDrive4W->mWheelsDynData.mWheels4DynData[i].mWheelSpeeds);
+ }
+ updateGraphDataInternalEngineDynamics(vehDrive4W->mDriveDynData.getEngineRotationSpeed());
+#endif
+
+ END_TIMER(TIMER_GRAPHS);
+ START_TIMER(TIMER_ADMIN);
+
+ //Unpack the vehicle.
+ //Unpack the 4W simulation and instanced dynamics components.
+ const PxVehicleWheels4SimData* wheels4SimDatas=vehDrive4W->mWheelsSimData.mWheels4SimData;
+ const PxVehicleTireLoadFilterData& tireLoadFilterData=vehDrive4W->mWheelsSimData.mNormalisedLoadFilter;
+ PxVehicleWheels4DynData* wheels4DynDatas=vehDrive4W->mWheelsDynData.mWheels4DynData;
+ const PxU32 numWheels4=vehDrive4W->mWheelsSimData.mNbWheels4;
+ const PxU32 numActiveWheels=vehDrive4W->mWheelsSimData.mNbActiveWheels;
+ const PxU32 numActiveWheelsInLast4=4-(4*numWheels4 - numActiveWheels);
+ const PxVehicleDriveSimData4W driveSimData=vehDrive4W->mDriveSimData;
+ PxVehicleDriveDynData& driveDynData=vehDrive4W->mDriveDynData;
+ PxRigidDynamic* vehActor=vehDrive4W->mActor;
+
+ //We need to store that data we are going to write to actors so we can do this at the end in one go with fewer write locks.
+ PxVehicleWheelConcurrentUpdateData wheelConcurrentUpdates[PX_MAX_NB_WHEELS];
+ PxVehicleConcurrentUpdateData vehicleConcurrentUpdates;
+ vehicleConcurrentUpdates.nbConcurrentWheelUpdates = numActiveWheels;
+ vehicleConcurrentUpdates.concurrentWheelUpdates = wheelConcurrentUpdates;
+
+ //Test if a non-zero drive torque was applied or if a non-zero steer angle was applied.
+ bool finiteInputApplied=false;
+ if(0!=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT) ||
+ 0!=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT) ||
+ 0!=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL) ||
+ driveDynData.getGearDown() || driveDynData.getGearUp())
+ {
+ finiteInputApplied=true;
+ }
+
+ //Awake or sleep.
+ if(vehActor->isSleeping())
+ {
+ if(finiteInputApplied)
+ {
+ //Driving inputs so we need the actor to start moving.
+ vehicleConcurrentUpdates.wakeup = true;
+ }
+ else if(isOnDynamicActor(vehDrive4W->mWheelsSimData, vehDrive4W->mWheelsDynData))
+ {
+ //Driving on dynamic so we need to keep moving.
+ vehicleConcurrentUpdates.wakeup = true;
+ }
+ else
+ {
+ //No driving inputs and the actor is asleep.
+ //Set internal dynamics to zero.
+ setInternalDynamicsToZero(vehDrive4W);
+ if(vehConcurrentUpdates) vehConcurrentUpdates->staySleeping = true;
+ return;
+ }
+ }
+
+ //In each block of 4 wheels record how many wheels are active.
+ PxU32 numActiveWheelsPerBlock4[PX_MAX_NB_SUSPWHEELTIRE4]={0,0,0,0,0};
+ numActiveWheelsPerBlock4[0]=PxMin(numActiveWheels,PxU32(4));
+ for(PxU32 i=1;i<numWheels4-1;i++)
+ {
+ numActiveWheelsPerBlock4[i]=4;
+ }
+ numActiveWheelsPerBlock4[numWheels4-1]=numActiveWheelsInLast4;
+ PX_ASSERT(numActiveWheels == numActiveWheelsPerBlock4[0] + numActiveWheelsPerBlock4[1] + numActiveWheelsPerBlock4[2] + numActiveWheelsPerBlock4[3] + numActiveWheelsPerBlock4[4]);
+
+ //Organise the shader data in blocks of 4.
+ PxVehicleTireForceCalculator4 tires4ForceCalculators[PX_MAX_NB_SUSPWHEELTIRE4];
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ tires4ForceCalculators[i].mShaderData[0]=vehDrive4W->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+0];
+ tires4ForceCalculators[i].mShaderData[1]=vehDrive4W->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+1];
+ tires4ForceCalculators[i].mShaderData[2]=vehDrive4W->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+2];
+ tires4ForceCalculators[i].mShaderData[3]=vehDrive4W->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+3];
+ tires4ForceCalculators[i].mShader=vehDrive4W->mWheelsDynData.mTireForceCalculators->mShader;
+ }
+
+ //Mark the constraints as dirty to force them to be updated in the sdk.
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ wheels4DynDatas[i].getVehicletConstraintShader().mConstraint->markDirty();
+ }
+
+ //We need to store data to pose the wheels at the end.
+ PxWheelQueryResult wheelQueryResults[PX_MAX_NB_WHEELS];
+
+ END_TIMER(TIMER_ADMIN);
+ START_TIMER(TIMER_COMPONENTS_UPDATE);
+
+ //Center of mass local pose.
+ PxTransform carChassisCMLocalPose;
+ //Compute the transform of the center of mass.
+ PxTransform origCarChassisTransform;
+ PxTransform carChassisTransform;
+ //Inverse mass and inertia to apply the tire/suspension forces as impulses.
+ PxF32 inverseChassisMass;
+ PxVec3 inverseInertia;
+ //Linear and angular velocity.
+ PxVec3 carChassisLinVel;
+ PxVec3 carChassisAngVel;
+ {
+ carChassisCMLocalPose = vehActor->getCMassLocalPose();
+ origCarChassisTransform = vehActor->getGlobalPose().transform(carChassisCMLocalPose);
+ carChassisTransform = origCarChassisTransform;
+ const PxF32 chassisMass = vehActor->getMass();
+ inverseChassisMass = 1.0f/chassisMass;
+ inverseInertia = vehActor->getMassSpaceInvInertiaTensor();
+ carChassisLinVel = vehActor->getLinearVelocity();
+ carChassisAngVel = vehActor->getAngularVelocity();
+ }
+
+ //Get the local poses of the wheel shapes.
+ //These are the poses from the last frame and equal to the poses used for the raycast we will process.
+ PxQuat wheelLocalPoseRotations[PX_MAX_NB_WHEELS];
+ PxF32 wheelThetas[PX_MAX_NB_WHEELS];
+ {
+ for (PxU32 i = 0; i < numActiveWheels; i++)
+ {
+ const PxI32 shapeId = vehDrive4W->mWheelsSimData.getWheelShapeMapping(i);
+ if (-1 != shapeId)
+ {
+ PxShape* shape = NULL;
+ vehActor->getShapes(&shape, 1, PxU32(shapeId));
+ wheelLocalPoseRotations[i] = shape->getLocalPose().q;
+ wheelThetas[i] = vehDrive4W->mWheelsDynData.getWheelRotationAngle(i);
+ }
+ }
+ }
+
+ //Update the auto-box and decide whether to change gear up or down.
+ PxF32 autoboxCompensatedAnalogAccel = driveDynData.mControlAnalogVals[PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL];
+ if(driveDynData.getUseAutoGears())
+ {
+ autoboxCompensatedAnalogAccel = processAutoBox(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL,timestep,driveSimData,driveDynData);
+ }
+
+ //Process gear-up/gear-down commands.
+ {
+ const PxVehicleGearsData& gearsData=driveSimData.getGearsData();
+ processGears(timestep,gearsData,driveDynData);
+ }
+
+ //Clutch strength;
+ PxF32 K;
+ {
+ const PxVehicleClutchData& clutchData=driveSimData.getClutchData();
+ const PxU32 currentGear=driveDynData.getCurrentGear();
+ K=computeClutchStrength(clutchData, currentGear);
+ }
+
+ //Clutch accuracy
+ PxVehicleClutchAccuracyMode::Enum clutchAccuracyMode;
+ PxU32 clutchMaxIterations;
+ {
+ const PxVehicleClutchData& clutchData=driveSimData.getClutchData();
+ clutchAccuracyMode = clutchData.mAccuracyMode;
+ clutchMaxIterations = clutchData.mEstimateIterations;
+ }
+
+ //Gear ratio.
+ PxF32 G;
+ PxU32 currentGear;
+ {
+ const PxVehicleGearsData& gearsData=driveSimData.getGearsData();
+ currentGear=driveDynData.getCurrentGear();
+ G=computeGearRatio(gearsData,currentGear);
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataGearRatio(G);
+#endif
+ }
+
+ //Retrieve control values from vehicle controls.
+ PxF32 accel,brake,handbrake,steerLeft,steerRight;
+ PxF32 steer;
+ bool isIntentionToAccelerate;
+ {
+ getVehicle4WControlValues(driveDynData,accel,brake,handbrake,steerLeft,steerRight);
+ steer=steerRight-steerLeft;
+ accel=autoboxCompensatedAnalogAccel;
+ isIntentionToAccelerate = (accel>0.0f && 0.0f==brake && 0.0f==handbrake && PxVehicleGearsData::eNEUTRAL != currentGear);
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataControlInputs(accel,brake,handbrake,steerLeft,steerRight);
+#endif
+ }
+
+ //Active wheels (wheels which have not been disabled).
+ bool activeWheelStates[4]={false,false,false,false};
+ {
+ computeWheelActiveStates(4*0, vehDrive4W->mWheelsSimData.mActiveWheelsBitmapBuffer, activeWheelStates);
+ }
+
+ //Get the drive wheels (the first 4 wheels are the drive wheels).
+ const PxVehicleWheels4SimData& wheels4SimData=wheels4SimDatas[0];
+ PxVehicleWheels4DynData& wheels4DynData=wheels4DynDatas[0];
+ const PxVehicleTireForceCalculator4& tires4ForceCalculator=tires4ForceCalculators[0];
+
+ //Contribution of each driven wheel to average wheel speed at clutch.
+ //With 4 driven wheels the average wheel speed at clutch is
+ //wAve = alpha0*w0 + alpha1*w1 + alpha2*w2 + alpha3*w3.
+ //This next bit of code computes alpha0,alpha1,alpha2,alpha3.
+ //For rear wheel drive alpha0=alpha1=0
+ //For front wheel drive alpha2=alpha3=0
+ PxF32 aveWheelSpeedContributions[4]={0.0f,0.0f,0.0f,0.0f};
+ {
+ const PxVehicleDifferential4WData& diffData=driveSimData.getDiffData();
+ computeDiffAveWheelSpeedContributions(diffData,handbrake,aveWheelSpeedContributions);
+
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataClutchSlip(wheels4DynData.mWheelSpeeds,aveWheelSpeedContributions,driveDynData.getEngineRotationSpeed(),G);
+#endif
+
+ PX_CHECK_AND_RETURN(
+ (activeWheelStates[0] || 0.0f==aveWheelSpeedContributions[0]) &&
+ (activeWheelStates[1] || 0.0f==aveWheelSpeedContributions[1]) &&
+ (activeWheelStates[2] || 0.0f==aveWheelSpeedContributions[2]) &&
+ (activeWheelStates[3] || 0.0f==aveWheelSpeedContributions[3]),
+ "PxVehicleDifferential4WData must be configured so that no torque is delivered to a disabled wheel");
+ }
+
+ //Compute a per-wheel accelerator pedal value.
+ bool isAccelApplied[4]={false,false,false,false};
+ if(isIntentionToAccelerate)
+ {
+ PX_ASSERT(accel>0);
+ computeIsAccelApplied(aveWheelSpeedContributions, isAccelApplied);
+ }
+
+ //Ackermann-corrected steering angles.
+ //http://en.wikipedia.org/wiki/Ackermann_steering_geometry
+ PxF32 steerAngles[4]={0.0f,0.0f,0.0f,0.0f};
+ {
+ computeAckermannCorrectedSteerAngles(driveSimData,wheels4SimData,steer,steerAngles);
+ }
+
+ END_TIMER(TIMER_COMPONENTS_UPDATE);
+ START_TIMER(TIMER_ADMIN);
+
+ //Store the susp line raycast data.
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ storeRaycasts(wheels4DynDatas[i], &wheelQueryResults[4*i]);
+ }
+
+ //Ready to do the update.
+ PxVec3 carChassisLinVelOrig=carChassisLinVel;
+ PxVec3 carChassisAngVelOrig=carChassisAngVel;
+ const PxU32 numSubSteps=computeNumberOfSubsteps(vehDrive4W->mWheelsSimData,carChassisLinVel,carChassisTransform,gForward);
+ const PxF32 timeFraction=1.0f/(1.0f*numSubSteps);
+ const PxF32 subTimestep=timestep*timeFraction;
+ const PxF32 recipSubTimeStep=1.0f/subTimestep;
+ const PxF32 recipTimestep=1.0f/timestep;
+ const PxF32 minLongSlipDenominator=vehDrive4W->mWheelsSimData.mMinLongSlipDenominator;
+ ProcessSuspWheelTireConstData constData={timeFraction, subTimestep, recipSubTimeStep, gravity, gravityMagnitude, recipGravityMagnitude, false, minLongSlipDenominator, vehActor, &drivableSurfaceToTireFrictionPairs};
+
+ END_TIMER(TIMER_ADMIN);
+
+ for(PxU32 k=0;k<numSubSteps;k++)
+ {
+ //Set the force and torque for the current update to zero.
+ PxVec3 chassisForce(0,0,0);
+ PxVec3 chassisTorque(0,0,0);
+
+ START_TIMER(TIMER_COMPONENTS_UPDATE);
+
+ //Update the drive/steer wheels and engine.
+ {
+ //Compute the brake torques.
+ PxF32 brakeTorques[4]={0.0f,0.0f,0.0f,0.0f};
+ bool isBrakeApplied[4]={false,false,false,false};
+ computeBrakeAndHandBrakeTorques
+ (&wheels4SimData.getWheelData(0),wheels4DynData.mWheelSpeeds,brake,handbrake,
+ brakeTorques,isBrakeApplied);
+
+ END_TIMER(TIMER_COMPONENTS_UPDATE);
+ START_TIMER(TIMER_WHEELS);
+
+ //Compute jounces, slips, tire forces, suspension forces etc.
+ ProcessSuspWheelTireInputData inputData=
+ {
+ isIntentionToAccelerate, isAccelApplied, isBrakeApplied, steerAngles, activeWheelStates,
+ carChassisTransform, carChassisLinVel, carChassisAngVel,
+ wheelLocalPoseRotations, wheelThetas, &wheels4SimData, &wheels4DynData, &tires4ForceCalculator, &tireLoadFilterData, numActiveWheelsPerBlock4[0]
+ };
+ ProcessSuspWheelTireOutputData outputData;
+ processSuspTireWheels(0, constData, inputData, outputData);
+ updateLowSpeedTimers(outputData.newLowForwardSpeedTimers, const_cast<PxF32*>(inputData.vehWheels4DynData->mTireLowForwardSpeedTimers));
+ updateLowSpeedTimers(outputData.newLowSideSpeedTimers, const_cast<PxF32*>(inputData.vehWheels4DynData->mTireLowSideSpeedTimers));
+ updateJounces(outputData.jounces, const_cast<PxF32*>(inputData.vehWheels4DynData->mJounces));
+ if((numSubSteps-1) == k)
+ {
+ updateCachedHitData(outputData.cachedHitCounts, outputData.cachedHitPlanes, outputData.cachedHitDistances, outputData.cachedFrictionMultipliers, outputData.cachedHitQueryTypes, &wheels4DynData);
+ }
+ chassisForce+=outputData.chassisForce;
+ chassisTorque+=outputData.chassisTorque;
+ if(0 == k)
+ {
+ wheels4DynData.mVehicleConstraints->mData=outputData.vehConstraintData;
+ }
+ storeSuspWheelTireResults(outputData, inputData.steerAngles, &wheelQueryResults[4*0], numActiveWheelsPerBlock4[0]);
+ storeHitActorForces(outputData, &vehicleConcurrentUpdates.concurrentWheelUpdates[4*0], numActiveWheelsPerBlock4[0]);
+
+ END_TIMER(TIMER_WHEELS);
+ START_TIMER(TIMER_INTERNAL_DYNAMICS_SOLVER);
+
+ //Diff torque ratios needed (how we split the torque between the drive wheels).
+ //The sum of the torque ratios is always 1.0f.
+ //The drive torque delivered to each wheel is the total available drive torque multiplied by the
+ //diff torque ratio for each wheel.
+ PxF32 diffTorqueRatios[4]={0.0f,0.0f,0.0f,0.0f};
+ computeDiffTorqueRatios(driveSimData.getDiffData(),handbrake,wheels4DynData.mWheelSpeeds,diffTorqueRatios);
+
+ PX_CHECK_AND_RETURN(
+ (activeWheelStates[0] || 0.0f==diffTorqueRatios[0]) &&
+ (activeWheelStates[1] || 0.0f==diffTorqueRatios[1]) &&
+ (activeWheelStates[2] || 0.0f==diffTorqueRatios[2]) &&
+ (activeWheelStates[3] || 0.0f==diffTorqueRatios[3]),
+ "PxVehicleDifferential4WData must be configured so that no torque is delivered to a disabled wheel");
+
+ PxF32 engineDriveTorque;
+ {
+ const PxVehicleEngineData& engineData=driveSimData.getEngineData();
+ const PxF32 engineOmega=driveDynData.getEngineRotationSpeed();
+ engineDriveTorque=computeEngineDriveTorque(engineData,engineOmega,accel);
+ #if PX_DEBUG_VEHICLE_ON
+ updateGraphDataEngineDriveTorque(engineDriveTorque);
+ #endif
+ }
+
+ PxF32 engineDampingRate;
+ {
+ const PxVehicleEngineData& engineData=driveSimData.getEngineData();
+ engineDampingRate=computeEngineDampingRate(engineData,currentGear,accel);
+ }
+
+ //Update the wheel and engine speeds - 5x5 matrix coupling engine and wheels.
+ ImplicitSolverInput implicitSolverInput=
+ {
+ subTimestep,
+ brake, handbrake,
+ K, G,
+ clutchAccuracyMode, clutchMaxIterations,
+ engineDriveTorque, engineDampingRate,
+ diffTorqueRatios, aveWheelSpeedContributions,
+ brakeTorques, isBrakeApplied, outputData.tireTorques,
+ 1, 4,
+ &wheels4SimData, &driveSimData
+ };
+ ImplicitSolverOutput implicitSolverOutput=
+ {
+ &wheels4DynData, &driveDynData
+ };
+ solveDrive4WInternaDynamicsEnginePlusDrivenWheels(implicitSolverInput, &implicitSolverOutput);
+
+ END_TIMER(TIMER_INTERNAL_DYNAMICS_SOLVER);
+ START_TIMER(TIMER_POSTUPDATE1);
+
+ //Integrate wheel rotation angle (theta += omega*dt)
+ integrateWheelRotationAngles
+ (subTimestep,
+ K,G,engineDriveTorque,
+ outputData.jounces,diffTorqueRatios,outputData.forwardSpeeds,isBrakeApplied,
+ driveSimData,wheels4SimData,
+ driveDynData,wheels4DynData);
+ }
+
+ END_TIMER(TIMER_POSTUPDATE1);
+
+ //////////////////////////////////////////////////////////////////////////
+ //susp and tire forces from extra wheels (non-driven wheels)
+ //////////////////////////////////////////////////////////////////////////
+ for(PxU32 j=1;j<numWheels4;j++)
+ {
+ //Only the driven wheels can steer but the non-drive wheels can still have a toe angle.
+ const PxVehicleWheelData& wheelData0=wheels4SimDatas[j].getWheelData(0);
+ const PxVehicleWheelData& wheelData1=wheels4SimDatas[j].getWheelData(1);
+ const PxVehicleWheelData& wheelData2=wheels4SimDatas[j].getWheelData(2);
+ const PxVehicleWheelData& wheelData3=wheels4SimDatas[j].getWheelData(3);
+ const PxF32 toe0=wheelData0.mToeAngle;
+ const PxF32 toe1=wheelData1.mToeAngle;
+ const PxF32 toe2=wheelData2.mToeAngle;
+ const PxF32 toe3=wheelData3.mToeAngle;
+ PxF32 extraWheelSteerAngles[4]={toe0,toe1,toe2,toe3};
+
+ //Only the driven wheels are connected to the diff.
+ PxF32 extraWheelsDiffTorqueRatios[4]={0.0f,0.0f,0.0f,0.0f};
+ bool extraIsAccelApplied[4]={false,false,false,false};
+
+ //The extra wheels do have brakes.
+ PxF32 extraWheelBrakeTorques[4]={0.0f,0.0f,0.0f,0.0f};
+ bool extraIsBrakeApplied[4]={false,false,false,false};
+ computeBrakeAndHandBrakeTorques
+ (&wheels4SimDatas[j].getWheelData(0),wheels4DynDatas[j].mWheelSpeeds,brake,handbrake,
+ extraWheelBrakeTorques,extraIsBrakeApplied);
+
+ //The extra wheels can be disabled or enabled.
+ bool extraWheelActiveStates[4]={false,false,false,false};
+ computeWheelActiveStates(4*j, vehDrive4W->mWheelsSimData.mActiveWheelsBitmapBuffer, extraWheelActiveStates);
+
+ ProcessSuspWheelTireInputData extraInputData=
+ {
+ isIntentionToAccelerate, extraIsAccelApplied, extraIsBrakeApplied, extraWheelSteerAngles, extraWheelActiveStates,
+ carChassisTransform, carChassisLinVel, carChassisAngVel,
+ &wheelLocalPoseRotations[j], &wheelThetas[j], &wheels4SimDatas[j], &wheels4DynDatas[j], &tires4ForceCalculators[j], &tireLoadFilterData, numActiveWheelsPerBlock4[j],
+ };
+ ProcessSuspWheelTireOutputData extraOutputData;
+ processSuspTireWheels(4*j, constData, extraInputData, extraOutputData);
+ updateLowSpeedTimers(extraOutputData.newLowForwardSpeedTimers, const_cast<PxF32*>(extraInputData.vehWheels4DynData->mTireLowForwardSpeedTimers));
+ updateLowSpeedTimers(extraOutputData.newLowSideSpeedTimers, const_cast<PxF32*>(extraInputData.vehWheels4DynData->mTireLowSideSpeedTimers));
+ updateJounces(extraOutputData.jounces, const_cast<PxF32*>(extraInputData.vehWheels4DynData->mJounces));
+ if((numSubSteps-1) == k)
+ {
+ updateCachedHitData(extraOutputData.cachedHitCounts, extraOutputData.cachedHitPlanes, extraOutputData.cachedHitDistances, extraOutputData.cachedFrictionMultipliers, extraOutputData.cachedHitQueryTypes, &wheels4DynDatas[j]);
+ }
+ chassisForce+=extraOutputData.chassisForce;
+ chassisTorque+=extraOutputData.chassisTorque;
+ if(0 == k)
+ {
+ wheels4DynDatas[j].mVehicleConstraints->mData=extraOutputData.vehConstraintData;
+ }
+ storeSuspWheelTireResults(extraOutputData, extraInputData.steerAngles, &wheelQueryResults[4*j], numActiveWheelsPerBlock4[j]);
+ storeHitActorForces(extraOutputData, &vehicleConcurrentUpdates.concurrentWheelUpdates[4*j], numActiveWheelsPerBlock4[j]);
+
+ //Integrate the tire torques (omega += (tireTorque + brakeTorque)*dt)
+ integrateUndriveWheelRotationSpeeds(subTimestep, brake, handbrake, extraOutputData.tireTorques, extraWheelBrakeTorques, wheels4SimDatas[j], wheels4DynDatas[j]);
+
+ //Integrate wheel rotation angle (theta += omega*dt)
+ integrateWheelRotationAngles
+ (subTimestep,
+ 0,0,0,
+ extraOutputData.jounces,extraWheelsDiffTorqueRatios,extraOutputData.forwardSpeeds,extraIsBrakeApplied,
+ driveSimData,wheels4SimDatas[j],
+ driveDynData,wheels4DynDatas[j]);
+ }
+
+ START_TIMER(TIMER_POSTUPDATE2);
+
+ //Apply the anti-roll suspension.
+ procesAntiRollSuspension(vehDrive4W->mWheelsSimData, carChassisTransform, wheelQueryResults, chassisTorque);
+
+ //Integrate one sustep.
+ integrateBody(inverseChassisMass, inverseInertia ,chassisForce, chassisTorque, subTimestep, carChassisLinVel, carChassisAngVel, carChassisTransform);
+
+ END_TIMER(TIMER_POSTUPDATE2);
+ }
+
+ START_TIMER(TIMER_POSTUPDATE3);
+
+ //Set the new chassis linear/angular velocity.
+ if(!gApplyForces)
+ {
+ vehicleConcurrentUpdates.linearMomentumChange = carChassisLinVel;
+ vehicleConcurrentUpdates.angularMomentumChange = carChassisAngVel;
+ }
+ else
+ {
+ //integration steps are:
+ //v = v0 + a*dt (1)
+ //x = x0 + v*dt (2)
+ //Sub (2) into (1.
+ //x = x0 + v0*dt + a*dt*dt;
+ //Rearrange for a
+ //a = (x -x0 - v0*dt)/(dt*dt) = [(x-x0)/dt - v0/dt]
+ //Rearrange again with v = (x-x0)/dt
+ //a = (v - v0)/dt
+ vehicleConcurrentUpdates.linearMomentumChange = (carChassisLinVel-carChassisLinVelOrig)*recipTimestep;;
+ vehicleConcurrentUpdates.angularMomentumChange = (carChassisAngVel-carChassisAngVelOrig)*recipTimestep;;
+ }
+
+ //Compute and pose the wheels from jounces, rotations angles, and steer angles.
+ PxTransform localPoses0[4] = {PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity)};
+ computeWheelLocalPoses(wheels4SimDatas[0],wheels4DynDatas[0],&wheelQueryResults[4*0],numActiveWheelsPerBlock4[0],carChassisCMLocalPose,localPoses0);
+ //Copy the poses to the wheelQueryResults
+ wheelQueryResults[4*0 + 0].localPose = localPoses0[0];
+ wheelQueryResults[4*0 + 1].localPose = localPoses0[1];
+ wheelQueryResults[4*0 + 2].localPose = localPoses0[2];
+ wheelQueryResults[4*0 + 3].localPose = localPoses0[3];
+ //Copy the poses to the concurrent update data.
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 0].localPose = localPoses0[0];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 1].localPose = localPoses0[1];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 2].localPose = localPoses0[2];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 3].localPose = localPoses0[3];
+ for(PxU32 i=1;i<numWheels4;i++)
+ {
+ PxTransform localPoses[4] = {PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity)};
+ computeWheelLocalPoses(wheels4SimDatas[i],wheels4DynDatas[i],&wheelQueryResults[4*i],numActiveWheelsPerBlock4[i],carChassisCMLocalPose,localPoses);
+ //Copy the poses to the wheelQueryResults
+ wheelQueryResults[4*i + 0].localPose = localPoses[0];
+ wheelQueryResults[4*i + 1].localPose = localPoses[1];
+ wheelQueryResults[4*i + 2].localPose = localPoses[2];
+ wheelQueryResults[4*i + 3].localPose = localPoses[3];
+ //Copy the poses to the concurrent update data.
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 0].localPose = localPoses[0];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 1].localPose = localPoses[1];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 2].localPose = localPoses[2];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 3].localPose = localPoses[3];
+ }
+
+ if(vehWheelQueryResults && vehWheelQueryResults->wheelQueryResults)
+ {
+ PxMemCopy(vehWheelQueryResults->wheelQueryResults, wheelQueryResults, sizeof(PxWheelQueryResult)*numActiveWheels);
+ }
+
+ if(vehConcurrentUpdates)
+ {
+ //Copy across to input data structure so that writes can be applied later.
+ PxMemCopy(vehConcurrentUpdates->concurrentWheelUpdates, vehicleConcurrentUpdates.concurrentWheelUpdates, sizeof(PxVehicleWheelConcurrentUpdateData)*numActiveWheels);
+ vehConcurrentUpdates->linearMomentumChange = vehicleConcurrentUpdates.linearMomentumChange;
+ vehConcurrentUpdates->angularMomentumChange = vehicleConcurrentUpdates.angularMomentumChange;
+ vehConcurrentUpdates->staySleeping = vehicleConcurrentUpdates.staySleeping;
+ vehConcurrentUpdates->wakeup = vehicleConcurrentUpdates.wakeup;
+ }
+ else
+ {
+ //Apply the writes immediately.
+ PxVehicleWheels* vehWheels[1]={vehDrive4W};
+ PxVehiclePostUpdates(&vehicleConcurrentUpdates, 1, vehWheels);
+ }
+
+ END_TIMER(TIMER_POSTUPDATE3);
+}
+
+void PxVehicleUpdate::updateDriveNW
+(const PxF32 timestep,
+ const PxVec3& gravity, const PxF32 gravityMagnitude, const PxF32 recipGravityMagnitude,
+ const PxVehicleDrivableSurfaceToTireFrictionPairs& drivableSurfaceToTireFrictionPairs,
+ PxVehicleDriveNW* vehDriveNW, PxVehicleWheelQueryResult* vehWheelQueryResults, PxVehicleConcurrentUpdateData* vehConcurrentUpdates)
+{
+ PX_SIMD_GUARD; // denorm exception triggered in transformInertiaTensor() on osx
+
+ START_TIMER(TIMER_ADMIN);
+
+ PX_CHECK_AND_RETURN(
+ vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_ACCEL]>-0.01f &&
+ vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_ACCEL]<1.01f,
+ "Illegal vehicle control value - accel must be in range (0,1)");
+ PX_CHECK_AND_RETURN(
+ vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_BRAKE]>-0.01f &&
+ vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_BRAKE]<1.01f,
+ "Illegal vehicle control value - brake must be in range (0,1)");
+ PX_CHECK_AND_RETURN(
+ vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_HANDBRAKE]>-0.01f &&
+ vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_HANDBRAKE]<1.01f,
+ "Illegal vehicle control value - handbrake must be in range (0,1)");
+ PX_CHECK_AND_RETURN(
+ vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_STEER_LEFT]>-1.01f &&
+ vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_STEER_LEFT]<1.01f,
+ "Illegal vehicle control value - left steer must be in range (-1,1)");
+ PX_CHECK_AND_RETURN(
+ vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_STEER_RIGHT]>-1.01f &&
+ vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_STEER_RIGHT]<1.01f,
+ "Illegal vehicle control value - right steer must be in range (-1,1)");
+ PX_CHECK_AND_RETURN(
+ PxAbs(vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_STEER_RIGHT]-
+ vehDriveNW->mDriveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_STEER_LEFT])<1.01f,
+ "Illegal vehicle control value - right steer value minus left steer value must be in range (-1,1)");
+ PX_CHECK_AND_RETURN(
+ !(vehDriveNW->getRigidDynamicActor()->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC),
+ "Attempting to update a drive4W with a kinematic actor - this isn't allowed");
+ PX_CHECK_AND_RETURN(
+ NULL==vehWheelQueryResults || vehWheelQueryResults->nbWheelQueryResults >= vehDriveNW->mWheelsSimData.getNbWheels(),
+ "nbWheelQueryResults must always be greater than or equal to number of wheels in corresponding vehicle");
+
+#if PX_CHECKED
+ for(PxU32 i=0;i<vehDriveNW->mWheelsSimData.getNbWheels();i++)
+ {
+ PX_CHECK_AND_RETURN(!vehDriveNW->mWheelsSimData.getIsWheelDisabled(i) || !vehDriveNW->mDriveSimData.getDiffData().getIsDrivenWheel(i),
+ "PxVehicleDifferentialNWData must be configured so that no torque is delivered to a disabled wheel");
+ }
+#endif
+
+ END_TIMER(TIMER_ADMIN);
+ START_TIMER(TIMER_GRAPHS);
+
+#if PX_DEBUG_VEHICLE_ON
+ for(PxU32 i=0;i<vehDriveNW->mWheelsSimData.mNbWheels4;i++)
+ {
+ updateGraphDataInternalWheelDynamics(4*i,vehDriveNW->mWheelsDynData.mWheels4DynData[i].mWheelSpeeds);
+ }
+ updateGraphDataInternalEngineDynamics(vehDriveNW->mDriveDynData.getEngineRotationSpeed());
+#endif
+
+ END_TIMER(TIMER_GRAPHS);
+ START_TIMER(TIMER_ADMIN);
+
+ //Unpack the vehicle.
+ //Unpack the NW simulation and instanced dynamics components.
+ const PxVehicleWheels4SimData* wheels4SimDatas=vehDriveNW->mWheelsSimData.mWheels4SimData;
+ const PxVehicleTireLoadFilterData& tireLoadFilterData=vehDriveNW->mWheelsSimData.mNormalisedLoadFilter;
+ PxVehicleWheels4DynData* wheels4DynDatas=vehDriveNW->mWheelsDynData.mWheels4DynData;
+ const PxU32 numWheels4=vehDriveNW->mWheelsSimData.mNbWheels4;
+ const PxU32 numActiveWheels=vehDriveNW->mWheelsSimData.mNbActiveWheels;
+ const PxU32 numActiveWheelsInLast4=4-(4*numWheels4 - numActiveWheels);
+ const PxVehicleDriveSimDataNW driveSimData=vehDriveNW->mDriveSimData;
+ PxVehicleDriveDynData& driveDynData=vehDriveNW->mDriveDynData;
+ PxRigidDynamic* vehActor=vehDriveNW->mActor;
+
+ //We need to store that data we are going to write to actors so we can do this at the end in one go with fewer write locks.
+ PxVehicleWheelConcurrentUpdateData wheelConcurrentUpdates[PX_MAX_NB_WHEELS];
+ PxVehicleConcurrentUpdateData vehicleConcurrentUpdates;
+ vehicleConcurrentUpdates.nbConcurrentWheelUpdates = numActiveWheels;
+ vehicleConcurrentUpdates.concurrentWheelUpdates = wheelConcurrentUpdates;
+
+ //In each block of 4 wheels record how many wheels are active.
+ PxU32 numActiveWheelsPerBlock4[PX_MAX_NB_SUSPWHEELTIRE4]={0,0,0,0,0};
+ numActiveWheelsPerBlock4[0]=PxMin(numActiveWheels,PxU32(4));
+ for(PxU32 i=1;i<numWheels4-1;i++)
+ {
+ numActiveWheelsPerBlock4[i]=4;
+ }
+ numActiveWheelsPerBlock4[numWheels4-1]=numActiveWheelsInLast4;
+ PX_ASSERT(numActiveWheels == numActiveWheelsPerBlock4[0] + numActiveWheelsPerBlock4[1] + numActiveWheelsPerBlock4[2] + numActiveWheelsPerBlock4[3] + numActiveWheelsPerBlock4[4]);
+
+
+ //Test if a non-zero drive torque was applied or if a non-zero steer angle was applied.
+ bool finiteInputApplied=false;
+ if(0!=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT) ||
+ 0!=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT) ||
+ 0!=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL) ||
+ driveDynData.getGearDown() || driveDynData.getGearUp())
+ {
+ finiteInputApplied=true;
+ }
+
+ //Awake or sleep.
+ {
+ if(vehActor->isSleeping())
+ {
+ if(finiteInputApplied)
+ {
+ //Driving inputs so we need the actor to start moving.
+ vehicleConcurrentUpdates.wakeup = true;
+ }
+ else if(isOnDynamicActor(vehDriveNW->mWheelsSimData, vehDriveNW->mWheelsDynData))
+ {
+ //Driving on dynamic so we need to keep moving.
+ vehicleConcurrentUpdates.wakeup = true;
+ }
+ else
+ {
+ //No driving inputs and the actor is asleep.
+ //Set internal dynamics to sleep.
+ setInternalDynamicsToZero(vehDriveNW);
+ if(vehConcurrentUpdates) vehConcurrentUpdates->staySleeping = true;
+ return;
+ }
+ }
+ }
+
+ //Organise the shader data in blocks of 4.
+ PxVehicleTireForceCalculator4 tires4ForceCalculators[PX_MAX_NB_SUSPWHEELTIRE4];
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ tires4ForceCalculators[i].mShaderData[0]=vehDriveNW->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+0];
+ tires4ForceCalculators[i].mShaderData[1]=vehDriveNW->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+1];
+ tires4ForceCalculators[i].mShaderData[2]=vehDriveNW->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+2];
+ tires4ForceCalculators[i].mShaderData[3]=vehDriveNW->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+3];
+ tires4ForceCalculators[i].mShader=vehDriveNW->mWheelsDynData.mTireForceCalculators->mShader;
+ }
+
+ //Mark the constraints as dirty to force them to be updated in the sdk.
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ wheels4DynDatas[i].getVehicletConstraintShader().mConstraint->markDirty();
+ }
+
+ //Need to store report data to pose the wheels.
+ PxWheelQueryResult wheelQueryResults[PX_MAX_NB_WHEELS];
+
+ END_TIMER(TIMER_ADMIN);
+ START_TIMER(TIMER_COMPONENTS_UPDATE);
+
+ //Center of mass local pose.
+ PxTransform carChassisCMLocalPose;
+ //Compute the transform of the center of mass.
+ PxTransform origCarChassisTransform;
+ PxTransform carChassisTransform;
+ //Inverse mass and inertia to apply the tire/suspension forces as impulses.
+ PxF32 inverseChassisMass;
+ PxVec3 inverseInertia;
+ //Linear and angular velocity.
+ PxVec3 carChassisLinVel;
+ PxVec3 carChassisAngVel;
+ {
+ carChassisCMLocalPose = vehActor->getCMassLocalPose();
+ origCarChassisTransform = vehActor->getGlobalPose().transform(carChassisCMLocalPose);
+ carChassisTransform = origCarChassisTransform;
+ const PxF32 chassisMass = vehActor->getMass();
+ inverseChassisMass = 1.0f/chassisMass;
+ inverseInertia = vehActor->getMassSpaceInvInertiaTensor();
+ carChassisLinVel = vehActor->getLinearVelocity();
+ carChassisAngVel = vehActor->getAngularVelocity();
+ }
+
+ //Get the local poses of the wheel shapes.
+ //These are the poses from the last frame and equal to the poses used for the raycast we will process.
+ PxQuat wheelLocalPoseRotations[PX_MAX_NB_WHEELS];
+ PxF32 wheelThetas[PX_MAX_NB_WHEELS];
+ {
+ for (PxU32 i = 0; i < numActiveWheels; i++)
+ {
+ const PxI32 shapeId = vehDriveNW->mWheelsSimData.getWheelShapeMapping(i);
+ if (-1 != shapeId)
+ {
+ PxShape* shape = NULL;
+ vehActor->getShapes(&shape, 1, PxU32(shapeId));
+ wheelLocalPoseRotations[i] = shape->getLocalPose().q;
+ wheelThetas[i] = vehDriveNW->mWheelsDynData.getWheelRotationAngle(i);
+ }
+ }
+ }
+
+ //Update the auto-box and decide whether to change gear up or down.
+ PxF32 autoboxCompensatedAnalogAccel = driveDynData.mControlAnalogVals[PxVehicleDriveNWControl::eANALOG_INPUT_ACCEL];
+ if(driveDynData.getUseAutoGears())
+ {
+ autoboxCompensatedAnalogAccel = processAutoBox(PxVehicleDriveNWControl::eANALOG_INPUT_ACCEL,timestep,driveSimData,driveDynData);
+ }
+
+ //Process gear-up/gear-down commands.
+ {
+ const PxVehicleGearsData& gearsData=driveSimData.getGearsData();
+ processGears(timestep,gearsData,driveDynData);
+ }
+
+ //Clutch strength.
+ PxF32 K;
+ {
+ const PxVehicleClutchData& clutchData=driveSimData.getClutchData();
+ const PxU32 currentGear=driveDynData.getCurrentGear();
+ K=computeClutchStrength(clutchData, currentGear);
+ }
+
+ //Clutch accuracy.
+ PxVehicleClutchAccuracyMode::Enum clutchAccuracyMode;
+ PxU32 clutchMaxIterations;
+ {
+ const PxVehicleClutchData& clutchData=driveSimData.getClutchData();
+ clutchAccuracyMode=clutchData.mAccuracyMode;
+ clutchMaxIterations=clutchData.mEstimateIterations;
+ }
+
+ //Gear ratio.
+ PxF32 G;
+ PxU32 currentGear;
+ {
+ const PxVehicleGearsData& gearsData=driveSimData.getGearsData();
+ currentGear=driveDynData.getCurrentGear();
+ G=computeGearRatio(gearsData,currentGear);
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataGearRatio(G);
+#endif
+ }
+
+ //Retrieve control values from vehicle controls.
+ PxF32 accel,brake,handbrake,steerLeft,steerRight;
+ PxF32 steer;
+ bool isIntentionToAccelerate;
+ {
+ getVehicleNWControlValues(driveDynData,accel,brake,handbrake,steerLeft,steerRight);
+ steer=steerRight-steerLeft;
+ accel=autoboxCompensatedAnalogAccel;
+ isIntentionToAccelerate = (accel>0.0f && 0.0f==brake && 0.0f==handbrake && PxVehicleGearsData::eNEUTRAL != currentGear);
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataControlInputs(accel,brake,handbrake,steerLeft,steerRight);
+#endif
+ }
+
+ //Compute the wheels that are disabled or enabled.
+ bool activeWheelStates[PX_MAX_NB_WHEELS];
+ PxMemSet(activeWheelStates, 0, sizeof(bool)*PX_MAX_NB_WHEELS);
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ computeWheelActiveStates(4*i, vehDriveNW->mWheelsSimData.mActiveWheelsBitmapBuffer, &activeWheelStates[4*i]);
+ }
+
+ //Contribution of each driven wheel to average wheel speed at clutch.
+ //For NW drive equal torque split is supported.
+ const PxVehicleDifferentialNWData diffData=driveSimData.getDiffData();
+ const PxF32 invNumDrivenWheels=diffData.mInvNbDrivenWheels;
+ PxF32 aveWheelSpeedContributions[PX_MAX_NB_WHEELS];
+ PxMemSet(aveWheelSpeedContributions, 0, sizeof(PxF32)*PX_MAX_NB_WHEELS);
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ aveWheelSpeedContributions[i] = diffData.getIsDrivenWheel(i) ? invNumDrivenWheels : 0;
+ }
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataClutchSlipNW(numWheels4,wheels4DynDatas,aveWheelSpeedContributions,driveDynData.getEngineRotationSpeed(),G);
+#endif
+
+ //Compute a per-wheel accelerator pedal value.
+ bool isAccelApplied[PX_MAX_NB_WHEELS];
+ PxMemSet(isAccelApplied, 0, sizeof(bool)*PX_MAX_NB_WHEELS);
+ if(isIntentionToAccelerate)
+ {
+ PX_ASSERT(accel>0);
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ computeIsAccelApplied(&aveWheelSpeedContributions[4*i],&isAccelApplied[4*i]);
+ }
+ }
+
+ //Steer angles.
+ PxF32 steerAngles[PX_MAX_NB_WHEELS];
+ PxMemSet(steerAngles, 0, sizeof(PxF32)*PX_MAX_NB_WHEELS);
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ const PxVehicleWheelData& wheelData=vehDriveNW->mWheelsSimData.getWheelData(i);
+ const PxF32 steerGain=wheelData.mMaxSteer;
+ const PxF32 toe=wheelData.mToeAngle;
+ steerAngles[i]=steerGain*steer + toe;
+ }
+
+ //Diff torque ratios needed (how we split the torque between the drive wheels).
+ //The sum of the torque ratios is always 1.0f.
+ //The drive torque delivered to each wheel is the total available drive torque multiplied by the
+ //diff torque ratio for each wheel.
+ PxF32 diffTorqueRatios[PX_MAX_NB_WHEELS];
+ PxMemSet(diffTorqueRatios, 0, sizeof(PxF32)*PX_MAX_NB_WHEELS);
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ diffTorqueRatios[i] = diffData.getIsDrivenWheel(i) ? invNumDrivenWheels : 0.0f;
+ }
+
+ END_TIMER(TIMER_COMPONENTS_UPDATE);
+ START_TIMER(TIMER_ADMIN);
+
+ //Store the susp line raycast data.
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ storeRaycasts(wheels4DynDatas[i], &wheelQueryResults[4*i]);
+ }
+
+ //Ready to do the update.
+ PxVec3 carChassisLinVelOrig=carChassisLinVel;
+ PxVec3 carChassisAngVelOrig=carChassisAngVel;
+ const PxU32 numSubSteps=computeNumberOfSubsteps(vehDriveNW->mWheelsSimData,carChassisLinVel,carChassisTransform,gForward);
+ const PxF32 timeFraction=1.0f/(1.0f*numSubSteps);
+ const PxF32 subTimestep=timestep*timeFraction;
+ const PxF32 recipSubTimeStep=1.0f/subTimestep;
+ const PxF32 recipTimestep=1.0f/timestep;
+ const PxF32 minLongSlipDenominator=vehDriveNW->mWheelsSimData.mMinLongSlipDenominator;
+ ProcessSuspWheelTireConstData constData={timeFraction, subTimestep, recipSubTimeStep, gravity, gravityMagnitude, recipGravityMagnitude, false, minLongSlipDenominator, vehActor, &drivableSurfaceToTireFrictionPairs};
+
+ END_TIMER(TIMER_ADMIN);
+
+ for(PxU32 k=0;k<numSubSteps;k++)
+ {
+ //Set the force and torque for the current update to zero.
+ PxVec3 chassisForce(0,0,0);
+ PxVec3 chassisTorque(0,0,0);
+
+ START_TIMER(TIMER_COMPONENTS_UPDATE);
+
+ PxF32 brakeTorques[PX_MAX_NB_WHEELS];
+ bool isBrakeApplied[PX_MAX_NB_WHEELS];
+ PxMemSet(brakeTorques, 0, sizeof(PxF32)*PX_MAX_NB_WHEELS);
+ PxMemSet(isBrakeApplied, false, sizeof(bool)*PX_MAX_NB_WHEELS);
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ computeBrakeAndHandBrakeTorques(&wheels4SimDatas[i].getWheelData(0),wheels4DynDatas[i].mWheelSpeeds,brake,handbrake,&brakeTorques[4*i],&isBrakeApplied[4*i]);
+ }
+
+ END_TIMER(TIMER_COMPONENTS_UPDATE);
+ START_TIMER(TIMER_WHEELS);
+
+ ProcessSuspWheelTireOutputData outputData[PX_MAX_NB_SUSPWHEELTIRE4];
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ ProcessSuspWheelTireInputData inputData=
+ {
+ isIntentionToAccelerate, &isAccelApplied[4*i], &isBrakeApplied[4*i], &steerAngles[4*i], &activeWheelStates[4*i],
+ carChassisTransform, carChassisLinVel, carChassisAngVel,
+ &wheelLocalPoseRotations[i], &wheelThetas[i], &wheels4SimDatas[i], &wheels4DynDatas[i], &tires4ForceCalculators[i], &tireLoadFilterData, numActiveWheelsPerBlock4[i]
+ };
+ processSuspTireWheels(4*i, constData, inputData, outputData[i]);
+ updateLowSpeedTimers(outputData[i].newLowForwardSpeedTimers, const_cast<PxF32*>(inputData.vehWheels4DynData->mTireLowForwardSpeedTimers));
+ updateLowSpeedTimers(outputData[i].newLowSideSpeedTimers, const_cast<PxF32*>(inputData.vehWheels4DynData->mTireLowSideSpeedTimers));
+ updateJounces(outputData[i].jounces, const_cast<PxF32*>(inputData.vehWheels4DynData->mJounces));
+ if((numSubSteps-1) == k)
+ {
+ updateCachedHitData(outputData[i].cachedHitCounts, outputData[i].cachedHitPlanes, outputData[i].cachedHitDistances, outputData[i].cachedFrictionMultipliers, outputData[i].cachedHitQueryTypes, &wheels4DynDatas[i]);
+ }
+ chassisForce+=outputData[i].chassisForce;
+ chassisTorque+=outputData[i].chassisTorque;
+ if(0 == k)
+ {
+ wheels4DynDatas[i].mVehicleConstraints->mData=outputData[i].vehConstraintData;
+ }
+ storeSuspWheelTireResults(outputData[i], inputData.steerAngles, &wheelQueryResults[4*i], numActiveWheelsPerBlock4[i]);
+ storeHitActorForces(outputData[i], &vehicleConcurrentUpdates.concurrentWheelUpdates[4*i], numActiveWheelsPerBlock4[i]);
+ }
+
+ //Store the tire torques in a single array.
+ PxF32 tireTorques[PX_MAX_NB_WHEELS];
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ tireTorques[4*i+0]=outputData[i].tireTorques[0];
+ tireTorques[4*i+1]=outputData[i].tireTorques[1];
+ tireTorques[4*i+2]=outputData[i].tireTorques[2];
+ tireTorques[4*i+3]=outputData[i].tireTorques[3];
+ }
+
+ END_TIMER(TIMER_WHEELS);
+ START_TIMER(TIMER_INTERNAL_DYNAMICS_SOLVER);
+
+ PxF32 engineDriveTorque;
+ {
+ const PxVehicleEngineData& engineData=driveSimData.getEngineData();
+ const PxF32 engineOmega=driveDynData.getEngineRotationSpeed();
+ engineDriveTorque=computeEngineDriveTorque(engineData,engineOmega,accel);
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataEngineDriveTorque(engineDriveTorque);
+#endif
+ }
+
+ PxF32 engineDampingRate;
+ {
+ const PxVehicleEngineData& engineData=driveSimData.getEngineData();
+ engineDampingRate=computeEngineDampingRate(engineData,currentGear,accel);
+ }
+
+ //Update the wheel and engine speeds - (N+1)*(N+1) matrix coupling engine and wheels.
+ ImplicitSolverInput implicitSolverInput=
+ {
+ subTimestep,
+ brake, handbrake,
+ K, G,
+ clutchAccuracyMode, clutchMaxIterations,
+ engineDriveTorque, engineDampingRate,
+ diffTorqueRatios, aveWheelSpeedContributions,
+ brakeTorques, isBrakeApplied, tireTorques,
+ numWheels4, numActiveWheels,
+ wheels4SimDatas, &driveSimData
+ };
+ ImplicitSolverOutput implicitSolverOutput=
+ {
+ wheels4DynDatas, &driveDynData
+ };
+ solveDriveNWInternalDynamicsEnginePlusDrivenWheels(implicitSolverInput, &implicitSolverOutput);
+
+ END_TIMER(TIMER_INTERNAL_DYNAMICS_SOLVER);
+ START_TIMER(TIMER_POSTUPDATE1);
+
+ //Integrate wheel rotation angle (theta += omega*dt)
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ integrateWheelRotationAngles
+ (subTimestep,
+ K,G,engineDriveTorque,
+ outputData[i].jounces,&diffTorqueRatios[4*i],outputData[i].forwardSpeeds,&isBrakeApplied[4*i],
+ driveSimData,wheels4SimDatas[i],
+ driveDynData,wheels4DynDatas[i]);
+ }
+
+ END_TIMER(TIMER_POSTUPDATE1);
+ START_TIMER(TIMER_POSTUPDATE2);
+
+ //Apply the anti-roll suspension.
+ procesAntiRollSuspension(vehDriveNW->mWheelsSimData, carChassisTransform, wheelQueryResults, chassisTorque);
+
+ //Integrate the chassis velocity by applying the accumulated force and torque.
+ integrateBody(inverseChassisMass, inverseInertia, chassisForce, chassisTorque, subTimestep, carChassisLinVel, carChassisAngVel, carChassisTransform);
+
+ END_TIMER(TIMER_POSTUPDATE2);
+ }
+
+ //Set the new chassis linear/angular velocity.
+ if(!gApplyForces)
+ {
+ vehicleConcurrentUpdates.linearMomentumChange = carChassisLinVel;
+ vehicleConcurrentUpdates.angularMomentumChange = carChassisAngVel;
+ }
+ else
+ {
+ //integration steps are:
+ //v = v0 + a*dt (1)
+ //x = x0 + v*dt (2)
+ //Sub (2) into (1.
+ //x = x0 + v0*dt + a*dt*dt;
+ //Rearrange for a
+ //a = (x -x0 - v0*dt)/(dt*dt) = [(x-x0)/dt - v0/dt]
+ //Rearrange again with v = (x-x0)/dt
+ //a = (v - v0)/dt
+ vehicleConcurrentUpdates.linearMomentumChange = (carChassisLinVel-carChassisLinVelOrig)*recipTimestep;
+ vehicleConcurrentUpdates.angularMomentumChange = (carChassisAngVel-carChassisAngVelOrig)*recipTimestep;
+ }
+
+ START_TIMER(TIMER_POSTUPDATE3);
+
+ //Pose the wheels from jounces, rotations angles, and steer angles.
+ PxTransform localPoses0[4] = {PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity)};
+ computeWheelLocalPoses(wheels4SimDatas[0],wheels4DynDatas[0],&wheelQueryResults[4*0],numActiveWheelsPerBlock4[0],carChassisCMLocalPose,localPoses0);
+ wheelQueryResults[4*0 + 0].localPose = localPoses0[0];
+ wheelQueryResults[4*0 + 1].localPose = localPoses0[1];
+ wheelQueryResults[4*0 + 2].localPose = localPoses0[2];
+ wheelQueryResults[4*0 + 3].localPose = localPoses0[3];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 0].localPose = localPoses0[0];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 1].localPose = localPoses0[1];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 2].localPose = localPoses0[2];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 3].localPose = localPoses0[3];
+ for(PxU32 i=1;i<numWheels4;i++)
+ {
+ PxTransform localPoses[4] = {PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity)};
+ computeWheelLocalPoses(wheels4SimDatas[i],wheels4DynDatas[i],&wheelQueryResults[4*i],numActiveWheelsPerBlock4[i],carChassisCMLocalPose,localPoses);
+ wheelQueryResults[4*i + 0].localPose = localPoses[0];
+ wheelQueryResults[4*i + 1].localPose = localPoses[1];
+ wheelQueryResults[4*i + 2].localPose = localPoses[2];
+ wheelQueryResults[4*i + 3].localPose = localPoses[3];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 0].localPose = localPoses[0];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 1].localPose = localPoses[1];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 2].localPose = localPoses[2];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 3].localPose = localPoses[3];
+ }
+
+ if(vehWheelQueryResults && vehWheelQueryResults->wheelQueryResults)
+ {
+ PxMemCopy(vehWheelQueryResults->wheelQueryResults, wheelQueryResults, sizeof(PxWheelQueryResult)*numActiveWheels);
+ }
+
+ if(vehConcurrentUpdates)
+ {
+ //Copy across to input data structure so that writes can be applied later.
+ PxMemCopy(vehConcurrentUpdates->concurrentWheelUpdates, vehicleConcurrentUpdates.concurrentWheelUpdates, sizeof(PxVehicleWheelConcurrentUpdateData)*numActiveWheels);
+ vehConcurrentUpdates->linearMomentumChange = vehicleConcurrentUpdates.linearMomentumChange;
+ vehConcurrentUpdates->angularMomentumChange = vehicleConcurrentUpdates.angularMomentumChange;
+ vehConcurrentUpdates->staySleeping = vehicleConcurrentUpdates.staySleeping;
+ vehConcurrentUpdates->wakeup = vehicleConcurrentUpdates.wakeup;
+ }
+ else
+ {
+ //Apply the writes immediately.
+ PxVehicleWheels* vehWheels[1]={vehDriveNW};
+ PxVehiclePostUpdates(&vehicleConcurrentUpdates, 1, vehWheels);
+ }
+
+ END_TIMER(TIMER_POSTUPDATE3);
+}
+
+void PxVehicleUpdate::updateTank
+(const PxF32 timestep,
+ const PxVec3& gravity, const PxF32 gravityMagnitude, const PxF32 recipGravityMagnitude,
+ const PxVehicleDrivableSurfaceToTireFrictionPairs& drivableSurfaceToTireFrictionPairs,
+ PxVehicleDriveTank* vehDriveTank, PxVehicleWheelQueryResult* vehWheelQueryResults, PxVehicleConcurrentUpdateData* vehConcurrentUpdates)
+{
+ PX_SIMD_GUARD; // denorm exception in transformInertiaTensor()
+
+ PX_CHECK_AND_RETURN(
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL]>-0.01f &&
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL]<1.01f,
+ "Illegal tank control value - accel must be in range (0,1)" );
+ PX_CHECK_AND_RETURN(
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT]>-0.01f &&
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT]<1.01f,
+ "Illegal tank control value - left brake must be in range (0,1)");
+ PX_CHECK_AND_RETURN(
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT]>-0.01f &&
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT]<1.01f,
+ "Illegal tank control right value - right brake must be in range (0,1)");
+ PX_CHECK_AND_RETURN(
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT]>-1.01f &&
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT]<1.01f,
+ "Illegal tank control value - left thrust must be in range (-1,1)");
+ PX_CHECK_AND_RETURN(
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT]>-1.01f &&
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT]<1.01f,
+ "Illegal tank control value - right thrust must be in range (-1,1)");
+ PX_CHECK_AND_RETURN(
+ PxVehicleDriveTankControlModel::eSPECIAL==vehDriveTank->mDriveModel ||
+ (vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT]>-0.01f &&
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT]<1.01f),
+ "Illegal tank control value - left thrust must be in range (-1,1)");
+ PX_CHECK_AND_RETURN(
+ PxVehicleDriveTankControlModel::eSPECIAL==vehDriveTank->mDriveModel ||
+ (vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT]>-0.01f &&
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT]<1.01f),
+ "Illegal tank control value - right thrust must be in range (-1,1)");
+ PX_CHECK_AND_RETURN(
+ PxVehicleDriveTankControlModel::eSPECIAL==vehDriveTank->mDriveModel ||
+ 0.0f==
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT]*
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT],
+ "Illegal tank control value - thrust left and brake left simultaneously non-zero in standard drive mode");
+ PX_CHECK_AND_RETURN(
+ PxVehicleDriveTankControlModel::eSPECIAL==vehDriveTank->mDriveModel ||
+ 0.0f==
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT]*
+ vehDriveTank->mDriveDynData.mControlAnalogVals[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT],
+ "Illegal tank control value - thrust right and brake right simultaneously non-zero in standard drive mode");
+ PX_CHECK_AND_RETURN(
+ !(vehDriveTank->getRigidDynamicActor()->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC),
+ "Attempting to update a tank with a kinematic actor - this isn't allowed");
+ PX_CHECK_AND_RETURN(
+ NULL==vehWheelQueryResults || vehWheelQueryResults->nbWheelQueryResults >= vehDriveTank->mWheelsSimData.getNbWheels(),
+ "nbWheelQueryResults must always be greater than or equal to number of wheels in corresponding vehicle");
+
+#if PX_CHECKED
+ {
+ PxVec3 fl=vehDriveTank->mWheelsSimData.getWheelCentreOffset(PxVehicleDriveTankWheelOrder::eFRONT_LEFT);
+ PxVec3 fr=vehDriveTank->mWheelsSimData.getWheelCentreOffset(PxVehicleDriveTankWheelOrder::eFRONT_RIGHT);
+ const PxVec3 right=gRight;
+ const PxF32 s0=computeSign((fr-fl).dot(right));
+ for(PxU32 i=PxVehicleDriveTankWheelOrder::e1ST_FROM_FRONT_LEFT;i<vehDriveTank->mWheelsSimData.getNbWheels();i+=2)
+ {
+ PxVec3 rl=vehDriveTank->mWheelsSimData.getWheelCentreOffset(i);
+ PxVec3 rr=vehDriveTank->mWheelsSimData.getWheelCentreOffset(i+1);
+ const PxF32 t0=computeSign((rr-rl).dot(right));
+ PX_CHECK_AND_RETURN(s0==t0 || 0==s0 || 0==t0, "Tank wheels must be ordered with odd wheels on one side and even wheels on the other side");
+ }
+ }
+#endif
+
+
+#if PX_DEBUG_VEHICLE_ON
+ for(PxU32 i=0;i<vehDriveTank->mWheelsSimData.mNbWheels4;i++)
+ {
+ updateGraphDataInternalWheelDynamics(4*i,vehDriveTank->mWheelsDynData.mWheels4DynData[i].mWheelSpeeds);
+ }
+ updateGraphDataInternalEngineDynamics(vehDriveTank->mDriveDynData.getEngineRotationSpeed());
+#endif
+
+ //Unpack the tank simulation and instanced dynamics components.
+ const PxVehicleWheels4SimData* wheels4SimDatas=vehDriveTank->mWheelsSimData.mWheels4SimData;
+ const PxVehicleTireLoadFilterData& tireLoadFilterData=vehDriveTank->mWheelsSimData.mNormalisedLoadFilter;
+ PxVehicleWheels4DynData* wheels4DynDatas=vehDriveTank->mWheelsDynData.mWheels4DynData;
+ const PxU32 numWheels4=vehDriveTank->mWheelsSimData.mNbWheels4;
+ const PxU32 numActiveWheels=vehDriveTank->mWheelsSimData.mNbActiveWheels;
+ const PxU32 numActiveWheelsInLast4=4-(4*numWheels4-numActiveWheels);
+ const PxVehicleDriveSimData driveSimData=vehDriveTank->mDriveSimData;
+ PxVehicleDriveDynData& driveDynData=vehDriveTank->mDriveDynData;
+ PxRigidDynamic* vehActor=vehDriveTank->mActor;
+
+ //We need to store that data we are going to write to actors so we can do this at the end in one go with fewer write locks.
+ PxVehicleWheelConcurrentUpdateData wheelConcurrentUpdates[PX_MAX_NB_WHEELS];
+ PxVehicleConcurrentUpdateData vehicleConcurrentUpdates;
+ vehicleConcurrentUpdates.nbConcurrentWheelUpdates = numActiveWheels;
+ vehicleConcurrentUpdates.concurrentWheelUpdates = wheelConcurrentUpdates;
+
+ //Test if a non-zero drive torque was applied or if a non-zero steer angle was applied.
+ bool finiteInputApplied=false;
+ if(0!=driveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT) ||
+ 0!=driveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT) ||
+ 0!=driveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL) ||
+ driveDynData.getGearDown() || driveDynData.getGearUp())
+ {
+ finiteInputApplied=true;
+ }
+
+ //Awake or sleep.
+ {
+ if(vehActor->isSleeping())
+ {
+ if(finiteInputApplied)
+ {
+ //Driving inputs so we need the actor to start moving.
+ vehicleConcurrentUpdates.wakeup = true;
+ }
+ else if(isOnDynamicActor(vehDriveTank->mWheelsSimData, vehDriveTank->mWheelsDynData))
+ {
+ //Driving on dynamic so we need to keep moving.
+ vehicleConcurrentUpdates.wakeup = true;
+ }
+ else
+ {
+ //No driving inputs and the actor is asleep.
+ //Set internal dynamics to sleep.
+ setInternalDynamicsToZero(vehDriveTank);
+ if(vehConcurrentUpdates) vehConcurrentUpdates->staySleeping = true;
+ return;
+ }
+ }
+ }
+
+ //In each block of 4 wheels record how many wheels are active.
+ PxU32 numActiveWheelsPerBlock4[PX_MAX_NB_SUSPWHEELTIRE4]={0,0,0,0,0};
+ numActiveWheelsPerBlock4[0]=PxMin(numActiveWheels,PxU32(4));
+ for(PxU32 i=1;i<numWheels4-1;i++)
+ {
+ numActiveWheelsPerBlock4[i]=4;
+ }
+ numActiveWheelsPerBlock4[numWheels4-1]=numActiveWheelsInLast4;
+ PX_ASSERT(numActiveWheels == numActiveWheelsPerBlock4[0] + numActiveWheelsPerBlock4[1] + numActiveWheelsPerBlock4[2] + numActiveWheelsPerBlock4[3] + numActiveWheelsPerBlock4[4]);
+
+ //Organise the shader data in blocks of 4.
+ PxVehicleTireForceCalculator4 tires4ForceCalculators[PX_MAX_NB_SUSPWHEELTIRE4];
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ tires4ForceCalculators[i].mShaderData[0]=vehDriveTank->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+0];
+ tires4ForceCalculators[i].mShaderData[1]=vehDriveTank->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+1];
+ tires4ForceCalculators[i].mShaderData[2]=vehDriveTank->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+2];
+ tires4ForceCalculators[i].mShaderData[3]=vehDriveTank->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+3];
+ tires4ForceCalculators[i].mShader=vehDriveTank->mWheelsDynData.mTireForceCalculators->mShader;
+ }
+
+ //Mark the suspension/tire constraints as dirty to force them to be updated in the sdk.
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ wheels4DynDatas[i].getVehicletConstraintShader().mConstraint->markDirty();
+ }
+
+ //Need to store report data to pose the wheels.
+ PxWheelQueryResult wheelQueryResults[PX_MAX_NB_WHEELS];
+
+
+ //Center of mass local pose.
+ PxTransform carChassisCMLocalPose;
+ //Compute the transform of the center of mass.
+ PxTransform origCarChassisTransform;
+ PxTransform carChassisTransform;
+ //Inverse mass and inertia to apply the tire/suspension forces as impulses.
+ PxF32 inverseChassisMass;
+ PxVec3 inverseInertia;
+ //Linear and angular velocity.
+ PxVec3 carChassisLinVel;
+ PxVec3 carChassisAngVel;
+ {
+ carChassisCMLocalPose = vehActor->getCMassLocalPose();
+ origCarChassisTransform = vehActor->getGlobalPose().transform(vehActor->getCMassLocalPose());
+ carChassisTransform = origCarChassisTransform;
+ const PxF32 chassisMass = vehActor->getMass();
+ inverseChassisMass = 1.0f/chassisMass;
+ inverseInertia = vehActor->getMassSpaceInvInertiaTensor();
+ carChassisLinVel = vehActor->getLinearVelocity();
+ carChassisAngVel = vehActor->getAngularVelocity();
+ }
+
+ //Get the local poses of the wheel shapes.
+ //These are the poses from the last frame and equal to the poses used for the raycast we will process.
+ PxQuat wheelLocalPoseRotations[PX_MAX_NB_WHEELS];
+ PxF32 wheelThetas[PX_MAX_NB_WHEELS];
+ {
+ for (PxU32 i = 0; i < numActiveWheels; i++)
+ {
+ const PxI32 shapeId = vehDriveTank->mWheelsSimData.getWheelShapeMapping(i);
+ if (-1 != shapeId)
+ {
+ PxShape* shape = NULL;
+ vehActor->getShapes(&shape, 1, PxU32(shapeId));
+ wheelLocalPoseRotations[i] = shape->getLocalPose().q;
+ wheelThetas[i] = vehDriveTank->mWheelsDynData.getWheelRotationAngle(i);
+ }
+ }
+ }
+
+
+ //Retrieve control values from vehicle controls.
+ PxF32 accel,brakeLeft,brakeRight,thrustLeft,thrustRight;
+ {
+ getTankControlValues(driveDynData,accel,brakeLeft,brakeRight,thrustLeft,thrustRight);
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataControlInputs(accel,brakeLeft,brakeRight,thrustLeft,thrustRight);
+#endif
+ }
+
+ //Update the auto-box and decide whether to change gear up or down.
+ //If the tank is supposed to turn sharply don't process the auto-box.
+ bool useAutoGears;
+ if(vehDriveTank->getDriveModel()==PxVehicleDriveTankControlModel::eSPECIAL)
+ {
+ useAutoGears = driveDynData.getUseAutoGears() ? ((((thrustRight*thrustLeft) >= 0.0f) || (0.0f==thrustLeft && 0.0f==thrustRight)) ? true : false) : false;
+ }
+ else
+ {
+ useAutoGears = driveDynData.getUseAutoGears() ? (thrustRight*brakeLeft>0 || thrustLeft*brakeRight>0 ? false : true) : false;
+ }
+ if(useAutoGears)
+ {
+ processAutoBox(PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL,timestep,driveSimData,driveDynData);
+ }
+
+ //Process gear-up/gear-down commands.
+ {
+ const PxVehicleGearsData& gearsData=driveSimData.getGearsData();
+ processGears(timestep,gearsData,driveDynData);
+ }
+
+ //Clutch strength;
+ PxF32 K;
+ {
+ const PxVehicleClutchData& clutchData=driveSimData.getClutchData();
+ const PxU32 currentGear=driveDynData.getCurrentGear();
+ K=computeClutchStrength(clutchData, currentGear);
+ }
+
+ //Gear ratio.
+ PxF32 G;
+ PxU32 currentGear;
+ {
+ const PxVehicleGearsData& gearsData=driveSimData.getGearsData();
+ currentGear=driveDynData.getCurrentGear();
+ G=computeGearRatio(gearsData,currentGear);
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataGearRatio(G);
+#endif
+ }
+
+ bool isIntentionToAccelerate;
+ {
+ const PxF32 thrustLeftAbs=PxAbs(thrustLeft);
+ const PxF32 thrustRightAbs=PxAbs(thrustRight);
+ isIntentionToAccelerate = (accel*(thrustLeftAbs+thrustRightAbs)>0 && PxVehicleGearsData::eNEUTRAL != currentGear);
+ }
+
+
+ //Compute the wheels that are enabled/disabled.
+ bool activeWheelStates[PX_MAX_NB_WHEELS];
+ PxMemZero(activeWheelStates, sizeof(bool)*PX_MAX_NB_WHEELS);
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ computeWheelActiveStates(4*i, vehDriveTank->mWheelsSimData.mActiveWheelsBitmapBuffer, &activeWheelStates[4*i]);
+ }
+
+ //Set up contribution of each wheel to the average wheel speed at the clutch
+ //Set up the torque ratio delivered by the diff to each wheel.
+ //Set the sign of the gearing applied to the left and right wheels.
+ PxF32 aveWheelSpeedContributions[PX_MAX_NB_WHEELS];
+ PxF32 diffTorqueRatios[PX_MAX_NB_WHEELS];
+ PxF32 wheelGearings[PX_MAX_NB_WHEELS];
+ PxMemZero(aveWheelSpeedContributions, sizeof(PxF32)*PX_MAX_NB_WHEELS);
+ PxMemZero(diffTorqueRatios, sizeof(PxF32)*PX_MAX_NB_WHEELS);
+ PxMemZero(wheelGearings, sizeof(PxF32)*PX_MAX_NB_WHEELS);
+ computeTankDiff
+ (thrustLeft, thrustRight,
+ numActiveWheels, activeWheelStates,
+ aveWheelSpeedContributions, diffTorqueRatios, wheelGearings);
+
+ //Compute an accelerator pedal value per wheel.
+ bool isAccelApplied[PX_MAX_NB_WHEELS];
+ PxMemZero(isAccelApplied, sizeof(bool)*PX_MAX_NB_WHEELS);
+ if(isIntentionToAccelerate)
+ {
+ PX_ASSERT(accel>0);
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ computeIsAccelApplied(&aveWheelSpeedContributions[4*i], &isAccelApplied[4*i]);
+ }
+ }
+
+
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataClutchSlip(wheels4DynDatas[0].mWheelSpeeds,aveWheelSpeedContributions,driveDynData.getEngineRotationSpeed(),G);
+#endif
+
+ //Ackermann-corrected steer angles
+ //For tanks this is always zero because they turn by torque delivery rather than a steering mechanism.
+ PxF32 steerAngles[PX_MAX_NB_WHEELS];
+ PxMemZero(steerAngles, sizeof(PxF32)*PX_MAX_NB_WHEELS);
+
+ //Store the susp line raycast data.
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ storeRaycasts(wheels4DynDatas[i], &wheelQueryResults[4*i]);
+ }
+
+ //Ready to do the update.
+ PxVec3 carChassisLinVelOrig=carChassisLinVel;
+ PxVec3 carChassisAngVelOrig=carChassisAngVel;
+ const PxU32 numSubSteps=computeNumberOfSubsteps(vehDriveTank->mWheelsSimData,carChassisLinVel,carChassisTransform,gForward);
+ const PxF32 timeFraction=1.0f/(1.0f*numSubSteps);
+ const PxF32 subTimestep=timestep*timeFraction;
+ const PxF32 recipSubTimeStep=1.0f/subTimestep;
+ const PxF32 recipTimestep=1.0f/timestep;
+ const PxF32 minLongSlipDenominator=vehDriveTank->mWheelsSimData.mMinLongSlipDenominator;
+ ProcessSuspWheelTireConstData constData={timeFraction, subTimestep, recipSubTimeStep, gravity, gravityMagnitude, recipGravityMagnitude, true, minLongSlipDenominator, vehActor, &drivableSurfaceToTireFrictionPairs};
+
+ for(PxU32 k=0;k<numSubSteps;k++)
+ {
+ //Set the force and torque for the current update to zero.
+ PxVec3 chassisForce(0,0,0);
+ PxVec3 chassisTorque(0,0,0);
+
+ //Compute the brake torques.
+ PxF32 brakeTorques[PX_MAX_NB_WHEELS];
+ bool isBrakeApplied[PX_MAX_NB_WHEELS];
+ PxMemZero(brakeTorques, sizeof(PxF32)*PX_MAX_NB_WHEELS);
+ PxMemZero(isBrakeApplied, sizeof(bool)*PX_MAX_NB_WHEELS);
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ computeTankBrakeTorques
+ (&wheels4SimDatas[i].getWheelData(0),wheels4DynDatas[i].mWheelSpeeds,brakeLeft,brakeRight,
+ &brakeTorques[i*4],&isBrakeApplied[i*4]);
+ }
+
+ //Compute jounces, slips, tire forces, suspension forces etc.
+ ProcessSuspWheelTireOutputData outputData[PX_MAX_NB_SUSPWHEELTIRE4];
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ ProcessSuspWheelTireInputData inputData=
+ {
+ isIntentionToAccelerate, &isAccelApplied[i*4], &isBrakeApplied[i*4], &steerAngles[i*4], &activeWheelStates[4*i],
+ carChassisTransform, carChassisLinVel, carChassisAngVel,
+ &wheelLocalPoseRotations[i], &wheelThetas[i], &wheels4SimDatas[i], &wheels4DynDatas[i], &tires4ForceCalculators[i], &tireLoadFilterData, numActiveWheelsPerBlock4[i],
+ };
+ processSuspTireWheels(i*4, constData, inputData, outputData[i]);
+ updateLowSpeedTimers(outputData[i].newLowForwardSpeedTimers, const_cast<PxF32*>(inputData.vehWheels4DynData->mTireLowForwardSpeedTimers));
+ updateLowSpeedTimers(outputData[i].newLowSideSpeedTimers, const_cast<PxF32*>(inputData.vehWheels4DynData->mTireLowSideSpeedTimers));
+ updateJounces(outputData[i].jounces, const_cast<PxF32*>(inputData.vehWheels4DynData->mJounces));
+ if((numSubSteps-1) == k)
+ {
+ updateCachedHitData(outputData[i].cachedHitCounts, outputData[i].cachedHitPlanes, outputData[i].cachedHitDistances, outputData[i].cachedFrictionMultipliers, outputData[i].cachedHitQueryTypes, &wheels4DynDatas[i]);
+ }
+ chassisForce+=outputData[i].chassisForce;
+ chassisTorque+=outputData[i].chassisTorque;
+ if(0 == k)
+ {
+ wheels4DynDatas[i].mVehicleConstraints->mData=outputData[i].vehConstraintData;
+ }
+ storeSuspWheelTireResults(outputData[i], inputData.steerAngles, &wheelQueryResults[4*i], numActiveWheelsPerBlock4[i]);
+ storeHitActorForces(outputData[i], &vehicleConcurrentUpdates.concurrentWheelUpdates[4*i], numActiveWheelsPerBlock4[i]);
+ }
+
+ //Copy the tire torques to a single array.
+ PxF32 tireTorques[PX_MAX_NB_WHEELS];
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ tireTorques[4*i+0]=outputData[i].tireTorques[0];
+ tireTorques[4*i+1]=outputData[i].tireTorques[1];
+ tireTorques[4*i+2]=outputData[i].tireTorques[2];
+ tireTorques[4*i+3]=outputData[i].tireTorques[3];
+ }
+
+ PxF32 engineDriveTorque;
+ {
+ const PxVehicleEngineData& engineData=driveSimData.getEngineData();
+ const PxF32 engineOmega=driveDynData.getEngineRotationSpeed();
+ engineDriveTorque=computeEngineDriveTorque(engineData,engineOmega,accel);
+#if PX_DEBUG_VEHICLE_ON
+ updateGraphDataEngineDriveTorque(engineDriveTorque);
+#endif
+ }
+
+ PxF32 engineDampingRate;
+ {
+ const PxVehicleEngineData& engineData=driveSimData.getEngineData();
+ engineDampingRate=computeEngineDampingRate(engineData,currentGear,accel);
+ }
+
+ //Update the wheel and engine speeds - 5x5 matrix coupling engine and wheels.
+ ImplicitSolverInput implicitSolverInput =
+ {
+ subTimestep,
+ 0.0f, 0.0f,
+ K, G,
+ PxVehicleClutchAccuracyMode::eBEST_POSSIBLE, 0,
+ engineDriveTorque, engineDampingRate,
+ diffTorqueRatios, aveWheelSpeedContributions,
+ brakeTorques, isBrakeApplied, tireTorques,
+ numWheels4, numActiveWheels,
+ wheels4SimDatas, &driveSimData
+ };
+ ImplicitSolverOutput implicitSolverOutput =
+ {
+ wheels4DynDatas, &driveDynData
+ };
+ solveTankInternaDynamicsEnginePlusDrivenWheels(implicitSolverInput, activeWheelStates, wheelGearings, &implicitSolverOutput);
+
+ //Integrate wheel rotation angle (theta += omega*dt)
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ integrateWheelRotationAngles
+ (subTimestep,
+ K,G,engineDriveTorque,
+ outputData[i].jounces,diffTorqueRatios,outputData[i].forwardSpeeds,isBrakeApplied,
+ driveSimData,wheels4SimDatas[i],
+ driveDynData,wheels4DynDatas[i]);
+ }
+
+ //Apply the anti-roll suspension.
+ procesAntiRollSuspension(vehDriveTank->mWheelsSimData, carChassisTransform, wheelQueryResults, chassisTorque);
+
+ //Integrate the chassis velocity by applying the accumulated force and torque.
+ integrateBody(inverseChassisMass, inverseInertia, chassisForce, chassisTorque, subTimestep, carChassisLinVel, carChassisAngVel, carChassisTransform);
+ }
+
+ //Set the new chassis linear/angular velocity.
+ if(!gApplyForces)
+ {
+ vehicleConcurrentUpdates.linearMomentumChange = carChassisLinVel;
+ vehicleConcurrentUpdates.angularMomentumChange = carChassisAngVel;
+ }
+ else
+ {
+ //integration steps are:
+ //v = v0 + a*dt (1)
+ //x = x0 + v*dt (2)
+ //Sub (2) into (1.
+ //x = x0 + v0*dt + a*dt*dt;
+ //Rearrange for a
+ //a = (x -x0 - v0*dt)/(dt*dt) = [(x-x0)/dt - v0/dt]
+ //Rearrange again with v = (x-x0)/dt
+ //a = (v - v0)/dt
+ vehicleConcurrentUpdates.linearMomentumChange = (carChassisLinVel-carChassisLinVelOrig)*recipTimestep;
+ vehicleConcurrentUpdates.angularMomentumChange = (carChassisAngVel-carChassisAngVelOrig)*recipTimestep;
+ }
+
+ //Pose the wheels from jounces, rotations angles, and steer angles.
+ PxTransform localPoses0[4] = {PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity)};
+ computeWheelLocalPoses(wheels4SimDatas[0],wheels4DynDatas[0],&wheelQueryResults[4*0],numActiveWheelsPerBlock4[0],carChassisCMLocalPose,localPoses0);
+ wheelQueryResults[4*0 + 0].localPose = localPoses0[0];
+ wheelQueryResults[4*0 + 1].localPose = localPoses0[1];
+ wheelQueryResults[4*0 + 2].localPose = localPoses0[2];
+ wheelQueryResults[4*0 + 3].localPose = localPoses0[3];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 0].localPose = localPoses0[0];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 1].localPose = localPoses0[1];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 2].localPose = localPoses0[2];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 3].localPose = localPoses0[3];
+ for(PxU32 i=1;i<numWheels4;i++)
+ {
+ PxTransform localPoses[4] = {PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity)};
+ computeWheelLocalPoses(wheels4SimDatas[i],wheels4DynDatas[i],&wheelQueryResults[4*i],numActiveWheelsPerBlock4[i],carChassisCMLocalPose,localPoses);
+ wheelQueryResults[4*i + 0].localPose = localPoses[0];
+ wheelQueryResults[4*i + 1].localPose = localPoses[1];
+ wheelQueryResults[4*i + 2].localPose = localPoses[2];
+ wheelQueryResults[4*i + 3].localPose = localPoses[3];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 0].localPose = localPoses[0];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 1].localPose = localPoses[1];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 2].localPose = localPoses[2];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 3].localPose = localPoses[3];
+ }
+
+ if(vehWheelQueryResults && vehWheelQueryResults->wheelQueryResults)
+ {
+ PxMemCopy(vehWheelQueryResults->wheelQueryResults, wheelQueryResults, sizeof(PxWheelQueryResult)*numActiveWheels);
+ }
+
+ if(vehConcurrentUpdates)
+ {
+ //Copy across to input data structure so that writes can be applied later.
+ PxMemCopy(vehConcurrentUpdates->concurrentWheelUpdates, vehicleConcurrentUpdates.concurrentWheelUpdates, sizeof(PxVehicleWheelConcurrentUpdateData)*numActiveWheels);
+ vehConcurrentUpdates->linearMomentumChange = vehicleConcurrentUpdates.linearMomentumChange;
+ vehConcurrentUpdates->angularMomentumChange = vehicleConcurrentUpdates.angularMomentumChange;
+ vehConcurrentUpdates->staySleeping = vehicleConcurrentUpdates.staySleeping;
+ vehConcurrentUpdates->wakeup = vehicleConcurrentUpdates.wakeup;
+ }
+ else
+ {
+ //Apply the writes immediately.
+ PxVehicleWheels* vehWheels[1]={vehDriveTank};
+ PxVehiclePostUpdates(&vehicleConcurrentUpdates, 1, vehWheels);
+ }
+}
+
+void PxVehicleUpdate::updateNoDrive
+(const PxF32 timestep,
+ const PxVec3& gravity, const PxF32 gravityMagnitude, const PxF32 recipGravityMagnitude,
+ const PxVehicleDrivableSurfaceToTireFrictionPairs& drivableSurfaceToTireFrictionPairs,
+ PxVehicleNoDrive* vehNoDrive, PxVehicleWheelQueryResult* vehWheelQueryResults, PxVehicleConcurrentUpdateData* vehConcurrentUpdates)
+{
+ PX_SIMD_GUARD; // denorm exception in transformInertiaTensor() on osx
+
+ PX_CHECK_AND_RETURN(
+ !(vehNoDrive->getRigidDynamicActor()->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC),
+ "Attempting to update a PxVehicleNoDrive with a kinematic actor - this isn't allowed");
+
+ PX_CHECK_AND_RETURN(
+ NULL==vehWheelQueryResults || vehWheelQueryResults->nbWheelQueryResults >= vehNoDrive->mWheelsSimData.getNbWheels(),
+ "nbWheelQueryResults must always be greater than or equal to number of wheels in corresponding vehicle");
+
+#if PX_CHECKED
+ for(PxU32 i=0;i<vehNoDrive->mWheelsSimData.getNbWheels();i++)
+ {
+ PX_CHECK_AND_RETURN(
+ !vehNoDrive->mWheelsSimData.getIsWheelDisabled(i) || 0==vehNoDrive->getDriveTorque(i),
+ "Disabled wheels should have zero drive torque applied to them.");
+ }
+#endif
+
+#if PX_DEBUG_VEHICLE_ON
+ for(PxU32 i=0;i<vehNoDrive->mWheelsSimData.mNbWheels4;i++)
+ {
+ updateGraphDataInternalWheelDynamics(4*i,vehNoDrive->mWheelsDynData.mWheels4DynData[i].mWheelSpeeds);
+ }
+#endif
+
+ //Unpack the tank simulation and instanced dynamics components.
+ const PxVehicleWheels4SimData* wheels4SimDatas=vehNoDrive->mWheelsSimData.mWheels4SimData;
+ const PxVehicleTireLoadFilterData& tireLoadFilterData=vehNoDrive->mWheelsSimData.mNormalisedLoadFilter;
+ PxVehicleWheels4DynData* wheels4DynDatas=vehNoDrive->mWheelsDynData.mWheels4DynData;
+ const PxU32 numWheels4=vehNoDrive->mWheelsSimData.mNbWheels4;
+ const PxU32 numActiveWheels=vehNoDrive->mWheelsSimData.mNbActiveWheels;
+ const PxU32 numActiveWheelsInLast4=4-(4*numWheels4-numActiveWheels);
+ PxRigidDynamic* vehActor=vehNoDrive->mActor;
+
+ //We need to store that data we are going to write to actors so we can do this at the end in one go with fewer write locks.
+ PxVehicleWheelConcurrentUpdateData wheelConcurrentUpdates[PX_MAX_NB_WHEELS];
+ PxVehicleConcurrentUpdateData vehicleConcurrentUpdates;
+ vehicleConcurrentUpdates.nbConcurrentWheelUpdates = numActiveWheels;
+ vehicleConcurrentUpdates.concurrentWheelUpdates = wheelConcurrentUpdates;
+
+ //Test if a non-zero drive torque was applied or if a non-zero steer angle was applied.
+ bool finiteInputApplied=false;
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ if(vehNoDrive->getDriveTorque(i) != 0.0f)
+ {
+ finiteInputApplied=true;
+ break;
+ }
+ if(vehNoDrive->getSteerAngle(i)!=0.0f)
+ {
+ finiteInputApplied=true;
+ break;
+ }
+ }
+
+ //Wake or sleep.
+ {
+ if(vehActor->isSleeping())
+ {
+ if(finiteInputApplied)
+ {
+ //Driving inputs so we need the actor to start moving.
+ vehicleConcurrentUpdates.wakeup = true;
+ }
+ else if(isOnDynamicActor(vehNoDrive->mWheelsSimData, vehNoDrive->mWheelsDynData))
+ {
+ //Driving on dynamic so we need to keep moving.
+ vehicleConcurrentUpdates.wakeup = true;
+ }
+ else
+ {
+ //No driving inputs and the actor is asleep.
+ //Set internal dynamics to sleep.
+ setInternalDynamicsToZero(vehNoDrive);
+ if(vehConcurrentUpdates) vehConcurrentUpdates->staySleeping = true;
+ return;
+ }
+ }
+ }
+
+ //In each block of 4 wheels record how many wheels are active.
+ PxU32 numActiveWheelsPerBlock4[PX_MAX_NB_SUSPWHEELTIRE4]={0,0,0,0,0};
+ numActiveWheelsPerBlock4[0]=PxMin(numActiveWheels,PxU32(4));
+ for(PxU32 i=1;i<numWheels4-1;i++)
+ {
+ numActiveWheelsPerBlock4[i]=4;
+ }
+ numActiveWheelsPerBlock4[numWheels4-1]=numActiveWheelsInLast4;
+ PX_ASSERT(numActiveWheels == numActiveWheelsPerBlock4[0] + numActiveWheelsPerBlock4[1] + numActiveWheelsPerBlock4[2] + numActiveWheelsPerBlock4[3] + numActiveWheelsPerBlock4[4]);
+
+ //Organise the shader data in blocks of 4.
+ PxVehicleTireForceCalculator4 tires4ForceCalculators[PX_MAX_NB_SUSPWHEELTIRE4];
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ tires4ForceCalculators[i].mShaderData[0]=vehNoDrive->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+0];
+ tires4ForceCalculators[i].mShaderData[1]=vehNoDrive->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+1];
+ tires4ForceCalculators[i].mShaderData[2]=vehNoDrive->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+2];
+ tires4ForceCalculators[i].mShaderData[3]=vehNoDrive->mWheelsDynData.mTireForceCalculators->mShaderData[4*i+3];
+ tires4ForceCalculators[i].mShader=vehNoDrive->mWheelsDynData.mTireForceCalculators->mShader;
+ }
+
+ //Mark the suspension/tire constraints as dirty to force them to be updated in the sdk.
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ wheels4DynDatas[i].getVehicletConstraintShader().mConstraint->markDirty();
+ }
+
+ //Need to store report data to pose the wheels.
+ PxWheelQueryResult wheelQueryResults[PX_MAX_NB_WHEELS];
+
+ //Center of mass local pose.
+ PxTransform carChassisCMLocalPose;
+ //Compute the transform of the center of mass.
+ PxTransform origCarChassisTransform;
+ PxTransform carChassisTransform;
+ //Inverse mass and inertia to apply the tire/suspension forces as impulses.
+ PxF32 inverseChassisMass;
+ PxVec3 inverseInertia;
+ //Linear and angular velocity.
+ PxVec3 carChassisLinVel;
+ PxVec3 carChassisAngVel;
+ {
+ carChassisCMLocalPose = vehActor->getCMassLocalPose();
+ origCarChassisTransform = vehActor->getGlobalPose().transform(carChassisCMLocalPose);
+ carChassisTransform = origCarChassisTransform;
+ const PxF32 chassisMass = vehActor->getMass();
+ inverseChassisMass = 1.0f/chassisMass;
+ inverseInertia = vehActor->getMassSpaceInvInertiaTensor();
+ carChassisLinVel = vehActor->getLinearVelocity();
+ carChassisAngVel = vehActor->getAngularVelocity();
+ }
+
+ //Get the local poses of the wheel shapes.
+ //These are the poses from the last frame and equal to the poses used for the raycast we will process.
+ PxQuat wheelLocalPoseRotations[PX_MAX_NB_WHEELS];
+ PxF32 wheelThetas[PX_MAX_NB_WHEELS];
+ {
+ for (PxU32 i = 0; i < numActiveWheels; i++)
+ {
+ const PxI32 shapeId = vehNoDrive->mWheelsSimData.getWheelShapeMapping(i);
+ if (-1 != shapeId)
+ {
+ PxShape* shape = NULL;
+ vehActor->getShapes(&shape, 1, PxU32(shapeId));
+ wheelLocalPoseRotations[i] = shape->getLocalPose().q;
+ wheelThetas[i] = vehNoDrive->mWheelsDynData.getWheelRotationAngle(i);
+ }
+ }
+ }
+
+ PxF32 maxAccel=0;
+ PxF32 maxBrake=0;
+ for(PxU32 i=0;i<numActiveWheels;i++)
+ {
+ maxAccel = PxMax(PxAbs(vehNoDrive->mDriveTorques[i]), maxAccel);
+ maxBrake = PxMax(PxAbs(vehNoDrive->mBrakeTorques[i]), maxBrake);
+ }
+ const bool isIntentionToAccelerate = (maxAccel>0.0f && 0.0f==maxBrake);
+
+ //Store the susp line raycast data.
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ storeRaycasts(wheels4DynDatas[i], &wheelQueryResults[4*i]);
+ }
+
+ //Ready to do the update.
+ PxVec3 carChassisLinVelOrig=carChassisLinVel;
+ PxVec3 carChassisAngVelOrig=carChassisAngVel;
+ const PxU32 numSubSteps=computeNumberOfSubsteps(vehNoDrive->mWheelsSimData,carChassisLinVel,carChassisTransform,gForward);
+ const PxF32 timeFraction=1.0f/(1.0f*numSubSteps);
+ const PxF32 subTimestep=timestep*timeFraction;
+ const PxF32 recipSubTimeStep=1.0f/subTimestep;
+ const PxF32 recipTimestep=1.0f/timestep;
+ const PxF32 minLongSlipDenominator=vehNoDrive->mWheelsSimData.mMinLongSlipDenominator;
+ ProcessSuspWheelTireConstData constData={timeFraction, subTimestep, recipSubTimeStep, gravity, gravityMagnitude, recipGravityMagnitude, false, minLongSlipDenominator, vehActor, &drivableSurfaceToTireFrictionPairs};
+
+ for(PxU32 k=0;k<numSubSteps;k++)
+ {
+ //Set the force and torque for the current update to zero.
+ PxVec3 chassisForce(0,0,0);
+ PxVec3 chassisTorque(0,0,0);
+
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ //Get the raw input torques.
+ const PxF32* PX_RESTRICT rawBrakeTorques=&vehNoDrive->mBrakeTorques[4*i];
+ const PxF32* PX_RESTRICT rawSteerAngles=&vehNoDrive->mSteerAngles[4*i];
+ const PxF32* PX_RESTRICT rawDriveTorques=&vehNoDrive->mDriveTorques[4*i];
+
+ //Work out which wheels are enabled.
+ bool activeWheelStates[4]={false,false,false,false};
+ computeWheelActiveStates(4*i, vehNoDrive->mWheelsSimData.mActiveWheelsBitmapBuffer, activeWheelStates);
+
+ const PxVehicleWheels4SimData& wheels4SimData=wheels4SimDatas[i];
+ PxVehicleWheels4DynData& wheels4DynData=wheels4DynDatas[i];
+
+ //Compute the brake torques.
+ PxF32 brakeTorques[4]={0.0f,0.0f,0.0f,0.0f};
+ bool isBrakeApplied[4]={false,false,false,false};
+ computeNoDriveBrakeTorques
+ (wheels4SimData.mWheels,wheels4DynData.mWheelSpeeds,rawBrakeTorques,
+ brakeTorques,isBrakeApplied);
+
+ //Compute the per wheel accel pedal values.
+ bool isAccelApplied[4]={false,false,false,false};
+ if(isIntentionToAccelerate)
+ {
+ computeIsAccelApplied(rawDriveTorques, isAccelApplied);
+ }
+
+ //Compute jounces, slips, tire forces, suspension forces etc.
+ ProcessSuspWheelTireInputData inputData=
+ {
+ isIntentionToAccelerate, isAccelApplied, isBrakeApplied, rawSteerAngles, activeWheelStates,
+ carChassisTransform, carChassisLinVel, carChassisAngVel,
+ &wheelLocalPoseRotations[i], &wheelThetas[i], &wheels4SimData, &wheels4DynData, &tires4ForceCalculators[i], &tireLoadFilterData, numActiveWheelsPerBlock4[i]
+ };
+ ProcessSuspWheelTireOutputData outputData;
+ processSuspTireWheels(4*i, constData, inputData, outputData);
+ updateLowSpeedTimers(outputData.newLowForwardSpeedTimers, const_cast<PxF32*>(inputData.vehWheels4DynData->mTireLowForwardSpeedTimers));
+ updateLowSpeedTimers(outputData.newLowSideSpeedTimers, const_cast<PxF32*>(inputData.vehWheels4DynData->mTireLowSideSpeedTimers));
+ updateJounces(outputData.jounces, const_cast<PxF32*>(inputData.vehWheels4DynData->mJounces));
+ if((numSubSteps-1) == k)
+ {
+ updateCachedHitData(outputData.cachedHitCounts, outputData.cachedHitPlanes, outputData.cachedHitDistances, outputData.cachedFrictionMultipliers, outputData.cachedHitQueryTypes, &wheels4DynData);
+ }
+ chassisForce+=outputData.chassisForce;
+ chassisTorque+=outputData.chassisTorque;
+ if(0 == k)
+ {
+ wheels4DynDatas[i].mVehicleConstraints->mData=outputData.vehConstraintData;
+ }
+ storeSuspWheelTireResults(outputData, inputData.steerAngles, &wheelQueryResults[4*i], numActiveWheelsPerBlock4[i]);
+ storeHitActorForces(outputData, &vehicleConcurrentUpdates.concurrentWheelUpdates[4*i], numActiveWheelsPerBlock4[i]);
+
+ //Integrate wheel speeds.
+ const PxF32 wheelDampingRates[4]=
+ {
+ wheels4SimData.getWheelData(0).mDampingRate,
+ wheels4SimData.getWheelData(1).mDampingRate,
+ wheels4SimData.getWheelData(2).mDampingRate,
+ wheels4SimData.getWheelData(3).mDampingRate
+ };
+ integrateNoDriveWheelSpeeds(
+ subTimestep,
+ brakeTorques,isBrakeApplied,rawDriveTorques,outputData.tireTorques,wheelDampingRates,
+ wheels4SimData,wheels4DynData);
+
+ integrateNoDriveWheelRotationAngles(
+ subTimestep,
+ rawDriveTorques,
+ outputData.jounces, outputData.forwardSpeeds, isBrakeApplied,
+ wheels4SimData,
+ wheels4DynData);
+ }
+
+ //Apply the anti-roll suspension.
+ procesAntiRollSuspension(vehNoDrive->mWheelsSimData, carChassisTransform, wheelQueryResults, chassisTorque);
+
+ //Integrate the chassis velocity by applying the accumulated force and torque.
+ integrateBody(inverseChassisMass, inverseInertia, chassisForce, chassisTorque, subTimestep, carChassisLinVel, carChassisAngVel, carChassisTransform);
+ }
+
+ //Set the new chassis linear/angular velocity.
+ if(!gApplyForces)
+ {
+ vehicleConcurrentUpdates.linearMomentumChange = carChassisLinVel;
+ vehicleConcurrentUpdates.angularMomentumChange = carChassisAngVel;
+ }
+ else
+ {
+ //integration steps are:
+ //v = v0 + a*dt (1)
+ //x = x0 + v*dt (2)
+ //Sub (2) into (1.
+ //x = x0 + v0*dt + a*dt*dt;
+ //Rearrange for a
+ //a = (x -x0 - v0*dt)/(dt*dt) = [(x-x0)/dt - v0/dt]
+ //Rearrange again with v = (x-x0)/dt
+ //a = (v - v0)/dt
+ vehicleConcurrentUpdates.linearMomentumChange = (carChassisLinVel-carChassisLinVelOrig)*recipTimestep;
+ vehicleConcurrentUpdates.angularMomentumChange = (carChassisAngVel-carChassisAngVelOrig)*recipTimestep;
+ }
+
+ //Pose the wheels from jounces, rotations angles, and steer angles.
+ PxTransform localPoses0[4] = {PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity)};
+ computeWheelLocalPoses(wheels4SimDatas[0],wheels4DynDatas[0],&wheelQueryResults[4*0],numActiveWheelsPerBlock4[0],carChassisCMLocalPose,localPoses0);
+ wheelQueryResults[4*0 + 0].localPose = localPoses0[0];
+ wheelQueryResults[4*0 + 1].localPose = localPoses0[1];
+ wheelQueryResults[4*0 + 2].localPose = localPoses0[2];
+ wheelQueryResults[4*0 + 3].localPose = localPoses0[3];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 0].localPose = localPoses0[0];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 1].localPose = localPoses0[1];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 2].localPose = localPoses0[2];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*0 + 3].localPose = localPoses0[3];
+ for(PxU32 i=1;i<numWheels4;i++)
+ {
+ PxTransform localPoses[4] = {PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity), PxTransform(PxIdentity)};
+ computeWheelLocalPoses(wheels4SimDatas[i],wheels4DynDatas[i],&wheelQueryResults[4*i],numActiveWheelsPerBlock4[i],carChassisCMLocalPose,localPoses);
+ wheelQueryResults[4*i + 0].localPose = localPoses[0];
+ wheelQueryResults[4*i + 1].localPose = localPoses[1];
+ wheelQueryResults[4*i + 2].localPose = localPoses[2];
+ wheelQueryResults[4*i + 3].localPose = localPoses[3];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 0].localPose = localPoses[0];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 1].localPose = localPoses[1];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 2].localPose = localPoses[2];
+ vehicleConcurrentUpdates.concurrentWheelUpdates[4*i + 3].localPose = localPoses[3];
+ }
+
+ if(vehWheelQueryResults && vehWheelQueryResults->wheelQueryResults)
+ {
+ PxMemCopy(vehWheelQueryResults->wheelQueryResults, wheelQueryResults, sizeof(PxWheelQueryResult)*numActiveWheels);
+ }
+
+ if(vehConcurrentUpdates)
+ {
+ //Copy across to input data structure so that writes can be applied later.
+ PxMemCopy(vehConcurrentUpdates->concurrentWheelUpdates, vehicleConcurrentUpdates.concurrentWheelUpdates, sizeof(PxVehicleWheelConcurrentUpdateData)*numActiveWheels);
+ vehConcurrentUpdates->linearMomentumChange = vehicleConcurrentUpdates.linearMomentumChange;
+ vehConcurrentUpdates->angularMomentumChange = vehicleConcurrentUpdates.angularMomentumChange;
+ vehConcurrentUpdates->staySleeping = vehicleConcurrentUpdates.staySleeping;
+ vehConcurrentUpdates->wakeup = vehicleConcurrentUpdates.wakeup;
+ }
+ else
+ {
+ //Apply the writes immediately.
+ PxVehicleWheels* vehWheels[1]={vehNoDrive};
+ PxVehiclePostUpdates(&vehicleConcurrentUpdates, 1, vehWheels);
+ }
+}
+
+
+void PxVehicleUpdate::shiftOrigin(const PxVec3& shift, const PxU32 numVehicles, PxVehicleWheels** vehicles)
+{
+ for(PxU32 i=0; i < numVehicles; i++)
+ {
+ //Get the current car.
+ PxVehicleWheels& veh = *vehicles[i];
+ PxVehicleWheels4DynData* PX_RESTRICT wheels4DynData=veh.mWheelsDynData.mWheels4DynData;
+ const PxU32 numWheels4=veh.mWheelsSimData.mNbWheels4;
+
+ //Blocks of 4 wheels.
+ for(PxU32 j=0; j < numWheels4; j++)
+ {
+ bool activeWheelStates[4]={false,false,false,false};
+ computeWheelActiveStates(4*j, veh.mWheelsSimData.mActiveWheelsBitmapBuffer, activeWheelStates);
+
+ if (wheels4DynData[j].mRaycastResults) // this is set when a query has been scheduled
+ {
+ PxVehicleWheels4DynData::SuspLineRaycast& raycast =
+ reinterpret_cast<PxVehicleWheels4DynData::SuspLineRaycast&>(wheels4DynData[j].mQueryOrCachedHitResults);
+
+ for(PxU32 k=0; k < 4; k++)
+ {
+ if (activeWheelStates[k])
+ {
+ raycast.mStarts[k] -= shift;
+
+ if (wheels4DynData[j].mRaycastResults[k].hasBlock)
+ const_cast<PxVec3&>(wheels4DynData[j].mRaycastResults[k].block.position) -= shift;
+ }
+ }
+ }
+ else if(wheels4DynData[i].mSweepResults)
+ {
+ PxVehicleWheels4DynData::SuspLineSweep& sweep =
+ reinterpret_cast<PxVehicleWheels4DynData::SuspLineSweep&>(wheels4DynData[j].mQueryOrCachedHitResults);
+
+ for(PxU32 k=0; k < 4; k++)
+ {
+ if (activeWheelStates[k])
+ {
+ sweep.mStartPose[k].p -= shift;
+
+ if (wheels4DynData[j].mSweepResults[k].hasBlock)
+ const_cast<PxVec3&>(wheels4DynData[j].mSweepResults[k].block.position) -= shift;
+ }
+ }
+ }
+ }
+ }
+}
+
+}//namespace physx
+
+#if PX_DEBUG_VEHICLE_ON
+
+/////////////////////////////////////////////////////////////////////////////////
+//Update a single vehicle of any type and record the associated telemetry data.
+/////////////////////////////////////////////////////////////////////////////////
+
+void PxVehicleUpdate::updateSingleVehicleAndStoreTelemetryData
+(const PxF32 timestep, const PxVec3& gravity, const PxVehicleDrivableSurfaceToTireFrictionPairs& vehicleDrivableSurfaceToTireFrictionPairs,
+ PxVehicleWheels* vehWheels, PxVehicleWheelQueryResult* vehWheelQueryResults, PxVehicleTelemetryData& telemetryData)
+{
+ START_TIMER(TIMER_ALL);
+
+ PX_CHECK_MSG(gravity.magnitude()>0, "gravity vector must have non-zero length");
+ PX_CHECK_MSG(timestep>0, "timestep must be greater than zero");
+ PX_CHECK_AND_RETURN(gThresholdForwardSpeedForWheelAngleIntegration>0, "PxInitVehicleSDK needs to be called before ever calling PxVehicleUpdateSingleVehicleAndStoreTelemetryData");
+ PX_CHECK_MSG(vehWheels->mWheelsSimData.getNbWheels()==telemetryData.getNbWheelGraphs(), "vehicle and telemetry data need to have the same number of wheels");
+ PX_CHECK_AND_RETURN(NULL==vehWheelQueryResults || vehWheelQueryResults->nbWheelQueryResults >= vehWheels->mWheelsSimData.getNbWheels(),
+ "nbWheelQueryResults must always be greater than or equal to number of wheels in corresponding vehicle");
+
+#if PX_CHECKED
+ for(PxU32 i=0;i<vehWheels->mWheelsSimData.mNbWheels4;i++)
+ {
+ PX_CHECK_MSG(vehWheels->mWheelsDynData.mWheels4DynData[i].mRaycastResults || vehWheels->mWheelsDynData.mWheels4DynData[i].mSweepResults,
+ "Need to call PxVehicleSuspensionRaycasts or PxVehicleSuspensionSweeps before trying to update");
+ }
+ for(PxU32 i=0;i<vehWheels->mWheelsSimData.mNbActiveWheels;i++)
+ {
+ PX_CHECK_MSG(vehWheels->mWheelsDynData.mTireForceCalculators->mShaderData[i], "Need to set non-null tire force shader data ptr");
+ }
+ PX_CHECK_MSG(vehWheels->mWheelsDynData.mTireForceCalculators->mShader, "Need to set non-null tire force shader function");
+
+ for(PxU32 i=0;i<vehWheels->mWheelsSimData.mNbActiveWheels;i++)
+ {
+ PX_CHECK_AND_RETURN(!vehWheels->mWheelsSimData.getIsWheelDisabled(i) || -1==vehWheels->mWheelsSimData.getWheelShapeMapping(i),
+ "Disabled wheels must not be associated with a PxShape: use setWheelShapeMapping to remove the association");
+ PX_CHECK_AND_RETURN(!vehWheels->mWheelsSimData.getIsWheelDisabled(i) || 0==vehWheels->mWheelsDynData.getWheelRotationSpeed(i),
+ "Disabled wheels must have zero rotation speed: use setWheelRotationSpeed to set the wheel to zero rotation speed");
+ }
+#endif
+
+ PxF32 engineGraphData[PxVehicleDriveGraphChannel::eMAX_NB_DRIVE_CHANNELS];
+ PxMemZero(&engineGraphData[0], PxVehicleDriveGraphChannel::eMAX_NB_DRIVE_CHANNELS*sizeof(PxF32));
+ gCarEngineGraphData=engineGraphData;
+
+ PxF32 wheelGraphData[PX_MAX_NB_WHEELS][PxVehicleWheelGraphChannel::eMAX_NB_WHEEL_CHANNELS];
+ PxMemZero(&wheelGraphData[0][0], PX_MAX_NB_WHEELS*PxVehicleWheelGraphChannel::eMAX_NB_WHEEL_CHANNELS*sizeof(PxF32));
+ for(PxU32 i=0;i<4*vehWheels->mWheelsSimData.mNbWheels4;i++)
+ {
+ gCarWheelGraphData[i]=wheelGraphData[i];
+ }
+ for(PxU32 i=4*vehWheels->mWheelsSimData.mNbWheels4; i<PX_MAX_NB_WHEELS;i++)
+ {
+ gCarWheelGraphData[i]=NULL;
+ }
+
+ PxVec3 suspForceAppPoints[PX_MAX_NB_WHEELS];
+ PxMemZero(suspForceAppPoints, PX_MAX_NB_WHEELS*sizeof(PxVec3));
+ gCarSuspForceAppPoints=suspForceAppPoints;
+
+ PxVec3 tireForceAppPoints[PX_MAX_NB_WHEELS];
+ PxMemZero(tireForceAppPoints, PX_MAX_NB_WHEELS*sizeof(PxVec3));
+ gCarTireForceAppPoints=tireForceAppPoints;
+
+ const PxF32 gravityMagnitude=gravity.magnitude();
+ const PxF32 recipGravityMagnitude=1.0f/gravityMagnitude;
+
+ switch(vehWheels->mType)
+ {
+ case PxVehicleTypes::eDRIVE4W:
+ {
+ PxVehicleDrive4W* vehDrive4W=static_cast<PxVehicleDrive4W*>(vehWheels);
+
+ PxVehicleUpdate::updateDrive4W(
+ timestep,
+ gravity, gravityMagnitude, recipGravityMagnitude,
+ vehicleDrivableSurfaceToTireFrictionPairs,
+ vehDrive4W, vehWheelQueryResults, NULL);
+
+ for(PxU32 i=0;i<vehWheels->mWheelsSimData.mNbActiveWheels;i++)
+ {
+ telemetryData.mWheelGraphs[i].updateTimeSlice(wheelGraphData[i]);
+ telemetryData.mSuspforceAppPoints[i]=suspForceAppPoints[i];
+ telemetryData.mTireforceAppPoints[i]=tireForceAppPoints[i];
+ }
+ telemetryData.mEngineGraph->updateTimeSlice(engineGraphData);
+ }
+ break;
+ case PxVehicleTypes::eDRIVENW:
+ {
+ PxVehicleDriveNW* vehDriveNW=static_cast<PxVehicleDriveNW*>(vehWheels);
+
+ PxVehicleUpdate::updateDriveNW(
+ timestep,
+ gravity, gravityMagnitude, recipGravityMagnitude,
+ vehicleDrivableSurfaceToTireFrictionPairs,
+ vehDriveNW, vehWheelQueryResults, NULL);
+
+ for(PxU32 i=0;i<vehWheels->mWheelsSimData.mNbActiveWheels;i++)
+ {
+ telemetryData.mWheelGraphs[i].updateTimeSlice(wheelGraphData[i]);
+ telemetryData.mSuspforceAppPoints[i]=suspForceAppPoints[i];
+ telemetryData.mTireforceAppPoints[i]=tireForceAppPoints[i];
+ }
+ telemetryData.mEngineGraph->updateTimeSlice(engineGraphData);
+ }
+ break;
+
+ case PxVehicleTypes::eDRIVETANK:
+ {
+ PxVehicleDriveTank* vehDriveTank=static_cast<PxVehicleDriveTank*>(vehWheels);
+
+ PxVehicleUpdate::updateTank(
+ timestep,
+ gravity,gravityMagnitude,recipGravityMagnitude,
+ vehicleDrivableSurfaceToTireFrictionPairs,
+ vehDriveTank, vehWheelQueryResults, NULL);
+
+ for(PxU32 i=0;i<vehWheels->mWheelsSimData.mNbActiveWheels;i++)
+ {
+ telemetryData.mWheelGraphs[i].updateTimeSlice(wheelGraphData[i]);
+ telemetryData.mSuspforceAppPoints[i]=suspForceAppPoints[i];
+ telemetryData.mTireforceAppPoints[i]=tireForceAppPoints[i];
+ }
+ telemetryData.mEngineGraph->updateTimeSlice(engineGraphData);
+ }
+ break;
+ case PxVehicleTypes::eNODRIVE:
+ {
+ PxVehicleNoDrive* vehDriveNoDrive=static_cast<PxVehicleNoDrive*>(vehWheels);
+
+ PxVehicleUpdate::updateNoDrive(
+ timestep,
+ gravity,gravityMagnitude,recipGravityMagnitude,
+ vehicleDrivableSurfaceToTireFrictionPairs,
+ vehDriveNoDrive, vehWheelQueryResults, NULL);
+
+ for(PxU32 i=0;i<vehWheels->mWheelsSimData.mNbActiveWheels;i++)
+ {
+ telemetryData.mWheelGraphs[i].updateTimeSlice(wheelGraphData[i]);
+ telemetryData.mSuspforceAppPoints[i]=suspForceAppPoints[i];
+ telemetryData.mTireforceAppPoints[i]=tireForceAppPoints[i];
+ }
+ }
+ break;
+
+ default:
+ PX_CHECK_MSG(false, "updateSingleVehicleAndStoreTelemetryData - unsupported vehicle type");
+ break;
+ }
+
+ END_TIMER(TIMER_ALL);
+
+#if PX_VEHICLE_PROFILE
+
+ gTimerCount++;
+ if(10==gTimerCount)
+ {
+
+ /*
+ printf("%f %f %f %f %f %f %f %f %f\n",
+ localTimers[TIMER_ADMIN]/(1.0f*localTimers[TIMER_ALL]),
+ localTimers[TIMER_GRAPHS]/(1.0f*localTimers[TIMER_ALL]),
+ localTimers[TIMER_COMPONENTS_UPDATE]/(1.0f*localTimers[TIMER_ALL]),
+ localTimers[TIMER_WHEELS]/(1.0f*localTimers[TIMER_ALL]),
+ localTimers[TIMER_INTERNAL_DYNAMICS_SOLVER]/(1.0f*localTimers[TIMER_ALL]),
+ localTimers[TIMER_POSTUPDATE1]/(1.0f*localTimers[TIMER_ALL]),
+ localTimers[TIMER_POSTUPDATE2]/(1.0f*localTimers[TIMER_ALL]),
+ localTimers[TIMER_POSTUPDATE3]/(1.0f*localTimers[TIMER_ALL]),
+ floatTimeIn10sOfNs);
+ */
+
+ printf("%f %f %f %f %f %f \n",
+ getTimerFraction(TIMER_WHEELS),
+ getTimerFraction(TIMER_INTERNAL_DYNAMICS_SOLVER),
+ getTimerFraction(TIMER_POSTUPDATE2),
+ getTimerFraction(TIMER_POSTUPDATE3),
+ getTimerInMilliseconds(TIMER_ALL),
+ getTimerInMilliseconds(TIMER_RAYCASTS));
+
+ gTimerCount=0;
+ for(PxU32 i=0;i<MAX_NB_TIMERS;i++)
+ {
+ gTimers[i]=0;
+ }
+ }
+
+#endif
+}
+
+void physx::PxVehicleUpdateSingleVehicleAndStoreTelemetryData
+(const PxReal timestep, const PxVec3& gravity, const physx::PxVehicleDrivableSurfaceToTireFrictionPairs& vehicleDrivableSurfaceToTireFrictionPairs,
+ PxVehicleWheels* focusVehicle, PxVehicleWheelQueryResult* wheelQueryResults, PxVehicleTelemetryData& telemetryData)
+{
+ PxVehicleUpdate::updateSingleVehicleAndStoreTelemetryData
+ (timestep, gravity, vehicleDrivableSurfaceToTireFrictionPairs, focusVehicle, wheelQueryResults, telemetryData);
+}
+
+#endif
+
+////////////////////////////////////////////////////////////
+//Update an array of vehicles of any type
+////////////////////////////////////////////////////////////
+
+void PxVehicleUpdate::update
+(const PxF32 timestep, const PxVec3& gravity, const PxVehicleDrivableSurfaceToTireFrictionPairs& vehicleDrivableSurfaceToTireFrictionPairs,
+ const PxU32 numVehicles, PxVehicleWheels** vehicles, PxVehicleWheelQueryResult* vehicleWheelQueryResults, PxVehicleConcurrentUpdateData* vehicleConcurrentUpdates)
+{
+ PX_CHECK_AND_RETURN(gravity.magnitude()>0, "gravity vector must have non-zero length");
+ PX_CHECK_AND_RETURN(timestep>0, "timestep must be greater than zero");
+ PX_CHECK_AND_RETURN(gThresholdForwardSpeedForWheelAngleIntegration>0, "PxInitVehicleSDK needs to be called before ever calling PxVehicleUpdates");
+
+#if PX_CHECKED
+ for(PxU32 i=0;i<numVehicles;i++)
+ {
+ const PxVehicleWheels* const vehWheels=vehicles[i];
+ for(PxU32 j=0;j<vehWheels->mWheelsSimData.mNbWheels4;j++)
+ {
+ PX_CHECK_MSG(
+ vehWheels->mWheelsDynData.mWheels4DynData[j].mRaycastResults ||
+ vehWheels->mWheelsDynData.mWheels4DynData[j].mSweepResults ||
+ vehWheels->mWheelsDynData.mWheels4DynData[0].mHasCachedRaycastHitPlane ||
+ (vehWheels->mWheelsSimData.getIsWheelDisabled(4*j+0) &&
+ vehWheels->mWheelsSimData.getIsWheelDisabled(4*j+1) &&
+ vehWheels->mWheelsSimData.getIsWheelDisabled(4*j+2) &&
+ vehWheels->mWheelsSimData.getIsWheelDisabled(4*j+3)),
+ "Need to call PxVehicleSuspensionRaycasts or PxVehicleSuspensionSweeps at least once before trying to update");
+ }
+ for(PxU32 j=0;j<vehWheels->mWheelsSimData.mNbActiveWheels;j++)
+ {
+ PX_CHECK_MSG(vehWheels->mWheelsDynData.mTireForceCalculators->mShaderData[j], "Need to set non-null tire force shader data ptr");
+ }
+ PX_CHECK_MSG(vehWheels->mWheelsDynData.mTireForceCalculators->mShader, "Need to set non-null tire force shader function");
+
+ PX_CHECK_AND_RETURN(NULL==vehicleWheelQueryResults || vehicleWheelQueryResults[i].nbWheelQueryResults >= vehicles[i]->mWheelsSimData.getNbWheels(),
+ "nbWheelQueryResults must always be greater than or equal to number of wheels in corresponding vehicle");
+
+ for(PxU32 j=0;j<vehWheels->mWheelsSimData.mNbActiveWheels;j++)
+ {
+ PX_CHECK_AND_RETURN(!vehWheels->mWheelsSimData.getIsWheelDisabled(j) || -1==vehWheels->mWheelsSimData.getWheelShapeMapping(j),
+ "Disabled wheels must not be associated with a PxShape: use setWheelShapeMapping to remove the association");
+
+ PX_CHECK_AND_RETURN(!vehWheels->mWheelsSimData.getIsWheelDisabled(j) || 0==vehWheels->mWheelsDynData.getWheelRotationSpeed(j),
+ "Disabled wheels must have zero rotation speed: use setWheelRotationSpeed to set the wheel to zero rotation speed");
+ }
+
+ PX_CHECK_AND_RETURN(!vehicleConcurrentUpdates || (vehicleConcurrentUpdates[i].concurrentWheelUpdates && vehicleConcurrentUpdates[i].nbConcurrentWheelUpdates >= vehicles[i]->mWheelsSimData.getNbWheels()),
+ "vehicleConcurrentUpdates is illegally configured with either null pointers or with insufficient memory for successful concurrent updates.");
+
+ for(PxU32 j=0; j < vehWheels->mWheelsSimData.mNbActiveAntiRollBars; j++)
+ {
+ const PxVehicleAntiRollBarData antiRoll = vehWheels->mWheelsSimData.getAntiRollBarData(j);
+ PX_CHECK_AND_RETURN(!vehWheels->mWheelsSimData.getIsWheelDisabled(antiRoll.mWheel0), "Wheel0 of antiroll bar is disabled. This is not supported.");
+ PX_CHECK_AND_RETURN(!vehWheels->mWheelsSimData.getIsWheelDisabled(antiRoll.mWheel1), "Wheel1 of antiroll bar is disabled. This is not supported.");
+ }
+ }
+#endif
+
+#if PX_DEBUG_VEHICLE_ON
+ gCarEngineGraphData=NULL;
+ for(PxU32 j=0;j<PX_MAX_NB_WHEELS;j++)
+ {
+ gCarWheelGraphData[j]=NULL;
+ }
+ gCarSuspForceAppPoints=NULL;
+ gCarTireForceAppPoints=NULL;
+#endif
+
+ const PxF32 gravityMagnitude=gravity.magnitude();
+ const PxF32 recipGravityMagnitude=1.0f/gravityMagnitude;
+
+ for(PxU32 i=0;i<numVehicles;i++)
+ {
+ PxVehicleWheels* vehWheels=vehicles[i];
+ PxVehicleWheelQueryResult* vehWheelQueryResults = vehicleWheelQueryResults ? &vehicleWheelQueryResults[i] : NULL;
+ PxVehicleConcurrentUpdateData* vehConcurrentUpdateData = vehicleConcurrentUpdates ? &vehicleConcurrentUpdates[i] : NULL;
+ switch(vehWheels->mType)
+ {
+ case PxVehicleTypes::eDRIVE4W:
+ {
+ PxVehicleDrive4W* vehDrive4W=static_cast<PxVehicleDrive4W*>(vehWheels);
+
+ PxVehicleUpdate::updateDrive4W(
+ timestep,
+ gravity,gravityMagnitude,recipGravityMagnitude,
+ vehicleDrivableSurfaceToTireFrictionPairs,
+ vehDrive4W, vehWheelQueryResults, vehConcurrentUpdateData);
+ }
+ break;
+
+ case PxVehicleTypes::eDRIVENW:
+ {
+ PxVehicleDriveNW* vehDriveNW=static_cast<PxVehicleDriveNW*>(vehWheels);
+
+ PxVehicleUpdate::updateDriveNW(
+ timestep,
+ gravity,gravityMagnitude,recipGravityMagnitude,
+ vehicleDrivableSurfaceToTireFrictionPairs,
+ vehDriveNW, vehWheelQueryResults, vehConcurrentUpdateData);
+ }
+ break;
+
+ case PxVehicleTypes::eDRIVETANK:
+ {
+ PxVehicleDriveTank* vehDriveTank=static_cast<PxVehicleDriveTank*>(vehWheels);
+
+ PxVehicleUpdate::updateTank(
+ timestep,
+ gravity,gravityMagnitude,recipGravityMagnitude,
+ vehicleDrivableSurfaceToTireFrictionPairs,
+ vehDriveTank, vehWheelQueryResults, vehConcurrentUpdateData);
+ }
+ break;
+
+ case PxVehicleTypes::eNODRIVE:
+ {
+ PxVehicleNoDrive* vehDriveNoDrive=static_cast<PxVehicleNoDrive*>(vehWheels);
+
+ PxVehicleUpdate::updateNoDrive(
+ timestep,
+ gravity,gravityMagnitude,recipGravityMagnitude,
+ vehicleDrivableSurfaceToTireFrictionPairs,
+ vehDriveNoDrive, vehWheelQueryResults, vehConcurrentUpdateData);
+ }
+ break;
+
+ default:
+ PX_CHECK_MSG(false, "update - unsupported vehicle type");
+ break;
+ }
+ }
+}
+
+
+void PxVehicleUpdate::updatePost
+(const PxVehicleConcurrentUpdateData* vehicleConcurrentUpdates, const PxU32 numVehicles, PxVehicleWheels** vehicles)
+{
+ PX_CHECK_AND_RETURN(vehicleConcurrentUpdates, "vehicleConcurrentUpdates must be non-null.");
+
+#if PX_CHECKED
+ for(PxU32 i=0;i<numVehicles;i++)
+ {
+ PxVehicleWheels* vehWheels=vehicles[i];
+ for(PxU32 j=0;j<vehWheels->mWheelsSimData.mNbActiveWheels;j++)
+ {
+ PX_CHECK_AND_RETURN(!vehWheels->mWheelsSimData.getIsWheelDisabled(j) || -1==vehWheels->mWheelsSimData.getWheelShapeMapping(j),
+ "Disabled wheels must not be associated with a PxShape: use setWheelShapeMapping to remove the association");
+
+ PX_CHECK_AND_RETURN(!vehWheels->mWheelsSimData.getIsWheelDisabled(j) || 0==vehWheels->mWheelsDynData.getWheelRotationSpeed(j),
+ "Disabled wheels must have zero rotation speed: use setWheelRotationSpeed to set the wheel to zero rotation speed");
+
+ PX_CHECK_AND_RETURN(vehicleConcurrentUpdates[i].concurrentWheelUpdates && vehicleConcurrentUpdates[i].nbConcurrentWheelUpdates >= vehWheels->mWheelsSimData.getNbWheels(),
+ "vehicleConcurrentUpdates is illegally configured with either null pointers or insufficient memory for successful concurrent vehicle updates.");
+ }
+ }
+#endif
+
+ for(PxU32 i=0;i<numVehicles;i++)
+ {
+ //Get the ith vehicle and its actor.
+ PxVehicleWheels* vehWheels=vehicles[i];
+ PxRigidDynamic* vehActor = vehWheels->getRigidDynamicActor();
+
+ //Get the concurrent update data for the ith vehicle.
+ //This contains the data that couldn't get updated concurrently and now must be
+ //set sequentially.
+ const PxVehicleConcurrentUpdateData& vehicleConcurrentUpdate = vehicleConcurrentUpdates[i];
+
+ //Test if the actor is to remain sleeping.
+ //If the actor is to remain sleeping then do nothing.
+ if(!vehicleConcurrentUpdate.staySleeping)
+ {
+ //Wake the vehicle's actor up as required.
+ if(vehicleConcurrentUpdate.wakeup)
+ {
+ vehActor->wakeUp();
+ }
+
+ //Apply momentum changes to vehicle's actor
+ if(!gApplyForces)
+ {
+ vehActor->setLinearVelocity(vehicleConcurrentUpdate.linearMomentumChange, false);
+ vehActor->setAngularVelocity(vehicleConcurrentUpdate.angularMomentumChange, false);
+ }
+ else
+ {
+ vehActor->addForce(vehicleConcurrentUpdate.linearMomentumChange, PxForceMode::eACCELERATION, false);
+ vehActor->addTorque(vehicleConcurrentUpdate.angularMomentumChange, PxForceMode::eACCELERATION, false);
+ }
+
+ //In each block of 4 wheels record how many wheels are active.
+ const PxU32 numActiveWheels=vehWheels->mWheelsSimData.mNbActiveWheels;
+ const PxU32 numWheels4 = vehWheels->mWheelsSimData.getNbWheels4();
+ const PxU32 numActiveWheelsInLast4=4-(4*numWheels4 - numActiveWheels);
+ PxU32 numActiveWheelsPerBlock4[PX_MAX_NB_SUSPWHEELTIRE4]={0,0,0,0,0};
+ numActiveWheelsPerBlock4[0]=PxMin(numActiveWheels,PxU32(4));
+ for(PxU32 j=1;j<numWheels4-1;j++)
+ {
+ numActiveWheelsPerBlock4[j]=4;
+ }
+ numActiveWheelsPerBlock4[numWheels4-1]=numActiveWheelsInLast4;
+ PX_ASSERT(numActiveWheels == numActiveWheelsPerBlock4[0] + numActiveWheelsPerBlock4[1] + numActiveWheelsPerBlock4[2] + numActiveWheelsPerBlock4[3] + numActiveWheelsPerBlock4[4]);
+
+ //Apply the local poses to the shapes of the vehicle's actor that represent wheels.
+ for(PxU32 j=0;j<numWheels4;j++)
+ {
+ PxTransform localPoses[4]=
+ {
+ vehicleConcurrentUpdate.concurrentWheelUpdates[j*4 + 0].localPose,
+ vehicleConcurrentUpdate.concurrentWheelUpdates[j*4 + 1].localPose,
+ vehicleConcurrentUpdate.concurrentWheelUpdates[j*4 + 2].localPose,
+ vehicleConcurrentUpdate.concurrentWheelUpdates[j*4 + 3].localPose
+ };
+ poseWheels(vehWheels->mWheelsSimData.mWheels4SimData[j],localPoses,numActiveWheelsPerBlock4[j],vehActor);
+ }
+
+ //Apply forces to dynamic actors hit by the wheels.
+ for(PxU32 j=0;j<numActiveWheels;j++)
+ {
+ PxRigidDynamic* hitActor=vehicleConcurrentUpdate.concurrentWheelUpdates[j].hitActor;
+ if(hitActor)
+ {
+ const PxVec3& hitForce=vehicleConcurrentUpdate.concurrentWheelUpdates[j].hitActorForce;
+ const PxVec3& hitForcePosition=vehicleConcurrentUpdate.concurrentWheelUpdates[j].hitActorForcePosition;
+ PxRigidBodyExt::addForceAtPos(*hitActor,hitForce,hitForcePosition);
+ }
+ }
+ }
+ }
+}
+
+
+void physx::PxVehicleUpdates
+(const PxReal timestep, const PxVec3& gravity, const PxVehicleDrivableSurfaceToTireFrictionPairs& vehicleDrivableSurfaceToTireFrictionPairs,
+ const PxU32 numVehicles, PxVehicleWheels** vehicles, PxVehicleWheelQueryResult* vehicleWheelQueryResults, PxVehicleConcurrentUpdateData* vehicleConcurrentUpdates)
+{
+ PX_PROFILE_ZONE("PxVehicleUpdates::ePROFILE_UPDATES",0);
+ PxVehicleUpdate::update(timestep, gravity, vehicleDrivableSurfaceToTireFrictionPairs, numVehicles, vehicles, vehicleWheelQueryResults, vehicleConcurrentUpdates);
+}
+
+void physx::PxVehiclePostUpdates
+(const PxVehicleConcurrentUpdateData* vehicleConcurrentUpdates, const PxU32 numVehicles, PxVehicleWheels** vehicles)
+{
+ PX_PROFILE_ZONE("PxVehicleUpdates::ePROFILE_POSTUPDATES",0);
+ PxVehicleUpdate::updatePost(vehicleConcurrentUpdates, numVehicles, vehicles);
+}
+
+void physx::PxVehicleShiftOrigin(const PxVec3& shift, const PxU32 numVehicles, PxVehicleWheels** vehicles)
+{
+ PxVehicleUpdate::shiftOrigin(shift, numVehicles, vehicles);
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+//The following functions issue a single batch of suspension raycasts for an array of vehicles of any type.
+//The buffer of sceneQueryResults is distributed among the vehicles in the array
+//for use in the next PxVehicleUpdates call.
+///////////////////////////////////////////////////////////////////////////////////
+
+void PxVehicleWheels4SuspensionRaycasts
+(PxBatchQuery* batchQuery,
+ const PxVehicleWheels4SimData& wheels4SimData, PxVehicleWheels4DynData& wheels4DynData,
+ const PxQueryFilterData* carFilterData, const bool* activeWheelStates, const PxU32 numActiveWheels,
+ PxRigidDynamic* vehActor)
+{
+ //Get the transform of the chassis.
+ PxTransform carChassisTrnsfm=vehActor->getGlobalPose().transform(vehActor->getCMassLocalPose());
+
+ //Add a raycast for each wheel.
+ for(PxU32 j=0;j<numActiveWheels;j++)
+ {
+ const PxVehicleSuspensionData& susp=wheels4SimData.getSuspensionData(j);
+ const PxVehicleWheelData& wheel=wheels4SimData.getWheelData(j);
+
+ const PxVec3& bodySpaceSuspTravelDir=wheels4SimData.getSuspTravelDirection(j);
+ PxVec3 bodySpaceWheelCentreOffset=wheels4SimData.getWheelCentreOffset(j);
+ PxF32 maxDroop=susp.mMaxDroop;
+ PxF32 maxBounce=susp.mMaxCompression;
+ PxF32 radius=wheel.mRadius;
+ PX_ASSERT(maxBounce>=0);
+ PX_ASSERT(maxDroop>=0);
+
+ if(!activeWheelStates[j])
+ {
+ //For disabled wheels just issue a raycast of almost zero length.
+ //This should be very cheap and ought to hit nothing.
+ bodySpaceWheelCentreOffset=PxVec3(0,0,0);
+ maxDroop=1e-5f*gToleranceScaleLength;
+ maxBounce=1e-5f*gToleranceScaleLength;
+ radius=1e-5f*gToleranceScaleLength;
+ }
+
+ PxVec3 suspLineStart;
+ PxVec3 suspLineDir;
+ computeSuspensionRaycast(carChassisTrnsfm,bodySpaceWheelCentreOffset,bodySpaceSuspTravelDir,radius,maxBounce,suspLineStart,suspLineDir);
+
+ //Total length from top of wheel at max compression to bottom of wheel at max droop.
+ PxF32 suspLineLength=radius + maxBounce + maxDroop + radius;
+ //Add another radius on for good measure.
+ suspLineLength+=radius;
+
+ //Store the susp line ray for later use.
+ PxVehicleWheels4DynData::SuspLineRaycast& raycast =
+ reinterpret_cast<PxVehicleWheels4DynData::SuspLineRaycast&>(wheels4DynData.mQueryOrCachedHitResults);
+ raycast.mStarts[j]=suspLineStart;
+ raycast.mDirs[j]=suspLineDir;
+ raycast.mLengths[j]=suspLineLength;
+
+ //Add the raycast to the scene query.
+ batchQuery->raycast(
+ suspLineStart, suspLineDir, suspLineLength, 0,
+ PxHitFlag::ePOSITION|PxHitFlag::eNORMAL|PxHitFlag::eDISTANCE|PxHitFlag::eUV, carFilterData[j]);
+ }
+}
+
+void PxVehicleUpdate::suspensionRaycasts(PxBatchQuery* batchQuery, const PxU32 numVehicles, PxVehicleWheels** vehicles, const PxU32 numSceneQueryResults, PxRaycastQueryResult* sceneQueryResults, const bool* vehiclesToRaycast)
+{
+ START_TIMER(TIMER_RAYCASTS);
+
+ //Reset all hit counts to zero.
+ for(PxU32 i=0;i<numSceneQueryResults;i++)
+ {
+ sceneQueryResults[i].hasBlock=false;
+ }
+
+ PxRaycastQueryResult* sqres=sceneQueryResults;
+
+ const PxQueryFlags flags = PxQueryFlag::eSTATIC|PxQueryFlag::eDYNAMIC|PxQueryFlag::ePREFILTER;
+ PxQueryFilterData carFilterData[4];
+ carFilterData[0].flags=flags;
+ carFilterData[1].flags=flags;
+ carFilterData[2].flags=flags;
+ carFilterData[3].flags=flags;
+
+ //Work out the rays for the suspension line raycasts and perform all the raycasts.
+ for(PxU32 i=0;i<numVehicles;i++)
+ {
+ //Get the current car.
+ PxVehicleWheels& veh=*vehicles[i];
+ const PxVehicleWheels4SimData* PX_RESTRICT wheels4SimData=veh.mWheelsSimData.mWheels4SimData;
+ PxVehicleWheels4DynData* PX_RESTRICT wheels4DynData=veh.mWheelsDynData.mWheels4DynData;
+ const PxU32 numWheels4=((veh.mWheelsSimData.mNbActiveWheels & ~3) >> 2);
+ const PxU32 numActiveWheels=veh.mWheelsSimData.mNbActiveWheels;
+ const PxU32 numActiveWheelsInLast4=numActiveWheels-4*numWheels4;
+ PxRigidDynamic* vehActor=veh.mActor;
+
+ //Set the results pointer and start the raycasts.
+ PX_ASSERT(numActiveWheelsInLast4<4);
+
+ //Blocks of 4 wheels.
+ for(PxU32 j=0;j<numWheels4;j++)
+ {
+ bool activeWheelStates[4]={false,false,false,false};
+ computeWheelActiveStates(4*j, veh.mWheelsSimData.mActiveWheelsBitmapBuffer, activeWheelStates);
+
+ wheels4DynData[j].mRaycastResults=NULL;
+ wheels4DynData[j].mSweepResults=NULL;
+
+ if(NULL==vehiclesToRaycast || vehiclesToRaycast[i])
+ {
+ if((sceneQueryResults + numSceneQueryResults) >= (sqres+4))
+ {
+ carFilterData[0].data=wheels4SimData[j].getSceneQueryFilterData(0);
+ carFilterData[1].data=wheels4SimData[j].getSceneQueryFilterData(1);
+ carFilterData[2].data=wheels4SimData[j].getSceneQueryFilterData(2);
+ carFilterData[3].data=wheels4SimData[j].getSceneQueryFilterData(3);
+ wheels4DynData[j].mRaycastResults=sqres;
+ PxVehicleWheels4SuspensionRaycasts(batchQuery,wheels4SimData[j],wheels4DynData[j],carFilterData,activeWheelStates,4,vehActor);
+ }
+ else
+ {
+ PX_CHECK_MSG(false, "PxVehicleUpdate::suspensionRaycasts - numSceneQueryResults not big enough to support one raycast hit report per wheel. Increase size of sceneQueryResults");
+ }
+ sqres+=4;
+ }
+ }
+ //Remainder that don't make up a block of 4.
+ if(numActiveWheelsInLast4>0)
+ {
+ const PxU32 j=numWheels4;
+
+ bool activeWheelStates[4]={false,false,false,false};
+ computeWheelActiveStates(4*j, veh.mWheelsSimData.mActiveWheelsBitmapBuffer, activeWheelStates);
+
+ wheels4DynData[j].mRaycastResults=NULL;
+ wheels4DynData[j].mSweepResults=NULL;
+
+ if(NULL==vehiclesToRaycast || vehiclesToRaycast[i])
+ {
+ if((sceneQueryResults + numSceneQueryResults) >= (sqres+numActiveWheelsInLast4))
+ {
+ if(0<numActiveWheelsInLast4) carFilterData[0].data=wheels4SimData[j].getSceneQueryFilterData(0);
+ if(1<numActiveWheelsInLast4) carFilterData[1].data=wheels4SimData[j].getSceneQueryFilterData(1);
+ if(2<numActiveWheelsInLast4) carFilterData[2].data=wheels4SimData[j].getSceneQueryFilterData(2);
+ wheels4DynData[j].mRaycastResults=sqres;
+ PxVehicleWheels4SuspensionRaycasts(batchQuery,wheels4SimData[j],wheels4DynData[j],carFilterData,activeWheelStates,numActiveWheelsInLast4,vehActor);
+ }
+ else
+ {
+ PX_CHECK_MSG(false, "PxVehicleUpdate::suspensionRaycasts - numSceneQueryResults not bit enough to support one raycast hit report per wheel. Increase size of sceneQueryResults");
+ }
+ sqres+=numActiveWheelsInLast4;
+ }
+ }
+ }
+
+ batchQuery->execute();
+
+ END_TIMER(TIMER_RAYCASTS);
+}
+
+void physx::PxVehicleSuspensionRaycasts(PxBatchQuery* batchQuery, const PxU32 numVehicles, PxVehicleWheels** vehicles, const PxU32 numSceneQueryesults, PxRaycastQueryResult* sceneQueryResults, const bool* vehiclesToRaycast)
+{
+ PX_PROFILE_ZONE("PxVehicleSuspensionRaycasts::ePROFILE_RAYCASTS",0);
+ PxVehicleUpdate::suspensionRaycasts(batchQuery, numVehicles, vehicles, numSceneQueryesults, sceneQueryResults, vehiclesToRaycast);
+}
+
+
+void PxVehicleWheels4SuspensionSweeps
+(PxBatchQuery* batchQuery,
+ const PxVehicleWheels4SimData& wheels4SimData, PxVehicleWheels4DynData& wheels4DynData,
+ const PxQueryFilterData* carFilterData, const bool* activeWheelStates, const PxU32 numActiveWheels,
+ const PxU16 nbHitsPerQuery,
+ const PxI32* wheelShapeIds,
+ PxRigidDynamic* vehActor,
+ const PxF32 sweepWidthScale, const PxF32 sweepRadiusScale)
+{
+ PX_UNUSED(sweepWidthScale);
+ PX_UNUSED(sweepRadiusScale);
+
+ //Get the transform of the chassis.
+ PxTransform carChassisTrnsfm=vehActor->getGlobalPose().transform(vehActor->getCMassLocalPose());
+
+ //Add a raycast for each wheel.
+ for(PxU32 j=0;j<numActiveWheels;j++)
+ {
+ const PxVehicleSuspensionData& susp = wheels4SimData.getSuspensionData(j);
+ const PxVehicleWheelData& wheel = wheels4SimData.getWheelData(j);
+
+ PxShape* wheelShape;
+ vehActor->getShapes(&wheelShape, 1, PxU32(wheelShapeIds[j]));
+
+ PxGeometryHolder suspGeometry;
+ if (PxGeometryType::eCONVEXMESH == wheelShape->getGeometryType())
+ {
+ PxConvexMeshGeometry convMeshGeom;
+ wheelShape->getConvexMeshGeometry(convMeshGeom);
+ convMeshGeom.scale.scale =
+ PxVec3(
+ gRight.x*sweepWidthScale + (gUp.x + gForward.x)*sweepRadiusScale,
+ gRight.y*sweepWidthScale + (gUp.y + gForward.y)*sweepRadiusScale,
+ gRight.z*sweepWidthScale + (gUp.z + gForward.z)*sweepRadiusScale);
+ suspGeometry.storeAny(convMeshGeom);
+ }
+ else if (PxGeometryType::eCAPSULE == wheelShape->getGeometryType())
+ {
+ PxCapsuleGeometry capsuleGeom;
+ wheelShape->getCapsuleGeometry(capsuleGeom);
+ capsuleGeom.halfHeight *= sweepWidthScale;
+ capsuleGeom.radius *= sweepRadiusScale;
+ suspGeometry.storeAny(capsuleGeom);
+ }
+ else
+ {
+ PX_ASSERT(PxGeometryType::eSPHERE == wheelShape->getGeometryType());
+ PxSphereGeometry sphereGeom;
+ wheelShape->getSphereGeometry(sphereGeom);
+ sphereGeom.radius *= sweepRadiusScale;
+ suspGeometry.storeAny(sphereGeom);
+ }
+
+ const PxQuat wheelLocalPoseRotation = wheelShape->getLocalPose().q;
+ const PxF32 wheelTheta = wheels4DynData.mWheelRotationAngles[j];
+
+ const PxVec3& bodySpaceSuspTravelDir = wheels4SimData.getSuspTravelDirection(j);
+ PxVec3 bodySpaceWheelCentreOffset = wheels4SimData.getWheelCentreOffset(j);
+ PxF32 maxDroop = susp.mMaxDroop;
+ PxF32 maxBounce = susp.mMaxCompression;
+ PxF32 radius = wheel.mRadius;
+ PX_ASSERT(maxBounce >= 0);
+ PX_ASSERT(maxDroop >= 0);
+
+ if(!activeWheelStates[j])
+ {
+ //For disabled wheels just issue a raycast of almost zero length.
+ //This should be very cheap and ought to hit nothing.
+ bodySpaceWheelCentreOffset = PxVec3(0,0,0);
+ maxDroop = 1e-5f*gToleranceScaleLength;
+ maxBounce = 1e-5f*gToleranceScaleLength;
+ radius = 1e-5f*gToleranceScaleLength;
+ }
+
+ PxTransform suspPoseStart;
+ PxVec3 suspLineDir;
+ computeSuspensionSweep(
+ carChassisTrnsfm,
+ wheelLocalPoseRotation, wheelTheta,
+ bodySpaceWheelCentreOffset, bodySpaceSuspTravelDir, radius, maxBounce,
+ suspPoseStart, suspLineDir);
+ const PxF32 suspLineLength = radius + maxBounce + maxDroop + radius;
+
+ //Store the susp line ray for later use.
+ PxVehicleWheels4DynData::SuspLineSweep& sweep =
+ reinterpret_cast<PxVehicleWheels4DynData::SuspLineSweep&>(wheels4DynData.mQueryOrCachedHitResults);
+ sweep.mStartPose[j] = suspPoseStart;
+ sweep.mDirs[j] = suspLineDir;
+ sweep.mLengths[j] = suspLineLength;
+ sweep.mGometries[j] = suspGeometry;
+
+ //Add the raycast to the scene query.
+ batchQuery->sweep(sweep.mGometries[j].any(),
+ suspPoseStart, suspLineDir, suspLineLength, nbHitsPerQuery,
+ PxHitFlag::ePOSITION|PxHitFlag::eNORMAL|PxHitFlag::eDISTANCE|PxHitFlag::eUV,
+ carFilterData[j]);
+ }
+}
+
+
+void PxVehicleUpdate::suspensionSweeps
+(PxBatchQuery* batchQuery,
+ const PxU32 numVehicles, PxVehicleWheels** vehicles,
+ const PxU32 numSceneQueryResults, PxSweepQueryResult* sceneQueryResults, const PxU16 nbHitsPerQuery,
+ const bool* vehiclesToSweep,
+ const PxF32 sweepWidthScale, const PxF32 sweepRadiusScale)
+{
+ PX_CHECK_MSG(sweepWidthScale > 0.0f, "PxVehicleUpdate::suspensionSweeps - sweepWidthScale must be greater than 0.0");
+ PX_CHECK_MSG(sweepRadiusScale > 0.0f, "PxVehicleUpdate::suspensionSweeps - sweepRadiusScale must be greater than 0.0");
+
+ START_TIMER(TIMER_SWEEPS);
+
+ //Reset all hit counts to zero.
+ for(PxU32 i=0;i<numSceneQueryResults;i++)
+ {
+ sceneQueryResults[i].hasBlock=false;
+ }
+
+ PxSweepQueryResult* sqres=sceneQueryResults;
+
+ const PxQueryFlags flags = PxQueryFlag::eSTATIC|PxQueryFlag::eDYNAMIC|PxQueryFlag::ePREFILTER|PxQueryFlag::ePOSTFILTER;
+ PxQueryFilterData carFilterData[4];
+ carFilterData[0].flags=flags;
+ carFilterData[1].flags=flags;
+ carFilterData[2].flags=flags;
+ carFilterData[3].flags=flags;
+
+ //Work out the rays for the suspension line raycasts and perform all the raycasts.
+ for(PxU32 i=0;i<numVehicles;i++)
+ {
+ //Get the current car.
+ PxVehicleWheels& veh=*vehicles[i];
+ const PxVehicleWheels4SimData* PX_RESTRICT wheels4SimData=veh.mWheelsSimData.mWheels4SimData;
+ PxVehicleWheels4DynData* PX_RESTRICT wheels4DynData=veh.mWheelsDynData.mWheels4DynData;
+ const PxU32 numWheels4=((veh.mWheelsSimData.mNbActiveWheels & ~3) >> 2);
+ const PxU32 numActiveWheels=veh.mWheelsSimData.mNbActiveWheels;
+ const PxU32 numActiveWheelsInLast4=numActiveWheels-4*numWheels4;
+ PxRigidDynamic* vehActor=veh.mActor;
+
+ //Set the results pointer and start the raycasts.
+ PX_ASSERT(numActiveWheelsInLast4<4);
+
+ //Get the shape ids for the wheels.
+ PxI32 wheelShapeIds[PX_MAX_NB_WHEELS];
+ PxMemSet(wheelShapeIds, 0xff, sizeof(PxI32)*PX_MAX_NB_WHEELS);
+ for(PxU32 j = 0; j < veh.mWheelsSimData.getNbWheels(); j++)
+ {
+ PX_CHECK_AND_RETURN(veh.mWheelsSimData.getWheelShapeMapping(j) != -1, "PxVehicleUpdate::suspensionSweeps - trying to sweep a shape that doesn't exist.");
+ wheelShapeIds[j] = veh.mWheelsSimData.getWheelShapeMapping(j);
+ }
+
+ //Blocks of 4 wheels.
+ for(PxU32 j=0;j<numWheels4;j++)
+ {
+ bool activeWheelStates[4]={false,false,false,false};
+ computeWheelActiveStates(4*j, veh.mWheelsSimData.mActiveWheelsBitmapBuffer, activeWheelStates);
+
+ const PxI32* wheelShapeIds4 = wheelShapeIds + 4*j;
+
+ wheels4DynData[j].mRaycastResults=NULL;
+ wheels4DynData[j].mSweepResults=NULL;
+
+ if(NULL==vehiclesToSweep || vehiclesToSweep[i])
+ {
+ if((sceneQueryResults + numSceneQueryResults) >= (sqres+4))
+ {
+ carFilterData[0].data=wheels4SimData[j].getSceneQueryFilterData(0);
+ carFilterData[1].data=wheels4SimData[j].getSceneQueryFilterData(1);
+ carFilterData[2].data=wheels4SimData[j].getSceneQueryFilterData(2);
+ carFilterData[3].data=wheels4SimData[j].getSceneQueryFilterData(3);
+ wheels4DynData[j].mSweepResults=sqres;
+ PxVehicleWheels4SuspensionSweeps(
+ batchQuery,
+ wheels4SimData[j], wheels4DynData[j],
+ carFilterData, activeWheelStates, 4,
+ nbHitsPerQuery,
+ wheelShapeIds4,
+ vehActor,
+ sweepWidthScale, sweepRadiusScale);
+ }
+ else
+ {
+ PX_CHECK_MSG(false, "PxVehicleUpdate::suspensionRaycasts - numSceneQueryResults not big enough to support one raycast hit report per wheel. Increase size of sceneQueryResults");
+ }
+ sqres+=4;
+ }
+ }
+ //Remainder that don't make up a block of 4.
+ if(numActiveWheelsInLast4>0)
+ {
+ const PxU32 j=numWheels4;
+
+ bool activeWheelStates[4]={false,false,false,false};
+ computeWheelActiveStates(4*j, veh.mWheelsSimData.mActiveWheelsBitmapBuffer, activeWheelStates);
+
+ const PxI32* wheelShapeIds4 = wheelShapeIds + 4*j;
+
+ wheels4DynData[j].mRaycastResults=NULL;
+ wheels4DynData[j].mSweepResults=NULL;
+
+ if(NULL==vehiclesToSweep || vehiclesToSweep[i])
+ {
+ if((sceneQueryResults + numSceneQueryResults) >= (sqres+numActiveWheelsInLast4))
+ {
+ if(0<numActiveWheelsInLast4) carFilterData[0].data=wheels4SimData[j].getSceneQueryFilterData(0);
+ if(1<numActiveWheelsInLast4) carFilterData[1].data=wheels4SimData[j].getSceneQueryFilterData(1);
+ if(2<numActiveWheelsInLast4) carFilterData[2].data=wheels4SimData[j].getSceneQueryFilterData(2);
+ wheels4DynData[j].mRaycastResults=NULL;
+ wheels4DynData[j].mSweepResults=sqres;
+ PxVehicleWheels4SuspensionSweeps(
+ batchQuery,
+ wheels4SimData[j], wheels4DynData[j],
+ carFilterData, activeWheelStates, numActiveWheelsInLast4,
+ nbHitsPerQuery,
+ wheelShapeIds4,
+ vehActor,
+ sweepWidthScale, sweepRadiusScale);
+ }
+ else
+ {
+ PX_CHECK_MSG(false, "PxVehicleUpdate::suspensionSweeps - numSceneQueryResults not bit enough to support one sweep hit report per wheel. Increase size of sceneQueryResults");
+ }
+ sqres+=numActiveWheelsInLast4;
+ }
+ }
+ }
+
+ batchQuery->execute();
+
+ END_TIMER(TIMER_SWEEPS);
+}
+
+namespace physx
+{
+ void PxVehicleSuspensionSweeps
+ (PxBatchQuery* batchQuery,
+ const PxU32 nbVehicles, PxVehicleWheels** vehicles,
+ const PxU32 nbSceneQueryResults, PxSweepQueryResult* sceneQueryResults, const PxU16 nbHitsPerQuery,
+ const bool* vehiclesToSweep,
+ const PxF32 sweepWidthScale, const PxF32 sweepRadiusScale)
+ {
+ PX_PROFILE_ZONE("PxVehicleSuspensionSweeps::ePROFILE_SWEEPS",0);
+ PxVehicleUpdate::suspensionSweeps(
+ batchQuery, nbVehicles, vehicles, nbSceneQueryResults, sceneQueryResults, nbHitsPerQuery, vehiclesToSweep, sweepWidthScale, sweepRadiusScale);
+ }
+}
+
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleWheels.cpp b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleWheels.cpp
new file mode 100644
index 00000000..cb731d1a
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/PxVehicleWheels.cpp
@@ -0,0 +1,857 @@
+// 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 "PxVehicleWheels.h"
+#include "PxVehicleSuspWheelTire4.h"
+#include "PxVehicleSuspLimitConstraintShader.h"
+#include "PxVehicleDefaults.h"
+#include "PxRigidDynamic.h"
+#include "PxShape.h"
+#include "PsUtilities.h"
+#include "CmPhysXCommon.h"
+#include "CmBitMap.h"
+#include "PxPhysics.h"
+#include "PsIntrinsics.h"
+#include "PsFoundation.h"
+
+namespace physx
+{
+
+extern PxVec3 gRight;
+extern PxVec3 gUp;
+extern PxVec3 gForward;
+
+PxF32 gThresholdLongSpeed=5.0f;
+PxU32 gLowLongSpeedSubstepCount=3;
+PxU32 gHighLongSpeedSubstepCount=1;
+PxF32 gMinLongSlipDenominator=4.0f;
+
+extern PxF32 gToleranceScaleLength;
+
+
+PxU32 PxVehicleWheelsSimData::computeByteSize(const PxU32 numWheels)
+{
+ const PxU32 numWheels4 =(((numWheels + 3) & ~3) >> 2);
+ const PxU32 byteSize = sizeof(PxVehicleWheels4SimData)*numWheels4 + sizeof(PxVehicleAntiRollBarData)*2*numWheels4;
+ return byteSize;
+}
+
+PxU8* PxVehicleWheelsSimData::patchUpPointers(const PxU32 numWheels, PxVehicleWheelsSimData* simData, PxU8* ptrIn)
+{
+ const PxU32 numWheels4 =(((numWheels + 3) & ~3) >> 2);
+ PxU8* ptr = ptrIn;
+ simData->mWheels4SimData = reinterpret_cast<PxVehicleWheels4SimData*>(ptr);
+ ptr += sizeof(PxVehicleWheels4SimData)*numWheels4;
+ simData->mAntiRollBars = reinterpret_cast<PxVehicleAntiRollBarData*>(ptr);
+ ptr += sizeof(PxVehicleAntiRollBarData)*numWheels4*2;
+ PX_ASSERT((ptrIn + computeByteSize(numWheels)) == ptr);
+ return ptr;
+}
+
+PxVehicleWheelsSimData::PxVehicleWheelsSimData(const PxU32 numWheels)
+{
+ const PxU32 numWheels4 =(((numWheels + 3) & ~3) >> 2);
+
+ //Set numWheels
+ mNbWheels4 = numWheels4;
+ mNbActiveWheels = numWheels;
+
+ //Set numAntiRollBars to zero.
+ mNbAntiRollBars4 = 2*numWheels4;
+ mNbActiveAntiRollBars = 0;
+
+ //Placement new for wheels4
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ new(&mWheels4SimData[i]) PxVehicleWheels4SimData();
+ }
+
+ //Placement new for anti-roll bars
+ for(PxU32 i=0;i<numWheels4*2;i++)
+ {
+ new(&mAntiRollBars[i]) PxVehicleAntiRollBarData();
+ }
+
+ //Placement new for tire load filter data.
+ new(&mNormalisedLoadFilter) PxVehicleTireLoadFilterData();
+
+ //Enable used wheels, disabled unused wheels.
+ PxMemZero(mActiveWheelsBitmapBuffer, sizeof(PxU32) * (((PX_MAX_NB_WHEELS + 31) & ~31) >> 5));
+ for(PxU32 i=0;i<numWheels;i++)
+ {
+ //Enabled used wheel.
+ enableWheel(i);
+ setWheelShapeMapping(i,PxI32(i));
+ setSceneQueryFilterData(i, PxFilterData());
+ }
+ for(PxU32 i=numWheels;i<numWheels4*4;i++)
+ {
+ //Disable unused wheel.
+ disableWheel(i);
+ setWheelShapeMapping(i,-1);
+ setSceneQueryFilterData(i, PxFilterData());
+ }
+
+ //Default values for substep count computation.
+ mThresholdLongitudinalSpeed = gThresholdLongSpeed*gToleranceScaleLength;
+ mLowForwardSpeedSubStepCount = gLowLongSpeedSubstepCount;
+ mHighForwardSpeedSubStepCount = gHighLongSpeedSubstepCount;
+ mMinLongSlipDenominator = gMinLongSlipDenominator*gToleranceScaleLength;
+}
+
+PxVehicleWheelsSimData* PxVehicleWheelsSimData::allocate(const PxU32 numWheels)
+{
+ //Byte size
+ const PxU32 byteSize = sizeof(PxVehicleWheelsSimData) + computeByteSize(numWheels);
+
+ //Allocate
+ PxU8* ptrStart = static_cast<PxU8*>(PX_ALLOC(byteSize, "PxVehicleWheelsSimData"));
+
+ //Patchup pointers
+ PxU8* ptr = ptrStart;
+ PxVehicleWheelsSimData* simData = reinterpret_cast<PxVehicleWheelsSimData*>(ptr);
+ ptr += sizeof(PxVehicleWheelsSimData);
+ ptr = patchUpPointers(numWheels, simData, ptr);
+ PX_ASSERT((ptrStart+ byteSize) == ptr);
+
+ //Constructor.
+ new(simData) PxVehicleWheelsSimData(numWheels);
+
+ //Finished.
+ return simData;
+}
+
+void PxVehicleWheelsSimData::setChassisMass(const PxF32 chassisMass)
+{
+
+ //Target spring natural frequency = 9.66
+ //Target spring damping ratio = 0.62
+ const PxF32 mult=1.0f/(1.0f*mNbActiveWheels);
+ const PxF32 sprungMass=chassisMass*mult;
+ const PxF32 w0=9.66f;
+ const PxF32 r=0.62f;
+ for(PxU32 i=0;i<mNbActiveWheels;i++)
+ {
+ PxVehicleSuspensionData susp=getSuspensionData(i);
+ susp.mSprungMass=sprungMass;
+ susp.mSpringStrength=w0*w0*sprungMass;
+ susp.mSpringDamperRate=r*2*sprungMass*w0;
+ setSuspensionData(i,susp);
+ }
+}
+
+void PxVehicleWheelsSimData::free()
+{
+ for(PxU32 i=0;i<mNbWheels4;i++)
+ {
+ mWheels4SimData[i].~PxVehicleWheels4SimData();
+ }
+
+ PX_FREE(this);
+}
+
+PxVehicleWheelsSimData& PxVehicleWheelsSimData::operator=(const PxVehicleWheelsSimData& src)
+{
+ PX_CHECK_MSG(mNbActiveWheels == src.mNbActiveWheels, "target PxVehicleSuspWheelTireNSimData must match the number of wheels in src");
+
+ for(PxU32 i=0;i<src.mNbWheels4;i++)
+ {
+ mWheels4SimData[i] = src.mWheels4SimData[i];
+ }
+
+ mNbActiveAntiRollBars = src.mNbActiveAntiRollBars;
+ for(PxU32 i=0; i<src.mNbActiveAntiRollBars; i++)
+ {
+ mAntiRollBars[i] = src.mAntiRollBars[i];
+ }
+
+ mNormalisedLoadFilter = src.mNormalisedLoadFilter;
+
+ mThresholdLongitudinalSpeed = src.mThresholdLongitudinalSpeed;
+ mLowForwardSpeedSubStepCount = src.mLowForwardSpeedSubStepCount;
+ mHighForwardSpeedSubStepCount = src.mHighForwardSpeedSubStepCount;
+ mMinLongSlipDenominator = src.mMinLongSlipDenominator;
+
+ PxMemCopy(mActiveWheelsBitmapBuffer, src.mActiveWheelsBitmapBuffer, sizeof(PxU32)* (((PX_MAX_NB_WHEELS + 31) & ~31) >> 5));
+
+ return *this;
+}
+
+void PxVehicleWheelsSimData::copy(const PxVehicleWheelsSimData& src, const PxU32 srcWheel, const PxU32 wheel)
+{
+ PX_CHECK_AND_RETURN(srcWheel < src.mNbActiveWheels, "Illegal src wheel");
+ PX_CHECK_AND_RETURN(wheel < mNbActiveWheels, "Illegal target wheel");
+
+ setSuspensionData(wheel,src.getSuspensionData(srcWheel));
+ setWheelData(wheel,src.getWheelData(srcWheel));
+ setTireData(wheel,src.getTireData(srcWheel));
+ setSuspTravelDirection(wheel,src.getSuspTravelDirection(srcWheel));
+ setSuspForceAppPointOffset(wheel,src.getSuspForceAppPointOffset(srcWheel));
+ setTireForceAppPointOffset(wheel,src.getTireForceAppPointOffset(srcWheel));
+ setWheelCentreOffset(wheel,src.getWheelCentreOffset(srcWheel));
+ setWheelShapeMapping(wheel, src.getWheelShapeMapping(srcWheel));
+ setSceneQueryFilterData(wheel, src.getSceneQueryFilterData(srcWheel));
+ if(src.getIsWheelDisabled(srcWheel))
+ disableWheel(wheel);
+ else
+ enableWheel(wheel);
+}
+
+bool PxVehicleWheelsSimData::isValid() const
+{
+ for(PxU32 i=0;i<mNbWheels4-1;i++)
+ {
+ mWheels4SimData[i].isValid(0);
+ mWheels4SimData[i].isValid(1);
+ mWheels4SimData[i].isValid(2);
+ mWheels4SimData[i].isValid(3);
+ }
+ const PxU32 numInLastBlock = 4 - (4*mNbWheels4 - mNbActiveWheels);
+ for(PxU32 i=0;i<numInLastBlock;i++)
+ {
+ mWheels4SimData[mNbWheels4-1].isValid(i);
+ }
+
+ PX_CHECK_AND_RETURN_VAL(mNormalisedLoadFilter.isValid(), "Invalid PxVehicleWheelsSimData.mNormalisedLoadFilter", false);
+ return true;
+}
+
+void PxVehicleWheelsSimData::disableWheel(const PxU32 wheel)
+{
+ PX_CHECK_AND_RETURN(wheel < 4*mNbWheels4, "PxVehicleWheelsSimData::disableWheel - Illegal wheel");
+
+ Cm::BitMap bm;
+ bm.setWords(mActiveWheelsBitmapBuffer, ((PX_MAX_NB_WHEELS + 31) & ~31) >> 5);
+ bm.reset(wheel);
+}
+
+void PxVehicleWheelsSimData::enableWheel(const PxU32 wheel)
+{
+ PX_CHECK_AND_RETURN(wheel < 4*mNbWheels4, "PxVehicleWheelsSimData::disableWheel - Illegal wheel");
+
+ Cm::BitMap bm;
+ bm.setWords(mActiveWheelsBitmapBuffer, ((PX_MAX_NB_WHEELS + 31) & ~31) >> 5);
+ bm.set(wheel);
+}
+
+bool PxVehicleWheelsSimData::getIsWheelDisabled(const PxU32 wheel) const
+{
+ PX_CHECK_AND_RETURN_VAL(wheel < 4*mNbWheels4, "PxVehicleWheelsSimData::getIsWheelDisabled - Illegal wheel", false);
+ Cm::BitMap bm;
+ bm.setWords(const_cast<PxU32*>(mActiveWheelsBitmapBuffer), ((PX_MAX_NB_WHEELS + 31) & ~31) >> 5);
+ return (bm.test(wheel) ? false : true);
+}
+
+const PxVehicleSuspensionData& PxVehicleWheelsSimData::getSuspensionData(const PxU32 id) const
+{
+ PX_CHECK_MSG(id < 4*mNbWheels4, "PxVehicleWheelsSimData::getSuspensionData - Illegal wheel");
+ return mWheels4SimData[id>>2].getSuspensionData(id & 3);
+}
+
+const PxVehicleWheelData& PxVehicleWheelsSimData::getWheelData(const PxU32 id) const
+{
+ PX_CHECK_MSG(id < 4*mNbWheels4, "PxVehicleWheelsSimData::getWheelData - Illegal wheel");
+ return mWheels4SimData[id>>2].getWheelData(id & 3);
+}
+
+const PxVehicleTireData& PxVehicleWheelsSimData::getTireData(const PxU32 id) const
+{
+ PX_CHECK_MSG(id < 4*mNbWheels4, "PxVehicleWheelsSimData::getTireData - Illegal wheel");
+ return mWheels4SimData[id>>2].getTireData(id & 3);
+}
+
+const PxVec3& PxVehicleWheelsSimData::getSuspTravelDirection(const PxU32 id) const
+{
+ PX_CHECK_MSG(id < 4*mNbWheels4, "PxVehicleWheelsSimData::getSuspTravelDirection - Illegal wheel");
+ return mWheels4SimData[id>>2].getSuspTravelDirection(id & 3);
+}
+
+const PxVec3& PxVehicleWheelsSimData::getSuspForceAppPointOffset(const PxU32 id) const
+{
+ PX_CHECK_MSG(id < 4*mNbWheels4, "PxVehicleWheelsSimData::getSuspForceAppPointOffset - Illegal wheel");
+ return mWheels4SimData[id>>2].getSuspForceAppPointOffset(id & 3);
+}
+
+const PxVec3& PxVehicleWheelsSimData::getTireForceAppPointOffset(const PxU32 id) const
+{
+ PX_CHECK_MSG(id < 4*mNbWheels4, "PxVehicleWheelsSimData::getTireForceAppPointOffset - Illegal wheel");
+ return mWheels4SimData[id>>2].getTireForceAppPointOffset(id & 3);
+}
+
+const PxVec3& PxVehicleWheelsSimData::getWheelCentreOffset(const PxU32 id) const
+{
+ PX_CHECK_MSG(id < 4*mNbWheels4, "PxVehicleWheelsSimData::getWheelCentreOffset - Illegal wheel");
+ return mWheels4SimData[id>>2].getWheelCentreOffset(id & 3);
+}
+
+PxI32 PxVehicleWheelsSimData::getWheelShapeMapping(const PxU32 id) const
+{
+ PX_CHECK_MSG(id < 4*mNbWheels4, "PxVehicleWheelsSimData::getWheelShapeMapping - Illegal wheel");
+ return mWheels4SimData[id>>2].getWheelShapeMapping(id & 3);
+}
+
+const PxFilterData& PxVehicleWheelsSimData::getSceneQueryFilterData(const PxU32 id) const
+{
+ PX_CHECK_MSG(id < 4*mNbWheels4, "PxVehicleWheelsSimData::getSceneQueryFilterData - Illegal wheel");
+ return mWheels4SimData[id>>2].getSceneQueryFilterData(id & 3);
+}
+
+const PxVehicleAntiRollBarData& PxVehicleWheelsSimData::getAntiRollBarData(const PxU32 antiRollId) const
+{
+ PX_CHECK_MSG(antiRollId < mNbActiveAntiRollBars, "PxVehicleWheelsSimData::getAntiRollBarData - Illegal anti-roll bar");
+ return mAntiRollBars[antiRollId];
+}
+
+void PxVehicleWheelsSimData::setSuspensionData(const PxU32 id, const PxVehicleSuspensionData& susp)
+{
+ PX_CHECK_AND_RETURN(id < 4*mNbWheels4, "PxVehicleWheelsSimData::setSuspensionData - Illegal wheel");
+ mWheels4SimData[id>>2].setSuspensionData(id & 3, susp);
+}
+
+void PxVehicleWheelsSimData::setWheelData(const PxU32 id, const PxVehicleWheelData& wheel)
+{
+ PX_CHECK_AND_RETURN(id < 4*mNbWheels4, "PxVehicleWheelsSimData::setWheelData - Illegal wheel");
+ mWheels4SimData[id>>2].setWheelData(id & 3, wheel);
+}
+
+void PxVehicleWheelsSimData::setTireData(const PxU32 id, const PxVehicleTireData& tire)
+{
+ PX_CHECK_AND_RETURN(id < 4*mNbWheels4, "PxVehicleWheelsSimData::setTireData - Illegal wheel");
+ mWheels4SimData[id>>2].setTireData(id & 3, tire);
+}
+
+void PxVehicleWheelsSimData::setSuspTravelDirection(const PxU32 id, const PxVec3& dir)
+{
+ PX_CHECK_AND_RETURN(id < 4*mNbWheels4, "PxVehicleWheelsSimData::setSuspTravelDirection - Illegal wheel");
+ mWheels4SimData[id>>2].setSuspTravelDirection(id & 3, dir);
+}
+
+void PxVehicleWheelsSimData::setSuspForceAppPointOffset(const PxU32 id, const PxVec3& offset)
+{
+ PX_CHECK_AND_RETURN(id < 4*mNbWheels4, "PxVehicleWheelsSimData::setSuspForceAppPointOffset - Illegal wheel");
+ mWheels4SimData[id>>2].setSuspForceAppPointOffset(id & 3, offset);
+}
+
+void PxVehicleWheelsSimData::setTireForceAppPointOffset(const PxU32 id, const PxVec3& offset)
+{
+ PX_CHECK_AND_RETURN(id < 4*mNbWheels4, "PxVehicleWheelsSimData::setTireForceAppPointOffset - Illegal wheel");
+ mWheels4SimData[id>>2].setTireForceAppPointOffset(id & 3, offset);
+}
+
+void PxVehicleWheelsSimData::setWheelCentreOffset(const PxU32 id, const PxVec3& offset)
+{
+ PX_CHECK_AND_RETURN(id < 4*mNbWheels4, "PxVehicleWheelsSimData::setWheelCentreOffset - Illegal wheel");
+ mWheels4SimData[id>>2].setWheelCentreOffset(id & 3, offset);
+}
+
+void PxVehicleWheelsSimData::setWheelShapeMapping(const PxU32 id, const PxI32 shapeId)
+{
+ PX_CHECK_AND_RETURN(id < 4*mNbWheels4, "PxVehicleWheelsSimData::setWheelShapeMapping - Illegal wheel");
+ mWheels4SimData[id>>2].setWheelShapeMapping(id & 3, shapeId);
+}
+
+void PxVehicleWheelsSimData::setSceneQueryFilterData(const PxU32 id, const PxFilterData& sqFilterData)
+{
+ PX_CHECK_AND_RETURN(id < 4*mNbWheels4, "PxVehicleWheelsSimData::setSceneQueryFilterData - Illegal wheel");
+ mWheels4SimData[id>>2].setSceneQueryFilterData(id & 3, sqFilterData);
+}
+
+void PxVehicleWheelsSimData::setTireLoadFilterData(const PxVehicleTireLoadFilterData& tireLoadFilter)
+{
+ PX_CHECK_AND_RETURN(tireLoadFilter.mMaxNormalisedLoad>tireLoadFilter.mMinNormalisedLoad, "Illegal graph points");
+ PX_CHECK_AND_RETURN(tireLoadFilter.mMaxFilteredNormalisedLoad>0, "Max filtered load must be greater than zero");
+ mNormalisedLoadFilter=tireLoadFilter;
+ mNormalisedLoadFilter.mDenominator=1.0f/(mNormalisedLoadFilter.mMaxNormalisedLoad-mNormalisedLoadFilter.mMinNormalisedLoad);
+}
+
+PxU32 PxVehicleWheelsSimData::addAntiRollBarData(const PxVehicleAntiRollBarData& antiRollBar)
+{
+ PX_CHECK_AND_RETURN_VAL(antiRollBar.isValid(), "Illegal antiRollBar", 0xffffffff)
+ PX_CHECK_AND_RETURN_VAL(antiRollBar.mWheel0 < mNbActiveWheels, "Illegal wheel0", 0xffffffff);
+ PX_CHECK_AND_RETURN_VAL(antiRollBar.mWheel1 < mNbActiveWheels, "Illegal wheel1", 0xffffffff);
+
+ //If the anti-roll pair already exists then modify it.
+ for(PxU32 i = 0; i < mNbActiveAntiRollBars; i++)
+ {
+ if( ((mAntiRollBars[i].mWheel0 == antiRollBar.mWheel0) && (mAntiRollBars[i].mWheel1 == antiRollBar.mWheel1)) ||
+ ((mAntiRollBars[i].mWheel1 == antiRollBar.mWheel0) && (mAntiRollBars[i].mWheel0 == antiRollBar.mWheel1)) )
+ {
+ mAntiRollBars[i].mStiffness = antiRollBar.mStiffness;
+ return i;
+ }
+ }
+
+ //Check we have space for an extra anti-roll bar.
+ PX_CHECK_AND_RETURN_VAL(mNbActiveAntiRollBars < 2*mNbWheels4, "The buffer of anti-roll bars is full", 0xffffffff);
+
+ //Add a new anti-roll bar.
+ const PxU32 id = mNbActiveAntiRollBars;
+ mAntiRollBars[mNbActiveAntiRollBars] = antiRollBar;
+ mNbActiveAntiRollBars++;
+
+ //Finished.
+ return id;
+}
+
+//Only used for serialization.
+void PxVehicleWheelsSimData::setAntiRollBarData(const PxU32 id, const PxVehicleAntiRollBarData& antiRoll)
+{
+ PX_UNUSED(id);
+ addAntiRollBarData(antiRoll);
+}
+
+void PxVehicleWheelsSimData::setSubStepCount(const PxReal thresholdLongitudinalSpeed, const PxU32 lowForwardSpeedSubStepCount, const PxU32 highForwardSpeedSubStepCount)
+{
+ PX_CHECK_AND_RETURN(thresholdLongitudinalSpeed>=0, "thresholdLongitudinalSpeed must be greater than or equal to zero.");
+ PX_CHECK_AND_RETURN(lowForwardSpeedSubStepCount>0, "lowForwardSpeedSubStepCount must be greater than zero.");
+ PX_CHECK_AND_RETURN(highForwardSpeedSubStepCount>0, "highForwardSpeedSubStepCount must be greater than zero.");
+
+ mThresholdLongitudinalSpeed=thresholdLongitudinalSpeed;
+ mLowForwardSpeedSubStepCount=lowForwardSpeedSubStepCount;
+ mHighForwardSpeedSubStepCount=highForwardSpeedSubStepCount;
+}
+
+void PxVehicleWheelsSimData::setMinLongSlipDenominator(const PxReal minLongSlipDenominator)
+{
+ PX_CHECK_AND_RETURN(minLongSlipDenominator>0, "minLongSlipDenominator must be greater than or equal to zero.");
+ mMinLongSlipDenominator=minLongSlipDenominator;
+}
+
+
+
+/////////////////////////////
+
+PxU32 PxVehicleWheelsDynData::computeByteSize(const PxU32 numWheels)
+{
+ const PxU32 numWheels4 =(((numWheels + 3) & ~3) >> 2);
+ const PxU32 byteSize =
+ sizeof(PxVehicleWheels4DynData)*numWheels4 +
+ sizeof(PxVehicleTireForceCalculator) + sizeof(void*)*4*numWheels4 +
+ sizeof(void*)*4*numWheels4 +
+ sizeof(PxVehicleConstraintShader)*numWheels4;
+ return byteSize;
+}
+
+PxU8* PxVehicleWheelsDynData::patchUpPointers(const PxU32 numWheels, PxVehicleWheelsDynData* dynData, PxU8* ptrIn)
+{
+ const PxU32 numWheels4 =(((numWheels + 3) & ~3) >> 2);
+ PxU8* ptr = ptrIn;
+ dynData->mWheels4DynData = reinterpret_cast<PxVehicleWheels4DynData*>(ptr);
+ ptr += sizeof(PxVehicleWheels4DynData)*numWheels4;
+ dynData->mTireForceCalculators = reinterpret_cast<PxVehicleTireForceCalculator*>(ptr);
+ ptr += sizeof(PxVehicleTireForceCalculator);
+ dynData->mTireForceCalculators->mShaderData = reinterpret_cast<const void**>(ptr);
+ ptr += sizeof(void*)*4*numWheels4;
+ dynData->mUserDatas = reinterpret_cast<void**>(ptr);
+ ptr += sizeof(void*)*4*numWheels4;
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ PxVehicleConstraintShader* shader = new(ptr) PxVehicleConstraintShader();
+ dynData->mWheels4DynData[i].setVehicleConstraintShader(shader);
+ ptr += sizeof(PxVehicleConstraintShader);
+ }
+
+ PX_ASSERT((ptrIn + computeByteSize(numWheels)) == ptr);
+ return ptr;
+}
+
+PxVehicleWheelsDynData::PxVehicleWheelsDynData(const PxU32 numWheels)
+{
+ const PxU32 numWheels4 =(((numWheels + 3) & ~3) >> 2);
+
+ mNbWheels4=numWheels4;
+ mNbActiveWheels=numWheels;
+
+ //Placement new for wheels4
+ for(PxU32 i=0;i<numWheels4;i++)
+ {
+ new(&mWheels4DynData[i]) PxVehicleWheels4DynData();
+ }
+
+ //Initialise tire calculator
+ for(PxU32 i=0;i<4*numWheels4;i++)
+ {
+ mTireForceCalculators->mShaderData[i]=NULL;
+ }
+ new(mTireForceCalculators) PxVehicleTireForceCalculator;
+
+ //Initialise user data
+ for(PxU32 i=0;i<4*numWheels4;i++)
+ {
+ mUserDatas[i]=NULL;
+ }
+}
+
+bool PxVehicleWheelsDynData::isValid() const
+{
+ for(PxU32 i=0;i<mNbWheels4;i++)
+ {
+ PX_CHECK_AND_RETURN_VAL(mWheels4DynData[i].isValid(), "Invalid PxVehicleSuspWheelTireNDynData.mSuspWheelTire4DynData[i]", false);
+ }
+ return true;
+}
+
+void PxVehicleWheelsDynData::setToRestState()
+{
+ //Set susp/wheel/tires to rest state.
+ const PxU32 numSuspWheelTire4=mNbWheels4;
+ for(PxU32 i=0;i<numSuspWheelTire4;i++)
+ {
+ mWheels4DynData[i].setToRestState();
+ }
+}
+
+void PxVehicleWheelsDynData::setTireForceShaderFunction(PxVehicleComputeTireForce tireForceShaderFn)
+{
+ mTireForceCalculators->mShader=tireForceShaderFn;
+}
+
+void PxVehicleWheelsDynData::setTireForceShaderData(const PxU32 tireId, const void* tireForceShaderData)
+{
+ PX_CHECK_AND_RETURN(tireId < mNbActiveWheels, "PxVehicleWheelsDynData::setTireForceShaderData - Illegal tire");
+ mTireForceCalculators->mShaderData[tireId]=tireForceShaderData;
+}
+
+const void* PxVehicleWheelsDynData::getTireForceShaderData(const PxU32 tireId) const
+{
+ PX_CHECK_AND_RETURN_VAL(tireId < mNbActiveWheels, "PxVehicleWheelsDynData::getTireForceShaderData - Illegal tire", NULL);
+ return mTireForceCalculators->mShaderData[tireId];
+}
+
+void PxVehicleWheelsDynData::setWheelRotationSpeed(const PxU32 wheelIdx, const PxReal speed)
+{
+ PX_CHECK_AND_RETURN(wheelIdx < mNbActiveWheels, "PxVehicleWheelsDynData::setWheelRotationSpeed - Illegal wheel");
+ PxVehicleWheels4DynData& suspWheelTire4=mWheels4DynData[(wheelIdx>>2)];
+ suspWheelTire4.mWheelSpeeds[wheelIdx & 3] = speed;
+ suspWheelTire4.mCorrectedWheelSpeeds[wheelIdx & 3] = speed;
+}
+
+PxReal PxVehicleWheelsDynData::getWheelRotationSpeed(const PxU32 wheelIdx) const
+{
+ PX_CHECK_AND_RETURN_VAL(wheelIdx < mNbActiveWheels, "PxVehicleWheelsDynData::getWheelRotationSpeed - Illegal wheel", 0.0f);
+ const PxVehicleWheels4DynData& suspWheelTire4=mWheels4DynData[(wheelIdx>>2)];
+ return suspWheelTire4.mCorrectedWheelSpeeds[wheelIdx & 3];
+}
+
+void PxVehicleWheelsDynData::setWheelRotationAngle(const PxU32 wheelIdx, const PxReal angle)
+{
+ PX_CHECK_AND_RETURN(wheelIdx < mNbActiveWheels, "PxVehicleWheelsDynData::setWheelRotationAngle - Illegal wheel");
+ PxVehicleWheels4DynData& suspWheelTire4=mWheels4DynData[(wheelIdx>>2)];
+ suspWheelTire4.mWheelRotationAngles[wheelIdx & 3] = angle;
+}
+
+PxReal PxVehicleWheelsDynData::getWheelRotationAngle(const PxU32 wheelIdx) const
+{
+ PX_CHECK_AND_RETURN_VAL(wheelIdx < mNbActiveWheels, "PxVehicleWheelsDynData::getWheelRotationAngle - Illegal wheel", 0.0f);
+ const PxVehicleWheels4DynData& suspWheelTire4=mWheels4DynData[(wheelIdx>>2)];
+ return suspWheelTire4.mWheelRotationAngles[wheelIdx & 3];
+}
+
+void PxVehicleWheels::setToRestState()
+{
+ //Set the rigid body to rest and clear all the accumulated forces and impulses.
+ if(!(mActor->getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC))
+ {
+ mActor->setLinearVelocity(PxVec3(0,0,0));
+ mActor->setAngularVelocity(PxVec3(0,0,0));
+ mActor->clearForce(PxForceMode::eACCELERATION);
+ mActor->clearForce(PxForceMode::eVELOCITY_CHANGE);
+ mActor->clearTorque(PxForceMode::eACCELERATION);
+ mActor->clearTorque(PxForceMode::eVELOCITY_CHANGE);
+ }
+
+ //Set the wheels to rest state.
+ mWheelsDynData.setToRestState();
+}
+
+bool PxVehicleWheels::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mWheelsSimData.isValid(), "invalid mWheelsSimData", false);
+ PX_CHECK_AND_RETURN_VAL(mWheelsDynData.isValid(), "invalid mWheelsDynData", false);
+ return true;
+}
+
+PxU32 PxVehicleWheels::computeByteSize(const PxU32 numWheels)
+{
+ const PxU32 byteSize =
+ PxVehicleWheelsSimData::computeByteSize(numWheels) +
+ PxVehicleWheelsDynData::computeByteSize(numWheels);
+ return byteSize;
+}
+
+PxU8* PxVehicleWheels::patchupPointers(const PxU32 numWheels, PxVehicleWheels* vehWheels, PxU8* ptrIn)
+{
+ PxU8* ptr = ptrIn;
+ ptr = PxVehicleWheelsSimData::patchUpPointers(numWheels, &vehWheels->mWheelsSimData, ptr);
+ ptr = PxVehicleWheelsDynData::patchUpPointers(numWheels, &vehWheels->mWheelsDynData, ptr);
+ PX_ASSERT((ptrIn + computeByteSize(numWheels)) == ptr);
+ return ptr;
+}
+
+void PxVehicleWheels::init(const PxU32 numWheels)
+{
+ new(&mWheelsSimData) PxVehicleWheelsSimData(numWheels);
+ new(&mWheelsDynData) PxVehicleWheelsDynData(numWheels);
+
+ for(PxU32 i = 0; i < mWheelsSimData.mNbWheels4; i++)
+ {
+ new(&mWheelsDynData.mWheels4DynData[i].getVehicletConstraintShader()) PxVehicleConstraintShader(this);
+ }
+
+ mOnConstraintReleaseCounter = Ps::to8(mWheelsSimData.mNbWheels4);
+}
+
+void PxVehicleWheels::free()
+{
+ PX_CHECK_AND_RETURN(mWheelsSimData.mNbWheels4>0, "Cars with zero wheels are illegal");
+
+ const PxU32 numSuspWheelTire4 = mWheelsSimData.mNbWheels4;
+
+ for(PxU32 i=0;i<numSuspWheelTire4;i++)
+ {
+ mWheelsDynData.mWheels4DynData[i].getVehicletConstraintShader().release();
+ }
+}
+
+static PxConstraintShaderTable t =
+ {
+ PxVehicleConstraintShader::vehicleSuspLimitConstraintSolverPrep,
+ 0,
+ PxVehicleConstraintShader::visualiseConstraint,
+ PxConstraintFlag::Enum(0)
+ };
+
+void PxVehicleWheels::setup
+(PxPhysics* physics, PxRigidDynamic* vehActor,
+ const PxVehicleWheelsSimData& wheelsData,
+ const PxU32 numDrivenWheels, const PxU32 numNonDrivenWheels)
+{
+ mNbNonDrivenWheels = numNonDrivenWheels;
+
+ PX_CHECK_AND_RETURN(wheelsData.getNbWheels() == mWheelsSimData.getNbWheels(), "PxVehicleWheels::setup - vehicle must be setup with same number of wheels as wheelsData");
+ PX_CHECK_AND_RETURN(vehActor, "PxVehicleWheels::setup - vehActor is null ptr : you need to instantiate an empty PxRigidDynamic for the vehicle");
+ PX_CHECK_AND_RETURN(wheelsData.isValid(), "PxVehicleWheels::setup -invalid wheelsData");
+ PX_UNUSED(numDrivenWheels);
+
+#if PX_CHECKED
+ PxF32 totalSprungMass=0.0f;
+ for(PxU32 i=0;i<(numDrivenWheels+numNonDrivenWheels);i++)
+ {
+ totalSprungMass+=wheelsData.getSuspensionData(i).mSprungMass;
+ }
+ PX_CHECK_MSG(PxAbs((vehActor->getMass()-totalSprungMass)/vehActor->getMass()) < 0.01f, "Sum of suspension sprung masses doesn't match actor mass");
+#endif
+
+ //Copy the simulation data.
+ mWheelsSimData=wheelsData;
+
+ //Set the actor pointer.
+ mActor=vehActor;
+
+ //Set all the sq result ptrs to null.
+ const PxU32 numSuspWheelTire4=wheelsData.mNbWheels4;
+ for(PxU32 i=0;i<numSuspWheelTire4;i++)
+ {
+ mWheelsDynData.mWheels4DynData[i].mRaycastResults=NULL;
+ mWheelsDynData.mWheels4DynData[i].mSweepResults=NULL;
+ }
+
+ //Set up the suspension limits constraints.
+ for(PxU32 i=0;i<numSuspWheelTire4;i++)
+ {
+ PxVehicleConstraintShader& shader=mWheelsDynData.mWheels4DynData[i].getVehicletConstraintShader();
+ for(PxU32 j=0;j<4;j++)
+ {
+ shader.mData.mSuspLimitData.mCMOffsets[j]=wheelsData.mWheels4SimData[i].getSuspForceAppPointOffset(j);
+ shader.mData.mSuspLimitData.mDirs[j]=wheelsData.mWheels4SimData[i].getSuspTravelDirection(j);
+ shader.mData.mSuspLimitData.mErrors[j]=0.0f;
+ shader.mData.mSuspLimitData.mActiveFlags[j]=false;
+
+ shader.mData.mStickyTireForwardData.mCMOffsets[j]=PxVec3(0,0,0);
+ shader.mData.mStickyTireForwardData.mDirs[j]=PxVec3(0,0,0);
+ shader.mData.mStickyTireForwardData.mTargetSpeeds[j]=0.0f;
+ shader.mData.mStickyTireForwardData.mActiveFlags[j]=false;
+
+ shader.mData.mStickyTireSideData.mCMOffsets[j]=PxVec3(0,0,0);
+ shader.mData.mStickyTireSideData.mDirs[j]=PxVec3(0,0,0);
+ shader.mData.mStickyTireSideData.mTargetSpeeds[j]=0.0f;
+ shader.mData.mStickyTireSideData.mActiveFlags[j]=false;
+ }
+
+
+ shader.mConstraint=physics->createConstraint(vehActor, NULL, shader, t, sizeof(PxVehicleConstraintShader::VehicleConstraintData));
+ shader.mConstraint->markDirty();
+ }
+
+ //Set up the shader data ptrs.
+ for(PxU32 i=0;i<wheelsData.mNbActiveWheels;i++)
+ {
+ mWheelsDynData.setTireForceShaderData(i,&mWheelsSimData.getTireData(i));
+ }
+
+ //Disable the unused wheels.
+ for(PxU32 i=wheelsData.mNbActiveWheels;i<4*mWheelsSimData.mNbWheels4;i++)
+ {
+ mWheelsSimData.disableWheel(i);
+ }
+
+ //Pose the wheels that are mapped to shapes so that all shapes are at the rest pose.
+ for(PxU32 i=0;i<wheelsData.mNbActiveWheels;i++)
+ {
+ const PxI32 shapeId = mWheelsSimData.getWheelShapeMapping(i);
+ if(-1!=shapeId)
+ {
+ PX_CHECK_AND_RETURN(PxU32(shapeId) < mActor->getNbShapes(), "Illegal wheel shape mapping, shape does not exist on actor");
+
+ //Compute the shape local pose
+ const PxTransform chassisCMOffset=mActor->getCMassLocalPose();
+ PxTransform wheelOffset=chassisCMOffset;
+ wheelOffset.p+=mWheelsSimData.getWheelCentreOffset(i);
+ //Pose the shape.
+ PxShape* shapeBuffer[1];
+ mActor->getShapes(shapeBuffer,1,PxU32(shapeId));
+ shapeBuffer[0]->setLocalPose(wheelOffset);
+ }
+ }
+}
+
+void PxVehicleWheels::requires(PxProcessPxBaseCallback& c)
+{
+ c.process(*mActor);
+
+ for(PxU32 i=0;i<mWheelsSimData.mNbWheels4;i++)
+ {
+ c.process(*mWheelsDynData.mWheels4DynData[i].getVehicletConstraintShader().getPxConstraint());
+ }
+}
+
+static PxConstraint* resolveConstraintPtr(PxDeserializationContext& context,
+ PxConstraint* old,
+ PxConstraintConnector* connector,
+ PxConstraintShaderTable &shaders)
+{
+ context.translatePxBase(old);
+ PxConstraint* new_nx = static_cast<PxConstraint*>(old);
+ new_nx->setConstraintFunctions(*connector, shaders);
+ return new_nx;
+}
+
+void PxVehicleWheels::resolveReferences(PxDeserializationContext& context)
+{
+ context.translatePxBase(mActor);
+
+ for(PxU32 i=0;i<mWheelsSimData.mNbWheels4;i++)
+ {
+ PxVehicleConstraintShader& shader=mWheelsDynData.mWheels4DynData[i].getVehicletConstraintShader();
+ shader.setPxConstraint(resolveConstraintPtr(context,shader.getPxConstraint(), shader.getConnector(), t));
+ }
+
+ //Set up the shader data ptrs.
+ for(PxU32 i=0;i<mWheelsSimData.mNbActiveWheels;i++)
+ {
+ mWheelsDynData.setTireForceShaderData(i,&mWheelsSimData.getTireData(i));
+ }
+}
+
+PxReal PxVehicleWheels::computeForwardSpeed() const
+{
+ const PxTransform vehicleChassisTrnsfm=mActor->getGlobalPose().transform(mActor->getCMassLocalPose());
+ return mActor->getLinearVelocity().dot(vehicleChassisTrnsfm.q.rotate(gForward));
+}
+
+PxReal PxVehicleWheels::computeSidewaysSpeed() const
+{
+ const PxTransform vehicleChassisTrnsfm=mActor->getGlobalPose().transform(mActor->getCMassLocalPose());
+ return mActor->getLinearVelocity().dot(vehicleChassisTrnsfm.q.rotate(gRight));
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+void PxVehicleWheelsDynData::setUserData(const PxU32 tireIdx, void* userData)
+{
+ PX_CHECK_AND_RETURN(tireIdx < mNbActiveWheels, "PxVehicleWheelsDynData::setUserData - Illegal wheel");
+ mUserDatas[tireIdx]=userData;
+}
+
+void* PxVehicleWheelsDynData::getUserData(const PxU32 tireIdx) const
+{
+ PX_CHECK_AND_RETURN_VAL(tireIdx < mNbActiveWheels, "PxVehicleWheelsDynData::setUserData - Illegal wheel", NULL);
+ return mUserDatas[tireIdx];
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+
+void PxVehicleWheelsDynData::copy(const PxVehicleWheelsDynData& src, const PxU32 srcWheel, const PxU32 trgWheel)
+{
+ PX_CHECK_AND_RETURN(srcWheel < src.mNbActiveWheels, "PxVehicleWheelsDynData::copy - Illegal src wheel");
+ PX_CHECK_AND_RETURN(trgWheel < mNbActiveWheels, "PxVehicleWheelsDynData::copy - Illegal trg wheel");
+
+ const PxVehicleWheels4DynData& src4 = src.mWheels4DynData[(srcWheel>>2)];
+ PxVehicleWheels4DynData& trg4 = mWheels4DynData[(trgWheel>>2)];
+
+ trg4.mWheelSpeeds[trgWheel & 3] = src4.mWheelSpeeds[srcWheel & 3];
+ trg4.mCorrectedWheelSpeeds[trgWheel & 3] = src4.mCorrectedWheelSpeeds[srcWheel & 3];
+ trg4.mTireLowForwardSpeedTimers[trgWheel & 3] = src4.mTireLowForwardSpeedTimers[srcWheel & 3];
+ trg4.mTireLowSideSpeedTimers[trgWheel & 3] = src4.mTireLowSideSpeedTimers[srcWheel & 3];
+ trg4.mWheelRotationAngles[trgWheel & 3] = src4.mWheelRotationAngles[srcWheel & 3];
+
+ if(src4.mRaycastResults)
+ {
+ const PxVehicleWheels4DynData::SuspLineRaycast& suspLineRaycastSrc = reinterpret_cast<const PxVehicleWheels4DynData::SuspLineRaycast&>(src4.mQueryOrCachedHitResults);
+ PxVehicleWheels4DynData::SuspLineRaycast& suspLineRaycastTrg = reinterpret_cast<PxVehicleWheels4DynData::SuspLineRaycast&>(trg4.mQueryOrCachedHitResults);
+
+ suspLineRaycastTrg.mStarts[trgWheel & 3] = suspLineRaycastSrc.mStarts[srcWheel & 3];
+ suspLineRaycastTrg.mDirs[trgWheel & 3] = suspLineRaycastSrc.mDirs[srcWheel & 3];
+ suspLineRaycastTrg.mLengths[trgWheel & 3] = suspLineRaycastSrc.mLengths[srcWheel & 3];
+ }
+ else if(src4.mSweepResults)
+ {
+ const PxVehicleWheels4DynData::SuspLineSweep& suspLineSweepSrc = reinterpret_cast<const PxVehicleWheels4DynData::SuspLineSweep&>(src4.mQueryOrCachedHitResults);
+ PxVehicleWheels4DynData::SuspLineSweep& suspLineSweepTrg = reinterpret_cast<PxVehicleWheels4DynData::SuspLineSweep&>(trg4.mQueryOrCachedHitResults);
+
+ suspLineSweepTrg.mStartPose[trgWheel & 3] = suspLineSweepSrc.mStartPose[srcWheel & 3];
+ suspLineSweepTrg.mDirs[trgWheel & 3] = suspLineSweepSrc.mDirs[srcWheel & 3];
+ suspLineSweepTrg.mLengths[trgWheel & 3] = suspLineSweepSrc.mLengths[srcWheel & 3];
+ }
+ else
+ {
+ const PxVehicleWheels4DynData::CachedSuspLineSceneQuerytHitResult& cachedHitResultSrc = reinterpret_cast<const PxVehicleWheels4DynData::CachedSuspLineSceneQuerytHitResult&>(src4.mQueryOrCachedHitResults);
+ PxVehicleWheels4DynData::CachedSuspLineSceneQuerytHitResult& cachedHitResultTrg = reinterpret_cast<PxVehicleWheels4DynData::CachedSuspLineSceneQuerytHitResult&>(trg4.mQueryOrCachedHitResults);
+
+ cachedHitResultTrg.mPlanes[trgWheel & 3] = cachedHitResultSrc.mPlanes[srcWheel & 3];
+ cachedHitResultTrg.mFrictionMultipliers[trgWheel & 3] = cachedHitResultSrc.mFrictionMultipliers[srcWheel & 3];
+ cachedHitResultTrg.mCounts[trgWheel & 3] = cachedHitResultSrc.mCounts[srcWheel & 3];
+ cachedHitResultTrg.mDistances[trgWheel & 3] = cachedHitResultSrc.mDistances[srcWheel & 3];
+ }
+}
+
+
+} //namespace physx
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilControl.cpp b/PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilControl.cpp
new file mode 100644
index 00000000..a9d3d135
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilControl.cpp
@@ -0,0 +1,474 @@
+// 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 "PxVehicleUtilControl.h"
+#include "PxVehicleDrive4W.h"
+#include "PsFoundation.h"
+#include "PsUtilities.h"
+#include "CmPhysXCommon.h"
+
+namespace physx
+{
+
+#if PX_CHECKED
+void testValidAnalogValue(const PxF32 actualValue, const PxF32 minVal, const PxF32 maxVal, const char* errorString)
+{
+ const PxF32 tolerance = 1e-2f;
+ PX_CHECK_MSG((actualValue > (minVal - tolerance)) && (actualValue < (maxVal + tolerance)), errorString);
+}
+#endif
+
+
+PxF32 processDigitalValue
+(const PxU32 inputType,
+ const PxVehicleKeySmoothingData& keySmoothing, const bool digitalValue,
+ const PxF32 timestep,
+ const PxF32 analogVal)
+{
+ PxF32 newAnalogVal=analogVal;
+ if(digitalValue)
+ {
+ newAnalogVal+=keySmoothing.mRiseRates[inputType]*timestep;
+ }
+ else
+ {
+ newAnalogVal-=keySmoothing.mFallRates[inputType]*timestep;
+ }
+
+ return PxClamp(newAnalogVal,0.0f,1.0f);
+}
+
+void PxVehicleDriveSmoothDigitalRawInputsAndSetAnalogInputs
+(const PxVehicleKeySmoothingData& keySmoothing, const PxFixedSizeLookupTable<8>& steerVsForwardSpeedTable,
+ const PxVehicleDrive4WRawInputData& rawInputData,
+ const PxF32 timestep,
+ const bool isVehicleInAir,
+ const PxVehicleWheels& vehicle, PxVehicleDriveDynData& driveDynData)
+{
+ const bool gearup=rawInputData.getGearUp();
+ const bool geardown=rawInputData.getGearDown();
+ driveDynData.setGearDown(geardown);
+ driveDynData.setGearUp(gearup);
+
+ const PxF32 accel=processDigitalValue(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL,keySmoothing,rawInputData.getDigitalAccel(),timestep,driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL));
+ driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL,accel);
+
+ const PxF32 brake=processDigitalValue(PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE,keySmoothing,rawInputData.getDigitalBrake(),timestep,driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE));
+ driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE,brake);
+
+ const PxF32 handbrake=processDigitalValue(PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE,keySmoothing,rawInputData.getDigitalHandbrake(),timestep,driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE));
+ driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE,handbrake);
+
+ PxF32 steerLeft=processDigitalValue(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT,keySmoothing,rawInputData.getDigitalSteerLeft(),timestep,driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT));
+ PxF32 steerRight=processDigitalValue(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT,keySmoothing,rawInputData.getDigitalSteerRight(),timestep,driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT));
+ const PxF32 vz=vehicle.computeForwardSpeed();
+ const PxF32 vzAbs=PxAbs(vz);
+ const PxF32 maxSteer=(isVehicleInAir ? 1.0f :steerVsForwardSpeedTable.getYVal(vzAbs));
+ const PxF32 steer=PxAbs(steerRight-steerLeft);
+ if(steer>maxSteer)
+ {
+ const PxF32 k=maxSteer/steer;
+ steerLeft*=k;
+ steerRight*=k;
+ }
+ driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT, steerLeft);
+ driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT, steerRight);
+}
+
+//////////////////////////////////
+
+//process value in range(0,1)
+PX_FORCE_INLINE PxF32 processPositiveAnalogValue
+(const PxF32 riseRate, const PxF32 fallRate,
+ const PxF32 currentVal, const PxF32 targetVal,
+ const PxF32 timestep)
+{
+ PX_ASSERT(targetVal>=-0.01f && targetVal<=1.01f);
+ PxF32 val;
+ if(currentVal<targetVal)
+ {
+ val=currentVal + riseRate*timestep;
+ val=PxMin(val,targetVal);
+ }
+ else
+ {
+ val=currentVal - fallRate*timestep;
+ val=PxMax(val,targetVal);
+ }
+ return val;
+}
+
+//process value in range(-1,1)
+PX_FORCE_INLINE PxF32 processAnalogValue
+(const PxF32 riseRate, const PxF32 fallRate,
+ const PxF32 currentVal, const PxF32 targetVal,
+ const PxF32 timestep)
+{
+ PX_ASSERT(PxAbs(targetVal)<=1.01f);
+
+ PxF32 val=0.0f; // PT: the following code could leave that variable uninitialized!!!!!
+ if(0==targetVal)
+ {
+ //Drift slowly back to zero
+ if(currentVal>0)
+ {
+ val=currentVal-fallRate*timestep;
+ val=PxMax(val,0.0f);
+ }
+ else if(currentVal<0)
+ {
+ val=currentVal+fallRate*timestep;
+ val=PxMin(val,0.0f);
+ }
+ }
+ else
+ {
+ if(currentVal < targetVal)
+ {
+ if(currentVal<0)
+ {
+ val=currentVal + fallRate*timestep;
+ val=PxMin(val,targetVal);
+ }
+ else
+ {
+ val=currentVal + riseRate*timestep;
+ val=PxMin(val,targetVal);
+ }
+ }
+ else
+ {
+ if(currentVal>0)
+ {
+ val=currentVal - fallRate*timestep;
+ val=PxMax(val,targetVal);
+ }
+ else
+ {
+ val=currentVal - riseRate*timestep;
+ val=PxMax(val,targetVal);
+ }
+ }
+ }
+ return val;
+}
+
+void PxVehicleDriveSmoothAnalogRawInputsAndSetAnalogInputs
+(const PxVehiclePadSmoothingData& padSmoothing, const PxFixedSizeLookupTable<8>& steerVsForwardSpeedTable,
+ const PxVehicleDrive4WRawInputData& rawInputData,
+ const PxF32 timestep,
+ const bool isVehicleInAir,
+ const PxVehicleWheels& vehicle, PxVehicleDriveDynData& driveDynData)
+{
+ //gearup/geardown
+ const bool gearup=rawInputData.getGearUp();
+ const bool geardown=rawInputData.getGearDown();
+ driveDynData.setGearUp(gearup);
+ driveDynData.setGearDown(geardown);
+
+ //Update analog inputs for focus vehicle.
+
+ //Process the accel.
+ {
+ const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL];
+ const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL];
+ const PxF32 currentVal=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL);
+ const PxF32 targetVal=rawInputData.getAnalogAccel();
+ const PxF32 accel=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
+ driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_ACCEL, accel);
+ }
+
+ //Process the brake
+ {
+ const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE];
+ const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE];
+ const PxF32 currentVal=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE);
+ const PxF32 targetVal=rawInputData.getAnalogBrake();
+ const PxF32 brake=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
+ driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_BRAKE, brake);
+ }
+
+ //Process the handbrake.
+ {
+ const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE];
+ const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE];
+ const PxF32 currentVal=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE);
+ const PxF32 targetVal=rawInputData.getAnalogHandbrake();
+ const PxF32 handbrake=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
+ driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_HANDBRAKE, handbrake);
+ }
+
+ //Process the steer
+ {
+ const PxF32 vz=vehicle.computeForwardSpeed();
+ const PxF32 vzAbs=PxAbs(vz);
+ const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT];
+ const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT];
+ const PxF32 currentVal=driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT)-driveDynData.getAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT);
+ const PxF32 targetVal=rawInputData.getAnalogSteer()*(isVehicleInAir ? 1.0f :steerVsForwardSpeedTable.getYVal(vzAbs));
+ const PxF32 steer=processAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
+ driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_LEFT, 0.0f);
+ driveDynData.setAnalogInput(PxVehicleDrive4WControl::eANALOG_INPUT_STEER_RIGHT, steer);
+ }
+}
+
+
+////////////////
+
+void PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs
+(const PxVehicleKeySmoothingData& keySmoothing, const PxFixedSizeLookupTable<8>& steerVsForwardSpeedTable,
+ const PxVehicleDrive4WRawInputData& rawInputData,
+ const PxF32 timestep,
+ const bool isVehicleInAir,
+ PxVehicleDrive4W& focusVehicle)
+{
+ PxVehicleDriveSmoothDigitalRawInputsAndSetAnalogInputs
+ (keySmoothing, steerVsForwardSpeedTable, rawInputData, timestep, isVehicleInAir, focusVehicle, focusVehicle.mDriveDynData);
+}
+
+void PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs
+(const PxVehiclePadSmoothingData& padSmoothing, const PxFixedSizeLookupTable<8>& steerVsForwardSpeedTable,
+ const PxVehicleDrive4WRawInputData& rawInputData,
+ const PxF32 timestep,
+ const bool isVehicleInAir,
+ PxVehicleDrive4W& focusVehicle)
+{
+ PxVehicleDriveSmoothAnalogRawInputsAndSetAnalogInputs
+ (padSmoothing,steerVsForwardSpeedTable,rawInputData,timestep,isVehicleInAir,focusVehicle,focusVehicle.mDriveDynData);
+}
+
+////////////////
+
+void PxVehicleDriveNWSmoothDigitalRawInputsAndSetAnalogInputs
+(const PxVehicleKeySmoothingData& keySmoothing, const PxFixedSizeLookupTable<8>& steerVsForwardSpeedTable,
+ const PxVehicleDriveNWRawInputData& rawInputData,
+ const PxReal timestep,
+ const bool isVehicleInAir,
+ PxVehicleDriveNW& focusVehicle)
+{
+ PxVehicleDriveSmoothDigitalRawInputsAndSetAnalogInputs
+ (keySmoothing,steerVsForwardSpeedTable,rawInputData,timestep,isVehicleInAir,focusVehicle,focusVehicle.mDriveDynData);
+}
+
+void PxVehicleDriveNWSmoothAnalogRawInputsAndSetAnalogInputs
+(const PxVehiclePadSmoothingData& padSmoothing, const PxFixedSizeLookupTable<8>& steerVsForwardSpeedTable,
+ const PxVehicleDriveNWRawInputData& rawInputData,
+ const PxReal timestep,
+ const bool isVehicleInAir,
+ PxVehicleDriveNW& focusVehicle)
+{
+ PxVehicleDriveSmoothAnalogRawInputsAndSetAnalogInputs
+ (padSmoothing,steerVsForwardSpeedTable,rawInputData,timestep,isVehicleInAir,focusVehicle,focusVehicle.mDriveDynData);
+}
+
+////////////////
+
+void PxVehicleDriveTankSmoothAnalogRawInputsAndSetAnalogInputs
+(const PxVehiclePadSmoothingData& padSmoothing,
+ const PxVehicleDriveTankRawInputData& rawInputData,
+ const PxReal timestep,
+ PxVehicleDriveTank& focusVehicle)
+{
+ //Process the gearup/geardown buttons.
+ const bool gearup=rawInputData.getGearUp();
+ const bool geardown=rawInputData.getGearDown();
+ focusVehicle.mDriveDynData.setGearUp(gearup);
+ focusVehicle.mDriveDynData.setGearDown(geardown);
+
+ //Process the accel.
+ {
+ const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL];
+ const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL];
+ const PxF32 currentVal=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL);
+ const PxF32 targetVal=rawInputData.getAnalogAccel();
+ const PxF32 accel=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL, accel);
+ }
+
+ PX_ASSERT(focusVehicle.getDriveModel()==rawInputData.getDriveModel());
+ switch(rawInputData.getDriveModel())
+ {
+ case PxVehicleDriveTankControlModel::eSPECIAL:
+ {
+ //Process the left brake.
+ {
+ const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT];
+ const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT];
+ const PxF32 currentVal=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT);
+ const PxF32 targetVal=rawInputData.getAnalogLeftBrake();
+ const PxF32 accel=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT, accel);
+ }
+
+ //Process the right brake.
+ {
+ const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT];
+ const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT];
+ const PxF32 currentVal=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT);
+ const PxF32 targetVal=rawInputData.getAnalogRightBrake();
+ const PxF32 accel=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT, accel);
+ }
+
+ //Left thrust
+ {
+ const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT];
+ const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT];
+ const PxF32 currentVal=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT);
+ const PxF32 targetVal=rawInputData.getAnalogLeftThrust();
+ const PxF32 val=processAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT, val);
+ }
+
+ //Right thrust
+ {
+ const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT];
+ const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT];
+ const PxF32 currentVal=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT);
+ const PxF32 targetVal=rawInputData.getAnalogRightThrust();
+ const PxF32 val=processAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT, val);
+ }
+ }
+ break;
+
+ case PxVehicleDriveTankControlModel::eSTANDARD:
+ {
+ //Right thrust
+ {
+ const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT];
+ const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT];
+ const PxF32 currentVal=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT)-focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT);
+ const PxF32 targetVal=rawInputData.getAnalogRightThrust()-rawInputData.getAnalogRightBrake();
+ const PxF32 val=processAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
+ if(val>0)
+ {
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT, val);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT, 0.0f);
+ }
+ else
+ {
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT, 0.0f);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT, -val);
+ }
+ }
+
+ //Left thrust
+ {
+ const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT];
+ const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT];
+ const PxF32 currentVal=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT)-focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT);
+ const PxF32 targetVal=rawInputData.getAnalogLeftThrust()-rawInputData.getAnalogLeftBrake();
+ const PxF32 val=processAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
+ if(val>0)
+ {
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT, val);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT, 0.0f);
+ }
+ else
+ {
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT, 0.0f);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT, -val);
+ }
+ }
+ }
+ break;
+ }
+}
+
+void PxVehicleDriveTankSmoothDigitalRawInputsAndSetAnalogInputs
+(const PxVehicleKeySmoothingData& keySmoothing,
+ const PxVehicleDriveTankRawInputData& rawInputData,
+ const PxF32 timestep,
+ PxVehicleDriveTank& focusVehicle)
+{
+ PxF32 val;
+ val=processDigitalValue(PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL,keySmoothing,rawInputData.getDigitalAccel(),timestep,focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL));
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_ACCEL, val);
+ val=processDigitalValue(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT,keySmoothing,rawInputData.getDigitalLeftThrust(),timestep,focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT));
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT, val);
+ val=processDigitalValue(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT,keySmoothing,rawInputData.getDigitalRightThrust(),timestep,focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT));
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT, val);
+ val=processDigitalValue(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT,keySmoothing,rawInputData.getDigitalLeftBrake(),timestep,focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT));
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT, val);
+ val=processDigitalValue(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT,keySmoothing,rawInputData.getDigitalRightBrake(),timestep,focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT));
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT, val);
+
+ //Update digital inputs for focus vehicle.
+ focusVehicle.mDriveDynData.setGearUp(rawInputData.getGearUp());
+ focusVehicle.mDriveDynData.setGearDown(rawInputData.getGearDown());
+
+ switch(rawInputData.getDriveModel())
+ {
+ case PxVehicleDriveTankControlModel::eSPECIAL:
+ {
+ const PxF32 thrustL=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT)-focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT, thrustL);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT, 0.0f);
+
+ const PxF32 thrustR=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT)-focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT, thrustR);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT, 0.0f);
+ }
+ break;
+ case PxVehicleDriveTankControlModel::eSTANDARD:
+ {
+ const PxF32 thrustL=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT)-focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT);
+ if(thrustL>0)
+ {
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT, thrustL);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT, 0.0f);
+ }
+ else
+ {
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_LEFT, 0.0f);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_LEFT, -thrustL);
+ }
+
+ const PxF32 thrustR=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT)-focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT);
+ if(thrustR>0)
+ {
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT, thrustR);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT, 0.0f);
+ }
+ else
+ {
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_THRUST_RIGHT, 0.0f);
+ focusVehicle.mDriveDynData.setAnalogInput(PxVehicleDriveTankControl::eANALOG_INPUT_BRAKE_RIGHT, -thrustR);
+ }
+ }
+ break;
+ }
+
+}
+
+
+
+} //physx
+
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilSetup.cpp b/PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilSetup.cpp
new file mode 100644
index 00000000..c7bfb9ec
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilSetup.cpp
@@ -0,0 +1,246 @@
+// 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 "foundation/PxMath.h"
+#include "PxVehicleUtilSetup.h"
+#include "PxVehicleDrive4W.h"
+#include "PxVehicleDriveNW.h"
+#include "PxVehicleDriveTank.h"
+#include "PxVehicleNoDrive.h"
+#include "PxVehicleWheels.h"
+#include "PxVehicleUtil.h"
+#include "PxVehicleUpdate.h"
+#include "PsFoundation.h"
+#include "CmPhysXCommon.h"
+
+namespace physx
+{
+
+void enable3WMode(const PxU32 rightDirection, const PxU32 upDirection, const bool removeFrontWheel, PxVehicleWheelsSimData& wheelsSimData, PxVehicleWheelsDynData& wheelsDynData, PxVehicleDriveSimData4W& driveSimData);
+
+void computeDirection(PxU32& rightDirection, PxU32& upDirection);
+
+void PxVehicle4WEnable3WTadpoleMode(PxVehicleWheelsSimData& wheelsSimData, PxVehicleWheelsDynData& wheelsDynData, PxVehicleDriveSimData4W& driveSimData)
+{
+ PX_CHECK_AND_RETURN
+ (!wheelsSimData.getIsWheelDisabled(PxVehicleDrive4WWheelOrder::eFRONT_LEFT) &&
+ !wheelsSimData.getIsWheelDisabled(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT) &&
+ !wheelsSimData.getIsWheelDisabled(PxVehicleDrive4WWheelOrder::eREAR_LEFT) &&
+ !wheelsSimData.getIsWheelDisabled(PxVehicleDrive4WWheelOrder::eREAR_RIGHT), "PxVehicle4WEnable3WTadpoleMode requires no wheels to be disabled");
+
+ PxU32 rightDirection=0xffffffff;
+ PxU32 upDirection=0xffffffff;
+ computeDirection(rightDirection, upDirection);
+ PX_CHECK_AND_RETURN(rightDirection<3 && upDirection<3, "PxVehicle4WEnable3WTadpoleMode requires the vectors set in PxVehicleSetBasisVectors to be axis-aligned");
+
+ enable3WMode(rightDirection, upDirection, false, wheelsSimData, wheelsDynData, driveSimData);
+}
+
+void PxVehicle4WEnable3WDeltaMode(PxVehicleWheelsSimData& wheelsSimData, PxVehicleWheelsDynData& wheelsDynData, PxVehicleDriveSimData4W& driveSimData)
+{
+ PX_CHECK_AND_RETURN
+ (!wheelsSimData.getIsWheelDisabled(PxVehicleDrive4WWheelOrder::eFRONT_LEFT) &&
+ !wheelsSimData.getIsWheelDisabled(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT) &&
+ !wheelsSimData.getIsWheelDisabled(PxVehicleDrive4WWheelOrder::eREAR_LEFT) &&
+ !wheelsSimData.getIsWheelDisabled(PxVehicleDrive4WWheelOrder::eREAR_RIGHT), "PxVehicle4WEnable3WDeltaMode requires no wheels to be disabled");
+
+ PxU32 rightDirection=0xffffffff;
+ PxU32 upDirection=0xffffffff;
+ computeDirection(rightDirection, upDirection);
+ PX_CHECK_AND_RETURN(rightDirection<3 && upDirection<3, "PxVehicle4WEnable3WTadpoleMode requires the vectors set in PxVehicleSetBasisVectors to be axis-aligned");
+
+ enable3WMode(rightDirection, upDirection, true, wheelsSimData, wheelsDynData, driveSimData);
+}
+
+void computeSprungMasses(const PxU32 numSprungMasses, const PxVec3* sprungMassCoordinates, const PxVec3& centreOfMass, const PxReal totalMass, const PxU32 gravityDirection, PxReal* sprungMasses);
+
+void PxVehicleComputeSprungMasses(const PxU32 numSprungMasses, const PxVec3* sprungMassCoordinates, const PxVec3& centreOfMass, const PxReal totalMass, const PxU32 gravityDirection, PxReal* sprungMasses)
+{
+ computeSprungMasses(numSprungMasses, sprungMassCoordinates, centreOfMass, totalMass, gravityDirection, sprungMasses);
+}
+
+void PxVehicleCopyDynamicsData(const PxVehicleCopyDynamicsMap& wheelMap, const PxVehicleWheels& src, PxVehicleWheels* trg)
+{
+ PX_CHECK_AND_RETURN(trg, "PxVehicleCopyDynamicsData requires that trg is a valid vehicle pointer");
+
+ PX_CHECK_AND_RETURN(src.getVehicleType() == trg->getVehicleType(), "PxVehicleCopyDynamicsData requires that both src and trg are the same type of vehicle");
+
+#if PX_CHECKED
+ {
+ const PxU32 numWheelsSrc = src.mWheelsSimData.getNbWheels();
+ const PxU32 numWheelsTrg = trg->mWheelsSimData.getNbWheels();
+ PxU8 copiedWheelsSrc[PX_MAX_NB_WHEELS];
+ PxMemZero(copiedWheelsSrc, sizeof(PxU8) * PX_MAX_NB_WHEELS);
+ PxU8 setWheelsTrg[PX_MAX_NB_WHEELS];
+ PxMemZero(setWheelsTrg, sizeof(PxU8) * PX_MAX_NB_WHEELS);
+ for(PxU32 i = 0; i < PxMin(numWheelsSrc, numWheelsTrg); i++)
+ {
+ const PxU32 srcWheelId = wheelMap.sourceWheelIds[i];
+ PX_CHECK_AND_RETURN(srcWheelId < numWheelsSrc, "PxVehicleCopyDynamicsData - wheelMap contains illegal source wheel id");
+ PX_CHECK_AND_RETURN(0 == copiedWheelsSrc[srcWheelId], "PxVehicleCopyDynamicsData - wheelMap contains illegal source wheel id");
+ copiedWheelsSrc[srcWheelId] = 1;
+
+ const PxU32 trgWheelId = wheelMap.targetWheelIds[i];
+ PX_CHECK_AND_RETURN(trgWheelId < numWheelsTrg, "PxVehicleCopyDynamicsData - wheelMap contains illegal target wheel id");
+ PX_CHECK_AND_RETURN(0 == setWheelsTrg[trgWheelId], "PxVehicleCopyDynamicsData - wheelMap contains illegal target wheel id");
+ setWheelsTrg[trgWheelId]=1;
+ }
+ }
+#endif
+
+
+ const PxU32 numWheelsSrc = src.mWheelsSimData.getNbWheels();
+ const PxU32 numWheelsTrg = trg->mWheelsSimData.getNbWheels();
+
+ //Set all dynamics data on the target to zero.
+ //Be aware that setToRestState sets the rigid body to
+ //rest so set the momentum back after calling setToRestState.
+ PxRigidDynamic* actorTrg = trg->getRigidDynamicActor();
+ PxVec3 linVel = actorTrg->getLinearVelocity();
+ PxVec3 angVel = actorTrg->getAngularVelocity();
+ switch(src.getVehicleType())
+ {
+ case PxVehicleTypes::eDRIVE4W:
+ static_cast<PxVehicleDrive4W*>(trg)->setToRestState();
+ break;
+ case PxVehicleTypes::eDRIVENW:
+ static_cast<PxVehicleDriveNW*>(trg)->setToRestState();
+ break;
+ case PxVehicleTypes::eDRIVETANK:
+ static_cast<PxVehicleDriveTank*>(trg)->setToRestState();
+ break;
+ case PxVehicleTypes::eNODRIVE:
+ static_cast<PxVehicleNoDrive*>(trg)->setToRestState();
+ break;
+ default:
+ break;
+ }
+ actorTrg->setLinearVelocity(linVel);
+ actorTrg->setAngularVelocity(angVel);
+
+
+ //Keep a track of the wheels on trg that have their dynamics data set as a copy from src.
+ PxU8 setWheelsTrg[PX_MAX_NB_WHEELS];
+ PxMemZero(setWheelsTrg, sizeof(PxU8) * PX_MAX_NB_WHEELS);
+
+ //Keep a track of the average wheel rotation speed of all enabled wheels on src.
+ PxU32 numEnabledWheelsSrc = 0;
+ PxF32 accumulatedWheelRotationSpeedSrc = 0.0f;
+
+ //Copy wheel dynamics data from src wheels to trg wheels.
+ //Track the target wheels that have been given dynamics data from src wheels.
+ //Compute the accumulated wheel rotation speed of all enabled src wheels.
+ const PxU32 numMappedWheels = PxMin(numWheelsSrc, numWheelsTrg);
+ for(PxU32 i = 0; i < numMappedWheels; i++)
+ {
+ const PxU32 srcWheelId = wheelMap.sourceWheelIds[i];
+ const PxU32 trgWheelId = wheelMap.targetWheelIds[i];
+
+ trg->mWheelsDynData.copy(src.mWheelsDynData, srcWheelId, trgWheelId);
+
+ setWheelsTrg[trgWheelId] = 1;
+
+ if(!src.mWheelsSimData.getIsWheelDisabled(srcWheelId))
+ {
+ numEnabledWheelsSrc++;
+ accumulatedWheelRotationSpeedSrc += src.mWheelsDynData.getWheelRotationSpeed(srcWheelId);
+ }
+ }
+
+ //Compute the average wheel rotation speed of src.
+ PxF32 averageWheelRotationSpeedSrc = 0;
+ if(numEnabledWheelsSrc > 0)
+ {
+ averageWheelRotationSpeedSrc = (accumulatedWheelRotationSpeedSrc/ (1.0f * numEnabledWheelsSrc));
+ }
+
+ //For wheels on trg that have not had their dynamics data copied from src just set
+ //their wheel rotation speed to the average wheel rotation speed.
+ for(PxU32 i = 0; i < numWheelsTrg; i++)
+ {
+ if(0 == setWheelsTrg[i] && !trg->mWheelsSimData.getIsWheelDisabled(i))
+ {
+ trg->mWheelsDynData.setWheelRotationSpeed(i, averageWheelRotationSpeedSrc);
+ }
+ }
+
+ //Copy the engine rotation speed/gear states/autobox states/etc.
+ switch(src.getVehicleType())
+ {
+ case PxVehicleTypes::eDRIVE4W:
+ case PxVehicleTypes::eDRIVENW:
+ case PxVehicleTypes::eDRIVETANK:
+ {
+ const PxVehicleDriveDynData& driveDynDataSrc = static_cast<const PxVehicleDrive&>(src).mDriveDynData;
+ PxVehicleDriveDynData* driveDynDataTrg = &static_cast<PxVehicleDrive*>(trg)->mDriveDynData;
+ *driveDynDataTrg = driveDynDataSrc;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool areEqual(const PxQuat& q0, const PxQuat& q1)
+{
+ return ((q0.x == q1.x) && (q0.y == q1.y) && (q0.z == q1.z) && (q0.w == q1.w));
+}
+
+void PxVehicleUpdateCMassLocalPose(const PxTransform& oldCMassLocalPose, const PxTransform& newCMassLocalPose, const PxU32 gravityDirection, PxVehicleWheels* vehicle)
+{
+ PX_CHECK_AND_RETURN(areEqual(PxQuat(PxIdentity), oldCMassLocalPose.q), "Only center of mass poses with identity rotation are supported");
+ PX_CHECK_AND_RETURN(areEqual(PxQuat(PxIdentity), newCMassLocalPose.q), "Only center of mass poses with identity rotation are supported");
+ PX_CHECK_AND_RETURN(0==gravityDirection || 1==gravityDirection || 2==gravityDirection, "gravityDirection must be 0 or 1 or 2.");
+
+ //Update the offsets from the rigid body center of mass.
+ PxVec3 wheelCenterCMOffsets[PX_MAX_NB_WHEELS];
+ const PxU32 nbWheels = vehicle->mWheelsSimData.getNbWheels();
+ for(PxU32 i = 0; i < nbWheels; i++)
+ {
+ wheelCenterCMOffsets[i] = vehicle->mWheelsSimData.getWheelCentreOffset(i) + oldCMassLocalPose.p - newCMassLocalPose.p;
+ vehicle->mWheelsSimData.setWheelCentreOffset(i, vehicle->mWheelsSimData.getWheelCentreOffset(i) + oldCMassLocalPose.p - newCMassLocalPose.p);
+ vehicle->mWheelsSimData.setSuspForceAppPointOffset(i, vehicle->mWheelsSimData.getSuspForceAppPointOffset(i) + oldCMassLocalPose.p - newCMassLocalPose.p);
+ vehicle->mWheelsSimData.setTireForceAppPointOffset(i, vehicle->mWheelsSimData.getTireForceAppPointOffset(i) + oldCMassLocalPose.p - newCMassLocalPose.p);
+ }
+
+ //Now update the sprung masses.
+ PxF32 sprungMasses[PX_MAX_NB_WHEELS];
+ PxVehicleComputeSprungMasses(nbWheels, wheelCenterCMOffsets, PxVec3(0,0,0), vehicle->getRigidDynamicActor()->getMass(), gravityDirection, sprungMasses);
+ for(PxU32 i = 0; i < nbWheels; i++)
+ {
+ PxVehicleSuspensionData suspData = vehicle->mWheelsSimData.getSuspensionData(i);
+ const PxF32 massRatio = sprungMasses[i]/suspData.mSprungMass;
+ suspData.mSprungMass = sprungMasses[i];
+ suspData.mSpringStrength *= massRatio;
+ suspData.mSpringDamperRate *= massRatio;
+ vehicle->mWheelsSimData.setSuspensionData(i, suspData);
+ }
+}
+
+}//physx
diff --git a/PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilTelemetry.cpp b/PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilTelemetry.cpp
new file mode 100644
index 00000000..9e9539ac
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXVehicle/src/VehicleUtilTelemetry.cpp
@@ -0,0 +1,577 @@
+// 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 "PxVehicleUtilTelemetry.h"
+#include "PsFoundation.h"
+#include "PsUtilities.h"
+#include "stdio.h"
+#include "CmPhysXCommon.h"
+
+namespace physx
+{
+
+#if PX_DEBUG_VEHICLE_ON
+
+PxVehicleGraphDesc::PxVehicleGraphDesc()
+: mPosX(PX_MAX_F32),
+ mPosY(PX_MAX_F32),
+ mSizeX(PX_MAX_F32),
+ mSizeY(PX_MAX_F32),
+ mBackgroundColor(PxVec3(PX_MAX_F32,PX_MAX_F32,PX_MAX_F32)),
+ mAlpha(PX_MAX_F32)
+{
+}
+
+bool PxVehicleGraphDesc::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mPosX != PX_MAX_F32, "PxVehicleGraphDesc.mPosX must be initialised", false);
+ PX_CHECK_AND_RETURN_VAL(mPosY != PX_MAX_F32, "PxVehicleGraphDesc.mPosY must be initialised", false);
+ PX_CHECK_AND_RETURN_VAL(mSizeX != PX_MAX_F32, "PxVehicleGraphDesc.mSizeX must be initialised", false);
+ PX_CHECK_AND_RETURN_VAL(mSizeY != PX_MAX_F32, "PxVehicleGraphDesc.mSizeY must be initialised", false);
+ PX_CHECK_AND_RETURN_VAL(mBackgroundColor.x != PX_MAX_F32 && mBackgroundColor.y != PX_MAX_F32 && mBackgroundColor.z != PX_MAX_F32, "PxVehicleGraphDesc.mBackgroundColor must be initialised", false);
+ PX_CHECK_AND_RETURN_VAL(mAlpha != PX_MAX_F32, "PxVehicleGraphDesc.mAlpha must be initialised", false);
+ return true;
+}
+
+PxVehicleGraphChannelDesc::PxVehicleGraphChannelDesc()
+: mMinY(PX_MAX_F32),
+ mMaxY(PX_MAX_F32),
+ mMidY(PX_MAX_F32),
+ mColorLow(PxVec3(PX_MAX_F32,PX_MAX_F32,PX_MAX_F32)),
+ mColorHigh(PxVec3(PX_MAX_F32,PX_MAX_F32,PX_MAX_F32)),
+ mTitle(NULL)
+{
+}
+
+bool PxVehicleGraphChannelDesc::isValid() const
+{
+ PX_CHECK_AND_RETURN_VAL(mMinY != PX_MAX_F32, "PxVehicleGraphChannelDesc.mMinY must be initialised", false);
+ PX_CHECK_AND_RETURN_VAL(mMaxY != PX_MAX_F32, "PxVehicleGraphChannelDesc.mMaxY must be initialised", false);
+ PX_CHECK_AND_RETURN_VAL(mMidY != PX_MAX_F32, "PxVehicleGraphChannelDesc.mMidY must be initialised", false);
+ PX_CHECK_AND_RETURN_VAL(mColorLow.x != PX_MAX_F32 && mColorLow.y != PX_MAX_F32 && mColorLow.z != PX_MAX_F32, "PxVehicleGraphChannelDesc.mColorLow must be initialised", false);
+ PX_CHECK_AND_RETURN_VAL(mColorHigh.x != PX_MAX_F32 && mColorHigh.y != PX_MAX_F32 && mColorHigh.z != PX_MAX_F32, "PxVehicleGraphChannelDesc.mColorHigh must be initialised", false);
+ PX_CHECK_AND_RETURN_VAL(mTitle, "PxVehicleGraphChannelDesc.mTitle must be initialised", false);
+ return true;
+}
+
+PxVehicleGraph::PxVehicleGraph()
+{
+ mBackgroundMinX=0;
+ mBackgroundMaxX=0;
+ mBackgroundMinY=0;
+ mBackgroundMaxY=0;
+ mSampleTide=0;
+ mBackgroundColor=PxVec3(255.f,255.f,255.f);
+ mBackgroundAlpha=1.0f;
+ for(PxU32 i=0;i<eMAX_NB_CHANNELS;i++)
+ {
+ mChannelMinY[i]=0;
+ mChannelMaxY[i]=0;
+ mChannelMidY[i]=0;
+ mChannelColorLow[i]=PxVec3(0,0,255.f);
+ mChannelColorHigh[i]=PxVec3(255.f,0,0);
+ memset(mChannelSamples[i], 0, sizeof(PxReal)*eMAX_NB_SAMPLES);
+ }
+ mNbChannels = 0;
+ PX_COMPILE_TIME_ASSERT(size_t(PxVehicleGraph::eMAX_NB_CHANNELS) >= size_t(PxVehicleDriveGraphChannel::eMAX_NB_DRIVE_CHANNELS) && size_t(PxVehicleGraph::eMAX_NB_CHANNELS) >= size_t(PxVehicleWheelGraphChannel::eMAX_NB_WHEEL_CHANNELS));
+}
+
+PxVehicleGraph::~PxVehicleGraph()
+{
+}
+
+void PxVehicleGraph::setup(const PxVehicleGraphDesc& desc, const PxVehicleGraphType::Enum graphType)
+{
+ mBackgroundMinX = (desc.mPosX - 0.5f*desc.mSizeX);
+ mBackgroundMaxX = (desc.mPosX + 0.5f*desc.mSizeX);
+ mBackgroundMinY = (desc.mPosY - 0.5f*desc.mSizeY);
+ mBackgroundMaxY = (desc.mPosY + 0.5f*desc.mSizeY);
+
+ mBackgroundColor=desc.mBackgroundColor;
+ mBackgroundAlpha=desc.mAlpha;
+
+ mNbChannels = (PxVehicleGraphType::eWHEEL==graphType) ? PxU32(PxVehicleWheelGraphChannel::eMAX_NB_WHEEL_CHANNELS) : PxU32(PxVehicleDriveGraphChannel::eMAX_NB_DRIVE_CHANNELS);
+}
+
+void PxVehicleGraph::setChannel(PxVehicleGraphChannelDesc& desc, const PxU32 channel)
+{
+ PX_ASSERT(channel<eMAX_NB_CHANNELS);
+
+ mChannelMinY[channel]=desc.mMinY;
+ mChannelMaxY[channel]=desc.mMaxY;
+ mChannelMidY[channel]=desc.mMidY;
+ PX_CHECK_MSG(mChannelMinY[channel]<=mChannelMidY[channel], "mChannelMinY must be less than or equal to mChannelMidY");
+ PX_CHECK_MSG(mChannelMidY[channel]<=mChannelMaxY[channel], "mChannelMidY must be less than or equal to mChannelMaxY");
+
+ mChannelColorLow[channel]=desc.mColorLow;
+ mChannelColorHigh[channel]=desc.mColorHigh;
+
+ strcpy(mChannelTitle[channel], desc.mTitle);
+}
+
+void PxVehicleGraph::clearRecordedChannelData()
+{
+ mSampleTide=0;
+ for(PxU32 i=0;i<eMAX_NB_CHANNELS;i++)
+ {
+ memset(mChannelSamples[i], 0, sizeof(PxReal)*eMAX_NB_SAMPLES);
+ }
+}
+
+void PxVehicleGraph::updateTimeSlice(const PxReal* const samples)
+{
+ mSampleTide++;
+ mSampleTide=mSampleTide%eMAX_NB_SAMPLES;
+
+ for(PxU32 i=0;i<mNbChannels;i++)
+ {
+ mChannelSamples[i][mSampleTide]=samples[i];
+ }
+}
+
+void PxVehicleGraph::computeGraphChannel(const PxU32 channel, PxReal* xy, PxVec3* colors, char* title) const
+{
+ PX_ASSERT(channel<mNbChannels);
+ const PxReal sizeX=mBackgroundMaxX-mBackgroundMinX;
+ const PxReal sizeY=mBackgroundMaxY-mBackgroundMinY;
+ const PxF32 minVal=mChannelMinY[channel];
+ const PxF32 maxVal=mChannelMaxY[channel];
+ const PxF32 midVal=mChannelMidY[channel];
+ const PxVec3 colorLow=mChannelColorLow[channel];
+ const PxVec3 colorHigh=mChannelColorHigh[channel];
+ for(PxU32 i=0;i<PxVehicleGraph::eMAX_NB_SAMPLES;i++)
+ {
+ const PxU32 index = (mSampleTide+1+i)%PxVehicleGraph::eMAX_NB_SAMPLES;
+ xy[2*i+0] = mBackgroundMinX+sizeX*i/(1.0f * PxVehicleGraph::eMAX_NB_SAMPLES);
+ const PxF32 sampleVal = PxClamp(mChannelSamples[channel][index],minVal,maxVal);
+ const PxReal y = (sampleVal-minVal)/(maxVal-minVal);
+ xy[2*i+1] = mBackgroundMinY+sizeY*y;
+ colors[i] = sampleVal < midVal ? colorLow : colorHigh;
+ }
+
+ strcpy(title,mChannelTitle[channel]);
+}
+
+PxF32 PxVehicleGraph::getLatestValue(const PxU32 channel) const
+{
+ PX_CHECK_AND_RETURN_VAL(channel < mNbChannels, "PxVehicleGraph::getLatestValue: Illegal channel", 0.0f);
+ return mChannelSamples[channel][mSampleTide];
+}
+
+void PxVehicleGraph::setupEngineGraph
+(const PxF32 sizeX, const PxF32 sizeY, const PxF32 posX, const PxF32 posY,
+ const PxVec3& backgoundColor, const PxVec3& lineColorHigh, const PxVec3& lineColorLow)
+{
+ PxVehicleGraphDesc desc;
+ desc.mSizeX=sizeX;
+ desc.mSizeY=sizeY;
+ desc.mPosX=posX;
+ desc.mPosY=posY;
+ desc.mBackgroundColor=backgoundColor;
+ desc.mAlpha=0.5f;
+ setup(desc,PxVehicleGraphType::eDRIVE);
+
+ //Engine revs
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=800.0f;
+ desc2.mMidY=400.0f;
+ char title[64];
+ sprintf(title, "engineRevs");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleDriveGraphChannel::eENGINE_REVS);
+ }
+
+ //Engine torque
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=1000.0f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "engineDriveTorque");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleDriveGraphChannel::eENGINE_DRIVE_TORQUE);
+ }
+
+ //Clutch slip
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=-200.0f;
+ desc2.mMaxY=200.0f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "clutchSlip");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleDriveGraphChannel::eCLUTCH_SLIP);
+ }
+
+ //Accel control
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=1.1f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "accel");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleDriveGraphChannel::eACCEL_CONTROL);
+ }
+
+ //Brake control
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=1.1f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "brake/tank brake left");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleDriveGraphChannel::eBRAKE_CONTROL);
+ }
+
+ //HandBrake control
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=1.1f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "handbrake/tank brake right");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleDriveGraphChannel::eHANDBRAKE_CONTROL);
+ }
+
+ //Steer control
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=-1.1f;
+ desc2.mMaxY=1.1f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "steerLeft/tank thrust left");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleDriveGraphChannel::eSTEER_LEFT_CONTROL);
+ }
+
+ //Steer control
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=-1.1f;
+ desc2.mMaxY=1.1f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "steerRight/tank thrust right");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleDriveGraphChannel::eSTEER_RIGHT_CONTROL);
+ }
+
+ //Gear
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=-4.f;
+ desc2.mMaxY=20.f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "gearRatio");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleDriveGraphChannel::eGEAR_RATIO);
+ }
+}
+
+void PxVehicleGraph::setupWheelGraph
+ (const PxF32 sizeX, const PxF32 sizeY, const PxF32 posX, const PxF32 posY,
+ const PxVec3& backgoundColor, const PxVec3& lineColorHigh, const PxVec3& lineColorLow)
+{
+ PxVehicleGraphDesc desc;
+ desc.mSizeX=sizeX;
+ desc.mSizeY=sizeY;
+ desc.mPosX=posX;
+ desc.mPosY=posY;
+ desc.mBackgroundColor=backgoundColor;
+ desc.mAlpha=0.5f;
+ setup(desc,PxVehicleGraphType::eWHEEL);
+
+ //Jounce data channel
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=-0.2f;
+ desc2.mMaxY=0.4f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "suspJounce");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleWheelGraphChannel::eJOUNCE);
+ }
+
+ //Jounce susp force channel
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=20000.0f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "suspForce");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleWheelGraphChannel::eSUSPFORCE);
+ }
+
+ //Tire load channel.
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=20000.0f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "tireLoad");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleWheelGraphChannel::eTIRELOAD);
+ }
+
+ //Normalised tire load channel.
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=3.0f;
+ desc2.mMidY=1.0f;
+ char title[64];
+ sprintf(title, "normTireLoad");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleWheelGraphChannel::eNORMALIZED_TIRELOAD);
+ }
+
+ //Wheel omega channel
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=-50.0f;
+ desc2.mMaxY=250.0f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "wheelOmega");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleWheelGraphChannel::eWHEEL_OMEGA);
+ }
+
+ //Tire friction
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=1.1f;
+ desc2.mMidY=1.0f;
+ char title[64];
+ sprintf(title, "friction");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleWheelGraphChannel::eTIRE_FRICTION);
+ }
+
+
+ //Tire long slip
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=-0.2f;
+ desc2.mMaxY=0.2f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "tireLongSlip");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleWheelGraphChannel::eTIRE_LONG_SLIP);
+ }
+
+ //Normalised tire long force
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=2.0f;
+ desc2.mMidY=1.0f;
+ char title[64];
+ sprintf(title, "normTireLongForce");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleWheelGraphChannel::eNORM_TIRE_LONG_FORCE);
+ }
+
+ //Tire lat slip
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=-1.0f;
+ desc2.mMaxY=1.0f;
+ desc2.mMidY=0.0f;
+ char title[64];
+ sprintf(title, "tireLatSlip");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleWheelGraphChannel::eTIRE_LAT_SLIP);
+ }
+
+ //Normalised tire lat force
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=2.0f;
+ desc2.mMidY=1.0f;
+ char title[64];
+ sprintf(title, "normTireLatForce");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleWheelGraphChannel::eNORM_TIRE_LAT_FORCE);
+ }
+
+ //Normalized aligning moment
+ {
+ PxVehicleGraphChannelDesc desc2;
+ desc2.mColorHigh=lineColorHigh;
+ desc2.mColorLow=lineColorLow;
+ desc2.mMinY=0.0f;
+ desc2.mMaxY=2.0f;
+ desc2.mMidY=1.0f;
+ char title[64];
+ sprintf(title, "normTireAlignMoment");
+ desc2.mTitle=title;
+ setChannel(desc2,PxVehicleWheelGraphChannel::eNORM_TIRE_ALIGNING_MOMENT);
+ }
+}
+
+PxVehicleTelemetryData* physx::PxVehicleTelemetryData::allocate(const PxU32 numWheels)
+{
+ //Work out the byte size required.
+ PxU32 size = sizeof(PxVehicleTelemetryData);
+ size += sizeof(PxVehicleGraph); //engine graph
+ size += sizeof(PxVehicleGraph)*numWheels; //wheel graphs
+ size += sizeof(PxVec3)*numWheels; //tire force app points
+ size += sizeof(PxVec3)*numWheels; //susp force app points
+
+ //Allocate the memory.
+ PxVehicleTelemetryData* vehTelData=static_cast<PxVehicleTelemetryData*>(PX_ALLOC(size, "PxVehicleNWTelemetryData"));
+
+ //Patch up the pointers.
+ PxU8* ptr = reinterpret_cast<PxU8*>(vehTelData) + sizeof(PxVehicleTelemetryData);
+ vehTelData->mEngineGraph = reinterpret_cast<PxVehicleGraph*>(ptr);
+ new(vehTelData->mEngineGraph) PxVehicleGraph();
+ ptr += sizeof(PxVehicleGraph);
+ vehTelData->mWheelGraphs = reinterpret_cast<PxVehicleGraph*>(ptr);
+ for(PxU32 i=0;i<numWheels;i++)
+ {
+ new(&vehTelData->mWheelGraphs[i]) PxVehicleGraph();
+ }
+ ptr += sizeof(PxVehicleGraph)*numWheels;
+ vehTelData->mSuspforceAppPoints = reinterpret_cast<PxVec3*>(ptr);
+ ptr += sizeof(PxVec3)*numWheels;
+ vehTelData->mTireforceAppPoints = reinterpret_cast<PxVec3*>(ptr);
+ ptr += sizeof(PxVec3)*numWheels;
+
+ //Set the number of wheels in each structure that needs it.
+ vehTelData->mNbActiveWheels=numWheels;
+
+ //Finished.
+ return vehTelData;
+}
+
+void PxVehicleTelemetryData::free()
+{
+ PX_FREE(this);
+}
+
+void physx::PxVehicleTelemetryData::setup
+(const PxF32 graphSizeX, const PxF32 graphSizeY,
+const PxF32 engineGraphPosX, const PxF32 engineGraphPosY,
+const PxF32* const wheelGraphPosX, const PxF32* const wheelGraphPosY,
+const PxVec3& backgroundColor, const PxVec3& lineColorHigh, const PxVec3& lineColorLow)
+{
+ mEngineGraph->setupEngineGraph
+ (graphSizeX, graphSizeY, engineGraphPosX, engineGraphPosY,
+ backgroundColor, lineColorHigh, lineColorLow);
+
+ const PxU32 numActiveWheels=mNbActiveWheels;
+ for(PxU32 k=0;k<numActiveWheels;k++)
+ {
+ mWheelGraphs[k].setupWheelGraph
+ (graphSizeX, graphSizeY, wheelGraphPosX[k], wheelGraphPosY[k],
+ backgroundColor, lineColorHigh, lineColorLow);
+
+ mTireforceAppPoints[k]=PxVec3(0,0,0);
+ mSuspforceAppPoints[k]=PxVec3(0,0,0);
+ }
+}
+
+void physx::PxVehicleTelemetryData::clear()
+{
+ mEngineGraph->clearRecordedChannelData();
+
+ const PxU32 numActiveWheels=mNbActiveWheels;
+ for(PxU32 k=0;k<numActiveWheels;k++)
+ {
+ mWheelGraphs[k].clearRecordedChannelData();
+ mTireforceAppPoints[k]=PxVec3(0,0,0);
+ mSuspforceAppPoints[k]=PxVec3(0,0,0);
+ }
+}
+
+#endif //PX_DEBUG_VEHICLE_ON
+
+} //physx
+
+
+
+