mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	move MotionEmu from core/frontend to input_common as a InputDevice
This commit is contained in:
		
							parent
							
								
									867eabd6b7
								
							
						
					
					
						commit
						188194908c
					
				
					 17 changed files with 221 additions and 244 deletions
				
			
		|  | @ -62,29 +62,6 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { | |||
|     TouchPressed(framebuffer_x, framebuffer_y); | ||||
| } | ||||
| 
 | ||||
| void EmuWindow::AccelerometerChanged(float x, float y, float z) { | ||||
|     constexpr float coef = 512; | ||||
| 
 | ||||
|     std::lock_guard<std::mutex> lock(accel_mutex); | ||||
| 
 | ||||
|     // TODO(wwylele): do a time stretch as it in GyroscopeChanged
 | ||||
|     // The time stretch formula should be like
 | ||||
|     // stretched_vector = (raw_vector - gravity) * stretch_ratio + gravity
 | ||||
|     accel_x = static_cast<s16>(x * coef); | ||||
|     accel_y = static_cast<s16>(y * coef); | ||||
|     accel_z = static_cast<s16>(z * coef); | ||||
| } | ||||
| 
 | ||||
| void EmuWindow::GyroscopeChanged(float x, float y, float z) { | ||||
|     constexpr float FULL_FPS = 60; | ||||
|     float coef = GetGyroscopeRawToDpsCoefficient(); | ||||
|     float stretch = Core::System::GetInstance().perf_stats.GetLastFrameTimeScale(); | ||||
|     std::lock_guard<std::mutex> lock(gyro_mutex); | ||||
|     gyro_x = static_cast<s16>(x * coef * stretch); | ||||
|     gyro_y = static_cast<s16>(y * coef * stretch); | ||||
|     gyro_z = static_cast<s16>(z * coef * stretch); | ||||
| } | ||||
| 
 | ||||
| void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { | ||||
|     Layout::FramebufferLayout layout; | ||||
|     if (Settings::values.custom_layout == true) { | ||||
|  |  | |||
|  | @ -68,27 +68,6 @@ public: | |||
|      */ | ||||
|     void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Signal accelerometer state has changed. | ||||
|      * @param x X-axis accelerometer value | ||||
|      * @param y Y-axis accelerometer value | ||||
|      * @param z Z-axis accelerometer value | ||||
|      * @note all values are in unit of g (gravitational acceleration). | ||||
|      *    e.g. x = 1.0 means 9.8m/s^2 in x direction. | ||||
|      * @see GetAccelerometerState for axis explanation. | ||||
|      */ | ||||
|     void AccelerometerChanged(float x, float y, float z); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Signal gyroscope state has changed. | ||||
|      * @param x X-axis accelerometer value | ||||
|      * @param y Y-axis accelerometer value | ||||
|      * @param z Z-axis accelerometer value | ||||
|      * @note all values are in deg/sec. | ||||
|      * @see GetGyroscopeState for axis explanation. | ||||
|      */ | ||||
|     void GyroscopeChanged(float x, float y, float z); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed). | ||||
|      * @note This should be called by the core emu thread to get a state set by the window thread. | ||||
|  | @ -100,52 +79,6 @@ public: | |||
|         return std::make_tuple(touch_x, touch_y, touch_pressed); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the current accelerometer state (acceleration along each three axis). | ||||
|      * Axis explained: | ||||
|      *   +x is the same direction as LEFT on D-pad. | ||||
|      *   +y is normal to the touch screen, pointing outward. | ||||
|      *   +z is the same direction as UP on D-pad. | ||||
|      * Units: | ||||
|      *   1 unit of return value = 1/512 g (measured by hw test), | ||||
|      *   where g is the gravitational acceleration (9.8 m/sec2). | ||||
|      * @note This should be called by the core emu thread to get a state set by the window thread. | ||||
|      * @return std::tuple of (x, y, z) | ||||
|      */ | ||||
|     std::tuple<s16, s16, s16> GetAccelerometerState() { | ||||
|         std::lock_guard<std::mutex> lock(accel_mutex); | ||||
|         return std::make_tuple(accel_x, accel_y, accel_z); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the current gyroscope state (angular rates about each three axis). | ||||
|      * Axis explained: | ||||
|      *   +x is the same direction as LEFT on D-pad. | ||||
|      *   +y is normal to the touch screen, pointing outward. | ||||
|      *   +z is the same direction as UP on D-pad. | ||||
|      * Orientation is determined by right-hand rule. | ||||
|      * Units: | ||||
|      *   1 unit of return value = (1/coef) deg/sec, | ||||
|      *   where coef is the return value of GetGyroscopeRawToDpsCoefficient(). | ||||
|      * @note This should be called by the core emu thread to get a state set by the window thread. | ||||
|      * @return std::tuple of (x, y, z) | ||||
|      */ | ||||
|     std::tuple<s16, s16, s16> GetGyroscopeState() { | ||||
|         std::lock_guard<std::mutex> lock(gyro_mutex); | ||||
|         return std::make_tuple(gyro_x, gyro_y, gyro_z); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the coefficient for units conversion of gyroscope state. | ||||
|      * The conversion formula is r = coefficient * v, | ||||
|      * where v is angular rate in deg/sec, | ||||
|      * and r is the gyroscope state. | ||||
|      * @return float-type coefficient | ||||
|      */ | ||||
|     f32 GetGyroscopeRawToDpsCoefficient() const { | ||||
|         return 14.375f; // taken from hw test, and gyroscope's document
 | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Returns currently active configuration. | ||||
|      * @note Accesses to the returned object need not be consistent because it may be modified in | ||||
|  | @ -187,12 +120,6 @@ protected: | |||
|         touch_x = 0; | ||||
|         touch_y = 0; | ||||
|         touch_pressed = false; | ||||
|         accel_x = 0; | ||||
|         accel_y = -512; | ||||
|         accel_z = 0; | ||||
|         gyro_x = 0; | ||||
|         gyro_y = 0; | ||||
|         gyro_z = 0; | ||||
|     } | ||||
|     virtual ~EmuWindow() {} | ||||
| 
 | ||||
|  | @ -255,16 +182,6 @@ private: | |||
|     u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
 | ||||
|     u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
 | ||||
| 
 | ||||
|     std::mutex accel_mutex; | ||||
|     s16 accel_x; ///< Accelerometer X-axis value in native 3DS units
 | ||||
|     s16 accel_y; ///< Accelerometer Y-axis value in native 3DS units
 | ||||
|     s16 accel_z; ///< Accelerometer Z-axis value in native 3DS units
 | ||||
| 
 | ||||
|     std::mutex gyro_mutex; | ||||
|     s16 gyro_x; ///< Gyroscope X-axis value in native 3DS units
 | ||||
|     s16 gyro_y; ///< Gyroscope Y-axis value in native 3DS units
 | ||||
|     s16 gyro_z; ///< Gyroscope Z-axis value in native 3DS units
 | ||||
| 
 | ||||
|     /**
 | ||||
|      * Clip the provided coordinates to be inside the touchscreen area. | ||||
|      */ | ||||
|  |  | |||
|  | @ -112,16 +112,15 @@ using AnalogDevice = InputDevice<std::tuple<float, float>>; | |||
|  * A motion device is an input device that returns a tuple of accelerometer state vector and | ||||
|  * gyroscope state vector. | ||||
|  * | ||||
|  * For accelerometer state vector: | ||||
|  * For both vectors: | ||||
|  *   x+ is the same direction as LEFT on D-pad. | ||||
|  *   y+ is normal to the touch screen, pointing outward. | ||||
|  *   z+ is the same direction as UP on D-pad. | ||||
|  *   Units: measured in unit of gravitational acceleration | ||||
|  * | ||||
|  * For accelerometer state vector | ||||
|  *   Units: g (gravitational acceleration) | ||||
|  * | ||||
|  * For gyroscope state vector: | ||||
|  *   x+ is the same direction as LEFT on D-pad. | ||||
|  *   y+ is normal to the touch screen, pointing outward. | ||||
|  *   z+ is the same direction as UP on D-pad. | ||||
|  *   Orientation is determined by right-hand rule. | ||||
|  *   Units: deg/sec | ||||
|  */ | ||||
|  |  | |||
|  | @ -1,89 +0,0 @@ | |||
| // Copyright 2016 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "common/math_util.h" | ||||
| #include "common/quaternion.h" | ||||
| #include "core/frontend/emu_window.h" | ||||
| #include "core/frontend/motion_emu.h" | ||||
| 
 | ||||
| namespace Motion { | ||||
| 
 | ||||
| static constexpr int update_millisecond = 100; | ||||
| static constexpr auto update_duration = | ||||
|     std::chrono::duration_cast<std::chrono::steady_clock::duration>( | ||||
|         std::chrono::milliseconds(update_millisecond)); | ||||
| 
 | ||||
| MotionEmu::MotionEmu(EmuWindow& emu_window) | ||||
|     : motion_emu_thread(&MotionEmu::MotionEmuThread, this, std::ref(emu_window)) {} | ||||
| 
 | ||||
| MotionEmu::~MotionEmu() { | ||||
|     if (motion_emu_thread.joinable()) { | ||||
|         shutdown_event.Set(); | ||||
|         motion_emu_thread.join(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MotionEmu::MotionEmuThread(EmuWindow& emu_window) { | ||||
|     auto update_time = std::chrono::steady_clock::now(); | ||||
|     Math::Quaternion<float> q = MakeQuaternion(Math::Vec3<float>(), 0); | ||||
|     Math::Quaternion<float> old_q; | ||||
| 
 | ||||
|     while (!shutdown_event.WaitUntil(update_time)) { | ||||
|         update_time += update_duration; | ||||
|         old_q = q; | ||||
| 
 | ||||
|         { | ||||
|             std::lock_guard<std::mutex> guard(tilt_mutex); | ||||
| 
 | ||||
|             // Find the quaternion describing current 3DS tilting
 | ||||
|             q = MakeQuaternion(Math::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), | ||||
|                                tilt_angle); | ||||
|         } | ||||
| 
 | ||||
|         auto inv_q = q.Inverse(); | ||||
| 
 | ||||
|         // Set the gravity vector in world space
 | ||||
|         auto gravity = Math::MakeVec(0.0f, -1.0f, 0.0f); | ||||
| 
 | ||||
|         // Find the angular rate vector in world space
 | ||||
|         auto angular_rate = ((q - old_q) * inv_q).xyz * 2; | ||||
|         angular_rate *= 1000 / update_millisecond / MathUtil::PI * 180; | ||||
| 
 | ||||
|         // Transform the two vectors from world space to 3DS space
 | ||||
|         gravity = QuaternionRotate(inv_q, gravity); | ||||
|         angular_rate = QuaternionRotate(inv_q, angular_rate); | ||||
| 
 | ||||
|         // Update the sensor state
 | ||||
|         emu_window.AccelerometerChanged(gravity.x, gravity.y, gravity.z); | ||||
|         emu_window.GyroscopeChanged(angular_rate.x, angular_rate.y, angular_rate.z); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MotionEmu::BeginTilt(int x, int y) { | ||||
|     mouse_origin = Math::MakeVec(x, y); | ||||
|     is_tilting = true; | ||||
| } | ||||
| 
 | ||||
| void MotionEmu::Tilt(int x, int y) { | ||||
|     constexpr float SENSITIVITY = 0.01f; | ||||
|     auto mouse_move = Math::MakeVec(x, y) - mouse_origin; | ||||
|     if (is_tilting) { | ||||
|         std::lock_guard<std::mutex> guard(tilt_mutex); | ||||
|         if (mouse_move.x == 0 && mouse_move.y == 0) { | ||||
|             tilt_angle = 0; | ||||
|         } else { | ||||
|             tilt_direction = mouse_move.Cast<float>(); | ||||
|             tilt_angle = MathUtil::Clamp(tilt_direction.Normalize() * SENSITIVITY, 0.0f, | ||||
|                                          MathUtil::PI * 0.5f); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MotionEmu::EndTilt() { | ||||
|     std::lock_guard<std::mutex> guard(tilt_mutex); | ||||
|     tilt_angle = 0; | ||||
|     is_tilting = false; | ||||
| } | ||||
| 
 | ||||
| } // namespace Motion
 | ||||
|  | @ -1,52 +0,0 @@ | |||
| // Copyright 2016 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include "common/thread.h" | ||||
| #include "common/vector_math.h" | ||||
| 
 | ||||
| class EmuWindow; | ||||
| 
 | ||||
| namespace Motion { | ||||
| 
 | ||||
| class MotionEmu final { | ||||
| public: | ||||
|     MotionEmu(EmuWindow& emu_window); | ||||
|     ~MotionEmu(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Signals that a motion sensor tilt has begun. | ||||
|      * @param x the x-coordinate of the cursor | ||||
|      * @param y the y-coordinate of the cursor | ||||
|      */ | ||||
|     void BeginTilt(int x, int y); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Signals that a motion sensor tilt is occurring. | ||||
|      * @param x the x-coordinate of the cursor | ||||
|      * @param y the y-coordinate of the cursor | ||||
|      */ | ||||
|     void Tilt(int x, int y); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Signals that a motion sensor tilt has ended. | ||||
|      */ | ||||
|     void EndTilt(); | ||||
| 
 | ||||
| private: | ||||
|     Math::Vec2<int> mouse_origin; | ||||
| 
 | ||||
|     std::mutex tilt_mutex; | ||||
|     Math::Vec2<float> tilt_direction; | ||||
|     float tilt_angle = 0; | ||||
| 
 | ||||
|     bool is_tilting = false; | ||||
| 
 | ||||
|     Common::Event shutdown_event; | ||||
|     std::thread motion_emu_thread; | ||||
| 
 | ||||
|     void MotionEmuThread(EmuWindow& emu_window); | ||||
| }; | ||||
| 
 | ||||
| } // namespace Motion
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue