mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00: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 = |     Settings::values.layout_option = | ||||||
|         static_cast<Settings::LayoutOption>(sdl2_config->GetInteger("Layout", "layout_option", 0)); |         static_cast<Settings::LayoutOption>(sdl2_config->GetInteger("Layout", "layout_option", 0)); | ||||||
|     Settings::values.swap_screen = sdl2_config->GetBoolean("Layout", "swap_screen", false); |     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_layout = sdl2_config->GetBoolean("Layout", "custom_layout", false); | ||||||
|     Settings::values.custom_top_left = |     Settings::values.custom_top_left = | ||||||
|         static_cast<u16>(sdl2_config->GetInteger("Layout", "custom_top_left", 0)); |         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 | # 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent | ||||||
| swap_screen = | 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]/. | # Dumps textures as PNG to dump/textures/[Title ID]/. | ||||||
| # 0 (default): Off, 1: On | # 0 (default): Off, 1: On | ||||||
| dump_textures = | 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
 | // 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.
 | // UISetting::values.shortcuts, which is alphabetically ordered.
 | ||||||
| // clang-format off
 | // 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("Advance Frame"),            QStringLiteral("Main Window"), {QStringLiteral("\\"), Qt::ApplicationShortcut}}, | ||||||
|      {QStringLiteral("Capture Screenshot"),       QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::ApplicationShortcut}}, |      {QStringLiteral("Capture Screenshot"),       QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::ApplicationShortcut}}, | ||||||
|      {QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}}, |      {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("Load File"),                QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), Qt::WindowShortcut}}, | ||||||
|      {QStringLiteral("Remove Amiibo"),            QStringLiteral("Main Window"), {QStringLiteral("F3"), Qt::ApplicationShortcut}}, |      {QStringLiteral("Remove Amiibo"),            QStringLiteral("Main Window"), {QStringLiteral("F3"), Qt::ApplicationShortcut}}, | ||||||
|      {QStringLiteral("Restart Emulation"),        QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}}, |      {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("Stop Emulation"),           QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}}, | ||||||
|      {QStringLiteral("Swap Screens"),             QStringLiteral("Main Window"), {QStringLiteral("F9"), Qt::WindowShortcut}}, |      {QStringLiteral("Swap Screens"),             QStringLiteral("Main Window"), {QStringLiteral("F9"), Qt::WindowShortcut}}, | ||||||
|      {QStringLiteral("Toggle Filter Bar"),        QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), 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 = |     Settings::values.layout_option = | ||||||
|         static_cast<Settings::LayoutOption>(ReadSetting(QStringLiteral("layout_option")).toInt()); |         static_cast<Settings::LayoutOption>(ReadSetting(QStringLiteral("layout_option")).toInt()); | ||||||
|     Settings::values.swap_screen = ReadSetting(QStringLiteral("swap_screen"), false).toBool(); |     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_layout = ReadSetting(QStringLiteral("custom_layout"), false).toBool(); | ||||||
|     Settings::values.custom_top_left = ReadSetting(QStringLiteral("custom_top_left"), 0).toInt(); |     Settings::values.custom_top_left = ReadSetting(QStringLiteral("custom_top_left"), 0).toInt(); | ||||||
|     Settings::values.custom_top_top = ReadSetting(QStringLiteral("custom_top_top"), 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("filter_mode"), Settings::values.filter_mode, true); | ||||||
|     WriteSetting(QStringLiteral("layout_option"), static_cast<int>(Settings::values.layout_option)); |     WriteSetting(QStringLiteral("layout_option"), static_cast<int>(Settings::values.layout_option)); | ||||||
|     WriteSetting(QStringLiteral("swap_screen"), Settings::values.swap_screen, false); |     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_layout"), Settings::values.custom_layout, false); | ||||||
|     WriteSetting(QStringLiteral("custom_top_left"), Settings::values.custom_top_left, 0); |     WriteSetting(QStringLiteral("custom_top_left"), Settings::values.custom_top_left, 0); | ||||||
|     WriteSetting(QStringLiteral("custom_top_top"), Settings::values.custom_top_top, 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->layout_combobox->setCurrentIndex(static_cast<int>(Settings::values.layout_option)); | ||||||
|     ui->swap_screen->setChecked(Settings::values.swap_screen); |     ui->swap_screen->setChecked(Settings::values.swap_screen); | ||||||
|     ui->toggle_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache); |     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_dump_textures->setChecked(Settings::values.dump_textures); | ||||||
|     ui->toggle_custom_textures->setChecked(Settings::values.custom_textures); |     ui->toggle_custom_textures->setChecked(Settings::values.custom_textures); | ||||||
|     ui->toggle_preload_textures->setChecked(Settings::values.preload_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()); |         static_cast<Settings::LayoutOption>(ui->layout_combobox->currentIndex()); | ||||||
|     Settings::values.swap_screen = ui->swap_screen->isChecked(); |     Settings::values.swap_screen = ui->swap_screen->isChecked(); | ||||||
|     Settings::values.use_disk_shader_cache = ui->toggle_disk_shader_cache->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.dump_textures = ui->toggle_dump_textures->isChecked(); | ||||||
|     Settings::values.custom_textures = ui->toggle_custom_textures->isChecked(); |     Settings::values.custom_textures = ui->toggle_custom_textures->isChecked(); | ||||||
|     Settings::values.preload_textures = ui->toggle_preload_textures->isChecked(); |     Settings::values.preload_textures = ui->toggle_preload_textures->isChecked(); | ||||||
|  |  | ||||||
|  | @ -239,6 +239,13 @@ | ||||||
|         </property> |         </property> | ||||||
|        </widget> |        </widget> | ||||||
|       </item> |       </item> | ||||||
|  |       <item> | ||||||
|  |        <widget class="QCheckBox" name="upright_screen"> | ||||||
|  |         <property name="text"> | ||||||
|  |          <string>Rotate Screens Upright</string> | ||||||
|  |         </property> | ||||||
|  |        </widget> | ||||||
|  |       </item> | ||||||
|       <item> |       <item> | ||||||
|        <layout class="QHBoxLayout" name="horizontalLayout_6"> |        <layout class="QHBoxLayout" name="horizontalLayout_6"> | ||||||
|         <item> |         <item> | ||||||
|  |  | ||||||
|  | @ -410,6 +410,8 @@ void GMainWindow::InitializeHotkeys() { | ||||||
|             }); |             }); | ||||||
|     connect(hotkey_registry.GetHotkey("Main Window", "Swap Screens", render_window), |     connect(hotkey_registry.GetHotkey("Main Window", "Swap Screens", render_window), | ||||||
|             &QShortcut::activated, ui.action_Screen_Layout_Swap_Screens, &QAction::trigger); |             &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), |     connect(hotkey_registry.GetHotkey("Main Window", "Toggle Screen Layout", render_window), | ||||||
|             &QShortcut::activated, this, &GMainWindow::ToggleScreenLayout); |             &QShortcut::activated, this, &GMainWindow::ToggleScreenLayout); | ||||||
|     connect(hotkey_registry.GetHotkey("Main Window", "Fullscreen", render_window), |     connect(hotkey_registry.GetHotkey("Main Window", "Fullscreen", render_window), | ||||||
|  | @ -607,6 +609,9 @@ void GMainWindow::ConnectMenuEvents() { | ||||||
|     ui.action_Screen_Layout_Swap_Screens->setShortcut( |     ui.action_Screen_Layout_Swap_Screens->setShortcut( | ||||||
|         hotkey_registry.GetHotkey("Main Window", "Swap Screens", this)->key()); |         hotkey_registry.GetHotkey("Main Window", "Swap Screens", this)->key()); | ||||||
|     ui.action_Screen_Layout_Swap_Screens->setShortcutContext(Qt::WidgetWithChildrenShortcut); |     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_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); | ||||||
|     connect(ui.action_Screen_Layout_Default, &QAction::triggered, this, |     connect(ui.action_Screen_Layout_Default, &QAction::triggered, this, | ||||||
|             &GMainWindow::ChangeScreenLayout); |             &GMainWindow::ChangeScreenLayout); | ||||||
|  | @ -618,6 +623,8 @@ void GMainWindow::ConnectMenuEvents() { | ||||||
|             &GMainWindow::ChangeScreenLayout); |             &GMainWindow::ChangeScreenLayout); | ||||||
|     connect(ui.action_Screen_Layout_Swap_Screens, &QAction::triggered, this, |     connect(ui.action_Screen_Layout_Swap_Screens, &QAction::triggered, this, | ||||||
|             &GMainWindow::OnSwapScreens); |             &GMainWindow::OnSwapScreens); | ||||||
|  |     connect(ui.action_Screen_Layout_Upright_Screens, &QAction::triggered, this, | ||||||
|  |             &GMainWindow::OnRotateScreens); | ||||||
| 
 | 
 | ||||||
|     // Movie
 |     // Movie
 | ||||||
|     connect(ui.action_Record_Movie, &QAction::triggered, this, &GMainWindow::OnRecordMovie); |     connect(ui.action_Record_Movie, &QAction::triggered, this, &GMainWindow::OnRecordMovie); | ||||||
|  | @ -1435,6 +1442,11 @@ void GMainWindow::OnSwapScreens() { | ||||||
|     Settings::Apply(); |     Settings::Apply(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void GMainWindow::OnRotateScreens() { | ||||||
|  |     Settings::values.upright_screen = ui.action_Screen_Layout_Upright_Screens->isChecked(); | ||||||
|  |     Settings::Apply(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void GMainWindow::OnCheats() { | void GMainWindow::OnCheats() { | ||||||
|     CheatDialog cheat_dialog(this); |     CheatDialog cheat_dialog(this); | ||||||
|     cheat_dialog.exec(); |     cheat_dialog.exec(); | ||||||
|  | @ -2032,6 +2044,7 @@ void GMainWindow::SyncMenuUISettings() { | ||||||
|     ui.action_Screen_Layout_Side_by_Side->setChecked(Settings::values.layout_option == |     ui.action_Screen_Layout_Side_by_Side->setChecked(Settings::values.layout_option == | ||||||
|                                                      Settings::LayoutOption::SideScreen); |                                                      Settings::LayoutOption::SideScreen); | ||||||
|     ui.action_Screen_Layout_Swap_Screens->setChecked(Settings::values.swap_screen); |     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() { | void GMainWindow::RetranslateStatusBar() { | ||||||
|  |  | ||||||
|  | @ -187,6 +187,7 @@ private slots: | ||||||
|     void ChangeScreenLayout(); |     void ChangeScreenLayout(); | ||||||
|     void ToggleScreenLayout(); |     void ToggleScreenLayout(); | ||||||
|     void OnSwapScreens(); |     void OnSwapScreens(); | ||||||
|  |     void OnRotateScreens(); | ||||||
|     void OnCheats(); |     void OnCheats(); | ||||||
|     void ShowFullscreen(); |     void ShowFullscreen(); | ||||||
|     void HideFullscreen(); |     void HideFullscreen(); | ||||||
|  |  | ||||||
|  | @ -109,6 +109,7 @@ | ||||||
|      <addaction name="action_Screen_Layout_Large_Screen"/> |      <addaction name="action_Screen_Layout_Large_Screen"/> | ||||||
|      <addaction name="action_Screen_Layout_Side_by_Side"/> |      <addaction name="action_Screen_Layout_Side_by_Side"/> | ||||||
|      <addaction name="separator"/> |      <addaction name="separator"/> | ||||||
|  |      <addaction name="action_Screen_Layout_Upright_Screens"/> | ||||||
|      <addaction name="action_Screen_Layout_Swap_Screens"/> |      <addaction name="action_Screen_Layout_Swap_Screens"/> | ||||||
|     </widget> |     </widget> | ||||||
|     <addaction name="action_Fullscreen"/> |     <addaction name="action_Fullscreen"/> | ||||||
|  | @ -425,6 +426,14 @@ | ||||||
|     <string>Swap Screens</string> |     <string>Swap Screens</string> | ||||||
|    </property> |    </property> | ||||||
|   </action> |   </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"> |   <action name="action_Check_For_Updates"> | ||||||
|    <property name="text"> |    <property name="text"> | ||||||
|     <string>Check for Updates</string> |     <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) / |         static_cast<float>(framebuffer_y - framebuffer_layout.bottom_screen.top) / | ||||||
|         (framebuffer_layout.bottom_screen.bottom - 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; |     touch_state->touch_pressed = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -145,17 +150,21 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) | ||||||
|     } else { |     } else { | ||||||
|         switch (Settings::values.layout_option) { |         switch (Settings::values.layout_option) { | ||||||
|         case Settings::LayoutOption::SingleScreen: |         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; |             break; | ||||||
|         case Settings::LayoutOption::LargeScreen: |         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; |             break; | ||||||
|         case Settings::LayoutOption::SideScreen: |         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; |             break; | ||||||
|         case Settings::LayoutOption::Default: |         case Settings::LayoutOption::Default: | ||||||
|         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; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -15,9 +15,17 @@ static const float TOP_SCREEN_ASPECT_RATIO = | ||||||
|     static_cast<float>(Core::kScreenTopHeight) / Core::kScreenTopWidth; |     static_cast<float>(Core::kScreenTopHeight) / Core::kScreenTopWidth; | ||||||
| static const float BOT_SCREEN_ASPECT_RATIO = | static const float BOT_SCREEN_ASPECT_RATIO = | ||||||
|     static_cast<float>(Core::kScreenBottomHeight) / Core::kScreenBottomWidth; |     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 { | 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
 | // 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))}; |                                 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(width > 0); | ||||||
|     ASSERT(height > 0); |     ASSERT(height > 0); | ||||||
| 
 | 
 | ||||||
|     FramebufferLayout res{width, height, true, true, {}, {}}; |     FramebufferLayout res{width, height, true, true, {}, {}, !upright}; | ||||||
|     // Default layout gives equal screen sizes to the top and bottom screen
 |     Common::Rectangle<u32> screen_window_area; | ||||||
|     Common::Rectangle<u32> screen_window_area{0, 0, width, height / 2}; |     Common::Rectangle<u32> top_screen; | ||||||
|     Common::Rectangle<u32> top_screen = maxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO); |     Common::Rectangle<u32> bot_screen; | ||||||
|     Common::Rectangle<u32> bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO); |     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; |     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) { |     if (window_aspect_ratio < emulation_aspect_ratio) { | ||||||
|         // Apply borders to the left and right sides of the window.
 |         // Window is wider than the emulation content => apply borders to the right and left sides
 | ||||||
|         top_screen = |         if (upright) { | ||||||
|             top_screen.TranslateX((screen_window_area.GetWidth() - top_screen.GetWidth()) / 2); |             // Recalculate the bottom screen to account for the height difference between right and
 | ||||||
|         bot_screen = |             // left
 | ||||||
|             bot_screen.TranslateX((screen_window_area.GetWidth() - bot_screen.GetWidth()) / 2); |             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 { |     } else { | ||||||
|         // Window is narrower than the emulation content => apply borders to the top and bottom
 |         // 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
 |         if (upright) { | ||||||
|         screen_window_area = {0, 0, width, top_screen.GetHeight()}; |             top_screen = top_screen.TranslateY( | ||||||
|         bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO); |                 (screen_window_area.GetHeight() - top_screen.GetHeight()) / 2); | ||||||
|         bot_screen = bot_screen.TranslateX((top_screen.GetWidth() - bot_screen.GetWidth()) / 2); |             bot_screen = bot_screen.TranslateY( | ||||||
|         if (swapped) { |                 (screen_window_area.GetHeight() - bot_screen.GetHeight()) / 2); | ||||||
|             bot_screen = bot_screen.TranslateY(height / 2 - bot_screen.GetHeight()); |  | ||||||
|         } else { |         } 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.
 |     if (upright) { | ||||||
|     res.top_screen = swapped ? top_screen.TranslateY(height / 2) : top_screen; |         // Move the top screen to the right if we are swapped.
 | ||||||
|     res.bottom_screen = swapped ? bot_screen : bot_screen.TranslateY(height / 2); |         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; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped) { | FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped, bool upright) { | ||||||
|     ASSERT(width > 0); |     ASSERT(width > 0); | ||||||
|     ASSERT(height > 0); |     ASSERT(height > 0); | ||||||
|     // The drawing code needs at least somewhat valid values for both screens
 |     // The drawing code needs at least somewhat valid values for both screens
 | ||||||
|     // so just calculate them both even if the other isn't showing.
 |     // 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> screen_window_area{0, 0, width, height}; | ||||||
|     Common::Rectangle<u32> top_screen = maxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO); |     Common::Rectangle<u32> top_screen; | ||||||
|     Common::Rectangle<u32> bot_screen = maxRectangle(screen_window_area, BOT_SCREEN_ASPECT_RATIO); |     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 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) { |     if (window_aspect_ratio < emulation_aspect_ratio) { | ||||||
|         top_screen = |         top_screen = | ||||||
|  | @ -96,21 +155,42 @@ FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool swapped) { | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped) { | FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upright) { | ||||||
|     ASSERT(width > 0); |     ASSERT(width > 0); | ||||||
|     ASSERT(height > 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
 |     // 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
 |     // 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 window_aspect_ratio = static_cast<float>(height) / width; | ||||||
|     float emulation_aspect_ratio = |     float emulation_aspect_ratio; | ||||||
|         swapped ? Core::kScreenBottomHeight * 4 / |     float large_screen_aspect_ratio; | ||||||
|                       (Core::kScreenBottomWidth * 4.0f + Core::kScreenTopWidth) |     float small_screen_aspect_ratio; | ||||||
|                 : Core::kScreenTopHeight * 4 / |     if (upright) { | ||||||
|                       (Core::kScreenTopWidth * 4.0f + Core::kScreenBottomWidth); |         if (swapped) { | ||||||
|     float large_screen_aspect_ratio = swapped ? BOT_SCREEN_ASPECT_RATIO : TOP_SCREEN_ASPECT_RATIO; |             emulation_aspect_ratio = (Core::kScreenBottomWidth * 4.0f + Core::kScreenTopWidth) / | ||||||
|     float small_screen_aspect_ratio = swapped ? TOP_SCREEN_ASPECT_RATIO : BOT_SCREEN_ASPECT_RATIO; |                                      (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> screen_window_area{0, 0, width, height}; | ||||||
|     Common::Rectangle<u32> total_rect = maxRectangle(screen_window_area, emulation_aspect_ratio); |     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); |     Common::Rectangle<u32> small_screen = maxRectangle(fourth_size_rect, small_screen_aspect_ratio); | ||||||
| 
 | 
 | ||||||
|     if (window_aspect_ratio < emulation_aspect_ratio) { |     if (window_aspect_ratio < emulation_aspect_ratio) { | ||||||
|         large_screen = |         large_screen = large_screen.TranslateX((width - total_rect.GetWidth()) / 2); | ||||||
|             large_screen.TranslateX((screen_window_area.GetWidth() - total_rect.GetWidth()) / 2); |  | ||||||
|     } else { |     } else { | ||||||
|         large_screen = large_screen.TranslateY((height - total_rect.GetHeight()) / 2); |         large_screen = large_screen.TranslateY((height - total_rect.GetHeight()) / 2); | ||||||
|     } |     } | ||||||
|     // Shift the small screen to the bottom right corner
 |     if (upright) { | ||||||
|     small_screen = |         large_screen = large_screen.TranslateY(small_screen.GetHeight()); | ||||||
|         small_screen.TranslateX(large_screen.right) |         small_screen = small_screen.TranslateX(large_screen.right - small_screen.GetWidth()) | ||||||
|             .TranslateY(large_screen.GetHeight() + large_screen.top - small_screen.GetHeight()); |                            .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.top_screen = swapped ? small_screen : large_screen; | ||||||
|     res.bottom_screen = swapped ? large_screen : small_screen; |     res.bottom_screen = swapped ? large_screen : small_screen; | ||||||
|     return res; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| FramebufferLayout SideFrameLayout(u32 width, u32 height, bool swapped) { | FramebufferLayout SideFrameLayout(u32 width, u32 height, bool swapped, bool upright) { | ||||||
|     ASSERT(width > 0); |     ASSERT(width > 0); | ||||||
|     ASSERT(height > 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
 |     // Aspect ratio of both screens side by side
 | ||||||
|     const float emulation_aspect_ratio = static_cast<float>(Core::kScreenTopHeight) / |     float emulation_aspect_ratio = | ||||||
|                                          (Core::kScreenTopWidth + Core::kScreenBottomWidth); |         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; |     float window_aspect_ratio = static_cast<float>(height) / width; | ||||||
|     Common::Rectangle<u32> screen_window_area{0, 0, width, height}; |     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
 |     // 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); |     Common::Rectangle<u32> screen_rect = maxRectangle(screen_window_area, emulation_aspect_ratio); | ||||||
|     // Find sizes of top and bottom screen
 |     // Find sizes of top and bottom screen
 | ||||||
|     Common::Rectangle<u32> top_screen = maxRectangle(screen_rect, TOP_SCREEN_ASPECT_RATIO); |     Common::Rectangle<u32> top_screen = | ||||||
|     Common::Rectangle<u32> bot_screen = maxRectangle(screen_rect, BOT_SCREEN_ASPECT_RATIO); |         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) { |     if (window_aspect_ratio < emulation_aspect_ratio) { | ||||||
|         // Apply borders to the left and right sides of the window.
 |         // 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); |         top_screen = top_screen.TranslateY(shift_vertical); | ||||||
|         bot_screen = bot_screen.TranslateY(shift_vertical); |         bot_screen = bot_screen.TranslateY(shift_vertical); | ||||||
|     } |     } | ||||||
|     // Move the top screen to the right if we are swapped.
 |     if (upright) { | ||||||
|     res.top_screen = swapped ? top_screen.TranslateX(bot_screen.GetWidth()) : top_screen; |         // Leave the top screen at the top if we are swapped.
 | ||||||
|     res.bottom_screen = swapped ? bot_screen : bot_screen.TranslateX(top_screen.GetWidth()); |         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; |     return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -170,7 +270,7 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height) { | ||||||
|     ASSERT(width > 0); |     ASSERT(width > 0); | ||||||
|     ASSERT(height > 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{ |     Common::Rectangle<u32> top_screen{ | ||||||
|         Settings::values.custom_top_left, Settings::values.custom_top_top, |         Settings::values.custom_top_left, Settings::values.custom_top_top, | ||||||
|  | @ -194,35 +294,69 @@ FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) { | ||||||
|         int width, height; |         int width, height; | ||||||
|         switch (Settings::values.layout_option) { |         switch (Settings::values.layout_option) { | ||||||
|         case Settings::LayoutOption::SingleScreen: |         case Settings::LayoutOption::SingleScreen: | ||||||
|             if (Settings::values.swap_screen) { |             if (Settings::values.upright_screen) { | ||||||
|                 width = Core::kScreenBottomWidth * res_scale; |                 if (Settings::values.swap_screen) { | ||||||
|                 height = Core::kScreenBottomHeight * res_scale; |                     width = Core::kScreenBottomHeight * res_scale; | ||||||
|  |                     height = Core::kScreenBottomWidth * res_scale; | ||||||
|  |                 } else { | ||||||
|  |                     width = Core::kScreenTopHeight * res_scale; | ||||||
|  |                     height = Core::kScreenTopWidth * res_scale; | ||||||
|  |                 } | ||||||
|             } else { |             } else { | ||||||
|                 width = Core::kScreenTopWidth * res_scale; |                 if (Settings::values.swap_screen) { | ||||||
|                 height = Core::kScreenTopHeight * res_scale; |                     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; |             break; | ||||||
|         case Settings::LayoutOption::LargeScreen: |         case Settings::LayoutOption::LargeScreen: | ||||||
|             if (Settings::values.swap_screen) { |             if (Settings::values.upright_screen) { | ||||||
|                 width = (Core::kScreenBottomWidth + Core::kScreenTopWidth / 4) * res_scale; |                 if (Settings::values.swap_screen) { | ||||||
|                 height = Core::kScreenBottomHeight * res_scale; |                     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 { |             } else { | ||||||
|                 width = (Core::kScreenTopWidth + Core::kScreenBottomWidth / 4) * res_scale; |                 if (Settings::values.swap_screen) { | ||||||
|                 height = Core::kScreenTopHeight * res_scale; |                     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; |             break; | ||||||
|         case Settings::LayoutOption::SideScreen: |         case Settings::LayoutOption::SideScreen: | ||||||
|             width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale; |             if (Settings::values.upright_screen) { | ||||||
|             height = Core::kScreenTopHeight * res_scale; |                 width = Core::kScreenTopHeight * res_scale; | ||||||
|             layout = SideFrameLayout(width, height, Settings::values.swap_screen); |                 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; |             break; | ||||||
|         case Settings::LayoutOption::Default: |         case Settings::LayoutOption::Default: | ||||||
|         default: |         default: | ||||||
|             width = Core::kScreenTopWidth * res_scale; |             if (Settings::values.upright_screen) { | ||||||
|             height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; |                 width = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale; | ||||||
|             layout = DefaultFrameLayout(width, height, Settings::values.swap_screen); |                 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; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ struct FramebufferLayout { | ||||||
|     bool bottom_screen_enabled; |     bool bottom_screen_enabled; | ||||||
|     Common::Rectangle<u32> top_screen; |     Common::Rectangle<u32> top_screen; | ||||||
|     Common::Rectangle<u32> bottom_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 |      * 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 |  * @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 |  * @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 |  * 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) |  * @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 |  * @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 |  * 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 |  * @param is_swapped if true, the bottom screen will be the large display | ||||||
|  * @return Newly created FramebufferLayout object with default screen regions initialized |  * @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 |  * 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 |  * @param is_swapped if true, the bottom screen will be the left display | ||||||
|  * @return Newly created FramebufferLayout object with default screen regions initialized |  * @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 |  * Factory method for constructing a custom FramebufferLayout | ||||||
|  |  | ||||||
|  | @ -87,6 +87,7 @@ void LogSettings() { | ||||||
|     LogSetting("Stereoscopy_Factor3d", Settings::values.factor_3d); |     LogSetting("Stereoscopy_Factor3d", Settings::values.factor_3d); | ||||||
|     LogSetting("Layout_LayoutOption", static_cast<int>(Settings::values.layout_option)); |     LogSetting("Layout_LayoutOption", static_cast<int>(Settings::values.layout_option)); | ||||||
|     LogSetting("Layout_SwapScreen", Settings::values.swap_screen); |     LogSetting("Layout_SwapScreen", Settings::values.swap_screen); | ||||||
|  |     LogSetting("Layout_UprightScreen", Settings::values.upright_screen); | ||||||
|     LogSetting("Utility_DumpTextures", Settings::values.dump_textures); |     LogSetting("Utility_DumpTextures", Settings::values.dump_textures); | ||||||
|     LogSetting("Utility_CustomTextures", Settings::values.custom_textures); |     LogSetting("Utility_CustomTextures", Settings::values.custom_textures); | ||||||
|     LogSetting("Audio_EnableDspLle", Settings::values.enable_dsp_lle); |     LogSetting("Audio_EnableDspLle", Settings::values.enable_dsp_lle); | ||||||
|  |  | ||||||
|  | @ -150,6 +150,7 @@ struct Values { | ||||||
| 
 | 
 | ||||||
|     LayoutOption layout_option; |     LayoutOption layout_option; | ||||||
|     bool swap_screen; |     bool swap_screen; | ||||||
|  |     bool upright_screen; | ||||||
|     bool custom_layout; |     bool custom_layout; | ||||||
|     u16 custom_top_left; |     u16 custom_top_left; | ||||||
|     u16 custom_top_top; |     u16 custom_top_top; | ||||||
|  |  | ||||||
|  | @ -781,6 +781,35 @@ void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa | ||||||
|     state.Apply(); |     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 |  * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD | ||||||
|  * rotation. |  * rotation. | ||||||
|  | @ -819,6 +848,40 @@ void RendererOpenGL::DrawSingleScreenStereoRotated(const ScreenInfo& screen_info | ||||||
|     state.Apply(); |     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. |  * Draws the emulated screens to the emulator window. | ||||||
|  */ |  */ | ||||||
|  | @ -866,44 +929,85 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout) { | ||||||
| 
 | 
 | ||||||
|     glUniform1i(uniform_layer, 0); |     glUniform1i(uniform_layer, 0); | ||||||
|     if (layout.top_screen_enabled) { |     if (layout.top_screen_enabled) { | ||||||
|         if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { |         if (layout.is_rotated) { | ||||||
|             DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left, (float)top_screen.top, |             if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { | ||||||
|                                     (float)top_screen.GetWidth(), (float)top_screen.GetHeight()); |                 DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left, | ||||||
|         } else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { |                                         (float)top_screen.top, (float)top_screen.GetWidth(), | ||||||
|             DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left / 2, |                                         (float)top_screen.GetHeight()); | ||||||
|                                     (float)top_screen.top, (float)top_screen.GetWidth() / 2, |             } else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { | ||||||
|                                     (float)top_screen.GetHeight()); |                 DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left / 2, | ||||||
|             glUniform1i(uniform_layer, 1); |                                         (float)top_screen.top, (float)top_screen.GetWidth() / 2, | ||||||
|             DrawSingleScreenRotated(screen_infos[1], |                                         (float)top_screen.GetHeight()); | ||||||
|                                     ((float)top_screen.left / 2) + ((float)layout.width / 2), |                 glUniform1i(uniform_layer, 1); | ||||||
|                                     (float)top_screen.top, (float)top_screen.GetWidth() / 2, |                 DrawSingleScreenRotated(screen_infos[1], | ||||||
|                                     (float)top_screen.GetHeight()); |                                         ((float)top_screen.left / 2) + ((float)layout.width / 2), | ||||||
|         } else if (stereo_single_screen) { |                                         (float)top_screen.top, (float)top_screen.GetWidth() / 2, | ||||||
|             DrawSingleScreenStereoRotated(screen_infos[0], screen_infos[1], (float)top_screen.left, |                                         (float)top_screen.GetHeight()); | ||||||
|                                           (float)top_screen.top, (float)top_screen.GetWidth(), |             } else if (stereo_single_screen) { | ||||||
|                                           (float)top_screen.GetHeight()); |                 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); |     glUniform1i(uniform_layer, 0); | ||||||
|     if (layout.bottom_screen_enabled) { |     if (layout.bottom_screen_enabled) { | ||||||
|         if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { |         if (layout.is_rotated) { | ||||||
|             DrawSingleScreenRotated(screen_infos[2], (float)bottom_screen.left, |             if (Settings::values.render_3d == Settings::StereoRenderOption::Off) { | ||||||
|                                     (float)bottom_screen.top, (float)bottom_screen.GetWidth(), |                 DrawSingleScreenRotated(screen_infos[2], (float)bottom_screen.left, | ||||||
|                                     (float)bottom_screen.GetHeight()); |                                         (float)bottom_screen.top, (float)bottom_screen.GetWidth(), | ||||||
|         } else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { |                                         (float)bottom_screen.GetHeight()); | ||||||
|             DrawSingleScreenRotated(screen_infos[2], (float)bottom_screen.left / 2, |             } else if (Settings::values.render_3d == Settings::StereoRenderOption::SideBySide) { | ||||||
|                                     (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, |                 DrawSingleScreenRotated( | ||||||
|                                     (float)bottom_screen.GetHeight()); |                     screen_infos[2], (float)bottom_screen.left / 2, (float)bottom_screen.top, | ||||||
|             glUniform1i(uniform_layer, 1); |                     (float)bottom_screen.GetWidth() / 2, (float)bottom_screen.GetHeight()); | ||||||
|             DrawSingleScreenRotated(screen_infos[2], |                 glUniform1i(uniform_layer, 1); | ||||||
|                                     ((float)bottom_screen.left / 2) + ((float)layout.width / 2), |                 DrawSingleScreenRotated( | ||||||
|                                     (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, |                     screen_infos[2], ((float)bottom_screen.left / 2) + ((float)layout.width / 2), | ||||||
|                                     (float)bottom_screen.GetHeight()); |                     (float)bottom_screen.top, (float)bottom_screen.GetWidth() / 2, | ||||||
|         } else if (stereo_single_screen) { |                     (float)bottom_screen.GetHeight()); | ||||||
|             DrawSingleScreenStereoRotated(screen_infos[2], screen_infos[2], |             } else if (stereo_single_screen) { | ||||||
|                                           (float)bottom_screen.left, (float)bottom_screen.top, |                 DrawSingleScreenStereoRotated(screen_infos[2], screen_infos[2], | ||||||
|                                           (float)bottom_screen.GetWidth(), |                                               (float)bottom_screen.left, (float)bottom_screen.top, | ||||||
|                                           (float)bottom_screen.GetHeight()); |                                               (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); |                                      const GPU::Regs::FramebufferConfig& framebuffer); | ||||||
|     void DrawScreens(const Layout::FramebufferLayout& layout); |     void DrawScreens(const Layout::FramebufferLayout& layout); | ||||||
|     void DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y, float w, float h); |     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, |     void DrawSingleScreenStereoRotated(const ScreenInfo& screen_info_l, | ||||||
|                                        const ScreenInfo& screen_info_r, float x, float y, float w, |                                        const ScreenInfo& screen_info_r, float x, float y, float w, | ||||||
|                                        float h); |                                        float h); | ||||||
|  |     void DrawSingleScreenStereo(const ScreenInfo& screen_info_l, const ScreenInfo& screen_info_r, | ||||||
|  |                                 float x, float y, float w, float h); | ||||||
|     void UpdateFramerate(); |     void UpdateFramerate(); | ||||||
| 
 | 
 | ||||||
|     // Loads framebuffer from emulated memory into the display information structure
 |     // Loads framebuffer from emulated memory into the display information structure
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue