diff options
| author | Jordan Woyak <jordan.woyak@gmail.com> | 2020-11-03 17:10:54 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-03 17:10:54 -0600 |
| commit | 3cd4c56645541640f61a761dfde16464b1ef09df (patch) | |
| tree | da78e02789930be5be5addf02f4326d673ca0c09 /Source/Core/InputCommon/ControllerEmu | |
| parent | d2f80a45954d1c638af44b346223d4f480ce4e82 (diff) | |
| parent | 55dd3d73376746c4fc46df02d8266269a6e4537e (diff) | |
Merge pull request #9203 from nick-michael/virtual-notches
Logic & UI for "Virtual Notches"
Diffstat (limited to 'Source/Core/InputCommon/ControllerEmu')
6 files changed, 49 insertions, 2 deletions
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp index a0157eec8f..881be39471 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp @@ -65,6 +65,12 @@ OctagonAnalogStick::OctagonAnalogStick(const char* name_, const char* ui_name_, ControlState gate_radius) : AnalogStick(name_, ui_name_, std::make_unique<ControllerEmu::OctagonStickGate>(gate_radius)) { + AddVirtualNotchSetting(&m_virtual_notch_setting, 45); +} + +ControlState OctagonAnalogStick::GetVirtualNotchSize() const +{ + return m_virtual_notch_setting.GetValue() * MathUtil::TAU / 360; } } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h index cafb1dad51..d13fd60a68 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h @@ -33,6 +33,11 @@ class OctagonAnalogStick : public AnalogStick public: OctagonAnalogStick(const char* name, ControlState gate_radius); OctagonAnalogStick(const char* name, const char* ui_name, ControlState gate_radius); + + ControlState GetVirtualNotchSize() const override; + +private: + SettingValue<double> m_virtual_notch_setting; }; } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp index 70975937c9..ee33e32f0f 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp @@ -28,6 +28,17 @@ ControlGroup::ControlGroup(std::string name_, std::string ui_name_, const GroupT { } +void ControlGroup::AddVirtualNotchSetting(SettingValue<double>* value, double max_virtual_notch_deg) +{ + AddSetting(value, + {_trans("Virtual Notches"), + // i18n: The degrees symbol. + _trans("°"), + // i18n: Snap the thumbstick position to the nearest octagonal axis. + _trans("Snap the thumbstick position to the nearest octagonal axis.")}, + 0, 0, max_virtual_notch_deg); +} + void ControlGroup::AddDeadzoneSetting(SettingValue<double>* value, double maximum_deadzone) { AddSetting(value, diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h index 46b8172d14..45c2367c10 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h @@ -82,6 +82,8 @@ public: std::make_unique<NumericSetting<T>>(value, details, default_value_, min_value, max_value)); } + void AddVirtualNotchSetting(SettingValue<double>* value, double max_virtual_notch_deg); + void AddDeadzoneSetting(SettingValue<double>* value, double maximum_deadzone); template <typename T> diff --git a/Source/Core/InputCommon/ControllerEmu/StickGate.cpp b/Source/Core/InputCommon/ControllerEmu/StickGate.cpp index 1497471c14..797d19aadf 100644 --- a/Source/Core/InputCommon/ControllerEmu/StickGate.cpp +++ b/Source/Core/InputCommon/ControllerEmu/StickGate.cpp @@ -48,6 +48,16 @@ std::optional<double> GetRayLineIntersection(Common::DVec2 ray, Common::DVec2 po return diff.Cross(-point1) / dot; } +double GetNearestNotch(double angle, double virtual_notch_angle) +{ + constexpr auto sides = 8; + constexpr auto rounding = MathUtil::TAU / sides; + const auto closest_notch = std::round(angle / rounding) * rounding; + const auto angle_diff = + std::fmod(angle - closest_notch + MathUtil::PI, MathUtil::TAU) - MathUtil::PI; + return std::abs(angle_diff) < virtual_notch_angle / 2 ? closest_notch : angle; +} + Common::DVec2 GetPointFromAngleAndLength(double angle, double length) { return Common::DVec2{std::cos(angle), std::sin(angle)} * length; @@ -276,16 +286,24 @@ ReshapableInput::ReshapeData ReshapableInput::Reshape(ControlState x, ControlSta y -= m_center.y; // TODO: make the AtAngle functions work with negative angles: - const ControlState angle = std::atan2(y, x) + MathUtil::TAU; + ControlState angle = std::atan2(y, x) + MathUtil::TAU; - const ControlState gate_max_dist = GetGateRadiusAtAngle(angle); const ControlState input_max_dist = GetInputRadiusAtAngle(angle); + ControlState gate_max_dist = GetGateRadiusAtAngle(angle); // If input radius (from calibration) is zero apply no scaling to prevent division by zero. const ControlState max_dist = input_max_dist ? input_max_dist : gate_max_dist; ControlState dist = Common::DVec2{x, y}.Length() / max_dist; + const double virtual_notch_size = GetVirtualNotchSize(); + + if (virtual_notch_size > 0.0 && dist >= MINIMUM_NOTCH_DISTANCE) + { + angle = GetNearestNotch(angle, virtual_notch_size); + gate_max_dist = GetGateRadiusAtAngle(angle); + } + // If the modifier is pressed, scale the distance by the modifier's value. // This is affected by the modifier's "range" setting which defaults to 50%. if (modifier) diff --git a/Source/Core/InputCommon/ControllerEmu/StickGate.h b/Source/Core/InputCommon/ControllerEmu/StickGate.h index aa5096b271..8a0a0ab100 100644 --- a/Source/Core/InputCommon/ControllerEmu/StickGate.h +++ b/Source/Core/InputCommon/ControllerEmu/StickGate.h @@ -15,6 +15,9 @@ namespace ControllerEmu { +// Minimum stick distance from the center before virtual notches are applied. +constexpr ControlState MINIMUM_NOTCH_DISTANCE = 0.9; + // An abstract class representing the plastic shell that limits an analog stick's movement. class StickGate { @@ -85,6 +88,8 @@ public: ControlState GetDeadzonePercentage() const; + virtual ControlState GetVirtualNotchSize() const { return 0.0; }; + virtual ControlState GetGateRadiusAtAngle(double angle) const = 0; virtual ReshapeData GetReshapableState(bool adjusted) = 0; virtual ControlState GetDefaultInputRadiusAtAngle(double ang) const; |
