diff options
Diffstat (limited to 'Source/Core/InputCommon/ControllerEmu/StickGate.cpp')
| -rw-r--r-- | Source/Core/InputCommon/ControllerEmu/StickGate.cpp | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/Source/Core/InputCommon/ControllerEmu/StickGate.cpp b/Source/Core/InputCommon/ControllerEmu/StickGate.cpp index c0c2a668a3..64cf238e17 100644 --- a/Source/Core/InputCommon/ControllerEmu/StickGate.cpp +++ b/Source/Core/InputCommon/ControllerEmu/StickGate.cpp @@ -6,7 +6,9 @@ #include <cmath> +#include "Common/Common.h" #include "Common/MathUtil.h" +#include "InputCommon/ControllerEmu/Setting/NumericSetting.h" namespace ControllerEmu { @@ -44,4 +46,90 @@ ControlState SquareStickGate::GetRadiusAtAngle(double ang) const return m_half_width / std::cos(std::fmod(ang + section_ang / 2, section_ang) - section_ang / 2); } +ReshapableInput::ReshapableInput(std::string name, std::string ui_name, GroupType type) + : ControlGroup(std::move(name), std::move(ui_name), type) +{ +} + +ControlState ReshapableInput::GetDeadzoneRadiusAtAngle(double ang) const +{ + return CalculateInputShapeRadiusAtAngle(ang) * numeric_settings[SETTING_DEADZONE]->GetValue(); +} + +ControlState ReshapableInput::GetInputRadiusAtAngle(double ang) const +{ + const ControlState radius = + CalculateInputShapeRadiusAtAngle(ang) * numeric_settings[SETTING_INPUT_RADIUS]->GetValue(); + // Clamp within the -1 to +1 square as input radius may be greater than 1.0: + return std::min(radius, SquareStickGate(1).GetRadiusAtAngle(ang)); +} + +void ReshapableInput::AddReshapingSettings(ControlState default_radius, ControlState default_shape, + int max_deadzone) +{ + // Allow radius greater than 1.0 for definitions of rounded squares + // This is ideal for Xbox controllers (and probably others) + numeric_settings.emplace_back( + std::make_unique<NumericSetting>(_trans("Input Radius"), default_radius, 0, 140)); + numeric_settings.emplace_back( + std::make_unique<NumericSetting>(_trans("Input Shape"), default_shape, 0, 50)); + numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Dead Zone"), 0, 0, 50)); +} + +ReshapableInput::ReshapeData ReshapableInput::Reshape(ControlState x, ControlState y, + ControlState modifier) +{ + // TODO: make the AtAngle functions work with negative angles: + const ControlState ang = std::atan2(y, x) + MathUtil::TAU; + + const ControlState gate_max_dist = GetGateRadiusAtAngle(ang); + const ControlState input_max_dist = GetInputRadiusAtAngle(ang); + + // If input radius is zero we apply no scaling. + // This is useful when mapping native controllers without knowing intimate radius details. + const ControlState max_dist = input_max_dist ? input_max_dist : gate_max_dist; + + ControlState dist = std::sqrt(x * x + y * y) / max_dist; + + // 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) + { + // TODO: Modifier's range setting gets reset to 100% when the clear button is clicked. + // This causes the modifier to not behave how a user might suspect. + // Retaining the old scale-by-50% behavior until range is fixed to clear to 50%. + dist *= 0.5; + // dist *= modifier; + } + + // Apply deadzone as a percentage of the user-defined radius/shape: + const ControlState deadzone = GetDeadzoneRadiusAtAngle(ang); + dist = std::max(0.0, dist - deadzone) / (1.0 - deadzone); + + // Scale to the gate shape/radius: + dist = dist *= gate_max_dist; + + x = MathUtil::Clamp(std::cos(ang) * dist, -1.0, 1.0); + y = MathUtil::Clamp(std::sin(ang) * dist, -1.0, 1.0); + return {x, y}; +} + +ControlState ReshapableInput::CalculateInputShapeRadiusAtAngle(double ang) const +{ + const auto shape = numeric_settings[SETTING_INPUT_SHAPE]->GetValue() * 4.0; + + if (shape < 1.0) + { + // Between 0 and 25 return a shape between octagon and circle + const auto amt = shape; + return OctagonStickGate(1).GetRadiusAtAngle(ang) * (1 - amt) + amt; + } + else + { + // Between 25 and 50 return a shape between circle and square + const auto amt = shape - 1.0; + return (1 - amt) + SquareStickGate(1).GetRadiusAtAngle(ang) * amt; + } +} + } // namespace ControllerEmu |
