Merge pull request #3904 from DedeHai/FX_fcn_improvements

added improvements to color scaling and blurring
This commit is contained in:
Blaž Kristan 2024-04-16 17:41:20 +02:00 committed by GitHub
commit d126611e87
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 90 additions and 70 deletions

View File

@ -582,7 +582,7 @@ typedef struct Segment {
#endif #endif
uint32_t getPixelColor(int i); uint32_t getPixelColor(int i);
// 1D support functions (some implement 2D as well) // 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 fill(uint32_t c);
void fade_out(uint8_t r); void fade_out(uint8_t r);
void fadeToBlackBy(uint8_t fadeBy); 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, 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); } 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 #endif
uint32_t getPixelColorXY(uint16_t x, uint16_t y); uint32_t getPixelColorXY(int x, int y);
// 2D support functions // 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, 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); } 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 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)); } 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 box_blur(uint16_t i, bool vertical, fract8 blur_amount); // 1D box blur (with weight)
void blurRow(uint16_t row, fract8 blur_amount); void blurRow(uint32_t row, fract8 blur_amount, bool smear = false);
void blurCol(uint16_t col, fract8 blur_amount); void blurCol(uint32_t col, fract8 blur_amount, bool smear = false);
void moveX(int8_t delta, bool wrap = false); void moveX(int8_t delta, bool wrap = false);
void moveY(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); 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 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 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 box_blur(uint16_t i, bool vertical, fract8 blur_amount) {}
inline void blurRow(uint16_t row, fract8 blur_amount) {} inline void blurRow(uint32_t row, fract8 blur_amount, bool smear = false) {}
inline void blurCol(uint16_t col, fract8 blur_amount) {} inline void blurCol(uint32_t col, fract8 blur_amount, bool smear = false) {}
inline void moveX(int8_t delta, bool wrap = false) {} inline void moveX(int8_t delta, bool wrap = false) {}
inline void moveY(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) {} inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {}

View File

@ -175,11 +175,7 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
uint8_t _bri_t = currentBri(); uint8_t _bri_t = currentBri();
if (_bri_t < 255) { if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t); col = color_fade(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);
} }
if (reverse ) x = virtualWidth() - x - 1; if (reverse ) x = virtualWidth() - x - 1;
@ -265,7 +261,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
#endif #endif
// returns RGBW values of pixel // 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 (!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 (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; 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 // 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 if (!isActive() || blur_amount == 0) return; // not active
const uint_fast16_t cols = virtualWidth(); const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight(); const uint_fast16_t rows = virtualHeight();
if (row >= rows) return; if (row >= rows) return;
// blur one row // blur one row
uint8_t keep = 255 - blur_amount; uint8_t keep = smear ? 255 : 255 - blur_amount;
uint8_t seep = blur_amount >> 1; 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++) { for (unsigned x = 0; x < cols; x++) {
CRGB cur = getPixelColorXY(x, row); uint32_t cur = getPixelColorXY(x, row);
CRGB before = cur; // remember color before blur uint32_t part = color_fade(cur, seep);
CRGB part = cur; curnew = color_fade(cur, keep);
part.nscale8(seep); if (x > 0) {
cur.nscale8(keep); if (carryover)
cur += carryover; curnew = color_add(curnew, carryover, true);
if (x>0) { uint32_t prev = color_add(lastnew, part, true);
CRGB prev = CRGB(getPixelColorXY(x-1, row)) + part; if (last != prev) // optimization: only set pixel if color has changed
setPixelColorXY(x-1, row, prev); setPixelColorXY(x - 1, row, prev);
} }
if (before != cur) // optimization: only set pixel if color has changed else // first pixel
setPixelColorXY(x, row, cur); setPixelColorXY(x, row, curnew);
lastnew = curnew;
last = cur; // save original value for comparison on next iteration
carryover = part; carryover = part;
} }
setPixelColorXY(cols-1, row, curnew); // set last pixel
} }
// blurCol: perform a blur on a column of a rectangular matrix // 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 if (!isActive() || blur_amount == 0) return; // not active
const uint_fast16_t cols = virtualWidth(); const uint_fast16_t cols = virtualWidth();
const uint_fast16_t rows = virtualHeight(); const uint_fast16_t rows = virtualHeight();
if (col >= cols) return; if (col >= cols) return;
// blur one column // blur one column
uint8_t keep = 255 - blur_amount; uint8_t keep = smear ? 255 : 255 - blur_amount;
uint8_t seep = blur_amount >> 1; 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++) { for (unsigned y = 0; y < rows; y++) {
CRGB cur = getPixelColorXY(col, y); uint32_t cur = getPixelColorXY(col, y);
CRGB part = cur; uint32_t part = color_fade(cur, seep);
CRGB before = cur; // remember color before blur curnew = color_fade(cur, keep);
part.nscale8(seep); if (y > 0) {
cur.nscale8(keep); if (carryover)
cur += carryover; curnew = color_add(curnew, carryover, true);
if (y>0) { uint32_t prev = color_add(lastnew, part, true);
CRGB prev = CRGB(getPixelColorXY(col, y-1)) + part; if (last != prev) // optimization: only set pixel if color has changed
setPixelColorXY(col, y-1, prev); setPixelColorXY(col, y - 1, prev);
} }
if (before != cur) // optimization: only set pixel if color has changed else // first pixel
setPixelColorXY(col, y, cur); setPixelColorXY(col, y, curnew);
carryover = part; 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]) // 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur])

View File

@ -735,11 +735,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
uint16_t len = length(); uint16_t len = length();
uint8_t _bri_t = currentBri(); uint8_t _bri_t = currentBri();
if (_bri_t < 255) { if (_bri_t < 255) {
byte r = scale8(R(col), _bri_t); col = color_fade(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);
} }
// expand pixel (taking into account start, grouping, spacing [and offset]) // 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 * 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" if (!isActive() || blur_amount == 0) return; // optimization: 0 means "don't blur"
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
if (is2D()) { if (is2D()) {
// compatibility with 2D // compatibility with 2D
const unsigned cols = virtualWidth(); const unsigned cols = virtualWidth();
const unsigned rows = virtualHeight(); const unsigned rows = virtualHeight();
for (unsigned i = 0; i < rows; i++) blurRow(i, blur_amount); // blur all rows 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); // blur all columns for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear); // blur all columns
return; return;
} }
#endif #endif
uint8_t keep = 255 - blur_amount; uint8_t keep = smear ? 255 : 255 - blur_amount;
uint8_t seep = blur_amount >> 1; uint8_t seep = blur_amount >> 1;
uint32_t carryover = BLACK;
unsigned vlength = virtualLength(); unsigned vlength = virtualLength();
uint32_t carryover = BLACK;
uint32_t lastnew;
uint32_t last;
uint32_t curnew;
for (unsigned i = 0; i < vlength; i++) { for (unsigned i = 0; i < vlength; i++) {
uint32_t cur = getPixelColor(i); uint32_t cur = getPixelColor(i);
uint32_t part = color_fade(cur, seep); uint32_t part = color_fade(cur, seep);
cur = color_add(color_fade(cur, keep), carryover, true); curnew = color_fade(cur, keep);
if (i > 0) { if (i > 0) {
uint32_t c = getPixelColor(i-1); if (carryover)
setPixelColor(i-1, color_add(c, part, true)); 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; carryover = part;
} }
setPixelColor(vlength - 1, curnew);
} }
/* /*

View File

@ -65,24 +65,30 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast)
* fades color toward black * fades color toward black
* if using "video" method the resulting color will never become black unless it is already 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) uint32_t color_fade(uint32_t c1, uint8_t amount, bool video)
{ {
uint8_t r = R(c1); uint32_t scaledcolor; // color order is: W R G B from MSB to LSB
uint8_t g = G(c1); uint32_t r = R(c1);
uint8_t b = B(c1); uint32_t g = G(c1);
uint8_t w = W(c1); uint32_t b = B(c1);
if (video) { uint32_t w = W(c1);
r = scale8_video(r, amount); if (video) {
g = scale8_video(g, amount); uint32_t scale = amount; // 32bit for faster calculation
b = scale8_video(b, amount); scaledcolor = (((r * scale) >> 8) << 16) + ((r && scale) ? 1 : 0);
w = scale8_video(w, amount); scaledcolor |= (((g * scale) >> 8) << 8) + ((g && scale) ? 1 : 0);
} else { scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0);
r = scale8(r, amount); scaledcolor |= (((w * scale) >> 8) << 24) + ((w && scale) ? 1 : 0);
g = scale8(g, amount); return scaledcolor;
b = scale8(b, amount); }
w = scale8(w, amount); 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) void setRandomColor(byte* rgb)