Files
GTASource/game/Vehicles/wheel.h
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1019 lines
38 KiB
C++

//
//
//
//
#ifndef _WHEEL_H_
#define _WHEEL_H_
// Rage headers
#include "math/amath.h"
#include "phcore/materialmgr.h"
#include "phcore/segment.h"
#include "vector/vector3.h"
#include "rmcore/instance.h"
#include "physics/intersection.h"
#include "physics/shapetest.h"
// Framework headers
#include "fwtl/pool.h"
#include "fwutil/Flags.h"
// Game headers
#include "Control/Replay/ReplaySettings.h"
#include "Modelinfo/VehicleModelInfo.h"
#include "Renderer/HierarchyIds.h"
#include "Scene/RegdRefTypes.h"
#include "Vfx/VfxHelper.h"
#include "Vfx/Systems/VfxLiquid.h"
#include "Weapons/WeaponEnums.h"
namespace rage {
class phArticulatedBodyPart;
}
// Forward declarations:
namespace WorldProbe
{
class CShapeTestHitPoint;
}
class CBike;
class CHandlingData;
class CPed;
class CPhysical;
class CVehicle;
class CVehicleNodeList;
class CVehicleStructure;
class CRoutePoint;
class CTrailer;
struct VfxWheelInfo_s;
#define SPU_WHEEL_INTEGRATION (1 && (__PS3))
#define APPLY_GRAVITY_IN_INTEGRATOR (1)
#define LARGEST_PHBOUND phBoundBox
enum eScriptWheelList
{
SC_WHEEL_CAR_FRONT_LEFT = 0,
SC_WHEEL_CAR_FRONT_RIGHT,
SC_WHEEL_CAR_MID_LEFT,
SC_WHEEL_CAR_MID_RIGHT,
SC_WHEEL_CAR_REAR_LEFT,
SC_WHEEL_CAR_REAR_RIGHT,
SC_WHEEL_BIKE_FRONT,
SC_WHEEL_BIKE_REAR,
SC_WHEEL_NUM
};
// JP: Split wheel flags into 2 so we have room for more if needed
// In general the wheel flags change at runtime whilst the config flags stay constant
enum eWheelFlags
{
// state flags
WF_HIT = BIT(0),
WF_HIT_PREV = BIT(1),
WF_ON_GAS = BIT(2),
WF_ON_FIRE = BIT(3),
// Cheat flags
WF_CHEAT_TC = BIT(4),
WF_CHEAT_SC = BIT(5),
WF_CHEAT_GRIP1 = BIT(6),
WF_CHEAT_GRIP2 = BIT(7),
// runtime flags
WF_BURNOUT = BIT(8),
WF_BURNOUT_NON_DRIVEN_WHEEL = BIT(9),
WF_INSHALLOWWATER = BIT(10),
WF_INDEEPWATER = BIT(11),
WF_TYRES_HEAT_UP = BIT(12),
WF_ABS_ACTIVE = BIT(13),
// Abs modes
// Set every frame by the vehicle so they are classed as runtime flags
// This is because A.I. Drivers have ABS always on
WF_ABS = BIT(14),
WF_ABS_ALT = BIT(15),
WF_SQUASHING_PED = BIT(16),
WF_REDUCE_GRIP = BIT(17),
// when a vehicle is teleported its wheel contact positions aren't teleported with it
// this can cause issues when relocating particle effects so we set a flag to stop wheel vfx being updated this frame
WF_TELEPORTED_NO_VFX = BIT(18),
WF_RESET = BIT(19),
WF_BROKEN_OFF = BIT(20),
WF_FULL_THROTTLE = BIT(21),
WF_SIDE_IMPACT = BIT(22),
WF_DUMMY_TRANSITION = BIT(23),
WF_DUMMY_TRANSITION_PREV = BIT(24),
WF_NO_LATERAL_SPRING = BIT(25),
WF_WITHIN_DAMAGE_REGION = BIT(26),
WF_WITHIN_HEAVYDAMAGE_REGION = BIT(27),
WF_TOUCHING_PAVEMENT = BIT(28),
WF_DUMMY = BIT(29),
WF_FORCE_NO_SLEEP = BIT(30),
WF_SLEEPING_ON_DEBRIS = BIT(31)
};
enum eWheelConfigFlags
{
// configuration flags
WCF_BIKE_WHEEL = BIT(0),
WCF_LEFTWHEEL = BIT(1),
WCF_REARWHEEL = BIT(2),
WCF_STEER = BIT(3),
WCF_POWERED = BIT(4),
WCF_TILT_INDEP = BIT(5),
WCF_TILT_SOLID = BIT(6),
WCF_BIKE_CONSTRAINED_COLLIDER = BIT(7),
WCF_BIKE_FALLEN_COLLIDER = BIT(8),
WCF_INSTANCED = BIT(9),
WCF_DONT_RENDER_STEER = BIT(10), // Dont render the wheel steering
WCF_UPDATE_SUSPENSION = BIT(11), // Update suspension every frame
WCF_QUAD_WHEEL = BIT(12),
WCF_HIGH_FRICTION_WHEEL = BIT(13),
WCF_DONT_REDUCE_GRIP_ON_BURNOUT = BIT(14), // Used for low powered vehicles
WCF_IS_PHYSICAL = BIT(15), // Used for wheels that are children of articulated joints
WCF_BICYCLE_WHEEL = BIT(16),
WCF_TRACKED_WHEEL = BIT(17),
WCF_PLANE_WHEEL = BIT(18),
WCF_DONT_RENDER_HUB = BIT(19),
WCF_SPOILER = BIT(20), // Has the vehicle got a spoiler mod.
WCF_ROTATE_BOUNDS = BIT(21),
WCF_EXTEND_ON_UPDATE_SUSPENSION = BIT(22), // Used to force wheels to extend when updating the suspension
WCF_CENTRE_WHEEL = BIT(23), // The three wheeled cars have a centre wheel
WCF_AMPHIBIOUS_WHEEL = BIT(24),
WCF_RENDER_WITH_ZERO_COMPRESSION = BIT(25)
// NOTE: If you add another flag (beyond 31) you need to increase the size of CWheel::m_nConfigFlags
};
enum eWheelHydraulicState
{
WHS_INVALID = -1,
WHS_IDLE,
WHS_LOCK_START,
WHS_LOCK = WHS_LOCK_START,
WHS_LOCK_UP_ALL,
WHS_LOCK_UP,
WHS_LOCK_DOWN_ALL,
WHS_LOCK_DOWN,
WHS_LOCK_END = WHS_LOCK_DOWN,
WHS_BOUNCE_START,
WHS_BOUNCE_LEFT_RIGHT = WHS_BOUNCE_START,
WHS_BOUNCE_FRONT_BACK,
WHS_BOUNCE,
WHS_BOUNCE_ALL,
WHS_BOUNCE_END = WHS_BOUNCE_ALL,
WHS_BOUNCE_FIRST_ACTIVE,
WHS_BOUNCE_ACTIVE = WHS_BOUNCE_FIRST_ACTIVE,
WHS_BOUNCE_LANDING,
WHS_BOUNCE_LANDED,
WHS_BOUNCE_ALL_ACTIVE,
WHS_BOUNCE_ALL_LANDING,
WHS_FREE,
WHS_BOUNCE_LAST_ACTIVE = WHS_FREE,
};
#define VEHICLE_USE_INTEGRATION_FOR_WHEELS 1
#define WF_DYNAMIC_STATE (WF_HIT|WF_ON_GAS)
#define WF_RESET_STATE (WF_HIT|WF_HIT_PREV)
#define WF_RESET_CHEATS (WF_CHEAT_TC|WF_CHEAT_SC|WF_CHEAT_GRIP1|WF_CHEAT_GRIP2)
#define MAX_WHEEL_BOUNDS_PER_WHEEL (3)
#define WHEEL_CLIMB_BOUND (2)
#define TRACTION_TABLE_ENTRIES (10)
#define SUSPENSION_HEALTH_DEFAULT (1000.0f)
#define SUSPENSION_HEALTH_DEFAULT_INV (1.0f / SUSPENSION_HEALTH_DEFAULT)
#define TYRE_HEALTH_DEFAULT (1000.0f)
#define TYRE_HEALTH_DEFAULT_INV (1.0f / TYRE_HEALTH_DEFAULT)
#define TYRE_HEALTH_HIGH_GRIP (850.0f)
#define TYRE_HEALTH_MEDIUM_GRIP (450.0f)
#define TYRE_HEALTH_FLAT (350.0f)
#define TYRE_HEALTH_FLAT_ADD (0.0001f)
#if VEHICLE_USE_INTEGRATION_FOR_WHEELS
struct WheelIntegrationTimeInfo
{
float fProbeTimeStep;
float fProbeTimeStep_Inv;
float fIntegrationTimeStep;
float fIntegrationTimeStep_Inv;
float fTimeInIntegration;
float fTimeInIntegration_Inv;
};
#endif
class CWheel
{
friend class CVfxWheel;
#if GTA_REPLAY
friend class CPacketVehicleUpdate;
friend class CPacketVehicleWheelUpdate_Old;
friend class CWheelFullData;
friend class ReplayWheelValues;
#endif // GTA_REPLAY
public:
CWheel();
~CWheel();
FW_REGISTER_CLASS_POOL(CWheel);
void Init(CVehicle* pParentVehicle, eHierarchyId wheelId, float fRadius, float fForceMult, int nConfigFlags, s8 oppositeWheelIndex = -1);
void InitOnSpu(CHandlingData* pHandling);
CHandlingData* GetHandlingData() const {return m_pHandling;}
// call this when vehicle is created, and every time vehicle is damaged
void SuspensionSetup(const void* damageTexturePtr);
// call this to get transformed probes before doing test
bool ProbeGetTransfomedSegment(const Matrix34* pMatrix, phSegment& pProbeSegment);
// call this after test to deal with results
bool ProbeProcessResults(const Matrix34* pMatrix, WorldProbe::CShapeTestHitPoint& probeResults);
// set compression from place properly on road
void SetCompressionFromHitPos(const Matrix34* pParentMat, const Vector3& vecPos, bool bIsAHit, const Vector3& vecNormal = ZAXIS);
void SetCompressionFromGroundHeightLocalAndHitPos(float fGroundHeightLocal, Vector3::Vector3Param vHitPos, Vector3::Vector3Param vHitNormal);
void ResetCompressionFromPrev() { m_fCompression = m_fCompressionOld; }
void UpdateSuspension(const void* pDamageTexture, bool bSyncSkelToArtBody = true);
// called from ProcessPreComputeImpacts to intercept impacts for use in suspension
void ProcessImpactResults();
// PURPOSE: Used with ProcessImpact(), to hold data that can be computed
// about the parent vehicle and can be shared between the wheels
// to avoid recomputation.
struct ProcessImpactCommonData
{
explicit ProcessImpactCommonData(const CVehicle& rParentVehicle);
float GetVelocitySq() const { return m_ComputedValues.GetXf(); }
float GetTreadWidthMultIfNotBikeWheel() const { return m_ComputedValues.GetYf(); }
ScalarV_Out GetTreadWidthMultIfNotBikeWheelV() const { return m_ComputedValues.GetY(); }
int GetIsStill() const { return m_ComputedValues.GetWi(); }
Vec3V m_Velocity;
// X: fVelocitySq;
// Y: fTreadWidthMultIfNotBikeWheel
// Z: bDriveOverVehicle
// W: bIsStill
Vec4V m_ComputedValues;
const CPed* m_pDriver;
const CTrailer* m_pAttachedTrailer;
bool m_bPlayerVehicle;
};
void ProcessImpact(const ProcessImpactCommonData& commonData, phCachedContactIterator &impacts, const atUserArray<CVehicle*> &aVehicleFlattenNormals);
void SetWheelHit(float fCompression, Vec3V_In vHitPos, Vec3V_In vHitNormal, const bool bSetToDefaultMaterial = true);
bool ProcessImpactPopTires( phCachedContactIterator& impacts, const CEntity & rOtherEntity);
void ProcessPreSimUpdate( const void *basePtr, phCollider* vehicleCollider, Mat34V_In vehicleMatrix, float fWheelExtension);
//Helper function to see if impact is on the side of the wheel
// bool ImpactIsOnSide(CVehicle * pParentVehicle, phCachedContactConstIterator& impact) const;
// process forces from this wheel
void ProcessAsleep( const Vector3& parentVelocity, const float fTimeStep, const float fGravityForce, bool updateWheelAngVelFromVehicleVel);
bool WantsToBeAwake() {return (m_fTyreHealth < TYRE_HEALTH_DEFAULT && m_fTyreHealth > TYRE_HEALTH_FLAT + TYRE_HEALTH_FLAT_ADD);}
void UpdateCompressionOnDeactivation();
//Called to make sure we clear audio effects when wheels are no longer processed but the vehicle has active audio
void ProcessLowLODAudio();
void CalculateTractionVectors(const Matrix34& matParent, Vector3& vecFwd, Vector3& vecSide, Vector3& vecHitDelta, float fSteerAngle);
void CalculateTractionVectorsNew( const Matrix34& matParent, Vector3& vecFwd, Vector3& vecSide, Vector3& vecHitDelta, float fSteerAngle, Vector3 localSpeed );//, Vector3 angVelocity, Vector3 linearVelocity );
float GetTractionCoefficientFromRatio(float fRatio, float fMult, float fLoss);
#if VEHICLE_USE_INTEGRATION_FOR_WHEELS
void IntegrateSuspensionAccel(phCollider* pVehCollider, Vector3& vecForceResult, Vector3& vecAccelResult, Vector3& vecAngAccelResult, float& fSuspensionForce, float& compressionDelta, const Matrix34& mat, const Vector3& vecVel, const WheelIntegrationTimeInfo& timeInfo, const CWheel *pOppositeWheel, const float fGravity);
void IntegrateTyreAccel(phCollider* pVehCollider, Vector3& vecForceResult, Vector3& vecAccelResult, Vector3& vecAngAccelResult, Vector3& vecFwd, Vector3& vecSide, float& fWheelAngSlipDtResult, float fSuspensionForce, const Matrix34& mat, const Vector3& vecVel, const Vector3& vecAngVel, float fWheelAngSlip, const WheelIntegrationTimeInfo& timeInfo, const CWheel *pOppositeWheel, const float fGravity);
float IntegrateCalculateForces(phCollider* pVehCollider, Vector3& vecForceResult, float fSpeed, float fSpeedAlongFwd, float fSpeedAlongSide, float fSpringAlongFwd, float fSpringAlongSide, float fRotSlipRatio, float fBrakeForce, float fDriveForce, float fLoadForce, float fIntegrationTimeStep, const float fGravity);
float IntegrateCalculateForceLimits(float fSpeedAlongFwd, float fSpeedAlongSide, float fSpringAlongFwd, float fSpringAlongSide, float fAngVel, float& fFwdForceLimit, float& fSideForceLimit, float fTimeRatio);
void IntegrationPostProcess(phCollider* pVehCollider, float fWheelAngSlip, float fMaxVelInGear, int nGear, float fTimeStep, unsigned frameCount, Vector3& vecPushToSide, Vector3& vecFwd, Vector3& vecSide, const float fGravity);
#if !__SPU
void IntegrationFinalProcess(phCollider* pVehCollider, ScalarV_In timeStep);//This process is done after the integrator thread was finished.
#endif // !__SPU
float GetMassAlongVector(phCollider* pVehCollider, const Vector3& vecNormal, const Vector3& vecWorldPos);
// Update the m_fCompression during the integration loop
// Either using a shapetest or using predicted hit points
void UpdateCompressionInsideIntegrator(const Matrix34& matUpdated, const phCollider* pCollider, float& compressionDelta);
#endif
void UpdateContactsAfterNetworkBlend(const Matrix34& matOld, const Matrix34& matNew);
void ProcessWheelMatrixForAutomobile(crSkeleton & rSkeleton);
void ProcessAnimatedWheelDeformationForAutomobile(crSkeleton & rSkeleton);
void ProcessWheelMatrixForBike();
void ProcessWheelMatrixForTrike();
void ProcessWheelMatrixCore(crSkeleton & rSkeleton, CVehicleStructure & rStructure, CWheel * const * ppWheels, int numWheels, bool bAnimated, float fSteerAngle);
void ProcessWheelDeformationMatrixCore(crSkeleton & rSkeleton, CVehicleStructure & rStructure, bool bAnimated);
void ProcessWheelScale(crSkeleton* pSkeleton, CVehicleStructure* pStructure, CWheel * const * ppWheels);
void ProcessAudio();
void ProcessVFx(bool bContainsLocalPlayer);
void ProcessPedCollision();
void ProcessWheelVFxDry( CVfxVehicleInfo* pVfxVehicleInfo, VfxGroup_e mtlVfxGroup, Vec3V_In vVfxVecHitPos, Vec3V_In vVfxVecHitCentrePos, Vec3V_In vVfxVecHitNormal, float vfxSlipVal, float vfxGroundSpeedVal, float currRoadWetness, float distSqrToCam);
void ProcessWheelVFxWet( CVfxVehicleInfo* pVfxVehicleInfo, VfxGroup_e mtlVfxGroup, Vec3V_In vVfxVecHitPos, Vec3V_In vVfxVecHitCentrePos, Vec3V_In vVfxVecHitNormal, float vfxSlipVal, float vfxGroundSpeedVal, float currRoadWetness, bool inWater, float waterZ, float distSqrToCam);
void ProcessWheelVFx( CVfxVehicleInfo* pVfxVehicleInfo, VfxWheelInfo_s* pVfxWheelInfo, Vec3V_In vVfxVecHitPos, Vec3V_In vVfxVecHitCentrePos, Vec3V_In vVfxVecHitNormal, float vfxSlipVal, float vfxGroundSpeedVal, float wetEvo, bool isWet, bool inWater, float waterZ, float distSqrToCam);
void ProcessSkidmarkVFx( CVfxVehicleInfo* pVfxVehicleInfo, VfxGroup_e mtlVfxGroup, Vec3V_In vVfxVecHitCentrePos, Vec3V_In vVfxVecHitNormal, float vfxSlipVal, float vfxPressureVal, float currRoadWetness, float distSqrToCam);
void ProcessTyreTemp(const Vector3& vecVelocity, float fTimestep);
void UpdateTyreWear( float fTimeStep );
void SetSteerAngle(float fAngle);
void SetBrakeAndDriveForce(const float fForce, const float fDriveForce, const float fThrottle, const float fSpeedSqr );
void SetBrakeForce( const float fForce ) { m_fBrakeForce = fForce; }
void SetDriveForce( const float fForce ) { m_fDriveForce = fForce; }
void SetHandBrakeForce(float fForce);
inline void UpdateAbsTimer(float fTimeStep) {m_fAbsTimer = rage::Max(0.0f, m_fAbsTimer - fTimeStep);}
#if !__SPU
void ApplyTireForceToPed(CPed *pPed, phCollider *pVehCollider, u16 hitComponent);
#endif // !__SPU
bool GetIsTouching() const {return m_nDynamicFlags.IsFlagSet(WF_HIT);}
bool GetWasTouching() const {return m_nDynamicFlags.IsFlagSet(WF_HIT_PREV);}
bool GetSideImpact() const {return m_nDynamicFlags.IsFlagSet(WF_SIDE_IMPACT);}
bool GetWasReset() const {return m_nDynamicFlags.IsFlagSet(WF_RESET);}
bool GetIsDriveWheel() const {return m_nConfigFlags.IsFlagSet(WCF_POWERED);}
const Vector3& GetHitPos() const { return m_vecHitPos; }
void ResetHitPos() { m_vecHitPos = VEC3_ZERO; }
const Vector3& GetHitNormal() const { return m_vecHitNormal; }
u16 GetHitComponent() const { return m_nHitComponent; }
CPhysical* GetHitPhysical() {return (m_nDynamicFlags &WF_HIT) ? m_pHitPhysical.Get() : NULL;}
const CPhysical* GetHitPhysical() const {return (m_nDynamicFlags &WF_HIT) ? m_pHitPhysical.Get() : NULL;}
const CPhysical* GetPrevHitPhysical() const {return m_pPrevHitPhysical.Get();}
CPhysical* GetPrevHitPhysical() {return m_pPrevHitPhysical.Get();}
float GetGroundSpeed() const {return -m_fRotAngVel*m_fWheelRadius;}
const Vector3 *GetGroundBeneathWheelsVelocity() const {return &m_vecGroundVelocity;}
float GetRotSpeed() const {return m_fRotAngVel;}
void SetRotSpeed( float rotAngVel ) { m_fRotAngVel = rotAngVel; }
float GetRotSlipRatio() const {return m_fRotSlipRatio;}
void SetRotSlipRatio( float rotSlipRatio ) { m_fRotSlipRatio = rotSlipRatio; }
inline void SetRotAngle(float fRotAngle) { m_fRotAng = fwAngle::LimitRadianAngleFast(fRotAngle); }
float GetRotAngle() { return m_fRotAng; }
void ScaleTyreContactVelocity( float scale ) { m_vecTyreContactVelocity *= scale; }
phMaterialMgr::Id GetMaterialId() const {return m_nHitMaterialId;}
void Reset(bool bExtend=false);
void Teleport() {GetDynamicFlags().SetFlag(WF_TELEPORTED_NO_VFX);}
fwFlags32& GetDynamicFlags() {return m_nDynamicFlags;}
fwFlags32& GetConfigFlags() {return m_nConfigFlags;}
const fwFlags32& GetDynamicFlags() const {return m_nDynamicFlags;}
const fwFlags32& GetConfigFlags() const {return m_nConfigFlags;}
void SetMaterialFlags();
const phSegment& GetProbeSegment() const {return m_aWheelLines;}
float GetFwdSlipAngle() const {return m_fFwdSlipAngle;}
float GetSideSlipAngle() const {return m_fSideSlipAngle;}
float GetCamberForce() const {return m_fTyreCamberForce;}
float GetEffectiveSlipAngle() const {return m_fEffectiveSlipAngle;}
const float& GetEffectiveSlipAngleRef() const { return m_fEffectiveSlipAngle; }
float GetFrictionDamage() const { return m_fFrictionDamage; }
float GetCompression() const {return m_fCompression;}
float GetCompressionChange() const {return m_fCompression - m_fCompressionOld;}
float GetMaxTravelDelta() const {return m_fMaxTravelDelta;}
float GetSuspensionLength() const {return m_fSusLength;}
float GetWheelCompression() const {return m_fWheelCompression;}
float GetCalculatedWheelCompression();
float GetWheelCompressionIncBurstAndSink() const;
float GetWheelCompressionFromStaticIncBurstAndSink() const {return GetWheelCompressionIncBurstAndSink() - m_fStaticDelta;}
float GetStaticDelta() const { return m_fStaticDelta; }
float GetFrictionDamageScaledBySpeed(const Vector3& vVelocity);
const Vector3 & GetSuspensionAxis() const { return m_vecSuspensionAxis; }
eHierarchyId GetHierarchyId() const { return m_WheelId;}
s16 GetOppositeWheelIndex() const {return m_nOppositeWheelIndex;}
void SetOppositeWheelIndex( s8 oppositewheelIndex ) {m_nOppositeWheelIndex = oppositewheelIndex;}
int GetFragChild(int iChildIndex = 0) const {return m_nFragChild[iChildIndex];}
inline CVfxDeepSurfaceInfo& GetDeepSurfaceInfo() {return m_deepSurfaceInfo;}
inline void SetWetnessInfo(const VfxLiquidType_e liquidType) {m_liquidAttachInfo.Set(VFXMTL_WET_MODE_WHEEL, liquidType);}
float GetSteeringAngle() const { return m_fSteerAngle; }
float GetBrakeForce() const { return m_fBrakeForce; }
float GetDriveForce() const { return m_fDriveForce; }
float GetDriveForceOld() const { return m_fDriveForceOld; }
void ScaleDriveForce( float forceScale ) { m_fDriveForce *= forceScale; }
void ProcessWheelDamage(float fTimeStep);
void SetWheelOnFire(bool bNetworkCheck = true);
bool IsWheelOnFire() const;
void ClearWheelOnFire();
void ProcessWheelBurst();
bool DoBurstWheelToRim();
bool GetTyreShouldBurst(const Vector3& vecVelocity) const;
bool GetTyreShouldBurstFromDamage() const;
bool GetTyreShouldBreakFromDamage() const;
void UpdateGroundVelocity();
// get position of suspension, taken as original centre of wheel pos, returns radius for damage calculations
float GetSuspensionPos(Vector3& vecPosResult);
void ApplySuspensionDamage(float fDamage);
float GetSuspensionHealth() const { return m_fSuspensionHealth; }
void SetSuspensionHealth(float fHealth) { m_fSuspensionHealth = fHealth; }
Vec3V_Out GetWheelStaticPositionLocal() const;
float GetWheelPosAndRadius(Vector3& vecResult) const;
float GetWheelWidth() const { return m_fWheelWidth; }
float GetWheelRadius() const { return m_fWheelRadius; }
ScalarV_Out GetWheelRadiusV() const { return LoadScalar32IntoScalarV(m_fWheelRadius); }
float GetWheelRimRadius() const { return m_fWheelRimRadius; }
void SetWheelRimRadius(float radius) { m_fWheelRimRadius = radius; }
inline float GetWheelRadiusIncBurst() const
{
if(m_fTyreHealth <= 0.0f)
return m_fWheelRimRadius;
else
return m_fWheelRimRadius + (m_fTyreHealth * TYRE_HEALTH_DEFAULT_INV) * (m_fWheelRadius - m_fWheelRimRadius);
}
inline float GetTyreThickness() const
{
if(m_fTyreHealth <= 0.0f)
return 0;
else
return (m_fTyreHealth * TYRE_HEALTH_DEFAULT_INV) * (m_fWheelRadius - m_fWheelRimRadius);
}
void CalculateMaximumExtents(Mat34V_InOut lastWheelMatrixOut, Mat34V_InOut currentWheelMatrixOut, phCollider *pParentCollider = NULL);
bool GetWheelMatrixAndBBox( Matrix34& matResult, Vector3& vecBoxMaxResult) const;
void ApplyTyreDamage(const CEntity* pInflictor, float fDamage, const Vector3& vecPosLocal, const Vector3& vecNormLocal, eDamageType nDamageType, int nWheelIndex, bool bNetworkCheck = true);
float GetTyreHealth() const {return m_fTyreHealth;}
void SetTyreHealth(float health)
{
m_fTyreHealth = health;
m_nDynamicFlags.ChangeFlag(WF_FORCE_NO_SLEEP,WantsToBeAwake());
}
float GetTyreBurstSideRatio() const;
float GetTyreBurstRatio() const
{
if(m_fTyreHealth <= 0.0f)
return 1.0f;
else if(m_fStaticDelta != 0.0f)
return rage::Max(0.0f, rage::Min(1.0f, m_fCompression / m_fStaticDelta)*(1.0f - m_fTyreHealth*TYRE_HEALTH_DEFAULT_INV));
return 0.0f;
}
float GetTyreBurstCompression() const
{
if(m_fTyreHealth <= 0.0f)
return (m_fWheelRadius - m_fWheelRimRadius);
else if(m_fTyreWearRate > 0.0f && m_fTyreHealth > TYRE_HEALTH_FLAT )
{
return 0.0f;
}
else if(m_fStaticDelta != 0.0f)
return rage::Max(0.0f, rage::Min(1.0f, m_fCompression / m_fStaticDelta)*(1.0f - m_fTyreHealth*TYRE_HEALTH_DEFAULT_INV)) * (m_fWheelRadius - m_fWheelRimRadius);
return 0.0f;
}
float GetTyreWearRate() const
{
return m_fTyreWearRate;
}
void SetTyreWearRate( float wearRate );
void SetWearRateScale( float wearRateScale ) { m_fWearRateScale = wearRateScale; }
float GetWearRateScale() const { return m_fWearRateScale; }
void SetMaxGripDiffFromWearRate( float gripDiff ) { m_fMaxGripDiffFromWearRate = gripDiff; }
float GetMaxGripDiffFromWearRate() const { return m_fMaxGripDiffFromWearRate; }
void UpdateTyreHealthFromNetwork(float fHealth);
void ResetDamage();
void PushToSide(phCollider* pVehCollider, const Vector3& vecPushDirn);
bool GetIsFlat() const { return (m_fTyreHealth <= (TYRE_HEALTH_FLAT + TYRE_HEALTH_FLAT_ADD)); }
void SetFrontRearSelector(float fFrontRearSelector) { m_fFrontRearSelector = fFrontRearSelector; }
float GetFrontRearSelector() const { return m_fFrontRearSelector; }
float GetMaterialGrip() const {return m_fMaterialGrip;}
void SetStaticForce(float fForceMult) { m_fStaticForce = fForceMult; }
float GetStaticForce() const { return m_fStaticForce; }
void SetGripMult(float fGripMult) { m_fGripMult = fGripMult; }
float GetGripMult() { return m_fGripMult; }
float GetTyreDrag() const { return m_fMaterialDrag; }
float GetTyreTemp() const { return m_fTyreTemp; }
void SetMassMultForAcceleration(float fMassMultForAccel) { Assert(fMassMultForAccel > 0.0f); m_fMassMultForAccelerationInv = (1.0f / fMassMultForAccel); }
static eHierarchyId GetScriptWheelId(eScriptWheelList nWheel) {Assert(nWheel < SC_WHEEL_NUM); return ms_aScriptWheelIds[nWheel];}
float GetWheelImpactOffset() const { return m_fWheelImpactOffset; }
float GetTyreLoad() const {return m_fTyreLoad;}
bool GetIsTouchingPavement() const { return GetDynamicFlags().IsFlagSet(WF_TOUCHING_PAVEMENT); }
bool IsMaterialIdPavement(phMaterialMgr::Id materialId) const;
bool IsMaterialIdTrainTrack(phMaterialMgr::Id materialId) const;
bool IsMaterialIdStairs(phMaterialMgr::Id materialId) const;
#if !__SPU
static Vector3 GetWheelOffset(CVehicleModelInfo* pVehicleModelInfo, eHierarchyId wheelId);
#endif // !__SPU
bool GetHasDummyTransition() const { return GetDynamicFlags().IsFlagSet(WF_DUMMY_TRANSITION); }
void EndDummyTransition() { GetDynamicFlags().ClearFlag(WF_DUMMY_TRANSITION); }
void StartDummyTransition();
void UpdateDummyTransitionCompression(float timeStep);
bool HasInnerWheel() const;
void SetSuspensionTargetRaiseAmount(float fSuspensionTargetRaise, float fAccelerationScale) { m_fSuspensionTargetRaiseAmount = fSuspensionTargetRaise; m_fSuspensionRaiseRate = fAccelerationScale; }
void SetSuspensionRaiseAmount(float fSuspensionRaise) { m_fSuspensionRaiseAmount = fSuspensionRaise; m_fSuspensionTargetRaiseAmount = fSuspensionRaise; m_fSuspensionRaiseRate = 1.0f; }
void SetSuspensionForwardOffset( float fForwardOffset ) { m_fSuspensionForwardOffset = fForwardOffset; }
float GetSuspensionRaiseAmount() { return m_fSuspensionRaiseAmount; }
float GetSuspensionTargetRaiseAmount() { return m_fSuspensionTargetRaiseAmount; }
float GetSuspensionRaiseRate() { return m_fSuspensionRaiseRate; }
eWheelHydraulicState GetSuspensionHydraulicState() { return m_WheelState; }
eWheelHydraulicState GetSuspensionHydraulicTargetState() { return m_WheelTargetState; }
void SetSuspensionHydraulicTargetState( eWheelHydraulicState targetState ) { m_WheelTargetState = targetState; }
void UpdateHydraulics( int timeStep );
bool UpdateHydraulicsFlags( CAutomobile* pAutomobile );
void UpdateDownforce();
void SetWheelInWater(bool bNewValue) { m_bIsWheelInWater = bNewValue; }
void SetExtraWheelDrag( float extraDrag ) { m_fExtraWheelDrag = extraDrag; }
float GetExtraWheelDrag() { return m_fExtraWheelDrag; }
private:
friend class CWheelIntegrator;
#if __DEV && !__SPU
void DrawForceLimits(float fCurrent, float fCurrentSpring, float fLoadForce, float fNormalLoad, bool bLateral, float fLoss=1.0f);
void DrawForceLimitsImproved(float fCurrentLat, float fCurrentLong, float fCurrentSpring, float fLoadForce, float fNormalLoad, float fLoss=1.0f);
#endif
#if __DEV
// This doesn't iterate.. it just draws the current impact's stuff
void DebugDrawSingleImpact(phCachedContactConstIterator& impact);
void DrawWheelImpact(const CVehicle & rParentVehicle, phCachedContactIterator & impacts, Color32 col1, Color32 col2, Color32 col3) const;
#endif
// Calculates last and current matrices in space of vehicle
// Note if wheels are not children of root bone then these matrices will need transforming into their parent's bone space
void CalcWheelMatrices(Mat34V_InOut lastWheelMatrixOut, Mat34V_InOut currentWheelMatrixOut, phCollider *pParentCollider);
float GetReduceGripMultiplier();
/////////////////
// vector description of this wheel
Vector3 m_vecAxleAxis; // axle axis vector (along right vector) without steering effect
Vector3 m_vecSuspensionAxis; // line of suspension travel
phSegment m_aWheelLines; // Min / Max of suspension probe lines;
////////////////
// intersection state
//phIntersection m_aWheelIntersections[NUM_WHEEL_PROBES]; // intersection point with ground
Vector3 m_vecHitPos;
Vector3 m_vecHitCentrePos;
Vector3 m_vecHitCentrePosOld; // previous intersection position
Vector3 m_vecHitNormal;
Vector3 m_vecHitPhysicalOffset;
Vector3 m_vecGroundVelocity;
Vector3 m_vecSolverForce;
////////////////
// saved stuff used for particles and audio
Vector3 m_vecGroundContactVelocity;
Vector3 m_vecTyreContactVelocity;
////////////////
// Vfx
CVfxDeepSurfaceInfo m_deepSurfaceInfo;
CVfxLiquidAttachInfo m_liquidAttachInfo;
float m_fOnFireTimer;
////////////////
// timers
u32 m_uLastPopTireCheck;
////////////////
// Dummy transition surface (for dummy->real)
float m_fPreviousTransitionCompression;
float m_fTransitionCompression;
////////////////
// config vars
eHierarchyId m_WheelId : 16; // which bone in the vehicle skeleton is this wheel attached to
s8 m_nFragChild[MAX_WHEEL_BOUNDS_PER_WHEEL];
s8 m_nOppositeWheelIndex; //index into m_ppWheel array for opposite wheel, -1 for no opposite wheel. Used for the antirollbar
float m_fWheelRadius; // radius of this wheel
float m_fWheelRimRadius;
float m_fInitialRimRadius;
float m_fWheelWidth;
CHandlingData* m_pHandling;
CVehicle* m_pParentVehicle;
float m_fSusLength;
float m_fMaxTravelDelta;
float m_fStaticDelta; // compression ratio vehicle should rest at
float m_fStaticForce;
float m_fFrontRearSelector;
float m_fMassMultForAccelerationInv; // a Mass multiplier used to just increase or decrease acceleration, for instance if a car had extra passengers in it
float m_fSuspensionTargetRaiseAmount;
float m_fSuspensionRaiseAmount;
float m_fSuspensionRaiseRate;
float m_fSuspensionForwardOffset;
eWheelHydraulicState m_WheelState;
eWheelHydraulicState m_WheelTargetState;
/////////////////
// current suspension state
float m_fCompression; // movement of suspension from static pos
float m_fCompressionOld;
float m_fWheelCompression; // movement of wheel from static pos (used for positioning rendered wheel)
/////////////////
// current wheel state
float m_fRotAng; // current rotation angle
float m_fRotAngVel; // current rotation angular velocity
float m_fRotSlipRatio;
float m_fTyreTemp;
////////////////
// intersection state
RegdPhy m_pHitPhysical; // entity wheel is touching
RegdPhy m_pPrevHitPhysical;
RegdPed m_pHitPed;
float m_fMaterialGrip;
float m_fMaterialWetLoss;
float m_fMaterialDrag;
float m_fMaterialTopSpeedMult;
float m_fGripMult; // this is the same for all wheels on the vehicle
// Sink this much further into the ground (compared to the rest of the car)
// e.g. soft mud, sand, snow etc.
float m_fExtraSinkDepth;
float m_fWheelImpactOffsetOriginal;
float m_fWheelImpactOffset;
////////////////
// saved stuff used for particles and audio
float m_fEffectiveSlipAngle;
float m_fTyreLoad;
float m_fFwdSlipAngle;
float m_fSideSlipAngle;
float m_fTyreCamberForce;
//////////////
// control inputs
float m_fSteerAngle; // input steer angle
float m_fBrakeForce; // input braking force
float m_fDriveForce; // input engine force
float m_fAbsTimer;
float m_fBrakeForceOld; // need these to integrate across smaller time steps
float m_fDriveForceOld;
float m_fFrictionDamage; // persistent var, will get increased with damage
float m_fSuspensionHealth; // 1000.0 = full, 500.0 = partially broken, 100.0 = totally broken, 0.0 = wheel falls off
float m_fTyreHealth; // 1000.0 = full, 500.0 = flat, 0.0 = tyre disintegrates
float m_fTyreWearRate;
float m_fMaxGripDiffFromWearRate;
float m_fWearRateScale;
float m_fBurstCheckTimer;
////////////////
// configuration and state flags
fwFlags32 m_nDynamicFlags;
fwFlags32 m_nConfigFlags;
u16 m_nHitComponent;
u8 m_nHitMaterialId; // we don't use anything other than the material index currently.
bool m_TyreBurstDueToWear;
public:
bool m_bSuspensionForceModified;
bool m_bHasDonkHydraulics;
bool m_bReduceLongSlipRatioWhenDamaged;
bool m_bIgnoreMaterialMaxSpeed;
private:
bool m_bIsWheelInWater;
bool m_bUpdateWheelRotation;
bool m_bDisableWheelForces;
bool m_bDisableBottomingOut;
bool m_IncreaseSuspensionForceWithSpeed;
bool m_ReduceSuspensionForce; //Reduced suspension force used to "stance" tuner pack vehicles
float m_fReducedGripMult;
float m_fExtraWheelDrag;
public:
float m_fDownforceMult; // Multiplier for the downforce for this wheel. Was previously determined based on the WCF_SPOILER flag.
#if __BANK
float m_fLastCalculatedTractionLoss;
#endif // #if __BANK
void SetReducedGripLevel( int reducedGripLevel );
void SetDisableWheelForces( bool disableWheelForces ) { m_bDisableWheelForces = disableWheelForces; }
void SetDisableBottomingOut( bool disableBottomingOut ) { m_bDisableBottomingOut = disableBottomingOut; }
bool GetDisableWheelForces() { return m_bDisableWheelForces; }
void SetIncreaseSuspensionForceWithSpeed( bool increaseSuspensionForce ) { m_IncreaseSuspensionForceWithSpeed = increaseSuspensionForce; }
void SetReducedSuspensionForce( const bool bReduceSuspensionForce ) { m_ReduceSuspensionForce = bReduceSuspensionForce; }
const bool GetReducedSuspensionForce() { return m_ReduceSuspensionForce; }
private:
// 2 bytes of padding
//////////////////
// statics
static eHierarchyId ms_aScriptWheelIds[SC_WHEEL_NUM];
public:
static bank_bool ms_bUseWheelIntegrationTask;
static dev_float ms_fWheelExtensionRate;
static bank_bool ms_bActivateWheelImpacts;
#if __BANK
static bank_bool ms_bDontCompressOnRecentlyBrokenFragments;
#endif
static bank_float ms_fWheelBurstDamageChance;
static bank_float ms_fFrictionDamageThreshForBurst;
static bank_float ms_fFrictionDamageThreshForBreak;
static dev_float ms_fWheelIndepRotMult;
static dev_float ms_fWheelIndepPivotDistCompression;
static dev_float ms_fWheelIndepPivotDistExtension;
//Air in tyre
static bank_float ms_fTyreTempHeatMult;
static bank_float ms_fTyreTempCoolMult;
static bank_float ms_fTyreTempCoolMovingMult;
static bank_float ms_fTyreTempBurstThreshold;
static dev_float ms_fDownforceMult;
static dev_float ms_fDownforceMultSpoiler;
static dev_float ms_fDownforceMultBikes;
static const eHierarchyId ms_HubComponents[VEH_WHEEL_RM3 - VEH_WHEEL_LF + 1];
static const eHierarchyId ms_OpposingWheels[VEH_WHEEL_RM3 - VEH_WHEEL_LF + 1];
static u32 uXmasWeather;
static phMaterialMgr::Id m_MaterialIdStuntTrack;
static dev_bool ms_bUseExtraWheelDownForce;
static dev_float GetReduceGripOnRimMultFront();
static dev_float GetReduceGripOnRimMultRear();
};
#if !__SPU
inline Vector3 CWheel::GetWheelOffset(CVehicleModelInfo* pVehicleModelInfo, eHierarchyId wheelId)
{
Assert(pVehicleModelInfo);
return VEC3V_TO_VECTOR3(pVehicleModelInfo->GetWheelOffset(wheelId));
}
#endif // !__SPU
inline float CWheel::GetTyreBurstSideRatio() const
{
return rage::Clamp(m_fSideSlipAngle, -1.0f, 1.0f);
}
#if VEHICLE_USE_INTEGRATION_FOR_WHEELS
#define INTEGRATION_MAX_NUM_WHEELS (10)
// Integration variables that are needed after integration on the main thread
// Anything in this class will be stored directly on CAutomobile
struct WheelIntegrationOutput
{
Vector3 vel;
};
// Extra data used during the integration process
struct WheelIntegrationLocals
{
WheelIntegrationOutput output;
Matrix34 mat;
Vector3 angVel;
Vector3 calcFwd[INTEGRATION_MAX_NUM_WHEELS];
Vector3 calcSide[INTEGRATION_MAX_NUM_WHEELS];
float aWheelAngSlip[INTEGRATION_MAX_NUM_WHEELS];
float compressionDelta[INTEGRATION_MAX_NUM_WHEELS];
};
struct WheelIntegrationState
{
WheelIntegrationState() : jobPending(0) {}
WheelIntegrationOutput output;
sysDependency dependency;
u32 jobPending;
};
struct WheelIntegrationDerivative
{
Vector3 vel;
Vector3 angVel;
Vector3 accel;
Vector3 angAccel;
float aWheelAngSlipDt[INTEGRATION_MAX_NUM_WHEELS];
Vector3 aWheelForce[INTEGRATION_MAX_NUM_WHEELS];
};
class CWheelIntegrator
{
public:
struct InternalState {
Vector3 m_vecAccelDueToGravity;
Vector3 m_vecInternalAccel;
Vector3 m_vecInternalAngAccel;
phCollider* m_pCollider;
CWheel* const* m_ppWheels;
int m_nNumWheels;
};
static void ProcessIntegration(phCollider* pCollider, CVehicle* pVehicle, WheelIntegrationState& state, float fTimeStep, unsigned frameCount);
static void ProcessIntegrationTask(phCollider* pCollider, const Vector3& vecInternalForce, const Vector3& vecInternalTorque, WheelIntegrationLocals& locals, CWheel* const* ppWheels, int nNumWheels, float fMaxVelInGear, int nGear, float fTimeStep, unsigned frameCount, float fGravity);
static void ProcessResultInternal(phCollider* pCollider, WheelIntegrationLocals& locals, CWheel* const* pWheels, int nNumWheels, float fMaxVelInGear, int nGear, float fTimeStep, unsigned frameCount, Vector3* pForceApplied, float fGravity);
#if !__SPU
static void ProcessResult(WheelIntegrationState& state, Vector3* pForceApplied);
static void ProcessResultsFinal(phCollider* pCollider, CWheel** ppWheels, int nNumWheels, ScalarV_In timeStep);
#endif // !__SPU
static void AddVelToMatrix(Matrix34& matResult, const Matrix34& matInit, const Vector3& vel, const Vector3& angVel, float dt);
static void WheelIntegrationEvaluate(WheelIntegrationDerivative &output,
WheelIntegrationLocals& initialLocals,
const WheelIntegrationTimeInfo& timeInfo,
float fDerivativeTimeStep,
const WheelIntegrationDerivative* pD,
InternalState& state,
const float fGravity );
private:
static bool RunFromDependency(const sysDependency& dependency);
static bool RunHoverModeFromDependancy(const sysDependency& dependency);
static void ApplyDifferentials( CWheel* const* ppWheels, int nNumWheels, float fMaxVelInGear, float fTimeStep );
// static phCollider* ms_pCollider;
// static CWheel* ms_pWheels;
// static int ms_nNumWheels;
static float ms_fDesiredIntegrationStepSize;
};
#if __PS3
class CWheelTaskInfo
{
public:
Vector3 vecInternalForce;
Vector3 vecInternalTorque;
float fTimeStep;
float gGameTimeStep;
phCollider* pCollider;
float fMaxVelInGear;
WheelIntegrationState* pIntegrationState;
float fGravity;
u8 gFrameCount; // Frame count is only used for ABS so doesn't matter if it loops round
u8 nNumWheels;
u8 nGear : 6;
bool bIsArticulated :1;
bool bIsBike :1;
};
#endif //VEHICLE_USE_INTEGRATION_FOR_WHEELS
#endif // __PS3
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#if !__SPU
class rmcInstanceWheelData;
#if __D3D11 || RSG_ORBIS
class CWheelInstanceData_UsageInfo : rmcInstanceData_ConstBufferUpdateDesc
{
public:
CWheelInstanceData_UsageInfo() { m_RegisterCounts[0] = 8; m_RegisterCounts[1] = 2; }
~CWheelInstanceData_UsageInfo() {};
u32 GetNoOfConstantBuffers() const { return 2; }
grmShaderGroupVar GetStartVariable(int index) const { return m_ShaderGroupVariables[index]; }
u32 GetRegisterCount(int index) const { return m_RegisterCounts[index]; };
private:
u32 m_RegisterCounts[2];
grmShaderGroupVar m_ShaderGroupVariables[2]; // matWheelTransform, tyreDeformParams & tyreDeformParams2.
friend class CWheelInstanceRenderer;
};
#endif //__D3D11 || RSG_ORBIS
//
//
//
//
class CWheelInstanceRenderer
{
public:
CWheelInstanceRenderer() { }
~CWheelInstanceRenderer() { }
public:
static bool Initialise();
static void Shutdown();
static void InitBeforeRender();
static void AddWheelModel(const Matrix34& childMatrix, const grmModel *pModel, const grmShaderGroup *pShaderGroup, s32 shaderBucket,
Vector4::Vector4Param tyreDeformParams, Vector4::Vector4Param tyreDeformParams2);
static void RenderAllWheels();
private:
static s32 ms_currInstanceIndices[NUMBER_OF_RENDER_THREADS];
static rmcInstanceWheelData* ms_pInstances[NUMBER_OF_RENDER_THREADS];
static atArray<datRef<const rmcInstanceDataBase> > ms_instArrays[NUMBER_OF_RENDER_THREADS];
#if __D3D11 || RSG_ORBIS
static CWheelInstanceData_UsageInfo ms_InstanceUsageInfos[NUMBER_OF_RENDER_THREADS];
static grcEffectGlobalVar ms_WheelTessellationVar;
#if __BANK
public:
#endif //__BANK
static int ms_WheelTessellationFactor;
static int ms_TreeTessellationFactor;
static float ms_TreeTessellation_PNTriangle_K;
#endif // __D3D11 || RSG_ORBIS
};
#endif //!__SPU...
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Inlined functions
__forceinline void CWheel::CalculateMaximumExtents(Mat34V_InOut lastWheelMatrixOut, Mat34V_InOut currentWheelMatrixOut, phCollider *pParentCollider)
{
float tempCompression = m_fCompression;
m_fCompression = 0;
CalcWheelMatrices(lastWheelMatrixOut,currentWheelMatrixOut,pParentCollider);
m_fCompression = tempCompression;
}
#endif//_WHEEL_H_...