From b3cc9ba02e370f71700a7866a4e57e19f6cb59f1 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Mon, 13 Apr 2026 13:06:14 -0600 Subject: [PATCH] Add "Bloom Mode" config option (Off, Classic, Dusk) --- include/dusk/config_var.hpp | 11 +++++++ include/dusk/settings.h | 16 +++++++++- src/dusk/config.cpp | 41 +++++++++++++++++++++++++- src/dusk/imgui/ImGuiFirstRunPreset.cpp | 3 ++ src/dusk/imgui/ImGuiMenuGame.cpp | 16 +++++++++- src/dusk/settings.cpp | 4 +-- src/m_Do/m_Do_graphic.cpp | 8 ++--- 7 files changed, 89 insertions(+), 10 deletions(-) diff --git a/include/dusk/config_var.hpp b/include/dusk/config_var.hpp index 6b78ee2e33..a480887fb2 100644 --- a/include/dusk/config_var.hpp +++ b/include/dusk/config_var.hpp @@ -146,6 +146,12 @@ concept ConfigValue = template const ConfigImplBase* GetConfigImpl(); +template +struct ConfigEnumRange { + static constexpr auto min = std::numeric_limits>::min(); + static constexpr auto max = std::numeric_limits>::max(); +}; + /** * \brief A CVar storing values. * @@ -189,6 +195,11 @@ public: } } + [[nodiscard]] constexpr const T& getDefaultValue() const noexcept { + checkRegistered(); + return defaultValue; + } + /** * \brief Change the value of a CVar. * diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 68ea49c752..3ec1bac876 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -7,6 +7,20 @@ namespace dusk { using namespace config; +enum class BloomMode : int { + Off = 0, + Classic = 1, + Dusk = 2, +}; + +namespace config { +template <> +struct ConfigEnumRange { + static constexpr auto min = BloomMode::Off; + static constexpr auto max = BloomMode::Dusk; +}; +} + // Persistent user settings struct UserSettings { @@ -53,7 +67,7 @@ struct UserSettings { ConfigVar invertCameraXAxis; // Graphics - ConfigVar enableBloom; + ConfigVar bloomMode; ConfigVar enableWaterRefraction; ConfigVar enableFrameInterpolation; ConfigVar shadowResolutionMultiplier; diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index 98f32cf8cd..c377d1ba54 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -5,6 +5,7 @@ #include "aurora/lib/logging.hpp" #include "dusk/io.hpp" +#include "dusk/settings.h" #include #include @@ -37,9 +38,24 @@ const ConfigImplBase* ConfigVarBase::getImpl() const noexcept { return impl; } +template +static T sanitizeEnumValue(const ConfigVar& cVar, T value) { + if constexpr (std::is_enum_v) { + using Underlying = std::underlying_type_t; + const Underlying raw = static_cast(value); + const Underlying min = static_cast(ConfigEnumRange::min); + const Underlying max = static_cast(ConfigEnumRange::max); + if (raw < min || raw > max) { + return cVar.getDefaultValue(); + } + } + + return value; +} + template void ConfigImpl::loadFromJson(ConfigVar& cVar, const json& jsonValue) { - cVar.setValue(jsonValue.get(), false); + cVar.setValue(sanitizeEnumValue(cVar, jsonValue.get()), false); } template @@ -85,6 +101,28 @@ static void loadFromArgImpl(ConfigVar& cVar, const std::string_view cVar.setOverrideValue(std::string(stringValue)); } +template requires std::is_enum_v +static void loadFromArgImpl(ConfigVar& cVar, const std::string_view stringValue) { + using Underlying = std::underlying_type_t; + const std::string str(stringValue); + + if constexpr (std::is_signed_v) { + const auto result = std::stoll(str); + if (result >= std::numeric_limits::min() && result <= std::numeric_limits::max()) { + cVar.setOverrideValue(sanitizeEnumValue(cVar, static_cast(result))); + } else { + throw std::out_of_range("Value is too large"); + } + } else { + const auto result = std::stoull(str); + if (result <= std::numeric_limits::max()) { + cVar.setOverrideValue(sanitizeEnumValue(cVar, static_cast(result))); + } else { + throw std::out_of_range("Value is too large"); + } + } +} + template void ConfigImpl::loadFromArg(ConfigVar& cVar, const std::string_view stringValue) { loadFromArgImpl(cVar, stringValue); @@ -115,6 +153,7 @@ namespace dusk::config { template class ConfigImpl; template class ConfigImpl; template class ConfigImpl; + template class ConfigImpl; } void dusk::config::Register(ConfigVarBase& configVar) { diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp index b73eaff6e6..99c77dac70 100644 --- a/src/dusk/imgui/ImGuiFirstRunPreset.cpp +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -12,11 +12,13 @@ namespace dusk { static void ApplyPresetClassic() { auto& s = getSettings(); s.video.lockAspectRatio.setValue(true); + s.game.bloomMode.setValue(BloomMode::Classic); VILockAspectRatio(defaultAspectRatioW, defaultAspectRatioH); } static void ApplyPresetHD() { auto& s = getSettings(); + s.game.bloomMode.setValue(BloomMode::Classic); s.game.hideTvSettingsScreen.setValue(true); s.game.skipWarningScreen.setValue(true); s.game.noReturnRupees.setValue(true); @@ -37,6 +39,7 @@ static void ApplyPresetDusk() { s.game.instantSaves.setValue(true); s.game.midnasLamentNonStop.setValue(true); s.game.enableFrameInterpolation.setValue(true); + s.game.bloomMode.setValue(BloomMode::Dusk); } // ========================================================================= diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index d2b893c884..3d658a5d10 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -62,7 +62,21 @@ namespace dusk { config::Save(); } - config::ImGuiCheckbox("Native Bloom", getSettings().game.enableBloom); + constexpr const char* bloomModeNames[] = {"Off", "Classic", "Dusk"}; + int bloomMode = static_cast(getSettings().game.bloomMode.getValue()); + if (ImGui::BeginCombo("Bloom", bloomModeNames[bloomMode])) { + for (int i = 0; i < IM_ARRAYSIZE(bloomModeNames); i++) { + const bool selected = bloomMode == i; + if (ImGui::Selectable(bloomModeNames[i], selected)) { + getSettings().game.bloomMode.setValue(static_cast(i)); + config::Save(); + } + if (selected) { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } config::ImGuiCheckbox("Enable Water Refraction", getSettings().game.enableWaterRefraction); diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 9d3d873acc..fbac3fc6d3 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -41,7 +41,7 @@ UserSettings g_userSettings = { .invertCameraXAxis {"game.invertCameraXAxis", false}, // Graphics - .enableBloom {"game.enableBloom", true}, + .bloomMode {"game.bloomMode", BloomMode::Classic}, .enableWaterRefraction {"game.enableWaterRefraction", true}, .enableFrameInterpolation = {"game.enableFrameInterpolation", false}, .shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1}, @@ -113,7 +113,7 @@ void registerSettings() { Register(g_userSettings.game.instantSaves); Register(g_userSettings.game.enableMirrorMode); Register(g_userSettings.game.invertCameraXAxis); - Register(g_userSettings.game.enableBloom); + Register(g_userSettings.game.bloomMode); Register(g_userSettings.game.enableWaterRefraction); Register(g_userSettings.game.shadowResolutionMultiplier); Register(g_userSettings.game.enableFastIronBoots); diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index 84a839fd4a..144ebd5873 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -1501,13 +1501,11 @@ void mDoGph_gInf_c::bloom_c::draw2() { void mDoGph_gInf_c::bloom_c::draw() { ZoneScoped; - if (!dusk::getSettings().game.enableBloom) { + if (dusk::getSettings().game.bloomMode.getValue() == dusk::BloomMode::Dusk) { + draw2(); return; } - - static bool s_bloom2 = false; - if (s_bloom2) { - draw2(); + if (dusk::getSettings().game.bloomMode.getValue() != dusk::BloomMode::Classic) { return; }