Virtual Notch settings and UI for octagonal stick

This commit is contained in:
Nick Michael
2020-10-29 22:11:34 +00:00
parent ab8a128588
commit 55dd3d7337
7 changed files with 108 additions and 2 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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