Signed-off-by: elim <e_sliwka@tuta.io>
This commit is contained in:
		@@ -187,6 +187,7 @@ filter_mode =
 | 
			
		||||
# 2: Large Screen Small Screen
 | 
			
		||||
# 3: Side by Side
 | 
			
		||||
# 4: Separate Windows
 | 
			
		||||
# 5: Hybrid Screen
 | 
			
		||||
layout_option =
 | 
			
		||||
 | 
			
		||||
# Toggle custom layout (using the settings below) on or off.
 | 
			
		||||
 
 | 
			
		||||
@@ -368,6 +368,11 @@
 | 
			
		||||
             <string>Separate Windows</string>
 | 
			
		||||
            </property>
 | 
			
		||||
           </item>
 | 
			
		||||
           <item>
 | 
			
		||||
            <property name="text">
 | 
			
		||||
             <string>Hybrid Screen</string>
 | 
			
		||||
            </property>
 | 
			
		||||
           </item>
 | 
			
		||||
          </widget>
 | 
			
		||||
         </item>
 | 
			
		||||
        </layout>
 | 
			
		||||
 
 | 
			
		||||
@@ -387,6 +387,7 @@ void GMainWindow::InitializeWidgets() {
 | 
			
		||||
    actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Default);
 | 
			
		||||
    actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Single_Screen);
 | 
			
		||||
    actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Large_Screen);
 | 
			
		||||
    actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Hybrid_Screen);
 | 
			
		||||
    actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Side_by_Side);
 | 
			
		||||
    actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Separate_Windows);
 | 
			
		||||
}
 | 
			
		||||
@@ -800,6 +801,7 @@ void GMainWindow::ConnectMenuEvents() {
 | 
			
		||||
    connect_menu(ui->action_Screen_Layout_Default, &GMainWindow::ChangeScreenLayout);
 | 
			
		||||
    connect_menu(ui->action_Screen_Layout_Single_Screen, &GMainWindow::ChangeScreenLayout);
 | 
			
		||||
    connect_menu(ui->action_Screen_Layout_Large_Screen, &GMainWindow::ChangeScreenLayout);
 | 
			
		||||
    connect_menu(ui->action_Screen_Layout_Hybrid_Screen, &GMainWindow::ChangeScreenLayout);
 | 
			
		||||
    connect_menu(ui->action_Screen_Layout_Side_by_Side, &GMainWindow::ChangeScreenLayout);
 | 
			
		||||
    connect_menu(ui->action_Screen_Layout_Separate_Windows, &GMainWindow::ChangeScreenLayout);
 | 
			
		||||
    connect_menu(ui->action_Screen_Layout_Swap_Screens, &GMainWindow::OnSwapScreens);
 | 
			
		||||
@@ -1883,6 +1885,8 @@ void GMainWindow::ChangeScreenLayout() {
 | 
			
		||||
        new_layout = Settings::LayoutOption::SingleScreen;
 | 
			
		||||
    } else if (ui->action_Screen_Layout_Large_Screen->isChecked()) {
 | 
			
		||||
        new_layout = Settings::LayoutOption::LargeScreen;
 | 
			
		||||
    } else if (ui->action_Screen_Layout_Hybrid_Screen->isChecked()) {
 | 
			
		||||
        new_layout = Settings::LayoutOption::HybridScreen;
 | 
			
		||||
    } else if (ui->action_Screen_Layout_Side_by_Side->isChecked()) {
 | 
			
		||||
        new_layout = Settings::LayoutOption::SideScreen;
 | 
			
		||||
    } else if (ui->action_Screen_Layout_Separate_Windows->isChecked()) {
 | 
			
		||||
@@ -1902,6 +1906,8 @@ void GMainWindow::ToggleScreenLayout() {
 | 
			
		||||
        case Settings::LayoutOption::SingleScreen:
 | 
			
		||||
            return Settings::LayoutOption::LargeScreen;
 | 
			
		||||
        case Settings::LayoutOption::LargeScreen:
 | 
			
		||||
            return Settings::LayoutOption::HybridScreen;
 | 
			
		||||
        case Settings::LayoutOption::HybridScreen:
 | 
			
		||||
            return Settings::LayoutOption::SideScreen;
 | 
			
		||||
        case Settings::LayoutOption::SideScreen:
 | 
			
		||||
            return Settings::LayoutOption::SeparateWindows;
 | 
			
		||||
@@ -2774,6 +2780,8 @@ void GMainWindow::SyncMenuUISettings() {
 | 
			
		||||
                                                       Settings::LayoutOption::SingleScreen);
 | 
			
		||||
    ui->action_Screen_Layout_Large_Screen->setChecked(Settings::values.layout_option.GetValue() ==
 | 
			
		||||
                                                      Settings::LayoutOption::LargeScreen);
 | 
			
		||||
    ui->action_Screen_Layout_Hybrid_Screen->setChecked(Settings::values.layout_option.GetValue() ==
 | 
			
		||||
                                                       Settings::LayoutOption::HybridScreen);
 | 
			
		||||
    ui->action_Screen_Layout_Side_by_Side->setChecked(Settings::values.layout_option.GetValue() ==
 | 
			
		||||
                                                      Settings::LayoutOption::SideScreen);
 | 
			
		||||
    ui->action_Screen_Layout_Separate_Windows->setChecked(
 | 
			
		||||
 
 | 
			
		||||
@@ -134,6 +134,7 @@
 | 
			
		||||
     <addaction name="action_Screen_Layout_Default"/>
 | 
			
		||||
     <addaction name="action_Screen_Layout_Single_Screen"/>
 | 
			
		||||
     <addaction name="action_Screen_Layout_Large_Screen"/>
 | 
			
		||||
     <addaction name="action_Screen_Layout_Hybrid_Screen"/>
 | 
			
		||||
     <addaction name="action_Screen_Layout_Side_by_Side"/>
 | 
			
		||||
     <addaction name="action_Screen_Layout_Separate_Windows"/>
 | 
			
		||||
     <addaction name="separator"/>
 | 
			
		||||
@@ -504,6 +505,14 @@
 | 
			
		||||
    <string>Large Screen</string>
 | 
			
		||||
   </property>
 | 
			
		||||
  </action>
 | 
			
		||||
  <action name="action_Screen_Layout_Hybrid_Screen">
 | 
			
		||||
   <property name="checkable">
 | 
			
		||||
    <bool>true</bool>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="text">
 | 
			
		||||
    <string>Hybrid Screen</string>
 | 
			
		||||
   </property>
 | 
			
		||||
  </action>
 | 
			
		||||
  <action name="action_Screen_Layout_Side_by_Side">
 | 
			
		||||
   <property name="checkable">
 | 
			
		||||
    <bool>true</bool>
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,7 @@ enum class LayoutOption : u32 {
 | 
			
		||||
#ifndef ANDROID
 | 
			
		||||
    SeparateWindows,
 | 
			
		||||
#endif
 | 
			
		||||
    HybridScreen,
 | 
			
		||||
    // Similiar to default, but better for mobile devices in portrait mode. Top screen in clamped to
 | 
			
		||||
    // the top of the frame, and the bottom screen is enlarged to match the top screen.
 | 
			
		||||
    MobilePortrait,
 | 
			
		||||
 
 | 
			
		||||
@@ -200,6 +200,11 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height,
 | 
			
		||||
                                         Settings::values.upright_screen.GetValue(),
 | 
			
		||||
                                         Settings::values.large_screen_proportion.GetValue());
 | 
			
		||||
            break;
 | 
			
		||||
        case Settings::LayoutOption::HybridScreen:
 | 
			
		||||
            layout =
 | 
			
		||||
                Layout::HybridScreenLayout(width, height, Settings::values.swap_screen.GetValue(),
 | 
			
		||||
                                           Settings::values.upright_screen.GetValue());
 | 
			
		||||
            break;
 | 
			
		||||
        case Settings::LayoutOption::SideScreen:
 | 
			
		||||
            layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen.GetValue(),
 | 
			
		||||
                                             Settings::values.upright_screen.GetValue());
 | 
			
		||||
 
 | 
			
		||||
@@ -299,6 +299,80 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FramebufferLayout HybridScreenLayout(u32 width, u32 height, bool swapped, bool upright) {
 | 
			
		||||
    ASSERT(width > 0);
 | 
			
		||||
    ASSERT(height > 0);
 | 
			
		||||
 | 
			
		||||
    FramebufferLayout res{width, height, true, true, {}, {}, !upright, true, {}};
 | 
			
		||||
 | 
			
		||||
    // Split the window into two parts. Give 2.25x width to the main screen,
 | 
			
		||||
    // and make a bar on the right side with 1x width top screen and 1.25x width bottom screen
 | 
			
		||||
    // To do that, find the total emulation box and maximize that based on window size
 | 
			
		||||
    const float window_aspect_ratio = static_cast<float>(height) / width;
 | 
			
		||||
    const float scale_factor = 2.25f;
 | 
			
		||||
 | 
			
		||||
    float main_screen_aspect_ratio = TOP_SCREEN_ASPECT_RATIO;
 | 
			
		||||
    float hybrid_area_aspect_ratio = 27.f / 65;
 | 
			
		||||
    float top_screen_aspect_ratio = TOP_SCREEN_ASPECT_RATIO;
 | 
			
		||||
    float bot_screen_aspect_ratio = BOT_SCREEN_ASPECT_RATIO;
 | 
			
		||||
 | 
			
		||||
    if (swapped) {
 | 
			
		||||
        main_screen_aspect_ratio = BOT_SCREEN_ASPECT_RATIO;
 | 
			
		||||
        hybrid_area_aspect_ratio =
 | 
			
		||||
            Core::kScreenBottomHeight * scale_factor /
 | 
			
		||||
            (Core::kScreenBottomWidth * scale_factor + Core::kScreenTopWidth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (upright) {
 | 
			
		||||
        hybrid_area_aspect_ratio = 1.f / hybrid_area_aspect_ratio;
 | 
			
		||||
        main_screen_aspect_ratio = 1.f / main_screen_aspect_ratio;
 | 
			
		||||
        top_screen_aspect_ratio = TOP_SCREEN_UPRIGHT_ASPECT_RATIO;
 | 
			
		||||
        bot_screen_aspect_ratio = BOT_SCREEN_UPRIGHT_ASPECT_RATIO;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Common::Rectangle<u32> screen_window_area{0, 0, width, height};
 | 
			
		||||
    Common::Rectangle<u32> total_rect = maxRectangle(screen_window_area, hybrid_area_aspect_ratio);
 | 
			
		||||
    Common::Rectangle<u32> large_main_screen = maxRectangle(total_rect, main_screen_aspect_ratio);
 | 
			
		||||
    Common::Rectangle<u32> side_rect = total_rect.Scale(1.f / scale_factor);
 | 
			
		||||
    Common::Rectangle<u32> small_top_screen = maxRectangle(side_rect, top_screen_aspect_ratio);
 | 
			
		||||
    Common::Rectangle<u32> small_bottom_screen = maxRectangle(side_rect, bot_screen_aspect_ratio);
 | 
			
		||||
 | 
			
		||||
    if (window_aspect_ratio < hybrid_area_aspect_ratio) {
 | 
			
		||||
        large_main_screen = large_main_screen.TranslateX((width - total_rect.GetWidth()) / 2);
 | 
			
		||||
    } else {
 | 
			
		||||
        large_main_screen = large_main_screen.TranslateY((height - total_rect.GetHeight()) / 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Scale the bottom screen so it's width is the same as top screen
 | 
			
		||||
    small_bottom_screen = small_bottom_screen.Scale(1.25f);
 | 
			
		||||
    if (upright) {
 | 
			
		||||
        large_main_screen = large_main_screen.TranslateY(small_bottom_screen.GetHeight());
 | 
			
		||||
        // Shift small bottom screen to upper right corner
 | 
			
		||||
        small_bottom_screen =
 | 
			
		||||
            small_bottom_screen.TranslateX(large_main_screen.right - small_bottom_screen.GetWidth())
 | 
			
		||||
                .TranslateY(large_main_screen.top - small_bottom_screen.GetHeight());
 | 
			
		||||
 | 
			
		||||
        // Shift small top screen to upper left corner
 | 
			
		||||
        small_top_screen = small_top_screen.TranslateX(large_main_screen.left)
 | 
			
		||||
                               .TranslateY(large_main_screen.top - small_bottom_screen.GetHeight());
 | 
			
		||||
    } else {
 | 
			
		||||
        // Shift the small bottom screen to the bottom right corner
 | 
			
		||||
        small_bottom_screen =
 | 
			
		||||
            small_bottom_screen.TranslateX(large_main_screen.right)
 | 
			
		||||
                .TranslateY(large_main_screen.GetHeight() + large_main_screen.top -
 | 
			
		||||
                            small_bottom_screen.GetHeight());
 | 
			
		||||
 | 
			
		||||
        // Shift small top screen to upper right corner
 | 
			
		||||
        small_top_screen =
 | 
			
		||||
            small_top_screen.TranslateX(large_main_screen.right).TranslateY(large_main_screen.top);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    res.top_screen = small_top_screen;
 | 
			
		||||
    res.additional_screen = swapped ? small_bottom_screen : large_main_screen;
 | 
			
		||||
    res.bottom_screen = swapped ? large_main_screen : small_bottom_screen;
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FramebufferLayout SideFrameLayout(u32 width, u32 height, bool swapped, bool upright) {
 | 
			
		||||
    ASSERT(width > 0);
 | 
			
		||||
    ASSERT(height > 0);
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,9 @@ struct FramebufferLayout {
 | 
			
		||||
    Common::Rectangle<u32> bottom_screen;
 | 
			
		||||
    bool is_rotated = true;
 | 
			
		||||
 | 
			
		||||
    bool additional_screen_enabled;
 | 
			
		||||
    Common::Rectangle<u32> additional_screen;
 | 
			
		||||
 | 
			
		||||
    CardboardSettings cardboard;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -99,6 +102,15 @@ FramebufferLayout SingleFrameLayout(u32 width, u32 height, bool is_swapped, bool
 | 
			
		||||
 */
 | 
			
		||||
FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool is_swapped, bool upright,
 | 
			
		||||
                                   float scale_factor);
 | 
			
		||||
/**
 | 
			
		||||
 * Factory method for constructing a frame with 2.5 times bigger top screen on the right,
 | 
			
		||||
 * and 1x top and bottom screen on the left
 | 
			
		||||
 * @param width Window framebuffer width in pixels
 | 
			
		||||
 * @param height Window framebuffer height in pixels
 | 
			
		||||
 * @param is_swapped if true, the bottom screen will be the large display
 | 
			
		||||
 * @return Newly created FramebufferLayout object with default screen regions initialized
 | 
			
		||||
 */
 | 
			
		||||
FramebufferLayout HybridScreenLayout(u32 width, u32 height, bool swapped, bool upright);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Factory method for constructing a Frame with the Top screen and bottom
 | 
			
		||||
 
 | 
			
		||||
@@ -942,6 +942,15 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
 | 
			
		||||
        ApplySecondLayerOpacity();
 | 
			
		||||
        DrawTopScreen(layout, top_screen);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (layout.additional_screen_enabled) {
 | 
			
		||||
        const auto& additional_screen = layout.additional_screen;
 | 
			
		||||
        if (!Settings::values.swap_screen.GetValue()) {
 | 
			
		||||
            DrawTopScreen(layout, additional_screen);
 | 
			
		||||
        } else {
 | 
			
		||||
            DrawBottomScreen(layout, additional_screen);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    ResetSecondLayerOpacity();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user