diff --git a/wled00/FXparticleSystem.cpp b/wled00/FXparticleSystem.cpp index 85264b7f1..bc6641744 100644 --- a/wled00/FXparticleSystem.cpp +++ b/wled00/FXparticleSystem.cpp @@ -584,7 +584,7 @@ void ParticleSystem2D::render() { continue; // generate RGB values for particle if (fireIntesity) { // fire mode - brightness = (uint32_t)particles[i].ttl * (3 + (fireIntesity >> 5)) + 20; + brightness = (uint32_t)particles[i].ttl * (3 + (fireIntesity >> 5)) + 5; brightness = min(brightness, (uint32_t)255); baseRGB = ColorFromPaletteWLED(SEGPALETTE, brightness, 255, LINEARBLEND_NOWRAP); } @@ -600,6 +600,7 @@ void ParticleSystem2D::render() { baseRGB = (CRGB)tempcolor; } } + brightness = gamma8(brightness); // apply gamma correction, used for gamma-inverted brightness distribution renderParticle(i, brightness, baseRGB, particlesettings.wrapX, particlesettings.wrapY); } @@ -676,6 +677,14 @@ __attribute__((optimize("O2"))) void ParticleSystem2D::renderParticle(const uint pxlbrightness[1] = (dx * precal2) >> PS_P_SURFACE; // bottom right value equal to (dx * (PS_P_RADIUS-dy) * brightness) >> PS_P_SURFACE pxlbrightness[2] = (dx * precal3) >> PS_P_SURFACE; // top right value equal to (dx * dy * brightness) >> PS_P_SURFACE pxlbrightness[3] = (precal1 * precal3) >> PS_P_SURFACE; // top left value equal to ((PS_P_RADIUS-dx) * dy * brightness) >> PS_P_SURFACE + // adjust brightness such that distribution is linear after gamma correction: + // - scale brigthness with gamma correction (done in render()) + // - apply inverse gamma correction to brightness values + // - gamma is applied again in show() -> the resulting brightness distribution is linear but gamma corrected in total + pxlbrightness[0] = gamma8inv(pxlbrightness[0]); // use look-up-table for invers gamma + pxlbrightness[1] = gamma8inv(pxlbrightness[1]); + pxlbrightness[2] = gamma8inv(pxlbrightness[2]); + pxlbrightness[3] = gamma8inv(pxlbrightness[3]); if (advPartProps && advPartProps[particleindex].size > 1) { //render particle to a bigger size CRGB renderbuffer[100]; // 10x10 pixel buffer @@ -1467,6 +1476,7 @@ void ParticleSystem1D::render() { baseRGB = (CRGB)tempcolor; } } + brightness = gamma8(brightness); // apply gamma correction, used for gamma-inverted brightness distribution renderParticle(i, brightness, baseRGB, particlesettings.wrap); } // apply smear-blur to rendered frame @@ -1534,6 +1544,12 @@ __attribute__((optimize("O2"))) void ParticleSystem1D::renderParticle(const uint //calculate the brightness values for both pixels using linear interpolation (note: in standard rendering out of frame pixels could be skipped but if checks add more clock cycles over all) pxlbrightness[0] = (((int32_t)PS_P_RADIUS_1D - dx) * brightness) >> PS_P_SURFACE_1D; pxlbrightness[1] = (dx * brightness) >> PS_P_SURFACE_1D; + // adjust brightness such that distribution is linear after gamma correction: + // - scale brigthness with gamma correction (done in render()) + // - apply inverse gamma correction to brightness values + // - gamma is applied again in show() -> the resulting brightness distribution is linear but gamma corrected in total + pxlbrightness[0] = gamma8inv(pxlbrightness[0]); // use look-up-table for invers gamma + pxlbrightness[1] = gamma8inv(pxlbrightness[1]); // check if particle has advanced size properties and buffer is available if (advPartProps && advPartProps[particleindex].size > 1) { diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index de4aa1182..72ace8dbf 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -532,7 +532,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { gammaCorrectBri = false; gammaCorrectCol = false; } - NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table + NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up tables JsonObject light_tr = light["tr"]; int tdd = light_tr["dur"] | -1; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 3b3d9ab70..ff6f3ab58 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -564,14 +564,17 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) { } } -// gamma lookup table used for color correction (filled on 1st use (cfg.cpp & set.cpp)) +// gamma lookup tables used for color correction (filled on 1st use (cfg.cpp & set.cpp)) uint8_t NeoGammaWLEDMethod::gammaT[256]; +uint8_t NeoGammaWLEDMethod::gammaT_inv[256]; -// re-calculates & fills gamma table +// re-calculates & fills gamma tables void NeoGammaWLEDMethod::calcGammaTable(float gamma) { + float gamma_inv = 1.0f / gamma; // inverse gamma for (size_t i = 0; i < 256; i++) { gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f); + gammaT_inv[i] = (int)(powf((float)i / 255.0f, gamma_inv) * 255.0f + 0.5f); } } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 486e5c562..8e4233f2c 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -158,13 +158,16 @@ class NeoGammaWLEDMethod { public: [[gnu::hot]] static uint8_t Correct(uint8_t value); // apply Gamma to single channel [[gnu::hot]] static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB) - static void calcGammaTable(float gamma); // re-calculates & fills gamma table + static void calcGammaTable(float gamma); // re-calculates & fills gamma tables static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB) + static inline uint8_t rawInverseGamma8(uint8_t val) { return gammaT_inv[val]; } // get value from inverse Gamma table (WLED specific, not used by NPB) private: static uint8_t gammaT[]; + static uint8_t gammaT_inv[]; }; #define gamma32(c) NeoGammaWLEDMethod::Correct32(c) #define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c) +#define gamma8inv(c) NeoGammaWLEDMethod::rawInverseGamma8(c) [[gnu::hot, gnu::pure]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend); inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); }; [[gnu::hot, gnu::pure]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false); diff --git a/wled00/set.cpp b/wled00/set.cpp index 038e84b41..6229ba28e 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -341,7 +341,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) gammaCorrectBri = false; gammaCorrectCol = false; } - NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table + NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up tables t = request->arg(F("TD")).toInt(); if (t >= 0) transitionDelayDefault = t;