mirror of
https://github.com/thug1src/thug.git
synced 2024-11-30 12:06:44 +00:00
521 lines
14 KiB
C++
521 lines
14 KiB
C++
// SkaterPad.cpp
|
|
|
|
#include <sk\objects\skaterpad.h>
|
|
#include <gel\inpman.h>
|
|
#include <core\math.h>
|
|
|
|
//#define PS2_SIMULATING_XBOX
|
|
|
|
// The constructor of a skater pad just sets all the names
|
|
CSkaterPad::CSkaterPad()
|
|
{
|
|
// Note: These names must match those used when defining event queries in .q files.
|
|
// (Otherwise the queries won't work)
|
|
m_up.SetName("UP");
|
|
m_down.SetName("DOWN");
|
|
m_left.SetName("LEFT");
|
|
m_right.SetName("RIGHT");
|
|
m_square.SetName("SQUARE");
|
|
m_circle.SetName("CIRCLE");
|
|
m_triangle.SetName("TRIANGLE");
|
|
m_x.SetName("X");
|
|
m_L1.SetName("L1");
|
|
m_L2.SetName("L2");
|
|
m_L3.SetName("L3");
|
|
m_R1.SetName("R1");
|
|
m_R2.SetName("R2");
|
|
m_R3.SetName("R3");
|
|
m_start.SetName("START");
|
|
m_select.SetName("SELECT");
|
|
|
|
m_leftAnalogUpDebounceTime = 0;
|
|
m_leftAnalogDownDebounceTime = 0;
|
|
}
|
|
|
|
#ifdef __NOPT_ASSERT__
|
|
void CSkaterPad::Update ( Inp::Data* input, bool debug )
|
|
#else
|
|
void CSkaterPad::Update ( Inp::Data* input )
|
|
#endif
|
|
{
|
|
#ifdef __NOPT_ASSERT__
|
|
|
|
m_up.Update(input->m_Event[Inp::Data::vA_UP] ? 255 : 0, debug);
|
|
m_down.Update(input->m_Event[Inp::Data::vA_DOWN] ? 255 : 0, debug);
|
|
m_left.Update(input->m_Event[Inp::Data::vA_LEFT] ? 255 : 0, debug);
|
|
m_right.Update(input->m_Event[Inp::Data::vA_RIGHT] ? 255 : 0, debug);
|
|
|
|
m_square.Update(input->m_Event[Inp::Data::vA_SQUARE] ? 255 : 0, debug);
|
|
m_circle.Update(input->m_Event[Inp::Data::vA_CIRCLE] ? 255 : 0, debug);
|
|
m_x.Update(input->m_Event[Inp::Data::vA_X] ? 255 : 0, debug);
|
|
m_triangle.Update(input->m_Event[Inp::Data::vA_TRIANGLE] ? 255 : 0, debug);
|
|
|
|
m_L1.Update(input->m_Event[Inp::Data::vA_L1] ? 255 : 0, debug);
|
|
m_R1.Update(input->m_Event[Inp::Data::vA_R1] ? 255 : 0, debug);
|
|
|
|
#ifndef PS2_SIMULATING_XBOX
|
|
m_L2.Update(input->m_Event[Inp::Data::vA_L2] ? 255 : 0, debug);
|
|
m_R2.Update(input->m_Event[Inp::Data::vA_R2] ? 255 : 0, debug);
|
|
#else // update both 1 and 2 from L1/R1, to simulate the X-Box
|
|
m_L2.Update(input->m_Event[Inp::Data::vA_L1] ? 255 : 0, debug);
|
|
m_R2.Update(input->m_Event[Inp::Data::vA_R1] ? 255 : 0, debug);
|
|
#endif
|
|
|
|
m_L3.Update(input->m_Buttons & Inp::Data::mD_L3 ? 255 : 0, debug);
|
|
m_R3.Update(input->m_Buttons & Inp::Data::mD_R3 ? 255 : 0, debug);
|
|
|
|
|
|
m_select.Update(input->m_Buttons & Inp::Data::mD_SELECT ? 255 : 0, debug);
|
|
|
|
#else
|
|
|
|
m_up.Update(input->m_Event[Inp::Data::vA_UP] ? 255 : 0);
|
|
m_down.Update(input->m_Event[Inp::Data::vA_DOWN] ? 255 : 0);
|
|
m_left.Update(input->m_Event[Inp::Data::vA_LEFT] ? 255 : 0);
|
|
m_right.Update(input->m_Event[Inp::Data::vA_RIGHT] ? 255 : 0);
|
|
|
|
m_square.Update(input->m_Event[Inp::Data::vA_SQUARE] ? 255 : 0);
|
|
m_circle.Update(input->m_Event[Inp::Data::vA_CIRCLE] ? 255 : 0);
|
|
m_x.Update(input->m_Event[Inp::Data::vA_X] ? 255 : 0);
|
|
m_triangle.Update(input->m_Event[Inp::Data::vA_TRIANGLE] ? 255 : 0);
|
|
|
|
m_L1.Update(input->m_Event[Inp::Data::vA_L1] ? 255 : 0);
|
|
m_R1.Update(input->m_Event[Inp::Data::vA_R1] ? 255 : 0);
|
|
|
|
#ifndef PS2_SIMULATING_XBOX
|
|
m_L2.Update(input->m_Event[Inp::Data::vA_L2] ? 255 : 0);
|
|
m_R2.Update(input->m_Event[Inp::Data::vA_R2] ? 255 : 0);
|
|
#else // update both 1 and 2 from L1/R1, to simulate the X-Box
|
|
m_L2.Update(input->m_Event[Inp::Data::vA_L1] ? 255 : 0);
|
|
m_R2.Update(input->m_Event[Inp::Data::vA_R1] ? 255 : 0);
|
|
#endif
|
|
|
|
m_L3.Update(input->m_Buttons & Inp::Data::mD_L3 ? 255 : 0);
|
|
m_R3.Update(input->m_Buttons & Inp::Data::mD_R3 ? 255 : 0);
|
|
|
|
m_select.Update(input->m_Buttons & Inp::Data::mD_SELECT ? 255 : 0);
|
|
|
|
#endif
|
|
|
|
int in;
|
|
|
|
in = input->m_Event[Inp::Data::vA_RIGHT_X] - 128;
|
|
if (in == 0)
|
|
{
|
|
m_scaled_rightX = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
if (in == -128)
|
|
{
|
|
in = -127;
|
|
}
|
|
m_scaled_rightX = (in + (in > 0 ? -Inp::vANALOGUE_TOL : Inp::vANALOGUE_TOL)) / (127.0f - Inp::vANALOGUE_TOL);
|
|
}
|
|
|
|
in = input->m_Event[Inp::Data::vA_RIGHT_Y] - 128;
|
|
if (in == 0)
|
|
{
|
|
m_scaled_rightY = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
if (in == -128)
|
|
{
|
|
in = -127;
|
|
}
|
|
m_scaled_rightY = (in + (in > 0 ? -Inp::vANALOGUE_TOL : Inp::vANALOGUE_TOL)) / (127.0f - Inp::vANALOGUE_TOL);
|
|
}
|
|
|
|
in = input->m_Event[Inp::Data::vA_LEFT_X] - 128;
|
|
if (in == 0)
|
|
{
|
|
m_scaled_leftX = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
if (in == -128)
|
|
{
|
|
in = -127;
|
|
}
|
|
m_scaled_leftX = (in + (in > 0 ? -Inp::vANALOGUE_TOL : Inp::vANALOGUE_TOL)) / (127.0f - Inp::vANALOGUE_TOL);
|
|
}
|
|
|
|
in = input->m_Event[Inp::Data::vA_LEFT_Y] - 128;
|
|
if (in == 0)
|
|
{
|
|
m_scaled_leftY = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
if (in == -128)
|
|
{
|
|
in = -127;
|
|
}
|
|
m_scaled_leftY = (in + (in > 0 ? -Inp::vANALOGUE_TOL : Inp::vANALOGUE_TOL)) / (127.0f - Inp::vANALOGUE_TOL);
|
|
}
|
|
|
|
m_rightX = input->m_Event[Inp::Data::vA_RIGHT_X_UNCLAMPED] - 128;
|
|
m_rightY = input->m_Event[Inp::Data::vA_RIGHT_Y_UNCLAMPED] - 128;
|
|
m_leftX = input->m_Event[Inp::Data::vA_LEFT_X_UNCLAMPED] - 128;
|
|
m_leftY = input->m_Event[Inp::Data::vA_LEFT_Y_UNCLAMPED] - 128;
|
|
|
|
// Calculate the direction, and the amount
|
|
|
|
m_rightLength = sqrtf(m_rightX * m_rightX + m_rightY * m_rightY);
|
|
m_rightAngle = atan2f(m_rightX, -m_rightY);
|
|
|
|
m_leftLength = sqrtf(m_leftX * m_leftX + m_leftY * m_leftY);
|
|
if (m_leftLength > 0.001f)
|
|
{
|
|
m_leftAngle = atan2f(m_leftX, -m_leftY);
|
|
}
|
|
else
|
|
{
|
|
// if left analog stick not pressed, then get it from the D-Pad
|
|
bool Up;
|
|
bool Down;
|
|
bool Left;
|
|
bool Right;
|
|
Up = input->m_Event[Inp::Data::vA_UP];
|
|
Down = input->m_Event[Inp::Data::vA_DOWN];
|
|
Left = input->m_Event[Inp::Data::vA_LEFT];
|
|
Right = input->m_Event[Inp::Data::vA_RIGHT];
|
|
|
|
if (Up || Down || Left || Right)
|
|
{
|
|
m_leftAngle = sGetAngleFromDPad(Up, Down, Left, Right);
|
|
m_leftLength = 127.0f;
|
|
}
|
|
else
|
|
{
|
|
m_leftAngle = 0.0f;
|
|
m_leftLength = 0.0f;
|
|
}
|
|
}
|
|
|
|
if (m_leftAnalogUpDebounceTime)
|
|
{
|
|
// if not pressed, or debounce time expired
|
|
if (m_leftLength == 0.0f || !(Mth::Abs(m_leftAngle) < Mth::DegToRad(45.0f)))
|
|
{
|
|
m_leftAnalogUpDebounceTime = 0;
|
|
}
|
|
else if ((float)Tmr::GetTime() > m_leftAnalogUpDebounceTime)
|
|
{
|
|
m_leftAnalogUpDebounceTime = 0;
|
|
}
|
|
}
|
|
|
|
if (m_leftAnalogDownDebounceTime)
|
|
{
|
|
// if not pressed, or debounce time expired
|
|
if (m_leftLength == 0.0f || !((Mth::PI - Mth::Abs(m_leftAngle)) < Mth::DegToRad(45.0f)))
|
|
{
|
|
m_leftAnalogDownDebounceTime = 0;
|
|
}
|
|
else if ((float)Tmr::GetTime() > m_leftAnalogDownDebounceTime)
|
|
{
|
|
m_leftAnalogDownDebounceTime = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
CSkaterButton *CSkaterPad::GetButton(uint32 NameChecksum)
|
|
{
|
|
|
|
// Maybe optimize using a hash table later for speed.
|
|
if (m_up.GetName()==NameChecksum) return &m_up;
|
|
else if (m_down.GetName()==NameChecksum) return &m_down;
|
|
else if (m_left.GetName()==NameChecksum) return &m_left;
|
|
else if (m_right.GetName()==NameChecksum) return &m_right;
|
|
else if (m_square.GetName()==NameChecksum) return &m_square;
|
|
else if (m_circle.GetName()==NameChecksum) return &m_circle;
|
|
else if (m_triangle.GetName()==NameChecksum) return &m_triangle;
|
|
else if (m_x.GetName()==NameChecksum) return &m_x;
|
|
else if (m_L1.GetName()==NameChecksum) return &m_L1;
|
|
else if (m_L2.GetName()==NameChecksum) return &m_L2;
|
|
else if (m_L3.GetName()==NameChecksum) return &m_L3;
|
|
else if (m_R1.GetName()==NameChecksum) return &m_R1;
|
|
else if (m_R2.GetName()==NameChecksum) return &m_R2;
|
|
else if (m_R3.GetName()==NameChecksum) return &m_R3;
|
|
else if (m_start.GetName()==NameChecksum) return &m_start;
|
|
else if (m_select.GetName()==NameChecksum) return &m_select;
|
|
else
|
|
{
|
|
Dbg_MsgAssert(0,("Bad checksum '%x' sent to GetButton",NameChecksum));
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
float CSkaterPad::GetScaledAnalogStickMagnitude ( float analog_x, float analog_y, float analog_angle )
|
|
{
|
|
float x = analog_x / (analog_x > 0.0f ? 127.0f : 128.0f);
|
|
float y = analog_y / (analog_y > 0.0f ? 127.0f : 128.0f);
|
|
|
|
#ifndef __PLAT_NGC__
|
|
|
|
float angle;
|
|
if (analog_angle > (-Mth::PI / 4.0f) && analog_angle < (Mth::PI / 4.0f))
|
|
{
|
|
// top quadrant
|
|
angle = analog_angle;
|
|
}
|
|
else if (analog_angle > (Mth::PI / 4.0f) && analog_angle < (3.0f * Mth::PI / 4.0f))
|
|
{
|
|
// right quadrant
|
|
angle = analog_angle - (Mth::PI / 2.0f);
|
|
}
|
|
else if (Mth::Abs(analog_angle) > (3.0f * Mth::PI / 4.0f))
|
|
{
|
|
// bottom quadrant
|
|
angle = Mth::Abs(analog_angle) - Mth::PI;
|
|
}
|
|
else
|
|
{
|
|
// left quadrant
|
|
angle = analog_angle + (Mth::PI / 2.0f);
|
|
}
|
|
|
|
return sqrtf(x * x + y * y) * Mth::Abs(cosf(angle));
|
|
|
|
#else
|
|
|
|
return sqrtf(x * x + y * y);
|
|
|
|
#endif
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
uint32 CSkaterPad::GetPressedMask( void )
|
|
{
|
|
uint32 mask;
|
|
|
|
mask = 0;
|
|
|
|
if( m_up.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_UP;
|
|
}
|
|
if( m_down.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_DOWN;
|
|
}
|
|
if( m_left.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_LEFT;
|
|
}
|
|
if( m_right.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_RIGHT;
|
|
}
|
|
if( m_L1.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_L1;
|
|
}
|
|
if( m_L2.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_L2;
|
|
}
|
|
if( m_R1.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_R1;
|
|
}
|
|
if( m_R2.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_R2;
|
|
}
|
|
if( m_circle.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_CIRCLE;
|
|
}
|
|
if( m_square.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_SQUARE;
|
|
}
|
|
if( m_triangle.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_TRIANGLE;
|
|
}
|
|
if( m_x.GetPressed())
|
|
{
|
|
mask |= Inp::Data::mA_X;
|
|
}
|
|
|
|
return mask;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
// Given the pressed state of the four cardinal directions
|
|
// then return a sensible value including diagonals
|
|
// given that we might be pressing opposing directions (Up+Down)
|
|
// and we still want to get some sensible response
|
|
// Here Up+Down is mapped to PAD_D
|
|
// all mapping where there is some conflict needing resolution are
|
|
// marked with an asterix
|
|
uint32 CSkaterPad::sGetDirection(bool Up, bool Down, bool Left, bool Right)
|
|
{
|
|
int Dir = Up + (Down << 1) + (Left << 2) + (Right << 3);
|
|
|
|
static uint DirectionMap[16] =
|
|
{
|
|
// RLDU
|
|
0, // 0000
|
|
PAD_U, // 0001
|
|
PAD_D, // 0010
|
|
PAD_D, // 0011 *
|
|
PAD_L, // 0100
|
|
PAD_UL, // 0101
|
|
PAD_DL, // 0110
|
|
PAD_DL, // 0111 *
|
|
PAD_R, // 1000
|
|
PAD_UR, // 1001
|
|
PAD_DR, // 1010
|
|
PAD_DR, // 1011 *
|
|
PAD_R, // 1100 *
|
|
PAD_UR, // 1101 *
|
|
PAD_DR, // 1110 *
|
|
PAD_DR, // 1111 *
|
|
};
|
|
|
|
return DirectionMap[Dir];
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
#define PAD_ANGLE_U ( 0.0f )
|
|
#define PAD_ANGLE_UR ( Mth::PI / 4.0f)
|
|
#define PAD_ANGLE_R ( Mth::PI / 2.0f)
|
|
#define PAD_ANGLE_DR ( Mth::PI * 3.0f / 4.0f)
|
|
#define PAD_ANGLE_D ( Mth::PI )
|
|
#define PAD_ANGLE_DL ( - Mth::PI * 3.0f / 4.0f)
|
|
#define PAD_ANGLE_L ( - Mth::PI / 2.0f )
|
|
#define PAD_ANGLE_UL ( - Mth::PI / 4.0f)
|
|
|
|
float CSkaterPad::sGetAngleFromDPad(bool Up, bool Down, bool Left, bool Right)
|
|
{
|
|
int Dir = Up + (Down << 1) + (Left << 2) + (Right << 3);
|
|
|
|
static float DirectionMap[16] =
|
|
{
|
|
// RLDU
|
|
0.0f, // 0000
|
|
PAD_ANGLE_U, // 0001
|
|
PAD_ANGLE_D, // 0010
|
|
PAD_ANGLE_D, // 0011 *
|
|
PAD_ANGLE_L, // 0100
|
|
PAD_ANGLE_UL, // 0101
|
|
PAD_ANGLE_DL, // 0110
|
|
PAD_ANGLE_DL, // 0111 *
|
|
PAD_ANGLE_R, // 1000
|
|
PAD_ANGLE_UR, // 1001
|
|
PAD_ANGLE_DR, // 1010
|
|
PAD_ANGLE_DR, // 1011 *
|
|
PAD_ANGLE_R, // 1100 *
|
|
PAD_ANGLE_UR, // 1101 *
|
|
PAD_ANGLE_DR, // 1110 *
|
|
PAD_ANGLE_DR, // 1111 *
|
|
};
|
|
|
|
return DirectionMap[Dir];
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CSkaterPad::Zero ( )
|
|
{
|
|
m_up.Update( 0 );
|
|
m_down.Update( 0 );
|
|
m_left.Update( 0 );
|
|
m_right.Update( 0 );
|
|
m_L1.Update( 0 );
|
|
m_L2.Update( 0 );
|
|
m_L3.Update( 0 );
|
|
m_R1.Update( 0 );
|
|
m_R2.Update( 0 );
|
|
m_R3.Update( 0 );
|
|
m_square.Update( 0 );
|
|
m_circle.Update( 0 );
|
|
m_x.Update( 0 );
|
|
m_triangle.Update( 0 );
|
|
m_start.Update( 0 );
|
|
m_select.Update( 0 );
|
|
|
|
m_rightX = 0.0f;
|
|
m_rightY = 0.0f;
|
|
m_leftX = 0.0f;
|
|
m_leftY = 0.0f;
|
|
|
|
m_scaled_rightX = 0.0f;
|
|
m_scaled_rightY = 0.0f;
|
|
m_scaled_leftX = 0.0f;
|
|
m_scaled_leftY = 0.0f;
|
|
|
|
m_rightAngle = 0.0f;
|
|
m_rightLength = 0.0f;
|
|
m_leftAngle = 0.0f;
|
|
m_leftLength = 0.0f;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CSkaterPad::Reset ( )
|
|
{
|
|
Zero();
|
|
|
|
m_up.ClearTrigger( );
|
|
m_up.ClearRelease( );
|
|
m_down.ClearTrigger( );
|
|
m_down.ClearRelease( );
|
|
m_left.ClearTrigger( );
|
|
m_left.ClearRelease( );
|
|
m_right.ClearTrigger( );
|
|
m_right.ClearRelease( );
|
|
m_L1.ClearTrigger( );
|
|
m_L1.ClearRelease( );
|
|
m_L2.ClearTrigger( );
|
|
m_L2.ClearRelease( );
|
|
m_L3.ClearTrigger( );
|
|
m_L3.ClearRelease( );
|
|
m_R1.ClearTrigger( );
|
|
m_R1.ClearRelease( );
|
|
m_R2.ClearTrigger( );
|
|
m_R2.ClearTrigger( );
|
|
m_R3.ClearRelease( );
|
|
m_R3.ClearRelease( );
|
|
m_square.ClearTrigger( );
|
|
m_square.ClearRelease( );
|
|
m_circle.ClearTrigger( );
|
|
m_circle.ClearRelease( );
|
|
m_x.ClearTrigger( );
|
|
m_x.ClearRelease( );
|
|
m_triangle.ClearTrigger( );
|
|
m_triangle.ClearRelease( );
|
|
m_start.ClearTrigger( );
|
|
m_start.ClearRelease( );
|
|
m_select.ClearTrigger( );
|
|
m_select.ClearRelease( );
|
|
}
|