mirror of
https://github.com/Lime3DS/Lime3DS
synced 2024-12-27 01:22:37 -06:00
Signed-off-by: elim <e_sliwka@tuta.io>
This commit is contained in:
parent
2d6aca4563
commit
0d516f6da5
9 changed files with 124 additions and 0 deletions
|
@ -187,6 +187,7 @@ filter_mode =
|
||||||
# 2: Large Screen Small Screen
|
# 2: Large Screen Small Screen
|
||||||
# 3: Side by Side
|
# 3: Side by Side
|
||||||
# 4: Separate Windows
|
# 4: Separate Windows
|
||||||
|
# 5: Hybrid Screen
|
||||||
layout_option =
|
layout_option =
|
||||||
|
|
||||||
# Toggle custom layout (using the settings below) on or off.
|
# Toggle custom layout (using the settings below) on or off.
|
||||||
|
|
|
@ -368,6 +368,11 @@
|
||||||
<string>Separate Windows</string>
|
<string>Separate Windows</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Hybrid Screen</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
|
@ -387,6 +387,7 @@ void GMainWindow::InitializeWidgets() {
|
||||||
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Default);
|
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Default);
|
||||||
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Single_Screen);
|
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_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_Side_by_Side);
|
||||||
actionGroup_ScreenLayouts->addAction(ui->action_Screen_Layout_Separate_Windows);
|
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_Default, &GMainWindow::ChangeScreenLayout);
|
||||||
connect_menu(ui->action_Screen_Layout_Single_Screen, &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_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_Side_by_Side, &GMainWindow::ChangeScreenLayout);
|
||||||
connect_menu(ui->action_Screen_Layout_Separate_Windows, &GMainWindow::ChangeScreenLayout);
|
connect_menu(ui->action_Screen_Layout_Separate_Windows, &GMainWindow::ChangeScreenLayout);
|
||||||
connect_menu(ui->action_Screen_Layout_Swap_Screens, &GMainWindow::OnSwapScreens);
|
connect_menu(ui->action_Screen_Layout_Swap_Screens, &GMainWindow::OnSwapScreens);
|
||||||
|
@ -1883,6 +1885,8 @@ void GMainWindow::ChangeScreenLayout() {
|
||||||
new_layout = Settings::LayoutOption::SingleScreen;
|
new_layout = Settings::LayoutOption::SingleScreen;
|
||||||
} else if (ui->action_Screen_Layout_Large_Screen->isChecked()) {
|
} else if (ui->action_Screen_Layout_Large_Screen->isChecked()) {
|
||||||
new_layout = Settings::LayoutOption::LargeScreen;
|
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()) {
|
} else if (ui->action_Screen_Layout_Side_by_Side->isChecked()) {
|
||||||
new_layout = Settings::LayoutOption::SideScreen;
|
new_layout = Settings::LayoutOption::SideScreen;
|
||||||
} else if (ui->action_Screen_Layout_Separate_Windows->isChecked()) {
|
} else if (ui->action_Screen_Layout_Separate_Windows->isChecked()) {
|
||||||
|
@ -1902,6 +1906,8 @@ void GMainWindow::ToggleScreenLayout() {
|
||||||
case Settings::LayoutOption::SingleScreen:
|
case Settings::LayoutOption::SingleScreen:
|
||||||
return Settings::LayoutOption::LargeScreen;
|
return Settings::LayoutOption::LargeScreen;
|
||||||
case Settings::LayoutOption::LargeScreen:
|
case Settings::LayoutOption::LargeScreen:
|
||||||
|
return Settings::LayoutOption::HybridScreen;
|
||||||
|
case Settings::LayoutOption::HybridScreen:
|
||||||
return Settings::LayoutOption::SideScreen;
|
return Settings::LayoutOption::SideScreen;
|
||||||
case Settings::LayoutOption::SideScreen:
|
case Settings::LayoutOption::SideScreen:
|
||||||
return Settings::LayoutOption::SeparateWindows;
|
return Settings::LayoutOption::SeparateWindows;
|
||||||
|
@ -2774,6 +2780,8 @@ void GMainWindow::SyncMenuUISettings() {
|
||||||
Settings::LayoutOption::SingleScreen);
|
Settings::LayoutOption::SingleScreen);
|
||||||
ui->action_Screen_Layout_Large_Screen->setChecked(Settings::values.layout_option.GetValue() ==
|
ui->action_Screen_Layout_Large_Screen->setChecked(Settings::values.layout_option.GetValue() ==
|
||||||
Settings::LayoutOption::LargeScreen);
|
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() ==
|
ui->action_Screen_Layout_Side_by_Side->setChecked(Settings::values.layout_option.GetValue() ==
|
||||||
Settings::LayoutOption::SideScreen);
|
Settings::LayoutOption::SideScreen);
|
||||||
ui->action_Screen_Layout_Separate_Windows->setChecked(
|
ui->action_Screen_Layout_Separate_Windows->setChecked(
|
||||||
|
|
|
@ -134,6 +134,7 @@
|
||||||
<addaction name="action_Screen_Layout_Default"/>
|
<addaction name="action_Screen_Layout_Default"/>
|
||||||
<addaction name="action_Screen_Layout_Single_Screen"/>
|
<addaction name="action_Screen_Layout_Single_Screen"/>
|
||||||
<addaction name="action_Screen_Layout_Large_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_Side_by_Side"/>
|
||||||
<addaction name="action_Screen_Layout_Separate_Windows"/>
|
<addaction name="action_Screen_Layout_Separate_Windows"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
@ -504,6 +505,14 @@
|
||||||
<string>Large Screen</string>
|
<string>Large Screen</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</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">
|
<action name="action_Screen_Layout_Side_by_Side">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
|
|
|
@ -36,6 +36,7 @@ enum class LayoutOption : u32 {
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
SeparateWindows,
|
SeparateWindows,
|
||||||
#endif
|
#endif
|
||||||
|
HybridScreen,
|
||||||
// Similiar to default, but better for mobile devices in portrait mode. Top screen in clamped to
|
// 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.
|
// the top of the frame, and the bottom screen is enlarged to match the top screen.
|
||||||
MobilePortrait,
|
MobilePortrait,
|
||||||
|
|
|
@ -200,6 +200,11 @@ void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height,
|
||||||
Settings::values.upright_screen.GetValue(),
|
Settings::values.upright_screen.GetValue(),
|
||||||
Settings::values.large_screen_proportion.GetValue());
|
Settings::values.large_screen_proportion.GetValue());
|
||||||
break;
|
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:
|
case Settings::LayoutOption::SideScreen:
|
||||||
layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen.GetValue(),
|
layout = Layout::SideFrameLayout(width, height, Settings::values.swap_screen.GetValue(),
|
||||||
Settings::values.upright_screen.GetValue());
|
Settings::values.upright_screen.GetValue());
|
||||||
|
|
|
@ -299,6 +299,80 @@ FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool swapped, bool upr
|
||||||
return res;
|
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) {
|
FramebufferLayout SideFrameLayout(u32 width, u32 height, bool swapped, bool upright) {
|
||||||
ASSERT(width > 0);
|
ASSERT(width > 0);
|
||||||
ASSERT(height > 0);
|
ASSERT(height > 0);
|
||||||
|
|
|
@ -37,6 +37,9 @@ struct FramebufferLayout {
|
||||||
Common::Rectangle<u32> bottom_screen;
|
Common::Rectangle<u32> bottom_screen;
|
||||||
bool is_rotated = true;
|
bool is_rotated = true;
|
||||||
|
|
||||||
|
bool additional_screen_enabled;
|
||||||
|
Common::Rectangle<u32> additional_screen;
|
||||||
|
|
||||||
CardboardSettings cardboard;
|
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,
|
FramebufferLayout LargeFrameLayout(u32 width, u32 height, bool is_swapped, bool upright,
|
||||||
float scale_factor);
|
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
|
* 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();
|
ApplySecondLayerOpacity();
|
||||||
DrawTopScreen(layout, top_screen);
|
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();
|
ResetSecondLayerOpacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue