summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2019-04-13 12:13:13 -0400
committerGitHub <noreply@github.com>2019-04-13 12:13:13 -0400
commita891115ea350528f1735dab54d05edc8b8fe77c6 (patch)
tree08257dd14877d4693d502dcf50e81a734e0cb043 /Source/Core
parent241166a1a5becb0a6a2af209e7f5ea2962d6a2dd (diff)
parentc89ddf8cba9c6b19d59e2db1896292797163c54c (diff)
Merge pull request #7952 from jordan-woyak/emu-shake-params
WiimoteEmu: Allow shake frequency and intensity to be configured.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/CMakeLists.txt1
-rw-r--r--Source/Core/Core/Config/WiimoteInputSettings.cpp33
-rw-r--r--Source/Core/Core/Config/WiimoteInputSettings.h31
-rw-r--r--Source/Core/Core/Core.vcxproj2
-rw-r--r--Source/Core/Core/Core.vcxproj.filters8
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/Dynamics.cpp106
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/Dynamics.h36
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp4
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp36
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h13
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp58
-rw-r--r--Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h13
-rw-r--r--Source/Core/Core/State.cpp2
-rw-r--r--Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp89
-rw-r--r--Source/Core/DolphinQt/Config/Mapping/MappingIndicator.h20
-rw-r--r--Source/Core/DolphinQt/Config/Mapping/MappingWidget.cpp17
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h11
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp3
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.cpp68
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.h24
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp13
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp5
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp2
-rw-r--r--Source/Core/InputCommon/ControllerEmu/StickGate.cpp3
24 files changed, 285 insertions, 313 deletions
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<double> WIIMOTE_INPUT_SHAKE_INTENSITY_HARD{{System::WiiPad, "Shake", "Hard"}, 5.0};
-const ConfigInfo<double> WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM{{System::WiiPad, "Shake", "Medium"},
- 3.0};
-const ConfigInfo<double> WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT{{System::WiiPad, "Shake", "Soft"}, 2.0};
-
-// Dynamic settings
-const ConfigInfo<int> WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_HARD{
- {System::WiiPad, "Dynamic_Shake", "FramesHeldHard"}, 45};
-const ConfigInfo<int> WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_SOFT{
- {System::WiiPad, "Dynamic_Shake", "FramesHeldSoft"}, 15};
-const ConfigInfo<int> WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_LENGTH{
- {System::WiiPad, "Dynamic_Shake", "FrameCount"}, 30};
-
-// NunchuckInput.Settings
-const ConfigInfo<double> NUNCHUK_INPUT_SHAKE_INTENSITY_HARD{
- {System::WiiPad, "Nunchuk_Shake", "Hard"}, 5.0};
-const ConfigInfo<double> NUNCHUK_INPUT_SHAKE_INTENSITY_MEDIUM{
- {System::WiiPad, "Nunchuk_Shake", "Medium"}, 3.0};
-const ConfigInfo<double> 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<double> WIIMOTE_INPUT_SHAKE_INTENSITY_HARD;
-extern const ConfigInfo<double> WIIMOTE_INPUT_SHAKE_INTENSITY_MEDIUM;
-extern const ConfigInfo<double> WIIMOTE_INPUT_SHAKE_INTENSITY_SOFT;
-
-// Below settings are for dynamic input only (based on how long the user holds a button)
-extern const ConfigInfo<int>
- WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_HARD; // How long button held constitutes a hard shake
-extern const ConfigInfo<int>
- WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_HELD_SOFT; // How long button held constitutes a soft shake
-extern const ConfigInfo<int>
- WIIMOTE_INPUT_SHAKE_DYNAMIC_FRAMES_LENGTH; // How long to execute a shake
-
-// NunchuckInput.Settings
-extern const ConfigInfo<double> NUNCHUK_INPUT_SHAKE_INTENSITY_HARD;
-extern const ConfigInfo<double> NUNCHUK_INPUT_SHAKE_INTENSITY_MEDIUM;
-extern const ConfigInfo<double> 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 @@
<ClCompile Include="ConfigLoaders\MovieConfigLoader.cpp" />
<ClCompile Include="ConfigLoaders\NetPlayConfigLoader.cpp" />
<ClCompile Include="ConfigManager.cpp" />
- <ClCompile Include="Config\WiimoteInputSettings.cpp" />
<ClCompile Include="Core.cpp" />
<ClCompile Include="CoreTiming.cpp" />
<ClCompile Include="Debugger\Debugger_SymbolMap.cpp" />
@@ -327,7 +326,6 @@
<ClInclude Include="ConfigLoaders\NetPlayConfigLoader.h" />
<ClInclude Include="ConfigManager.h" />
<ClInclude Include="Config\UISettings.h" />
- <ClInclude Include="Config\WiimoteInputSettings.h" />
<ClInclude Include="Core.h" />
<ClInclude Include="CoreTiming.h" />
<ClInclude Include="Debugger\Debugger_SymbolMap.h" />
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 @@
<ClCompile Include="Config\UISettings.cpp">
<Filter>Config</Filter>
</ClCompile>
- <ClCompile Include="Config\WiimoteInputSettings.cpp">
- <Filter>Config</Filter>
- </ClCompile>
<ClCompile Include="PowerPC\Jit64\RegCache\FPURegCache.cpp" />
<ClCompile Include="PowerPC\Jit64\RegCache\GPRRegCache.cpp" />
<ClCompile Include="PowerPC\Jit64\RegCache\JitRegCache.cpp" />
@@ -1592,9 +1589,6 @@
<ClInclude Include="Config\UISettings.h">
<Filter>Config</Filter>
</ClInclude>
- <ClInclude Include="Config\WiimoteInputSettings.h">
- <Filter>Config</Filter>
- </ClInclude>
<ClInclude Include="HW\WiimoteEmu\I2CBus.h">
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
</ClInclude>
@@ -1638,4 +1632,4 @@
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
-</Project> \ No newline at end of file
+</Project>
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))
- {
- 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
+ if (state->velocity.data[i] * std::copysign(1.f, target_position.data[i]) < 0 ||
+ state->position.data[i] / target_position.data[i] > 0.5)
{
- shake_step[i] = 0;
+ target_position.data[i] *= -1;
}
}
- return accel;
-}
-
-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;
+ // Time from "top" to "bottom" of one shake.
+ const auto travel_time = 1 / shake_group->GetFrequency() / 2;
- 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<int, 3> timing; // Hold length in frames for each axis
- std::array<double, 3> intensity; // Swing or shake intensity
- std::array<int, 3> 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<u8, 3> m_shake_step{};
- std::array<u8, 3> m_shake_soft_step{};
- std::array<u8, 3> 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<u8, 3> m_shake_step{};
- std::array<u8, 3> m_shake_soft_step{};
- std::array<u8, 3> m_shake_hard_step{};
- std::array<u8, 3> 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 <QToolButton>
#include <QWidget>
+#include <deque>
+
#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<ControllerEmu::Shake::StateData> 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<ControllerEmu::Shake*>(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 <cmath>
#include <memory>
#include <string>
+#include <type_traits>
#include <vector>
#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<double>* value, double maximum_deadzone);
+ template <typename T>
+ static T ApplyDeadzone(T input, std::common_type_t<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<double> m_jerk_setting;
SettingValue<double> 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<double> m_deadzone_setting;
+ SettingValue<double> m_intensity_setting;
+ SettingValue<double> 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;