From c9cefe402073de94cd69f7a5cf6adb4043d56d9c Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Wed, 2 Sep 2020 00:00:48 +1000 Subject: [PATCH] GameSettings: Add a bunch more user settings --- README.md | 1 + src/duckstation-qt/gamepropertiesdialog.cpp | 148 +++++++++++++-- src/duckstation-qt/gamepropertiesdialog.h | 2 + src/duckstation-qt/gamepropertiesdialog.ui | 200 ++++++++++++++++++-- src/duckstation-qt/gpusettingswidget.cpp | 69 +++---- src/duckstation-qt/qtutils.cpp | 23 +++ src/duckstation-qt/qtutils.h | 4 + src/frontend-common/game_list.h | 2 +- src/frontend-common/game_settings.cpp | 151 ++++++++++++++- src/frontend-common/game_settings.h | 14 +- 10 files changed, 531 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index 56e4bd7cf..db538a896 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ A "BIOS" ROM image is required to to start the emulator and to play games. You c ## Latest News +- 2020/09/01: Many additional user settings available, including memory cards and enhancements. Now you can set these per-game. - 2020/08/25: Automated builds for macOS now available. - 2020/08/22: XInput controller backend added. - 2020/08/20: Per-game setting overrides added. Mostly for compatibility, but some options are customizable. diff --git a/src/duckstation-qt/gamepropertiesdialog.cpp b/src/duckstation-qt/gamepropertiesdialog.cpp index 1564b54ca..b595ac76a 100644 --- a/src/duckstation-qt/gamepropertiesdialog.cpp +++ b/src/duckstation-qt/gamepropertiesdialog.cpp @@ -9,9 +9,13 @@ #include "scmversion/scmversion.h" #include #include +#include #include #include +static constexpr char MEMORY_CARD_IMAGE_FILTER[] = + QT_TRANSLATE_NOOP("MemoryCardSettingsWidget", "All Memory Card Types (*.mcd *.mcr *.mc)"); + GamePropertiesDialog::GamePropertiesDialog(QtHostInterface* host_interface, QWidget* parent /* = nullptr */) : QDialog(parent), m_host_interface(host_interface) { @@ -127,13 +131,15 @@ void GamePropertiesDialog::setupAdditionalUi() qApp->translate("DisplayCropMode", Settings::GetDisplayCropModeDisplayName(static_cast(i)))); } + m_ui.userResolutionScale->addItem(tr("(unchanged)")); + QtUtils::FillComboBoxWithResolutionScales(m_ui.userResolutionScale); + m_ui.userControllerType1->addItem(tr("(unchanged)")); for (u32 i = 0; i < static_cast(ControllerType::Count); i++) { m_ui.userControllerType1->addItem( qApp->translate("ControllerType", Settings::GetControllerTypeDisplayName(static_cast(i)))); } - m_ui.userControllerType2->addItem(tr("(unchanged)")); for (u32 i = 0; i < static_cast(ControllerType::Count); i++) { @@ -141,6 +147,19 @@ void GamePropertiesDialog::setupAdditionalUi() qApp->translate("ControllerType", Settings::GetControllerTypeDisplayName(static_cast(i)))); } + m_ui.userMemoryCard1Type->addItem(tr("(unchanged)")); + for (u32 i = 0; i < static_cast(MemoryCardType::Count); i++) + { + m_ui.userMemoryCard1Type->addItem( + qApp->translate("MemoryCardType", Settings::GetMemoryCardTypeDisplayName(static_cast(i)))); + } + m_ui.userMemoryCard2Type->addItem(tr("(unchanged)")); + for (u32 i = 0; i < static_cast(MemoryCardType::Count); i++) + { + m_ui.userMemoryCard2Type->addItem( + qApp->translate("MemoryCardType", Settings::GetMemoryCardTypeDisplayName(static_cast(i)))); + } + QGridLayout* traits_layout = new QGridLayout(m_ui.compatibilityTraits); for (u32 i = 0; i < static_cast(GameSettings::Trait::Count); i++) { @@ -198,6 +217,26 @@ void GamePropertiesDialog::populateTracksInfo(const std::string& image_path) } } +void GamePropertiesDialog::populateBooleanUserSetting(QCheckBox* cb, const std::optional& value) +{ + QSignalBlocker sb(cb); + if (value.has_value()) + cb->setCheckState(value.value() ? Qt::Checked : Qt::Unchecked); + else + cb->setCheckState(Qt::PartiallyChecked); +} + +void GamePropertiesDialog::connectBooleanUserSetting(QCheckBox* cb, std::optional* value) +{ + connect(cb, &QCheckBox::stateChanged, [this, value](int state) { + if (state == Qt::PartiallyChecked) + value->reset(); + else + *value = (state == Qt::Checked); + saveGameSettings(); + }); +} + void GamePropertiesDialog::populateGameSettings() { const GameSettings::Entry& gs = m_game_settings; @@ -230,6 +269,27 @@ void GamePropertiesDialog::populateGameSettings() m_ui.userAspectRatio->setCurrentIndex(static_cast(gs.display_aspect_ratio.value()) + 1); } + populateBooleanUserSetting(m_ui.userLinearUpscaling, gs.display_linear_upscaling); + populateBooleanUserSetting(m_ui.userIntegerUpscaling, gs.display_integer_upscaling); + + if (gs.gpu_resolution_scale.has_value()) + { + QSignalBlocker sb(m_ui.userResolutionScale); + m_ui.userResolutionScale->setCurrentIndex(static_cast(gs.gpu_resolution_scale.value()) + 1); + } + else + { + QSignalBlocker sb(m_ui.userResolutionScale); + m_ui.userResolutionScale->setCurrentIndex(0); + } + + populateBooleanUserSetting(m_ui.userTrueColor, gs.gpu_true_color); + populateBooleanUserSetting(m_ui.userScaledDithering, gs.gpu_scaled_dithering); + populateBooleanUserSetting(m_ui.userBilinearTextureFiltering, gs.gpu_bilinear_texture_filtering); + populateBooleanUserSetting(m_ui.userForceNTSCTimings, gs.gpu_force_ntsc_timings); + populateBooleanUserSetting(m_ui.userWidescreenHack, gs.gpu_widescreen_hack); + populateBooleanUserSetting(m_ui.userPGXP, gs.gpu_pgxp); + if (gs.controller_1_type.has_value()) { QSignalBlocker sb(m_ui.userControllerType1); @@ -240,15 +300,26 @@ void GamePropertiesDialog::populateGameSettings() QSignalBlocker sb(m_ui.userControllerType2); m_ui.userControllerType2->setCurrentIndex(static_cast(gs.controller_2_type.value()) + 1); } - if (gs.gpu_widescreen_hack.has_value()) + + if (gs.memory_card_1_type.has_value()) { - QSignalBlocker sb(m_ui.userWidescreenHack); - m_ui.userWidescreenHack->setCheckState(gs.gpu_widescreen_hack.value() ? Qt::Checked : Qt::Unchecked); + QSignalBlocker sb(m_ui.userMemoryCard1Type); + m_ui.userMemoryCard1Type->setCurrentIndex(static_cast(gs.memory_card_1_type.value()) + 1); } - else + if (gs.memory_card_2_type.has_value()) { - QSignalBlocker sb(m_ui.userWidescreenHack); - m_ui.userWidescreenHack->setCheckState(Qt::PartiallyChecked); + QSignalBlocker sb(m_ui.userMemoryCard2Type); + m_ui.userMemoryCard2Type->setCurrentIndex(static_cast(gs.memory_card_2_type.value()) + 1); + } + if (!gs.memory_card_1_shared_path.empty()) + { + QSignalBlocker sb(m_ui.userMemoryCard1SharedPath); + m_ui.userMemoryCard1SharedPath->setText(QString::fromStdString(gs.memory_card_1_shared_path)); + } + if (!gs.memory_card_2_shared_path.empty()) + { + QSignalBlocker sb(m_ui.userMemoryCard2SharedPath); + m_ui.userMemoryCard2SharedPath->setText(QString::fromStdString(gs.memory_card_2_shared_path)); } } @@ -306,6 +377,24 @@ void GamePropertiesDialog::connectUi() saveGameSettings(); }); + connectBooleanUserSetting(m_ui.userLinearUpscaling, &m_game_settings.display_linear_upscaling); + connectBooleanUserSetting(m_ui.userIntegerUpscaling, &m_game_settings.display_integer_upscaling); + + connect(m_ui.userResolutionScale, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) { + if (index <= 0) + m_game_settings.gpu_resolution_scale.reset(); + else + m_game_settings.gpu_resolution_scale = static_cast(index - 1); + saveGameSettings(); + }); + + connectBooleanUserSetting(m_ui.userTrueColor, &m_game_settings.gpu_true_color); + connectBooleanUserSetting(m_ui.userScaledDithering, &m_game_settings.gpu_scaled_dithering); + connectBooleanUserSetting(m_ui.userForceNTSCTimings, &m_game_settings.gpu_force_ntsc_timings); + connectBooleanUserSetting(m_ui.userBilinearTextureFiltering, &m_game_settings.gpu_bilinear_texture_filtering); + connectBooleanUserSetting(m_ui.userWidescreenHack, &m_game_settings.gpu_widescreen_hack); + connectBooleanUserSetting(m_ui.userPGXP, &m_game_settings.gpu_pgxp); + connect(m_ui.userControllerType1, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) { if (index <= 0) m_game_settings.controller_1_type.reset(); @@ -322,13 +411,50 @@ void GamePropertiesDialog::connectUi() saveGameSettings(); }); - connect(m_ui.userWidescreenHack, &QCheckBox::stateChanged, [this](int state) { - if (state == Qt::PartiallyChecked) - m_game_settings.gpu_widescreen_hack.reset(); + connect(m_ui.userMemoryCard1Type, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) { + if (index <= 0) + m_game_settings.memory_card_1_type.reset(); else - m_game_settings.gpu_widescreen_hack = (state == Qt::Checked); + m_game_settings.memory_card_1_type = static_cast(index - 1); saveGameSettings(); }); + connect(m_ui.userMemoryCard1SharedPath, &QLineEdit::textChanged, [this](const QString& text) { + if (text.isEmpty()) + std::string().swap(m_game_settings.memory_card_1_shared_path); + else + m_game_settings.memory_card_1_shared_path = text.toStdString(); + saveGameSettings(); + }); + connect(m_ui.userMemoryCard1SharedPathBrowse, &QPushButton::clicked, [this]() { + QString path = QFileDialog::getOpenFileName(this, tr("Select path to memory card image"), QString(), + qApp->translate("MemoryCardSettingsWidget", MEMORY_CARD_IMAGE_FILTER)); + if (path.isEmpty()) + return; + + m_ui.userMemoryCard1SharedPath->setText(path); + }); + connect(m_ui.userMemoryCard2Type, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) { + if (index <= 0) + m_game_settings.memory_card_2_type.reset(); + else + m_game_settings.memory_card_2_type = static_cast(index - 1); + saveGameSettings(); + }); + connect(m_ui.userMemoryCard2SharedPath, &QLineEdit::textChanged, [this](const QString& text) { + if (text.isEmpty()) + std::string().swap(m_game_settings.memory_card_2_shared_path); + else + m_game_settings.memory_card_2_shared_path = text.toStdString(); + saveGameSettings(); + }); + connect(m_ui.userMemoryCard2SharedPathBrowse, &QPushButton::clicked, [this]() { + QString path = QFileDialog::getOpenFileName(this, tr("Select path to memory card image"), QString(), + qApp->translate("MemoryCardSettingsWidget", MEMORY_CARD_IMAGE_FILTER)); + if (path.isEmpty()) + return; + + m_ui.userMemoryCard2SharedPath->setText(path); + }); for (u32 i = 0; i < static_cast(GameSettings::Trait::Count); i++) { diff --git a/src/duckstation-qt/gamepropertiesdialog.h b/src/duckstation-qt/gamepropertiesdialog.h index 65f74c22e..ed2e74aab 100644 --- a/src/duckstation-qt/gamepropertiesdialog.h +++ b/src/duckstation-qt/gamepropertiesdialog.h @@ -43,6 +43,8 @@ private: void populateCompatibilityInfo(const std::string& game_code); void populateTracksInfo(const std::string& image_path); void populateGameSettings(); + void populateBooleanUserSetting(QCheckBox* cb, const std::optional& value); + void connectBooleanUserSetting(QCheckBox* cb, std::optional* value); void saveGameSettings(); void fillEntryFromUi(GameListCompatibilityEntry* entry); void computeTrackHashes(); diff --git a/src/duckstation-qt/gamepropertiesdialog.ui b/src/duckstation-qt/gamepropertiesdialog.ui index e6a800ede..e6af3e8bf 100644 --- a/src/duckstation-qt/gamepropertiesdialog.ui +++ b/src/duckstation-qt/gamepropertiesdialog.ui @@ -7,7 +7,7 @@ 0 0 793 - 647 + 600 @@ -21,7 +21,7 @@ - 0 + 1 @@ -190,39 +190,132 @@ - GPU Settings + GPU Screen Display - - - Crop Mode: - - - - - - - Aspect Ratio: - + - - + + - Widescreen Hack + Crop Mode: + + + + + + + + + + Linear Upscaling true + + + + Integer Upscaling + + + true + + + + + + + + + + GPU Enhancements + + + + + + Resolution Scale: + + + + + + + + + + + + True Color Rendering (24-bit, disables dithering) + + + true + + + + + + + Scaled Dithering (scale dither pattern to resolution) + + + true + + + + + + + Widescreen Hack + + + true + + + + + + + Force NTSC Timings (60hz-on-PAL) + + + true + + + + + + + Bilinear Texture Filtering + + + true + + + + + + + PGXP Geometry Correction + + + true + + + + + @@ -256,7 +349,78 @@ - + + + Memory Card Settings + + + + + + Memory Card 1 Type: + + + + + + + + + + Memory Card 1 Shared Path: + + + + + + + + + + + + Browse... + + + + + + + + + Memory Card 2 Type: + + + + + + + + + + Memory Card 2 Shared Path: + + + + + + + + + + + + Browse... + + + + + + + + + + Qt::Vertical diff --git a/src/duckstation-qt/gpusettingswidget.cpp b/src/duckstation-qt/gpusettingswidget.cpp index 2f2f2919f..15964ad4f 100644 --- a/src/duckstation-qt/gpusettingswidget.cpp +++ b/src/duckstation-qt/gpusettingswidget.cpp @@ -1,6 +1,7 @@ #include "gpusettingswidget.h" #include "core/gpu.h" #include "core/settings.h" +#include "qtutils.h" #include "settingsdialog.h" #include "settingwidgetbinder.h" @@ -62,14 +63,15 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p dialog->registerWidgetHelp( m_ui.renderer, tr("Renderer"), Settings::GetRendererDisplayName(Settings::DEFAULT_GPU_RENDERER), - tr( - "Chooses the backend to use for rendering the console/game visuals.
Depending on your system and hardware, " - "Direct3D 11 and OpenGL hardware backends may be available.
The software renderer offers the best compatibility, " - "but is the slowest and does not offer any enhancements.")); + tr("Chooses the backend to use for rendering the console/game visuals.
Depending on your system and hardware, " + "Direct3D 11 and OpenGL hardware backends may be available.
The software renderer offers the best " + "compatibility, " + "but is the slowest and does not offer any enhancements.")); dialog->registerWidgetHelp( m_ui.adapter, tr("Adapter"), tr("(Default)"), tr("If your system contains multiple GPUs or adapters, you can select which GPU you wish to use for the hardware " - "renderers.
This option is only supported in Direct3D and Vulkan. OpenGL will always use the default device.")); + "renderers.
This option is only supported in Direct3D and Vulkan. OpenGL will always use the default " + "device.")); dialog->registerWidgetHelp( m_ui.displayAspectRatio, tr("Aspect Ratio"), QStringLiteral("4:3"), tr("Changes the aspect ratio used to display the console's output to the screen. The default " @@ -82,14 +84,16 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p "compromise between stability and hiding black borders.")); dialog->registerWidgetHelp( m_ui.disableInterlacing, tr("Disable Interlacing (force progressive render/scan)"), tr("Unchecked"), - tr("Forces the rendering and display of frames to progressive mode.
This removes the \"combing\" effect seen in " - "480i games by rendering them in 480p. Usually safe to enable.
" - "May not be compatible with all games.")); - dialog->registerWidgetHelp( - m_ui.displayLinearFiltering, tr("Linear Upscaling"), tr("Checked"), - tr("Uses bilinear texture filtering when displaying the console's framebuffer to the screen.
Disabling filtering " - "will producer a sharper, blockier/pixelated image. Enabling will smooth out the image.
The option will be less " - "noticable the higher the resolution scale.")); + tr( + "Forces the rendering and display of frames to progressive mode.
This removes the \"combing\" effect seen in " + "480i games by rendering them in 480p. Usually safe to enable.
" + "May not be compatible with all games.")); + dialog->registerWidgetHelp(m_ui.displayLinearFiltering, tr("Linear Upscaling"), tr("Checked"), + tr("Uses bilinear texture filtering when displaying the console's framebuffer to the " + "screen.
Disabling filtering " + "will producer a sharper, blockier/pixelated image. Enabling will smooth out the " + "image.
The option will be less " + "noticable the higher the resolution scale.")); dialog->registerWidgetHelp( m_ui.displayIntegerScaling, tr("Integer Upscaling"), tr("Unchecked"), tr("Adds padding to the display area to ensure that the ratio between pixels on the host to " @@ -114,12 +118,12 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p m_ui.scaledDithering, tr("Scaled Dithering (scale dither pattern to resolution)"), tr("Checked"), tr("Scales the dither pattern to the resolution scale of the emulated GPU. This makes the dither pattern much less " "obvious at higher resolutions.
Usually safe to enable, and only supported by the hardware renderers.")); - dialog->registerWidgetHelp( - m_ui.forceNTSCTimings, tr("Force NTSC Timings (60hz-on-PAL)"), tr("Unchecked"), - tr( - "Uses NTSC frame timings when the console is in PAL mode, forcing PAL games to run at 60hz.
For most games which " - "have a speed tied to the framerate, this will result in the game running approximately 17% faster.
For variable " - "frame rate games, it may not affect the speed.")); + dialog->registerWidgetHelp(m_ui.forceNTSCTimings, tr("Force NTSC Timings (60hz-on-PAL)"), tr("Unchecked"), + tr("Uses NTSC frame timings when the console is in PAL mode, forcing PAL games to run at " + "60hz.
For most games which " + "have a speed tied to the framerate, this will result in the game running " + "approximately 17% faster.
For variable " + "frame rate games, it may not affect the speed.")); dialog->registerWidgetHelp( m_ui.linearTextureFiltering, tr("Bilinear Texture Filtering"), tr("Unchecked"), tr("Smooths out the blockyness of magnified textures on 3D object by using bilinear filtering.
Will have a " @@ -128,7 +132,8 @@ GPUSettingsWidget::GPUSettingsWidget(QtHostInterface* host_interface, QWidget* p m_ui.widescreenHack, tr("Widescreen Hack"), tr("Unchecked"), tr("Scales vertex positions in screen-space to a widescreen aspect ratio, essentially " "increasing the field of view from 4:3 to 16:9 in 3D games.
For 2D games, or games which " - "use pre-rendered backgrounds, this enhancement will not work as expected.
May not be compatible with all games.")); + "use pre-rendered backgrounds, this enhancement will not work as expected.
May not be compatible with " + "all games.")); dialog->registerWidgetHelp( m_ui.pgxpEnable, tr("Geometry Correction"), tr("Unchecked"), tr("Reduces \"wobbly\" polygons and \"warping\" textures that are common in PS1 games.
Only " @@ -178,29 +183,7 @@ void GPUSettingsWidget::setupAdditionalUi() qApp->translate("DisplayCropMode", Settings::GetDisplayCropModeDisplayName(static_cast(i)))); } - std::array resolution_suffixes = {{ - QString(), // auto - QString(), // 1x - QString(), // 2x - tr(" (for 720p)"), // 3x - QString(), // 4x - tr(" (for 1080p)"), // 5x - tr(" (for 1440p)"), // 6x - QString(), // 7x - QString(), // 8x - tr(" (for 4K)"), // 9x - QString(), // 10x - QString(), // 11x - QString(), // 12x - QString(), // 13x - QString(), // 14x - QString(), // 15x - QString() // 16x - }}; - - m_ui.resolutionScale->addItem(tr("Automatic based on window size")); - for (u32 i = 1; i <= GPU::MAX_RESOLUTION_SCALE; i++) - m_ui.resolutionScale->addItem(tr("%1x%2").arg(i).arg(resolution_suffixes[i])); + QtUtils::FillComboBoxWithResolutionScales(m_ui.resolutionScale); } void GPUSettingsWidget::populateGPUAdapters() diff --git a/src/duckstation-qt/qtutils.cpp b/src/duckstation-qt/qtutils.cpp index 9df725acb..1122cdf00 100644 --- a/src/duckstation-qt/qtutils.cpp +++ b/src/duckstation-qt/qtutils.cpp @@ -1,8 +1,10 @@ #include "qtutils.h" #include "common/byte_stream.h" +#include #include #include #include +#include #include #include #include @@ -646,4 +648,25 @@ void OpenURL(QWidget* parent, const char* url) return OpenURL(parent, QUrl::fromEncoded(QByteArray(url, static_cast(std::strlen(url))))); } +void FillComboBoxWithResolutionScales(QComboBox* cb) +{ + cb->addItem(qApp->translate("GPUSettingsWidget", "Automatic based on window size")); + cb->addItem(qApp->translate("GPUSettingsWidget", "1x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "2x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "3x (for 720p)")); + cb->addItem(qApp->translate("GPUSettingsWidget", "4x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "5x (for 1080p)")); + cb->addItem(qApp->translate("GPUSettingsWidget", "6x (for 1440p)")); + cb->addItem(qApp->translate("GPUSettingsWidget", "7x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "8x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "9x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "10x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "11x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "12x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "13x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "14x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "15x")); + cb->addItem(qApp->translate("GPUSettingsWidget", "16x")); +} + } // namespace QtUtils \ No newline at end of file diff --git a/src/duckstation-qt/qtutils.h b/src/duckstation-qt/qtutils.h index 5eb42093a..b0df67fe9 100644 --- a/src/duckstation-qt/qtutils.h +++ b/src/duckstation-qt/qtutils.h @@ -9,6 +9,7 @@ Q_DECLARE_METATYPE(std::optional); class ByteStream; +class QComboBox; class QFrame; class QKeyEvent; class QTableView; @@ -54,4 +55,7 @@ void OpenURL(QWidget* parent, const QUrl& qurl); /// Opens a URL string with the default handler. void OpenURL(QWidget* parent, const char* url); +/// Fills a combo box with resolution scale options. +void FillComboBoxWithResolutionScales(QComboBox* cb); + } // namespace QtUtils \ No newline at end of file diff --git a/src/frontend-common/game_list.h b/src/frontend-common/game_list.h index aac50561d..7b00c602a 100644 --- a/src/frontend-common/game_list.h +++ b/src/frontend-common/game_list.h @@ -112,7 +112,7 @@ private: enum : u32 { GAME_LIST_CACHE_SIGNATURE = 0x45434C47, - GAME_LIST_CACHE_VERSION = 7 + GAME_LIST_CACHE_VERSION = 8 }; using DatabaseMap = std::unordered_map; diff --git a/src/frontend-common/game_settings.cpp b/src/frontend-common/game_settings.cpp index 7b2bc84af..9b9cf2228 100644 --- a/src/frontend-common/game_settings.cpp +++ b/src/frontend-common/game_settings.cpp @@ -70,6 +70,19 @@ bool ReadOptionalFromStream(ByteStream* stream, std::optional* dest) return true; } +static bool ReadStringFromStream(ByteStream* stream, std::string* dest) +{ + u32 size; + if (!stream->Read2(&size, sizeof(size))) + return false; + + dest->resize(size); + if (!stream->Read2(dest->data(), size)) + return false; + + return true; +} + template bool WriteOptionalToStream(ByteStream* stream, const std::optional& src) { @@ -83,6 +96,12 @@ bool WriteOptionalToStream(ByteStream* stream, const std::optional& src) return stream->Write2(&src.value(), sizeof(T)); } +static bool WriteStringToStream(ByteStream* stream, const std::string& str) +{ + const u32 size = static_cast(str.size()); + return (stream->Write2(&size, sizeof(size)) && (size == 0 || stream->Write2(str.data(), size))); +} + bool Entry::LoadFromStream(ByteStream* stream) { constexpr u32 num_bytes = (static_cast(Trait::Count) + 7) / 8; @@ -91,8 +110,17 @@ bool Entry::LoadFromStream(ByteStream* stream) if (!stream->Read2(bits.data(), num_bytes) || !ReadOptionalFromStream(stream, &display_active_start_offset) || !ReadOptionalFromStream(stream, &display_active_end_offset) || !ReadOptionalFromStream(stream, &display_crop_mode) || !ReadOptionalFromStream(stream, &display_aspect_ratio) || + !ReadOptionalFromStream(stream, &display_linear_upscaling) || + !ReadOptionalFromStream(stream, &display_integer_upscaling) || + !ReadOptionalFromStream(stream, &gpu_resolution_scale) || !ReadOptionalFromStream(stream, &gpu_true_color) || + !ReadOptionalFromStream(stream, &gpu_scaled_dithering) || + !ReadOptionalFromStream(stream, &gpu_force_ntsc_timings) || + !ReadOptionalFromStream(stream, &gpu_bilinear_texture_filtering) || + !ReadOptionalFromStream(stream, &gpu_widescreen_hack) || !ReadOptionalFromStream(stream, &gpu_pgxp) || !ReadOptionalFromStream(stream, &controller_1_type) || !ReadOptionalFromStream(stream, &controller_2_type) || - !ReadOptionalFromStream(stream, &gpu_widescreen_hack)) + !ReadOptionalFromStream(stream, &memory_card_1_type) || !ReadOptionalFromStream(stream, &memory_card_2_type) || + !ReadStringFromStream(stream, &memory_card_1_shared_path) || + !ReadStringFromStream(stream, &memory_card_2_shared_path)) { return false; } @@ -120,8 +148,17 @@ bool Entry::SaveToStream(ByteStream* stream) const return stream->Write2(bits.data(), num_bytes) && WriteOptionalToStream(stream, display_active_start_offset) && WriteOptionalToStream(stream, display_active_end_offset) && WriteOptionalToStream(stream, display_crop_mode) && - WriteOptionalToStream(stream, display_aspect_ratio) && WriteOptionalToStream(stream, controller_1_type) && - WriteOptionalToStream(stream, controller_2_type) && WriteOptionalToStream(stream, gpu_widescreen_hack); + WriteOptionalToStream(stream, display_linear_upscaling) && + WriteOptionalToStream(stream, display_integer_upscaling) && + WriteOptionalToStream(stream, display_aspect_ratio) && WriteOptionalToStream(stream, gpu_resolution_scale) && + WriteOptionalToStream(stream, gpu_true_color) && WriteOptionalToStream(stream, gpu_scaled_dithering) && + WriteOptionalToStream(stream, gpu_force_ntsc_timings) && + WriteOptionalToStream(stream, gpu_bilinear_texture_filtering) && + WriteOptionalToStream(stream, gpu_widescreen_hack) && WriteOptionalToStream(stream, gpu_pgxp) && + WriteOptionalToStream(stream, controller_1_type) && WriteOptionalToStream(stream, controller_2_type) && + WriteOptionalToStream(stream, memory_card_1_type) && WriteOptionalToStream(stream, memory_card_2_type) && + WriteStringToStream(stream, memory_card_1_shared_path) && + WriteStringToStream(stream, memory_card_2_shared_path); } static void ParseIniSection(Entry* entry, const char* section, const CSimpleIniA& ini) @@ -145,6 +182,34 @@ static void ParseIniSection(Entry* entry, const char* section, const CSimpleIniA cvalue = ini.GetValue(section, "DisplayAspectRatio", nullptr); if (cvalue) entry->display_aspect_ratio = Settings::ParseDisplayAspectRatio(cvalue); + cvalue = ini.GetValue(section, "DisplayLinearUpscaling", nullptr); + if (cvalue) + entry->display_linear_upscaling = StringUtil::FromChars(cvalue); + cvalue = ini.GetValue(section, "DisplayIntegerUpscaling", nullptr); + if (cvalue) + entry->display_integer_upscaling = StringUtil::FromChars(cvalue); + + cvalue = ini.GetValue(section, "GPUResolutionScale", nullptr); + if (cvalue) + entry->gpu_resolution_scale = StringUtil::FromChars(cvalue); + cvalue = ini.GetValue(section, "GPUTrueColor", nullptr); + if (cvalue) + entry->gpu_true_color = StringUtil::FromChars(cvalue); + cvalue = ini.GetValue(section, "GPUScaledDithering", nullptr); + if (cvalue) + entry->gpu_scaled_dithering = StringUtil::FromChars(cvalue); + cvalue = ini.GetValue(section, "GPUBilinearTextureFiltering", nullptr); + if (cvalue) + entry->gpu_bilinear_texture_filtering = StringUtil::FromChars(cvalue); + cvalue = ini.GetValue(section, "GPUForceNTSCTimings", nullptr); + if (cvalue) + entry->gpu_force_ntsc_timings = StringUtil::FromChars(cvalue); + cvalue = ini.GetValue(section, "GPUWidescreenHack", nullptr); + if (cvalue) + entry->gpu_widescreen_hack = StringUtil::FromChars(cvalue); + cvalue = ini.GetValue(section, "GPUPGXP", nullptr); + if (cvalue) + entry->gpu_pgxp = StringUtil::FromChars(cvalue); cvalue = ini.GetValue(section, "Controller1Type", nullptr); if (cvalue) @@ -153,9 +218,18 @@ static void ParseIniSection(Entry* entry, const char* section, const CSimpleIniA if (cvalue) entry->controller_2_type = Settings::ParseControllerTypeName(cvalue); - cvalue = ini.GetValue(section, "GPUWidescreenHack", nullptr); + cvalue = ini.GetValue(section, "MemoryCard1Type", nullptr); if (cvalue) - entry->gpu_widescreen_hack = StringUtil::FromChars(cvalue); + entry->memory_card_1_type = Settings::ParseMemoryCardTypeName(cvalue); + cvalue = ini.GetValue(section, "MemoryCard2Type", nullptr); + if (cvalue) + entry->memory_card_2_type = Settings::ParseMemoryCardTypeName(cvalue); + cvalue = ini.GetValue(section, "MemoryCard1SharedPath"); + if (cvalue) + entry->memory_card_1_shared_path = cvalue; + cvalue = ini.GetValue(section, "MemoryCard2SharedPath"); + if (cvalue) + entry->memory_card_2_shared_path = cvalue; } static void StoreIniSection(const Entry& entry, const char* section, CSimpleIniA& ini) @@ -179,14 +253,46 @@ static void StoreIniSection(const Entry& entry, const char* section, CSimpleIniA ini.SetValue(section, "DisplayAspectRatio", Settings::GetDisplayAspectRatioName(entry.display_aspect_ratio.value())); } + if (entry.display_linear_upscaling.has_value()) + ini.SetValue(section, "DisplayLinearUpscaling", entry.display_linear_upscaling.value() ? "true" : "false"); + if (entry.display_integer_upscaling.has_value()) + ini.SetValue(section, "DisplayIntegerUpscaling", entry.display_integer_upscaling.value() ? "true" : "false"); + + if (entry.gpu_resolution_scale.has_value()) + ini.SetLongValue(section, "GPUResolutionScale", static_cast(entry.gpu_resolution_scale.value())); + if (entry.gpu_true_color.has_value()) + ini.SetValue(section, "GPUTrueColor", entry.gpu_true_color.value() ? "true" : "false"); + if (entry.gpu_scaled_dithering.has_value()) + ini.SetValue(section, "GPUScaledDithering", entry.gpu_scaled_dithering.value() ? "true" : "false"); + if (entry.gpu_bilinear_texture_filtering.has_value()) + { + ini.SetValue(section, "GPUBilinearTextureFiltering", + entry.gpu_bilinear_texture_filtering.value() ? "true" : "false"); + } + if (entry.gpu_force_ntsc_timings.has_value()) + ini.SetValue(section, "GPUForceNTSCTimings", entry.gpu_force_ntsc_timings.value() ? "true" : "false"); + if (entry.gpu_widescreen_hack.has_value()) + ini.SetValue(section, "GPUWidescreenHack", entry.gpu_widescreen_hack.value() ? "true" : "false"); + if (entry.gpu_pgxp.has_value()) + ini.SetValue(section, "GPUPGXP", entry.gpu_pgxp.value() ? "true" : "false"); if (entry.controller_1_type.has_value()) ini.SetValue(section, "Controller1Type", Settings::GetControllerTypeName(entry.controller_1_type.value())); if (entry.controller_2_type.has_value()) ini.SetValue(section, "Controller2Type", Settings::GetControllerTypeName(entry.controller_2_type.value())); - if (entry.gpu_widescreen_hack.has_value()) - ini.SetValue(section, "GPUWidescreenHack", entry.gpu_widescreen_hack.value() ? "true" : "false"); + if (entry.controller_1_type.has_value()) + ini.SetValue(section, "Controller1Type", Settings::GetControllerTypeName(entry.controller_1_type.value())); + if (entry.controller_2_type.has_value()) + ini.SetValue(section, "Controller2Type", Settings::GetControllerTypeName(entry.controller_2_type.value())); + if (entry.memory_card_1_type.has_value()) + ini.SetValue(section, "MemoryCard1Type", Settings::GetMemoryCardTypeName(entry.memory_card_1_type.value())); + if (entry.memory_card_2_type.has_value()) + ini.SetValue(section, "MemoryCard2Type", Settings::GetMemoryCardTypeName(entry.memory_card_2_type.value())); + if (!entry.memory_card_1_shared_path.empty()) + ini.SetValue(section, "MemoryCard1SharedPath", entry.memory_card_1_shared_path.c_str()); + if (!entry.memory_card_2_shared_path.empty()) + ini.SetValue(section, "MemoryCard2SharedPath", entry.memory_card_2_shared_path.c_str()); } Database::Database() = default; @@ -297,12 +403,39 @@ void Entry::ApplySettings(bool display_osd_messages) const g_settings.display_crop_mode = display_crop_mode.value(); if (display_aspect_ratio.has_value()) g_settings.display_aspect_ratio = display_aspect_ratio.value(); + if (display_linear_upscaling.has_value()) + g_settings.display_linear_filtering = display_linear_upscaling.value(); + if (display_integer_upscaling.has_value()) + g_settings.display_integer_scaling = display_integer_upscaling.value(); + + if (gpu_resolution_scale.has_value()) + g_settings.gpu_resolution_scale = gpu_resolution_scale.value(); + if (gpu_true_color.has_value()) + g_settings.gpu_true_color = gpu_true_color.value(); + if (gpu_scaled_dithering.has_value()) + g_settings.gpu_scaled_dithering = gpu_scaled_dithering.value(); + if (gpu_force_ntsc_timings.has_value()) + g_settings.gpu_force_ntsc_timings = gpu_force_ntsc_timings.value(); + if (gpu_bilinear_texture_filtering) + g_settings.gpu_texture_filtering = gpu_bilinear_texture_filtering.value(); + if (gpu_widescreen_hack.has_value()) + g_settings.gpu_widescreen_hack = gpu_widescreen_hack.value(); + if (gpu_pgxp.has_value()) + g_settings.gpu_pgxp_enable = gpu_pgxp.value(); + if (controller_1_type.has_value()) g_settings.controller_types[0] = controller_1_type.value(); if (controller_2_type.has_value()) g_settings.controller_types[1] = controller_2_type.value(); - if (gpu_widescreen_hack.has_value()) - g_settings.gpu_widescreen_hack = gpu_widescreen_hack.value(); + + if (memory_card_1_type.has_value()) + g_settings.memory_card_types[0] = memory_card_1_type.value(); + if (!memory_card_1_shared_path.empty()) + g_settings.memory_card_paths[0] = memory_card_1_shared_path; + if (memory_card_2_type.has_value()) + g_settings.memory_card_types[1] = memory_card_2_type.value(); + if (!memory_card_1_shared_path.empty()) + g_settings.memory_card_paths[1] = memory_card_2_shared_path; if (HasTrait(Trait::ForceInterpreter)) { diff --git a/src/frontend-common/game_settings.h b/src/frontend-common/game_settings.h index 918210ab1..176bea0b3 100644 --- a/src/frontend-common/game_settings.h +++ b/src/frontend-common/game_settings.h @@ -40,9 +40,21 @@ struct Entry // user settings std::optional display_crop_mode; std::optional display_aspect_ratio; + std::optional display_linear_upscaling; + std::optional display_integer_upscaling; + std::optional gpu_resolution_scale; + std::optional gpu_true_color; + std::optional gpu_scaled_dithering; + std::optional gpu_force_ntsc_timings; + std::optional gpu_bilinear_texture_filtering; + std::optional gpu_widescreen_hack; + std::optional gpu_pgxp; std::optional controller_1_type; std::optional controller_2_type; - std::optional gpu_widescreen_hack; + std::optional memory_card_1_type; + std::optional memory_card_2_type; + std::string memory_card_1_shared_path; + std::string memory_card_2_shared_path; ALWAYS_INLINE bool HasTrait(Trait trait) const { return traits[static_cast(trait)]; } ALWAYS_INLINE void AddTrait(Trait trait) { traits[static_cast(trait)] = true; }