From 192c6175b848260c7eda75481447cf566b906fd2 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 17 Mar 2026 09:04:53 -0700 Subject: [PATCH] feat: add brightness slider to Video settings Black overlay dims below 50%, white overlay brightens above 50%. Persisted in settings.cfg, with restore-defaults support. --- include/rendering/renderer.hpp | 7 +++++++ include/ui/game_screen.hpp | 1 + src/rendering/renderer.cpp | 14 ++++++++++++++ src/ui/game_screen.cpp | 18 ++++++++++++++++++ 4 files changed, 40 insertions(+) diff --git a/include/rendering/renderer.hpp b/include/rendering/renderer.hpp index aed61820..07c6ebd6 100644 --- a/include/rendering/renderer.hpp +++ b/include/rendering/renderer.hpp @@ -381,6 +381,13 @@ private: void initOverlayPipeline(); void renderOverlay(const glm::vec4& color, VkCommandBuffer overrideCmd = VK_NULL_HANDLE); + // Brightness (1.0 = default, <1 darkens, >1 brightens) + float brightness_ = 1.0f; +public: + void setBrightness(float b) { brightness_ = b; } + float getBrightness() const { return brightness_; } +private: + // FSR 1.0 upscaling state struct FSRState { bool enabled = false; diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index 6c1244ae..75502dee 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -171,6 +171,7 @@ private: bool pendingShadows = true; float pendingShadowDistance = 300.0f; bool pendingWaterRefraction = false; + int pendingBrightness = 50; // 0-100, maps to 0.0-2.0 (50 = 1.0 default) int pendingMasterVolume = 100; int pendingMusicVolume = 30; int pendingAmbientVolume = 100; diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index f7f07e42..e20a0d6c 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -5287,6 +5287,13 @@ void Renderer::renderWorld(game::World* world, game::GameHandler* gameHandler) { renderOverlay(tint, cmd); } } + // Brightness overlay (applied before minimap so it doesn't affect UI) + if (brightness_ < 0.99f) { + renderOverlay(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f - brightness_), cmd); + } else if (brightness_ > 1.01f) { + float alpha = (brightness_ - 1.0f) / 1.0f; // maps 1.0-2.0 → 0.0-1.0 + renderOverlay(glm::vec4(1.0f, 1.0f, 1.0f, alpha), cmd); + } if (minimap && minimap->isEnabled() && camera && window) { glm::vec3 minimapCenter = camera->getPosition(); if (cameraController && cameraController->isThirdPerson()) @@ -5421,6 +5428,13 @@ void Renderer::renderWorld(game::World* world, game::GameHandler* gameHandler) { renderOverlay(tint); } } + // Brightness overlay (applied before minimap so it doesn't affect UI) + if (brightness_ < 0.99f) { + renderOverlay(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f - brightness_)); + } else if (brightness_ > 1.01f) { + float alpha = (brightness_ - 1.0f) / 1.0f; + renderOverlay(glm::vec4(1.0f, 1.0f, 1.0f, alpha)); + } if (minimap && minimap->isEnabled() && camera && window) { glm::vec3 minimapCenter = camera->getPosition(); if (cameraController && cameraController->isThirdPerson()) diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 64a6155e..1f62ac01 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -14900,6 +14900,16 @@ void GameScreen::renderSettingsWindow() { ImGui::Separator(); ImGui::Spacing(); + ImGui::SetNextItemWidth(200.0f); + if (ImGui::SliderInt("Brightness", &pendingBrightness, 0, 100, "%d%%")) { + if (renderer) renderer->setBrightness(static_cast(pendingBrightness) / 50.0f); + saveSettings(); + } + + ImGui::Spacing(); + ImGui::Separator(); + ImGui::Spacing(); + if (ImGui::Button("Restore Video Defaults", ImVec2(-1, 0))) { pendingFullscreen = kDefaultFullscreen; pendingVsync = kDefaultVsync; @@ -14912,9 +14922,11 @@ void GameScreen::renderSettingsWindow() { pendingPOM = true; pendingPOMQuality = 1; pendingResIndex = defaultResIndex; + pendingBrightness = 50; window->setFullscreen(pendingFullscreen); window->setVsync(pendingVsync); window->applyResolution(kResolutions[pendingResIndex][0], kResolutions[pendingResIndex][1]); + if (renderer) renderer->setBrightness(1.0f); pendingWaterRefraction = false; if (renderer) { renderer->setShadowsEnabled(pendingShadows); @@ -17284,6 +17296,7 @@ void GameScreen::saveSettings() { out << "ground_clutter_density=" << pendingGroundClutterDensity << "\n"; out << "shadows=" << (pendingShadows ? 1 : 0) << "\n"; out << "shadow_distance=" << pendingShadowDistance << "\n"; + out << "brightness=" << pendingBrightness << "\n"; out << "water_refraction=" << (pendingWaterRefraction ? 1 : 0) << "\n"; out << "antialiasing=" << pendingAntiAliasing << "\n"; out << "fxaa=" << (pendingFXAA ? 1 : 0) << "\n"; @@ -17428,6 +17441,11 @@ void GameScreen::loadSettings() { else if (key == "ground_clutter_density") pendingGroundClutterDensity = std::clamp(std::stoi(val), 0, 150); else if (key == "shadows") pendingShadows = (std::stoi(val) != 0); else if (key == "shadow_distance") pendingShadowDistance = std::clamp(std::stof(val), 40.0f, 500.0f); + else if (key == "brightness") { + pendingBrightness = std::clamp(std::stoi(val), 0, 100); + if (auto* r = core::Application::getInstance().getRenderer()) + r->setBrightness(static_cast(pendingBrightness) / 50.0f); + } else if (key == "water_refraction") pendingWaterRefraction = (std::stoi(val) != 0); else if (key == "antialiasing") pendingAntiAliasing = std::clamp(std::stoi(val), 0, 3); else if (key == "fxaa") pendingFXAA = (std::stoi(val) != 0);