diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp index 538e67bc5c..e6e8c72875 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp @@ -159,7 +159,8 @@ void MappingIndicator::DrawStick() { // Make the c-stick yellow: const bool is_c_stick = m_group->name == "C-Stick"; - const QColor gate_color = is_c_stick ? Qt::yellow : Qt::lightGray; + const QColor gate_brush_color = is_c_stick ? Qt::yellow : Qt::lightGray; + const QColor gate_pen_color = gate_brush_color.darker(125); auto& stick = *static_cast(m_group); @@ -191,8 +192,8 @@ void MappingIndicator::DrawStick() p.setRenderHint(QPainter::SmoothPixmapTransform, true); // Input gate. (i.e. the octagon shape) - p.setPen(Qt::darkGray); - p.setBrush(gate_color); + p.setPen(gate_pen_color); + p.setBrush(gate_brush_color); p.drawPolygon(GetPolygonFromRadiusGetter( [&stick](double ang) { return stick.GetGateRadiusAtAngle(ang); }, scale)); diff --git a/Source/Core/InputCommon/CMakeLists.txt b/Source/Core/InputCommon/CMakeLists.txt index a3ef2722d8..ece9bbbde8 100644 --- a/Source/Core/InputCommon/CMakeLists.txt +++ b/Source/Core/InputCommon/CMakeLists.txt @@ -2,6 +2,7 @@ add_library(inputcommon InputConfig.cpp InputProfile.cpp ControllerEmu/ControllerEmu.cpp + ControllerEmu/StickGate.cpp ControllerEmu/Control/Control.cpp ControllerEmu/Control/Input.cpp ControllerEmu/Control/Output.cpp diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp index 5368c6b7ba..3f766d5e45 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp @@ -4,9 +4,7 @@ #include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h" -#include #include -#include #include "Common/Common.h" #include "Common/MathUtil.h" @@ -33,8 +31,10 @@ AnalogStick::AnalogStick(const char* const name_, const char* const ui_name_, controls.emplace_back(std::make_unique(Translate, _trans("Modifier"))); + // Set default input radius to that of the gate radius (no resizing) numeric_settings.emplace_back( - std::make_unique(_trans("Input Radius"), 1.0, 0, 100)); + std::make_unique(_trans("Input Radius"), GetGateRadiusAtAngle(0.0), 0, 100)); + // Set default input shape to an octagon (no reshaping) numeric_settings.emplace_back( std::make_unique(_trans("Input Shape"), 0.0, 0, 50)); numeric_settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 50)); @@ -50,9 +50,7 @@ AnalogStick::StateData AnalogStick::GetState(bool adjusted) return {x, y}; // TODO: make the AtAngle functions work with negative angles: - const ControlState ang = atan2(y, x) + MathUtil::TAU; - const ControlState ang_sin = sin(ang); - const ControlState ang_cos = cos(ang); + const ControlState ang = std::atan2(y, x) + MathUtil::TAU; const ControlState gate_max_dist = GetGateRadiusAtAngle(ang); const ControlState input_max_dist = GetInputRadiusAtAngle(ang); @@ -82,9 +80,8 @@ AnalogStick::StateData AnalogStick::GetState(bool adjusted) // Scale to the gate shape/radius: dist = dist *= gate_max_dist; - y = std::max(-1.0, std::min(1.0, ang_sin * dist)); - x = std::max(-1.0, std::min(1.0, ang_cos * 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}; } @@ -111,57 +108,16 @@ ControlState AnalogStick::CalculateInputShapeRadiusAtAngle(double ang) const { // Between 0 and 25 return a shape between octagon and circle const auto amt = shape; - return OctagonStickGate::ComputeRadiusAtAngle(ang) * (1 - amt) + amt; + 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::ComputeRadiusAtAngle(ang) * amt; + return (1 - amt) + SquareStickGate(1).GetRadiusAtAngle(ang) * amt; } } -OctagonStickGate::OctagonStickGate(ControlState radius) : m_radius(radius) -{ -} - -ControlState OctagonStickGate::GetRadiusAtAngle(double ang) const -{ - return ComputeRadiusAtAngle(ang) * m_radius; -} - -ControlState OctagonStickGate::ComputeRadiusAtAngle(double ang) -{ - // Ratio of octagon circumcircle to incircle: - const double incircle_radius = 0.923879532511287; - const double section_ang = MathUtil::TAU / 8; - return incircle_radius / std::cos(std::fmod(ang, section_ang) - section_ang / 2); -} - -RoundStickGate::RoundStickGate(ControlState radius) : m_radius(radius) -{ -} - -ControlState RoundStickGate::GetRadiusAtAngle(double) const -{ - return m_radius; -} - -SquareStickGate::SquareStickGate(ControlState half_width) : m_half_width(half_width) -{ -} - -ControlState SquareStickGate::GetRadiusAtAngle(double ang) const -{ - return ComputeRadiusAtAngle(ang) * m_half_width; -} - -ControlState SquareStickGate::ComputeRadiusAtAngle(double ang) -{ - const double section_ang = MathUtil::TAU / 4; - return 1 / std::cos(std::fmod(ang + section_ang / 2, section_ang) - section_ang / 2); -} - OctagonAnalogStick::OctagonAnalogStick(const char* name, ControlState gate_radius) : OctagonAnalogStick(name, name, gate_radius) { diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h index 336669124a..2351189f74 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h @@ -5,54 +5,11 @@ #pragma once #include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" +#include "InputCommon/ControllerEmu/StickGate.h" #include "InputCommon/ControllerInterface/Device.h" namespace ControllerEmu { -// An abstract class representing the plastic shell that limits an analog stick's movement. -class StickGate -{ -public: - // Angle is in radians and should be non-negative - virtual ControlState GetRadiusAtAngle(double ang) const = 0; -}; - -// An octagon-shaped stick gate is found on most Nintendo GC/Wii analog sticks. -class OctagonStickGate : public StickGate -{ -public: - explicit OctagonStickGate(ControlState radius); - ControlState GetRadiusAtAngle(double ang) const override; - - static ControlState ComputeRadiusAtAngle(double ang); - - const ControlState m_radius; -}; - -// A round-shaped stick gate. Possibly found on 3rd-party accessories. -class RoundStickGate : public StickGate -{ -public: - explicit RoundStickGate(ControlState radius); - ControlState GetRadiusAtAngle(double ang) const override; - -private: - const ControlState m_radius; -}; - -// A square-shaped stick gate. e.g. keyboard input. -class SquareStickGate : public StickGate -{ -public: - explicit SquareStickGate(ControlState half_width); - ControlState GetRadiusAtAngle(double ang) const override; - - static ControlState ComputeRadiusAtAngle(double ang); - -private: - const ControlState m_half_width; -}; - class AnalogStick : public ControlGroup { public: diff --git a/Source/Core/InputCommon/ControllerEmu/StickGate.cpp b/Source/Core/InputCommon/ControllerEmu/StickGate.cpp new file mode 100644 index 0000000000..c0c2a668a3 --- /dev/null +++ b/Source/Core/InputCommon/ControllerEmu/StickGate.cpp @@ -0,0 +1,47 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "InputCommon/ControllerEmu/StickGate.h" + +#include + +#include "Common/MathUtil.h" + +namespace ControllerEmu +{ +OctagonStickGate::OctagonStickGate(ControlState radius) : m_radius(radius) +{ +} + +ControlState OctagonStickGate::GetRadiusAtAngle(double ang) const +{ + constexpr int sides = 8; + constexpr double sum_int_angles = (sides - 2) * MathUtil::PI; + constexpr double half_int_angle = sum_int_angles / sides / 2; + + ang = std::fmod(ang, MathUtil::TAU / sides); + // Solve ASA triangle using The Law of Sines: + return m_radius / std::sin(MathUtil::PI - ang - half_int_angle) * std::sin(half_int_angle); +} + +RoundStickGate::RoundStickGate(ControlState radius) : m_radius(radius) +{ +} + +ControlState RoundStickGate::GetRadiusAtAngle(double) const +{ + return m_radius; +} + +SquareStickGate::SquareStickGate(ControlState half_width) : m_half_width(half_width) +{ +} + +ControlState SquareStickGate::GetRadiusAtAngle(double ang) const +{ + constexpr double section_ang = MathUtil::TAU / 4; + return m_half_width / std::cos(std::fmod(ang + section_ang / 2, section_ang) - section_ang / 2); +} + +} // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/StickGate.h b/Source/Core/InputCommon/ControllerEmu/StickGate.h new file mode 100644 index 0000000000..decb15d234 --- /dev/null +++ b/Source/Core/InputCommon/ControllerEmu/StickGate.h @@ -0,0 +1,55 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "InputCommon/ControlReference/ControlReference.h" + +namespace ControllerEmu +{ +// An abstract class representing the plastic shell that limits an analog stick's movement. +class StickGate +{ +public: + // Angle is in radians and should be non-negative + virtual ControlState GetRadiusAtAngle(double ang) const = 0; + + virtual ~StickGate() = default; +}; + +// An octagon-shaped stick gate is found on most Nintendo GC/Wii analog sticks. +class OctagonStickGate : public StickGate +{ +public: + // Radius of circumscribed circle + explicit OctagonStickGate(ControlState radius); + ControlState GetRadiusAtAngle(double ang) const override final; + +private: + const ControlState m_radius; +}; + +// A round-shaped stick gate. Possibly found on 3rd-party accessories. +class RoundStickGate : public StickGate +{ +public: + explicit RoundStickGate(ControlState radius); + ControlState GetRadiusAtAngle(double ang) const override final; + +private: + const ControlState m_radius; +}; + +// A square-shaped stick gate. e.g. keyboard input. +class SquareStickGate : public StickGate +{ +public: + explicit SquareStickGate(ControlState half_width); + ControlState GetRadiusAtAngle(double ang) const override final; + +private: + const ControlState m_half_width; +}; + +} // namespace ControllerEmu diff --git a/Source/Core/InputCommon/InputCommon.vcxproj b/Source/Core/InputCommon/InputCommon.vcxproj index 0b5dc08018..2bef816726 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj +++ b/Source/Core/InputCommon/InputCommon.vcxproj @@ -37,6 +37,7 @@ + @@ -75,6 +76,7 @@ + @@ -119,4 +121,4 @@ - \ No newline at end of file + diff --git a/Source/Core/InputCommon/InputCommon.vcxproj.filters b/Source/Core/InputCommon/InputCommon.vcxproj.filters index c67333497c..01c5c371b6 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj.filters +++ b/Source/Core/InputCommon/InputCommon.vcxproj.filters @@ -32,6 +32,9 @@ ControllerEmu + + ControllerEmu + ControllerEmu\Control @@ -119,6 +122,9 @@ ControllerEmu + + ControllerEmu + ControllerEmu\Control