mirror of
https://github.com/wled/WLED.git
synced 2025-07-14 22:36:33 +00:00
Const and 2D box blur
- added 2D blur
This commit is contained in:
parent
db5e66a9b0
commit
cec67d8eff
@ -1226,15 +1226,18 @@ uint16_t mode_fireworks() {
|
||||
}
|
||||
SEGMENT.fade_out(128);
|
||||
|
||||
bool valid1 = (SEGENV.aux0 < width*height);
|
||||
bool valid2 = (SEGENV.aux1 < width*height);
|
||||
uint8_t x = SEGENV.aux0%width, y = SEGENV.aux0/width; // 2D coordinates stored in upper and lower byte
|
||||
uint32_t sv1 = 0, sv2 = 0;
|
||||
if (valid1) sv1 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color
|
||||
if (valid2) sv2 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux1);
|
||||
if (!SEGENV.step) SEGMENT.blur(16);
|
||||
if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur
|
||||
if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur
|
||||
if (!SEGENV.step) {
|
||||
// fireworks mode (blur flares)
|
||||
bool valid1 = (SEGENV.aux0 < width*height);
|
||||
bool valid2 = (SEGENV.aux1 < width*height);
|
||||
uint32_t sv1 = 0, sv2 = 0;
|
||||
if (valid1) sv1 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux0); // get spark color
|
||||
if (valid2) sv2 = SEGMENT.is2D() ? SEGMENT.getPixelColorXY(x, y) : SEGMENT.getPixelColor(SEGENV.aux1);
|
||||
SEGMENT.blur(16); // used in mode_rain()
|
||||
if (valid1) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv1); else SEGMENT.setPixelColor(SEGENV.aux0, sv1); } // restore spark color after blur
|
||||
if (valid2) { if (SEGMENT.is2D()) SEGMENT.setPixelColorXY(x, y, sv2); else SEGMENT.setPixelColor(SEGENV.aux1, sv2); } // restore old spark color after blur
|
||||
}
|
||||
|
||||
for (int i=0; i<max(1, width/20); i++) {
|
||||
if (random8(129 - (SEGMENT.intensity >> 1)) == 0) {
|
||||
@ -1261,7 +1264,7 @@ uint16_t mode_rain() {
|
||||
SEGENV.step += FRAMETIME;
|
||||
if (SEGENV.call && SEGENV.step > SPEED_FORMULA_L) {
|
||||
SEGENV.step = 1;
|
||||
if (strip.isMatrix) {
|
||||
if (SEGMENT.is2D()) {
|
||||
//uint32_t ctemp[width];
|
||||
//for (int i = 0; i<width; i++) ctemp[i] = SEGMENT.getPixelColorXY(i, height-1);
|
||||
SEGMENT.move(6, 1, true); // move all pixels down
|
||||
@ -3651,7 +3654,7 @@ uint16_t mode_exploding_fireworks(void)
|
||||
else SEGMENT.setPixelColor(int(sparks[i].posX) ? rows - int(sparks[i].pos) - 1 : int(sparks[i].pos), c.red, c.green, c.blue);
|
||||
}
|
||||
}
|
||||
SEGMENT.blur(16);
|
||||
if (SEGMENT.check3) SEGMENT.blur(16);
|
||||
*dying_gravity *= .8f; // as sparks burn out they fall slower
|
||||
} else {
|
||||
SEGENV.aux0 = 6 + random8(10); //wait for this many frames
|
||||
@ -3666,7 +3669,7 @@ uint16_t mode_exploding_fireworks(void)
|
||||
return FRAMETIME;
|
||||
}
|
||||
#undef MAX_SPARKS
|
||||
static const char _data_FX_MODE_EXPLODING_FIREWORKS[] PROGMEM = "Fireworks 1D@Gravity,Firing side;!,!;!;12;pal=11,ix=128";
|
||||
static const char _data_FX_MODE_EXPLODING_FIREWORKS[] PROGMEM = "Fireworks 1D@Gravity,Firing side,,,,,,Blur;!,!;!;12;pal=11,ix=128";
|
||||
|
||||
|
||||
/*
|
||||
@ -4890,11 +4893,11 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma
|
||||
// central white dot
|
||||
SEGMENT.setPixelColorXY(cols/2, rows/2, WHITE);
|
||||
// blur everything a bit
|
||||
SEGMENT.blur(cols*rows > 100 ? 16 : 0);
|
||||
if (SEGMENT.check3) SEGMENT.blur(16, cols*rows < 100);
|
||||
|
||||
return FRAMETIME;
|
||||
} // mode_2DBlackHole()
|
||||
static const char _data_FX_MODE_2DBLACKHOLE[] PROGMEM = "Black Hole@Fade rate,Outer Y freq.,Outer X freq.,Inner X freq.,Inner Y freq.,Solid;!;!;2;pal=11";
|
||||
static const char _data_FX_MODE_2DBLACKHOLE[] PROGMEM = "Black Hole@Fade rate,Outer Y freq.,Outer X freq.,Inner X freq.,Inner Y freq.,Solid,,Blur;!;!;2;pal=11";
|
||||
|
||||
|
||||
////////////////////////////
|
||||
@ -5636,7 +5639,7 @@ uint16_t mode_2DPulser(void) { // By: ldirko https://edi
|
||||
int y = map((sin8(a * 5) + sin8(a * 4) + sin8(a * 2)), 0, 765, rows-1, 0);
|
||||
SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, map(y, 0, rows-1, 0, 255), 255, LINEARBLEND));
|
||||
|
||||
SEGMENT.blur(1 + (SEGMENT.intensity>>4));
|
||||
SEGMENT.blur(SEGMENT.intensity>>4);
|
||||
|
||||
return FRAMETIME;
|
||||
} // mode_2DPulser()
|
||||
@ -6219,7 +6222,7 @@ uint16_t mode_2Ddriftrose(void) {
|
||||
uint32_t y = (CY + (cos_t(angle) * (beatsin8(i, 0, L*2)-L))) * 255.f;
|
||||
SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255));
|
||||
}
|
||||
SEGMENT.blur((SEGMENT.intensity>>4)+1);
|
||||
SEGMENT.blur(SEGMENT.intensity>>4);
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
@ -6475,11 +6478,11 @@ uint16_t mode_2DWaverly(void) {
|
||||
SEGMENT.addPixelColorXY((cols - 1) - i, (rows - 1) - j, ColorFromPalette(SEGPALETTE, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND));
|
||||
}
|
||||
}
|
||||
SEGMENT.blur(cols*rows > 100 ? 16 : 0);
|
||||
if (SEGMENT.check3) SEGMENT.blur(16, cols*rows < 100);
|
||||
|
||||
return FRAMETIME;
|
||||
} // mode_2DWaverly()
|
||||
static const char _data_FX_MODE_2DWAVERLY[] PROGMEM = "Waverly@Amplification,Sensitivity;;!;2v;ix=64,si=0"; // Beatsin
|
||||
static const char _data_FX_MODE_2DWAVERLY[] PROGMEM = "Waverly@Amplification,Sensitivity,,,,,Blur;;!;2v;ix=64,si=0"; // Beatsin
|
||||
|
||||
#endif // WLED_DISABLE_2D
|
||||
|
||||
|
75
wled00/FX.h
75
wled00/FX.h
@ -636,7 +636,8 @@ typedef struct Segment {
|
||||
inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), 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)); }
|
||||
void box_blur(uint16_t i, bool vertical, fract8 blur_amount); // 1D box blur (with weight)
|
||||
void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur
|
||||
void blur2D(uint8_t blur_amount, bool smear = false);
|
||||
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);
|
||||
@ -666,14 +667,15 @@ typedef struct Segment {
|
||||
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); }
|
||||
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||
#endif
|
||||
inline uint32_t getPixelColorXY(uint16_t x, uint16_t y) { return getPixelColor(x); }
|
||||
inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); }
|
||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
|
||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||
inline void addPixelColorXY(int x, int y, uint32_t color, bool fast = false) { addPixelColor(x, color, fast); }
|
||||
inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(x, RGBW32(r,g,b,w), 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 box_blur(uint16_t i, bool vertical, fract8 blur_amount) {}
|
||||
inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {}
|
||||
inline void blur2D(uint8_t blur_amount, bool smear = false) {}
|
||||
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) {}
|
||||
@ -800,56 +802,55 @@ class WS2812FX { // 96 bytes
|
||||
bool
|
||||
paletteFade,
|
||||
checkSegmentAlignment(void),
|
||||
hasRGBWBus(void),
|
||||
hasCCTBus(void),
|
||||
// return true if the strip is being sent pixel updates
|
||||
isUpdating(void),
|
||||
hasRGBWBus(void) const,
|
||||
hasCCTBus(void) const,
|
||||
isUpdating(void) const, // return true if the strip is being sent pixel updates
|
||||
deserializeMap(uint8_t n=0);
|
||||
|
||||
inline bool isServicing(void) { return _isServicing; } // returns true if strip.service() is executing
|
||||
inline bool hasWhiteChannel(void) { return _hasWhiteChannel; } // returns true if strip contains separate white chanel
|
||||
inline bool isOffRefreshRequired(void) { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset)
|
||||
inline bool isSuspended(void) { return _suspend; } // returns true if strip.service() execution is suspended
|
||||
inline bool needsUpdate(void) { return _triggered; } // returns true if strip received a trigger() request
|
||||
inline bool isServicing(void) const { return _isServicing; } // returns true if strip.service() is executing
|
||||
inline bool hasWhiteChannel(void) const { return _hasWhiteChannel; } // returns true if strip contains separate white chanel
|
||||
inline bool isOffRefreshRequired(void) const { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset)
|
||||
inline bool isSuspended(void) const { return _suspend; } // returns true if strip.service() execution is suspended
|
||||
inline bool needsUpdate(void) const { return _triggered; } // returns true if strip received a trigger() request
|
||||
|
||||
uint8_t
|
||||
paletteBlend,
|
||||
cctBlending,
|
||||
getActiveSegmentsNum(void),
|
||||
getFirstSelectedSegId(void),
|
||||
getLastActiveSegmentId(void),
|
||||
getActiveSegsLightCapabilities(bool selectedOnly = false);
|
||||
getActiveSegmentsNum(void) const,
|
||||
getFirstSelectedSegId(void) const,
|
||||
getLastActiveSegmentId(void) const,
|
||||
getActiveSegsLightCapabilities(bool selectedOnly = false) const;
|
||||
|
||||
inline uint8_t getBrightness(void) { return _brightness; } // returns current strip brightness
|
||||
inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
|
||||
inline uint8_t getSegmentsNum(void) { return _segments.size(); } // returns currently present segments
|
||||
inline uint8_t getCurrSegmentId(void) { return _segment_index; } // returns current segment index (only valid while strip.isServicing())
|
||||
inline uint8_t getMainSegmentId(void) { return _mainSegment; } // returns main segment index
|
||||
inline uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT + customPalettes.size(); }
|
||||
inline uint8_t getTargetFps() { return _targetFps; } // returns rough FPS value for las 2s interval
|
||||
inline uint8_t getModeCount() { return _modeCount; } // returns number of registered modes/effects
|
||||
inline uint8_t getBrightness(void) const { return _brightness; } // returns current strip brightness
|
||||
inline uint8_t getMaxSegments(void) const { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
|
||||
inline uint8_t getSegmentsNum(void) const { return _segments.size(); } // returns currently present segments
|
||||
inline uint8_t getCurrSegmentId(void) const { return _segment_index; } // returns current segment index (only valid while strip.isServicing())
|
||||
inline uint8_t getMainSegmentId(void) const { return _mainSegment; } // returns main segment index
|
||||
inline uint8_t getPaletteCount() const { return 13 + GRADIENT_PALETTE_COUNT + customPalettes.size(); }
|
||||
inline uint8_t getTargetFps() const { return _targetFps; } // returns rough FPS value for las 2s interval
|
||||
inline uint8_t getModeCount() const { return _modeCount; } // returns number of registered modes/effects
|
||||
|
||||
uint16_t
|
||||
getLengthPhysical(void),
|
||||
getLengthTotal(void), // will include virtual/nonexistent pixels in matrix
|
||||
getFps(),
|
||||
getMappedPixelIndex(uint16_t index);
|
||||
getLengthPhysical(void) const,
|
||||
getLengthTotal(void) const, // will include virtual/nonexistent pixels in matrix
|
||||
getFps() const,
|
||||
getMappedPixelIndex(uint16_t index) const;
|
||||
|
||||
inline uint16_t getFrameTime(void) { return _frametime; } // returns amount of time a frame should take (in ms)
|
||||
inline uint16_t getMinShowDelay(void) { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
|
||||
inline uint16_t getLength(void) { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
|
||||
inline uint16_t getTransition(void) { return _transitionDur; } // returns currently set transition time (in ms)
|
||||
inline uint16_t getFrameTime(void) const { return _frametime; } // returns amount of time a frame should take (in ms)
|
||||
inline uint16_t getMinShowDelay(void) const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
|
||||
inline uint16_t getLength(void) const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
|
||||
inline uint16_t getTransition(void) const { return _transitionDur; } // returns currently set transition time (in ms)
|
||||
|
||||
uint32_t
|
||||
now,
|
||||
timebase,
|
||||
getPixelColor(uint16_t);
|
||||
getPixelColor(uint16_t) const;
|
||||
|
||||
inline uint32_t getLastShow(void) { return _lastShow; } // returns millis() timestamp of last strip.show() call
|
||||
inline uint32_t segColor(uint8_t i) { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition
|
||||
inline uint32_t getLastShow(void) const { return _lastShow; } // returns millis() timestamp of last strip.show() call
|
||||
inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition
|
||||
|
||||
const char *
|
||||
getModeData(uint8_t id = 0) { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); }
|
||||
getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); }
|
||||
|
||||
const char **
|
||||
getModeDataSrc(void) { return &(_modeData[0]); } // vectors use arrays for underlying data
|
||||
@ -900,7 +901,7 @@ class WS2812FX { // 96 bytes
|
||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
||||
|
||||
inline uint32_t getPixelColorXY(uint16_t x, uint16_t y) { return getPixelColor(isMatrix ? y * Segment::maxWidth + x : x);}
|
||||
inline uint32_t getPixelColorXY(int x, int y) const { return getPixelColor(isMatrix ? y * Segment::maxWidth + x : x); }
|
||||
|
||||
// end 2D support
|
||||
|
||||
|
@ -184,13 +184,16 @@ void IRAM_ATTR Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
|
||||
x *= groupLength(); // expand to physical pixels
|
||||
y *= groupLength(); // expand to physical pixels
|
||||
if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit
|
||||
|
||||
unsigned W = width();
|
||||
unsigned H = height();
|
||||
if (x >= W || y >= H) return; // if pixel would fall out of segment just exit
|
||||
|
||||
uint32_t tmpCol = col;
|
||||
for (int j = 0; j < grouping; j++) { // groupping vertically
|
||||
for (int g = 0; g < grouping; g++) { // groupping horizontally
|
||||
for (unsigned j = 0; j < grouping; j++) { // groupping vertically
|
||||
for (unsigned g = 0; g < grouping; g++) { // groupping horizontally
|
||||
unsigned xX = (x+g), yY = (y+j);
|
||||
if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end
|
||||
if (xX >= W || yY >= H) continue; // we have reached one dimension's end
|
||||
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
// if blending modes, blend with underlying pixel
|
||||
@ -339,39 +342,126 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) {
|
||||
setPixelColorXY(col, rows - 1, curnew);
|
||||
}
|
||||
|
||||
// 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur])
|
||||
void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
|
||||
void Segment::blur2D(uint8_t blur_amount, bool smear) {
|
||||
if (!isActive() || blur_amount == 0) return; // not active
|
||||
const int cols = virtualWidth();
|
||||
const int rows = virtualHeight();
|
||||
const int dim1 = vertical ? rows : cols;
|
||||
const int dim2 = vertical ? cols : rows;
|
||||
if (i >= dim2) return;
|
||||
const float seep = blur_amount/255.f;
|
||||
const float keep = 3.f - 2.f*seep;
|
||||
// 1D box blur
|
||||
uint32_t out[dim1], in[dim1];
|
||||
for (int j = 0; j < dim1; j++) {
|
||||
int x = vertical ? i : j;
|
||||
int y = vertical ? j : i;
|
||||
in[j] = getPixelColorXY(x, y);
|
||||
const unsigned cols = virtualWidth();
|
||||
const unsigned rows = virtualHeight();
|
||||
|
||||
const uint8_t keep = smear ? 255 : 255 - blur_amount;
|
||||
const uint8_t seep = blur_amount >> (1 + smear);
|
||||
uint32_t lastnew;
|
||||
uint32_t last;
|
||||
for (unsigned row = 0; row < rows; row++) {
|
||||
uint32_t carryover = BLACK;
|
||||
uint32_t curnew = BLACK;
|
||||
for (unsigned x = 0; x < cols; x++) {
|
||||
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);
|
||||
// optimization: only set pixel if color has changed
|
||||
if (last != prev) setPixelColorXY(x - 1, row, prev);
|
||||
} else setPixelColorXY(x, row, curnew); // first pixel
|
||||
lastnew = curnew;
|
||||
last = cur; // save original value for comparison on next iteration
|
||||
carryover = part;
|
||||
}
|
||||
setPixelColorXY(cols-1, row, curnew); // set last pixel
|
||||
}
|
||||
for (int j = 0; j < dim1; j++) {
|
||||
uint32_t curr = in[j];
|
||||
uint32_t prev = j > 0 ? in[j-1] : BLACK;
|
||||
uint32_t next = j < dim1-1 ? in[j+1] : BLACK;
|
||||
uint8_t r, g, b, w;
|
||||
r = (R(curr)*keep + (R(prev) + R(next))*seep) / 3;
|
||||
g = (G(curr)*keep + (G(prev) + G(next))*seep) / 3;
|
||||
b = (B(curr)*keep + (B(prev) + B(next))*seep) / 3;
|
||||
w = (W(curr)*keep + (W(prev) + W(next))*seep) / 3;
|
||||
out[j] = RGBW32(r,g,b,w);
|
||||
for (unsigned col = 0; col < cols; col++) {
|
||||
uint32_t carryover = BLACK;
|
||||
uint32_t curnew = BLACK;
|
||||
for (unsigned y = 0; y < rows; y++) {
|
||||
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);
|
||||
// optimization: only set pixel if color has changed
|
||||
if (last != prev) setPixelColorXY(col, y - 1, prev);
|
||||
} else setPixelColorXY(col, y, curnew); // first pixel
|
||||
lastnew = curnew;
|
||||
last = cur; //save original value for comparison on next iteration
|
||||
carryover = part;
|
||||
}
|
||||
setPixelColorXY(col, rows - 1, curnew);
|
||||
}
|
||||
for (int j = 0; j < dim1; j++) {
|
||||
int x = vertical ? i : j;
|
||||
int y = vertical ? j : i;
|
||||
setPixelColorXY(x, y, out[j]);
|
||||
}
|
||||
|
||||
// 2D Box blur
|
||||
void Segment::box_blur(unsigned radius, bool smear) {
|
||||
if (!isActive() || radius == 0) return; // not active
|
||||
if (radius > 3) radius = 3;
|
||||
const unsigned d = (1 + 2*radius) * (1 + 2*radius); // averaging divisor
|
||||
const unsigned cols = virtualWidth();
|
||||
const unsigned rows = virtualHeight();
|
||||
uint16_t *tmpRSum = new uint16_t[cols*rows];
|
||||
uint16_t *tmpGSum = new uint16_t[cols*rows];
|
||||
uint16_t *tmpBSum = new uint16_t[cols*rows];
|
||||
uint16_t *tmpWSum = new uint16_t[cols*rows];
|
||||
// fill summed-area table (https://en.wikipedia.org/wiki/Summed-area_table)
|
||||
for (unsigned x = 0; x < cols; x++) {
|
||||
unsigned rS, gS, bS, wS;
|
||||
unsigned index;
|
||||
rS = gS = bS = wS = 0;
|
||||
for (unsigned y = 0; y < rows; y++) {
|
||||
index = x * cols + y;
|
||||
if (x > 0) {
|
||||
unsigned index2 = (x - 1) * cols + y;
|
||||
tmpRSum[index] = tmpRSum[index2];
|
||||
tmpGSum[index] = tmpGSum[index2];
|
||||
tmpBSum[index] = tmpBSum[index2];
|
||||
tmpWSum[index] = tmpWSum[index2];
|
||||
} else {
|
||||
tmpRSum[index] = 0;
|
||||
tmpGSum[index] = 0;
|
||||
tmpBSum[index] = 0;
|
||||
tmpWSum[index] = 0;
|
||||
}
|
||||
uint32_t c = getPixelColorXY(x, y);
|
||||
rS += R(c);
|
||||
gS += G(c);
|
||||
bS += B(c);
|
||||
wS += W(c);
|
||||
tmpRSum[index] += rS;
|
||||
tmpGSum[index] += gS;
|
||||
tmpBSum[index] += bS;
|
||||
tmpWSum[index] += wS;
|
||||
}
|
||||
}
|
||||
// do a box blur using pre-calculated sums
|
||||
for (unsigned x = 0; x < cols; x++) {
|
||||
for (unsigned y = 0; y < rows; y++) {
|
||||
// sum = D + A - B - C where k = (x,y)
|
||||
// +----+-+---- (x)
|
||||
// | | |
|
||||
// +----A-B
|
||||
// | |k|
|
||||
// +----C-D
|
||||
// |
|
||||
//(y)
|
||||
unsigned x0 = x < radius ? 0 : x - radius;
|
||||
unsigned y0 = y < radius ? 0 : y - radius;
|
||||
unsigned x1 = x >= cols - radius ? cols - 1 : x + radius;
|
||||
unsigned y1 = y >= rows - radius ? rows - 1 : y + radius;
|
||||
unsigned A = x0 * cols + y0;
|
||||
unsigned B = x1 * cols + y0;
|
||||
unsigned C = x0 * cols + y1;
|
||||
unsigned D = x1 * cols + y1;
|
||||
unsigned r = tmpRSum[D] + tmpRSum[A] - tmpRSum[C] - tmpRSum[B];
|
||||
unsigned g = tmpGSum[D] + tmpGSum[A] - tmpGSum[C] - tmpGSum[B];
|
||||
unsigned b = tmpBSum[D] + tmpBSum[A] - tmpBSum[C] - tmpBSum[B];
|
||||
unsigned w = tmpWSum[D] + tmpWSum[A] - tmpWSum[C] - tmpWSum[B];
|
||||
setPixelColorXY(x, y, RGBW32(r/d, g/d, b/d, w/d));
|
||||
}
|
||||
}
|
||||
delete[] tmpRSum;
|
||||
delete[] tmpGSum;
|
||||
delete[] tmpBSum;
|
||||
delete[] tmpWSum;
|
||||
}
|
||||
|
||||
void Segment::moveX(int8_t delta, bool wrap) {
|
||||
|
@ -954,9 +954,9 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i) const
|
||||
if (reverse) i = virtualLength() - i - 1;
|
||||
i *= groupLength();
|
||||
i += start;
|
||||
/* offset/phase */
|
||||
// offset/phase
|
||||
i += offset;
|
||||
if ((i >= stop) && (stop>0)) i -= length(); // avoids negative pixel index (stop = 0 is a possible value)
|
||||
if (i >= stop) i -= length();
|
||||
return strip.getPixelColor(i);
|
||||
}
|
||||
|
||||
@ -1110,15 +1110,13 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
|
||||
#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, smear); // blur all rows
|
||||
for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear); // blur all columns
|
||||
blur2D(blur_amount, smear);
|
||||
//box_blur(map(blur_amount,1,255,1,3), smear);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
uint8_t keep = smear ? 255 : 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
uint8_t seep = blur_amount >> (1 + smear);
|
||||
unsigned vlength = virtualLength();
|
||||
uint32_t carryover = BLACK;
|
||||
uint32_t lastnew;
|
||||
@ -1129,13 +1127,11 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
|
||||
uint32_t part = color_fade(cur, seep);
|
||||
curnew = color_fade(cur, keep);
|
||||
if (i > 0) {
|
||||
if (carryover)
|
||||
curnew = color_add(curnew, carryover, 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);
|
||||
}
|
||||
else // first pixel
|
||||
// optimization: only set pixel if color has changed
|
||||
if (last != prev) setPixelColor(i - 1, prev);
|
||||
} else // first pixel
|
||||
setPixelColor(i, curnew);
|
||||
lastnew = curnew;
|
||||
last = cur; // save original value for comparison on next iteration
|
||||
@ -1357,7 +1353,7 @@ void IRAM_ATTR WS2812FX::setPixelColor(unsigned i, uint32_t col) {
|
||||
BusManager::setPixelColor(i, col);
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) {
|
||||
uint32_t IRAM_ATTR WS2812FX::getPixelColor(uint16_t i) const {
|
||||
i = getMappedPixelIndex(i);
|
||||
if (i >= _length) return 0;
|
||||
return BusManager::getPixelColor(i);
|
||||
@ -1385,7 +1381,7 @@ void WS2812FX::show(void) {
|
||||
* Returns a true value if any of the strips are still being updated.
|
||||
* On some hardware (ESP32), strip updates are done asynchronously.
|
||||
*/
|
||||
bool WS2812FX::isUpdating() {
|
||||
bool WS2812FX::isUpdating() const {
|
||||
return !BusManager::canAllShow();
|
||||
}
|
||||
|
||||
@ -1393,7 +1389,7 @@ bool WS2812FX::isUpdating() {
|
||||
* Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough.
|
||||
* Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accuracy varies
|
||||
*/
|
||||
uint16_t WS2812FX::getFps() {
|
||||
uint16_t WS2812FX::getFps() const {
|
||||
if (millis() - _lastShow > 2000) return 0;
|
||||
return _cumulativeFps +1;
|
||||
}
|
||||
@ -1452,17 +1448,17 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getActiveSegsLightCapabilities(bool selectedOnly) {
|
||||
uint8_t WS2812FX::getActiveSegsLightCapabilities(bool selectedOnly) const {
|
||||
uint8_t totalLC = 0;
|
||||
for (segment &seg : _segments) {
|
||||
for (const segment &seg : _segments) {
|
||||
if (seg.isActive() && (!selectedOnly || seg.isSelected())) totalLC |= seg.getLightCapabilities();
|
||||
}
|
||||
return totalLC;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getFirstSelectedSegId(void) {
|
||||
uint8_t WS2812FX::getFirstSelectedSegId(void) const {
|
||||
size_t i = 0;
|
||||
for (segment &seg : _segments) {
|
||||
for (const segment &seg : _segments) {
|
||||
if (seg.isActive() && seg.isSelected()) return i;
|
||||
i++;
|
||||
}
|
||||
@ -1478,14 +1474,14 @@ void WS2812FX::setMainSegmentId(uint8_t n) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getLastActiveSegmentId(void) {
|
||||
uint8_t WS2812FX::getLastActiveSegmentId(void) const {
|
||||
for (size_t i = _segments.size() -1; i > 0; i--) {
|
||||
if (_segments[i].isActive()) return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getActiveSegmentsNum(void) {
|
||||
uint8_t WS2812FX::getActiveSegmentsNum(void) const {
|
||||
uint8_t c = 0;
|
||||
for (size_t i = 0; i < _segments.size(); i++) {
|
||||
if (_segments[i].isActive()) c++;
|
||||
@ -1493,13 +1489,13 @@ uint8_t WS2812FX::getActiveSegmentsNum(void) {
|
||||
return c;
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::getLengthTotal(void) {
|
||||
uint16_t WS2812FX::getLengthTotal(void) const {
|
||||
unsigned len = Segment::maxWidth * Segment::maxHeight; // will be _length for 1D (see finalizeInit()) but should cover whole matrix for 2D
|
||||
if (isMatrix && _length > len) len = _length; // for 2D with trailing strip
|
||||
return len;
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::getLengthPhysical(void) {
|
||||
uint16_t WS2812FX::getLengthPhysical(void) const {
|
||||
unsigned len = 0;
|
||||
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
|
||||
Bus *bus = BusManager::getBus(b);
|
||||
@ -1512,7 +1508,7 @@ uint16_t WS2812FX::getLengthPhysical(void) {
|
||||
//used for JSON API info.leds.rgbw. Little practical use, deprecate with info.leds.rgbw.
|
||||
//returns if there is an RGBW bus (supports RGB and White, not only white)
|
||||
//not influenced by auto-white mode, also true if white slider does not affect output white channel
|
||||
bool WS2812FX::hasRGBWBus(void) {
|
||||
bool WS2812FX::hasRGBWBus(void) const {
|
||||
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
|
||||
Bus *bus = BusManager::getBus(b);
|
||||
if (bus == nullptr || bus->getLength()==0) break;
|
||||
@ -1521,7 +1517,7 @@ bool WS2812FX::hasRGBWBus(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WS2812FX::hasCCTBus(void) {
|
||||
bool WS2812FX::hasCCTBus(void) const {
|
||||
if (cctFromRgb && !correctWB) return false;
|
||||
for (size_t b = 0; b < BusManager::getNumBusses(); b++) {
|
||||
Bus *bus = BusManager::getBus(b);
|
||||
@ -1813,7 +1809,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
|
||||
return (customMappingSize > 0);
|
||||
}
|
||||
|
||||
uint16_t IRAM_ATTR WS2812FX::getMappedPixelIndex(uint16_t index) {
|
||||
uint16_t IRAM_ATTR WS2812FX::getMappedPixelIndex(uint16_t index) const {
|
||||
// convert logical address to physical
|
||||
if (index < customMappingSize
|
||||
&& (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index];
|
||||
|
Loading…
x
Reference in New Issue
Block a user