mirror of
https://github.com/Lime3DS/Lime3DS
synced 2024-12-26 17:12:37 -06:00
Merge pull request #5043 from vitor-k/screen-rotate
Implement Upright/Book-style layout
This commit is contained in:
commit
a0f9c795c8
15 changed files with 408 additions and 115 deletions
|
@ -151,6 +151,7 @@ void Config::ReadValues() {
|
|||
Settings::values.layout_option =
|
||||
static_cast<Settings::LayoutOption>(sdl2_config->GetInteger("Layout", "layout_option", 0));
|
||||
Settings::values.swap_screen = sdl2_config->GetBoolean("Layout", "swap_screen", false);
|
||||
Settings::values.upright_screen = sdl2_config->GetBoolean("Layout", "upright_screen", false);
|
||||
Settings::values.custom_layout = sdl2_config->GetBoolean("Layout", "custom_layout", false);
|
||||
Settings::values.custom_top_left =
|
||||
static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_left", 0));
|
||||
|
|
|
@ -183,6 +183,10 @@ custom_bottom_bottom =
|
|||
# 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent
|
||||
swap_screen =
|
||||
|
||||
# Toggle upright orientation, for book style games.
|
||||
# 0 (default): Off, 1: On
|
||||
upright_screen =
|
||||
|
||||
# Dumps textures as PNG to dump/textures/[Title ID]/.
|
||||
# 0 (default): Off, 1: On
|
||||
dump_textures =
|
||||
|
|
|
@ -57,7 +57,7 @@ const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config:
|
|||
// This must be in alphabetical order according to action name as it must have the same order as
|
||||
// UISetting::values.shortcuts, which is alphabetically ordered.
|
||||
// clang-format off
|
||||
const std::array<UISettings::Shortcut, 20> default_hotkeys{
|
||||
const std::array<UISettings::Shortcut, 21> default_hotkeys{
|
||||
{{QStringLiteral("Advance Frame"), QStringLiteral("Main Window"), {QStringLiteral("\\"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}},
|
||||
|
@ -70,6 +70,7 @@ const std::array<UISettings::Shortcut, 20> default_hotkeys{
|
|||
{QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Remove Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F3"), Qt::ApplicationShortcut}},
|
||||
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Rotate Screens Upright"), QStringLiteral("Main Window"), {QStringLiteral("F8"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Swap Screens"), QStringLiteral("Main Window"), {QStringLiteral("F9"), Qt::WindowShortcut}},
|
||||
{QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}},
|
||||
|
@ -296,6 +297,7 @@ void Config::ReadLayoutValues() {
|
|||
Settings::values.layout_option =
|
||||
static_cast<Settings::LayoutOption>(ReadSetting(QStringLiteral("layout_option")).toInt());
|
||||
Settings::values.swap_screen = ReadSetting(QStringLiteral("swap_screen"), false).toBool();
|
||||
Settings::values.upright_screen = ReadSetting(QStringLiteral("upright_screen"), false).toBool();
|
||||
Settings::values.custom_layout = ReadSetting(QStringLiteral("custom_layout"), false).toBool();
|
||||
Settings::values.custom_top_left = ReadSetting(QStringLiteral("custom_top_left"), 0).toInt();
|
||||
Settings::values.custom_top_top = ReadSetting(QStringLiteral("custom_top_top"), 0).toInt();
|
||||
|
@ -765,6 +767,7 @@ void Config::SaveLayoutValues() {
|
|||
WriteSetting(QStringLiteral("filter_mode"), Settings::values.filter_mode, true);
|
||||
WriteSetting(QStringLiteral("layout_option"), static_cast<int>(Settings::values.layout_option));
|
||||
WriteSetting(QStringLiteral("swap_screen"), Settings::values.swap_screen, false);
|
||||
WriteSetting(QStringLiteral("upright_screen"), Settings::values.upright_screen, false);
|
||||
WriteSetting(QStringLiteral("custom_layout"), Settings::values.custom_layout, false);
|
||||
WriteSetting(QStringLiteral("custom_top_left"), Settings::values.custom_top_left, 0);
|
||||
WriteSetting(QStringLiteral("custom_top_top"), Settings::values.custom_top_top, 0);
|
||||
|
|
|
@ -53,6 +53,7 @@ void ConfigureEnhancements::SetConfiguration() {
|
|||
ui->layout_combobox->setCurrentIndex(static_cast<int>(Settings::values.layout_option));
|
||||
ui->swap_screen->setChecked(Settings::values.swap_screen);
|
||||
ui->toggle_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache);
|
||||
ui->upright_screen->setChecked(Settings::values.upright_screen);
|
||||
ui->toggle_dump_textures->setChecked(Settings::values.dump_textures);
|
||||
ui->toggle_custom_textures->setChecked(Settings::values.custom_textures);
|
||||
ui->toggle_preload_textures->setChecked(Settings::values.preload_textures);
|
||||
|
@ -101,6 +102,7 @@ void ConfigureEnhancements::ApplyConfiguration() {
|
|||
static_cast<Settings::LayoutOption>(ui->layout_combobox->currentIndex());
|
||||
Settings::values.swap_screen = ui->swap_screen->isChecked();
|
||||
Settings::values.use_disk_shader_cache = ui->toggle_disk_shader_cache->isChecked();
|
||||
Settings::values.upright_screen = ui->upright_screen->isChecked();
|
||||
Settings::values.dump_textures = ui->toggle_dump_textures->isChecked();
|
||||
Settings::values.custom_textures = ui->toggle_custom_textures->isChecked();
|
||||
Settings::values.preload_textures = ui->toggle_preload_textures->isChecked();
|
||||
|
|
|
@ -239,6 +239,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="upright_screen">
|
||||
<property name="text">
|
||||
<string>Rotate Screens Upright</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
|
|
|
@ -410,6 +410,8 @@ void GMainWindow::InitializeHotkeys() {
|
|||
});
|
||||
connect(hotkey_registry.GetHotkey("Main Window", "Swap Screens", render_window),
|
||||
&QShortcut::activated, ui.action_Screen_Layout_Swap_Screens, &QAction::trigger);
|
||||
connect(hotkey_registry.GetHotkey("Main Window", "Rotate Screens Upright", render_window),
|
||||
&QShortcut::activated, ui.action_Screen_Layout_Upright_Screens, &QAction::trigger);
|
||||
connect(hotkey_registry.GetHotkey("Main Window", "Toggle Screen Layout", render_window),
|
||||
&QShortcut::activated, this, &GMainWindow::ToggleScreenLayout);
|
||||
connect(hotkey_registry.GetHotkey("Main Window", "Fullscreen", render_window),
|
||||
|
@ -607,6 +609,9 @@ void GMainWindow::ConnectMenuEvents() {
|
|||
ui.action_Screen_Layout_Swap_Screens->setShortcut(
|
||||
hotkey_registry.GetHotkey("Main Window", "Swap Screens", this)->key());
|
||||
ui.action_Screen_Layout_Swap_Screens->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
ui.action_Screen_Layout_Upright_Screens->setShortcut(
|
||||
hotkey_registry.GetHotkey("Main Window", "Rotate Screens Upright", this)->key());
|
||||
ui.action_Screen_Layout_Upright_Screens->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
|
||||
connect(ui.action_Screen_Layout_Default, &QAction::triggered, this,
|
||||
&GMainWindow::ChangeScreenLayout);
|
||||
|
@ -618,6 +623,8 @@ void GMainWindow::ConnectMenuEvents() {
|
|||
&GMainWindow::ChangeScreenLayout);
|
||||
connect(ui.action_Screen_Layout_Swap_Screens, &QAction::triggered, this,
|
||||
&GMainWindow::OnSwapScreens);
|
||||
connect(ui.action_Screen_Layout_Upright_Screens, &QAction::triggered, this,
|
||||
&GMainWindow::OnRotateScreens);
|
||||
|
||||
// Movie
|
||||
connect(ui.action_Record_Movie, &QAction::triggered, this, &GMainWindow::OnRecordMovie);
|
||||
|
@ -1435,6 +1442,11 @@ void GMainWindow::OnSwapScreens() {
|
|||
Settings::Apply();
|
||||
}
|
||||
|
||||
void GMainWindow::OnRotateScreens() {
|
||||
Settings::values.upright_screen = ui.action_Screen_Layout_Upright_Screens->isChecked();
|
||||
Settings::Apply();
|
||||
}
|
||||
|
||||
void GMainWindow::OnCheats() {
|
||||
CheatDialog cheat_dialog(this);
|
||||
cheat_dialog.exec();
|
||||
|
@ -2032,6 +2044,7 @@ void GMainWindow::SyncMenuUISettings() {
|
|||
ui.action_Screen_Layout_Side_by_Side->setChecked(Settings::values.layout_option ==
|
||||
Settings::LayoutOption::SideScreen);
|
||||
ui.action_Screen_Layout_Swap_Screens->setChecked(Settings::values.swap_screen);
|
||||
ui.action_Screen_Layout_Upright_Screens->setChecked(Settings::values.upright_screen);
|
||||
}
|
||||
|
||||
void GMainWindow::RetranslateStatusBar() {
|
||||
|
|
|
@ -187,6 +187,7 @@ private slots:
|
|||
void ChangeScreenLayout();
|
||||
void ToggleScreenLayout();
|
||||
void OnSwapScreens();
|
||||
void OnRotateScreens();
|
||||
void OnCheats();
|
||||
void ShowFullscreen();
|
||||
void HideFullscreen();
|
||||
|
|
|
@ -109,6 +109,7 @@
|
|||
<addaction name="action_Screen_Layout_Large_Screen"/>
|
||||
<addaction name="action_Screen_Layout_Side_by_Side"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Screen_Layout_Upright_Screens"/>
|
||||
<addaction name="action_Screen_Layout_Swap_Screens"/>
|
||||
</widget>
|
||||
<addaction name="action_Fullscreen"/>
|
||||
|
@ -425,6 +426,14 @@
|
|||
<string>Swap Screens</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Screen_Layout_Upright_Screens">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rotate Upright</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Check_For_Updates">
|
||||
<property name="text">
|
||||
<string>Check for Updates</string>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -781,6 +781,35 @@ void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa
|
|||
state.Apply();
|
||||
}
|
||||
|
||||
void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w,
|
||||
float h) {
|
||||
const auto& texcoords = screen_info.display_texcoords;
|
||||
|
||||
const std::array<ScreenRectVertex, 4> vertices = {{
|
||||
ScreenRectVertex(x, y, texcoords.bottom, texcoords.right),
|
||||
ScreenRectVertex(x + w, y, texcoords.top, texcoords.right),
|
||||
ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.left),
|
||||
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left),
|
||||
}};
|
||||
|
||||
u16 scale_factor = VideoCore::GetResolutionScaleFactor();
|
||||
glUniform4f(uniform_i_resolution, screen_info.texture.width * scale_factor,
|
||||
screen_info.texture.height * scale_factor,
|
||||
1.0 / (screen_info.texture.width * scale_factor),
|
||||
1.0 / (screen_info.texture.height * scale_factor));
|
||||
glUniform4f(uniform_o_resolution, w, h, 1.0f / w, 1.0f / h);
|
||||
state.texture_units[0].texture_2d = screen_info.display_texture;
|
||||
state.texture_units[0].sampler = filter_sampler.handle;
|
||||
state.Apply();
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
state.texture_units[0].texture_2d = 0;
|
||||
state.texture_units[0].sampler = 0;
|
||||
state.Apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD
|
||||
* rotation.
|
||||
|
@ -819,6 +848,40 @@ void RendererOpenGL::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info
|
|||
state.Apply();
|
||||
}
|
||||
|
||||
void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l,
|
||||
const ScreenInfo& screen_info_r, float x, float y,
|
||||
float w, float h) {
|
||||
const auto& texcoords = screen_info_l.display_texcoords;
|
||||
|
||||
const std::array<ScreenRectVertex, 4> vertices = {{
|
||||
ScreenRectVertex(x, y, texcoords.bottom, texcoords.right),
|
||||
ScreenRectVertex(x + w, y, texcoords.top, texcoords.right),
|
||||
ScreenRectVertex(x, y + h, texcoords.bottom, texcoords.left),
|
||||
ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.left),
|
||||
}};
|
||||
|
||||
u16 scale_factor = VideoCore::GetResolutionScaleFactor();
|
||||
glUniform4f(uniform_i_resolution, screen_info_l.texture.width * scale_factor,
|
||||
screen_info_l.texture.height * scale_factor,
|
||||
1.0 / (screen_info_l.texture.width * scale_factor),
|
||||
1.0 / (screen_info_l.texture.height * scale_factor));
|
||||
glUniform4f(uniform_o_resolution, w, h, 1.0f / w, 1.0f / h);
|
||||
state.texture_units[0].texture_2d = screen_info_l.display_texture;
|
||||
state.texture_units[1].texture_2d = screen_info_r.display_texture;
|
||||
state.texture_units[0].sampler = filter_sampler.handle;
|
||||
state.texture_units[1].sampler = filter_sampler.handle;
|
||||
state.Apply();
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
state.texture_units[0].texture_2d = 0;
|
||||
state.texture_units[1].texture_2d = 0;
|
||||
state.texture_units[0].sampler = 0;
|
||||
state.texture_units[1].sampler = 0;
|
||||
state.Apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the emulated screens to the emulator window.
|
||||
*/
|
||||
|
@ -866,44 +929,85 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout) {
|
|||
|
||||
glUniform1i(uniform_layer, 0);
|
||||
if (layout.top_screen_enabled) {
|
||||
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
|
||||
DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left, (float)top_screen.top,
|
||||
(float)top_screen.GetWidth(), (float)top_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
|
||||
DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left / 2,
|
||||
(float)top_screen.top, (float)top_screen.GetWidth() / 2,
|
||||
(float)top_screen.GetHeight());
|
||||
glUniform1i(uniform_layer, 1);
|
||||
DrawSingleScreenRotated(screen_infos[1],
|
||||
((float)top_screen.left / 2) + ((float)layout.width / 2),
|
||||
(float)top_screen.top, (float)top_screen.GetWidth() / 2,
|
||||
(float)top_screen.GetHeight());
|
||||
} else if (stereo_single_screen) {
|
||||
DrawSingleScreenStereoRotated(screen_infos[0], screen_infos[1], (float)top_screen.left,
|
||||
(float)top_screen.top, (float)top_screen.GetWidth(),
|
||||
(float)top_screen.GetHeight());
|
||||
if (layout.is_rotated) {
|
||||
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
|
||||
DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left,
|
||||
(float)top_screen.top, (float)top_screen.GetWidth(),
|
||||
(float)top_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
|
||||
DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left / 2,
|
||||
(float)top_screen.top, (float)top_screen.GetWidth() / 2,
|
||||
(float)top_screen.GetHeight());
|
||||
glUniform1i(uniform_layer, 1);
|
||||
DrawSingleScreenRotated(screen_infos[1],
|
||||
((float)top_screen.left / 2) + ((float)layout.width / 2),
|
||||
(float)top_screen.top, (float)top_screen.GetWidth() / 2,
|
||||
(float)top_screen.GetHeight());
|
||||
} else if (stereo_single_screen) {
|
||||
DrawSingleScreenStereoRotated(
|
||||
screen_infos[0], screen_infos[1], (float)top_screen.left, (float)top_screen.top,
|
||||
(float)top_screen.GetWidth(), (float)top_screen.GetHeight());
|
||||
}
|
||||
} else {
|
||||
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
|
||||
DrawSingleScreen(screen_infos[0], (float)top_screen.left, (float)top_screen.top,
|
||||
(float)top_screen.GetWidth(), (float)top_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
|
||||
DrawSingleScreen(screen_infos[0], (float)top_screen.left / 2, (float)top_screen.top,
|
||||
(float)top_screen.GetWidth() / 2, (float)top_screen.GetHeight());
|
||||
glUniform1i(uniform_layer, 1);
|
||||
DrawSingleScreen(screen_infos[1],
|
||||
((float)top_screen.left / 2) + ((float)layout.width / 2),
|
||||
(float)top_screen.top, (float)top_screen.GetWidth() / 2,
|
||||
(float)top_screen.GetHeight());
|
||||
} else if (stereo_single_screen) {
|
||||
DrawSingleScreenStereo(screen_infos[0], screen_infos[1], (float)top_screen.left,
|
||||
(float)top_screen.top, (float)top_screen.GetWidth(),
|
||||
(float)top_screen.GetHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
glUniform1i(uniform_layer, 0);
|
||||
if (layout.bottom_screen_enabled) {
|
||||
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
|
||||
DrawSingleScreenRotated(screen_infos[2], (float)bottom_screen.left,
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth(),
|
||||
(float)bottom_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
|
||||
DrawSingleScreenRotated(screen_infos[2], (float)bottom_screen.left / 2,
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
|
||||
(float)bottom_screen.GetHeight());
|
||||
glUniform1i(uniform_layer, 1);
|
||||
DrawSingleScreenRotated(screen_infos[2],
|
||||
((float)bottom_screen.left / 2) + ((float)layout.width / 2),
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
|
||||
(float)bottom_screen.GetHeight());
|
||||
} else if (stereo_single_screen) {
|
||||
DrawSingleScreenStereoRotated(screen_infos[2], screen_infos[2],
|
||||
(float)bottom_screen.left, (float)bottom_screen.top,
|
||||
(float)bottom_screen.GetWidth(),
|
||||
(float)bottom_screen.GetHeight());
|
||||
if (layout.is_rotated) {
|
||||
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
|
||||
DrawSingleScreenRotated(screen_infos[2], (float)bottom_screen.left,
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth(),
|
||||
(float)bottom_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
|
||||
DrawSingleScreenRotated(
|
||||
screen_infos[2], (float)bottom_screen.left / 2, (float)bottom_screen.top,
|
||||
(float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetHeight());
|
||||
glUniform1i(uniform_layer, 1);
|
||||
DrawSingleScreenRotated(
|
||||
screen_infos[2], ((float)bottom_screen.left / 2) + ((float)layout.width / 2),
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
|
||||
(float)bottom_screen.GetHeight());
|
||||
} else if (stereo_single_screen) {
|
||||
DrawSingleScreenStereoRotated(screen_infos[2], screen_infos[2],
|
||||
(float)bottom_screen.left, (float)bottom_screen.top,
|
||||
(float)bottom_screen.GetWidth(),
|
||||
(float)bottom_screen.GetHeight());
|
||||
}
|
||||
} else {
|
||||
if (Settings::values.render_3d == Settings::StereoRenderOption::Off) {
|
||||
DrawSingleScreen(screen_infos[2], (float)bottom_screen.left,
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth(),
|
||||
(float)bottom_screen.GetHeight());
|
||||
} else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) {
|
||||
DrawSingleScreen(screen_infos[2], (float)bottom_screen.left / 2,
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
|
||||
(float)bottom_screen.GetHeight());
|
||||
glUniform1i(uniform_layer, 1);
|
||||
DrawSingleScreen(screen_infos[2],
|
||||
((float)bottom_screen.left / 2) + ((float)layout.width / 2),
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2,
|
||||
(float)bottom_screen.GetHeight());
|
||||
} else if (stereo_single_screen) {
|
||||
DrawSingleScreenStereo(screen_infos[2], screen_infos[2], (float)bottom_screen.left,
|
||||
(float)bottom_screen.top, (float)bottom_screen.GetWidth(),
|
||||
(float)bottom_screen.GetHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,9 +77,12 @@ private:
|
|||
const GPU::Regs::FramebufferConfig& framebuffer);
|
||||
void DrawScreens(const Layout::FramebufferLayout& layout);
|
||||
void DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, float w, float h);
|
||||
void DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w, float h);
|
||||
void DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l,
|
||||
const ScreenInfo& screen_info_r, float x, float y, float w,
|
||||
float h);
|
||||
void DrawSingleScreenStereo(const ScreenInfo& screen_info_l, const ScreenInfo& screen_info_r,
|
||||
float x, float y, float w, float h);
|
||||
void UpdateFramerate();
|
||||
|
||||
// Loads framebuffer from emulated memory into the display information structure
|
||||
|
|
Loading…
Reference in a new issue