diff --git a/wled00/FX.h b/wled00/FX.h index ec6eef8a..a5d258e5 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -922,6 +922,7 @@ class WS2812FX { void setUpMatrix(), setPixelColorXY(uint16_t x, uint16_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), + setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = false), blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend), blur1d(CRGB* leds, fract8 blur_amount), blur1d(uint16_t i, bool vertical, fract8 blur_amount, CRGB* leds=nullptr), // 1D box blur (with weight) @@ -942,6 +943,8 @@ class WS2812FX { inline void setPixelColorXY(uint16_t x, uint16_t y, uint32_t c) { setPixelColorXY(x, y, byte(c>>16), byte(c>>8), byte(c), byte(c>>24)); } inline void setPixelColorXY(uint16_t x, uint16_t y, CRGB c) { setPixelColorXY(x, y, c.red, c.green, c.blue); } + inline void setPixelColorXY(float x, float y, uint32_t c, bool aa) { setPixelColorXY(x, y, byte(c>>16), byte(c>>8), byte(c), byte(c>>24), aa); } + inline void setPixelColorXY(float x, float y, CRGB c, bool aa) { setPixelColorXY(x, y, c.red, c.green, c.blue, 0, aa); } inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) { drawLine(x0, y0, x1, y1, CRGB(byte(c>>16), byte(c>>8), byte(c))); } inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint32_t c) { drawCharacter(chr, x, y, CRGB(byte(c>>16), byte(c>>8), byte(c))); } diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index bf91f1da..d5c7d226 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -184,6 +184,60 @@ void IRAM_ATTR WS2812FX::setPixelColorXY(uint16_t x, uint16_t y, byte r, byte g, } } +// anti-aliased version of setPixelColorXY() +void /*IRAM_ATTR*/ WS2812FX::setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w, bool aa) +{ + if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized + + const uint16_t cols = SEGMENT.virtualWidth(); + 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)); + uint32_t cXLYT = getPixelColorXY(xL, yT); + uint32_t cXRYT = getPixelColorXY(xR, yT); + uint32_t cXLYB = getPixelColorXY(xL, yB); + uint32_t cXRYB = getPixelColorXY(xR, yB); + + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + setPixelColorXY(xL, yB, R(cXLYB), G(cXLYB), B(cXLYB), W(cXLYB)); + } else { + // exact match (x & y land on a pixel) + setPixelColorXY(xL, yT, r, g, b, w); + } + } else { + setPixelColorXY((uint16_t)roundf(x * (cols-1)), (uint16_t)roundf(y * (rows-1)), r, g, b, w); + } +} + // returns RGBW values of pixel uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) { if (SEGMENT.getOption(SEG_OPTION_TRANSPOSED)) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed