InputCommon: Simplified StickGate interface and moved class into its own file. Changed default input radius to perform no resizing. Tweaked the indicator colors a bit to improve visibility. Cleaned up some math and code.
This commit is contained in:
parent
ceb28a2302
commit
da9bcf83ef
|
@ -159,7 +159,8 @@ void MappingIndicator::DrawStick()
|
||||||
{
|
{
|
||||||
// Make the c-stick yellow:
|
// Make the c-stick yellow:
|
||||||
const bool is_c_stick = m_group->name == "C-Stick";
|
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<ControllerEmu::AnalogStick*>(m_group);
|
auto& stick = *static_cast<ControllerEmu::AnalogStick*>(m_group);
|
||||||
|
|
||||||
|
@ -191,8 +192,8 @@ void MappingIndicator::DrawStick()
|
||||||
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||||
|
|
||||||
// Input gate. (i.e. the octagon shape)
|
// Input gate. (i.e. the octagon shape)
|
||||||
p.setPen(Qt::darkGray);
|
p.setPen(gate_pen_color);
|
||||||
p.setBrush(gate_color);
|
p.setBrush(gate_brush_color);
|
||||||
p.drawPolygon(GetPolygonFromRadiusGetter(
|
p.drawPolygon(GetPolygonFromRadiusGetter(
|
||||||
[&stick](double ang) { return stick.GetGateRadiusAtAngle(ang); }, scale));
|
[&stick](double ang) { return stick.GetGateRadiusAtAngle(ang); }, scale));
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ add_library(inputcommon
|
||||||
InputConfig.cpp
|
InputConfig.cpp
|
||||||
InputProfile.cpp
|
InputProfile.cpp
|
||||||
ControllerEmu/ControllerEmu.cpp
|
ControllerEmu/ControllerEmu.cpp
|
||||||
|
ControllerEmu/StickGate.cpp
|
||||||
ControllerEmu/Control/Control.cpp
|
ControllerEmu/Control/Control.cpp
|
||||||
ControllerEmu/Control/Input.cpp
|
ControllerEmu/Control/Input.cpp
|
||||||
ControllerEmu/Control/Output.cpp
|
ControllerEmu/Control/Output.cpp
|
||||||
|
|
|
@ -4,9 +4,7 @@
|
||||||
|
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "Common/Common.h"
|
#include "Common/Common.h"
|
||||||
#include "Common/MathUtil.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<Input>(Translate, _trans("Modifier")));
|
controls.emplace_back(std::make_unique<Input>(Translate, _trans("Modifier")));
|
||||||
|
|
||||||
|
// Set default input radius to that of the gate radius (no resizing)
|
||||||
numeric_settings.emplace_back(
|
numeric_settings.emplace_back(
|
||||||
std::make_unique<NumericSetting>(_trans("Input Radius"), 1.0, 0, 100));
|
std::make_unique<NumericSetting>(_trans("Input Radius"), GetGateRadiusAtAngle(0.0), 0, 100));
|
||||||
|
// Set default input shape to an octagon (no reshaping)
|
||||||
numeric_settings.emplace_back(
|
numeric_settings.emplace_back(
|
||||||
std::make_unique<NumericSetting>(_trans("Input Shape"), 0.0, 0, 50));
|
std::make_unique<NumericSetting>(_trans("Input Shape"), 0.0, 0, 50));
|
||||||
numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Dead Zone"), 0, 0, 50));
|
numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Dead Zone"), 0, 0, 50));
|
||||||
|
@ -50,9 +50,7 @@ AnalogStick::StateData AnalogStick::GetState(bool adjusted)
|
||||||
return {x, y};
|
return {x, y};
|
||||||
|
|
||||||
// TODO: make the AtAngle functions work with negative angles:
|
// TODO: make the AtAngle functions work with negative angles:
|
||||||
const ControlState ang = atan2(y, x) + MathUtil::TAU;
|
const ControlState ang = std::atan2(y, x) + MathUtil::TAU;
|
||||||
const ControlState ang_sin = sin(ang);
|
|
||||||
const ControlState ang_cos = cos(ang);
|
|
||||||
|
|
||||||
const ControlState gate_max_dist = GetGateRadiusAtAngle(ang);
|
const ControlState gate_max_dist = GetGateRadiusAtAngle(ang);
|
||||||
const ControlState input_max_dist = GetInputRadiusAtAngle(ang);
|
const ControlState input_max_dist = GetInputRadiusAtAngle(ang);
|
||||||
|
@ -82,9 +80,8 @@ AnalogStick::StateData AnalogStick::GetState(bool adjusted)
|
||||||
// Scale to the gate shape/radius:
|
// Scale to the gate shape/radius:
|
||||||
dist = dist *= gate_max_dist;
|
dist = dist *= gate_max_dist;
|
||||||
|
|
||||||
y = std::max(-1.0, std::min(1.0, ang_sin * dist));
|
x = MathUtil::Clamp(std::cos(ang) * dist, -1.0, 1.0);
|
||||||
x = std::max(-1.0, std::min(1.0, ang_cos * dist));
|
y = MathUtil::Clamp(std::sin(ang) * dist, -1.0, 1.0);
|
||||||
|
|
||||||
return {x, y};
|
return {x, y};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,57 +108,16 @@ ControlState AnalogStick::CalculateInputShapeRadiusAtAngle(double ang) const
|
||||||
{
|
{
|
||||||
// Between 0 and 25 return a shape between octagon and circle
|
// Between 0 and 25 return a shape between octagon and circle
|
||||||
const auto amt = shape;
|
const auto amt = shape;
|
||||||
return OctagonStickGate::ComputeRadiusAtAngle(ang) * (1 - amt) + amt;
|
return OctagonStickGate(1).GetRadiusAtAngle(ang) * (1 - amt) + amt;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Between 25 and 50 return a shape between circle and square
|
// Between 25 and 50 return a shape between circle and square
|
||||||
const auto amt = shape - 1.0;
|
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::OctagonAnalogStick(const char* name, ControlState gate_radius)
|
||||||
: OctagonAnalogStick(name, name, gate_radius)
|
: OctagonAnalogStick(name, name, gate_radius)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,54 +5,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
||||||
|
#include "InputCommon/ControllerEmu/StickGate.h"
|
||||||
#include "InputCommon/ControllerInterface/Device.h"
|
#include "InputCommon/ControllerInterface/Device.h"
|
||||||
|
|
||||||
namespace ControllerEmu
|
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
|
class AnalogStick : public ControlGroup
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -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 <cmath>
|
||||||
|
|
||||||
|
#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
|
|
@ -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
|
|
@ -37,6 +37,7 @@
|
||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="ControllerEmu\ControllerEmu.cpp" />
|
<ClCompile Include="ControllerEmu\ControllerEmu.cpp" />
|
||||||
|
<ClCompile Include="ControllerEmu\StickGate.cpp" />
|
||||||
<ClCompile Include="ControllerEmu\Control\Control.cpp" />
|
<ClCompile Include="ControllerEmu\Control\Control.cpp" />
|
||||||
<ClCompile Include="ControllerEmu\Control\Input.cpp" />
|
<ClCompile Include="ControllerEmu\Control\Input.cpp" />
|
||||||
<ClCompile Include="ControllerEmu\Control\Output.cpp" />
|
<ClCompile Include="ControllerEmu\Control\Output.cpp" />
|
||||||
|
@ -75,6 +76,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="ControllerEmu\ControllerEmu.h" />
|
<ClInclude Include="ControllerEmu\ControllerEmu.h" />
|
||||||
|
<ClInclude Include="ControllerEmu\StickGate.h" />
|
||||||
<ClInclude Include="ControllerEmu\Control\Control.h" />
|
<ClInclude Include="ControllerEmu\Control\Control.h" />
|
||||||
<ClInclude Include="ControllerEmu\Control\Input.h" />
|
<ClInclude Include="ControllerEmu\Control\Input.h" />
|
||||||
<ClInclude Include="ControllerEmu\Control\Output.h" />
|
<ClInclude Include="ControllerEmu\Control\Output.h" />
|
||||||
|
@ -119,4 +121,4 @@
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -32,6 +32,9 @@
|
||||||
<ClCompile Include="ControllerEmu\ControllerEmu.cpp">
|
<ClCompile Include="ControllerEmu\ControllerEmu.cpp">
|
||||||
<Filter>ControllerEmu</Filter>
|
<Filter>ControllerEmu</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="ControllerEmu\StickGate.cpp">
|
||||||
|
<Filter>ControllerEmu</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="ControllerEmu\Control\Control.cpp">
|
<ClCompile Include="ControllerEmu\Control\Control.cpp">
|
||||||
<Filter>ControllerEmu\Control</Filter>
|
<Filter>ControllerEmu\Control</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -119,6 +122,9 @@
|
||||||
<ClInclude Include="ControllerEmu\ControllerEmu.h">
|
<ClInclude Include="ControllerEmu\ControllerEmu.h">
|
||||||
<Filter>ControllerEmu</Filter>
|
<Filter>ControllerEmu</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="ControllerEmu\StickGate.h">
|
||||||
|
<Filter>ControllerEmu</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="ControllerEmu\Control\Control.h">
|
<ClInclude Include="ControllerEmu\Control\Control.h">
|
||||||
<Filter>ControllerEmu\Control</Filter>
|
<Filter>ControllerEmu\Control</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
Loading…
Reference in New Issue