summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorJordan Woyak <jordan.woyak@gmail.com>2020-02-03 19:45:36 -0600
committerJordan Woyak <jordan.woyak@gmail.com>2020-02-17 15:57:43 -0600
commit82a3aa5ff67b0239b85d18a6da77d3fd2900640c (patch)
tree9d808c8590dad2fd32854c798482c9d9cc0ae16b /Source/Core
parent2d6a72e941da4b24d1795760e7f5a4394cc69263 (diff)
InputCommon: Add "Dead Zone" setting to raw gyro inputs.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp88
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.cpp31
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h8
3 files changed, 88 insertions, 39 deletions
diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp
index 2fd39b2a5b..61b291c96b 100644
--- a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp
+++ b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp
@@ -754,33 +754,34 @@ void AccelerometerMappingIndicator::paintEvent(QPaintEvent*)
p.setBrush(Qt::NoBrush);
p.drawEllipse(QPointF{}, scale * SPHERE_SIZE, scale * SPHERE_SIZE);
- // Red dot upright target.
- p.setPen(QPen(GetAdjustedInputColor(), INPUT_DOT_RADIUS / 2));
- p.drawEllipse(QPointF{0, SPHERE_INDICATOR_DIST} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
+ p.setPen(Qt::NoPen);
// Red dot.
const auto point = rotation * Common::Vec3{0, 0, SPHERE_INDICATOR_DIST};
if (point.y > 0 || Common::Vec2(point.x, point.z).Length() > SPHERE_SIZE)
{
- p.setPen(Qt::NoPen);
p.setBrush(GetAdjustedInputColor());
p.drawEllipse(QPointF(point.x, point.z) * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
}
- // Blue dot target.
- p.setPen(QPen(Qt::blue, INPUT_DOT_RADIUS / 2));
- p.setBrush(Qt::NoBrush);
- p.drawEllipse(QPointF{0, -SPHERE_INDICATOR_DIST} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
-
// Blue dot.
const auto point2 = -point;
if (point2.y > 0 || Common::Vec2(point2.x, point2.z).Length() > SPHERE_SIZE)
{
- p.setPen(Qt::NoPen);
p.setBrush(Qt::blue);
p.drawEllipse(QPointF(point2.x, point2.z) * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
}
+ p.setBrush(Qt::NoBrush);
+
+ // Red dot upright target.
+ p.setPen(QPen(GetAdjustedInputColor(), INPUT_DOT_RADIUS / 2));
+ p.drawEllipse(QPointF{0, SPHERE_INDICATOR_DIST} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
+
+ // Blue dot target.
+ p.setPen(QPen(Qt::blue, INPUT_DOT_RADIUS / 2));
+ p.drawEllipse(QPointF{0, -SPHERE_INDICATOR_DIST} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
+
// Only draw g-force text if acceleration data is present.
if (!accel_state.has_value())
return;
@@ -802,6 +803,7 @@ GyroMappingIndicator::GyroMappingIndicator(ControllerEmu::IMUGyroscope* group)
void GyroMappingIndicator::paintEvent(QPaintEvent*)
{
const auto gyro_state = m_gyro_group.GetState();
+ const auto raw_gyro_state = m_gyro_group.GetRawState();
const auto angular_velocity = gyro_state.value_or(Common::Vec3{});
m_state *= Common::Matrix33::FromQuaternion(angular_velocity.x / -INDICATOR_UPDATE_FREQ / 2,
@@ -810,8 +812,8 @@ void GyroMappingIndicator::paintEvent(QPaintEvent*)
// Reset orientation when stable for a bit:
constexpr u32 STABLE_RESET_STEPS = INDICATOR_UPDATE_FREQ;
- // This works well with my DS4 but a potentially noisy device might not behave.
- const bool is_stable = angular_velocity.Length() < MathUtil::TAU / 30;
+ // Consider device stable when data (with deadzone applied) is zero.
+ const bool is_stable = !angular_velocity.LengthSquared();
if (!is_stable)
m_stable_steps = 0;
@@ -839,10 +841,39 @@ void GyroMappingIndicator::paintEvent(QPaintEvent*)
p.setRenderHint(QPainter::Antialiasing, true);
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
+ // Deadzone.
+ if (const auto deadzone_value = m_gyro_group.GetDeadzone(); deadzone_value)
+ {
+ static constexpr auto DEADZONE_DRAW_SIZE = 1 - SPHERE_SIZE;
+ static constexpr auto DEADZONE_DRAW_BOTTOM = 1;
+
+ p.setPen(GetDeadZonePen());
+ p.setBrush(GetDeadZoneBrush());
+ p.scale(-1.0, 1.0);
+ p.drawRect(-scale, DEADZONE_DRAW_BOTTOM * scale, scale * 2, -scale * DEADZONE_DRAW_SIZE);
+ p.scale(-1.0, 1.0);
+
+ if (gyro_state.has_value())
+ {
+ const auto max_velocity = std::max(
+ {std::abs(raw_gyro_state.x), std::abs(raw_gyro_state.y), std::abs(raw_gyro_state.z)});
+ const auto max_velocity_line_y =
+ std::min(max_velocity / deadzone_value * DEADZONE_DRAW_SIZE - DEADZONE_DRAW_BOTTOM, 1.0);
+ p.setPen(QPen(GetRawInputColor(), INPUT_DOT_RADIUS));
+ p.drawLine(-scale, max_velocity_line_y * -scale, scale, max_velocity_line_y * -scale);
+
+ // Sphere background.
+ p.setPen(Qt::NoPen);
+ p.setBrush(GetBBoxBrush());
+ p.drawEllipse(QPointF{}, scale * SPHERE_SIZE, scale * SPHERE_SIZE);
+ }
+ }
+
+ // Sphere dots.
p.setPen(Qt::NoPen);
p.setBrush(GetRawInputColor());
- GenerateFibonacciSphere(SPHERE_POINT_COUNT, [&, this](const Common::Vec3& point) {
+ GenerateFibonacciSphere(SPHERE_POINT_COUNT, [&](const Common::Vec3& point) {
const auto pt = rotation * point;
if (pt.y > 0)
@@ -850,49 +881,36 @@ void GyroMappingIndicator::paintEvent(QPaintEvent*)
});
// Sphere outline.
- p.setPen(GetRawInputColor());
+ p.setPen(is_stable ? GetRawInputColor() : GetAdjustedInputColor());
p.setBrush(Qt::NoBrush);
p.drawEllipse(QPointF{}, scale * SPHERE_SIZE, scale * SPHERE_SIZE);
- // Red dot upright target.
- p.setPen(QPen(GetAdjustedInputColor(), INPUT_DOT_RADIUS / 2));
- p.drawEllipse(QPointF{0, -SPHERE_INDICATOR_DIST} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
+ p.setPen(Qt::NoPen);
// Red dot.
const auto point = rotation * Common::Vec3{0, 0, -SPHERE_INDICATOR_DIST};
if (point.y > 0 || Common::Vec2(point.x, point.z).Length() > SPHERE_SIZE)
{
- p.setPen(Qt::NoPen);
p.setBrush(GetAdjustedInputColor());
p.drawEllipse(QPointF(point.x, point.z) * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
}
-
- // Blue dot target.
- p.setPen(QPen(Qt::blue, INPUT_DOT_RADIUS / 2));
- p.setBrush(Qt::NoBrush);
- p.drawEllipse(QPointF{}, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
-
// Blue dot.
const auto point2 = rotation * Common::Vec3{0, SPHERE_INDICATOR_DIST, 0};
if (point2.y > 0 || Common::Vec2(point2.x, point2.z).Length() > SPHERE_SIZE)
{
- p.setPen(Qt::NoPen);
p.setBrush(Qt::blue);
p.drawEllipse(QPointF(point2.x, point2.z) * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
}
- // Only draw text if data is present.
- if (!gyro_state.has_value())
- return;
+ p.setBrush(Qt::NoBrush);
- // Angle of red dot from starting position.
- const auto angle = std::acos(point.Normalized().Dot({0, 0, -1}));
+ // Red dot upright target.
+ p.setPen(QPen(GetAdjustedInputColor(), INPUT_DOT_RADIUS / 2));
+ p.drawEllipse(QPointF{0, -SPHERE_INDICATOR_DIST} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
- // Angle text:
- p.setPen(GetTextColor());
- p.drawText(QRectF(-2, 0, scale, scale), Qt::AlignBottom | Qt::AlignRight,
- // i18n: "°" is the symbol for degrees (angular measurement).
- QString::fromStdString(fmt::format("{:.2f} °", angle / MathUtil::TAU * 360)));
+ // Blue dot target.
+ p.setPen(QPen(Qt::blue, INPUT_DOT_RADIUS / 2));
+ p.drawEllipse(QPointF{}, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS);
}
void MappingIndicator::DrawCalibration(QPainter& p, Common::DVec2 point)
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.cpp
index 84f9f20821..6109f20b8c 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.cpp
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.cpp
@@ -7,6 +7,7 @@
#include <memory>
#include "Common/Common.h"
+#include "Common/MathUtil.h"
#include "InputCommon/ControlReference/ControlReference.h"
#include "InputCommon/ControllerEmu/Control/Control.h"
@@ -23,6 +24,21 @@ IMUGyroscope::IMUGyroscope(std::string name, std::string ui_name)
AddInput(Translate, _trans("Roll Right"));
AddInput(Translate, _trans("Yaw Left"));
AddInput(Translate, _trans("Yaw Right"));
+
+ AddSetting(&m_deadzone_setting,
+ {_trans("Dead Zone"),
+ // i18n: "°/s" is the symbol for degrees (angular measurement) divided by seconds.
+ _trans("°/s"),
+ // i18n: Refers to the dead-zone setting of gyroscope input.
+ _trans("Angular velocity to ignore.")},
+ 1, 0, 180);
+}
+
+auto IMUGyroscope::GetRawState() const -> StateData
+{
+ return StateData(controls[1]->GetState() - controls[0]->GetState(),
+ controls[2]->GetState() - controls[3]->GetState(),
+ controls[4]->GetState() - controls[5]->GetState());
}
std::optional<IMUGyroscope::StateData> IMUGyroscope::GetState() const
@@ -30,11 +46,18 @@ std::optional<IMUGyroscope::StateData> IMUGyroscope::GetState() const
if (controls[0]->control_ref->BoundCount() == 0)
return std::nullopt;
- StateData state;
- state.x = (controls[1]->GetState() - controls[0]->GetState());
- state.y = (controls[2]->GetState() - controls[3]->GetState());
- state.z = (controls[4]->GetState() - controls[5]->GetState());
+ auto state = GetRawState();
+
+ // Apply "deadzone".
+ for (auto& c : state.data)
+ c *= std::abs(c) > GetDeadzone();
+
return state;
}
+ControlState IMUGyroscope::GetDeadzone() const
+{
+ return m_deadzone_setting.GetValue() / 360 * MathUtil::TAU;
+}
+
} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h
index c173c2f8b2..1258a3eb76 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h
@@ -9,6 +9,7 @@
#include "Common/Matrix.h"
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+#include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
namespace ControllerEmu
{
@@ -19,6 +20,13 @@ public:
IMUGyroscope(std::string name, std::string ui_name);
+ StateData GetRawState() const;
std::optional<StateData> GetState() const;
+
+ // Value is in rad/s.
+ ControlState GetDeadzone() const;
+
+private:
+ SettingValue<double> m_deadzone_setting;
};
} // namespace ControllerEmu