yuzu: Add motion preview to controller input
This commit is contained in:
parent
2506594c50
commit
46e835f2d6
7 changed files with 151 additions and 4 deletions
|
@ -259,6 +259,20 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RotateFromOrigin(float roll, float pitch, float yaw) {
|
||||||
|
float temp = y;
|
||||||
|
y = std::cos(roll) * y - std::sin(roll) * z;
|
||||||
|
z = std::sin(roll) * temp + std::cos(roll) * z;
|
||||||
|
|
||||||
|
temp = x;
|
||||||
|
x = std::cosf(pitch) * x + std::sin(pitch) * z;
|
||||||
|
z = -std::sin(pitch) * temp + std::cos(pitch) * z;
|
||||||
|
|
||||||
|
temp = x;
|
||||||
|
x = std::cos(yaw) * x - std::sin(yaw) * y;
|
||||||
|
y = std::sin(yaw) * temp + std::cos(yaw) * y;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr T Length2() const {
|
[[nodiscard]] constexpr T Length2() const {
|
||||||
return x * x + y * y + z * z;
|
return x * x + y * y + z * z;
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,6 +376,7 @@ void EmulatedController::ReloadInput() {
|
||||||
motion.accel = emulated_motion.GetAcceleration();
|
motion.accel = emulated_motion.GetAcceleration();
|
||||||
motion.gyro = emulated_motion.GetGyroscope();
|
motion.gyro = emulated_motion.GetGyroscope();
|
||||||
motion.rotation = emulated_motion.GetRotations();
|
motion.rotation = emulated_motion.GetRotations();
|
||||||
|
motion.euler = emulated_motion.GetEulerAngles();
|
||||||
motion.orientation = emulated_motion.GetOrientation();
|
motion.orientation = emulated_motion.GetOrientation();
|
||||||
motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
|
motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
|
||||||
}
|
}
|
||||||
|
@ -976,14 +977,11 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
|
||||||
emulated.UpdateOrientation(raw_status.delta_timestamp);
|
emulated.UpdateOrientation(raw_status.delta_timestamp);
|
||||||
force_update_motion = raw_status.force_update;
|
force_update_motion = raw_status.force_update;
|
||||||
|
|
||||||
if (is_configuring) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& motion = controller.motion_state[index];
|
auto& motion = controller.motion_state[index];
|
||||||
motion.accel = emulated.GetAcceleration();
|
motion.accel = emulated.GetAcceleration();
|
||||||
motion.gyro = emulated.GetGyroscope();
|
motion.gyro = emulated.GetGyroscope();
|
||||||
motion.rotation = emulated.GetRotations();
|
motion.rotation = emulated.GetRotations();
|
||||||
|
motion.euler = emulated.GetEulerAngles();
|
||||||
motion.orientation = emulated.GetOrientation();
|
motion.orientation = emulated.GetOrientation();
|
||||||
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
|
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,7 @@ struct ControllerMotion {
|
||||||
Common::Vec3f accel{};
|
Common::Vec3f accel{};
|
||||||
Common::Vec3f gyro{};
|
Common::Vec3f gyro{};
|
||||||
Common::Vec3f rotation{};
|
Common::Vec3f rotation{};
|
||||||
|
Common::Vec3f euler{};
|
||||||
std::array<Common::Vec3f, 3> orientation{};
|
std::array<Common::Vec3f, 3> orientation{};
|
||||||
bool is_at_rest{};
|
bool is_at_rest{};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
#include "core/hid/motion_input.h"
|
#include "core/hid/motion_input.h"
|
||||||
|
|
||||||
|
@ -51,6 +53,20 @@ void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) {
|
||||||
quat = quaternion;
|
quat = quaternion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MotionInput::SetEulerAngles(const Common::Vec3f& euler_angles) {
|
||||||
|
const float cr = std::cos(euler_angles.x * 0.5f);
|
||||||
|
const float sr = std::sin(euler_angles.x * 0.5f);
|
||||||
|
const float cp = std::cos(euler_angles.y * 0.5f);
|
||||||
|
const float sp = std::sin(euler_angles.y * 0.5f);
|
||||||
|
const float cy = std::cos(euler_angles.z * 0.5f);
|
||||||
|
const float sy = std::sin(euler_angles.z * 0.5f);
|
||||||
|
|
||||||
|
quat.w = cr * cp * cy + sr * sp * sy;
|
||||||
|
quat.xyz.x = sr * cp * cy - cr * sp * sy;
|
||||||
|
quat.xyz.y = cr * sp * cy + sr * cp * sy;
|
||||||
|
quat.xyz.z = cr * cp * sy - sr * sp * cy;
|
||||||
|
}
|
||||||
|
|
||||||
void MotionInput::SetGyroBias(const Common::Vec3f& bias) {
|
void MotionInput::SetGyroBias(const Common::Vec3f& bias) {
|
||||||
gyro_bias = bias;
|
gyro_bias = bias;
|
||||||
}
|
}
|
||||||
|
@ -222,6 +238,26 @@ Common::Vec3f MotionInput::GetRotations() const {
|
||||||
return rotations;
|
return rotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Common::Vec3f MotionInput::GetEulerAngles() const {
|
||||||
|
// roll (x-axis rotation)
|
||||||
|
const float sinr_cosp = 2 * (quat.w * quat.xyz.x + quat.xyz.y * quat.xyz.z);
|
||||||
|
const float cosr_cosp = 1 - 2 * (quat.xyz.x * quat.xyz.x + quat.xyz.y * quat.xyz.y);
|
||||||
|
|
||||||
|
// pitch (y-axis rotation)
|
||||||
|
const float sinp = std::sqrt(1 + 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
|
||||||
|
const float cosp = std::sqrt(1 - 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
|
||||||
|
|
||||||
|
// yaw (z-axis rotation)
|
||||||
|
const float siny_cosp = 2 * (quat.w * quat.xyz.z + quat.xyz.x * quat.xyz.y);
|
||||||
|
const float cosy_cosp = 1 - 2 * (quat.xyz.y * quat.xyz.y + quat.xyz.z * quat.xyz.z);
|
||||||
|
|
||||||
|
return {
|
||||||
|
std::atan2(sinr_cosp, cosr_cosp),
|
||||||
|
2 * std::atan2(sinp, cosp) - Common::PI / 2,
|
||||||
|
std::atan2(siny_cosp, cosy_cosp),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void MotionInput::ResetOrientation() {
|
void MotionInput::ResetOrientation() {
|
||||||
if (!reset_enabled || only_accelerometer) {
|
if (!reset_enabled || only_accelerometer) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -35,6 +35,7 @@ public:
|
||||||
void SetAcceleration(const Common::Vec3f& acceleration);
|
void SetAcceleration(const Common::Vec3f& acceleration);
|
||||||
void SetGyroscope(const Common::Vec3f& gyroscope);
|
void SetGyroscope(const Common::Vec3f& gyroscope);
|
||||||
void SetQuaternion(const Common::Quaternion<f32>& quaternion);
|
void SetQuaternion(const Common::Quaternion<f32>& quaternion);
|
||||||
|
void SetEulerAngles(const Common::Vec3f& euler_angles);
|
||||||
void SetGyroBias(const Common::Vec3f& bias);
|
void SetGyroBias(const Common::Vec3f& bias);
|
||||||
void SetGyroThreshold(f32 threshold);
|
void SetGyroThreshold(f32 threshold);
|
||||||
|
|
||||||
|
@ -54,6 +55,7 @@ public:
|
||||||
[[nodiscard]] Common::Vec3f GetGyroBias() const;
|
[[nodiscard]] Common::Vec3f GetGyroBias() const;
|
||||||
[[nodiscard]] Common::Vec3f GetRotations() const;
|
[[nodiscard]] Common::Vec3f GetRotations() const;
|
||||||
[[nodiscard]] Common::Quaternion<f32> GetQuaternion() const;
|
[[nodiscard]] Common::Quaternion<f32> GetQuaternion() const;
|
||||||
|
[[nodiscard]] Common::Vec3f GetEulerAngles() const;
|
||||||
|
|
||||||
[[nodiscard]] bool IsMoving(f32 sensitivity) const;
|
[[nodiscard]] bool IsMoving(f32 sensitivity) const;
|
||||||
[[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
|
[[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
|
||||||
|
|
|
@ -180,6 +180,10 @@ void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType typ
|
||||||
battery_values = controller->GetBatteryValues();
|
battery_values = controller->GetBatteryValues();
|
||||||
needs_redraw = true;
|
needs_redraw = true;
|
||||||
break;
|
break;
|
||||||
|
case Core::HID::ControllerTriggerType::Motion:
|
||||||
|
motion_values = controller->GetMotions();
|
||||||
|
needs_redraw = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -313,6 +317,15 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
|
||||||
DrawRawJoystick(p, center + QPointF(-140, 90), QPointF(0, 0));
|
DrawRawJoystick(p, center + QPointF(-140, 90), QPointF(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Draw motion cubes
|
||||||
|
using namespace Settings::NativeMotion;
|
||||||
|
p.setPen(colors.outline);
|
||||||
|
p.setBrush(colors.transparent);
|
||||||
|
Draw3dCube(p, center + QPointF(-140, 90),
|
||||||
|
motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f);
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Settings::NativeButton;
|
using namespace Settings::NativeButton;
|
||||||
|
|
||||||
// D-pad constants
|
// D-pad constants
|
||||||
|
@ -435,6 +448,15 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
|
||||||
DrawRawJoystick(p, QPointF(0, 0), center + QPointF(140, 90));
|
DrawRawJoystick(p, QPointF(0, 0), center + QPointF(140, 90));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Draw motion cubes
|
||||||
|
using namespace Settings::NativeMotion;
|
||||||
|
p.setPen(colors.outline);
|
||||||
|
p.setBrush(colors.transparent);
|
||||||
|
Draw3dCube(p, center + QPointF(140, 90),
|
||||||
|
motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f);
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Settings::NativeButton;
|
using namespace Settings::NativeButton;
|
||||||
|
|
||||||
// Face buttons constants
|
// Face buttons constants
|
||||||
|
@ -555,6 +577,17 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
|
||||||
DrawRawJoystick(p, center + QPointF(-180, 90), center + QPointF(180, 90));
|
DrawRawJoystick(p, center + QPointF(-180, 90), center + QPointF(180, 90));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Draw motion cubes
|
||||||
|
using namespace Settings::NativeMotion;
|
||||||
|
p.setPen(colors.outline);
|
||||||
|
p.setBrush(colors.transparent);
|
||||||
|
Draw3dCube(p, center + QPointF(-180, -5),
|
||||||
|
motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f);
|
||||||
|
Draw3dCube(p, center + QPointF(180, -5),
|
||||||
|
motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f);
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Settings::NativeButton;
|
using namespace Settings::NativeButton;
|
||||||
|
|
||||||
// Face buttons constants
|
// Face buttons constants
|
||||||
|
@ -647,6 +680,15 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
|
||||||
DrawRawJoystick(p, center + QPointF(-50, 0), center + QPointF(50, 0));
|
DrawRawJoystick(p, center + QPointF(-50, 0), center + QPointF(50, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Draw motion cubes
|
||||||
|
using namespace Settings::NativeMotion;
|
||||||
|
p.setPen(colors.outline);
|
||||||
|
p.setBrush(colors.transparent);
|
||||||
|
Draw3dCube(p, center + QPointF(0, -115),
|
||||||
|
motion_values[Settings::NativeMotion::MotionLeft].euler, 15.0f);
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Settings::NativeButton;
|
using namespace Settings::NativeButton;
|
||||||
|
|
||||||
// Face buttons constants
|
// Face buttons constants
|
||||||
|
@ -750,6 +792,15 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
|
||||||
DrawRawJoystick(p, center + QPointF(-50, 105), center + QPointF(50, 105));
|
DrawRawJoystick(p, center + QPointF(-50, 105), center + QPointF(50, 105));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Draw motion cubes
|
||||||
|
using namespace Settings::NativeMotion;
|
||||||
|
p.setPen(colors.button);
|
||||||
|
p.setBrush(colors.transparent);
|
||||||
|
Draw3dCube(p, center + QPointF(0, -100),
|
||||||
|
motion_values[Settings::NativeMotion::MotionLeft].euler, 15.0f);
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Settings::NativeButton;
|
using namespace Settings::NativeButton;
|
||||||
|
|
||||||
// Face buttons constants
|
// Face buttons constants
|
||||||
|
@ -2871,6 +2922,46 @@ void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Di
|
||||||
DrawPolygon(p, arrow_symbol);
|
DrawPolygon(p, arrow_symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw motion functions
|
||||||
|
void PlayerControlPreview::Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler,
|
||||||
|
float size) {
|
||||||
|
std::array<Common::Vec3f, 8> cube{
|
||||||
|
Common::Vec3f{-1, -1, -1},
|
||||||
|
{-1, 1, -1},
|
||||||
|
{1, 1, -1},
|
||||||
|
{1, -1, -1},
|
||||||
|
{-1, -1, 1},
|
||||||
|
{-1, 1, 1},
|
||||||
|
{1, 1, 1},
|
||||||
|
{1, -1, 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (Common::Vec3f& point : cube) {
|
||||||
|
point.RotateFromOrigin(euler.x, euler.y, euler.z);
|
||||||
|
point *= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::array<QPointF, 4> front_face{
|
||||||
|
center + QPointF{cube[0].x, cube[0].y},
|
||||||
|
center + QPointF{cube[1].x, cube[1].y},
|
||||||
|
center + QPointF{cube[2].x, cube[2].y},
|
||||||
|
center + QPointF{cube[3].x, cube[3].y},
|
||||||
|
};
|
||||||
|
const std::array<QPointF, 4> back_face{
|
||||||
|
center + QPointF{cube[4].x, cube[4].y},
|
||||||
|
center + QPointF{cube[5].x, cube[5].y},
|
||||||
|
center + QPointF{cube[6].x, cube[6].y},
|
||||||
|
center + QPointF{cube[7].x, cube[7].y},
|
||||||
|
};
|
||||||
|
|
||||||
|
DrawPolygon(p, front_face);
|
||||||
|
DrawPolygon(p, back_face);
|
||||||
|
p.drawLine(center + QPointF{cube[0].x, cube[0].y}, center + QPointF{cube[4].x, cube[4].y});
|
||||||
|
p.drawLine(center + QPointF{cube[1].x, cube[1].y}, center + QPointF{cube[5].x, cube[5].y});
|
||||||
|
p.drawLine(center + QPointF{cube[2].x, cube[2].y}, center + QPointF{cube[6].x, cube[6].y});
|
||||||
|
p.drawLine(center + QPointF{cube[3].x, cube[3].y}, center + QPointF{cube[7].x, cube[7].y});
|
||||||
|
}
|
||||||
|
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
void PlayerControlPreview::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) {
|
void PlayerControlPreview::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) {
|
||||||
p.drawPolygon(polygon.data(), static_cast<int>(polygon.size()));
|
p.drawPolygon(polygon.data(), static_cast<int>(polygon.size()));
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "common/input.h"
|
#include "common/input.h"
|
||||||
#include "common/settings_input.h"
|
#include "common/settings_input.h"
|
||||||
|
#include "common/vector_math.h"
|
||||||
#include "core/hid/emulated_controller.h"
|
#include "core/hid/emulated_controller.h"
|
||||||
#include "core/hid/hid_types.h"
|
#include "core/hid/hid_types.h"
|
||||||
|
|
||||||
|
@ -193,6 +194,9 @@ private:
|
||||||
void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size);
|
void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size);
|
||||||
void DrawArrow(QPainter& p, QPointF center, Direction direction, float size);
|
void DrawArrow(QPainter& p, QPointF center, Direction direction, float size);
|
||||||
|
|
||||||
|
// Draw motion functions
|
||||||
|
void Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler, float size);
|
||||||
|
|
||||||
// Draw primitive types
|
// Draw primitive types
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
void DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon);
|
void DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon);
|
||||||
|
@ -222,4 +226,5 @@ private:
|
||||||
Core::HID::SticksValues stick_values{};
|
Core::HID::SticksValues stick_values{};
|
||||||
Core::HID::TriggerValues trigger_values{};
|
Core::HID::TriggerValues trigger_values{};
|
||||||
Core::HID::BatteryValues battery_values{};
|
Core::HID::BatteryValues battery_values{};
|
||||||
|
Core::HID::MotionState motion_values{};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue