summaryrefslogtreecommitdiff
path: root/src/input_common/motion_emu.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2020-11-29 22:59:50 -0800
committerGravatar GitHub2020-11-29 22:59:50 -0800
commit7bc3e80399d62aabe4acbba094d0fff23a187186 (patch)
treeac12ca41f34fdda51992fedfeb55b169dedcfcaf /src/input_common/motion_emu.cpp
parentMerge pull request #5005 from ReinUsesLisp/div-ceil (diff)
parentImplement full mouse support (diff)
downloadyuzu-7bc3e80399d62aabe4acbba094d0fff23a187186.tar.gz
yuzu-7bc3e80399d62aabe4acbba094d0fff23a187186.tar.xz
yuzu-7bc3e80399d62aabe4acbba094d0fff23a187186.zip
Merge pull request #4939 from german77/MouseInput
InputCommon: Implement full mouse support
Diffstat (limited to 'src/input_common/motion_emu.cpp')
-rw-r--r--src/input_common/motion_emu.cpp179
1 files changed, 0 insertions, 179 deletions
diff --git a/src/input_common/motion_emu.cpp b/src/input_common/motion_emu.cpp
deleted file mode 100644
index d4da5596b..000000000
--- a/src/input_common/motion_emu.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <chrono>
7#include <mutex>
8#include <thread>
9#include <tuple>
10#include "common/math_util.h"
11#include "common/quaternion.h"
12#include "common/thread.h"
13#include "common/vector_math.h"
14#include "input_common/motion_emu.h"
15
16namespace InputCommon {
17
18// Implementation class of the motion emulation device
19class MotionEmuDevice {
20public:
21 explicit MotionEmuDevice(int update_millisecond_, float sensitivity_)
22 : update_millisecond(update_millisecond_),
23 update_duration(std::chrono::duration_cast<std::chrono::steady_clock::duration>(
24 std::chrono::milliseconds(update_millisecond))),
25 sensitivity(sensitivity_), motion_emu_thread(&MotionEmuDevice::MotionEmuThread, this) {}
26
27 ~MotionEmuDevice() {
28 if (motion_emu_thread.joinable()) {
29 shutdown_event.Set();
30 motion_emu_thread.join();
31 }
32 }
33
34 void BeginTilt(int x, int y) {
35 mouse_origin = Common::MakeVec(x, y);
36 is_tilting = true;
37 }
38
39 void Tilt(int x, int y) {
40 if (!is_tilting) {
41 return;
42 }
43
44 std::lock_guard guard{tilt_mutex};
45 const auto mouse_move = Common::MakeVec(x, y) - mouse_origin;
46 if (mouse_move.x == 0 && mouse_move.y == 0) {
47 tilt_angle = 0;
48 } else {
49 tilt_direction = mouse_move.Cast<float>();
50 tilt_angle =
51 std::clamp(tilt_direction.Normalize() * sensitivity, 0.0f, Common::PI * 0.5f);
52 }
53 }
54
55 void EndTilt() {
56 std::lock_guard guard{tilt_mutex};
57 tilt_angle = 0;
58 is_tilting = false;
59 }
60
61 Input::MotionStatus GetStatus() {
62 std::lock_guard guard{status_mutex};
63 return status;
64 }
65
66private:
67 const int update_millisecond;
68 const std::chrono::steady_clock::duration update_duration;
69 const float sensitivity;
70
71 Common::Vec2<int> mouse_origin;
72
73 std::mutex tilt_mutex;
74 Common::Vec2<float> tilt_direction;
75 float tilt_angle = 0;
76
77 bool is_tilting = false;
78
79 Common::Event shutdown_event;
80
81 Input::MotionStatus status;
82 std::mutex status_mutex;
83
84 // Note: always keep the thread declaration at the end so that other objects are initialized
85 // before this!
86 std::thread motion_emu_thread;
87
88 void MotionEmuThread() {
89 auto update_time = std::chrono::steady_clock::now();
90 Common::Quaternion<float> q = Common::MakeQuaternion(Common::Vec3<float>(), 0);
91
92 while (!shutdown_event.WaitUntil(update_time)) {
93 update_time += update_duration;
94 const Common::Quaternion<float> old_q = q;
95
96 {
97 std::lock_guard guard{tilt_mutex};
98
99 // Find the quaternion describing current 3DS tilting
100 q = Common::MakeQuaternion(
101 Common::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), tilt_angle);
102 }
103
104 const auto inv_q = q.Inverse();
105
106 // Set the gravity vector in world space
107 auto gravity = Common::MakeVec(0.0f, -1.0f, 0.0f);
108
109 // Find the angular rate vector in world space
110 auto angular_rate = ((q - old_q) * inv_q).xyz * 2;
111 angular_rate *= static_cast<float>(1000 / update_millisecond) / Common::PI * 180.0f;
112
113 // Transform the two vectors from world space to 3DS space
114 gravity = QuaternionRotate(inv_q, gravity);
115 angular_rate = QuaternionRotate(inv_q, angular_rate);
116
117 // TODO: Calculate the correct rotation vector and orientation matrix
118 const auto matrix4x4 = q.ToMatrix();
119 const auto rotation = Common::MakeVec(0.0f, 0.0f, 0.0f);
120 const std::array orientation{
121 Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]),
122 Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]),
123 Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10]),
124 };
125
126 // Update the sensor state
127 {
128 std::lock_guard guard{status_mutex};
129 status = std::make_tuple(gravity, angular_rate, rotation, orientation);
130 }
131 }
132 }
133};
134
135// Interface wrapper held by input receiver as a unique_ptr. It holds the implementation class as
136// a shared_ptr, which is also observed by the factory class as a weak_ptr. In this way the factory
137// can forward all the inputs to the implementation only when it is valid.
138class MotionEmuDeviceWrapper : public Input::MotionDevice {
139public:
140 explicit MotionEmuDeviceWrapper(int update_millisecond, float sensitivity) {
141 device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity);
142 }
143
144 Input::MotionStatus GetStatus() const override {
145 return device->GetStatus();
146 }
147
148 std::shared_ptr<MotionEmuDevice> device;
149};
150
151std::unique_ptr<Input::MotionDevice> MotionEmu::Create(const Common::ParamPackage& params) {
152 const int update_period = params.Get("update_period", 100);
153 const float sensitivity = params.Get("sensitivity", 0.01f);
154 auto device_wrapper = std::make_unique<MotionEmuDeviceWrapper>(update_period, sensitivity);
155 // Previously created device is disconnected here. Having two motion devices for 3DS is not
156 // expected.
157 current_device = device_wrapper->device;
158 return device_wrapper;
159}
160
161void MotionEmu::BeginTilt(int x, int y) {
162 if (auto ptr = current_device.lock()) {
163 ptr->BeginTilt(x, y);
164 }
165}
166
167void MotionEmu::Tilt(int x, int y) {
168 if (auto ptr = current_device.lock()) {
169 ptr->Tilt(x, y);
170 }
171}
172
173void MotionEmu::EndTilt() {
174 if (auto ptr = current_device.lock()) {
175 ptr->EndTilt();
176 }
177}
178
179} // namespace InputCommon