diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 38c2fa21a..63c446983 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -173,8 +173,7 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { TouchPressed(framebuffer_x, framebuffer_y); } -void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height, - bool is_portrait_mode) { +void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_portrait_mode) { Layout::FramebufferLayout layout; // If in portrait mode, only the MobilePortrait option really makes sense @@ -200,7 +199,8 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height, layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), Settings::values.upright_screen.GetValue(), - Settings::values.large_screen_proportion.GetValue()); + Settings::values.large_screen_proportion.GetValue(), + Layout::VerticalAlignment::Bottom); break; case Settings::LayoutOption::HybridScreen: layout = @@ -208,8 +208,10 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height, Settings::values.upright_screen.GetValue()); break; case Settings::LayoutOption::SideScreen: - layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue()); + layout = + Layout::LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue(), 1.0f, + Layout::VerticalAlignment::Bottom); break; #ifndef ANDROID case Settings::LayoutOption::SeparateWindows: @@ -222,8 +224,9 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height, Settings::values.swap_screen.GetValue()); break; case Settings::LayoutOption::MobileLandscape: - layout = Layout::MobileLandscapeFrameLayout( - width, height, Settings::values.swap_screen.GetValue(), 2.25f, false); + layout = + Layout::LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + false, 2.25f, Layout::VerticalAlignment::Top); break; case Settings::LayoutOption::Default: default: diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp index 40b86fb68..11d2249ac 100644 --- a/src/core/frontend/framebuffer_layout.cpp +++ b/src/core/frontend/framebuffer_layout.cpp @@ -30,7 +30,7 @@ u32 FramebufferLayout::GetScalingRatio() const { // Finds the largest size subrectangle contained in window area that is confined to the aspect ratio template -static Common::Rectangle maxRectangle(Common::Rectangle window_area, +static Common::Rectangle MaxRectangle(Common::Rectangle window_area, float screen_aspect_ratio) { float scale = std::min(static_cast(window_area.GetWidth()), window_area.GetHeight() / screen_aspect_ratio); @@ -50,15 +50,15 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool swapped, bool u if (upright) { // Default layout gives equal screen sizes to the top and bottom screen screen_window_area = {0, 0, width / 2, height}; - top_screen = maxRectangle(screen_window_area, TOP_SCREEN_UPRIGHT_ASPECT_RATIO); - bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_UPRIGHT_ASPECT_RATIO); + top_screen = MaxRectangle(screen_window_area, TOP_SCREEN_UPRIGHT_ASPECT_RATIO); + bot_screen = MaxRectangle(screen_window_area, BOT_SCREEN_UPRIGHT_ASPECT_RATIO); // both screens width are taken into account by dividing by 2 emulation_aspect_ratio = TOP_SCREEN_UPRIGHT_ASPECT_RATIO / 2; } else { // Default layout gives equal screen sizes to the top and bottom screen screen_window_area = {0, 0, width, height / 2}; - top_screen = maxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO); - bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO); + top_screen = MaxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO); + bot_screen = MaxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO); // both screens height are taken into account by multiplying by 2 emulation_aspect_ratio = TOP_SCREEN_ASPECT_RATIO * 2; } @@ -71,7 +71,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool swapped, bool u // Recalculate the bottom screen to account for the height difference between right and // left screen_window_area = {0, 0, top_screen.GetWidth(), height}; - bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_UPRIGHT_ASPECT_RATIO); + bot_screen = MaxRectangle(screen_window_area, BOT_SCREEN_UPRIGHT_ASPECT_RATIO); bot_screen = bot_screen.TranslateY((top_screen.GetHeight() - bot_screen.GetHeight()) / 2); if (swapped) { @@ -96,7 +96,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool swapped, bool u // Recalculate the bottom screen to account for the width difference between top and // bottom screen_window_area = {0, 0, width, top_screen.GetHeight()}; - bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO); + bot_screen = MaxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO); bot_screen = bot_screen.TranslateX((top_screen.GetWidth() - bot_screen.GetWidth()) / 2); if (swapped) { bot_screen = bot_screen.TranslateY(height / 2 - bot_screen.GetHeight()); @@ -124,8 +124,8 @@ FramebufferLayout MobilePortraitFrameLayout(u32 width, u32 height, bool swapped) 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); + 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 @@ -151,48 +151,6 @@ FramebufferLayout MobilePortraitFrameLayout(u32 width, u32 height, bool swapped) return res; } -FramebufferLayout MobileLandscapeFrameLayout(u32 width, u32 height, bool swapped, - float scale_factor, bool center_vertical) { - ASSERT(width > 0); - ASSERT(height > 0); - - FramebufferLayout res{width, height, true, true, {}, {}}; - // Split the window into two parts. Give 4x width to the main screen and 1x width to the small - // To do that, find the total emulation box and maximize that based on window size - float window_aspect_ratio = static_cast(height) / width; - float emulation_aspect_ratio = - swapped ? Core::kScreenBottomHeight * scale_factor / - (Core::kScreenBottomWidth * scale_factor + Core::kScreenTopWidth) - : Core::kScreenTopHeight * scale_factor / - (Core::kScreenTopWidth * scale_factor + Core::kScreenBottomWidth); - float large_screen_aspect_ratio = swapped ? BOT_SCREEN_ASPECT_RATIO : TOP_SCREEN_ASPECT_RATIO; - float small_screen_aspect_ratio = swapped ? TOP_SCREEN_ASPECT_RATIO : BOT_SCREEN_ASPECT_RATIO; - - Common::Rectangle screen_window_area{0, 0, width, height}; - Common::Rectangle total_rect = maxRectangle(screen_window_area, emulation_aspect_ratio); - Common::Rectangle large_screen = maxRectangle(total_rect, large_screen_aspect_ratio); - Common::Rectangle fourth_size_rect = total_rect.Scale(1.f / scale_factor); - Common::Rectangle small_screen = maxRectangle(fourth_size_rect, small_screen_aspect_ratio); - - if (window_aspect_ratio < emulation_aspect_ratio) { - large_screen = - large_screen.TranslateX((screen_window_area.GetWidth() - total_rect.GetWidth()) / 2); - } else if (center_vertical) { - large_screen = large_screen.TranslateY((height - total_rect.GetHeight()) / 2); - } - - // Shift the small screen to the bottom right corner - small_screen = small_screen.TranslateX(large_screen.right); - if (center_vertical) { - small_screen = small_screen.TranslateY(large_screen.GetHeight() + large_screen.top - - small_screen.GetHeight()); - } - - res.top_screen = swapped ? small_screen : large_screen; - res.bottom_screen = swapped ? large_screen : small_screen; - return res; -} - FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped, bool upright) { ASSERT(width > 0); ASSERT(height > 0); @@ -205,13 +163,13 @@ FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped, bool up Common::Rectangle bot_screen; float emulation_aspect_ratio; if (upright) { - top_screen = maxRectangle(screen_window_area, TOP_SCREEN_UPRIGHT_ASPECT_RATIO); - bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_UPRIGHT_ASPECT_RATIO); + top_screen = MaxRectangle(screen_window_area, TOP_SCREEN_UPRIGHT_ASPECT_RATIO); + bot_screen = MaxRectangle(screen_window_area, BOT_SCREEN_UPRIGHT_ASPECT_RATIO); emulation_aspect_ratio = (swapped) ? BOT_SCREEN_UPRIGHT_ASPECT_RATIO : TOP_SCREEN_UPRIGHT_ASPECT_RATIO; } else { - top_screen = maxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO); - bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO); + top_screen = MaxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO); + bot_screen = MaxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO); emulation_aspect_ratio = (swapped) ? BOT_SCREEN_ASPECT_RATIO : TOP_SCREEN_ASPECT_RATIO; } @@ -232,7 +190,7 @@ FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped, bool up } FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upright, - float scale_factor) { + float scale_factor, VerticalAlignment vertical_alignment) { ASSERT(width > 0); ASSERT(height > 0); @@ -274,10 +232,10 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr } Common::Rectangle screen_window_area{0, 0, width, height}; - Common::Rectangle total_rect = maxRectangle(screen_window_area, emulation_aspect_ratio); - Common::Rectangle large_screen = maxRectangle(total_rect, large_screen_aspect_ratio); - Common::Rectangle fourth_size_rect = total_rect.Scale(1.f / scale_factor); - Common::Rectangle small_screen = maxRectangle(fourth_size_rect, small_screen_aspect_ratio); + Common::Rectangle total_rect = MaxRectangle(screen_window_area, emulation_aspect_ratio); + Common::Rectangle large_screen = MaxRectangle(total_rect, large_screen_aspect_ratio); + Common::Rectangle scaled_rect = total_rect.Scale(1.f / scale_factor); + Common::Rectangle small_screen = MaxRectangle(scaled_rect, small_screen_aspect_ratio); if (window_aspect_ratio < emulation_aspect_ratio) { large_screen = large_screen.TranslateX((width - total_rect.GetWidth()) / 2); @@ -286,13 +244,46 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr } if (upright) { large_screen = large_screen.TranslateY(small_screen.GetHeight()); - small_screen = small_screen.TranslateX(large_screen.right - small_screen.GetWidth()) - .TranslateY(large_screen.top - small_screen.GetHeight()); + small_screen = small_screen.TranslateY(large_screen.top - small_screen.GetHeight()); + switch (vertical_alignment) { + case VerticalAlignment::Top: + // Shift the small screen to the top right corner + small_screen = small_screen.TranslateX(large_screen.left); + break; + case VerticalAlignment::Middle: + // Shift the small screen to the center right + small_screen = small_screen.TranslateX( + ((large_screen.GetWidth() - small_screen.GetWidth()) / 2) + large_screen.left); + break; + case VerticalAlignment::Bottom: + // Shift the small screen to the bottom right corner + small_screen = small_screen.TranslateX(large_screen.right - small_screen.GetWidth()); + break; + default: + UNREACHABLE(); + break; + } + } else { - // Shift the small screen to the bottom right corner - small_screen = - small_screen.TranslateX(large_screen.right) - .TranslateY(large_screen.GetHeight() + large_screen.top - small_screen.GetHeight()); + small_screen = small_screen.TranslateX(large_screen.right); + switch (vertical_alignment) { + case VerticalAlignment::Top: + // Shift the small screen to the top right corner + small_screen = small_screen.TranslateY(large_screen.top); + break; + case VerticalAlignment::Middle: + // Shift the small screen to the center right + small_screen = small_screen.TranslateY( + ((large_screen.GetHeight() - small_screen.GetHeight()) / 2) + large_screen.top); + break; + case VerticalAlignment::Bottom: + // Shift the small screen to the bottom right corner + small_screen = small_screen.TranslateY(large_screen.bottom - small_screen.GetHeight()); + break; + default: + UNREACHABLE(); + break; + } } res.top_screen = swapped ? small_screen : large_screen; res.bottom_screen = swapped ? large_screen : small_screen; @@ -331,11 +322,11 @@ FramebufferLayout HybridScreenLayout(u32 width, u32 height, bool swapped, bool u } Common::Rectangle screen_window_area{0, 0, width, height}; - Common::Rectangle total_rect = maxRectangle(screen_window_area, hybrid_area_aspect_ratio); - Common::Rectangle large_main_screen = maxRectangle(total_rect, main_screen_aspect_ratio); + Common::Rectangle total_rect = MaxRectangle(screen_window_area, hybrid_area_aspect_ratio); + Common::Rectangle large_main_screen = MaxRectangle(total_rect, main_screen_aspect_ratio); Common::Rectangle side_rect = total_rect.Scale(1.f / scale_factor); - Common::Rectangle small_top_screen = maxRectangle(side_rect, top_screen_aspect_ratio); - Common::Rectangle small_bottom_screen = maxRectangle(side_rect, bot_screen_aspect_ratio); + Common::Rectangle small_top_screen = MaxRectangle(side_rect, top_screen_aspect_ratio); + Common::Rectangle small_bottom_screen = MaxRectangle(side_rect, bot_screen_aspect_ratio); if (window_aspect_ratio < hybrid_area_aspect_ratio) { large_main_screen = large_main_screen.TranslateX((width - total_rect.GetWidth()) / 2); @@ -373,54 +364,6 @@ FramebufferLayout HybridScreenLayout(u32 width, u32 height, bool swapped, bool u return res; } -FramebufferLayout SideFrameLayout(u32 width, u32 height, bool swapped, bool upright) { - ASSERT(width > 0); - ASSERT(height > 0); - - FramebufferLayout res{width, height, true, true, {}, {}, !upright}; - - // Aspect ratio of both screens side by side - float emulation_aspect_ratio = - upright ? static_cast(Core::kScreenTopWidth + Core::kScreenBottomWidth) / - Core::kScreenTopHeight - : static_cast(Core::kScreenTopHeight) / - (Core::kScreenTopWidth + Core::kScreenBottomWidth); - - float window_aspect_ratio = static_cast(height) / width; - Common::Rectangle screen_window_area{0, 0, width, height}; - // Find largest Rectangle that can fit in the window size with the given aspect ratio - Common::Rectangle screen_rect = maxRectangle(screen_window_area, emulation_aspect_ratio); - // Find sizes of top and bottom screen - Common::Rectangle top_screen = - upright ? maxRectangle(screen_rect, TOP_SCREEN_UPRIGHT_ASPECT_RATIO) - : maxRectangle(screen_rect, TOP_SCREEN_ASPECT_RATIO); - Common::Rectangle bot_screen = - upright ? maxRectangle(screen_rect, BOT_SCREEN_UPRIGHT_ASPECT_RATIO) - : 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); - } - if (upright) { - // Leave the top screen at the top if we are swapped. - res.top_screen = swapped ? top_screen : top_screen.TranslateY(bot_screen.GetHeight()); - res.bottom_screen = swapped ? bot_screen.TranslateY(top_screen.GetHeight()) : bot_screen; - } else { - // 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 SeparateWindowsLayout(u32 width, u32 height, bool is_secondary, bool upright) { // When is_secondary is true, we disable the top screen, and enable the bottom screen. // The same logic is found in the SingleFrameLayout using the is_swapped bool. @@ -454,131 +397,103 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped) { } FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary) { - FramebufferLayout layout; if (Settings::values.custom_layout.GetValue() == true) { - layout = CustomFrameLayout(std::max(Settings::values.custom_top_right.GetValue(), - Settings::values.custom_bottom_right.GetValue()), - std::max(Settings::values.custom_top_bottom.GetValue(), - Settings::values.custom_bottom_bottom.GetValue()), - Settings::values.swap_screen.GetValue()); - } else { - int width, height; - switch (Settings::values.layout_option.GetValue()) { - case Settings::LayoutOption::SingleScreen: + return CustomFrameLayout(std::max(Settings::values.custom_top_right.GetValue(), + Settings::values.custom_bottom_right.GetValue()), + std::max(Settings::values.custom_top_bottom.GetValue(), + Settings::values.custom_bottom_bottom.GetValue()), + Settings::values.swap_screen.GetValue()); + } + + int width, height; + switch (Settings::values.layout_option.GetValue()) { + case Settings::LayoutOption::SingleScreen: #ifndef ANDROID - case Settings::LayoutOption::SeparateWindows: + case Settings::LayoutOption::SeparateWindows: #endif - { - const bool swap_screens = is_secondary || Settings::values.swap_screen.GetValue(); - if (Settings::values.upright_screen.GetValue()) { - if (swap_screens) { - width = Core::kScreenBottomHeight * res_scale; - height = Core::kScreenBottomWidth * res_scale; - } else { - width = Core::kScreenTopHeight * res_scale; - height = Core::kScreenTopWidth * res_scale; - } - } else { - if (swap_screens) { - width = Core::kScreenBottomWidth * res_scale; - height = Core::kScreenBottomHeight * res_scale; - } else { - width = Core::kScreenTopWidth * res_scale; - height = Core::kScreenTopHeight * res_scale; - } - } - layout = SingleFrameLayout(width, height, swap_screens, - Settings::values.upright_screen.GetValue()); - break; - } - case Settings::LayoutOption::LargeScreen: - if (Settings::values.upright_screen.GetValue()) { - if (Settings::values.swap_screen.GetValue()) { - width = Core::kScreenBottomHeight * res_scale; - height = - (Core::kScreenBottomWidth + - static_cast(Core::kScreenTopWidth / - Settings::values.large_screen_proportion.GetValue())) * - res_scale; - } else { - width = Core::kScreenTopHeight * res_scale; - height = - (Core::kScreenTopWidth + - static_cast(Core::kScreenBottomWidth / - Settings::values.large_screen_proportion.GetValue())) * - res_scale; - } - } else { - if (Settings::values.swap_screen.GetValue()) { - width = (Core::kScreenBottomWidth + - Core::kScreenTopWidth / - static_cast( - Settings::values.large_screen_proportion.GetValue())) * - res_scale; - height = Core::kScreenBottomHeight * res_scale; - } else { - width = (Core::kScreenTopWidth + - Core::kScreenBottomWidth / - static_cast( - Settings::values.large_screen_proportion.GetValue())) * - res_scale; - height = Core::kScreenTopHeight * res_scale; - } - } - layout = LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue(), - Settings::values.large_screen_proportion.GetValue()); - break; - case Settings::LayoutOption::SideScreen: - if (Settings::values.upright_screen.GetValue()) { - width = Core::kScreenTopHeight * res_scale; - height = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale; - } else { - width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale; - height = Core::kScreenTopHeight * res_scale; - } - layout = SideFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue()); - break; - case Settings::LayoutOption::MobilePortrait: + { + const bool swap_screens = is_secondary || Settings::values.swap_screen.GetValue(); + if (swap_screens) { + width = Core::kScreenBottomWidth * res_scale; + height = Core::kScreenBottomHeight * res_scale; + } else { width = Core::kScreenTopWidth * res_scale; - height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; - layout = - MobilePortraitFrameLayout(width, height, Settings::values.swap_screen.GetValue()); - break; - case Settings::LayoutOption::MobileLandscape: - if (Settings::values.swap_screen.GetValue()) { - width = - (Core::kScreenBottomWidth + static_cast(Core::kScreenTopWidth / 2.25f)) * - res_scale; - height = Core::kScreenBottomHeight * res_scale; - } else { - width = - (Core::kScreenTopWidth + static_cast(Core::kScreenBottomWidth / 2.25f)) * - res_scale; - height = Core::kScreenTopHeight * res_scale; - } - layout = MobileLandscapeFrameLayout( - width, height, Settings::values.swap_screen.GetValue(), 2.25f, false); - break; - case Settings::LayoutOption::Default: - default: - if (Settings::values.upright_screen.GetValue()) { - width = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; - height = Core::kScreenTopWidth * res_scale; - } else { - width = Core::kScreenTopWidth * res_scale; - height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; - } - layout = DefaultFrameLayout(width, height, Settings::values.swap_screen.GetValue(), - Settings::values.upright_screen.GetValue()); - break; + height = Core::kScreenTopHeight * res_scale; } + if (Settings::values.upright_screen.GetValue()) { + std::swap(width, height); + } + return SingleFrameLayout(width, height, swap_screens, + Settings::values.upright_screen.GetValue()); } - if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::CardboardVR) { - layout = Layout::GetCardboardSettings(layout); + + case Settings::LayoutOption::LargeScreen: + if (Settings::values.swap_screen.GetValue()) { + width = (Core::kScreenBottomWidth + + Core::kScreenTopWidth / + static_cast(Settings::values.large_screen_proportion.GetValue())) * + res_scale; + height = Core::kScreenBottomHeight * res_scale; + } else { + width = (Core::kScreenTopWidth + + Core::kScreenBottomWidth / + static_cast(Settings::values.large_screen_proportion.GetValue())) * + res_scale; + height = Core::kScreenTopHeight * res_scale; + } + if (Settings::values.upright_screen.GetValue()) { + std::swap(width, height); + } + return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue(), + Settings::values.large_screen_proportion.GetValue(), + VerticalAlignment::Bottom); + + case Settings::LayoutOption::SideScreen: + width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale; + height = Core::kScreenTopHeight * res_scale; + + if (Settings::values.upright_screen.GetValue()) { + std::swap(width, height); + } + return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue(), 1, + VerticalAlignment::Middle); + + case Settings::LayoutOption::MobilePortrait: + width = Core::kScreenTopWidth * res_scale; + height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; + return MobilePortraitFrameLayout(width, height, Settings::values.swap_screen.GetValue()); + + case Settings::LayoutOption::MobileLandscape: { + constexpr float large_screen_proportion = 2.25f; + if (Settings::values.swap_screen.GetValue()) { + width = (Core::kScreenBottomWidth + + static_cast(Core::kScreenTopWidth / large_screen_proportion)) * + res_scale; + height = Core::kScreenBottomHeight * res_scale; + } else { + width = (Core::kScreenTopWidth + + static_cast(Core::kScreenBottomWidth / large_screen_proportion)) * + res_scale; + height = Core::kScreenTopHeight * res_scale; + } + return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), false, + large_screen_proportion, VerticalAlignment::Top); } - return layout; + + case Settings::LayoutOption::Default: + default: + width = Core::kScreenTopWidth * res_scale; + height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; + + if (Settings::values.upright_screen.GetValue()) { + std::swap(width, height); + } + return DefaultFrameLayout(width, height, Settings::values.swap_screen.GetValue(), + Settings::values.upright_screen.GetValue()); + } + UNREACHABLE(); } FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout) { diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 76549954f..f2ed553fd 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h @@ -20,6 +20,31 @@ enum class DisplayOrientation { PortraitFlipped, // 3DS rotated 270 degrees counter-clockwise }; +/// Describes the vertical alignment of the top and bottom screens in LargeFrameLayout +/// Top +/// +-------------+-----+ +/// | | | +/// | +-----+ +/// | | +/// +-------------+ +/// Middle +/// +-------------+ +/// | +-----+ +/// | | | +/// | +-----+ +/// +-------------+ +/// Bottom +/// +-------------+ +/// | | +/// | +-----+ +/// | | | +/// +-------------+-----+ +enum class VerticalAlignment { + Top, + Middle, + Bottom, +}; + /// Describes the horizontal coordinates for the right eye screen when using Cardboard VR struct CardboardSettings { u32 top_screen_right_eye; @@ -43,7 +68,7 @@ struct FramebufferLayout { CardboardSettings cardboard; /** - * Returns the ration of pixel size of the top screen, compared to the native size of the 3DS + * Returns the ratio of pixel size of the top screen, compared to the native size of the 3DS * screen. */ u32 GetScalingRatio() const; @@ -54,6 +79,7 @@ struct 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 + * @param upright if true, the screens will be rotated 90 degrees anti-clockwise * @return Newly created FramebufferLayout object with default screen regions initialized */ FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool is_swapped, bool upright); @@ -67,25 +93,12 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool is_swapped, boo */ FramebufferLayout MobilePortraitFrameLayout(u32 width, u32 height, bool is_swapped); -/** - * Factory method for constructing a Frame with the a 4x size Top screen with a 1x size bottom - * screen on the right - * This is useful in particular because it matches well with a 1920x1080 resolution monitor - * @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 large display - * @param scale_factor Scale factor to use for bottom screen with respect to top screen - * @param center_vertical When true, centers the top and bottom screens vertically - * @return Newly created FramebufferLayout object with default screen regions initialized - */ -FramebufferLayout MobileLandscapeFrameLayout(u32 width, u32 height, bool is_swapped, - float scale_factor, bool center_vertical); - /** * Factory method for constructing a FramebufferLayout with only the top or bottom screen * @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 (and the top won't be displayed) + * @param upright if true, the screens will be rotated 90 degrees anti-clockwise * @return Newly created FramebufferLayout object with default screen regions initialized */ FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool is_swapped, bool upright); @@ -97,32 +110,25 @@ FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool is_swapped, bool * @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 large display + * @param upright if true, the screens will be rotated 90 degrees anti-clockwise * @param scale_factor The ratio between the large screen with respect to the smaller screen + * @param vertical_alignment The vertical alignment of the smaller screen relative to the larger + * screen * @return Newly created FramebufferLayout object with default screen regions initialized */ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool is_swapped, bool upright, - float scale_factor); + float scale_factor, VerticalAlignment vertical_alignment); /** * Factory method for constructing a frame with 2.5 times bigger top screen on the right, * and 1x top and bottom screen on the left * @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 large display + * @param upright if true, the screens will be rotated 90 degrees anti-clockwise * @return Newly created FramebufferLayout object with default screen regions initialized */ FramebufferLayout HybridScreenLayout(u32 width, u32 height, bool swapped, bool upright); -/** - * 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(u32 width, u32 height, bool is_swapped, bool upright); - /** * Factory method for constructing a Frame with the Top screen and bottom * screen on separate windows