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

354 lines
12 KiB
C++

//
// name: pad.h
// description: class handling pad input
#ifndef INC_PAD_H_
#define INC_PAD_H_
// Rage headers
#include "atl/array.h"
#include "input/pad.h"
#include "output/padactuatordevice.h"
//#include "vector/matrix34.h"
#define MAX_VIBRATION_FREQUENCY (256.0f) // 256 based on old SA value - could probably stick with it as the level guys are used to it, but may be better as a % value
#define MAX_VIBRATION_DROP_RATIO (0.8f)
#define MIN_VIBRATION_DROP (10)
#define USE_ACTUATOR_EFFECTS 1
#include "system/PadGestures.h"
#include "system/TouchPadGestures.h"
namespace rage {
class ioActuatorEffect;
class ioPad;
class Quaternion;
}
//
// name: CController
// description: Class returning state of controller
class CPad
{
friend class CControlMgr;
public:
CPad();
void SetPlayerNum(s32 num);
void Update();
void UpdateActuatorsAndShakes();
void Clear();
bool HasInput();
s32 GetPressedButtons();
s32 GetDebugButtons();
s32 GetPressedDebugButtons();
#if RSG_ORBIS
struct TouchPoint
{
u16 x;
u16 y;
};
#endif // RSG_ORBIS
struct CPadState
{
s32 m_leftX;
s32 m_leftY;
s32 m_rightX;
s32 m_rightY;
s32 m_l1;
s32 m_l2;
s32 m_l3;
s32 m_r1;
s32 m_r2;
s32 m_r3;
s32 m_square;
s32 m_triangle;
s32 m_circle;
s32 m_cross;
s32 m_dpadUp;
s32 m_dpadDown;
s32 m_dpadLeft;
s32 m_dpadRight;
s32 m_start;
s32 m_select;
s32 m_touchClick;
#if __PPU
// Motion sensors (PS3 Specific)
// Values defined at top of header
// XYZ give acceleration
// Equilibrium = 512 (no accel)
// Sensitivity = 113 counts/G
s32 m_sensorX; // +ve X is right of pad's face
s32 m_sensorY; // +ve Y is out of pad's face
s32 m_sensorZ; // +ve Z is down from pad's face
// Yaw angular vel
// Zero velocity = 512
// Sensitivity = 123 counts / 90 deg
s32 m_sensorG;
#endif
#if RSG_ORBIS
TouchPoint m_TouchOne;
TouchPoint m_TouchTwo;
u8 m_TouchIdOne;
u8 m_TouchIdTwo;
u8 m_NumTouches;
#endif // RSG_ORBIS
void Update(ioPad* pPad);
void Clear();
};
s32 GetLeftStickX() { return m_state.m_leftX;}
s32 GetLeftStickY() { return m_state.m_leftY;}
s32 GetRightStickX() { return m_state.m_rightX; }
s32 GetRightStickY() { return m_state.m_rightY; }
s32 GetDPadUp() { return m_state.m_dpadUp; }
s32 GetDPadDown() { return m_state.m_dpadDown; }
s32 GetDPadLeft() { return m_state.m_dpadLeft; }
s32 GetDPadRight() { return m_state.m_dpadRight; }
s32 GetStart() { return m_state.m_start; }
s32 GetSelect() { return m_state.m_select; }
s32 GetTouchClick() { return m_state.m_touchClick; }
s32 GetButtonSquare() { return m_state.m_square; }
s32 GetButtonTriangle() { return m_state.m_triangle; }
s32 GetButtonCross() { return m_state.m_cross; }
s32 GetButtonCircle() { return m_state.m_circle; }
s32 GetLeftShoulder1() { return m_state.m_l1;}
s32 GetLeftShoulder2() { return m_state.m_l2; }
s32 GetShockButtonL() { return m_state.m_l3; }
s32 GetRightShoulder1() { return m_state.m_r1; }
s32 GetRightShoulder2() { return m_state.m_r2; }
s32 GetShockButtonR() { return m_state.m_r3; }
bool LeftStickXJustActivated() { return (m_state.m_leftX && !m_oldState.m_leftX); }
bool LeftStickYJustActivated() { return (m_state.m_leftY && !m_oldState.m_leftY); }
bool RightStickXJustActivated() { return (m_state.m_rightX && !m_oldState.m_rightX); }
bool RightStickYJustActivated() { return (m_state.m_rightY && !m_oldState.m_rightY); }
bool StartJustDown() { return (m_state.m_start && !m_oldState.m_start);}
bool StartJustUp() { return (!m_state.m_start && m_oldState.m_start);}
bool SelectJustDown() { return (m_state.m_select && !m_oldState.m_select); }
bool SelectJustUp() { return (!m_state.m_select && m_oldState.m_select); }
bool ButtonSquareJustDown() { return (m_state.m_square && !m_oldState.m_square);}
bool ButtonSquareJustUp() { return (!m_state.m_square && m_oldState.m_square);}
bool ButtonTriangleJustDown() { return (m_state.m_triangle && !m_oldState.m_triangle);}
bool ButtonTriangleJustUp() { return (!m_state.m_triangle && m_oldState.m_triangle);}
bool ButtonCrossJustDown() { return (m_state.m_cross && !m_oldState.m_cross);}
bool ButtonCrossJustUp() { return (!m_state.m_cross && m_oldState.m_cross);}
bool ButtonCircleJustDown() { return (m_state.m_circle && !m_oldState.m_circle);}
bool ButtonCircleJustUp() { return (!m_state.m_circle && m_oldState.m_circle);}
bool LeftShoulder1JustDown() { return (m_state.m_l1 && !m_oldState.m_l1);}
bool LeftShoulder1JustUp() { return (!m_state.m_l1 && m_oldState.m_l1);}
bool LeftShoulder2JustDown() { return (m_state.m_l2 && !m_oldState.m_l2);}
bool LeftShoulder2JustUp() { return (!m_state.m_l2 && m_oldState.m_l2);}
bool ShockButtonLJustDown() { return (m_state.m_l3 && !m_oldState.m_l3);}
bool ShockButtonLJustUp() { return (!m_state.m_l3 && m_oldState.m_l3);}
bool RightShoulder1JustDown() { return (m_state.m_r1 && !m_oldState.m_r1);}
bool RightShoulder1JustUp() { return (!m_state.m_r1 && m_oldState.m_r1);}
bool RightShoulder2JustDown() { return (m_state.m_r2 && !m_oldState.m_r2);}
bool RightShoulder2JustUp() { return (!m_state.m_r2 && m_oldState.m_r2);}
bool ShockButtonRJustDown() { return (m_state.m_r3 && !m_oldState.m_r3);}
bool ShockButtonRJustUp() { return (!m_state.m_r3 && m_oldState.m_r3);}
bool TouchClickJustDown() { return (m_state.m_touchClick && !m_oldState.m_touchClick);}
bool TouchClickJustUp() { return (!m_state.m_touchClick && m_oldState.m_touchClick);}
bool DPadUpJustDown() { return (m_state.m_dpadUp && !m_oldState.m_dpadUp);}
bool DPadUpJustUp() { return (!m_state.m_dpadUp && m_oldState.m_dpadUp);}
bool DPadDownJustDown() { return (m_state.m_dpadDown && !m_oldState.m_dpadDown);}
bool DPadDownJustUp() { return (!m_state.m_dpadDown && m_oldState.m_dpadDown);}
bool DPadLeftJustDown() { return (m_state.m_dpadLeft && !m_oldState.m_dpadLeft);}
bool DPadLeftJustUp() { return (!m_state.m_dpadLeft && m_oldState.m_dpadLeft);}
bool DPadRightJustDown() { return (m_state.m_dpadRight && !m_oldState.m_dpadRight);}
bool DPadRightJustUp() { return (!m_state.m_dpadRight && m_oldState.m_dpadRight);}
#if USE_ACTUATOR_EFFECTS
void ApplyActuatorEffect(ioActuatorEffect* effect, bool isScriptCommand, s32 suppressedId, u32 delayAfterThisOne);
void ApplyActuatorEffect(ioActuatorEffect* effect, bool isScriptCommand, s32 suppressedId);
void ApplyActuatorEffect(ioActuatorEffect* effect, bool isScriptCommand);
void ApplyActuatorEffect(ioActuatorEffect* effect);
#else
// pad shake
void StartShake(u32 Duration0, s32 MotorFrequency0 = 0, u32 Duration1 = 0, s32 MotorFrequency1 = 0, s32 DelayAfterThisOne = 0, s32 suppressedId = -1);
void StartShake_Distance(u32 Duration, s32 Frequency, float X, float Y, float Z);
void StartShake_Train(float X, float Y);
#if HAS_TRIGGER_RUMBLE
void StartTriggerShake(u32 LeftDuration, s32 LeftMotorFrequency, u32 RightDuration, s32 RightMotorFrequency, s32 suppressedId = -1);
#endif // HAS_TRIGGER_RUMBLE
void SetScriptShake(bool fromScript) { m_bIsScriptShake = fromScript; }
#endif // USE_ACTUATOR_EFFECTS
void StopShaking(bool bForce = false);
bool IsShaking();
void NoMoreShake() { m_bShakeStoped = true; }
void AllowShake() { m_bShakeStoped = false; }
bool IsPreventedFromShaking() { return m_bShakeStoped; }
const static s32 NO_SUPPRESS = -1;
void SetSuppressedId(s32 uniqueId) { m_suppressedId = uniqueId; }
static bool IsIntercepted() { return ioPad::IsIntercepted(); }
bool IsConnected( PPU_ONLY(bool bIgnoreWasConnected = false) );
bool IsXBox360Pad() const;
bool IsXBox360CompatiblePad() const;
bool IsPs3Pad() const;
bool IsPs4Pad() const;
bool HasSensors() const;
#if USE_SIXAXIS_GESTURES
CPadGesture* GetPadGesture() { return HasSensors() ? &m_PadGesture : NULL; }
#endif
#if __PPU
// SIXAXIS
// Raw pad data
s32 GetSensorX(){ return m_state.m_sensorX; }
s32 GetSensorY(){ return m_state.m_sensorY; }
s32 GetSensorZ(){ return m_state.m_sensorZ; }
s32 GetSensorG(){ return m_state.m_sensorG; }
// Normalised data.
// xyz accel in Gs
// ang vel G in deg / s
float GetSensorXf(){ return (m_state.m_sensorX - MOTION_SENSOR_ZERO_COUNT)/(float)MOTION_SENSOR_ACCEL_SENSITIVTY;}
float GetSensorYf(){ return (m_state.m_sensorY - MOTION_SENSOR_ZERO_COUNT)/(float)MOTION_SENSOR_ACCEL_SENSITIVTY;}
float GetSensorZf(){ return (m_state.m_sensorZ - MOTION_SENSOR_ZERO_COUNT)/(float)MOTION_SENSOR_ACCEL_SENSITIVTY;}
float GetSensorGf(){ return 90.0f*(m_state.m_sensorG - MOTION_SENSOR_ZERO_COUNT)/(float)MOTION_SENSOR_ANG_VEL_SENSITIVITY;}
#endif
#if RSG_ORBIS
bool GetOrientation(Quaternion& result) const { if (m_pPad) { result = m_pPad->GetOrientation(); return true; } return false; }
void ResetOrientation() { if (m_pPad) { m_pPad->ResetOrientation(); } }
bool GetAcceleration(Vector3& acceleration) const { if (m_pPad) { acceleration = m_pPad->GetAcceleration(); return true; } return false; }
u8 GetNumTouches() const { return m_state.m_NumTouches; }
u8 GetTouchId(int index) const { return (index == 0) ? m_state.m_TouchIdOne : m_state.m_TouchIdTwo; }
void GetTouchPoint(int index, u16& x, u16& y);
const CTouchPadGesture& GetTouchPadGesture() { return m_TouchPadGesture; }
bool IsRemotePlayPad() const { if (m_pPad) { return m_pPad->IsRemotePlayPad(); } return false; }
bool HasBeenConnected() const { if (m_pPad) { return m_pPad->HasBeenConnected(); } return false; }
#endif // RSG_ORBIS
u32 GetTimeInMilliseconds();
void PrintDebug();
private:
void UpdateFromPad(CPad& pad) {m_oldState = m_state; m_state = pad.m_state;}
const static u32 MAX_SHAKE_ENTRIES = 32;
const static u32 MAX_SCRIPT_SHAKE_ENTRIES = 4;
#if USE_ACTUATOR_EFFECTS
struct ActuatorEntry
{
ActuatorEntry();
ioActuatorEffect* m_pEffect;
u32 m_StartTime;
};
atFixedArray<ActuatorEntry, MAX_SHAKE_ENTRIES> m_ActuatorEffects;
atFixedArray<ActuatorEntry, MAX_SCRIPT_SHAKE_ENTRIES> m_ScriptActuatorEffects;
ioPadActuatorDevice m_Actuator;
void UpdateActuatorEffects();
void RemoveExpiredActuatorEffects();
#else
// Rumble entry
struct RumbleEntry
{
RumbleEntry() { m_iStartTime = m_iDuration = 0; }
u32 m_iStartTime; // The start time
u32 m_iDuration;
s32 m_Freq;
u32 m_IsScript:1;
};
int FindSmallestShake(atFixedArray <RumbleEntry, MAX_SHAKE_ENTRIES> &rumbleEntries);
int FindLargestShake(atFixedArray <RumbleEntry, MAX_SHAKE_ENTRIES> &rumbleEntries);
RumbleEntry *FindScriptEntry(atFixedArray <RumbleEntry, MAX_SHAKE_ENTRIES> &rumbleEntries);
void PushNewShake(atFixedArray <RumbleEntry, MAX_SHAKE_ENTRIES> &rumbleEntries, s32 Frequency, u32 Duration);
void RegisterShake(atFixedArray <RumbleEntry, MAX_SHAKE_ENTRIES> &rumbleEntries, s32 Frequency, u32 Duration);
void RemoveLeastImportantShakes();
void RemoveExpiredShakes();
RumbleEntry *FindCurrentShake(int actID);
void UpdateShakes();
atFixedArray<RumbleEntry, MAX_SHAKE_ENTRIES> m_RumbleEntries[ioPad::MAX_ACTUATORS];
bool m_bIsScriptShake;
s32 m_noShakeFreq; // Don't shake if the frequency is lower than this? (only obeyed by one func)
#endif // USE_ACTUATOR_EFFECTS
ioPad* m_pPad;
CPadState m_state;
CPadState m_oldState;
// pad rumble
float m_DeathRumbleScaler;
bool m_bIsShaking;
bool m_bShakeStoped; // Stop shaking after the current shake has completed flag?
u32 m_noShakeBeforeThis; // Presumably a don't shake until this time? (only obeyed by one func)
s32 m_suppressedId; // If the ID passed to StartPadShake == this ID, then don't register the command (only obeyed by one func)
#if __PPU
bool m_WasConnected;
#endif
#if USE_SIXAXIS_GESTURES
CPadGesture m_PadGesture;
#endif
#if RSG_ORBIS
CTouchPadGesture m_TouchPadGesture;
#endif // RSG_ORBIS
};
#if USE_ACTUATOR_EFFECTS
inline CPad::ActuatorEntry::ActuatorEntry()
: m_pEffect(NULL)
, m_StartTime(0u)
{
}
inline void CPad::ApplyActuatorEffect(ioActuatorEffect* effect)
{
ApplyActuatorEffect(effect, false, NO_SUPPRESS, 0);
}
inline void CPad::ApplyActuatorEffect(ioActuatorEffect* effect, bool isScriptCommand)
{
ApplyActuatorEffect(effect, isScriptCommand, NO_SUPPRESS, 0);
}
inline void CPad::ApplyActuatorEffect(ioActuatorEffect* effect, bool isScriptCommand, s32 suppressedId)
{
ApplyActuatorEffect(effect, isScriptCommand, suppressedId, 0);
}
#endif // USE_ACTUATOR_EFFECTS
#endif // INC_PAD_H_