Merge pull request #5043 from vitor-k/screen-rotate

Implement Upright/Book-style layout
This commit is contained in:
James Rowe 2020-01-20 18:38:06 -07:00 committed by GitHub
commit a0f9c795c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 408 additions and 115 deletions

View file

@ -118,6 +118,11 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
static_cast<float>(framebuffer_y - framebuffer_layout.bottom_screen.top) /
(framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top);
if (!framebuffer_layout.is_rotated) {
std::swap(touch_state->touch_x, touch_state->touch_y);
touch_state->touch_x = 1.f - touch_state->touch_x;
}
touch_state->touch_pressed = true;
}
@ -145,17 +150,21 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height)
} else {
switch (Settings::values.layout_option) {
case Settings::LayoutOption::SingleScreen:
layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen);
layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen,
Settings::values.upright_screen);
break;
case Settings::LayoutOption::LargeScreen:
layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen);
layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen,
Settings::values.upright_screen);
break;
case Settings::LayoutOption::SideScreen:
layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen);
layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen,
Settings::values.upright_screen);
break;
case Settings::LayoutOption::Default:
default:
layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen);
layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen,
Settings::values.upright_screen);
break;
}
}

View file

@ -15,9 +15,17 @@ static const float TOP_SCREEN_ASPECT_RATIO =
static_cast<float>(Core::kScreenTopHeight) / Core::kScreenTopWidth;
static const float BOT_SCREEN_ASPECT_RATIO =
static_cast<float>(Core::kScreenBottomHeight) / Core::kScreenBottomWidth;
static const float TOP_SCREEN_UPRIGHT_ASPECT_RATIO =
static_cast<float>(Core::kScreenTopWidth) / Core::kScreenTopHeight;
static const float BOT_SCREEN_UPRIGHT_ASPECT_RATIO =
static_cast<float>(Core::kScreenBottomWidth) / Core::kScreenBottomHeight;
u32 FramebufferLayout::GetScalingRatio() const {
return static_cast<u32>(((top_screen.GetWidth() - 1) / Core::kScreenTopWidth) + 1);
if (is_rotated) {
return static_cast<u32>(((top_screen.GetWidth() - 1) / Core::kScreenTopWidth) + 1);
} else {
return static_cast<u32>(((top_screen.GetWidth() - 1) / Core::kScreenTopHeight) + 1);
}
}
// Finds the largest size subrectangle contained in window area that is confined to the aspect ratio
@ -30,57 +38,108 @@ static Common::Rectangle<T> maxRectangle(Common::Rectangle<T> window_area,
static_cast<T>(std::round(scale * screen_aspect_ratio))};
}
FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool swapped) {
FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool swapped, bool upright) {
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<u32> screen_window_area{0, 0, width, height / 2};
Common::Rectangle<u32> top_screen = maxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO);
Common::Rectangle<u32> bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO);
FramebufferLayout res{width, height, true, true, {}, {}, !upright};
Common::Rectangle<u32> screen_window_area;
Common::Rectangle<u32> top_screen;
Common::Rectangle<u32> bot_screen;
float emulation_aspect_ratio;
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);
// 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);
// both screens height are taken into account by multiplying by 2
emulation_aspect_ratio = TOP_SCREEN_ASPECT_RATIO * 2;
}
float window_aspect_ratio = static_cast<float>(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);
// Window is wider than the emulation content => apply borders to the right and left sides
if (upright) {
// 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 =
bot_screen.TranslateY((top_screen.GetHeight() - bot_screen.GetHeight()) / 2);
if (swapped) {
bot_screen = bot_screen.TranslateX(width / 2 - bot_screen.GetWidth());
} else {
top_screen = top_screen.TranslateX(width / 2 - top_screen.GetWidth());
}
} else {
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 => apply borders to the top and bottom
// 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 = bot_screen.TranslateX((top_screen.GetWidth() - bot_screen.GetWidth()) / 2);
if (swapped) {
bot_screen = bot_screen.TranslateY(height / 2 - bot_screen.GetHeight());
if (upright) {
top_screen = top_screen.TranslateY(
(screen_window_area.GetHeight() - top_screen.GetHeight()) / 2);
bot_screen = bot_screen.TranslateY(
(screen_window_area.GetHeight() - bot_screen.GetHeight()) / 2);
} else {
top_screen = top_screen.TranslateY(height / 2 - top_screen.GetHeight());
// 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 = bot_screen.TranslateX((top_screen.GetWidth() - bot_screen.GetWidth()) / 2);
if (swapped) {
bot_screen = bot_screen.TranslateY(height / 2 - bot_screen.GetHeight());
} else {
top_screen = top_screen.TranslateY(height / 2 - top_screen.GetHeight());
}
}
}
// Move the top screen to the bottom if we are swapped.
res.top_screen = swapped ? top_screen.TranslateY(height / 2) : top_screen;
res.bottom_screen = swapped ? bot_screen : bot_screen.TranslateY(height / 2);
if (upright) {
// Move the top screen to the right if we are swapped.
res.top_screen = swapped ? top_screen.TranslateX(width / 2) : top_screen;
res.bottom_screen = swapped ? bot_screen : bot_screen.TranslateX(width / 2);
} else {
// Move the top screen to the bottom if we are swapped.
res.top_screen = swapped ? top_screen.TranslateY(height / 2) : top_screen;
res.bottom_screen = swapped ? bot_screen : bot_screen.TranslateY(height / 2);
}
return res;
}
FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped) {
FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped, bool upright) {
ASSERT(width > 0);
ASSERT(height > 0);
// The drawing code needs at least somewhat valid values for both screens
// so just calculate them both even if the other isn't showing.
FramebufferLayout res{width, height, !swapped, swapped, {}, {}};
FramebufferLayout res{width, height, !swapped, swapped, {}, {}, !upright};
Common::Rectangle<u32> screen_window_area{0, 0, width, height};
Common::Rectangle<u32> top_screen = maxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO);
Common::Rectangle<u32> bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO);
Common::Rectangle<u32> top_screen;
Common::Rectangle<u32> 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);
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);
emulation_aspect_ratio = (swapped) ? BOT_SCREEN_ASPECT_RATIO : TOP_SCREEN_ASPECT_RATIO;
}
float window_aspect_ratio = static_cast<float>(height) / width;
float emulation_aspect_ratio = (swapped) ? BOT_SCREEN_ASPECT_RATIO : TOP_SCREEN_ASPECT_RATIO;
if (window_aspect_ratio < emulation_aspect_ratio) {
top_screen =
@ -96,21 +155,42 @@ FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped) {
return res;
}
FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped) {
FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upright) {
ASSERT(width > 0);
ASSERT(height > 0);
FramebufferLayout res{width, height, true, true, {}, {}};
FramebufferLayout res{width, height, true, true, {}, {}, !upright};
// 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<float>(height) / width;
float emulation_aspect_ratio =
swapped ? Core::kScreenBottomHeight * 4 /
(Core::kScreenBottomWidth * 4.0f + Core::kScreenTopWidth)
: Core::kScreenTopHeight * 4 /
(Core::kScreenTopWidth * 4.0f + 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;
float emulation_aspect_ratio;
float large_screen_aspect_ratio;
float small_screen_aspect_ratio;
if (upright) {
if (swapped) {
emulation_aspect_ratio = (Core::kScreenBottomWidth * 4.0f + Core::kScreenTopWidth) /
(Core::kScreenBottomHeight * 4);
large_screen_aspect_ratio = BOT_SCREEN_UPRIGHT_ASPECT_RATIO;
small_screen_aspect_ratio = TOP_SCREEN_UPRIGHT_ASPECT_RATIO;
} else {
emulation_aspect_ratio = (Core::kScreenTopWidth * 4.0f + Core::kScreenBottomWidth) /
(Core::kScreenTopHeight * 4);
large_screen_aspect_ratio = TOP_SCREEN_UPRIGHT_ASPECT_RATIO;
small_screen_aspect_ratio = BOT_SCREEN_UPRIGHT_ASPECT_RATIO;
}
} else {
if (swapped) {
emulation_aspect_ratio = Core::kScreenBottomHeight * 4 /
(Core::kScreenBottomWidth * 4.0f + Core::kScreenTopWidth);
large_screen_aspect_ratio = BOT_SCREEN_ASPECT_RATIO;
small_screen_aspect_ratio = TOP_SCREEN_ASPECT_RATIO;
} else {
emulation_aspect_ratio = Core::kScreenTopHeight * 4 /
(Core::kScreenTopWidth * 4.0f + Core::kScreenBottomWidth);
large_screen_aspect_ratio = TOP_SCREEN_ASPECT_RATIO;
small_screen_aspect_ratio = BOT_SCREEN_ASPECT_RATIO;
}
}
Common::Rectangle<u32> screen_window_area{0, 0, width, height};
Common::Rectangle<u32> total_rect = maxRectangle(screen_window_area, emulation_aspect_ratio);
@ -119,35 +199,49 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped) {
Common::Rectangle<u32> 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);
large_screen = large_screen.TranslateX((width - total_rect.GetWidth()) / 2);
} else {
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)
.TranslateY(large_screen.GetHeight() + large_screen.top - small_screen.GetHeight());
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());
} 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());
}
res.top_screen = swapped ? small_screen : large_screen;
res.bottom_screen = swapped ? large_screen : small_screen;
return res;
}
FramebufferLayout SideFrameLayout(u32 width, u32 height, bool swapped) {
FramebufferLayout SideFrameLayout(u32 width, u32 height, bool swapped, bool upright) {
ASSERT(width > 0);
ASSERT(height > 0);
FramebufferLayout res{width, height, true, true, {}, {}};
FramebufferLayout res{width, height, true, true, {}, {}, !upright};
// Aspect ratio of both screens side by side
const float emulation_aspect_ratio = static_cast<float>(Core::kScreenTopHeight) /
(Core::kScreenTopWidth + Core::kScreenBottomWidth);
float emulation_aspect_ratio =
upright ? static_cast<float>(Core::kScreenTopWidth + Core::kScreenBottomWidth) /
Core::kScreenTopHeight
: static_cast<float>(Core::kScreenTopHeight) /
(Core::kScreenTopWidth + Core::kScreenBottomWidth);
float window_aspect_ratio = static_cast<float>(height) / width;
Common::Rectangle<u32> screen_window_area{0, 0, width, height};
// Find largest Rectangle that can fit in the window size with the given aspect ratio
Common::Rectangle<u32> screen_rect = maxRectangle(screen_window_area, emulation_aspect_ratio);
// Find sizes of top and bottom screen
Common::Rectangle<u32> top_screen = maxRectangle(screen_rect, TOP_SCREEN_ASPECT_RATIO);
Common::Rectangle<u32> bot_screen = maxRectangle(screen_rect, BOT_SCREEN_ASPECT_RATIO);
Common::Rectangle<u32> top_screen =
upright ? maxRectangle(screen_rect, TOP_SCREEN_UPRIGHT_ASPECT_RATIO)
: maxRectangle(screen_rect, TOP_SCREEN_ASPECT_RATIO);
Common::Rectangle<u32> 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.
@ -160,9 +254,15 @@ FramebufferLayout SideFrameLayout(u32 width, u32 height, bool swapped) {
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());
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;
}
@ -170,7 +270,7 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height) {
ASSERT(width > 0);
ASSERT(height > 0);
FramebufferLayout res{width, height, true, true, {}, {}};
FramebufferLayout res{width, height, true, true, {}, {}, !Settings::values.upright_screen};
Common::Rectangle<u32> top_screen{
Settings::values.custom_top_left, Settings::values.custom_top_top,
@ -194,35 +294,69 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
int width, height;
switch (Settings::values.layout_option) {
case Settings::LayoutOption::SingleScreen:
if (Settings::values.swap_screen) {
width = Core::kScreenBottomWidth * res_scale;
height = Core::kScreenBottomHeight * res_scale;
if (Settings::values.upright_screen) {
if (Settings::values.swap_screen) {
width = Core::kScreenBottomHeight * res_scale;
height = Core::kScreenBottomWidth * res_scale;
} else {
width = Core::kScreenTopHeight * res_scale;
height = Core::kScreenTopWidth * res_scale;
}
} else {
width = Core::kScreenTopWidth * res_scale;
height = Core::kScreenTopHeight * res_scale;
if (Settings::values.swap_screen) {
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, Settings::values.swap_screen);
layout = SingleFrameLayout(width, height, Settings::values.swap_screen,
Settings::values.upright_screen);
break;
case Settings::LayoutOption::LargeScreen:
if (Settings::values.swap_screen) {
width = (Core::kScreenBottomWidth + Core::kScreenTopWidth / 4) * res_scale;
height = Core::kScreenBottomHeight * res_scale;
if (Settings::values.upright_screen) {
if (Settings::values.swap_screen) {
width = Core::kScreenBottomHeight * res_scale;
height = (Core::kScreenBottomWidth + Core::kScreenTopWidth / 4) * res_scale;
} else {
width = Core::kScreenTopHeight * res_scale;
height = (Core::kScreenTopWidth + Core::kScreenBottomWidth / 4) * res_scale;
}
} else {
width = (Core::kScreenTopWidth + Core::kScreenBottomWidth / 4) * res_scale;
height = Core::kScreenTopHeight * res_scale;
if (Settings::values.swap_screen) {
width = (Core::kScreenBottomWidth + Core::kScreenTopWidth / 4) * res_scale;
height = Core::kScreenBottomHeight * res_scale;
} else {
width = (Core::kScreenTopWidth + Core::kScreenBottomWidth / 4) * res_scale;
height = Core::kScreenTopHeight * res_scale;
}
}
layout = LargeFrameLayout(width, height, Settings::values.swap_screen);
layout = LargeFrameLayout(width, height, Settings::values.swap_screen,
Settings::values.upright_screen);
break;
case Settings::LayoutOption::SideScreen:
width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale;
height = Core::kScreenTopHeight * res_scale;
layout = SideFrameLayout(width, height, Settings::values.swap_screen);
if (Settings::values.upright_screen) {
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,
Settings::values.upright_screen);
break;
case Settings::LayoutOption::Default:
default:
width = Core::kScreenTopWidth * res_scale;
height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale;
layout = DefaultFrameLayout(width, height, Settings::values.swap_screen);
if (Settings::values.upright_screen) {
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,
Settings::values.upright_screen);
break;
}
}

View file

@ -16,6 +16,7 @@ struct FramebufferLayout {
bool bottom_screen_enabled;
Common::Rectangle<u32> top_screen;
Common::Rectangle<u32> bottom_screen;
bool is_rotated = true;
/**
* Returns the ration of pixel size of the top screen, compared to the native size of the 3DS
@ -31,7 +32,7 @@ struct FramebufferLayout {
* @param is_swapped if true, the bottom screen will be displayed above the top screen
* @return Newly created FramebufferLayout object with default screen regions initialized
*/
FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool is_swapped);
FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool is_swapped, bool upright);
/**
* Factory method for constructing a FramebufferLayout with only the top or bottom screen
@ -40,7 +41,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool is_swapped);
* @param is_swapped if true, the bottom screen will be displayed (and the top won't be displayed)
* @return Newly created FramebufferLayout object with default screen regions initialized
*/
FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool is_swapped);
FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool is_swapped, bool upright);
/**
* Factory method for constructing a Frame with the a 4x size Top screen with a 1x size bottom
@ -51,7 +52,7 @@ FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool is_swapped);
* @param is_swapped if true, the bottom screen will be the large display
* @return Newly created FramebufferLayout object with default screen regions initialized
*/
FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool is_swapped);
FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool is_swapped, bool upright);
/**
* Factory method for constructing a Frame with the Top screen and bottom
@ -62,7 +63,7 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool is_swapped);
* @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);
FramebufferLayout SideFrameLayout(u32 width, u32 height, bool is_swapped, bool upright);
/**
* Factory method for constructing a custom FramebufferLayout

View file

@ -87,6 +87,7 @@ void LogSettings() {
LogSetting("Stereoscopy_Factor3d", Settings::values.factor_3d);
LogSetting("Layout_LayoutOption", static_cast<int>(Settings::values.layout_option));
LogSetting("Layout_SwapScreen", Settings::values.swap_screen);
LogSetting("Layout_UprightScreen", Settings::values.upright_screen);
LogSetting("Utility_DumpTextures", Settings::values.dump_textures);
LogSetting("Utility_CustomTextures", Settings::values.custom_textures);
LogSetting("Audio_EnableDspLle", Settings::values.enable_dsp_lle);

View file

@ -150,6 +150,7 @@ struct Values {
LayoutOption layout_option;
bool swap_screen;
bool upright_screen;
bool custom_layout;
u16 custom_top_left;
u16 custom_top_top;