diff --git a/Source/DiabloUI/diabloui.cpp b/Source/DiabloUI/diabloui.cpp index 3191f6b01ed..29312d173a5 100644 --- a/Source/DiabloUI/diabloui.cpp +++ b/Source/DiabloUI/diabloui.cpp @@ -653,7 +653,7 @@ Sint16 GetCenterOffset(Sint16 w, Sint16 bw) void UiLoadDefaultPalette() { LoadPalette(gbIsHellfire ? "ui_art\\hellfire.pal" : "ui_art\\diablo.pal", /*blend=*/false); - ApplyGamma(logical_palette, orig_palette, 256); + ApplyToneMapping(logical_palette, orig_palette, 256); } bool UiLoadBlackBackground() @@ -673,7 +673,7 @@ void LoadBackgroundArt(const char *pszFile, int frames) return; LoadPalInMem(pPal); - ApplyGamma(logical_palette, orig_palette, 256); + ApplyToneMapping(logical_palette, orig_palette, 256); UiOnBackgroundChange(); } diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 48ff1d6b1dd..e5afd4a5f7b 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -1909,19 +1909,19 @@ void InitKeymapActions() SDLK_PAUSE, diablo_pause_game); options.Keymapper.AddAction( - "DecreaseGamma", - N_("Decrease Gamma"), + "DecreaseBrightness", + N_("Decrease Brightness"), N_("Reduce screen brightness."), - 'G', - DecreaseGamma, + 'F', + DecreaseBrightness, nullptr, CanPlayerTakeAction); options.Keymapper.AddAction( - "IncreaseGamma", - N_("Increase Gamma"), + "IncreaseBrightness", + N_("Increase Brightness"), N_("Increase screen brightness."), - 'F', - IncreaseGamma, + 'G', + IncreaseBrightness, nullptr, CanPlayerTakeAction); options.Keymapper.AddAction( @@ -2395,19 +2395,19 @@ void InitPadmapActions() ControllerButton_NONE, diablo_pause_game); options.Padmapper.AddAction( - "DecreaseGamma", - N_("Decrease Gamma"), + "DecreaseBrightness", + N_("Decrease Brightness"), N_("Reduce screen brightness."), ControllerButton_NONE, - DecreaseGamma, + DecreaseBrightness, nullptr, CanPlayerTakeAction); options.Padmapper.AddAction( - "IncreaseGamma", - N_("Increase Gamma"), + "IncreaseBrightness", + N_("Increase Brightness"), N_("Increase screen brightness."), ControllerButton_NONE, - IncreaseGamma, + IncreaseBrightness, nullptr, CanPlayerTakeAction); options.Padmapper.AddAction( diff --git a/Source/engine/palette.cpp b/Source/engine/palette.cpp index 3eb743e31ee..3dcf97f9cd1 100644 --- a/Source/engine/palette.cpp +++ b/Source/engine/palette.cpp @@ -40,11 +40,11 @@ namespace { /** Specifies whether the palette has max brightness. */ bool sgbFadedIn = true; -void LoadGamma() +void LoadBrightness() { - int gammaValue = *GetOptions().Graphics.gammaCorrection; - gammaValue = std::clamp(gammaValue, 30, 100); - GetOptions().Graphics.gammaCorrection.SetValue(gammaValue - gammaValue % 5); + int brightnessValue = *GetOptions().Graphics.brightness; + brightnessValue = std::clamp(brightnessValue, 0, 100); + GetOptions().Graphics.brightness.SetValue(brightnessValue - brightnessValue % 5); } Uint8 FindBestMatchForColor(std::array &palette, SDL_Color color, int skipFrom, int skipTo) @@ -183,21 +183,44 @@ void palette_update(int first, int ncolor) pal_surface_palette_version++; } -void ApplyGamma(std::array &dst, const std::array &src, int n) +// Applies a tone mapping curve based on the brightness slider value. +// The brightness value is in the range [0, 100] where 0 is neutral (no change) +// and 100 produces maximum brightening. +void ApplyToneMapping(std::array &dst, + const std::array &src, + int n) { - float g = *GetOptions().Graphics.gammaCorrection / 100.0F; + // Get the brightness slider value (0 = neutral, 100 = max brightening) + int brightnessSlider = *GetOptions().Graphics.brightness; // New brightness setting. + + // Maximum adjustment factor (tweak this constant to change the effect strength) + const float maxAdjustment = 2.0f; + // Compute the quadratic parameter: + // When brightnessSlider==0, then a==0 (identity mapping) + // When brightnessSlider==100, then a== -maxAdjustment (maximum brightening) + float a = -(brightnessSlider / 100.0f) * maxAdjustment; + + // Precompute a lookup table for speed. + uint8_t toneMap[256]; + for (int i = 0; i < 256; i++) { + float x = i / 255.0f; + // Our quadratic tone mapping: f(x) = a*x^2 + (1-a)*x. + const float y = std::clamp(a * x * x + (1.0f - a) * x, 0.0f, 1.0f); + toneMap[i] = static_cast(y * 255.0f + 0.5f); + } + // Apply the lookup table to each color channel in the palette. for (int i = 0; i < n; i++) { - dst[i].r = static_cast(pow(src[i].r / 256.0F, g) * 256.0F); - dst[i].g = static_cast(pow(src[i].g / 256.0F, g) * 256.0F); - dst[i].b = static_cast(pow(src[i].b / 256.0F, g) * 256.0F); + dst[i].r = toneMap[src[i].r]; + dst[i].g = toneMap[src[i].g]; + dst[i].b = toneMap[src[i].b]; } RedrawEverything(); } void palette_init() { - LoadGamma(); + LoadBrightness(); system_palette = orig_palette; InitPalette(); } @@ -267,34 +290,37 @@ void LoadRndLvlPal(dungeon_type l) LoadPalette(szFileName); } -void IncreaseGamma() +void IncreaseBrightness() { - int gammaValue = *GetOptions().Graphics.gammaCorrection; - if (gammaValue < 100) { - GetOptions().Graphics.gammaCorrection.SetValue(std::min(gammaValue + 5, 100)); - ApplyGamma(system_palette, logical_palette, 256); + int brightnessValue = *GetOptions().Graphics.brightness; + if (brightnessValue < 100) { + int newBrightness = std::min(brightnessValue + 5, 100); + GetOptions().Graphics.brightness.SetValue(newBrightness); + ApplyToneMapping(system_palette, logical_palette, 256); palette_update(); } } -void DecreaseGamma() +void DecreaseBrightness() { - int gammaValue = *GetOptions().Graphics.gammaCorrection; - if (gammaValue > 30) { - GetOptions().Graphics.gammaCorrection.SetValue(std::max(gammaValue - 5, 30)); - ApplyGamma(system_palette, logical_palette, 256); + int brightnessValue = *GetOptions().Graphics.brightness; + if (brightnessValue > 0) { + int newBrightness = std::max(brightnessValue - 5, 0); + GetOptions().Graphics.brightness.SetValue(newBrightness); + ApplyToneMapping(system_palette, logical_palette, 256); palette_update(); } } -int UpdateGamma(int gamma) +int UpdateBrightness(int brightness) { - if (gamma > 0) { - GetOptions().Graphics.gammaCorrection.SetValue(130 - gamma); - ApplyGamma(system_palette, logical_palette, 256); + if (brightness >= 0) { + GetOptions().Graphics.brightness.SetValue(brightness); + ApplyToneMapping(system_palette, logical_palette, 256); palette_update(); } - return 130 - *GetOptions().Graphics.gammaCorrection; + + return *GetOptions().Graphics.brightness; } void SetFadeLevel(int fadeval, bool updateHardwareCursor, const std::array &srcPalette) @@ -331,7 +357,7 @@ void PaletteFadeIn(int fr, const std::array &srcPalette) if (demo::IsRunning()) fr = 0; - ApplyGamma(logical_palette, srcPalette, 256); + ApplyToneMapping(logical_palette, srcPalette, 256); if (fr > 0) { const uint32_t tc = SDL_GetTicks(); @@ -434,7 +460,7 @@ void palette_update_quest_palette(int n) { int i = 32 - n; logical_palette[i] = orig_palette[i]; - ApplyGamma(system_palette, logical_palette, 32); + ApplyToneMapping(system_palette, logical_palette, 32); palette_update(0, 31); // Update blended transparency, but only for the color that was updated for (int j = 0; j < 256; j++) { diff --git a/Source/engine/palette.h b/Source/engine/palette.h index d84aab9e54b..4c8e6bc8360 100644 --- a/Source/engine/palette.h +++ b/Source/engine/palette.h @@ -57,10 +57,10 @@ void palette_update(int first = 0, int ncolor = 256); void palette_init(); void LoadPalette(const char *pszFileName, bool blend = true); void LoadRndLvlPal(dungeon_type l); -void IncreaseGamma(); -void ApplyGamma(std::array &dst, const std::array &src, int n); -void DecreaseGamma(); -int UpdateGamma(int gamma); +void IncreaseBrightness(); +void ApplyToneMapping(std::array &dst, const std::array &src, int n); +void DecreaseBrightness(); +int UpdateBrightness(int sliderValue); void BlackPalette(); void SetFadeLevel(int fadeval, bool updateHardwareCursor = true, const std::array &srcPalette = logical_palette); /** diff --git a/Source/gamemenu.cpp b/Source/gamemenu.cpp index 6ad584a4c9a..2cce3d8d66b 100644 --- a/Source/gamemenu.cpp +++ b/Source/gamemenu.cpp @@ -38,7 +38,7 @@ void GamemenuRestartTown(bool bActivate); void GamemenuOptions(bool bActivate); void GamemenuMusicVolume(bool bActivate); void GamemenuSoundVolume(bool bActivate); -void GamemenuGamma(bool bActivate); +void GamemenuBrightness(bool bActivate); void GamemenuSpeed(bool bActivate); /** Contains the game menu items of the single player menu. */ @@ -69,7 +69,7 @@ TMenuItem sgOptionsMenu[] = { // dwFlags, pszStr, fnMenu { GMENU_ENABLED | GMENU_SLIDER, nullptr, &GamemenuMusicVolume }, { GMENU_ENABLED | GMENU_SLIDER, nullptr, &GamemenuSoundVolume }, - { GMENU_ENABLED | GMENU_SLIDER, N_("Gamma"), &GamemenuGamma }, + { GMENU_ENABLED | GMENU_SLIDER, N_("Gamma"), &GamemenuBrightness }, { GMENU_ENABLED | GMENU_SLIDER, N_("Speed"), &GamemenuSpeed }, { GMENU_ENABLED , N_("Previous Menu"), &GamemenuPrevious }, { GMENU_ENABLED , nullptr, nullptr }, @@ -156,10 +156,10 @@ void GamemenuGetSound() GamemenuSoundMusicToggle(SoundToggleNames, &sgOptionsMenu[1], sound_get_or_set_sound_volume(1)); } -void GamemenuGetGamma() +void GamemenuGetBrightness() { - gmenu_slider_steps(&sgOptionsMenu[2], 15); - gmenu_slider_set(&sgOptionsMenu[2], 30, 100, UpdateGamma(0)); + gmenu_slider_steps(&sgOptionsMenu[2], 21); + gmenu_slider_set(&sgOptionsMenu[2], 0, 100, UpdateBrightness(-1)); } void GamemenuGetSpeed() @@ -184,16 +184,16 @@ void GamemenuGetSpeed() gmenu_slider_set(&sgOptionsMenu[3], 20, 50, sgGameInitInfo.nTickRate); } -int GamemenuSliderGamma() +int GamemenuSliderBrightness() { - return gmenu_slider_get(&sgOptionsMenu[2], 30, 100); + return gmenu_slider_get(&sgOptionsMenu[2], 0, 100); } void GamemenuOptions(bool /*bActivate*/) { GamemenuGetMusic(); GamemenuGetSound(); - GamemenuGetGamma(); + GamemenuGetBrightness(); GamemenuGetSpeed(); gmenu_set_items(sgOptionsMenu, nullptr); } @@ -254,21 +254,18 @@ void GamemenuSoundVolume(bool bActivate) GamemenuGetSound(); } -void GamemenuGamma(bool bActivate) +void GamemenuBrightness(bool bActivate) { - int gamma; + int brightness; if (bActivate) { - gamma = UpdateGamma(0); - if (gamma == 30) - gamma = 100; - else - gamma = 30; + brightness = UpdateBrightness(-1); + brightness = (brightness == 0) ? 100 : 0; } else { - gamma = GamemenuSliderGamma(); + brightness = GamemenuSliderBrightness(); } - UpdateGamma(gamma); - GamemenuGetGamma(); + UpdateBrightness(brightness); + GamemenuGetBrightness(); } void GamemenuSpeed(bool bActivate) diff --git a/Source/interfac.cpp b/Source/interfac.cpp index b7b09811e64..f456e0f472b 100644 --- a/Source/interfac.cpp +++ b/Source/interfac.cpp @@ -505,7 +505,7 @@ void ProgressEventHandler(const SDL_Event &event, uint16_t modState) if (RenderDirectlyToOutputSurface && PalSurface != nullptr) { // The loading thread sets `orig_palette`, so we make sure to use // our own palette for drawing the foreground. - ApplyGamma(logical_palette, ProgressEventHandlerState.palette, 256); + ApplyToneMapping(logical_palette, ProgressEventHandlerState.palette, 256); // Ensure that all back buffers have the full progress bar. const void *initialPixels = PalSurface->pixels; diff --git a/Source/options.cpp b/Source/options.cpp index 7942a57c4ad..6423d41fb40 100644 --- a/Source/options.cpp +++ b/Source/options.cpp @@ -672,7 +672,7 @@ GraphicsOptions::GraphicsOptions() #endif { FrameRateControl::CPUSleep, N_("Limit FPS") }, }) - , gammaCorrection("Gamma Correction", OptionEntryFlags::Invisible, "Gamma Correction", "Gamma correction level.", 100) + , brightness("Brightness Correction", OptionEntryFlags::Invisible, "Brightness Correction", "Brightness correction level.", 100) , zoom("Zoom", OptionEntryFlags::None, N_("Zoom"), N_("Zoom on when enabled."), false) , colorCycling("Color Cycling", OptionEntryFlags::None, N_("Color Cycling"), N_("Color cycling effect used for water, lava, and acid animation."), true) , alternateNestArt("Alternate nest art", OptionEntryFlags::OnlyHellfire | OptionEntryFlags::CantChangeInGame, N_("Alternate nest art"), N_("The game will use an alternative palette for Hellfire’s nest tileset."), false) @@ -701,7 +701,7 @@ std::vector GraphicsOptions::GetEntries() &integerScaling, #endif &frameRateControl, - &gammaCorrection, + &brightness, &zoom, &showFPS, &colorCycling, diff --git a/Source/options.h b/Source/options.h index 4cb09f44ebf..1c83e77e05b 100644 --- a/Source/options.h +++ b/Source/options.h @@ -526,8 +526,8 @@ struct GraphicsOptions : OptionCategoryBase { #endif /** @brief Limit frame rate either for vsync or CPU load. */ OptionEntryEnum frameRateControl; - /** @brief Gamma correction level. */ - OptionEntryInt gammaCorrection; + /** @brief Brightness level. */ + OptionEntryInt brightness; /** @brief Zoom on start. */ OptionEntryBoolean zoom; /** @brief Enable color cycling animations. */