From 113c86f1b4661c7e300d3867cd26ed26b2640f2a Mon Sep 17 00:00:00 2001 From: AndrewGDX Date: Mon, 10 Nov 2025 15:03:38 +0300 Subject: [PATCH] Improved stereoscopic 3D settings --- Source/Core/Core/Config/GraphicsSettings.cpp | 10 +++--- Source/Core/Core/Config/GraphicsSettings.h | 12 +++---- .../ConfigControls/ConfigFloatSlider.cpp | 11 ++++++ .../Config/ConfigControls/ConfigFloatSlider.h | 8 +++++ .../DolphinQt/Config/GameConfigWidget.cpp | 36 ++++++++++++++----- .../Core/DolphinQt/Config/GameConfigWidget.h | 6 ++-- .../Config/Graphics/EnhancementsWidget.cpp | 27 ++++++++++---- .../Config/Graphics/EnhancementsWidget.h | 9 +++-- Source/Core/DolphinQt/HotkeyScheduler.cpp | 4 +-- .../VideoCommon/GeometryShaderManager.cpp | 6 ++-- Source/Core/VideoCommon/VideoConfig.cpp | 8 ++--- Source/Core/VideoCommon/VideoConfig.h | 6 ++-- 12 files changed, 96 insertions(+), 47 deletions(-) diff --git a/Source/Core/Core/Config/GraphicsSettings.cpp b/Source/Core/Core/Config/GraphicsSettings.cpp index c21627807f0..7062a724cb5 100644 --- a/Source/Core/Core/Config/GraphicsSettings.cpp +++ b/Source/Core/Core/Config/GraphicsSettings.cpp @@ -171,15 +171,15 @@ const Info GFX_CC_HDR_PAPER_WHITE_NITS{{System::GFX, "ColorCorrection", " const Info GFX_STEREO_MODE{{System::GFX, "Stereoscopy", "StereoMode"}, StereoMode::Off}; const Info GFX_STEREO_PER_EYE_RESOLUTION_FULL{ {System::GFX, "Stereoscopy", "StereoPerEyeResolutionFull"}, false}; -const Info GFX_STEREO_DEPTH{{System::GFX, "Stereoscopy", "StereoDepth"}, 20}; -const Info GFX_STEREO_CONVERGENCE_PERCENTAGE{ +const Info GFX_STEREO_DEPTH{{System::GFX, "Stereoscopy", "StereoDepth"}, 20}; +const Info GFX_STEREO_CONVERGENCE_PERCENTAGE{ {System::GFX, "Stereoscopy", "StereoConvergencePercentage"}, 100}; const Info GFX_STEREO_SWAP_EYES{{System::GFX, "Stereoscopy", "StereoSwapEyes"}, false}; -const Info GFX_STEREO_CONVERGENCE{{System::GFX, "Stereoscopy", "StereoConvergence"}, 20}; +const Info GFX_STEREO_CONVERGENCE{{System::GFX, "Stereoscopy", "StereoConvergence"}, 20}; const Info GFX_STEREO_EFB_MONO_DEPTH{{System::GFX, "Stereoscopy", "StereoEFBMonoDepth"}, false}; -const Info GFX_STEREO_DEPTH_PERCENTAGE{{System::GFX, "Stereoscopy", "StereoDepthPercentage"}, - 100}; +const Info GFX_STEREO_DEPTH_PERCENTAGE{{System::GFX, "Stereoscopy", "StereoDepthPercentage"}, + 100}; // Graphics.Hacks diff --git a/Source/Core/Core/Config/GraphicsSettings.h b/Source/Core/Core/Config/GraphicsSettings.h index 431797cefa9..99dbfb5e645 100644 --- a/Source/Core/Core/Config/GraphicsSettings.h +++ b/Source/Core/Core/Config/GraphicsSettings.h @@ -145,16 +145,16 @@ extern const Info GFX_CC_HDR_PAPER_WHITE_NITS; extern const Info GFX_STEREO_MODE; extern const Info GFX_STEREO_PER_EYE_RESOLUTION_FULL; -extern const Info GFX_STEREO_DEPTH; -extern const Info GFX_STEREO_CONVERGENCE_PERCENTAGE; +extern const Info GFX_STEREO_DEPTH; +extern const Info GFX_STEREO_CONVERGENCE_PERCENTAGE; extern const Info GFX_STEREO_SWAP_EYES; -extern const Info GFX_STEREO_CONVERGENCE; +extern const Info GFX_STEREO_CONVERGENCE; extern const Info GFX_STEREO_EFB_MONO_DEPTH; -extern const Info GFX_STEREO_DEPTH_PERCENTAGE; +extern const Info GFX_STEREO_DEPTH_PERCENTAGE; // Stereoscopy pseudo-limits for consistent behavior between enhancements tab and hotkeys. -static constexpr int GFX_STEREO_DEPTH_MAXIMUM = 100; -static constexpr int GFX_STEREO_CONVERGENCE_MAXIMUM = 200; +static constexpr float GFX_STEREO_DEPTH_MAXIMUM = 100; +static constexpr float GFX_STEREO_CONVERGENCE_MAXIMUM = 200; // Graphics.Hacks diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.cpp b/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.cpp index e5211d00bbe..a35e94aa911 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.cpp +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.cpp @@ -1,6 +1,8 @@ // Copyright 2023 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include + #include "DolphinQt/Config/ConfigControls/ConfigFloatSlider.h" ConfigFloatSlider::ConfigFloatSlider(float minimum, float maximum, @@ -38,3 +40,12 @@ void ConfigFloatSlider::OnConfigChanged() { setValue(std::round((ReadValue(m_setting) - m_minimum) / m_step)); } + +ConfigFloatLabel::ConfigFloatLabel(const QString& text, ConfigFloatSlider* widget) : QLabel(text) +{ + connect(&Settings::Instance(), &Settings::ConfigChanged, this, [this, widget = QPointer{widget}] { + // Label shares font changes with ConfigFloatSlider to mark game ini settings. + if (widget) + setFont(widget->font()); + }); +} diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.h b/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.h index 4f85e31162c..e0dfccec153 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.h +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.h @@ -3,6 +3,8 @@ #pragma once +#include + #include "DolphinQt/Config/ConfigControls/ConfigControl.h" #include "DolphinQt/Config/ToolTipControls/ToolTipSlider.h" @@ -29,3 +31,9 @@ private: float m_step; const Config::Info m_setting; }; + +class ConfigFloatLabel final : public QLabel +{ +public: + ConfigFloatLabel(const QString& text, ConfigFloatSlider* widget); +}; diff --git a/Source/Core/DolphinQt/Config/GameConfigWidget.cpp b/Source/Core/DolphinQt/Config/GameConfigWidget.cpp index efaae69c627..32734a445f1 100644 --- a/Source/Core/DolphinQt/Config/GameConfigWidget.cpp +++ b/Source/Core/DolphinQt/Config/GameConfigWidget.cpp @@ -24,9 +24,9 @@ #include "Core/ConfigManager.h" #include "DolphinQt/Config/ConfigControls/ConfigBool.h" #include "DolphinQt/Config/ConfigControls/ConfigChoice.h" +#include "DolphinQt/Config/ConfigControls/ConfigFloatSlider.h" #include "DolphinQt/Config/ConfigControls/ConfigInteger.h" #include "DolphinQt/Config/ConfigControls/ConfigRadio.h" -#include "DolphinQt/Config/ConfigControls/ConfigSlider.h" #include "DolphinQt/Config/GameConfigEdit.h" #include "DolphinQt/Config/Graphics/GraphicsPane.h" #include "DolphinQt/QtUtils/QtUtils.h" @@ -140,26 +140,35 @@ void GameConfigWidget::CreateWidgets() auto* stereoscopy_layout = new QGridLayout; stereoscopy_box->setLayout(stereoscopy_layout); - m_depth_slider = new ConfigSlider(100, 200, Config::GFX_STEREO_DEPTH_PERCENTAGE, layer); - m_convergence_spin = new ConfigInteger(0, INT32_MAX, Config::GFX_STEREO_CONVERGENCE, layer); + m_depth_slider = + new ConfigFloatSlider(100, 200, Config::GFX_STEREO_DEPTH_PERCENTAGE, 1.0f, layer); + m_convergence_slider = + new ConfigFloatSlider(0, 1000, Config::GFX_STEREO_CONVERGENCE, 0.01f, layer); + auto* const depth_slider_value = new QLabel(); + auto* const convergence_slider_value = new QLabel(); m_use_monoscopic_shadows = new ConfigBool(tr("Monoscopic Shadows"), Config::GFX_STEREO_EFB_MONO_DEPTH, layer); m_depth_slider->SetDescription( tr("This value is multiplied with the depth set in the graphics configuration.")); - m_convergence_spin->SetDescription( + m_convergence_slider->SetDescription( tr("This value is added to the convergence value set in the graphics configuration.")); m_use_monoscopic_shadows->SetDescription( tr("Use a single depth buffer for both eyes. Needed for a few games.")); - stereoscopy_layout->addWidget(new ConfigSliderLabel(tr("Depth Percentage:"), m_depth_slider), 0, + stereoscopy_layout->addWidget(new ConfigFloatLabel(tr("Depth Percentage:"), m_depth_slider), 0, 0); stereoscopy_layout->addWidget(m_depth_slider, 0, 1); - stereoscopy_layout->addWidget(new ConfigIntegerLabel(tr("Convergence:"), m_convergence_spin), 1, + stereoscopy_layout->addWidget(depth_slider_value, 0, 2); + stereoscopy_layout->addWidget(new ConfigFloatLabel(tr("Convergence:"), m_convergence_slider), 1, 0); - stereoscopy_layout->addWidget(m_convergence_spin, 1, 1); + stereoscopy_layout->addWidget(m_convergence_slider, 1, 1); + stereoscopy_layout->addWidget(convergence_slider_value, 1, 2); stereoscopy_layout->addWidget(m_use_monoscopic_shadows, 2, 0); + depth_slider_value->setText(QString::asprintf("%.0f%%", m_depth_slider->GetValue())); + convergence_slider_value->setText(QString::asprintf("%.2f", m_convergence_slider->GetValue())); + auto* general_layout = new QVBoxLayout; general_layout->addWidget(core_box); general_layout->addWidget(stereoscopy_box); @@ -239,6 +248,15 @@ void GameConfigWidget::CreateWidgets() m_prev_tab_index = index; }); + connect(m_depth_slider, &ConfigFloatSlider::valueChanged, this, [this, depth_slider_value] { + depth_slider_value->setText(QString::asprintf("%.0f%%", m_depth_slider->GetValue())); + }); + connect(m_convergence_slider, &ConfigFloatSlider::valueChanged, this, + [this, convergence_slider_value] { + convergence_slider_value->setText( + QString::asprintf("%.2f", m_convergence_slider->GetValue())); + }); + const QString help_msg = tr( "Italics mark default game settings, bold marks user settings.\nRight-click to remove user " "settings.\nGraphics tabs don't display the value of a default game setting.\nAnti-Aliasing " @@ -320,7 +338,7 @@ void GameConfigWidget::LoadSettings() update_bool(m_emulate_disc_speed, true); update_int(m_depth_slider); - update_int(m_convergence_spin); + update_int(m_convergence_slider); } void GameConfigWidget::SetItalics() @@ -337,7 +355,7 @@ void GameConfigWidget::SetItalics() for (auto* config : findChildren()) italics(config); - for (auto* config : findChildren()) + for (auto* config : findChildren()) italics(config); for (auto* config : findChildren()) italics(config); diff --git a/Source/Core/DolphinQt/Config/GameConfigWidget.h b/Source/Core/DolphinQt/Config/GameConfigWidget.h index 1f291680135..5163dc13247 100644 --- a/Source/Core/DolphinQt/Config/GameConfigWidget.h +++ b/Source/Core/DolphinQt/Config/GameConfigWidget.h @@ -19,7 +19,7 @@ class Layer; class ConfigBool; class ConfigInteger; -class ConfigSlider; +class ConfigFloatSlider; class ConfigStringChoice; class QPushButton; class QTabWidget; @@ -50,8 +50,8 @@ private: ConfigBool* m_use_monoscopic_shadows; ConfigStringChoice* m_deterministic_dual_core; - ConfigSlider* m_depth_slider; - ConfigInteger* m_convergence_spin; + ConfigFloatSlider* m_depth_slider; + ConfigFloatSlider* m_convergence_slider; const UICommon::GameFile& m_game; std::string m_game_id; diff --git a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp index a8eb606a5c0..0aa77d53110 100644 --- a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp @@ -16,7 +16,7 @@ #include "DolphinQt/Config/ConfigControls/ConfigBool.h" #include "DolphinQt/Config/ConfigControls/ConfigChoice.h" -#include "DolphinQt/Config/ConfigControls/ConfigSlider.h" +#include "DolphinQt/Config/ConfigControls/ConfigFloatSlider.h" #include "DolphinQt/Config/GameConfigWidget.h" #include "DolphinQt/Config/Graphics/ColorCorrectionConfigWindow.h" #include "DolphinQt/Config/Graphics/GraphicsPane.h" @@ -214,10 +214,12 @@ void EnhancementsWidget::CreateWidgets() m_3d_mode = new ConfigChoice({tr("Off"), tr("Side-by-Side"), tr("Top-and-Bottom"), tr("Anaglyph"), tr("HDMI 3D"), tr("Passive")}, Config::GFX_STEREO_MODE, m_game_layer); - m_3d_depth = - new ConfigSlider(0, Config::GFX_STEREO_DEPTH_MAXIMUM, Config::GFX_STEREO_DEPTH, m_game_layer); - m_3d_convergence = new ConfigSlider(0, Config::GFX_STEREO_CONVERGENCE_MAXIMUM, - Config::GFX_STEREO_CONVERGENCE, m_game_layer, 100); + m_3d_depth = new ConfigFloatSlider(0, Config::GFX_STEREO_DEPTH_MAXIMUM, Config::GFX_STEREO_DEPTH, + 1.0f, m_game_layer); + m_3d_convergence = new ConfigFloatSlider(0, Config::GFX_STEREO_CONVERGENCE_MAXIMUM, + Config::GFX_STEREO_CONVERGENCE, 0.01f, m_game_layer); + m_3d_depth_value = new QLabel(); + m_3d_convergence_value = new QLabel(); m_3d_swap_eyes = new ConfigBool(tr("Swap Eyes"), Config::GFX_STEREO_SWAP_EYES, m_game_layer); @@ -226,13 +228,18 @@ void EnhancementsWidget::CreateWidgets() stereoscopy_layout->addWidget(new QLabel(tr("Stereoscopic 3D Mode:")), 0, 0); stereoscopy_layout->addWidget(m_3d_mode, 0, 1); - stereoscopy_layout->addWidget(new ConfigSliderLabel(tr("Depth:"), m_3d_depth), 1, 0); + stereoscopy_layout->addWidget(new ConfigFloatLabel(tr("Depth:"), m_3d_depth), 1, 0); stereoscopy_layout->addWidget(m_3d_depth, 1, 1); - stereoscopy_layout->addWidget(new ConfigSliderLabel(tr("Convergence:"), m_3d_convergence), 2, 0); + stereoscopy_layout->addWidget(m_3d_depth_value, 1, 2); + stereoscopy_layout->addWidget(new ConfigFloatLabel(tr("Convergence:"), m_3d_convergence), 2, 0); stereoscopy_layout->addWidget(m_3d_convergence, 2, 1); + stereoscopy_layout->addWidget(m_3d_convergence_value, 2, 2); stereoscopy_layout->addWidget(m_3d_swap_eyes, 3, 0); stereoscopy_layout->addWidget(m_3d_per_eye_resolution, 4, 0); + m_3d_depth_value->setText(QString::asprintf("%.0f", m_3d_depth->GetValue())); + m_3d_convergence_value->setText(QString::asprintf("%.2f", m_3d_convergence->GetValue())); + auto current_stereo_mode = ReadSetting(Config::GFX_STEREO_MODE); if (current_stereo_mode != StereoMode::SBS && current_stereo_mode != StereoMode::TAB) m_3d_per_eye_resolution->hide(); @@ -263,6 +270,12 @@ void EnhancementsWidget::ConnectWidgets() &EnhancementsWidget::ConfigureColorCorrection); connect(m_configure_post_processing_effect, &QPushButton::clicked, this, &EnhancementsWidget::ConfigurePostProcessingShader); + + connect(m_3d_depth, &ConfigFloatSlider::valueChanged, this, + [this] { m_3d_depth_value->setText(QString::asprintf("%.0f", m_3d_depth->GetValue())); }); + connect(m_3d_convergence, &ConfigFloatSlider::valueChanged, this, [this] { + m_3d_convergence_value->setText(QString::asprintf("%.2f", m_3d_convergence->GetValue())); + }); } template diff --git a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h index e6465461ff7..6309c6af0e7 100644 --- a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h +++ b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h @@ -9,9 +9,10 @@ class ConfigBool; class ConfigChoice; class ConfigComplexChoice; class ConfigStringChoice; -class ConfigSlider; +class ConfigFloatSlider; class GraphicsPane; class QPushButton; +class QLabel; class ToolTipPushButton; namespace Config @@ -63,8 +64,10 @@ private: // Stereoscopy ConfigChoice* m_3d_mode; - ConfigSlider* m_3d_depth; - ConfigSlider* m_3d_convergence; + ConfigFloatSlider* m_3d_depth; + QLabel* m_3d_depth_value; + ConfigFloatSlider* m_3d_convergence; + QLabel* m_3d_convergence_value; ConfigBool* m_3d_swap_eyes; ConfigBool* m_3d_per_eye_resolution; diff --git a/Source/Core/DolphinQt/HotkeyScheduler.cpp b/Source/Core/DolphinQt/HotkeyScheduler.cpp index ead6a40c66e..26a762377ce 100644 --- a/Source/Core/DolphinQt/HotkeyScheduler.cpp +++ b/Source/Core/DolphinQt/HotkeyScheduler.cpp @@ -608,7 +608,7 @@ void HotkeyScheduler::Run() const auto stereo_depth = Config::Get(Config::GFX_STEREO_DEPTH); if (IsHotkey(HK_DECREASE_DEPTH, true)) - Config::SetCurrent(Config::GFX_STEREO_DEPTH, std::max(stereo_depth - 1, 0)); + Config::SetCurrent(Config::GFX_STEREO_DEPTH, std::max(stereo_depth - 1, 0.0f)); if (IsHotkey(HK_INCREASE_DEPTH, true)) Config::SetCurrent(Config::GFX_STEREO_DEPTH, @@ -617,7 +617,7 @@ void HotkeyScheduler::Run() const auto stereo_convergence = Config::Get(Config::GFX_STEREO_CONVERGENCE); if (IsHotkey(HK_DECREASE_CONVERGENCE, true)) - Config::SetCurrent(Config::GFX_STEREO_CONVERGENCE, std::max(stereo_convergence - 5, 0)); + Config::SetCurrent(Config::GFX_STEREO_CONVERGENCE, std::max(stereo_convergence - 5, 0.0f)); if (IsHotkey(HK_INCREASE_CONVERGENCE, true)) Config::SetCurrent(Config::GFX_STEREO_CONVERGENCE, diff --git a/Source/Core/VideoCommon/GeometryShaderManager.cpp b/Source/Core/VideoCommon/GeometryShaderManager.cpp index 183b16acabc..43c934ed284 100644 --- a/Source/Core/VideoCommon/GeometryShaderManager.cpp +++ b/Source/Core/VideoCommon/GeometryShaderManager.cpp @@ -54,8 +54,7 @@ void GeometryShaderManager::SetConstants(PrimitiveType prim) if (xfmem.projection.type == ProjectionType::Perspective) { - float offset = (g_ActiveConfig.iStereoDepth / 1000.0f) * - (g_ActiveConfig.iStereoDepthPercentage / 100.0f); + const float offset = g_ActiveConfig.stereo_depth; constants.stereoparams[0] = g_ActiveConfig.bStereoSwapEyes ? offset : -offset; constants.stereoparams[1] = g_ActiveConfig.bStereoSwapEyes ? -offset : offset; } @@ -64,8 +63,7 @@ void GeometryShaderManager::SetConstants(PrimitiveType prim) constants.stereoparams[0] = constants.stereoparams[1] = 0; } - constants.stereoparams[2] = (float)(g_ActiveConfig.iStereoConvergence * - (g_ActiveConfig.iStereoConvergencePercentage / 100.0f)); + constants.stereoparams[2] = g_ActiveConfig.stereo_convergence; dirty = true; } diff --git a/Source/Core/VideoCommon/VideoConfig.cpp b/Source/Core/VideoCommon/VideoConfig.cpp index c4d764176c6..67eee5c5c3a 100644 --- a/Source/Core/VideoCommon/VideoConfig.cpp +++ b/Source/Core/VideoCommon/VideoConfig.cpp @@ -162,12 +162,12 @@ void VideoConfig::Refresh() stereo_mode = Config::Get(Config::GFX_STEREO_MODE); stereo_per_eye_resolution_full = Config::Get(Config::GFX_STEREO_PER_EYE_RESOLUTION_FULL); - iStereoDepth = Config::Get(Config::GFX_STEREO_DEPTH); - iStereoConvergencePercentage = Config::Get(Config::GFX_STEREO_CONVERGENCE_PERCENTAGE); + stereo_depth = Config::Get(Config::GFX_STEREO_DEPTH) * + Config::Get(Config::GFX_STEREO_DEPTH_PERCENTAGE) * 0.00001f; + stereo_convergence = Config::Get(Config::GFX_STEREO_CONVERGENCE) * + Config::Get(Config::GFX_STEREO_CONVERGENCE_PERCENTAGE) * 0.01f; bStereoSwapEyes = Config::Get(Config::GFX_STEREO_SWAP_EYES); - iStereoConvergence = Config::Get(Config::GFX_STEREO_CONVERGENCE); bStereoEFBMonoDepth = Config::Get(Config::GFX_STEREO_EFB_MONO_DEPTH); - iStereoDepthPercentage = Config::Get(Config::GFX_STEREO_DEPTH_PERCENTAGE); bEFBAccessEnable = Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE); bEFBAccessDeferInvalidation = Config::Get(Config::GFX_HACK_EFB_DEFER_INVALIDATION); diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index e42b8e5d850..b826fcb7834 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -310,12 +310,10 @@ struct VideoConfig final // Stereoscopy StereoMode stereo_mode{}; bool stereo_per_eye_resolution_full = false; - int iStereoDepth = 0; - int iStereoConvergence = 0; - int iStereoConvergencePercentage = 0; + float stereo_depth = 0; + float stereo_convergence = 0; bool bStereoSwapEyes = false; bool bStereoEFBMonoDepth = false; - int iStereoDepthPercentage = 0; // D3D only config, mostly to be merged into the above int iAdapter = 0;