diff --git a/include/engine_sim_application.h b/include/engine_sim_application.h index a81dad38..b79d4c23 100644 --- a/include/engine_sim_application.h +++ b/include/engine_sim_application.h @@ -26,6 +26,8 @@ #include "delta.h" #include "dtv.h" +#include "joystick.h" + #include class EngineSimApplication { @@ -151,6 +153,8 @@ class EngineSimApplication { bool m_paused; + Joystick j_Controller; + protected: void startRecording(); void updateScreenSizeStability(); diff --git a/include/joystick.h b/include/joystick.h new file mode 100644 index 00000000..8c5845ce --- /dev/null +++ b/include/joystick.h @@ -0,0 +1,73 @@ + +#ifndef ATG_ENGINE_SIM_JOYSTICK_H +#define ATG_ENGINE_SIM_JOYSTICK_H + +#include + +class Joystick +{ +public: + XINPUT_STATE GetState(); + int GetIndex(); + bool Alive(); + + void Update(); + void RefreshState(); + void Rumble(float a_fLM, float a_fRM); + + float LT(); + float RT(); + + bool buttonPressed(int j_iButton); + bool buttonDown(int j_iButton); + Joystick(); + Joystick(int j_iIndex); + +private: + XINPUT_STATE j_State; + int j_JoystickIndex; + + static const int button_count = 14; + bool bStates_prev[button_count]; + bool bStates[button_count]; + + bool b_ButtonsDown[button_count]; +}; + + + +static const WORD XINPUT_Buttons[] = { + XINPUT_GAMEPAD_A, + XINPUT_GAMEPAD_B, + XINPUT_GAMEPAD_X, + XINPUT_GAMEPAD_Y, + XINPUT_GAMEPAD_DPAD_UP, + XINPUT_GAMEPAD_DPAD_DOWN, + XINPUT_GAMEPAD_DPAD_LEFT, + XINPUT_GAMEPAD_DPAD_RIGHT, + XINPUT_GAMEPAD_LEFT_SHOULDER, + XINPUT_GAMEPAD_RIGHT_SHOULDER, + XINPUT_GAMEPAD_LEFT_THUMB, + XINPUT_GAMEPAD_RIGHT_THUMB, + XINPUT_GAMEPAD_START, + XINPUT_GAMEPAD_BACK +}; + +struct button_id +{ + button_id(); + + int A, B, X, Y; + + int d_up, d_down, d_left , d_right; + + int l_s, r_s; + + int l_th, r_th; + + int start; + int back; +}; +#endif /* ATG_ENGINE_SIM_JOYSTICK_H */ + +extern button_id j_Buttons; \ No newline at end of file diff --git a/src/engine_sim_application.cpp b/src/engine_sim_application.cpp index 3f679cfa..ff843657 100644 --- a/src/engine_sim_application.cpp +++ b/src/engine_sim_application.cpp @@ -81,6 +81,8 @@ EngineSimApplication::EngineSimApplication() { m_viewParameters.Layer1 = 0; m_displayAngle = 0.0f; + + j_Controller = Joystick(1); } EngineSimApplication::~EngineSimApplication() { @@ -671,6 +673,7 @@ void EngineSimApplication::processEngineInput() { return; } + j_Controller.Update(); const float dt = m_engine.GetFrameLength(); const bool fineControlMode = m_engine.IsKeyDown(ysKey::Code::Space); @@ -789,6 +792,9 @@ void EngineSimApplication::processEngineInput() { else if (fineControlMode && !fineControlInUse) { m_targetSpeedSetting = clamp(m_targetSpeedSetting + mouseWheelDelta * 0.0001); } + else if (j_Controller.Alive()) { + m_targetSpeedSetting = j_Controller.RT(); + } if (prevTargetThrottle != m_targetSpeedSetting) { m_infoCluster->setLogMessage("Speed control set to " + std::to_string(m_targetSpeedSetting)); @@ -813,7 +819,7 @@ void EngineSimApplication::processEngineInput() { m_infoCluster->setLogMessage("[,] - Set render layer to " + std::to_string(getViewParameters().Layer0)); } - if (m_engine.ProcessKeyDown(ysKey::Code::D)) { + if (m_engine.ProcessKeyDown(ysKey::Code::D) || j_Controller.buttonDown(j_Buttons.B)) { m_simulator.m_dyno.m_enabled = !m_simulator.m_dyno.m_enabled; const std::string msg = m_simulator.m_dyno.m_enabled @@ -822,7 +828,7 @@ void EngineSimApplication::processEngineInput() { m_infoCluster->setLogMessage(msg); } - if (m_engine.ProcessKeyDown(ysKey::Code::H)) { + if (m_engine.ProcessKeyDown(ysKey::Code::H) || j_Controller.buttonDown(j_Buttons.A)) { m_simulator.m_dyno.m_hold = !m_simulator.m_dyno.m_hold; const std::string msg = m_simulator.m_dyno.m_hold @@ -859,7 +865,9 @@ void EngineSimApplication::processEngineInput() { if (m_engine.IsKeyDown(ysKey::Code::S)) { m_simulator.m_starterMotor.m_enabled = true; } - else { + else if (j_Controller.Alive() && j_Controller.buttonPressed(j_Buttons.X)) { + m_simulator.m_starterMotor.m_enabled = true; + } else { m_simulator.m_starterMotor.m_enabled = false; } @@ -870,7 +878,7 @@ void EngineSimApplication::processEngineInput() { m_infoCluster->setLogMessage(msg); } - if (m_engine.ProcessKeyDown(ysKey::Code::A)) { + if (m_engine.ProcessKeyDown(ysKey::Code::A) || j_Controller.buttonDown(j_Buttons.Y)) { m_simulator.getEngine()->getIgnitionModule()->m_enabled = !m_simulator.getEngine()->getIgnitionModule()->m_enabled; @@ -880,13 +888,13 @@ void EngineSimApplication::processEngineInput() { m_infoCluster->setLogMessage(msg); } - if (m_engine.ProcessKeyDown(ysKey::Code::Up)) { + if (m_engine.ProcessKeyDown(ysKey::Code::Up) || j_Controller.buttonDown(j_Buttons.r_s)) { m_simulator.getTransmission()->changeGear(m_simulator.getTransmission()->getGear() + 1); m_infoCluster->setLogMessage( "UPSHIFTED TO " + std::to_string(m_simulator.getTransmission()->getGear() + 1)); } - else if (m_engine.ProcessKeyDown(ysKey::Code::Down)) { + else if (m_engine.ProcessKeyDown(ysKey::Code::Down) || j_Controller.buttonDown(j_Buttons.l_s)) { m_simulator.getTransmission()->changeGear(m_simulator.getTransmission()->getGear() - 1); if (m_simulator.getTransmission()->getGear() != -1) { @@ -908,10 +916,14 @@ void EngineSimApplication::processEngineInput() { m_targetClutchPressure = 0.0; m_infoCluster->setLogMessage("CLUTCH DEPRESSED"); } + else if (j_Controller.Alive()) { + m_targetClutchPressure = 1-j_Controller.LT(); + } else if (!m_engine.IsKeyDown(ysKey::Code::Y)) { m_targetClutchPressure = 1.0; } + m_targetClutchPressure = clamp(m_targetClutchPressure); double clutchRC = 0.001; @@ -922,6 +934,8 @@ void EngineSimApplication::processEngineInput() { const double clutch_s = dt / (dt + clutchRC); m_clutchPressure = m_clutchPressure * (1 - clutch_s) + m_targetClutchPressure * clutch_s; m_simulator.getTransmission()->setClutchPressure(m_clutchPressure); + + j_Controller.RefreshState(); } void EngineSimApplication::renderScene() { diff --git a/src/joystick.cpp b/src/joystick.cpp new file mode 100644 index 00000000..5fe21966 --- /dev/null +++ b/src/joystick.cpp @@ -0,0 +1,140 @@ +#include +#include "../include/joystick.h" + +#pragma comment(lib, "Xinput.lib") + +button_id j_Buttons; + +Joystick::Joystick() {}; + +Joystick::Joystick(int j_iIndex) { + j_JoystickIndex = j_iIndex - 1; + + for (int i = 0; i < button_count; i++) + { + bStates_prev[i] = false; + bStates[i] = false; + b_ButtonsDown[i] = false; + } +} + +XINPUT_STATE Joystick::GetState() { + + XINPUT_STATE js; + + memset(&js, 0, sizeof(XINPUT_STATE)); + + XInputGetState(j_JoystickIndex, &js); + + return js; +} + +int Joystick::GetIndex() { return j_JoystickIndex; } + +//Check if joystick is connected and working +bool Joystick::Alive() { + + memset(&j_State, 0, sizeof(XINPUT_STATE)); + + DWORD r = XInputGetState(j_JoystickIndex, &j_State); + + if (r == 0) + return true; + else + return false; +} + +//updates state of controller +//needs to be called before using any functions of controller +void Joystick::Update() { + j_State = GetState(); + + for (int i = 0; i < button_count; i++) + { + // Set button state for current frame + bStates[i] = (j_State.Gamepad.wButtons & + XINPUT_Buttons[i]) == XINPUT_Buttons[i]; + + // Set 'DOWN' state for current frame + b_ButtonsDown[i] = !bStates_prev[i] && + bStates[i]; + } +} + +//refreshes states of buttons. needs to be called at the end of use of controller +void Joystick::RefreshState() +{ + memcpy(bStates_prev, bStates, + sizeof(bStates_prev)); +} + +//get left trigger pull +float Joystick::LT() { + BYTE T = j_State.Gamepad.bLeftTrigger; + + if (T > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) { + return T / 255.0f; + } + return 0.0; +} + +//get right trigger pull +float Joystick::RT() { + BYTE T = j_State.Gamepad.bRightTrigger; + + if (T > XINPUT_GAMEPAD_TRIGGER_THRESHOLD) { + return T / 255.0f; + } + return 0.0; +} + +//vibrate controller, use 0,0 to cancel rumble +void Joystick::Rumble(float a_fLM, float a_fRM) { + XINPUT_VIBRATION VS; + + memset(&VS, 0, sizeof(XINPUT_VIBRATION)); + + int LM = int(a_fLM * 65535.0f); + int RM = int(a_fRM * 65535.0f); + + VS.wLeftMotorSpeed = LM; + VS.wRightMotorSpeed = RM; + + XInputSetState(j_JoystickIndex, &VS); +} + +//check if button is pressed. use this for single button checks +bool Joystick::buttonPressed(int j_iButton) { + if (j_State.Gamepad.wButtons & XINPUT_Buttons[j_iButton]) { + return true; + } + return false; + +} + +//check if button is down every frame +bool Joystick::buttonDown(int j_iButton) +{ + return b_ButtonsDown[j_iButton]; +} + +button_id::button_id() { + A = 0; + B = 1; + X = 2; + Y = 3; + + d_up = 4; + d_down = 5; + d_left = 6; + d_right = 7; + + l_s = 8; + r_s = 9; + + l_th = 10; + r_th = 11; + + start = 12; + back = 13; +} \ No newline at end of file