WiimoteEmu: Allow shake frequency and intensity to be configured. Other minor cleanups.

This commit is contained in:
Jordan Woyak
2019-03-29 14:39:48 -05:00
parent 635fd8c22c
commit c89ddf8cba
24 changed files with 285 additions and 313 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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;
}