WiimoteEmu: Allow shake frequency and intensity to be configured. Other minor cleanups.
This commit is contained in:
parent
635fd8c22c
commit
c89ddf8cba
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
</Project>
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue