diff --git a/wled00/FX.h b/wled00/FX.h index 66e74860..106a6712 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -582,7 +582,7 @@ typedef struct Segment { #endif uint32_t getPixelColor(int i); // 1D support functions (some implement 2D as well) - void blur(uint8_t); + void blur(uint8_t, bool smear = false); void fill(uint32_t c); void fade_out(uint8_t r); void fadeToBlackBy(uint8_t fadeBy); @@ -610,7 +610,7 @@ typedef struct Segment { inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); } inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); } #endif - uint32_t getPixelColorXY(uint16_t x, uint16_t y); + uint32_t getPixelColorXY(int x, int y); // 2D support functions inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); } inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); } @@ -619,8 +619,8 @@ typedef struct Segment { inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), fast); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); } void box_blur(uint16_t i, bool vertical, fract8 blur_amount); // 1D box blur (with weight) - void blurRow(uint16_t row, fract8 blur_amount); - void blurCol(uint16_t col, fract8 blur_amount); + void blurRow(uint32_t row, fract8 blur_amount, bool smear = false); + void blurCol(uint32_t col, fract8 blur_amount, bool smear = false); void moveX(int8_t delta, bool wrap = false); void moveY(int8_t delta, bool wrap = false); void move(uint8_t dir, uint8_t delta, bool wrap = false); @@ -655,8 +655,8 @@ typedef struct Segment { inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), fast); } inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); } inline void box_blur(uint16_t i, bool vertical, fract8 blur_amount) {} - inline void blurRow(uint16_t row, fract8 blur_amount) {} - inline void blurCol(uint16_t col, fract8 blur_amount) {} + inline void blurRow(uint32_t row, fract8 blur_amount, bool smear = false) {} + inline void blurCol(uint32_t col, fract8 blur_amount, bool smear = false) {} inline void moveX(int8_t delta, bool wrap = false) {} inline void moveY(int8_t delta, bool wrap = false) {} inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {} diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index b049ab6f..5a73792b 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -175,11 +175,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col) uint8_t _bri_t = currentBri(); if (_bri_t < 255) { - byte r = scale8(R(col), _bri_t); - byte g = scale8(G(col), _bri_t); - byte b = scale8(B(col), _bri_t); - byte w = scale8(W(col), _bri_t); - col = RGBW32(r, g, b, w); + col = color_fade(col, _bri_t); } if (reverse ) x = virtualWidth() - x - 1; @@ -265,7 +261,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa) #endif // returns RGBW values of pixel -uint32_t IRAM_ATTR Segment::getPixelColorXY(uint16_t x, uint16_t y) { +uint32_t IRAM_ATTR Segment::getPixelColorXY(int x, int y) { if (!isActive()) return 0; // not active if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit if (reverse ) x = virtualWidth() - x - 1; @@ -278,59 +274,71 @@ uint32_t IRAM_ATTR Segment::getPixelColorXY(uint16_t x, uint16_t y) { } // blurRow: perform a blur on a row of a rectangular matrix -void Segment::blurRow(uint16_t row, fract8 blur_amount) { +void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){ if (!isActive() || blur_amount == 0) return; // not active const uint_fast16_t cols = virtualWidth(); const uint_fast16_t rows = virtualHeight(); if (row >= rows) return; // blur one row - uint8_t keep = 255 - blur_amount; + uint8_t keep = smear ? 255 : 255 - blur_amount; uint8_t seep = blur_amount >> 1; - CRGB carryover = CRGB::Black; + uint32_t carryover = BLACK; + uint32_t lastnew; + uint32_t last; + uint32_t curnew; for (unsigned x = 0; x < cols; x++) { - CRGB cur = getPixelColorXY(x, row); - CRGB before = cur; // remember color before blur - CRGB part = cur; - part.nscale8(seep); - cur.nscale8(keep); - cur += carryover; - if (x>0) { - CRGB prev = CRGB(getPixelColorXY(x-1, row)) + part; - setPixelColorXY(x-1, row, prev); + uint32_t cur = getPixelColorXY(x, row); + uint32_t part = color_fade(cur, seep); + curnew = color_fade(cur, keep); + if (x > 0) { + if (carryover) + curnew = color_add(curnew, carryover, true); + uint32_t prev = color_add(lastnew, part, true); + if (last != prev) // optimization: only set pixel if color has changed + setPixelColorXY(x - 1, row, prev); } - if (before != cur) // optimization: only set pixel if color has changed - setPixelColorXY(x, row, cur); + else // first pixel + setPixelColorXY(x, row, curnew); + lastnew = curnew; + last = cur; // save original value for comparison on next iteration carryover = part; } + setPixelColorXY(cols-1, row, curnew); // set last pixel } // blurCol: perform a blur on a column of a rectangular matrix -void Segment::blurCol(uint16_t col, fract8 blur_amount) { +void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { if (!isActive() || blur_amount == 0) return; // not active const uint_fast16_t cols = virtualWidth(); const uint_fast16_t rows = virtualHeight(); if (col >= cols) return; // blur one column - uint8_t keep = 255 - blur_amount; + uint8_t keep = smear ? 255 : 255 - blur_amount; uint8_t seep = blur_amount >> 1; - CRGB carryover = CRGB::Black; + uint32_t carryover = BLACK; + uint32_t lastnew; + uint32_t last; + uint32_t curnew; for (unsigned y = 0; y < rows; y++) { - CRGB cur = getPixelColorXY(col, y); - CRGB part = cur; - CRGB before = cur; // remember color before blur - part.nscale8(seep); - cur.nscale8(keep); - cur += carryover; - if (y>0) { - CRGB prev = CRGB(getPixelColorXY(col, y-1)) + part; - setPixelColorXY(col, y-1, prev); + uint32_t cur = getPixelColorXY(col, y); + uint32_t part = color_fade(cur, seep); + curnew = color_fade(cur, keep); + if (y > 0) { + if (carryover) + curnew = color_add(curnew, carryover, true); + uint32_t prev = color_add(lastnew, part, true); + if (last != prev) // optimization: only set pixel if color has changed + setPixelColorXY(col, y - 1, prev); } - if (before != cur) // optimization: only set pixel if color has changed - setPixelColorXY(col, y, cur); - carryover = part; + else // first pixel + setPixelColorXY(col, y, curnew); + lastnew = curnew; + last = cur; //save original value for comparison on next iteration + carryover = part; } + setPixelColorXY(col, rows - 1, curnew); } // 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur]) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 9ab1f578..f3f74ba2 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -735,11 +735,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col) uint16_t len = length(); uint8_t _bri_t = currentBri(); if (_bri_t < 255) { - byte r = scale8(R(col), _bri_t); - byte g = scale8(G(col), _bri_t); - byte b = scale8(B(col), _bri_t); - byte w = scale8(W(col), _bri_t); - col = RGBW32(r, g, b, w); + col = color_fade(col, _bri_t); } // expand pixel (taking into account start, grouping, spacing [and offset]) @@ -995,33 +991,43 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) { /* * blurs segment content, source: FastLED colorutils.cpp */ -void Segment::blur(uint8_t blur_amount) { +void Segment::blur(uint8_t blur_amount, bool smear) { if (!isActive() || blur_amount == 0) return; // optimization: 0 means "don't blur" #ifndef WLED_DISABLE_2D if (is2D()) { // compatibility with 2D const unsigned cols = virtualWidth(); const unsigned rows = virtualHeight(); - for (unsigned i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows - for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount); // blur all columns + for (unsigned i = 0; i < rows; i++) blurRow(i, blur_amount, smear); // blur all rows + for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear); // blur all columns return; } #endif - uint8_t keep = 255 - blur_amount; + uint8_t keep = smear ? 255 : 255 - blur_amount; uint8_t seep = blur_amount >> 1; - uint32_t carryover = BLACK; unsigned vlength = virtualLength(); + uint32_t carryover = BLACK; + uint32_t lastnew; + uint32_t last; + uint32_t curnew; for (unsigned i = 0; i < vlength; i++) { uint32_t cur = getPixelColor(i); uint32_t part = color_fade(cur, seep); - cur = color_add(color_fade(cur, keep), carryover, true); + curnew = color_fade(cur, keep); if (i > 0) { - uint32_t c = getPixelColor(i-1); - setPixelColor(i-1, color_add(c, part, true)); + if (carryover) + curnew = color_add(curnew, carryover, true); + uint32_t prev = color_add(lastnew, part, true); + if (last != prev) // optimization: only set pixel if color has changed + setPixelColor(i - 1, prev); } - setPixelColor(i, cur); + else // first pixel + setPixelColor(i, curnew); + lastnew = curnew; + last = cur; // save original value for comparison on next iteration carryover = part; } + setPixelColor(vlength - 1, curnew); } /* diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 3ed54d95..30d2c069 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -65,24 +65,30 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) * fades color toward black * if using "video" method the resulting color will never become black unless it is already black */ + uint32_t color_fade(uint32_t c1, uint8_t amount, bool video) { - uint8_t r = R(c1); - uint8_t g = G(c1); - uint8_t b = B(c1); - uint8_t w = W(c1); - if (video) { - r = scale8_video(r, amount); - g = scale8_video(g, amount); - b = scale8_video(b, amount); - w = scale8_video(w, amount); - } else { - r = scale8(r, amount); - g = scale8(g, amount); - b = scale8(b, amount); - w = scale8(w, amount); + uint32_t scaledcolor; // color order is: W R G B from MSB to LSB + uint32_t r = R(c1); + uint32_t g = G(c1); + uint32_t b = B(c1); + uint32_t w = W(c1); + if (video) { + uint32_t scale = amount; // 32bit for faster calculation + scaledcolor = (((r * scale) >> 8) << 16) + ((r && scale) ? 1 : 0); + scaledcolor |= (((g * scale) >> 8) << 8) + ((g && scale) ? 1 : 0); + scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0); + scaledcolor |= (((w * scale) >> 8) << 24) + ((w && scale) ? 1 : 0); + return scaledcolor; + } + else { + uint32_t scale = 1 + amount; + scaledcolor = ((r * scale) >> 8) << 16; + scaledcolor |= ((g * scale) >> 8) << 8; + scaledcolor |= (b * scale) >> 8; + scaledcolor |= ((w * scale) >> 8) << 24; + return scaledcolor; } - return RGBW32(r, g, b, w); } void setRandomColor(byte* rgb)