diff --git a/README.md b/README.md index 91607f4ef..bf0634b0b 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 3816. +This is the source code for early-access 3817. ## Legal Notice diff --git a/src/common/settings.cpp b/src/common/settings.cpp index cad7f00b0..6af15298b 100755 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -211,9 +211,7 @@ const char* TranslateCategory(Category category) { return "Miscellaneous"; } -void UpdateRescalingInfo() { - const auto setup = values.resolution_setup.GetValue(); - auto& info = values.resolution_info; +void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info) { info.downscale = false; switch (setup) { case ResolutionSetup::Res1_2X: @@ -273,6 +271,12 @@ void UpdateRescalingInfo() { info.active = info.up_scale != 1 || info.down_shift != 0; } +void UpdateRescalingInfo() { + const auto setup = values.resolution_setup.GetValue(); + auto& info = values.resolution_info; + TranslateResolutionInfo(setup, info); +} + void RestoreGlobalState(bool is_powered_on) { // If a game is running, DO NOT restore the global settings state if (is_powered_on) { diff --git a/src/common/settings.h b/src/common/settings.h index e28cb46d3..6f37304f4 100755 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -527,6 +527,7 @@ std::string GetTimeZoneString(TimeZone time_zone); void LogSettings(); +void TranslateResolutionInfo(ResolutionSetup setup, ResolutionScalingInfo& info); void UpdateRescalingInfo(); // Restore the global state of all applicable settings in the Values struct diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 6c3460ea2..b8c431b4c 100755 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -11,6 +11,8 @@ #include #include +#include "common/settings_enums.h" +#include "uisettings.h" #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA #include #include @@ -916,7 +918,6 @@ void GRenderWindow::ReleaseRenderTarget() { void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) { auto& renderer = system.Renderer(); - const f32 res_scale = Settings::values.resolution_info.up_factor; if (renderer.IsScreenshotPending()) { LOG_WARNING(Render, @@ -924,7 +925,18 @@ void GRenderWindow::CaptureScreenshot(const QString& screenshot_path) { return; } - const Layout::FramebufferLayout layout{Layout::FrameLayoutFromResolutionScale(res_scale)}; + const Layout::FramebufferLayout layout{[]() { + u32 height = UISettings::values.screenshot_height.GetValue(); + if (height == 0) { + height = Settings::values.use_docked_mode.GetValue() ? Layout::ScreenDocked::Height + : Layout::ScreenUndocked::Height; + height *= Settings::values.resolution_info.up_factor; + } + const u32 width = + UISettings::CalculateWidth(height, Settings::values.aspect_ratio.GetValue()); + return Layout::DefaultFrameLayout(width, height); + }()}; + screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); renderer.RequestScreenshot( screenshot_image.bits(), diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 8ac907bd6..7a794aba8 100755 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -592,8 +592,7 @@ void Config::ReadRendererValues() { void Config::ReadScreenshotValues() { qt_config->beginGroup(QStringLiteral("Screenshots")); - UISettings::values.enable_screenshot_save_as = - ReadSetting(QStringLiteral("enable_screenshot_save_as"), true).toBool(); + ReadCategory(Settings::Category::Screenshots); FS::SetYuzuPath( FS::YuzuPath::ScreenshotsDir, qt_config diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index b89f3c3a0..56a7316e6 100755 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -4,6 +4,7 @@ #include #include "common/logging/log.h" #include "common/settings.h" +#include "common/settings_enums.h" #include "core/core.h" #include "ui_configure.h" #include "vk_device_info.h" @@ -41,16 +42,19 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, general_tab{std::make_unique(system_, nullptr, *builder, this)}, graphics_advanced_tab{ std::make_unique(system_, nullptr, *builder, this)}, + ui_tab{std::make_unique(system_, this)}, graphics_tab{std::make_unique( system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, + [this](Settings::AspectRatio ratio, Settings::ResolutionSetup setup) { + ui_tab->UpdateScreenshotInfo(ratio, setup); + }, nullptr, *builder, this)}, hotkeys_tab{std::make_unique(system_.HIDCore(), this)}, input_tab{std::make_unique(system_, this)}, network_tab{std::make_unique(system_, this)}, profile_tab{std::make_unique(system_, this)}, system_tab{std::make_unique(system_, nullptr, *builder, this)}, - ui_tab{std::make_unique(system_, this)}, web_tab{std::make_unique( - this)} { + web_tab{std::make_unique(this)} { Settings::SetConfiguringGlobal(true); ui->setupUi(this); diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index fbf9306c0..8f56c9bca 100755 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h @@ -81,12 +81,12 @@ private: std::unique_ptr filesystem_tab; std::unique_ptr general_tab; std::unique_ptr graphics_advanced_tab; + std::unique_ptr ui_tab; std::unique_ptr graphics_tab; std::unique_ptr hotkeys_tab; std::unique_ptr input_tab; std::unique_ptr network_tab; std::unique_ptr profile_tab; std::unique_ptr system_tab; - std::unique_ptr ui_tab; std::unique_ptr web_tab; }; diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index a3f8a88ce..7e36b7615 100755 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -77,13 +78,16 @@ static constexpr Settings::VSyncMode PresentModeToSetting(VkPresentModeKHR mode) } } -ConfigureGraphics::ConfigureGraphics(const Core::System& system_, - std::vector& records_, - const std::function& expose_compute_option_, - std::shared_ptr> group_, - const ConfigurationShared::Builder& builder, QWidget* parent) +ConfigureGraphics::ConfigureGraphics( + const Core::System& system_, std::vector& records_, + const std::function& expose_compute_option_, + const std::function& + update_aspect_ratio_, + std::shared_ptr> group_, + const ConfigurationShared::Builder& builder, QWidget* parent) : ConfigurationShared::Tab(group_, parent), ui{std::make_unique()}, - records{records_}, expose_compute_option{expose_compute_option_}, system{system_}, + records{records_}, expose_compute_option{expose_compute_option_}, + update_aspect_ratio{update_aspect_ratio_}, system{system_}, combobox_translations{builder.ComboboxTranslations()}, shader_mapping{ combobox_translations.at(Settings::EnumMetadata::Index())} { @@ -140,6 +144,26 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, UpdateBackgroundColorButton(new_bg_color); }); + const auto& update_screenshot_info = [this, &builder]() { + const auto& combobox_enumerations = builder.ComboboxTranslations().at( + Settings::EnumMetadata::Index()); + const auto index = aspect_ratio_combobox->currentIndex(); + const auto ratio = static_cast(combobox_enumerations[index].first); + + const auto& combobox_enumerations_resolution = builder.ComboboxTranslations().at( + Settings::EnumMetadata::Index()); + const auto res_index = resolution_combobox->currentIndex(); + const auto setup = static_cast( + combobox_enumerations_resolution[res_index].first); + + update_aspect_ratio(ratio, setup); + }; + + connect(aspect_ratio_combobox, QOverload::of(&QComboBox::currentIndexChanged), + update_screenshot_info); + connect(resolution_combobox, QOverload::of(&QComboBox::currentIndexChanged), + update_screenshot_info); + api_combobox->setEnabled(!UISettings::values.has_broken_vulkan && api_combobox->isEnabled()); ui->api_widget->setEnabled( (!UISettings::values.has_broken_vulkan || Settings::IsConfiguringGlobal()) && @@ -280,6 +304,14 @@ void ConfigureGraphics::Setup(const ConfigurationShared::Builder& builder) { // Keep track of vsync_mode's combobox so we can populate it vsync_mode_combobox = widget->combobox; hold_graphics.emplace(setting->Id(), widget); + } else if (setting->Id() == Settings::values.aspect_ratio.Id()) { + // Keep track of the aspect ratio combobox to update other UI tabs that need it + aspect_ratio_combobox = widget->combobox; + hold_graphics.emplace(setting->Id(), widget); + } else if (setting->Id() == Settings::values.resolution_setup.Id()) { + // Keep track of the resolution combobox to update other UI tabs that need it + resolution_combobox = widget->combobox; + hold_graphics.emplace(setting->Id(), widget); } else { hold_graphics.emplace(setting->Id(), widget); } diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 5c85321f8..d28ade2b1 100755 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -14,6 +14,7 @@ #include #include #include "common/common_types.h" +#include "common/settings_enums.h" #include "configuration/shared_translation.h" #include "vk_device_info.h" #include "yuzu/configuration/configuration_shared.h" @@ -43,12 +44,13 @@ class Builder; class ConfigureGraphics : public ConfigurationShared::Tab { public: - explicit ConfigureGraphics(const Core::System& system_, - std::vector& records, - const std::function& expose_compute_option_, - std::shared_ptr> group, - const ConfigurationShared::Builder& builder, - QWidget* parent = nullptr); + explicit ConfigureGraphics( + const Core::System& system_, std::vector& records, + const std::function& expose_compute_option, + const std::function& + update_aspect_ratio, + std::shared_ptr> group, + const ConfigurationShared::Builder& builder, QWidget* parent = nullptr); ~ConfigureGraphics() override; void ApplyConfiguration() override; @@ -91,6 +93,7 @@ private: u32 vulkan_device{}; Settings::ShaderBackend shader_backend{}; const std::function& expose_compute_option; + const std::function update_aspect_ratio; const Core::System& system; const ConfigurationShared::ComboboxTranslationMap& combobox_translations; @@ -104,4 +107,6 @@ private: QWidget* vulkan_device_widget; QWidget* api_widget; QWidget* shader_backend_widget; + QComboBox* aspect_ratio_combobox; + QComboBox* resolution_combobox; }; diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 7d2cc5dc0..33cf9b0ed 100755 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -17,6 +17,7 @@ #include #include "common/fs/fs_util.h" +#include "common/settings_enums.h" #include "configuration/shared_widget.h" #include "core/core.h" #include "core/file_sys/control_metadata.h" @@ -57,7 +58,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st std::make_unique(system_, tab_group, *builder, this); graphics_tab = std::make_unique( system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, - tab_group, *builder, this); + [](Settings::AspectRatio, Settings::ResolutionSetup) {}, tab_group, *builder, this); input_tab = std::make_unique(system_, game_config.get(), this); system_tab = std::make_unique(system_, tab_group, *builder, this); diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 9c1add3d1..01dd069ac 100755 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -1,18 +1,31 @@ // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include -#include -#include +#include "yuzu/configuration/configure_ui.h" +#include +#include +#include +#include +#include + +#include +#include +#include #include +#include +#include +#include +#include + #include "common/common_types.h" #include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/settings.h" +#include "common/settings_enums.h" #include "core/core.h" +#include "core/frontend/framebuffer_layout.h" #include "ui_configure_ui.h" -#include "yuzu/configuration/configure_ui.h" #include "yuzu/uisettings.h" namespace { @@ -54,8 +67,44 @@ QString GetTranslatedRowTextName(size_t index) { } } // Anonymous namespace +static float GetUpFactor(Settings::ResolutionSetup res_setup) { + Settings::ResolutionScalingInfo info{}; + Settings::TranslateResolutionInfo(res_setup, info); + return info.up_factor; +} + +static void PopulateResolutionComboBox(QComboBox* screenshot_height, QWidget* parent) { + screenshot_height->clear(); + + const auto& enumeration = + Settings::EnumMetadata::Canonicalizations(); + std::set resolutions{}; + for (const auto& [name, value] : enumeration) { + const float up_factor = GetUpFactor(value); + u32 height_undocked = Layout::ScreenUndocked::Height * up_factor; + u32 height_docked = Layout::ScreenDocked::Height * up_factor; + resolutions.emplace(height_undocked); + resolutions.emplace(height_docked); + } + + screenshot_height->addItem(parent->tr("Auto", "Screenshot height option")); + for (const auto res : resolutions) { + screenshot_height->addItem(QString::fromStdString(std::to_string(res))); + } +} + +static u32 ScreenshotDimensionToInt(const QString& height) { + try { + return std::stoi(height.toStdString()); + } catch (std::invalid_argument&) { + return 0; + } +} + ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent) - : QWidget(parent), ui{std::make_unique()}, system{system_} { + : QWidget(parent), ui{std::make_unique()}, + ratio{Settings::values.aspect_ratio.GetValue()}, + resolution_setting{Settings::values.resolution_setup.GetValue()}, system{system_} { ui->setupUi(this); InitializeLanguageComboBox(); @@ -68,6 +117,8 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent) InitializeIconSizeComboBox(); InitializeRowComboBoxes(); + PopulateResolutionComboBox(ui->screenshot_height, this); + SetConfiguration(); // Force game list reload if any of the relevant settings are changed. @@ -104,6 +155,10 @@ ConfigureUi::ConfigureUi(Core::System& system_, QWidget* parent) ui->screenshot_path_edit->setText(dir); } }); + + connect(ui->screenshot_height, &QComboBox::currentTextChanged, [this]() { UpdateWidthText(); }); + + UpdateWidthText(); } ConfigureUi::~ConfigureUi() = default; @@ -123,6 +178,10 @@ void ConfigureUi::ApplyConfiguration() { UISettings::values.enable_screenshot_save_as = ui->enable_screenshot_save_as->isChecked(); Common::FS::SetYuzuPath(Common::FS::YuzuPath::ScreenshotsDir, ui->screenshot_path_edit->text().toStdString()); + + const u32 height = ScreenshotDimensionToInt(ui->screenshot_height->currentText()); + UISettings::values.screenshot_height.SetValue(height); + system.ApplySettings(); } @@ -147,6 +206,13 @@ void ConfigureUi::SetConfiguration() { UISettings::values.enable_screenshot_save_as.GetValue()); ui->screenshot_path_edit->setText(QString::fromStdString( Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir))); + + const auto height = UISettings::values.screenshot_height.GetValue(); + if (height == 0) { + ui->screenshot_height->setCurrentIndex(0); + } else { + ui->screenshot_height->setCurrentText(QStringLiteral("%1").arg(height)); + } } void ConfigureUi::changeEvent(QEvent* event) { @@ -317,3 +383,29 @@ void ConfigureUi::OnLanguageChanged(int index) { emit LanguageChanged(ui->language_combobox->itemData(index).toString()); } + +void ConfigureUi::UpdateWidthText() { + const u32 height = ScreenshotDimensionToInt(ui->screenshot_height->currentText()); + const u32 width = UISettings::CalculateWidth(height, ratio); + if (height == 0) { + const auto up_factor = GetUpFactor(resolution_setting); + const u32 height_docked = Layout::ScreenDocked::Height * up_factor; + const u32 width_docked = UISettings::CalculateWidth(height_docked, ratio); + const u32 height_undocked = Layout::ScreenUndocked::Height * up_factor; + const u32 width_undocked = UISettings::CalculateWidth(height_undocked, ratio); + ui->screenshot_width->setText(tr("Auto (%1 x %2, %3 x %4)", "Screenshot width value") + .arg(width_undocked) + .arg(height_undocked) + .arg(width_docked) + .arg(height_docked)); + } else { + ui->screenshot_width->setText(QStringLiteral("%1 x").arg(width)); + } +} + +void ConfigureUi::UpdateScreenshotInfo(Settings::AspectRatio ratio_, + Settings::ResolutionSetup resolution_setting_) { + ratio = ratio_; + resolution_setting = resolution_setting_; + UpdateWidthText(); +} diff --git a/src/yuzu/configuration/configure_ui.h b/src/yuzu/configuration/configure_ui.h index 83643f9b7..31fee0830 100755 --- a/src/yuzu/configuration/configure_ui.h +++ b/src/yuzu/configuration/configure_ui.h @@ -5,6 +5,7 @@ #include #include +#include "common/settings_enums.h" namespace Core { class System; @@ -23,6 +24,9 @@ public: void ApplyConfiguration(); + void UpdateScreenshotInfo(Settings::AspectRatio ratio, + Settings::ResolutionSetup resolution_info); + private slots: void OnLanguageChanged(int index); @@ -44,7 +48,11 @@ private: void UpdateFirstRowComboBox(bool init = false); void UpdateSecondRowComboBox(bool init = false); + void UpdateWidthText(); + std::unique_ptr ui; + Settings::AspectRatio ratio; + Settings::ResolutionSetup resolution_setting; Core::System& system; }; diff --git a/src/yuzu/configuration/configure_ui.ui b/src/yuzu/configuration/configure_ui.ui index cb5658c17..05254f2c6 100755 --- a/src/yuzu/configuration/configure_ui.ui +++ b/src/yuzu/configuration/configure_ui.ui @@ -7,7 +7,7 @@ 0 0 363 - 562 + 603 @@ -201,6 +201,41 @@ + + + + 6 + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + + + + + + + Resolution: + + + + + diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp index 5add200d1..b89f291d4 100755 --- a/src/yuzu/uisettings.cpp +++ b/src/yuzu/uisettings.cpp @@ -36,4 +36,20 @@ bool IsDarkTheme() { Values values = {}; +u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) { + switch (ratio) { + case Settings::AspectRatio::R4_3: + return height * 4 / 3; + case Settings::AspectRatio::R21_9: + return height * 21 / 9; + case Settings::AspectRatio::R16_10: + return height * 16 / 10; + case Settings::AspectRatio::R16_9: + case Settings::AspectRatio::Stretch: + // TODO: Move this function wherever appropriate to implement Stretched aspect + break; + } + return height * 16 / 9; +} + } // namespace UISettings diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index ee1b17abb..9e2e6ac61 100755 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -13,6 +13,7 @@ #include #include "common/common_types.h" #include "common/settings.h" +#include "common/settings_enums.h" using Settings::Category; using Settings::Setting; @@ -127,8 +128,10 @@ struct Values { // logging Setting show_console{linkage, false, "showConsole", Category::Ui}; + // Screenshots Setting enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as", Category::Screenshots}; + Setting screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots}; QString roms_path; QString symbols_path; @@ -187,6 +190,8 @@ struct Values { extern Values values; +u32 CalculateWidth(u32 height, Settings::AspectRatio ratio); + } // namespace UISettings Q_DECLARE_METATYPE(UISettings::GameDir*);