From c89ddf8cba9c6b19d59e2db1896292797163c54c Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Fri, 29 Mar 2019 14:39:48 -0500 Subject: [PATCH] WiimoteEmu: Allow shake frequency and intensity to be configured. Other minor cleanups. --- Source/Core/Core/CMakeLists.txt | 1 - .../Core/Core/Config/WiimoteInputSettings.cpp | 33 ------ .../Core/Core/Config/WiimoteInputSettings.h | 31 ----- Source/Core/Core/Core.vcxproj | 2 - Source/Core/Core/Core.vcxproj.filters | 8 +- Source/Core/Core/HW/WiimoteEmu/Dynamics.cpp | 106 +++++------------- Source/Core/Core/HW/WiimoteEmu/Dynamics.h | 36 +----- .../Core/HW/WiimoteEmu/EmuSubroutines.cpp | 4 +- .../Core/HW/WiimoteEmu/Extension/Nunchuk.cpp | 36 ++---- .../Core/HW/WiimoteEmu/Extension/Nunchuk.h | 13 +-- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 58 ++-------- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h | 13 +-- Source/Core/Core/State.cpp | 2 +- .../Config/Mapping/MappingIndicator.cpp | 89 +++++++++++++++ .../Config/Mapping/MappingIndicator.h | 20 +++- .../Config/Mapping/MappingWidget.cpp | 17 ++- .../ControllerEmu/ControlGroup/ControlGroup.h | 11 +- .../ControllerEmu/ControlGroup/Cursor.cpp | 3 +- .../ControllerEmu/ControlGroup/Force.cpp | 68 ++++++++++- .../ControllerEmu/ControlGroup/Force.h | 24 ++++ .../ControlGroup/MixedTriggers.cpp | 13 +-- .../ControllerEmu/ControlGroup/Slider.cpp | 5 +- .../ControllerEmu/ControlGroup/Triggers.cpp | 2 +- .../InputCommon/ControllerEmu/StickGate.cpp | 3 +- 24 files changed, 285 insertions(+), 313 deletions(-) delete mode 100644 Source/Core/Core/Config/WiimoteInputSettings.cpp delete mode 100644 Source/Core/Core/Config/WiimoteInputSettings.h diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 645bb876a7..0cda183141 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -30,7 +30,6 @@ add_library(core Config/NetplaySettings.cpp Config/SYSCONFSettings.cpp Config/UISettings.cpp - Config/WiimoteInputSettings.cpp ConfigLoaders/BaseConfigLoader.cpp ConfigLoaders/GameConfigLoader.cpp ConfigLoaders/IsSettingSaveable.cpp diff --git a/Source/Core/Core/Config/WiimoteInputSettings.cpp b/Source/Core/Core/Config/WiimoteInputSettings.cpp deleted file mode 100644 index 69a094a3f5..0000000000 --- a/Source/Core/Core/Config/WiimoteInputSettings.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2018 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "Core/Config/WiimoteInputSettings.h" - -namespace Config -{ -// Configuration Information - -// WiimoteInput.Settings - -const ConfigInfo WIIMOTE_INPUT_SHAKE_INTENSITY_HARD{{System::WiiPad, "Shake", "Hard"}, 5.0}; -const ConfigInfo WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM{{System::WiiPad, "Shake", "Medium"}, - 3.0}; -const ConfigInfo WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT{{System::WiiPad, "Shake", "Soft"}, 2.0}; - -// Dynamic settings -const ConfigInfo WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_HARD{ - {System::WiiPad, "Dynamic_Shake", "FramesHeldHard"}, 45}; -const ConfigInfo WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_SOFT{ - {System::WiiPad, "Dynamic_Shake", "FramesHeldSoft"}, 15}; -const ConfigInfo WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_LENGTH{ - {System::WiiPad, "Dynamic_Shake", "FrameCount"}, 30}; - -// NunchuckInput.Settings -const ConfigInfo NUNCHUK_INPUT_SHAKE_INTENSITY_HARD{ - {System::WiiPad, "Nunchuk_Shake", "Hard"}, 5.0}; -const ConfigInfo NUNCHUK_INPUT_SHAKE_INTENSITY_MEDIUM{ - {System::WiiPad, "Nunchuk_Shake", "Medium"}, 3.0}; -const ConfigInfo NUNCHUK_INPUT_SHAKE_INTENSITY_SOFT{ - {System::WiiPad, "Nunchuk_Shake", "Soft"}, 2.0}; -} // namespace Config diff --git a/Source/Core/Core/Config/WiimoteInputSettings.h b/Source/Core/Core/Config/WiimoteInputSettings.h deleted file mode 100644 index 78c22b8b1b..0000000000 --- a/Source/Core/Core/Config/WiimoteInputSettings.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2018 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include "Common/Config/Config.h" - -namespace Config -{ -// Configuration Information - -// WiimoteInput.Settings -extern const ConfigInfo WIIMOTE_INPUT_SHAKE_INTENSITY_HARD; -extern const ConfigInfo WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM; -extern const ConfigInfo WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT; - -// Below settings are for dynamic input only (based on how long the user holds a button) -extern const ConfigInfo - WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_HARD; // How long button held constitutes a hard shake -extern const ConfigInfo - WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_SOFT; // How long button held constitutes a soft shake -extern const ConfigInfo - WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_LENGTH; // How long to execute a shake - -// NunchuckInput.Settings -extern const ConfigInfo NUNCHUK_INPUT_SHAKE_INTENSITY_HARD; -extern const ConfigInfo NUNCHUK_INPUT_SHAKE_INTENSITY_MEDIUM; -extern const ConfigInfo NUNCHUK_INPUT_SHAKE_INTENSITY_SOFT; - -} // namespace Config diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 8a6b08adfc..bd56b220ae 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -56,7 +56,6 @@ - @@ -327,7 +326,6 @@ - diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 7955ded024..35b9e5d7a5 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -874,9 +874,6 @@ Config - - Config - @@ -1592,9 +1589,6 @@ Config - - Config - HW %28Flipper/Hollywood%29\Wiimote\Emu @@ -1638,4 +1632,4 @@ - \ No newline at end of file + diff --git a/Source/Core/Core/HW/WiimoteEmu/Dynamics.cpp b/Source/Core/Core/HW/WiimoteEmu/Dynamics.cpp index b2af4d671f..7fac29e9b9 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Dynamics.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Dynamics.cpp @@ -8,8 +8,6 @@ #include "Common/MathUtil.h" #include "Core/Config/SYSCONFSettings.h" -#include "Core/Config/WiimoteInputSettings.h" -#include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "InputCommon/ControllerEmu/ControlGroup/Buttons.h" #include "InputCommon/ControllerEmu/ControlGroup/Cursor.h" @@ -18,11 +16,6 @@ namespace { -constexpr int SHAKE_FREQ = 6; -// Frame count of one up/down shake -// < 9 no shake detection in "Wario Land: Shake It" -constexpr int SHAKE_STEP_MAX = ::Wiimote::UPDATE_FREQ / SHAKE_FREQ; - // Given a velocity, acceleration, and maximum jerk value, // calculate change in position after a stop in the shortest possible time. // Used to smoothly adjust acceleration and come to complete stops at precise positions. @@ -61,81 +54,32 @@ double CalculateStopDistance(double velocity, double max_accel) namespace WiimoteEmu { -Common::Vec3 EmulateShake(ControllerEmu::Buttons* const buttons_group, const double intensity, - u8* const shake_step) +void EmulateShake(PositionalState* state, ControllerEmu::Shake* const shake_group, + float time_elapsed) { - // shake is a bitfield of X,Y,Z shake button states - static const unsigned int btns[] = {0x01, 0x02, 0x04}; - unsigned int shake = 0; - buttons_group->GetState(&shake, btns); - - Common::Vec3 accel; - - for (std::size_t i = 0; i != accel.data.size(); ++i) + auto target_position = shake_group->GetState() * shake_group->GetIntensity() / 2; + for (std::size_t i = 0; i != target_position.data.size(); ++i) { - if (shake & (1 << i)) + if (state->velocity.data[i] * std::copysign(1.f, target_position.data[i]) < 0 || + state->position.data[i] / target_position.data[i] > 0.5) { - accel.data[i] = std::sin(MathUtil::TAU * shake_step[i] / SHAKE_STEP_MAX) * intensity * - GRAVITY_ACCELERATION; - shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX; - } - else - { - shake_step[i] = 0; + target_position.data[i] *= -1; } } - return accel; -} + // Time from "top" to "bottom" of one shake. + const auto travel_time = 1 / shake_group->GetFrequency() / 2; -Common::Vec3 EmulateDynamicShake(DynamicData& dynamic_data, - ControllerEmu::Buttons* const buttons_group, - const DynamicConfiguration& config, u8* const shake_step) -{ - // shake is a bitfield of X,Y,Z shake button states - static const unsigned int btns[] = {0x01, 0x02, 0x04}; - unsigned int shake = 0; - buttons_group->GetState(&shake, btns); - - Common::Vec3 accel; - - for (std::size_t i = 0; i != accel.data.size(); ++i) + Common::Vec3 jerk; + for (std::size_t i = 0; i != target_position.data.size(); ++i) { - if ((shake & (1 << i)) && dynamic_data.executing_frames_left[i] == 0) - { - dynamic_data.timing[i]++; - } - else if (dynamic_data.executing_frames_left[i] > 0) - { - accel.data[i] = std::sin(MathUtil::TAU * shake_step[i] / SHAKE_STEP_MAX) * - dynamic_data.intensity[i] * GRAVITY_ACCELERATION; - shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX; - dynamic_data.executing_frames_left[i]--; - } - else if (shake == 0 && dynamic_data.timing[i] > 0) - { - if (dynamic_data.timing[i] > config.frames_needed_for_high_intensity) - { - dynamic_data.intensity[i] = config.high_intensity; - } - else if (dynamic_data.timing[i] < config.frames_needed_for_low_intensity) - { - dynamic_data.intensity[i] = config.low_intensity; - } - else - { - dynamic_data.intensity[i] = config.med_intensity; - } - dynamic_data.timing[i] = 0; - dynamic_data.executing_frames_left[i] = config.frames_to_execute; - } - else - { - shake_step[i] = 0; - } + const auto half_distance = + std::max(std::abs(target_position.data[i]), std::abs(state->position.data[i])); + + jerk.data[i] = half_distance / std::pow(travel_time / 2, 3); } - return accel; + ApproachPositionWithJerk(state, target_position, jerk, time_elapsed); } void EmulateTilt(RotationalState* state, ControllerEmu::Tilt* const tilt_group, float time_elapsed) @@ -158,8 +102,8 @@ void EmulateSwing(MotionState* state, ControllerEmu::Force* swing_group, float t // Note. Y/Z swapped because X/Y axis to the swing_group is X/Z to the wiimote. // X is negated because Wiimote X+ is to the left. - ApproachPositionWithJerk(state, {-target.x, -target.z, target.y}, swing_group->GetMaxJerk(), - time_elapsed); + ApproachPositionWithJerk(state, {-target.x, -target.z, target.y}, + Common::Vec3{1, 1, 1} * swing_group->GetMaxJerk(), time_elapsed); // Just jump to our target angle scaled by our progress to the target position. // TODO: If we wanted to be less hacky we could use ApproachAngleWithAccel. @@ -248,19 +192,19 @@ void ApproachAngleWithAccel(RotationalState* state, const Common::Vec3& angle_ta } void ApproachPositionWithJerk(PositionalState* state, const Common::Vec3& position_target, - float max_jerk, float time_elapsed) + const Common::Vec3& max_jerk, float time_elapsed) { const auto stop_distance = - Common::Vec3(CalculateStopDistance(state->velocity.x, state->acceleration.x, max_jerk), - CalculateStopDistance(state->velocity.y, state->acceleration.y, max_jerk), - CalculateStopDistance(state->velocity.z, state->acceleration.z, max_jerk)); + Common::Vec3(CalculateStopDistance(state->velocity.x, state->acceleration.x, max_jerk.x), + CalculateStopDistance(state->velocity.y, state->acceleration.y, max_jerk.y), + CalculateStopDistance(state->velocity.z, state->acceleration.z, max_jerk.z)); const auto offset = position_target - state->position; const auto stop_offset = offset - stop_distance; - const Common::Vec3 jerk{std::copysign(max_jerk, stop_offset.x), - std::copysign(max_jerk, stop_offset.y), - std::copysign(max_jerk, stop_offset.z)}; + const Common::Vec3 jerk{std::copysign(max_jerk.x, stop_offset.x), + std::copysign(max_jerk.y, stop_offset.y), + std::copysign(max_jerk.z, stop_offset.z)}; state->acceleration += jerk * time_elapsed; diff --git a/Source/Core/Core/HW/WiimoteEmu/Dynamics.h b/Source/Core/Core/HW/WiimoteEmu/Dynamics.h index 2788c95131..0316c9ec34 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Dynamics.h +++ b/Source/Core/Core/HW/WiimoteEmu/Dynamics.h @@ -17,15 +17,6 @@ namespace WiimoteEmu { constexpr double GRAVITY_ACCELERATION = 9.80665; -// Used for dynamic shake -// TODO: kill this. -struct DynamicData -{ - std::array timing; // Hold length in frames for each axis - std::array intensity; // Swing or shake intensity - std::array executing_frames_left; // Number of frames to execute the intensity operation -}; - struct PositionalState { Common::Vec3 position; @@ -47,34 +38,13 @@ struct MotionState : PositionalState, RotationalState // Build a rotational matrix from euler angles. Common::Matrix33 GetRotationalMatrix(const Common::Vec3& angle); -void ApproachPositionWithJerk(PositionalState* state, const Common::Vec3& target, float max_jerk, - float time_elapsed); +void ApproachPositionWithJerk(PositionalState* state, const Common::Vec3& target, + const Common::Vec3& max_jerk, float time_elapsed); void ApproachAngleWithAccel(RotationalState* state, const Common::Vec3& target, float max_accel, float time_elapsed); -// Used for dynamic shake. -// This is used to pass in data that defines the dynamic action -// TODO: kill this -struct DynamicConfiguration -{ - double low_intensity; - int frames_needed_for_low_intensity; - - double med_intensity; - // Frames needed for med intensity can be calculated between high & low - - double high_intensity; - int frames_needed_for_high_intensity; - - int frames_to_execute; // How many frames should we execute the action for? -}; - -Common::Vec3 EmulateShake(ControllerEmu::Buttons* buttons_group, double intensity, u8* shake_step); - -Common::Vec3 EmulateDynamicShake(DynamicData& dynamic_data, ControllerEmu::Buttons* buttons_group, - const DynamicConfiguration& config, u8* shake_step); - +void EmulateShake(PositionalState* state, ControllerEmu::Shake* shake_group, float time_elapsed); void EmulateTilt(RotationalState* state, ControllerEmu::Tilt* tilt_group, float time_elapsed); void EmulateSwing(MotionState* state, ControllerEmu::Force* swing_group, float time_elapsed); diff --git a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp index a3c8b507cc..d1fa9bd968 100644 --- a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp @@ -584,9 +584,7 @@ void Wiimote::DoState(PointerWrap& p) // Dynamics p.Do(m_swing_state); p.Do(m_tilt_state); - - // TODO: clean this up: - p.Do(m_shake_step); + p.Do(m_shake_state); p.DoMarker("Wiimote"); } diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp index 12aee5c615..9389ee046d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp @@ -12,7 +12,6 @@ #include "Common/Common.h" #include "Common/CommonTypes.h" #include "Common/MathUtil.h" -#include "Core/Config/WiimoteInputSettings.h" #include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" @@ -50,24 +49,10 @@ Nunchuk::Nunchuk() : EncryptedExtension(_trans("Nunchuk")) // tilt groups.emplace_back(m_tilt = new ControllerEmu::Tilt(_trans("Tilt"))); - // shake - groups.emplace_back(m_shake = new ControllerEmu::Buttons(_trans("Shake"))); - // i18n: Refers to a 3D axis (used when mapping motion controls) - m_shake->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::Translate, _trans("X"))); - // i18n: Refers to a 3D axis (used when mapping motion controls) - m_shake->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::Translate, _trans("Y"))); - // i18n: Refers to a 3D axis (used when mapping motion controls) - m_shake->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::Translate, _trans("Z"))); - - groups.emplace_back(m_shake_soft = new ControllerEmu::Buttons("ShakeSoft")); - m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "X")); - m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y")); - m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z")); - - groups.emplace_back(m_shake_hard = new ControllerEmu::Buttons("ShakeHard")); - m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "X")); - m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y")); - m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z")); + // Shake + // Inverse the default intensity so shake is opposite that of wiimote. + // This is needed by DKCR for proper shake action detection. + groups.emplace_back(m_shake = new ControllerEmu::Shake(_trans("Shake"), -1)); } void Nunchuk::Update() @@ -104,6 +89,7 @@ void Nunchuk::Update() // Acceleration data: EmulateSwing(&m_swing_state, m_swing, 1.f / ::Wiimote::UPDATE_FREQ); EmulateTilt(&m_tilt_state, m_tilt, 1.f / ::Wiimote::UPDATE_FREQ); + EmulateShake(&m_shake_state, m_shake, 1.f / ::Wiimote::UPDATE_FREQ); const auto transformation = GetRotationalMatrix(-m_tilt_state.angle) * GetRotationalMatrix(-m_swing_state.angle); @@ -112,12 +98,7 @@ void Nunchuk::Update() Common::Vec3(0, 0, float(GRAVITY_ACCELERATION))); // shake - accel += EmulateShake(m_shake, Config::Get(Config::NUNCHUK_INPUT_SHAKE_INTENSITY_MEDIUM), - m_shake_step.data()); - accel += EmulateShake(m_shake_soft, Config::Get(Config::NUNCHUK_INPUT_SHAKE_INTENSITY_SOFT), - m_shake_soft_step.data()); - accel += EmulateShake(m_shake_hard, Config::Get(Config::NUNCHUK_INPUT_SHAKE_INTENSITY_HARD), - m_shake_hard_step.data()); + accel += m_shake_state.acceleration; // Calibration values are 8-bit but we want 10-bit precision, so << 2. const auto acc = ConvertAccelData(accel, ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2); @@ -203,6 +184,7 @@ void Nunchuk::DoState(PointerWrap& p) p.Do(m_swing_state); p.Do(m_tilt_state); + p.Do(m_shake_state); } void Nunchuk::LoadDefaults(const ControllerInterface& ciface) @@ -227,5 +209,9 @@ void Nunchuk::LoadDefaults(const ControllerInterface& ciface) m_buttons->SetControlExpression(0, "Control_L"); // C m_buttons->SetControlExpression(1, "Shift_L"); // Z #endif + + // Shake + for (int i = 0; i < 3; ++i) + m_shake->SetControlExpression(i, "Click 2"); } } // namespace WiimoteEmu diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h index a542b7ebc2..35fd615475 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h @@ -101,23 +101,14 @@ public: private: ControllerEmu::Tilt* m_tilt; - ControllerEmu::Force* m_swing; - - ControllerEmu::Buttons* m_shake; - ControllerEmu::Buttons* m_shake_soft; - ControllerEmu::Buttons* m_shake_hard; - + ControllerEmu::Shake* m_shake; ControllerEmu::Buttons* m_buttons; ControllerEmu::AnalogStick* m_stick; // Dynamics: MotionState m_swing_state; RotationalState m_tilt_state; - - // TODO: kill - std::array m_shake_step{}; - std::array m_shake_soft_step{}; - std::array m_shake_hard_step{}; + PositionalState m_shake_state; }; } // namespace WiimoteEmu diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 084d290327..0bbb208fde 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -17,7 +17,6 @@ #include "Common/MsgHandler.h" #include "Core/Config/SYSCONFSettings.h" -#include "Core/Config/WiimoteInputSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/Wiimote.h" @@ -130,11 +129,7 @@ void Wiimote::Reset() // Dynamics: m_swing_state = {}; m_tilt_state = {}; - - m_shake_step = {}; - m_shake_soft_step = {}; - m_shake_hard_step = {}; - m_shake_dynamic_data = {}; + m_shake_state = {}; } Wiimote::Wiimote(const unsigned int index) : m_index(index) @@ -159,31 +154,7 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index) groups.emplace_back(m_tilt = new ControllerEmu::Tilt(_trans("Tilt"))); // shake - groups.emplace_back(m_shake = new ControllerEmu::Buttons(_trans("Shake"))); - // i18n: Refers to a 3D axis (used when mapping motion controls) - m_shake->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::Translate, _trans("X"))); - // i18n: Refers to a 3D axis (used when mapping motion controls) - m_shake->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::Translate, _trans("Y"))); - // i18n: Refers to a 3D axis (used when mapping motion controls) - m_shake->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::Translate, _trans("Z"))); - - groups.emplace_back(m_shake_soft = new ControllerEmu::Buttons("ShakeSoft")); - m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "X")); - m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y")); - m_shake_soft->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z")); - - groups.emplace_back(m_shake_hard = new ControllerEmu::Buttons("ShakeHard")); - m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "X")); - m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y")); - m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z")); - - groups.emplace_back(m_shake_dynamic = new ControllerEmu::Buttons("Shake Dynamic")); - m_shake_dynamic->controls.emplace_back( - new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "X")); - m_shake_dynamic->controls.emplace_back( - new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Y")); - m_shake_dynamic->controls.emplace_back( - new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z")); + groups.emplace_back(m_shake = new ControllerEmu::Shake(_trans("Shake"))); // extension groups.emplace_back(m_attachments = new ControllerEmu::Attachments(_trans("Extension"))); @@ -687,6 +658,7 @@ void Wiimote::StepDynamics() { EmulateSwing(&m_swing_state, m_swing, 1.f / ::Wiimote::UPDATE_FREQ); EmulateTilt(&m_tilt_state, m_tilt, 1.f / ::Wiimote::UPDATE_FREQ); + EmulateShake(&m_shake_state, m_shake, 1.f / ::Wiimote::UPDATE_FREQ); // TODO: Move cursor state out of ControllerEmu::Cursor // const auto cursor_mtx = EmulateCursorMovement(m_ir); @@ -710,24 +682,7 @@ Common::Vec3 Wiimote::GetAcceleration() GetTransformation().Transform( m_swing_state.acceleration + Common::Vec3(0, 0, float(GRAVITY_ACCELERATION)), 0); - DynamicConfiguration shake_config; - shake_config.low_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT); - shake_config.med_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM); - shake_config.high_intensity = Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_HARD); - shake_config.frames_needed_for_high_intensity = - Config::Get(Config::WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_HARD); - shake_config.frames_needed_for_low_intensity = - Config::Get(Config::WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_SOFT); - shake_config.frames_to_execute = Config::Get(Config::WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_LENGTH); - - accel += EmulateShake(m_shake, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM), - m_shake_step.data()); - accel += EmulateShake(m_shake_soft, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT), - m_shake_soft_step.data()); - accel += EmulateShake(m_shake_hard, Config::Get(Config::WIIMOTE_INPUT_SHAKE_INTENSITY_HARD), - m_shake_hard_step.data()); - accel += EmulateDynamicShake(m_shake_dynamic_data, m_shake_dynamic, shake_config, - m_shake_dynamic_step.data()); + accel += m_shake_state.acceleration; return accel; } @@ -735,9 +690,10 @@ Common::Vec3 Wiimote::GetAcceleration() Common::Matrix44 Wiimote::GetTransformation() const { // Includes positional and rotational effects of: - // IR, Swing, Tilt + // IR, Swing, Tilt, Shake - return Common::Matrix44::FromMatrix33(GetRotationalMatrix(-m_tilt_state.angle) * + return Common::Matrix44::Translate(-m_shake_state.position) * + Common::Matrix44::FromMatrix33(GetRotationalMatrix(-m_tilt_state.angle) * GetRotationalMatrix(-m_swing_state.angle)) * EmulateCursorMovement(m_ir) * Common::Matrix44::Translate(-m_swing_state.position); } diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index 68a56fd26c..fd505abf3d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -222,10 +222,7 @@ private: // Control groups for user input: ControllerEmu::Buttons* m_buttons; ControllerEmu::Buttons* m_dpad; - ControllerEmu::Buttons* m_shake; - ControllerEmu::Buttons* m_shake_soft; - ControllerEmu::Buttons* m_shake_hard; - ControllerEmu::Buttons* m_shake_dynamic; + ControllerEmu::Shake* m_shake; ControllerEmu::Cursor* m_ir; ControllerEmu::Tilt* m_tilt; ControllerEmu::Force* m_swing; @@ -270,12 +267,6 @@ private: // Dynamics: MotionState m_swing_state; RotationalState m_tilt_state; - - // TODO: kill these: - std::array m_shake_step{}; - std::array m_shake_soft_step{}; - std::array m_shake_hard_step{}; - std::array m_shake_dynamic_step{}; - DynamicData m_shake_dynamic_data; + PositionalState m_shake_state; }; } // namespace WiimoteEmu diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 5063f9ed9a..920ee474d3 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -74,7 +74,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 106; // Last changed in PR 7984 +static const u32 STATE_VERSION = 107; // Last changed in PR 7952 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list, diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp index 1d297922b8..3d8bf1c68b 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp @@ -514,6 +514,95 @@ void MappingIndicator::paintEvent(QPaintEvent*) Settings::Instance().SetControllerStateNeeded(false); } +ShakeMappingIndicator::ShakeMappingIndicator(ControllerEmu::Shake* group) + : MappingIndicator(group), m_shake_group(*group) +{ +} + +void ShakeMappingIndicator::paintEvent(QPaintEvent*) +{ + Settings::Instance().SetControllerStateNeeded(true); + DrawShake(); + Settings::Instance().SetControllerStateNeeded(false); +} + +void ShakeMappingIndicator::DrawShake() +{ + constexpr std::size_t HISTORY_COUNT = INDICATOR_UPDATE_FREQ; + + WiimoteEmu::EmulateShake(&m_motion_state, &m_shake_group, 1.f / INDICATOR_UPDATE_FREQ); + + constexpr float MAX_DISTANCE = 0.5f; + + m_position_samples.push_front(m_motion_state.position / MAX_DISTANCE); + // This also holds the current state so +1. + if (m_position_samples.size() > HISTORY_COUNT + 1) + m_position_samples.pop_back(); + + // Bounding box size: + const double scale = height() / 2.5; + + QPainter p(this); + p.translate(width() / 2, height() / 2); + + // Bounding box. + p.setBrush(BBOX_BRUSH_COLOR); + p.setPen(BBOX_PEN_COLOR); + p.drawRect(-scale - 1, -scale - 1, scale * 2 + 1, scale * 2 + 1); + + // UI y-axis is opposite that of acceleration Z. + p.scale(1.0, -1.0); + + // Enable AA after drawing bounding box. + p.setRenderHint(QPainter::Antialiasing, true); + p.setRenderHint(QPainter::SmoothPixmapTransform, true); + + // Deadzone. + p.setPen(DEADZONE_COLOR); + p.setBrush(DEADZONE_BRUSH); + p.drawRect(-scale, 0, scale * 2, m_shake_group.GetDeadzone() * scale); + + // Raw input. + const auto raw_coord = m_shake_group.GetState(false); + p.setPen(Qt::NoPen); + p.setBrush(RAW_INPUT_COLOR); + for (std::size_t c = 0; c != raw_coord.data.size(); ++c) + { + p.drawEllipse(QPointF{-0.5 + c * 0.5, raw_coord.data[c]} * scale, INPUT_DOT_RADIUS, + INPUT_DOT_RADIUS); + } + + // Grid line. + if (m_grid_line_position || + std::any_of(m_position_samples.begin(), m_position_samples.end(), + [](const Common::Vec3& v) { return v.LengthSquared() != 0.0; })) + { + // Only start moving the line if there's non-zero data. + m_grid_line_position = (m_grid_line_position + 1) % HISTORY_COUNT; + } + const double grid_line_x = 1.0 - m_grid_line_position * 2.0 / HISTORY_COUNT; + p.setPen(RAW_INPUT_COLOR); + p.drawLine(QPointF{grid_line_x, -1.0} * scale, QPointF{grid_line_x, 1.0} * scale); + + // Position history. + const QColor component_colors[] = {Qt::red, Qt::green, Qt::blue}; + p.setBrush(Qt::NoBrush); + for (std::size_t c = 0; c != raw_coord.data.size(); ++c) + { + QPolygonF polyline; + + int i = 0; + for (auto& sample : m_position_samples) + { + polyline.append(QPointF{1.0 - i * 2.0 / HISTORY_COUNT, sample.data[c]} * scale); + ++i; + } + + p.setPen(component_colors[c]); + p.drawPolyline(polyline); + } +} + void MappingIndicator::DrawCalibration(QPainter& p, Common::DVec2 point) { // TODO: Ugly magic number used in a few places in this file. diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.h b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.h index 0952fa3537..f5670db0c6 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.h +++ b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.h @@ -7,6 +7,8 @@ #include #include +#include + #include "Core/HW/WiimoteEmu/Dynamics.h" #include "InputCommon/ControllerEmu/StickGate.h" @@ -31,6 +33,9 @@ public: void SetCalibrationWidget(CalibrationWidget* widget); +protected: + WiimoteEmu::MotionState m_motion_state{}; + private: void DrawCursor(ControllerEmu::Cursor& cursor); void DrawReshapableInput(ControllerEmu::ReshapableInput& stick); @@ -45,8 +50,21 @@ private: ControllerEmu::ControlGroup* const m_group; CalibrationWidget* m_calibration_widget{}; +}; - WiimoteEmu::MotionState m_motion_state{}; +class ShakeMappingIndicator : public MappingIndicator +{ +public: + explicit ShakeMappingIndicator(ControllerEmu::Shake* group); + + void DrawShake(); + void paintEvent(QPaintEvent*) override; + +private: + std::deque m_position_samples; + int m_grid_line_position = 0; + + ControllerEmu::Shake& m_shake_group; }; class CalibrationWidget : public QToolButton diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp index 1e968c2ed2..257b9008c5 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp @@ -85,7 +85,8 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con group->type == ControllerEmu::GroupType::Stick || group->type == ControllerEmu::GroupType::Tilt || group->type == ControllerEmu::GroupType::MixedTriggers || - group->type == ControllerEmu::GroupType::Force; + group->type == ControllerEmu::GroupType::Force || + group->type == ControllerEmu::GroupType::Shake; const bool need_calibration = group->type == ControllerEmu::GroupType::Cursor || group->type == ControllerEmu::GroupType::Stick || @@ -129,7 +130,19 @@ QGroupBox* MappingWidget::CreateGroupBox(const QString& name, ControllerEmu::Con if (need_indicator) { - auto const indicator = new MappingIndicator(group); + MappingIndicator* indicator; + + switch (group->type) + { + case ControllerEmu::GroupType::Shake: + indicator = new ShakeMappingIndicator(static_cast(group)); + break; + + default: + indicator = new MappingIndicator(group); + break; + } + connect(this, &MappingWidget::Update, indicator, QOverload<>::of(&MappingIndicator::update)); if (need_calibration) diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h index 30798b9b4d..146dc16fcb 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h @@ -4,8 +4,10 @@ #pragma once +#include #include #include +#include #include #include "Common/CommonTypes.h" @@ -35,7 +37,8 @@ enum class GroupType Tilt, Cursor, Triggers, - Slider + Slider, + Shake, }; class ControlGroup @@ -64,6 +67,12 @@ public: void AddDeadzoneSetting(SettingValue* value, double maximum_deadzone); + template + static T ApplyDeadzone(T input, std::common_type_t deadzone) + { + return std::copysign(std::max(T{0}, std::abs(input) - deadzone) / (T{1} - deadzone), input); + } + const std::string name; const std::string ui_name; const GroupType type; diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp index f4123154d0..5818f35d87 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp @@ -104,8 +104,7 @@ Cursor::StateData Cursor::GetState(const bool adjusted) const double max_z_step = STEP_Z_PER_SEC / 1000.0 * ms_since_update; // Apply deadzone to z: - const ControlState deadzone = GetDeadzonePercentage(); - z = std::copysign(std::max(0.0, std::abs(z) - deadzone) / (1.0 - deadzone), z); + z = ApplyDeadzone(z, GetDeadzonePercentage()); // Smooth out z movement: // FYI: Not using relative input for Z. diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.cpp index 715ae89b5a..93a9d06cb3 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.cpp @@ -71,8 +71,7 @@ Force::StateData Force::GetState(bool adjusted) if (adjusted) { // Apply deadzone to z. - const ControlState deadzone = GetDeadzonePercentage(); - z = std::copysign(std::max(0.0, std::abs(z) - deadzone) / (1.0 - deadzone), z); + z = ApplyDeadzone(z, GetDeadzonePercentage()); } return {float(state.x), float(state.y), float(z)}; @@ -105,4 +104,69 @@ ControlState Force::GetDefaultInputRadiusAtAngle(double) const return 1.0; } +Shake::Shake(const std::string& name_, ControlState default_intensity_scale) + : ControlGroup(name_, name_, GroupType::Shake) +{ + // i18n: Refers to a 3D axis (used when mapping motion controls) + controls.emplace_back(new ControllerEmu::Input(ControllerEmu::Translate, _trans("X"))); + // i18n: Refers to a 3D axis (used when mapping motion controls) + controls.emplace_back(new ControllerEmu::Input(ControllerEmu::Translate, _trans("Y"))); + // i18n: Refers to a 3D axis (used when mapping motion controls) + controls.emplace_back(new ControllerEmu::Input(ControllerEmu::Translate, _trans("Z"))); + + AddDeadzoneSetting(&m_deadzone_setting, 50); + + // Total travel distance in centimeters. + // Negative values can be used to reverse the initial direction of movement. + AddSetting(&m_intensity_setting, + // i18n: Refers to the intensity of shaking an emulated wiimote. + {_trans("Intensity"), + // i18n: The symbol/abbreviation for centimeters. + _trans("cm"), + // i18n: Refering to emulated wii remote movement. + _trans("Total travel distance.")}, + 10 * default_intensity_scale, -50, 50); + + // Approximate number of up/down movements in one second. + AddSetting(&m_frequency_setting, + // i18n: Refers to a number of actions per second in Hz. + {_trans("Frequency"), + // i18n: The symbol/abbreviation for hertz (cycles per second). + _trans("Hz"), + // i18n: Refering to emulated wii remote movement. + _trans("Number of shakes per second.")}, + 6, 1, 20); +} + +Shake::StateData Shake::GetState(bool adjusted) const +{ + const float x = controls[0]->control_ref->State(); + const float y = controls[1]->control_ref->State(); + const float z = controls[2]->control_ref->State(); + + StateData result = {x, y, z}; + + // FYI: Unadjusted values are used in UI. + if (adjusted) + for (auto& c : result.data) + c = ApplyDeadzone(c, GetDeadzone()); + + return result; +} + +ControlState Shake::GetDeadzone() const +{ + return m_deadzone_setting.GetValue() / 100; +} + +ControlState Shake::GetIntensity() const +{ + return m_intensity_setting.GetValue() / 100; +} + +ControlState Shake::GetFrequency() const +{ + return m_frequency_setting.GetValue(); +} + } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.h index 21aca174a9..da66dc034e 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.h @@ -40,4 +40,28 @@ private: SettingValue m_jerk_setting; SettingValue m_angle_setting; }; + +class Shake : public ControlGroup +{ +public: + using StateData = Common::Vec3; + + explicit Shake(const std::string& name, ControlState default_intensity_scale = 1); + + StateData GetState(bool adjusted = true) const; + + ControlState GetDeadzone() const; + + // Return total travel distance in meters. + ControlState GetIntensity() const; + + // Return frequency in Hz. + ControlState GetFrequency() const; + +private: + SettingValue m_deadzone_setting; + SettingValue m_intensity_setting; + SettingValue m_frequency_setting; +}; + } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp index 30ff474706..3b3e68f291 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp @@ -20,6 +20,8 @@ namespace ControllerEmu MixedTriggers::MixedTriggers(const std::string& name_) : ControlGroup(name_, GroupType::MixedTriggers) { + AddDeadzoneSetting(&m_deadzone_setting, 25); + AddSetting(&m_threshold_setting, {_trans("Threshold"), // i18n: The percent symbol. @@ -27,8 +29,6 @@ MixedTriggers::MixedTriggers(const std::string& name_) // i18n: Refers to the "threshold" setting for pressure sensitive gamepad inputs. _trans("Input strength required for activation.")}, 90, 0, 100); - - AddDeadzoneSetting(&m_deadzone_setting, 25); } void MixedTriggers::GetState(u16* const digital, const u16* bitmasks, ControlState* analog, @@ -46,12 +46,9 @@ void MixedTriggers::GetState(u16* const digital, const u16* bitmasks, ControlSta const int trigger_count = int(controls.size() / 2); for (int i = 0; i != trigger_count; ++i) { - ControlState button_value = controls[i]->control_ref->State(); - ControlState analog_value = controls[trigger_count + i]->control_ref->State(); - - // Apply deadzone: - analog_value = std::max(0.0, analog_value - deadzone) / (1.0 - deadzone); - button_value = std::max(0.0, button_value - deadzone) / (1.0 - deadzone); + const ControlState button_value = ApplyDeadzone(controls[i]->control_ref->State(), deadzone); + ControlState analog_value = + ApplyDeadzone(controls[trigger_count + i]->control_ref->State(), deadzone); // Apply threshold: if (button_value > threshold) diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp index f734b46181..f8865329b9 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp @@ -34,9 +34,6 @@ Slider::StateData Slider::GetState() const ControlState deadzone = m_deadzone_setting.GetValue() / 100; const ControlState state = controls[1]->control_ref->State() - controls[0]->control_ref->State(); - if (fabs(state) > deadzone) - return {(state - (deadzone * sign(state))) / (1 - deadzone)}; - - return {0.0}; + return {ApplyDeadzone(state, deadzone)}; } } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp index e4a359eeba..900f30de3c 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp @@ -28,7 +28,7 @@ Triggers::StateData Triggers::GetState() StateData result(trigger_count); for (size_t i = 0; i < trigger_count; ++i) - result.data[i] = std::max(controls[i]->control_ref->State() - deadzone, 0.0) / (1 - deadzone); + result.data[i] = ApplyDeadzone(controls[i]->control_ref->State(), deadzone); return result; } diff --git a/Source/Core/InputCommon/ControllerEmu/StickGate.cpp b/Source/Core/InputCommon/ControllerEmu/StickGate.cpp index 8e9d48467a..48c21ae5be 100644 --- a/Source/Core/InputCommon/ControllerEmu/StickGate.cpp +++ b/Source/Core/InputCommon/ControllerEmu/StickGate.cpp @@ -272,8 +272,7 @@ ReshapableInput::ReshapeData ReshapableInput::Reshape(ControlState x, ControlSta } // Apply deadzone as a percentage of the user-defined calibration shape/size: - const ControlState deadzone = GetDeadzonePercentage(); - dist = std::max(0.0, dist - deadzone) / (1.0 - deadzone); + dist = ApplyDeadzone(dist, GetDeadzonePercentage()); // Scale to the gate shape/radius: dist *= gate_max_dist;