From 867eabd6b7effc8ba6c21d7fcbd0480b14f81ad0 Mon Sep 17 00:00:00 2001 From: wwylele Date: Sun, 6 Aug 2017 22:54:19 +0300 Subject: HID: use MotionDevice for Accelerometer and Gyroscope --- src/core/frontend/input.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/core/frontend') diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 0a5713dc0..a8be49440 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h @@ -11,6 +11,7 @@ #include #include "common/logging/log.h" #include "common/param_package.h" +#include "common/vector_math.h" namespace Input { @@ -107,4 +108,23 @@ using ButtonDevice = InputDevice; */ using AnalogDevice = InputDevice>; +/** + * A motion device is an input device that returns a tuple of accelerometer state vector and + * gyroscope state vector. + * + * For accelerometer 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. + * Units: measured in unit of 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 + */ +using MotionDevice = InputDevice, Math::Vec3>>; + } // namespace Input -- cgit v1.2.3 From 188194908c2785bd1e03485941b9148777cdddd7 Mon Sep 17 00:00:00 2001 From: wwylele Date: Mon, 7 Aug 2017 00:04:06 +0300 Subject: move MotionEmu from core/frontend to input_common as a InputDevice --- src/core/frontend/emu_window.cpp | 23 ----------- src/core/frontend/emu_window.h | 83 ------------------------------------- src/core/frontend/input.h | 9 ++-- src/core/frontend/motion_emu.cpp | 89 ---------------------------------------- src/core/frontend/motion_emu.h | 52 ----------------------- 5 files changed, 4 insertions(+), 252 deletions(-) delete mode 100644 src/core/frontend/motion_emu.cpp delete mode 100644 src/core/frontend/motion_emu.h (limited to 'src/core/frontend') diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 4f7d54a33..60b20d4e2 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -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 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(x * coef); - accel_y = static_cast(y * coef); - accel_z = static_cast(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 lock(gyro_mutex); - gyro_x = static_cast(x * coef * stretch); - gyro_y = static_cast(y * coef * stretch); - gyro_z = static_cast(z * coef * stretch); -} - void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { Layout::FramebufferLayout layout; if (Settings::values.custom_layout == true) { diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 9414123a4..7bdee251c 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -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 GetAccelerometerState() { - std::lock_guard 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 GetGyroscopeState() { - std::lock_guard 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. */ diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index a8be49440..5916a901d 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h @@ -112,16 +112,15 @@ using AnalogDevice = InputDevice>; * 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 */ diff --git a/src/core/frontend/motion_emu.cpp b/src/core/frontend/motion_emu.cpp deleted file mode 100644 index 9a5b3185d..000000000 --- a/src/core/frontend/motion_emu.cpp +++ /dev/null @@ -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::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 q = MakeQuaternion(Math::Vec3(), 0); - Math::Quaternion old_q; - - while (!shutdown_event.WaitUntil(update_time)) { - update_time += update_duration; - old_q = q; - - { - std::lock_guard 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 guard(tilt_mutex); - if (mouse_move.x == 0 && mouse_move.y == 0) { - tilt_angle = 0; - } else { - tilt_direction = mouse_move.Cast(); - tilt_angle = MathUtil::Clamp(tilt_direction.Normalize() * SENSITIVITY, 0.0f, - MathUtil::PI * 0.5f); - } - } -} - -void MotionEmu::EndTilt() { - std::lock_guard guard(tilt_mutex); - tilt_angle = 0; - is_tilting = false; -} - -} // namespace Motion diff --git a/src/core/frontend/motion_emu.h b/src/core/frontend/motion_emu.h deleted file mode 100644 index 99d41a726..000000000 --- a/src/core/frontend/motion_emu.h +++ /dev/null @@ -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 mouse_origin; - - std::mutex tilt_mutex; - Math::Vec2 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 -- cgit v1.2.3 From c84e60b4700778db236d3177714a076c515f9ce7 Mon Sep 17 00:00:00 2001 From: wwylele Date: Tue, 8 Aug 2017 21:34:17 +0300 Subject: HID: use TouchDevice for touch pad --- src/core/frontend/input.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/core/frontend') diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 5916a901d..8c256beb5 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h @@ -126,4 +126,10 @@ using AnalogDevice = InputDevice>; */ using MotionDevice = InputDevice, Math::Vec3>>; +/** + * A touch device is an input device that returns a tuple of two floats and a bool. The floats are + * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. + */ +using TouchDevice = InputDevice>; + } // namespace Input -- cgit v1.2.3 From 2617de1fe6f6f1fc846a8e038e1ea77a894554b2 Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 9 Aug 2017 02:57:42 +0300 Subject: EmuWindow: refactor touch input into a TouchDevice --- src/core/frontend/emu_window.cpp | 71 ++++++++++++++++++++++++++++++++-------- src/core/frontend/emu_window.h | 31 +++--------------- 2 files changed, 63 insertions(+), 39 deletions(-) (limited to 'src/core/frontend') diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 60b20d4e2..787c517ff 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -2,14 +2,55 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include #include -#include "common/assert.h" -#include "core/3ds.h" -#include "core/core.h" +#include #include "core/frontend/emu_window.h" +#include "core/frontend/input.h" #include "core/settings.h" +class EmuWindow::TouchState : public Input::Factory, + public std::enable_shared_from_this { +public: + std::unique_ptr Create(const Common::ParamPackage&) override { + return std::make_unique(shared_from_this()); + } + + std::mutex mutex; + + bool touch_pressed = false; ///< True if touchpad area is currently pressed, otherwise false + + float touch_x = 0.0f; ///< Touchpad X-position + float touch_y = 0.0f; ///< Touchpad Y-position + +private: + class Device : public Input::TouchDevice { + public: + explicit Device(std::weak_ptr&& touch_state) : touch_state(touch_state) {} + std::tuple GetStatus() const override { + if (auto state = touch_state.lock()) { + std::lock_guard guard(state->mutex); + return std::make_tuple(state->touch_x, state->touch_y, state->touch_pressed); + } + return std::make_tuple(0.0f, 0.0f, false); + } + + private: + std::weak_ptr touch_state; + }; +}; + +EmuWindow::EmuWindow() { + // TODO: Find a better place to set this. + config.min_client_area_size = std::make_pair(400u, 480u); + active_config = config; + touch_state = std::make_shared(); + Input::RegisterFactory("emu_window", touch_state); +} + +EmuWindow::~EmuWindow() { + Input::UnregisterFactory("emu_window"); +} + /** * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout * @param layout FramebufferLayout object describing the framebuffer size and screen positions @@ -38,22 +79,26 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) return; - touch_x = Core::kScreenBottomWidth * (framebuffer_x - framebuffer_layout.bottom_screen.left) / - (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); - touch_y = Core::kScreenBottomHeight * (framebuffer_y - framebuffer_layout.bottom_screen.top) / - (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); + std::lock_guard guard(touch_state->mutex); + touch_state->touch_x = + static_cast(framebuffer_x - framebuffer_layout.bottom_screen.left) / + (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); + touch_state->touch_y = + static_cast(framebuffer_y - framebuffer_layout.bottom_screen.top) / + (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); - touch_pressed = true; + touch_state->touch_pressed = true; } void EmuWindow::TouchReleased() { - touch_pressed = false; - touch_x = 0; - touch_y = 0; + std::lock_guard guard(touch_state->mutex); + touch_state->touch_pressed = false; + touch_state->touch_x = 0; + touch_state->touch_y = 0; } void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { - if (!touch_pressed) + if (!touch_state->touch_pressed) return; if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 7bdee251c..c10dee51b 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -4,11 +4,10 @@ #pragma once -#include +#include #include #include #include "common/common_types.h" -#include "common/math_util.h" #include "core/frontend/framebuffer_layout.h" /** @@ -68,17 +67,6 @@ public: */ void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y); - /** - * 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. - * @todo Fix this function to be thread-safe. - * @return std::tuple of (x, y, pressed) where `x` and `y` are the touch coordinates and - * `pressed` is true if the touch screen is currently being pressed - */ - std::tuple GetTouchState() const { - return std::make_tuple(touch_x, touch_y, touch_pressed); - } - /** * Returns currently active configuration. * @note Accesses to the returned object need not be consistent because it may be modified in @@ -113,15 +101,8 @@ public: void UpdateCurrentFramebufferLayout(unsigned width, unsigned height); protected: - EmuWindow() { - // TODO: Find a better place to set this. - config.min_client_area_size = std::make_pair(400u, 480u); - active_config = config; - touch_x = 0; - touch_y = 0; - touch_pressed = false; - } - virtual ~EmuWindow() {} + EmuWindow(); + virtual ~EmuWindow(); /** * Processes any pending configuration changes from the last SetConfig call. @@ -177,10 +158,8 @@ private: /// ProcessConfigurationChanges) WindowConfig active_config; ///< Internal active configuration - bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false - - 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) + class TouchState; + std::shared_ptr touch_state; /** * Clip the provided coordinates to be inside the touchscreen area. -- cgit v1.2.3 From 3cdf854e44e7ff088fa0cbdcfa2bcc6e41822b2c Mon Sep 17 00:00:00 2001 From: ThaMighty90 <30285364+ThaMighty90@users.noreply.github.com> Date: Fri, 25 Aug 2017 23:53:07 +0200 Subject: SidebySide Layout (#2859) * added a SidebySide Layout * Reworked, so both screen have the same height and cleaned up screen translates. * added the option in the UI, hope this is the right way to do it. formated framebuffer_layout.cpp * delete the x64 files * deleted ui_configure_graphics.h * added Option for the Layout in the xml * got rid of SIDE_BY_SIDE_ASPECT_RATIO because it was useless. pulled translate into variables * changed shift variables to u32 and moved them in their respective branch. remove notr="true" for the Screen layout drop down * reworked intends :). changed function description for SideFrameLayout * some description reworking --- src/core/frontend/emu_window.cpp | 3 +++ src/core/frontend/framebuffer_layout.cpp | 36 +++++++++++++++++++++++++++++++- src/core/frontend/framebuffer_layout.h | 11 ++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) (limited to 'src/core/frontend') diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 60b20d4e2..54fa5c7fa 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -74,6 +74,9 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) case Settings::LayoutOption::LargeScreen: layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen); break; + case Settings::LayoutOption::SideScreen: + layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen); + break; case Settings::LayoutOption::Default: default: layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen); diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index d2d02f9ff..e9f778fcb 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -141,6 +141,40 @@ FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool swapped return res; } +FramebufferLayout SideFrameLayout(unsigned width, unsigned height, bool swapped) { + ASSERT(width > 0); + ASSERT(height > 0); + + FramebufferLayout res{width, height, true, true, {}, {}}; + // Aspect ratio of both screens side by side + const float emulation_aspect_ratio = static_cast(Core::kScreenTopHeight) / + (Core::kScreenTopWidth + Core::kScreenBottomWidth); + float window_aspect_ratio = static_cast(height) / width; + MathUtil::Rectangle screen_window_area{0, 0, width, height}; + // Find largest Rectangle that can fit in the window size with the given aspect ratio + MathUtil::Rectangle screen_rect = + maxRectangle(screen_window_area, emulation_aspect_ratio); + // Find sizes of top and bottom screen + MathUtil::Rectangle top_screen = maxRectangle(screen_rect, TOP_SCREEN_ASPECT_RATIO); + MathUtil::Rectangle bot_screen = maxRectangle(screen_rect, BOT_SCREEN_ASPECT_RATIO); + + if (window_aspect_ratio < emulation_aspect_ratio) { + // Apply borders to the left and right sides of the window. + u32 shift_horizontal = (screen_window_area.GetWidth() - screen_rect.GetWidth()) / 2; + top_screen = top_screen.TranslateX(shift_horizontal); + bot_screen = bot_screen.TranslateX(shift_horizontal); + } else { + // Window is narrower than the emulation content => apply borders to the top and bottom + u32 shift_vertical = (screen_window_area.GetHeight() - screen_rect.GetHeight()) / 2; + top_screen = top_screen.TranslateY(shift_vertical); + bot_screen = bot_screen.TranslateY(shift_vertical); + } + // Move the top screen to the right if we are swapped. + res.top_screen = swapped ? top_screen.TranslateX(bot_screen.GetWidth()) : top_screen; + res.bottom_screen = swapped ? bot_screen : bot_screen.TranslateX(top_screen.GetWidth()); + return res; +} + FramebufferLayout CustomFrameLayout(unsigned width, unsigned height) { ASSERT(width > 0); ASSERT(height > 0); @@ -158,4 +192,4 @@ FramebufferLayout CustomFrameLayout(unsigned width, unsigned height) { res.bottom_screen = bot_screen; return res; } -} +} // namespace Layout diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 9a7738969..4983cf103 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -53,6 +53,17 @@ FramebufferLayout SingleFrameLayout(unsigned width, unsigned height, bool is_swa */ FramebufferLayout LargeFrameLayout(unsigned width, unsigned height, bool is_swapped); +/** +* Factory method for constructing a Frame with the Top screen and bottom +* screen side by side +* This is useful for devices with small screens, like the GPDWin +* @param width Window framebuffer width in pixels +* @param height Window framebuffer height in pixels +* @param is_swapped if true, the bottom screen will be the left display +* @return Newly created FramebufferLayout object with default screen regions initialized +*/ +FramebufferLayout SideFrameLayout(unsigned width, unsigned height, bool is_swapped); + /** * Factory method for constructing a custom FramebufferLayout * @param width Window framebuffer width in pixels -- cgit v1.2.3