mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 05:09:34 -06:00
WiimoteEmu: Allow shake frequency and intensity to be configured. Other minor cleanups.
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user