Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions wled00/FX_fcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1766,19 +1766,14 @@ void WS2812FX::show() {
int oldCCT = Bus::getCCT(); // store original CCT value (since it is global)
// when cctFromRgb is true we implicitly calculate WW and CW from RGB values (cct==-1)
if (cctFromRgb) BusManager::setSegmentCCT(-1);
// use color gamma correction if enabled, not in realtime mode with gamma disabled or currently overriding RT mode
bool useGammaCorrection = gammaCorrectCol && !(realtimeMode && arlsDisableGammaCorrection && !realtimeOverride);

for (size_t i = 0; i < totalLen; i++) {
// when correctWB is true setSegmentCCT() will convert CCT into K with which we can then
// correct/adjust RGB value according to desired CCT value, it will still affect actual WW/CW ratio
if (_pixelCCT) { // cctFromRgb already exluded at allocation
if (i == 0 || _pixelCCT[i-1] != _pixelCCT[i]) BusManager::setSegmentCCT(_pixelCCT[i], correctWB);
}

uint32_t c = _pixels[i]; // need a copy, do not modify _pixels directly (no byte access allowed on ESP32)
if (c > 0 && useGammaCorrection)
c = gamma32(c); // apply gamma correction if enabled note: applying gamma after brightness has too much color loss
BusManager::setPixelColor(getMappedPixelIndex(i), c);
}
Bus::setCCT(oldCCT); // restore old CCT for ABL adjustments
Expand Down Expand Up @@ -1854,7 +1849,8 @@ void WS2812FX::setCCT(uint16_t k) {
// direct=true either expects the caller to call show() themselves (realtime modes) or be ok waiting for the next frame for the change to apply
// direct=false immediately triggers an effect redraw
void WS2812FX::setBrightness(uint8_t b, bool direct) {
if (gammaCorrectBri) b = gamma8(b);
if (b > 0 && gammaCorrectBri)
b = gamma8(map(b, 1, 255, gamma8inv(1), 255)); // map from 1 to 255 in gamma space or strip will turn off at low brightness as gamma(b) goes to 0
if (_brightness == b) return;
_brightness = b;
if (_brightness == 0) { //unfreeze all segments on power off
Expand Down
61 changes: 40 additions & 21 deletions wled00/bus_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,33 +266,44 @@ void BusDigital::setStatusPixel(uint32_t c) {
}
}

void BusDigital::setBrightness(uint8_t b) {
_bri = b;
if (_bri < 255 && applyGamma)
_bri = gamma8inv(_bri+1); // limit min brightness so gamma does not dim to black
}
Comment thread
DedeHai marked this conversation as resolved.

// note: using WLED_O2_ATTR makes this function ~7% faster at the expense of 600 bytes of flash
void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) {
if (!_valid) return;
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
if (_reversed) pix = _len - pix -1;
pix += _skip;
uint8_t cctWW = 0, cctCW = 0;
uint16_t wwcw = 0;
if (hasWhite()) c = autoWhiteCalc(c, cctWW, cctCW);
c = color_fade(c, _bri, true); // apply brightness

if (hasCCT()) {
wwcw = ((cctCW + 1) * _bri) & 0xFF00; // apply brightness to CCT (store CW in upper byte)
wwcw |= ((cctWW + 1) * _bri) >> 8;
if (_type == TYPE_WS2812_WWA) c = RGBW32(wwcw, wwcw >> 8, 0, W(c)); // ww,cw, 0, w
}
// apply brightness, color correction and white calculation, if black, we can skip all of it as they are no-ops
if (c > 0) {
c = color_fade(c, _bri, false); // apply brightness
c = gamma32(c); // apply gamma correction if (currently) used
if (!_valid) return;
Comment thread
DedeHai marked this conversation as resolved.
Outdated
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT

if (hasWhite()) c = autoWhiteCalc(c, cctWW, cctCW);

if (hasCCT()) {
wwcw = (cctCW + 1) & 0xFF00; // apply brightness to CCT (store CW in upper byte)
wwcw |= (cctWW + 1) >> 8;
if (_type == TYPE_WS2812_WWA) c = RGBW32(wwcw, wwcw >> 8, 0, W(c)); // ww,cw, 0, w
Comment thread
DedeHai marked this conversation as resolved.
Comment thread
DedeHai marked this conversation as resolved.
}

if (BusManager::_useABL) {
// if using ABL, sum all color channels to estimate current and limit brightness in show()
uint8_t r = R(c), g = G(c), b = B(c);
if (_milliAmpsPerLed < 255) { // normal ABL
_colorSum += r + g + b + W(c);
} else { // wacky WS2815 power model, ignore white channel, use max of RGB (issue #549)
_colorSum += ((r > g) ? ((r > b) ? r : b) : ((g > b) ? g : b));
if (BusManager::_useABL) {
// if using ABL, sum all color channels to estimate current and limit brightness in show()
uint8_t r = R(c), g = G(c), b = B(c);
if (_milliAmpsPerLed < 255) { // normal ABL
_colorSum += r + g + b + W(c);
} else { // wacky WS2815 power model, ignore white channel, use max of RGB (issue #549)
_colorSum += ((r > g) ? ((r > b) ? r : b) : ((g > b) ? g : b));
}
}
}

if (_reversed) pix = _len - pix -1;
pix += _skip;
const uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
unsigned pOld = pix;
Expand Down Expand Up @@ -469,6 +480,7 @@ BusPwm::BusPwm(const BusConfig &bc)

void BusPwm::setPixelColor(unsigned pix, uint32_t c) {
if (pix != 0 || !_valid) return; //only react to first pixel
c = gamma32(c); // apply gamma correction if (currently) used
Comment thread
DedeHai marked this conversation as resolved.
Outdated
if (Bus::_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) {
c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
}
Expand Down Expand Up @@ -560,8 +572,14 @@ void BusPwm::show() {
// for all other cases it will just try to "spread" the load on PSU
// Phase shifting requires that LEDC timers are synchronised (see setup()). For PWM CCT (and H-bridge) it is
// also mandatory that both channels use the same timer (pinManager takes care of that).
unsigned duty;
for (unsigned i = 0; i < numPins; i++) {
unsigned duty = (_data[i] * pwmBri) / 255;
unsigned duty;
if (applyGamma) {
duty = (unsigned)(powf((float)_data[i] / 255.0f, gammaCorrectVal) * pwmBri); // apply full resolution gamma correction: way more accurate than using gamma8(_data[i])
} else {
duty = (_data[i] * pwmBri) / 255;
}
unsigned deadTime = 0;

if (_type == TYPE_ANALOG_2CH && Bus::_cctBlend <= 0) {
Expand Down Expand Up @@ -714,6 +732,7 @@ BusNetwork::BusNetwork(const BusConfig &bc)
void BusNetwork::setPixelColor(unsigned pix, uint32_t c) {
if (!_valid || pix >= _len) return;
uint8_t ww, cw; // dummy, unused
// TODO: should gamma be applied here or better leave it to the receiver?
if (_hasWhite) c = autoWhiteCalc(c, ww, cw);
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
unsigned offset = pix * _UDPchannels;
Expand Down Expand Up @@ -1109,8 +1128,8 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.

void IRAM_ATTR BusHub75Matrix::setPixelColor(unsigned pix, uint32_t c) {
if (!_valid) return; // note: no need to check pix >= _len as that is checked in containsPixel()
c = gamma32(c); // apply gamma correction if (currently) used
// if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT

if (_ledBuffer) {
CRGB fastled_col = CRGB(c);
if (_ledBuffer[pix] != fastled_col) {
Expand Down
1 change: 1 addition & 0 deletions wled00/bus_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ class BusDigital : public Bus {
void show() override;
bool canShow() const override;
void setStatusPixel(uint32_t c) override;
void setBrightness(uint8_t b) override;
[[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override;
void setColorOrder(uint8_t colorOrder) override;
[[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override;
Expand Down
1 change: 1 addition & 0 deletions wled00/cfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
gammaCorrectBri = false;
gammaCorrectCol = false;
}
applyGamma = gammaCorrectCol; // apply gamma to colors if used
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up tables

JsonObject light_tr = light["tr"];
Expand Down
4 changes: 2 additions & 2 deletions wled00/colors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,13 +663,13 @@ void NeoGammaWLEDMethod::calcGammaTable(float gamma)

uint8_t NeoGammaWLEDMethod::Correct(uint8_t value)
{
if (!gammaCorrectCol) return value;
if (!applyGamma) return value; // gamma is (currently) disabled
return gammaT[value];
}

uint32_t NeoGammaWLEDMethod::inverseGamma32(uint32_t color)
{
if (!gammaCorrectCol) return color;
if (!applyGamma) return color;
uint8_t w = W(color);
uint8_t r = R(color);
uint8_t g = G(color);
Expand Down
5 changes: 3 additions & 2 deletions wled00/colors.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
struct CRGBW; // forward declations
struct CHSV32;

extern bool gammaCorrectCol;
extern bool applyGamma;
extern float gammaCorrectVal;
// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod)
class NeoGammaWLEDMethod {
public:
Expand All @@ -39,7 +40,7 @@ class NeoGammaWLEDMethod {
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)
static inline uint32_t Correct32(uint32_t color) { // apply Gamma to RGBW32 color (WLED specific, not used by NPB)
if (!gammaCorrectCol) return color; // no gamma correction
if (!applyGamma) return color; // gamma is (currently) disabled
uint8_t w = byte(color>>24), r = byte(color>>16), g = byte(color>>8), b = byte(color); // extract r, g, b, w channels
w = gammaT[w]; r = gammaT[r]; g = gammaT[g]; b = gammaT[b];
return (uint32_t(w) << 24) | (uint32_t(r) << 16) | (uint32_t(g) << 8) | uint32_t(b);
Expand Down
1 change: 1 addition & 0 deletions wled00/set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
gammaCorrectBri = false;
gammaCorrectCol = false;
}
applyGamma = gammaCorrectCol && !(realtimeMode && arlsDisableGammaCorrection && !realtimeOverride); // update gamma use (disable if needed)
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up tables

t = request->arg(F("TD")).toInt();
Expand Down
2 changes: 2 additions & 0 deletions wled00/udp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ void realtimeLock(uint32_t timeoutMs, byte md)
realtimeTimeout = (timeoutMs == 255001 || timeoutMs == 65000) ? UINT32_MAX : millis() + timeoutMs;
}
realtimeMode = md;
applyGamma = gammaCorrectCol && !(realtimeMode && arlsDisableGammaCorrection && !realtimeOverride); // update gamma use (disable if needed)

if (realtimeOverride) return;
if (arlsForceMaxBri) strip.setBrightness(255, true);
Expand All @@ -442,6 +443,7 @@ void realtimeLock(uint32_t timeoutMs, byte md)
void exitRealtime() {
if (!realtimeMode) return;
if (realtimeOverride == REALTIME_OVERRIDE_ONCE) realtimeOverride = REALTIME_OVERRIDE_NONE;
applyGamma = gammaCorrectCol; // reenable gamma if used
strip.setBrightness(bri, true);
realtimeTimeout = 0; // cancel realtime mode immediately
realtimeMode = REALTIME_MODE_INACTIVE; // inform UI immediately
Expand Down
1 change: 1 addition & 0 deletions wled00/wled.h
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ WLED_GLOBAL bool cctICused _INIT(true); // CCT IC used (Athom 15W bulb
WLED_GLOBAL bool cctICused _INIT(false); // CCT IC used (Athom 15W bulbs)
#endif
WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on colors
WLED_GLOBAL bool applyGamma _INIT(true); // apply gamma correction to colors if not (temporarily) disabled
WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness
WLED_GLOBAL float gammaCorrectVal _INIT(2.2f); // gamma correction value

Expand Down
Loading