From 03929d8cff2f2c6afe3d4ba842fd7ae1c017da72 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Jul 2019 22:03:14 -0400 Subject: [PATCH] android: frontend: Implement MobilePortrait layout, which makes more sense for mobile. --- src/citra_android/jni/config.cpp | 4 +-- src/citra_android/jni/native.cpp | 4 +-- src/core/frontend/emu_window.cpp | 4 +++ src/core/frontend/framebuffer_layout.cpp | 39 ++++++++++++++++++++++++ src/core/frontend/framebuffer_layout.h | 9 ++++++ src/core/settings.h | 4 +++ 6 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/citra_android/jni/config.cpp b/src/citra_android/jni/config.cpp index 4a828993a..c36ae2d8f 100644 --- a/src/citra_android/jni/config.cpp +++ b/src/citra_android/jni/config.cpp @@ -118,8 +118,8 @@ void Config::ReadValues() { Settings::values.bg_blue = static_cast(sdl2_config->GetReal("Renderer", "bg_blue", 0.0)); // Layout - Settings::values.layout_option = - static_cast(sdl2_config->GetInteger("Layout", "layout_option", 0)); + Settings::values.layout_option = static_cast(sdl2_config->GetInteger( + "Layout", "layout_option", static_cast(Settings::LayoutOption::MobilePortrait))); Settings::values.swap_screen = sdl2_config->GetBoolean("Layout", "swap_screen", false); Settings::values.custom_layout = sdl2_config->GetBoolean("Layout", "custom_layout", false); Settings::values.custom_top_left = diff --git a/src/citra_android/jni/native.cpp b/src/citra_android/jni/native.cpp index 7a8c657f9..3049b278d 100644 --- a/src/citra_android/jni/native.cpp +++ b/src/citra_android/jni/native.cpp @@ -194,14 +194,14 @@ void Java_org_citra_citra_1android_NativeLibrary_CacheClassesAndMethods(JNIEnv* } void Java_org_citra_citra_1android_NativeLibrary_SwitchScreenLayout(JNIEnv* env, jobject obj) { - if (Settings::values.layout_option == Settings::LayoutOption::Default) { + if (Settings::values.layout_option == Settings::LayoutOption::MobilePortrait) { Settings::values.layout_option = Settings::LayoutOption::SingleScreen; } else if (Settings::values.layout_option == Settings::LayoutOption::SingleScreen) { Settings::values.layout_option = Settings::LayoutOption::LargeScreen; } else if (Settings::values.layout_option == Settings::LayoutOption::LargeScreen) { Settings::values.layout_option = Settings::LayoutOption::SideScreen; } else { - Settings::values.layout_option = Settings::LayoutOption::Default; + Settings::values.layout_option = Settings::LayoutOption::MobilePortrait; } VideoCore::g_renderer->UpdateCurrentFramebufferLayout(); } diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 44502858d..c92322f90 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -169,6 +169,10 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen, Settings::values.upright_screen); break; + case Settings::LayoutOption::MobilePortrait: + layout = + Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen, true, true); + 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 71dce24be..c3d937b1e 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -117,6 +117,40 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool swapped, bool u return res; } +FramebufferLayout MobilePortraitFrameLayout(u32 width, u32 height, bool swapped) { + ASSERT(width > 0); + ASSERT(height > 0); + + FramebufferLayout res{width, height, true, true, {}, {}}; + // Default layout gives equal screen sizes to the top and bottom screen + Common::Rectangle screen_window_area{0, 0, width, height / 2}; + Common::Rectangle top_screen = maxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO); + Common::Rectangle bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO); + + float window_aspect_ratio = static_cast(height) / width; + // both screens height are taken into account by multiplying by 2 + float emulation_aspect_ratio = TOP_SCREEN_ASPECT_RATIO * 2; + + if (window_aspect_ratio < emulation_aspect_ratio) { + // Apply borders to the left and right sides of the window. + top_screen = + top_screen.TranslateX((screen_window_area.GetWidth() - top_screen.GetWidth()) / 2); + bot_screen = + bot_screen.TranslateX((screen_window_area.GetWidth() - bot_screen.GetWidth()) / 2); + } else { + // Window is narrower than the emulation content + // Recalculate the bottom screen to account for the width difference between top and bottom + + bot_screen = bot_screen.TranslateX((top_screen.GetWidth() - bot_screen.GetWidth()) / 2); + } + + // Move the top screen to the bottom if we are swapped. + res.top_screen = swapped ? top_screen.TranslateY(bot_screen.GetHeight()) : top_screen; + res.bottom_screen = swapped ? bot_screen : bot_screen.TranslateY(top_screen.GetHeight()); + + return res; +} + FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped, bool upright) { ASSERT(width > 0); ASSERT(height > 0); @@ -346,6 +380,11 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) { layout = SideFrameLayout(width, height, Settings::values.swap_screen, Settings::values.upright_screen); break; + case Settings::LayoutOption::MobilePortrait: + width = Core::kScreenTopWidth * res_scale; + height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; + layout = MobilePortraitFrameLayout(width, height, Settings::values.swap_screen); + break; case Settings::LayoutOption::Default: default: if (Settings::values.upright_screen) { diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index ad3ff2724..5aead06f7 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -35,6 +35,15 @@ struct FramebufferLayout { */ FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool is_swapped, bool upright); +/** + * Factory method for constructing a mobile portrait FramebufferLayout + * @param width Window framebuffer width in pixels + * @param height Window framebuffer height in pixels + * @param is_swapped if true, the bottom screen will be displayed above the top screen + * @return Newly created FramebufferLayout object with mobile portrait screen regions initialized + */ +FramebufferLayout MobilePortraitFrameLayout(u32 width, u32 height, bool is_swapped); + /** * Factory method for constructing a FramebufferLayout with only the top or bottom screen * @param width Window framebuffer width in pixels diff --git a/src/core/settings.h b/src/core/settings.h index af41b9a02..5c440cacb 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -24,6 +24,10 @@ enum class LayoutOption { SingleScreen, LargeScreen, SideScreen, + + // Similiar to default, but better for mobile devices in portrait mode. Top screen in clamped to + // the top of the frame, and the bottom screen is enlarged to match the top screen. + MobilePortrait, }; enum class MicInputType {