diff --git a/wled00/FX.h b/wled00/FX.h index b672da34c..2fc5e77cc 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -709,12 +709,15 @@ class WS2812FX { makeAutoSegments(bool forceReset = false), fixInvalidSegments(), setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), + setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = false), show(void), setTargetFps(uint8_t fps), deserializeMap(uint8_t n=0); - inline void setPixelColor(uint16_t n, uint32_t c) {setPixelColor(n, byte(c>>16), byte(c>>8), byte(c), byte(c>>24));} - inline void setPixelColor(uint16_t n, CRGB &c) {setPixelColor(n, c.red, c.green, c.blue);} + inline void setPixelColor(uint16_t n, uint32_t c) {setPixelColor(n, byte(c>>16), byte(c>>8), byte(c), byte(c>>24));} + inline void setPixelColor(uint16_t n, CRGB c) {setPixelColor(n, c.red, c.green, c.blue);} + inline void setPixelColor(float i, uint32_t c, bool aa = false) {setPixelColor(i, byte(c>>16), byte(c>>8), byte(c), byte(c>>24), aa);} + inline void setPixelColor(float i, CRGB c, bool aa = false) {setPixelColor(i, c.red, c.green, c.blue, 0, aa);} bool gammaCorrectBri = false, @@ -768,6 +771,7 @@ class WS2812FX { color_wheel(uint8_t), color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255), color_blend(uint32_t,uint32_t,uint16_t,bool b16=false), + color_add(uint32_t,uint32_t), currentColor(uint32_t colorNew, uint8_t tNr), gamma32(uint32_t), getLastShow(void), diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index d5c7d2264..0df41723f 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -193,10 +193,16 @@ void /*IRAM_ATTR*/ WS2812FX::setPixelColorXY(float x, float y, byte r, byte g, b const uint16_t rows = SEGMENT.virtualHeight(); if (aa) { - uint16_t xL = floorf(x * (cols-1)); - uint16_t xR = ceilf(x * (cols-1)); - uint16_t yT = floorf(y * (rows-1)); - uint16_t yB = ceilf(y * (rows-1)); + float fX = x * (cols-1); + float fL = floorf(x * (cols-1)); + float fR = ceilf(x * (cols-1)); + float fY = y * (rows-1); + float fT = floorf(y * (rows-1)); + float fB = ceilf(y * (rows-1)); + uint16_t xL = fL; + uint16_t xR = fR; + uint16_t yT = fT; + uint16_t yB = fB; uint32_t cXLYT = getPixelColorXY(xL, yT); uint32_t cXRYT = getPixelColorXY(xR, yT); uint32_t cXLYB = getPixelColorXY(xL, yB); @@ -204,30 +210,30 @@ void /*IRAM_ATTR*/ WS2812FX::setPixelColorXY(float x, float y, byte r, byte g, b if (xL!=xR && yT!=yB) { // blend TL pixel - cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, sqrtf((x - floor(x))*(y - floorf(y)))*UINT16_MAX, true); + cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, sqrtf((fR - fX)*(fB - fY))*UINT16_MAX, true); setPixelColorXY(xR, yT, R(cXLYT), G(cXLYT), B(cXLYT), W(cXLYT)); // blend TR pixel - cXRYT = color_blend(RGBW32(r,g,b,w), cXRYT, sqrtf((ceilf(x) - x)*(y - floorf(y)))*UINT16_MAX, true); + cXRYT = color_blend(RGBW32(r,g,b,w), cXRYT, sqrtf((fX - fL)*(fB - fY))*UINT16_MAX, true); setPixelColorXY(xR, yT, R(cXRYT), G(cXRYT), B(cXRYT), W(cXRYT)); // blend BL pixel - cXLYB = color_blend(RGBW32(r,g,b,w), cXLYB, sqrtf((x - floor(x))*(ceil(y) - y))*UINT16_MAX, true); + cXLYB = color_blend(RGBW32(r,g,b,w), cXLYB, sqrtf((fR - fX)*(fY - fT))*UINT16_MAX, true); setPixelColorXY(xL, yB, R(cXLYB), G(cXLYB), B(cXLYB), W(cXLYB)); // blend BR pixel - cXRYB = color_blend(RGBW32(r,g,b,w), cXRYB, sqrtf((ceilf(x) - x)*(ceil(y) - y))*UINT16_MAX, true); + cXRYB = color_blend(RGBW32(r,g,b,w), cXRYB, sqrtf((fX - fL)*(fY - fT))*UINT16_MAX, true); setPixelColorXY(xR, yB, R(cXRYB), G(cXRYB), B(cXRYB), W(cXRYB)); } else if (xR!=xL && yT==yB) { // blend L pixel - cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, (x - floor(x))*UINT16_MAX, true); + cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, (fR - fX)*UINT16_MAX, true); setPixelColorXY(xR, yT, R(cXLYT), G(cXLYT), B(cXLYT), W(cXLYT)); // blend R pixel - cXRYT = color_blend(RGBW32(r,g,b,w), cXRYT, (ceilf(x) - x)*UINT16_MAX, true); + cXRYT = color_blend(RGBW32(r,g,b,w), cXRYT, (fX - fL)*UINT16_MAX, true); setPixelColorXY(xR, yT, R(cXRYT), G(cXRYT), B(cXRYT), W(cXRYT)); } else if (xR==xL && yT!=yB) { // blend T pixel - cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, (y - floorf(y))*UINT16_MAX, true); + cXLYT = color_blend(RGBW32(r,g,b,w), cXLYT, (fB - fY)*UINT16_MAX, true); setPixelColorXY(xR, yT, R(cXLYT), G(cXLYT), B(cXLYT), W(cXLYT)); // blend B pixel - cXLYB = color_blend(RGBW32(r,g,b,w), cXLYB, (ceil(y) - y)*UINT16_MAX, true); + cXLYB = color_blend(RGBW32(r,g,b,w), cXLYB, (fY - fT)*UINT16_MAX, true); setPixelColorXY(xL, yB, R(cXLYB), G(cXLYB), B(cXLYB), W(cXLYB)); } else { // exact match (x & y land on a pixel) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index f5bb3a4c0..d382942f2 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -182,6 +182,35 @@ void WS2812FX::service() { _triggered = false; } +// anti-aliased normalized version of setPixelColor() +void /*IRAM_ATTR*/ WS2812FX::setPixelColor(float i, byte r, byte g, byte b, byte w, bool aa) +{ + if (i<0.0f || i>1.0f) return; // not normalized + + if (aa) { + float fC = i * (SEGLEN-1); + float fL = floorf(i * (SEGLEN-1)); + float fR = ceilf(i * (SEGLEN-1)); + uint16_t iL = fL; + uint16_t iR = fR; + uint32_t cIL = getPixelColor(iL); + uint32_t cIR = getPixelColor(iR); + if (iR!=iL) { + // blend L pixel + cIL = color_blend(RGBW32(r,g,b,w), cIL, (fR - fC)*UINT16_MAX, true); + setPixelColor(iL, R(cIL), G(cIL), B(cIL), W(cIL)); + // blend R pixel + cIR = color_blend(RGBW32(r,g,b,w), cIR, (fC - fL)*UINT16_MAX, true); + setPixelColor(iR, R(cIR), G(cIR), B(cIR), W(cIR)); + } else { + // exact match (x & y land on a pixel) + setPixelColor(iL, r, g, b, w); + } + } else { + setPixelColor((uint16_t)roundf(i * (SEGLEN-1)), r, g, b, w); + } +} + void IRAM_ATTR WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) { uint8_t segIdx = SEGLEN ? _segment_index : _mainSegment; @@ -887,6 +916,24 @@ uint32_t IRAM_ATTR WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint1 return RGBW32(r3, g3, b3, w3); } +/* + * color add function that preserves ratio + * idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule + */ +uint32_t WS2812FX::color_add(uint32_t c1, uint32_t c2) +{ + uint32_t r = R(c1) + R(c2); + uint32_t g = G(c1) + G(c2); + uint32_t b = B(c1) + B(c2); + uint32_t w = W(c1) + W(c2); + uint16_t max = r; + if (g > max) max = g; + if (b > max) max = b; + if (w > max) max = w; + if (max < 256) return RGBW32(r, g, b, w); + else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max); +} + /* * Fills segment with color */