mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	Frontend: emulate motion sensor
This commit is contained in:
		
							parent
							
								
									6479f63091
								
							
						
					
					
						commit
						bcf9d20d57
					
				@ -19,16 +19,22 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
 | 
					void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
 | 
				
			||||||
    TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
 | 
					    TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
 | 
				
			||||||
 | 
					    motion_emu->Tilt(x, y);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
 | 
					void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
 | 
				
			||||||
    if (button != SDL_BUTTON_LEFT)
 | 
					    if (button == SDL_BUTTON_LEFT) {
 | 
				
			||||||
        return;
 | 
					        if (state == SDL_PRESSED) {
 | 
				
			||||||
 | 
					            TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
 | 
				
			||||||
    if (state == SDL_PRESSED) {
 | 
					        } else {
 | 
				
			||||||
        TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
 | 
					            TouchReleased();
 | 
				
			||||||
    } else {
 | 
					        }
 | 
				
			||||||
        TouchReleased();
 | 
					    } else if (button == SDL_BUTTON_RIGHT) {
 | 
				
			||||||
 | 
					        if (state == SDL_PRESSED) {
 | 
				
			||||||
 | 
					            motion_emu->BeginTilt(x, y);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            motion_emu->EndTilt();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -54,6 +60,7 @@ EmuWindow_SDL2::EmuWindow_SDL2() {
 | 
				
			|||||||
    keyboard_id = KeyMap::NewDeviceId();
 | 
					    keyboard_id = KeyMap::NewDeviceId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ReloadSetKeymaps();
 | 
					    ReloadSetKeymaps();
 | 
				
			||||||
 | 
					    motion_emu = std::make_unique<Motion::MotionEmu>(*this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SDL_SetMainReady();
 | 
					    SDL_SetMainReady();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -109,6 +116,7 @@ EmuWindow_SDL2::EmuWindow_SDL2() {
 | 
				
			|||||||
EmuWindow_SDL2::~EmuWindow_SDL2() {
 | 
					EmuWindow_SDL2::~EmuWindow_SDL2() {
 | 
				
			||||||
    SDL_GL_DeleteContext(gl_context);
 | 
					    SDL_GL_DeleteContext(gl_context);
 | 
				
			||||||
    SDL_Quit();
 | 
					    SDL_Quit();
 | 
				
			||||||
 | 
					    motion_emu = nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EmuWindow_SDL2::SwapBuffers() {
 | 
					void EmuWindow_SDL2::SwapBuffers() {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,8 +4,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
#include "core/frontend/emu_window.h"
 | 
					#include "core/frontend/emu_window.h"
 | 
				
			||||||
 | 
					#include "core/frontend/motion_emu.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct SDL_Window;
 | 
					struct SDL_Window;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -61,4 +63,7 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// Device id of keyboard for use with KeyMap
 | 
					    /// Device id of keyboard for use with KeyMap
 | 
				
			||||||
    int keyboard_id;
 | 
					    int keyboard_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Motion sensors emulation
 | 
				
			||||||
 | 
					    std::unique_ptr<Motion::MotionEmu> motion_emu;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -191,6 +191,7 @@ qreal GRenderWindow::windowPixelRatio() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GRenderWindow::closeEvent(QCloseEvent* event) {
 | 
					void GRenderWindow::closeEvent(QCloseEvent* event) {
 | 
				
			||||||
 | 
					    motion_emu = nullptr;
 | 
				
			||||||
    emit Closed();
 | 
					    emit Closed();
 | 
				
			||||||
    QWidget::closeEvent(event);
 | 
					    QWidget::closeEvent(event);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -204,11 +205,13 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GRenderWindow::mousePressEvent(QMouseEvent* event) {
 | 
					void GRenderWindow::mousePressEvent(QMouseEvent* event) {
 | 
				
			||||||
 | 
					    auto pos = event->pos();
 | 
				
			||||||
    if (event->button() == Qt::LeftButton) {
 | 
					    if (event->button() == Qt::LeftButton) {
 | 
				
			||||||
        auto pos = event->pos();
 | 
					 | 
				
			||||||
        qreal pixelRatio = windowPixelRatio();
 | 
					        qreal pixelRatio = windowPixelRatio();
 | 
				
			||||||
        this->TouchPressed(static_cast<unsigned>(pos.x() * pixelRatio),
 | 
					        this->TouchPressed(static_cast<unsigned>(pos.x() * pixelRatio),
 | 
				
			||||||
                           static_cast<unsigned>(pos.y() * pixelRatio));
 | 
					                           static_cast<unsigned>(pos.y() * pixelRatio));
 | 
				
			||||||
 | 
					    } else if (event->button() == Qt::RightButton) {
 | 
				
			||||||
 | 
					        motion_emu->BeginTilt(pos.x(), pos.y());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -217,11 +220,14 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
 | 
				
			|||||||
    qreal pixelRatio = windowPixelRatio();
 | 
					    qreal pixelRatio = windowPixelRatio();
 | 
				
			||||||
    this->TouchMoved(std::max(static_cast<unsigned>(pos.x() * pixelRatio), 0u),
 | 
					    this->TouchMoved(std::max(static_cast<unsigned>(pos.x() * pixelRatio), 0u),
 | 
				
			||||||
                     std::max(static_cast<unsigned>(pos.y() * pixelRatio), 0u));
 | 
					                     std::max(static_cast<unsigned>(pos.y() * pixelRatio), 0u));
 | 
				
			||||||
 | 
					    motion_emu->Tilt(pos.x(), pos.y());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
 | 
					void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
 | 
				
			||||||
    if (event->button() == Qt::LeftButton)
 | 
					    if (event->button() == Qt::LeftButton)
 | 
				
			||||||
        this->TouchReleased();
 | 
					        this->TouchReleased();
 | 
				
			||||||
 | 
					    else if (event->button() == Qt::RightButton)
 | 
				
			||||||
 | 
					        motion_emu->EndTilt();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GRenderWindow::ReloadSetKeymaps() {
 | 
					void GRenderWindow::ReloadSetKeymaps() {
 | 
				
			||||||
@ -279,11 +285,13 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) {
 | 
					void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) {
 | 
				
			||||||
 | 
					    motion_emu = std::make_unique<Motion::MotionEmu>(*this);
 | 
				
			||||||
    this->emu_thread = emu_thread;
 | 
					    this->emu_thread = emu_thread;
 | 
				
			||||||
    child->DisablePainting();
 | 
					    child->DisablePainting();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void GRenderWindow::OnEmulationStopping() {
 | 
					void GRenderWindow::OnEmulationStopping() {
 | 
				
			||||||
 | 
					    motion_emu = nullptr;
 | 
				
			||||||
    emu_thread = nullptr;
 | 
					    emu_thread = nullptr;
 | 
				
			||||||
    child->EnablePainting();
 | 
					    child->EnablePainting();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,7 @@
 | 
				
			|||||||
#include <QThread>
 | 
					#include <QThread>
 | 
				
			||||||
#include "common/thread.h"
 | 
					#include "common/thread.h"
 | 
				
			||||||
#include "core/frontend/emu_window.h"
 | 
					#include "core/frontend/emu_window.h"
 | 
				
			||||||
 | 
					#include "core/frontend/motion_emu.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class QKeyEvent;
 | 
					class QKeyEvent;
 | 
				
			||||||
class QScreen;
 | 
					class QScreen;
 | 
				
			||||||
@ -156,6 +157,9 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    EmuThread* emu_thread;
 | 
					    EmuThread* emu_thread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Motion sensors emulation
 | 
				
			||||||
 | 
					    std::unique_ptr<Motion::MotionEmu> motion_emu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
    void showEvent(QShowEvent* event) override;
 | 
					    void showEvent(QShowEvent* event) override;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -31,6 +31,7 @@ set(SRCS
 | 
				
			|||||||
            file_sys/savedata_archive.cpp
 | 
					            file_sys/savedata_archive.cpp
 | 
				
			||||||
            frontend/emu_window.cpp
 | 
					            frontend/emu_window.cpp
 | 
				
			||||||
            frontend/key_map.cpp
 | 
					            frontend/key_map.cpp
 | 
				
			||||||
 | 
					            frontend/motion_emu.cpp
 | 
				
			||||||
            gdbstub/gdbstub.cpp
 | 
					            gdbstub/gdbstub.cpp
 | 
				
			||||||
            hle/config_mem.cpp
 | 
					            hle/config_mem.cpp
 | 
				
			||||||
            hle/applets/applet.cpp
 | 
					            hle/applets/applet.cpp
 | 
				
			||||||
@ -202,6 +203,7 @@ set(HEADERS
 | 
				
			|||||||
            file_sys/savedata_archive.h
 | 
					            file_sys/savedata_archive.h
 | 
				
			||||||
            frontend/emu_window.h
 | 
					            frontend/emu_window.h
 | 
				
			||||||
            frontend/key_map.h
 | 
					            frontend/key_map.h
 | 
				
			||||||
 | 
					            frontend/motion_emu.h
 | 
				
			||||||
            gdbstub/gdbstub.h
 | 
					            gdbstub/gdbstub.h
 | 
				
			||||||
            hle/config_mem.h
 | 
					            hle/config_mem.h
 | 
				
			||||||
            hle/function_wrappers.h
 | 
					            hle/function_wrappers.h
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@
 | 
				
			|||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <cmath>
 | 
					#include <cmath>
 | 
				
			||||||
#include "common/assert.h"
 | 
					#include "common/assert.h"
 | 
				
			||||||
 | 
					#include "common/profiler_reporting.h"
 | 
				
			||||||
#include "core/frontend/emu_window.h"
 | 
					#include "core/frontend/emu_window.h"
 | 
				
			||||||
#include "core/frontend/key_map.h"
 | 
					#include "core/frontend/key_map.h"
 | 
				
			||||||
#include "video_core/video_core.h"
 | 
					#include "video_core/video_core.h"
 | 
				
			||||||
@ -89,6 +90,27 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
 | 
				
			|||||||
    TouchPressed(framebuffer_x, framebuffer_y);
 | 
					    TouchPressed(framebuffer_x, framebuffer_y);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EmuWindow::AccelerometerChanged(float x, float y, float z) {
 | 
				
			||||||
 | 
					    constexpr float coef = 512;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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 = x * coef;
 | 
				
			||||||
 | 
					    accel_y = y * coef;
 | 
				
			||||||
 | 
					    accel_z = z * coef;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EmuWindow::GyroscopeChanged(float x, float y, float z) {
 | 
				
			||||||
 | 
					    constexpr float FULL_FPS = 60;
 | 
				
			||||||
 | 
					    float coef = GetGyroscopeRawToDpsCoefficient();
 | 
				
			||||||
 | 
					    float stretch =
 | 
				
			||||||
 | 
					        FULL_FPS / Common::Profiling::GetTimingResultsAggregator()->GetAggregatedResults().fps;
 | 
				
			||||||
 | 
					    gyro_x = x * coef * stretch;
 | 
				
			||||||
 | 
					    gyro_y = y * coef * stretch;
 | 
				
			||||||
 | 
					    gyro_z = z * coef * stretch;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) {
 | 
					void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) {
 | 
				
			||||||
    Layout::FramebufferLayout layout;
 | 
					    Layout::FramebufferLayout layout;
 | 
				
			||||||
    switch (Settings::values.layout_option) {
 | 
					    switch (Settings::values.layout_option) {
 | 
				
			||||||
 | 
				
			|||||||
@ -92,6 +92,27 @@ public:
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y);
 | 
					    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 pad state (which buttons are pressed).
 | 
					     * Gets the current pad state (which buttons are pressed).
 | 
				
			||||||
     * @note This should be called by the core emu thread to get a state set by the window thread.
 | 
					     * @note This should be called by the core emu thread to get a state set by the window thread.
 | 
				
			||||||
@ -134,12 +155,11 @@ public:
 | 
				
			|||||||
     *   1 unit of return value = 1/512 g (measured by hw test),
 | 
					     *   1 unit of return value = 1/512 g (measured by hw test),
 | 
				
			||||||
     *   where g is the gravitational acceleration (9.8 m/sec2).
 | 
					     *   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.
 | 
					     * @note This should be called by the core emu thread to get a state set by the window thread.
 | 
				
			||||||
     * @todo Implement accelerometer input in front-end.
 | 
					     * @todo Fix this function to be thread-safe.
 | 
				
			||||||
     * @return std::tuple of (x, y, z)
 | 
					     * @return std::tuple of (x, y, z)
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    std::tuple<s16, s16, s16> GetAccelerometerState() const {
 | 
					    std::tuple<s16, s16, s16> GetAccelerometerState() {
 | 
				
			||||||
        // stubbed
 | 
					        return std::make_tuple(accel_x, accel_y, accel_z);
 | 
				
			||||||
        return std::make_tuple(0, -512, 0);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -153,12 +173,11 @@ public:
 | 
				
			|||||||
     *   1 unit of return value = (1/coef) deg/sec,
 | 
					     *   1 unit of return value = (1/coef) deg/sec,
 | 
				
			||||||
     *   where coef is the return value of GetGyroscopeRawToDpsCoefficient().
 | 
					     *   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.
 | 
					     * @note This should be called by the core emu thread to get a state set by the window thread.
 | 
				
			||||||
     * @todo Implement gyroscope input in front-end.
 | 
					     * @todo Fix this function to be thread-safe.
 | 
				
			||||||
     * @return std::tuple of (x, y, z)
 | 
					     * @return std::tuple of (x, y, z)
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    std::tuple<s16, s16, s16> GetGyroscopeState() const {
 | 
					    std::tuple<s16, s16, s16> GetGyroscopeState() {
 | 
				
			||||||
        // stubbed
 | 
					        return std::make_tuple(gyro_x, gyro_y, gyro_z);
 | 
				
			||||||
        return std::make_tuple(0, 0, 0);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -216,6 +235,12 @@ protected:
 | 
				
			|||||||
        circle_pad_x = 0;
 | 
					        circle_pad_x = 0;
 | 
				
			||||||
        circle_pad_y = 0;
 | 
					        circle_pad_y = 0;
 | 
				
			||||||
        touch_pressed = false;
 | 
					        touch_pressed = false;
 | 
				
			||||||
 | 
					        accel_x = 0;
 | 
				
			||||||
 | 
					        accel_y = -512;
 | 
				
			||||||
 | 
					        accel_z = 0;
 | 
				
			||||||
 | 
					        gyro_x = 0;
 | 
				
			||||||
 | 
					        gyro_y = 0;
 | 
				
			||||||
 | 
					        gyro_z = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    virtual ~EmuWindow() {}
 | 
					    virtual ~EmuWindow() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -281,6 +306,14 @@ private:
 | 
				
			|||||||
    s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156)
 | 
					    s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156)
 | 
				
			||||||
    s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156)
 | 
					    s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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.
 | 
					     * Clip the provided coordinates to be inside the touchscreen area.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										89
									
								
								src/core/frontend/motion_emu.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/core/frontend/motion_emu.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					// 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
 | 
				
			||||||
							
								
								
									
										52
									
								
								src/core/frontend/motion_emu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/core/frontend/motion_emu.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					// 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…
	
		Reference in New Issue
	
	Block a user