From 3d29be24e089b1c267409f05b897ce3f03e99a07 Mon Sep 17 00:00:00 2001 From: Craig Robbins Date: Sun, 14 Dec 2014 21:28:08 +1000 Subject: [PATCH] Add display_gamma option for client --- minetest.conf.example | 6 ++- src/clientmap.cpp | 1 - src/defaultsettings.cpp | 1 + src/game.cpp | 2 + src/light.cpp | 98 +++++++++++++++++++++++++++++++++-------- src/light.h | 30 ++++++++----- src/mapnode.h | 12 +---- 7 files changed, 108 insertions(+), 42 deletions(-) diff --git a/minetest.conf.example b/minetest.conf.example index 95b88c84b..8570eb052 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -114,7 +114,11 @@ # Enable smooth lighting with simple ambient occlusion. # Disable for speed or for different looks. #smooth_lighting = true -# Path to texture directory. All textures are first searched from here. +# Adjust the gamma encoding for the light tables. Valid values are in the range +# 1.1 to 3.0 (inclusive); lower numbers are brighter. This setting is for the +# client only and is ignored by the server +#display_gamma = 1.8 +# Path to texture directory. All textures are first searched from here. #texture_path = # Video back-end. # Possible values: null, software, burningsvideo, direct3d8, direct3d9, opengl. diff --git a/src/clientmap.cpp b/src/clientmap.cpp index a5d364b73..0e53ab678 100644 --- a/src/clientmap.cpp +++ b/src/clientmap.cpp @@ -854,7 +854,6 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor, ret = decode_light(n.getLightBlend(daylight_factor, ndef)); } else { ret = oldvalue; - //ret = blend_light(255, 0, daylight_factor); } } else { /*float pre = (float)brightness_sum / (float)brightness_count; diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index b660912f9..f46260dab 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -108,6 +108,7 @@ void set_default_settings(Settings *settings) settings->setDefault("new_style_leaves", "true"); settings->setDefault("connected_glass", "false"); settings->setDefault("smooth_lighting", "true"); + settings->setDefault("display_gamma", "1.8"); settings->setDefault("texture_path", ""); settings->setDefault("shader_path", ""); settings->setDefault("video_driver", "opengl"); diff --git a/src/game.cpp b/src/game.cpp index 79dec17c6..5d44a7db5 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1747,6 +1747,8 @@ void Game::run() std::vector highlight_boxes; + set_light_table(g_settings->getFloat("display_gamma")); + while (device->run() && !(*kill || g_gamecallback->shutdown_requested)) { /* Must be called immediately after a device->run() call because it diff --git a/src/light.cpp b/src/light.cpp index 765c6303a..08380a180 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -18,31 +18,93 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "light.h" +#include +#include "util/numeric.h" + +#ifndef SERVER -#if 1 -// Middle-raised variation of a_n+1 = a_n * 0.786 // Length of LIGHT_MAX+1 means LIGHT_MAX is the last value. // LIGHT_SUN is read as LIGHT_MAX from here. -u8 light_decode_table[LIGHT_MAX+1] = + +u8 light_LUT[LIGHT_MAX+1] = { -8, -11+2, -14+7, -18+10, -22+15, -29+20, -37+20, -47+15, -60+10, -76+7, -97+5, -123+2, -157, -200, -255, + /* Middle-raised variation of a_n+1 = a_n * 0.786 + * Length of LIGHT_MAX+1 means LIGHT_MAX is the last value. + * LIGHT_SUN is read as LIGHT_MAX from here. + */ + 8, + 11+2, + 14+7, + 18+10, + 22+15, + 29+20, + 37+20, + 47+15, + 60+10, + 76+7, + 97+5, + 123+2, + 157, + 200, + 255, }; + +const u8 *light_decode_table = light_LUT; + +/** Initialize or update the light value tables using the specified \p gamma. + * If \p gamma == 1.0 then the light table is linear. Typically values for + * gamma range between 1.8 and 2.2. + * + * @note The value for gamma will be restricted to the range 1.1 <= gamma <= 3.0. + * + * @note This function is not, currently, a simple linear to gamma encoding + * because adjustments are made so that a gamma of 1.8 gives the same + * results as those hardcoded for use by the server. + */ +void set_light_table(float gamma) +{ + static const float brightness_step = 255.0f / (LIGHT_MAX + 1); + + /* These are adjustment values that are added to the calculated light value + * after gamma is applied. Currently they are used so that given a gamma + * of 1.8 the light values set by this function are the same as those + * hardcoded in the initalizer list for the declaration of light_LUT. + */ + static const int adjustments[LIGHT_MAX + 1] = { + 7, + 7, + 7, + 5, + 2, + 0, + -7, + -20, + -31, + -39, + -43, + -45, + -40, + -25, + 0 + }; + + gamma = rangelim(gamma, 1.1, 3.0); + + float brightness = brightness_step; + + for (size_t i = 0; i < LIGHT_MAX; i++) { + light_LUT[i] = (u8)(255 * powf(brightness / 255.0f, gamma)); + light_LUT[i] = rangelim(light_LUT[i] + adjustments[i], 0, 255); + if (i > 1 && light_LUT[i] < light_LUT[i-1]) + light_LUT[i] = light_LUT[i-1] + 1; + brightness += brightness_step; + } + light_LUT[LIGHT_MAX] = 255; +} #endif + + #if 0 /* Made using this and: diff --git a/src/light.h b/src/light.h index 769ca31ce..f49be4518 100644 --- a/src/light.h +++ b/src/light.h @@ -63,7 +63,21 @@ inline u8 undiminish_light(u8 light) return light + 1; } -extern u8 light_decode_table[LIGHT_MAX+1]; +#ifndef SERVER + +/** + * \internal + * + * \warning DO NOT USE this directly; it is here simply so that decode_light() + * can be inlined. + * + * Array size is #LIGHTMAX+1 + * + * The array is a lookup table to convert the internal representation of light + * (brightness) to the display brightness. + * + */ +extern const u8 *light_decode_table; // 0 <= light <= LIGHT_SUN // 0 <= return value <= 255 @@ -93,6 +107,10 @@ inline float decode_light_f(float light_f) return f * v2 + (1.0 - f) * v1; } +void set_light_table(float gamma); + +#endif // ifndef SERVER + // 0 <= daylight_factor <= 1000 // 0 <= lightday, lightnight <= LIGHT_SUN // 0 <= return value <= LIGHT_SUN @@ -105,15 +123,5 @@ inline u8 blend_light(u32 daylight_factor, u8 lightday, u8 lightnight) return l; } -// 0.0 <= daylight_factor <= 1.0 -// 0 <= lightday, lightnight <= LIGHT_SUN -// 0 <= return value <= 255 -inline u8 blend_light_f1(float daylight_factor, u8 lightday, u8 lightnight) -{ - u8 l = ((daylight_factor * decode_light(lightday) + - (1.0-daylight_factor) * decode_light(lightnight))); - return l; -} - #endif diff --git a/src/mapnode.h b/src/mapnode.h index e67724ec1..da6e9bdea 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -209,7 +209,7 @@ struct MapNode u8 getLightNoChecks(LightBank bank, const ContentFeatures *f); bool getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodemgr) const; - + // 0 <= daylight_factor <= 1000 // 0 <= return value <= LIGHT_SUN u8 getLightBlend(u32 daylight_factor, INodeDefManager *nodemgr) const @@ -220,16 +220,6 @@ struct MapNode return blend_light(daylight_factor, lightday, lightnight); } - // 0.0 <= daylight_factor <= 1.0 - // 0 <= return value <= LIGHT_SUN - u8 getLightBlendF1(float daylight_factor, INodeDefManager *nodemgr) const - { - u8 lightday = 0; - u8 lightnight = 0; - getLightBanks(lightday, lightnight, nodemgr); - return blend_light_f1(daylight_factor, lightday, lightnight); - } - u8 getFaceDir(INodeDefManager *nodemgr) const; u8 getWallMounted(INodeDefManager *nodemgr) const; v3s16 getWallMountedDir(INodeDefManager *nodemgr) const;