Pre-calculate virtual

- move SEGCOLOR() to Segment class
- add SEG_H, SEG_W macros
- try to speed up virtualXxxxx()
- compile warning fixes
This commit is contained in:
Blaz Kristan 2024-09-28 18:14:43 +02:00
parent 202901b09f
commit c842994df5
6 changed files with 367 additions and 371 deletions

File diff suppressed because it is too large Load Diff

View File

@ -90,11 +90,11 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
#define NUM_COLORS 3 /* number of colors per segment */ #define NUM_COLORS 3 /* number of colors per segment */
#define SEGMENT strip._segments[strip.getCurrSegmentId()] #define SEGMENT strip._segments[strip.getCurrSegmentId()]
#define SEGENV strip._segments[strip.getCurrSegmentId()] #define SEGENV strip._segments[strip.getCurrSegmentId()]
//#define SEGCOLOR(x) strip._segments[strip.getCurrSegmentId()].currentColor(x, strip._segments[strip.getCurrSegmentId()].colors[x]) #define SEGCOLOR(x) Segment::getCurrentColor(x)
//#define SEGLEN strip._segments[strip.getCurrSegmentId()].virtualLength()
#define SEGCOLOR(x) strip.segColor(x) /* saves us a few kbytes of code */
#define SEGPALETTE Segment::getCurrentPalette() #define SEGPALETTE Segment::getCurrentPalette()
#define SEGLEN strip._virtualSegmentLength /* saves us a few kbytes of code */ #define SEGLEN Segment::vLength()
#define SEG_W Segment::vWidth()
#define SEG_H Segment::vHeight()
#define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN) #define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN)
// some common colors // some common colors
@ -421,7 +421,9 @@ typedef struct Segment {
uint16_t _dataLen; uint16_t _dataLen;
static uint16_t _usedSegmentData; static uint16_t _usedSegmentData;
// perhaps this should be per segment, not static static unsigned _vLength; // 1D dimension used for current effect
static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect
static uint32_t _currentColors[NUM_COLORS]; // colors used for current effect
static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette()) static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette())
static CRGBPalette16 _randomPalette; // actual random palette static CRGBPalette16 _randomPalette; // actual random palette
static CRGBPalette16 _newRandomPalette; // target random palette static CRGBPalette16 _newRandomPalette; // target random palette
@ -534,14 +536,20 @@ typedef struct Segment {
inline uint16_t groupLength() const { return grouping + spacing; } inline uint16_t groupLength() const { return grouping + spacing; }
inline uint8_t getLightCapabilities() const { return _capabilities; } inline uint8_t getLightCapabilities() const { return _capabilities; }
inline static uint16_t getUsedSegmentData() { return _usedSegmentData; } inline static uint16_t getUsedSegmentData() { return Segment::_usedSegmentData; }
inline static void addUsedSegmentData(int len) { _usedSegmentData += len; } inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; }
#ifndef WLED_DISABLE_MODE_BLEND #ifndef WLED_DISABLE_MODE_BLEND
inline static void modeBlend(bool blend) { _modeBlend = blend; } inline static void modeBlend(bool blend) { _modeBlend = blend; }
#endif #endif
static void handleRandomPalette(); inline static unsigned vLength() { return Segment::_vLength; }
inline static unsigned vWidth() { return Segment::_vWidth; }
inline static unsigned vHeight() { return Segment::_vHeight; }
inline static uint32_t getCurrentColor(unsigned i) { return Segment::_currentColors[i]; } // { return i < 3 ? Segment::_currentColors[i] : 0; }
inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; } inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; }
static void handleRandomPalette();
void beginDraw(); // set up parameters for current effect
void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1); void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
bool setColor(uint8_t slot, uint32_t c); //returns true if changed bool setColor(uint8_t slot, uint32_t c); //returns true if changed
void setCCT(uint16_t k); void setCCT(uint16_t k);
@ -578,12 +586,11 @@ typedef struct Segment {
uint8_t currentMode() const; // currently active effect/mode (while in transition) uint8_t currentMode() const; // currently active effect/mode (while in transition)
[[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition) [[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition)
CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal); CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
void setCurrentPalette();
// 1D strip // 1D strip
[[gnu::hot]] uint16_t virtualLength() const; [[gnu::hot]] uint16_t virtualLength() const;
[[gnu::hot]] void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color [[gnu::hot]] void setPixelColor(int n, uint32_t c, bool unScaled = true); // set relative pixel within segment with color
inline void setPixelColor(unsigned n, uint32_t c) { setPixelColor(int(n), c); } inline void setPixelColor(unsigned n, uint32_t c, bool unScaled = true) { setPixelColor(int(n), c, unScaled); }
inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); }
inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); }
#ifdef WLED_USE_AA_PIXELS #ifdef WLED_USE_AA_PIXELS
@ -622,8 +629,8 @@ typedef struct Segment {
uint16_t nrOfVStrips() const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D) uint16_t nrOfVStrips() const; // returns number of virtual vertical strips in 2D matrix (used to expand 1D effects into 2D)
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
[[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment [[gnu::hot]] uint16_t XY(int x, int y); // support function to get relative index within segment
[[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color [[gnu::hot]] void setPixelColorXY(int x, int y, uint32_t c, bool unScaled = true); // set relative pixel within segment with color
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c, bool unScaled = true) { setPixelColorXY(int(x), int(y), c, unScaled); }
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, 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 void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); }
@ -642,8 +649,8 @@ typedef struct Segment {
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(unsigned r = 1U, bool smear = false); // 2D box blur void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur
void blur2D(uint8_t blur_amount, bool smear = false); void blur2D(uint8_t blur_amount, bool smear = false);
void blurRow(uint32_t row, fract8 blur_amount, bool smear = false); void blurRow(int row, fract8 blur_amount, bool smear = false);
void blurCol(uint32_t col, fract8 blur_amount, bool smear = false); void blurCol(int 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);
@ -660,9 +667,9 @@ typedef struct Segment {
inline void blur2d(fract8 blur_amount) { blur(blur_amount); } inline void blur2d(fract8 blur_amount) { blur(blur_amount); }
inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); }
#else #else
inline uint16_t XY(uint16_t x, uint16_t y) { return x; } inline uint16_t XY(int x, int y) { return x; }
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); } inline void setPixelColorXY(int x, int y, uint32_t c, bool unScaled = true) { setPixelColor(x, c, unScaled); }
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c, bool unScaled = true) { setPixelColor(int(x), c, unScaled); }
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); }
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); }
inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); } inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); }
@ -680,8 +687,8 @@ typedef struct Segment {
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(unsigned 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 blur2D(uint8_t blur_amount, bool smear = false) {}
inline void blurRow(uint32_t row, fract8 blur_amount, bool smear = false) {} inline void blurRow(int row, fract8 blur_amount, bool smear = false) {}
inline void blurCol(uint32_t col, fract8 blur_amount, bool smear = false) {} inline void blurCol(int 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) {}
@ -727,9 +734,6 @@ class WS2812FX { // 96 bytes
autoSegments(false), autoSegments(false),
correctWB(false), correctWB(false),
cctFromRgb(false), cctFromRgb(false),
// semi-private (just obscured) used in effect functions through macros
_colors_t{0,0,0},
_virtualSegmentLength(0),
// true private variables // true private variables
_suspend(false), _suspend(false),
_length(DEFAULT_LED_COUNT), _length(DEFAULT_LED_COUNT),
@ -829,7 +833,7 @@ class WS2812FX { // 96 bytes
addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp; addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp;
inline uint8_t getBrightness() const { return _brightness; } // returns current strip brightness inline uint8_t getBrightness() const { return _brightness; } // returns current strip brightness
inline uint8_t getMaxSegments() const { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value) inline constexpr unsigned getMaxSegments() { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
inline uint8_t getSegmentsNum() const { return _segments.size(); } // returns currently present segments inline uint8_t getSegmentsNum() const { return _segments.size(); } // returns currently present segments
inline uint8_t getCurrSegmentId() const { return _segment_index; } // returns current segment index (only valid while strip.isServicing()) inline uint8_t getCurrSegmentId() const { return _segment_index; } // returns current segment index (only valid while strip.isServicing())
inline uint8_t getMainSegmentId() const { return _mainSegment; } // returns main segment index inline uint8_t getMainSegmentId() const { return _mainSegment; } // returns main segment index
@ -855,7 +859,6 @@ class WS2812FX { // 96 bytes
uint32_t getPixelColor(unsigned) const; uint32_t getPixelColor(unsigned) const;
inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call inline uint32_t getLastShow() 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 * const char *
getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); } getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); }
@ -922,11 +925,6 @@ class WS2812FX { // 96 bytes
bool cctFromRgb : 1; bool cctFromRgb : 1;
}; };
// using public variables to reduce code size increase due to inline function getSegment() (with bounds checking)
// and color transitions
uint32_t _colors_t[3]; // color used for effect (includes transition)
uint16_t _virtualSegmentLength;
std::vector<segment> _segments; std::vector<segment> _segments;
friend class Segment; friend class Segment;

View File

@ -163,23 +163,24 @@ void WS2812FX::setUpMatrix() {
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element) // XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
uint16_t IRAM_ATTR_YN Segment::XY(int x, int y) uint16_t IRAM_ATTR_YN Segment::XY(int x, int y)
{ {
unsigned width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive) const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
unsigned height = virtualHeight(); // segment height in logical pixels (is always >= 1) const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
return isActive() ? (x%width) + (y%height) * width : 0; return isActive() ? (x%vW) + (y%vH) * vW : 0;
} }
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col, bool unScaled)
{ {
if (!isActive()) return; // not active if (!isActive()) return; // not active
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
uint8_t _bri_t = currentBri(); const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
if (_bri_t < 255) { const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
col = color_fade(col, _bri_t); if (x >= vW|| y >= vH || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
}
if (reverse ) x = virtualWidth() - x - 1; // if color is unscaled
if (reverse_y) y = virtualHeight() - y - 1; if (unScaled) col = color_fade(col, currentBri());
if (reverse ) x = vW - x - 1;
if (reverse_y) y = vH - y - 1;
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
x *= groupLength(); // expand to physical pixels x *= groupLength(); // expand to physical pixels
y *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels
@ -221,11 +222,8 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
if (!isActive()) return; // not active if (!isActive()) return; // not active
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
const unsigned cols = virtualWidth(); float fX = x * (vWidth()-1);
const unsigned rows = virtualHeight(); float fY = y * (vHeight()-1);
float fX = x * (cols-1);
float fY = y * (rows-1);
if (aa) { if (aa) {
unsigned xL = roundf(fX-0.49f); unsigned xL = roundf(fX-0.49f);
unsigned xR = roundf(fX+0.49f); unsigned xR = roundf(fX+0.49f);
@ -263,9 +261,11 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
// returns RGBW values of pixel // returns RGBW values of pixel
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
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 int vW = vWidth();
if (reverse ) x = virtualWidth() - x - 1; int vH = vHeight();
if (reverse_y) y = virtualHeight() - y - 1; if (x >= vW || y >= vH || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
if (reverse ) x = vW - x - 1;
if (reverse_y) y = vH - y - 1;
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
x *= groupLength(); // expand to physical pixels x *= groupLength(); // expand to physical pixels
y *= groupLength(); // expand to physical pixels y *= groupLength(); // expand to physical pixels
@ -274,10 +274,10 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
} }
// 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(uint32_t row, fract8 blur_amount, bool smear){ void Segment::blurRow(int row, fract8 blur_amount, bool smear){
if (!isActive() || blur_amount == 0) return; // not active if (!isActive() || blur_amount == 0) return; // not active
const unsigned cols = virtualWidth(); const int cols = vWidth();
const unsigned rows = virtualHeight(); const int rows = vHeight();
if (row >= rows) return; if (row >= rows) return;
// blur one row // blur one row
@ -287,7 +287,7 @@ void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){
uint32_t lastnew; uint32_t lastnew;
uint32_t last; uint32_t last;
uint32_t curnew = BLACK; uint32_t curnew = BLACK;
for (unsigned x = 0; x < cols; x++) { for (int x = 0; x < cols; x++) {
uint32_t cur = getPixelColorXY(x, row); uint32_t cur = getPixelColorXY(x, row);
uint32_t part = color_fade(cur, seep); uint32_t part = color_fade(cur, seep);
curnew = color_fade(cur, keep); curnew = color_fade(cur, keep);
@ -306,10 +306,10 @@ void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){
} }
// 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(uint32_t col, fract8 blur_amount, bool smear) { void Segment::blurCol(int col, fract8 blur_amount, bool smear) {
if (!isActive() || blur_amount == 0) return; // not active if (!isActive() || blur_amount == 0) return; // not active
const unsigned cols = virtualWidth(); const int cols = vWidth();
const unsigned rows = virtualHeight(); const int rows = vHeight();
if (col >= cols) return; if (col >= cols) return;
// blur one column // blur one column
@ -319,7 +319,7 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) {
uint32_t lastnew; uint32_t lastnew;
uint32_t last; uint32_t last;
uint32_t curnew = BLACK; uint32_t curnew = BLACK;
for (unsigned y = 0; y < rows; y++) { for (int y = 0; y < rows; y++) {
uint32_t cur = getPixelColorXY(col, y); uint32_t cur = getPixelColorXY(col, y);
uint32_t part = color_fade(cur, seep); uint32_t part = color_fade(cur, seep);
curnew = color_fade(cur, keep); curnew = color_fade(cur, keep);
@ -339,8 +339,8 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) {
void Segment::blur2D(uint8_t blur_amount, bool smear) { void Segment::blur2D(uint8_t blur_amount, bool smear) {
if (!isActive() || blur_amount == 0) return; // not active if (!isActive() || blur_amount == 0) return; // not active
const unsigned cols = virtualWidth(); const unsigned cols = vWidth();
const unsigned rows = virtualHeight(); const unsigned rows = vHeight();
const uint8_t keep = smear ? 255 : 255 - blur_amount; const uint8_t keep = smear ? 255 : 255 - blur_amount;
const uint8_t seep = blur_amount >> (1 + smear); const uint8_t seep = blur_amount >> (1 + smear);
@ -391,8 +391,8 @@ void Segment::box_blur(unsigned radius, bool smear) {
if (!isActive() || radius == 0) return; // not active if (!isActive() || radius == 0) return; // not active
if (radius > 3) radius = 3; if (radius > 3) radius = 3;
const unsigned d = (1 + 2*radius) * (1 + 2*radius); // averaging divisor const unsigned d = (1 + 2*radius) * (1 + 2*radius); // averaging divisor
const unsigned cols = virtualWidth(); const unsigned cols = vWidth();
const unsigned rows = virtualHeight(); const unsigned rows = vHeight();
uint16_t *tmpRSum = new uint16_t[cols*rows]; uint16_t *tmpRSum = new uint16_t[cols*rows];
uint16_t *tmpGSum = new uint16_t[cols*rows]; uint16_t *tmpGSum = new uint16_t[cols*rows];
uint16_t *tmpBSum = new uint16_t[cols*rows]; uint16_t *tmpBSum = new uint16_t[cols*rows];
@ -461,37 +461,37 @@ void Segment::box_blur(unsigned radius, bool smear) {
void Segment::moveX(int8_t delta, bool wrap) { void Segment::moveX(int8_t delta, bool wrap) {
if (!isActive()) return; // not active if (!isActive()) return; // not active
const int cols = virtualWidth(); const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
const int rows = virtualHeight(); const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
if (!delta || abs(delta) >= cols) return; if (!delta || abs(delta) >= vW) return;
uint32_t newPxCol[cols]; uint32_t newPxCol[vW];
for (int y = 0; y < rows; y++) { for (int y = 0; y < vH; y++) {
if (delta > 0) { if (delta > 0) {
for (int x = 0; x < cols-delta; x++) newPxCol[x] = getPixelColorXY((x + delta), y); for (int x = 0; x < vW-delta; x++) newPxCol[x] = getPixelColorXY((x + delta), y);
for (int x = cols-delta; x < cols; x++) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) - cols : x, y); for (int x = vW-delta; x < vW; x++) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) - vW : x, y);
} else { } else {
for (int x = cols-1; x >= -delta; x--) newPxCol[x] = getPixelColorXY((x + delta), y); for (int x = vW-1; x >= -delta; x--) newPxCol[x] = getPixelColorXY((x + delta), y);
for (int x = -delta-1; x >= 0; x--) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) + cols : x, y); for (int x = -delta-1; x >= 0; x--) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) + vW : x, y);
} }
for (int x = 0; x < cols; x++) setPixelColorXY(x, y, newPxCol[x]); for (int x = 0; x < vW; x++) setPixelColorXY(x, y, newPxCol[x]);
} }
} }
void Segment::moveY(int8_t delta, bool wrap) { void Segment::moveY(int8_t delta, bool wrap) {
if (!isActive()) return; // not active if (!isActive()) return; // not active
const int cols = virtualWidth(); const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
const int rows = virtualHeight(); const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
if (!delta || abs(delta) >= rows) return; if (!delta || abs(delta) >= vH) return;
uint32_t newPxCol[rows]; uint32_t newPxCol[vH];
for (int x = 0; x < cols; x++) { for (int x = 0; x < vW; x++) {
if (delta > 0) { if (delta > 0) {
for (int y = 0; y < rows-delta; y++) newPxCol[y] = getPixelColorXY(x, (y + delta)); for (int y = 0; y < vH-delta; y++) newPxCol[y] = getPixelColorXY(x, (y + delta));
for (int y = rows-delta; y < rows; y++) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) - rows : y); for (int y = vH-delta; y < vH; y++) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) - vH : y);
} else { } else {
for (int y = rows-1; y >= -delta; y--) newPxCol[y] = getPixelColorXY(x, (y + delta)); for (int y = vH-1; y >= -delta; y--) newPxCol[y] = getPixelColorXY(x, (y + delta));
for (int y = -delta-1; y >= 0; y--) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) + rows : y); for (int y = -delta-1; y >= 0; y--) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) + vH : y);
} }
for (int y = 0; y < rows; y++) setPixelColorXY(x, y, newPxCol[y]); for (int y = 0; y < vH; y++) setPixelColorXY(x, y, newPxCol[y]);
} }
} }
@ -545,18 +545,20 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col,
x++; x++;
} }
} else { } else {
// pre-scale color for all pixels
col = color_fade(col, currentBri());
// Bresenhams Algorithm // Bresenhams Algorithm
int d = 3 - (2*radius); int d = 3 - (2*radius);
int y = radius, x = 0; int y = radius, x = 0;
while (y >= x) { while (y >= x) {
setPixelColorXY(cx+x, cy+y, col); setPixelColorXY(cx+x, cy+y, col, false);
setPixelColorXY(cx-x, cy+y, col); setPixelColorXY(cx-x, cy+y, col, false);
setPixelColorXY(cx+x, cy-y, col); setPixelColorXY(cx+x, cy-y, col, false);
setPixelColorXY(cx-x, cy-y, col); setPixelColorXY(cx-x, cy-y, col, false);
setPixelColorXY(cx+y, cy+x, col); setPixelColorXY(cx+y, cy+x, col, false);
setPixelColorXY(cx-y, cy+x, col); setPixelColorXY(cx-y, cy+x, col, false);
setPixelColorXY(cx+y, cy-x, col); setPixelColorXY(cx+y, cy-x, col, false);
setPixelColorXY(cx-y, cy-x, col); setPixelColorXY(cx-y, cy-x, col, false);
x++; x++;
if (d > 0) { if (d > 0) {
y--; y--;
@ -571,17 +573,19 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col,
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs // by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) { void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) {
if (!isActive() || radius == 0) return; // not active if (!isActive() || radius == 0) return; // not active
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
// draw soft bounding circle // draw soft bounding circle
if (soft) drawCircle(cx, cy, radius, col, soft); if (soft) drawCircle(cx, cy, radius, col, soft);
// pre-scale color for all pixels
col = color_fade(col, currentBri());
// fill it // fill it
const int cols = virtualWidth();
const int rows = virtualHeight();
for (int y = -radius; y <= radius; y++) { for (int y = -radius; y <= radius; y++) {
for (int x = -radius; x <= radius; x++) { for (int x = -radius; x <= radius; x++) {
if (x * x + y * y <= radius * radius && if (x * x + y * y <= radius * radius &&
int(cx)+x>=0 && int(cy)+y>=0 && int(cx)+x >= 0 && int(cy)+y >= 0 &&
int(cx)+x<cols && int(cy)+y<rows) int(cx)+x < vW && int(cy)+y < vH)
setPixelColorXY(cx + x, cy + y, col); setPixelColorXY(cx + x, cy + y, col, false);
} }
} }
} }
@ -589,9 +593,9 @@ void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col,
//line function //line function
void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft) { void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft) {
if (!isActive()) return; // not active if (!isActive()) return; // not active
const int cols = virtualWidth(); const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
const int rows = virtualHeight(); const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return; if (x0 >= vW || x1 >= vW || y0 >= vH || y1 >= vH) return;
const int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1; // x distance & step const int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1; // x distance & step
const int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1; // y distance & step const int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1; // y distance & step
@ -629,10 +633,12 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
if (steep) std::swap(x,y); // restore if steep if (steep) std::swap(x,y); // restore if steep
} }
} else { } else {
// pre-scale color for all pixels
c = color_fade(c, currentBri());
// Bresenham's algorithm // Bresenham's algorithm
int err = (dx>dy ? dx : -dy)/2; // error direction int err = (dx>dy ? dx : -dy)/2; // error direction
for (;;) { for (;;) {
setPixelColorXY(x0, y0, c); setPixelColorXY(x0, y0, c, false);
if (x0==x1 && y0==y1) break; if (x0==x1 && y0==y1) break;
int e2 = err; int e2 = err;
if (e2 >-dx) { err -= dy; x0 += sx; } if (e2 >-dx) { err -= dy; x0 += sx; }
@ -653,8 +659,6 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
if (!isActive()) return; // not active if (!isActive()) return; // not active
if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported
chr -= 32; // align with font table entries chr -= 32; // align with font table entries
const int cols = virtualWidth();
const int rows = virtualHeight();
const int font = w*h; const int font = w*h;
CRGB col = CRGB(color); CRGB col = CRGB(color);
@ -681,7 +685,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
case 1: x0 = x + i; y0 = y + j; break; // +90 deg case 1: x0 = x + i; y0 = y + j; break; // +90 deg
default: x0 = x + (w-1) - j; y0 = y + i; break; // no rotation default: x0 = x + (w-1) - j; y0 = y + i; break; // no rotation
} }
if (x0 < 0 || x0 >= cols || y0 < 0 || y0 >= rows) continue; // drawing off-screen if (x0 < 0 || x0 >= (int)vWidth() || y0 < 0 || y0 >= (int)vHeight()) continue; // drawing off-screen
if (((bits>>(j+(8-w))) & 0x01)) { // bit set if (((bits>>(j+(8-w))) & 0x01)) { // bit set
setPixelColorXY(x0, y0, col); setPixelColorXY(x0, y0, col);
} }

View File

@ -83,12 +83,15 @@ static constexpr bool validatePinsAndTypes(const unsigned* types, unsigned numTy
uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[] uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[]
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
uint16_t Segment::maxHeight = 1; uint16_t Segment::maxHeight = 1;
unsigned Segment::_vLength = 0;
unsigned Segment::_vWidth = 0;
unsigned Segment::_vHeight = 0;
uint32_t Segment::_currentColors[NUM_COLORS] = {0,0,0};
CRGBPalette16 Segment::_currentPalette = CRGBPalette16(CRGB::Black); CRGBPalette16 Segment::_currentPalette = CRGBPalette16(CRGB::Black);
CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR);
CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR);
uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment
uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) uint16_t Segment::_lastPaletteBlend = 0; // in millis (lowest 16 bits only)
#ifndef WLED_DISABLE_MODE_BLEND #ifndef WLED_DISABLE_MODE_BLEND
bool Segment::_modeBlend = false; bool Segment::_modeBlend = false;
@ -437,7 +440,21 @@ uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const {
#endif #endif
} }
void Segment::setCurrentPalette() { // pre-calculate drawing parameters for faster access
void Segment::beginDraw() {
_vWidth = virtualWidth();
_vHeight = virtualHeight();
_vLength = virtualLength();
// adjust gamma for effects
for (unsigned i = 0; i < NUM_COLORS; i++) {
#ifndef WLED_DISABLE_MODE_BLEND
uint32_t col = isInTransition() ? color_blend(_t->_segT._colorT[i], colors[i], progress(), true) : colors[i];
#else
uint32_t col = isInTransition() ? color_blend(_t->_colorT[i], colors[i], progress(), true) : colors[i];
#endif
_currentColors[i] = gamma32(col);
}
// load palette into _currentPalette
loadPalette(_currentPalette, palette); loadPalette(_currentPalette, palette);
unsigned prog = progress(); unsigned prog = progress();
if (strip.paletteFade && prog < 0xFFFFU) { if (strip.paletteFade && prog < 0xFFFFU) {
@ -698,20 +715,21 @@ uint16_t IRAM_ATTR Segment::virtualLength() const {
return vLength; return vLength;
} }
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col, bool unScaled)
{ {
if (!isActive() || i < 0) return; // not active or invalid index if (!isActive() || i < 0) return; // not active or invalid index
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
int vStrip = 0; int vStrip = 0;
#endif #endif
int vL = vLength();
// if the 1D effect is using virtual strips "i" will have virtual strip id stored in upper 16 bits // if the 1D effect is using virtual strips "i" will have virtual strip id stored in upper 16 bits
// in such case "i" will be > virtualLength() // in such case "i" will be > virtualLength()
if (i >= virtualLength()) { if (i >= vL) {
// check if this is a virtual strip // check if this is a virtual strip
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows)
i &= 0xFFFF; //truncate vstrip index i &= 0xFFFF; //truncate vstrip index
if (i >= virtualLength()) return; // if pixel would still fall out of segment just exit if (i >= vL) return; // if pixel would still fall out of segment just exit
#else #else
return; return;
#endif #endif
@ -719,22 +737,24 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
if (is2D()) { if (is2D()) {
int vH = virtualHeight(); // segment height in logical pixels const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
int vW = virtualWidth(); const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
// pre-scale color for all pixels
col = color_fade(col, currentBri());
switch (map1D2D) { switch (map1D2D) {
case M12_Pixels: case M12_Pixels:
// use all available pixels as a long strip // use all available pixels as a long strip
setPixelColorXY(i % vW, i / vW, col); setPixelColorXY(i % vW, i / vW, col, false);
break; break;
case M12_pBar: case M12_pBar:
// expand 1D effect vertically or have it play on virtual strips // expand 1D effect vertically or have it play on virtual strips
if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col); if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col, false);
else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col); else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col, false);
break; break;
case M12_pArc: case M12_pArc:
// expand in circular fashion from center // expand in circular fashion from center
if (i == 0) if (i == 0)
setPixelColorXY(0, 0, col); setPixelColorXY(0, 0, col, false);
else { else {
float r = i; float r = i;
float step = HALF_PI / (2.8284f * r + 4); // we only need (PI/4)/(r/sqrt(2)+1) steps float step = HALF_PI / (2.8284f * r + 4); // we only need (PI/4)/(r/sqrt(2)+1) steps
@ -742,8 +762,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
int x = roundf(sin_t(rad) * r); int x = roundf(sin_t(rad) * r);
int y = roundf(cos_t(rad) * r); int y = roundf(cos_t(rad) * r);
// exploit symmetry // exploit symmetry
setPixelColorXY(x, y, col); setPixelColorXY(x, y, col, false);
setPixelColorXY(y, x, col); setPixelColorXY(y, x, col, false);
} }
// Bresenhams Algorithm (may not fill every pixel) // Bresenhams Algorithm (may not fill every pixel)
//int d = 3 - (2*i); //int d = 3 - (2*i);
@ -762,8 +782,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
} }
break; break;
case M12_pCorner: case M12_pCorner:
for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col); for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col, false);
for (int y = 0; y < i; y++) setPixelColorXY(i, y, col); for (int y = 0; y < i; y++) setPixelColorXY(i, y, col, false);
break; break;
case M12_sPinwheel: { case M12_sPinwheel: {
// i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small) // i = angle --> 0 - 296 (Big), 0 - 192 (Medium), 0 - 72 (Small)
@ -802,7 +822,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
int x = posx / Fixed_Scale; int x = posx / Fixed_Scale;
int y = posy / Fixed_Scale; int y = posy / Fixed_Scale;
// set pixel // set pixel
if (x != lastX || y != lastY) setPixelColorXY(x, y, col); // only paint if pixel position is different if (x != lastX || y != lastY) setPixelColorXY(x, y, col, false); // only paint if pixel position is different
lastX = x; lastX = x;
lastY = y; lastY = y;
// advance to next position // advance to next position
@ -813,12 +833,12 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
} }
} }
return; return;
} else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) { } else if (Segment::maxHeight != 1 && (width() == 1 || height() == 1)) {
if (start < Segment::maxWidth*Segment::maxHeight) { if (start < Segment::maxWidth*Segment::maxHeight) {
// we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed) // we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed)
int x = 0, y = 0; int x = 0, y = 0;
if (virtualHeight()>1) y = i; if (vHeight() > 1) y = i;
if (virtualWidth() >1) x = i; if (vWidth() > 1) x = i;
setPixelColorXY(x, y, col); setPixelColorXY(x, y, col);
return; return;
} }
@ -826,10 +846,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
#endif #endif
unsigned len = length(); unsigned len = length();
uint8_t _bri_t = currentBri(); // if color is unscaled
if (_bri_t < 255) { if (unScaled) col = color_fade(col, currentBri());
col = color_fade(col, _bri_t);
}
// expand pixel (taking into account start, grouping, spacing [and offset]) // expand pixel (taking into account start, grouping, spacing [and offset])
i = i * groupLength(); i = i * groupLength();
@ -907,8 +925,8 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
#ifndef WLED_DISABLE_2D #ifndef WLED_DISABLE_2D
if (is2D()) { if (is2D()) {
int vH = virtualHeight(); // segment height in logical pixels const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
int vW = virtualWidth(); const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
switch (map1D2D) { switch (map1D2D) {
case M12_Pixels: case M12_Pixels:
return getPixelColorXY(i % vW, i / vW); return getPixelColorXY(i % vW, i / vW);
@ -961,7 +979,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
} }
#endif #endif
if (reverse) i = virtualLength() - i - 1; if (reverse) i = vLength() - i - 1;
i *= groupLength(); i *= groupLength();
i += start; i += start;
// offset/phase // offset/phase
@ -1050,11 +1068,13 @@ void Segment::refreshLightCapabilities() {
*/ */
void Segment::fill(uint32_t c) { void Segment::fill(uint32_t c) {
if (!isActive()) return; // not active if (!isActive()) return; // not active
const int cols = is2D() ? virtualWidth() : virtualLength(); const int cols = is2D() ? vWidth() : vLength();
const int rows = virtualHeight(); // will be 1 for 1D const int rows = vHeight(); // will be 1 for 1D
// pre-scale color for all pixels
c = color_fade(c, currentBri());
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
if (is2D()) setPixelColorXY(x, y, c); if (is2D()) setPixelColorXY(x, y, c, false);
else setPixelColor(x, c); else setPixelColor(x, c, false);
} }
} }
@ -1063,8 +1083,8 @@ void Segment::fill(uint32_t c) {
*/ */
void Segment::fade_out(uint8_t rate) { void Segment::fade_out(uint8_t rate) {
if (!isActive()) return; // not active if (!isActive()) return; // not active
const int cols = is2D() ? virtualWidth() : virtualLength(); const int cols = is2D() ? vWidth() : vLength();
const int rows = virtualHeight(); // will be 1 for 1D const int rows = vHeight(); // will be 1 for 1D
rate = (255-rate) >> 1; rate = (255-rate) >> 1;
float mappedRate = 1.0f / (float(rate) + 1.1f); float mappedRate = 1.0f / (float(rate) + 1.1f);
@ -1102,8 +1122,8 @@ void Segment::fade_out(uint8_t rate) {
// fades all pixels to black using nscale8() // fades all pixels to black using nscale8()
void Segment::fadeToBlackBy(uint8_t fadeBy) { void Segment::fadeToBlackBy(uint8_t fadeBy) {
if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply
const int cols = is2D() ? virtualWidth() : virtualLength(); const int cols = is2D() ? vWidth() : vLength();
const int rows = virtualHeight(); // will be 1 for 1D const int rows = vHeight(); // will be 1 for 1D
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
if (is2D()) setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), 255-fadeBy)); if (is2D()) setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), 255-fadeBy));
@ -1126,7 +1146,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
#endif #endif
uint8_t keep = smear ? 255 : 255 - blur_amount; uint8_t keep = smear ? 255 : 255 - blur_amount;
uint8_t seep = blur_amount >> (1 + smear); uint8_t seep = blur_amount >> (1 + smear);
unsigned vlength = virtualLength(); unsigned vlength = vLength();
uint32_t carryover = BLACK; uint32_t carryover = BLACK;
uint32_t lastnew; uint32_t lastnew;
uint32_t last; uint32_t last;
@ -1140,8 +1160,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
uint32_t prev = color_add(lastnew, part); uint32_t prev = color_add(lastnew, part);
// optimization: only set pixel if color has changed // optimization: only set pixel if color has changed
if (last != prev) setPixelColor(i - 1, prev); if (last != prev) setPixelColor(i - 1, prev);
} else // first pixel } else setPixelColor(i, curnew); // first pixel
setPixelColor(i, curnew);
lastnew = curnew; lastnew = curnew;
last = cur; // save original value for comparison on next iteration last = cur; // save original value for comparison on next iteration
carryover = part; carryover = part;
@ -1156,7 +1175,7 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
*/ */
uint32_t Segment::color_wheel(uint8_t pos) const { uint32_t Segment::color_wheel(uint8_t pos) const {
if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true" if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true"
uint8_t w = W(currentColor(0)); uint8_t w = W(getCurrentColor(0));
pos = 255 - pos; pos = 255 - pos;
if (pos < 85) { if (pos < 85) {
return RGBW32((255 - pos * 3), 0, (pos * 3), w); return RGBW32((255 - pos * 3), 0, (pos * 3), w);
@ -1179,20 +1198,19 @@ uint32_t Segment::color_wheel(uint8_t pos) const {
* @returns Single color from palette * @returns Single color from palette
*/ */
uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const { uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const {
uint32_t color = getCurrentColor(mcol < NUM_COLORS ? mcol : 0);
uint32_t color = currentColor(mcol);
// default palette or no RGB support on segment // default palette or no RGB support on segment
if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) { if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) {
color = gamma32(color); return color_fade(color, pbri, true);
return (pbri == 255) ? color : color_fade(color, pbri, true);
} }
const int vL = vLength();
unsigned paletteIndex = i; unsigned paletteIndex = i;
if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1); if (mapping && vL > 1) paletteIndex = (i*255)/(vL -1);
// paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined) // paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined)
if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
CRGBW palcol = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global CRGBW palcol = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
palcol.w = gamma8(W(color)); palcol.w = W(color);
return palcol.color32; return palcol.color32;
} }
@ -1359,11 +1377,6 @@ void WS2812FX::service() {
if (!seg.freeze) { //only run effect function if not frozen if (!seg.freeze) { //only run effect function if not frozen
int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based) int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based)
_virtualSegmentLength = seg.virtualLength(); //SEGLEN
_colors_t[0] = gamma32(seg.currentColor(0));
_colors_t[1] = gamma32(seg.currentColor(1));
_colors_t[2] = gamma32(seg.currentColor(2));
seg.setCurrentPalette(); // load actual palette
// when correctWB is true we need to correct/adjust RGB value according to desired CCT value, but it will also affect actual WW/CW ratio // when correctWB is true we need to correct/adjust RGB value according to desired CCT value, but it will also affect actual WW/CW ratio
// when cctFromRgb is true we implicitly calculate WW and CW from RGB values // when cctFromRgb is true we implicitly calculate WW and CW from RGB values
if (cctFromRgb) BusManager::setSegmentCCT(-1); if (cctFromRgb) BusManager::setSegmentCCT(-1);
@ -1375,13 +1388,14 @@ void WS2812FX::service() {
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer // overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
// would need to be allocated for each effect and then blended together for each pixel. // would need to be allocated for each effect and then blended together for each pixel.
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition [[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition
seg.beginDraw(); // set up parameters for get/setPixelColor()
delay = (*_mode[seg.mode])(); // run new/current mode delay = (*_mode[seg.mode])(); // run new/current mode
#ifndef WLED_DISABLE_MODE_BLEND #ifndef WLED_DISABLE_MODE_BLEND
if (modeBlending && seg.mode != tmpMode) { if (modeBlending && seg.mode != tmpMode) {
Segment::tmpsegd_t _tmpSegData; Segment::tmpsegd_t _tmpSegData;
Segment::modeBlend(true); // set semaphore Segment::modeBlend(true); // set semaphore
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state) seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
_virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed) seg.beginDraw(); // set up parameters for get/setPixelColor()
unsigned d2 = (*_mode[tmpMode])(); // run old mode unsigned d2 = (*_mode[tmpMode])(); // run old mode
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state) seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
delay = MIN(delay,d2); // use shortest delay delay = MIN(delay,d2); // use shortest delay
@ -1397,7 +1411,6 @@ void WS2812FX::service() {
} }
_segment_index++; _segment_index++;
} }
_virtualSegmentLength = 0;
_isServicing = false; _isServicing = false;
_triggered = false; _triggered = false;

View File

@ -416,18 +416,18 @@ void realtimeLock(uint32_t timeoutMs, byte md)
start = mainseg.start; start = mainseg.start;
stop = mainseg.stop; stop = mainseg.stop;
mainseg.freeze = true; mainseg.freeze = true;
// if WLED was off and using main segment only, freeze non-main segments so they stay off
if (bri == 0) {
for (size_t s = 0; s < strip.getSegmentsNum(); s++) {
strip.getSegment(s).freeze = true;
}
}
} else { } else {
start = 0; start = 0;
stop = strip.getLengthTotal(); stop = strip.getLengthTotal();
} }
// clear strip/segment // clear strip/segment
for (size_t i = start; i < stop; i++) strip.setPixelColor(i,BLACK); for (size_t i = start; i < stop; i++) strip.setPixelColor(i,BLACK);
// if WLED was off and using main segment only, freeze non-main segments so they stay off
if (useMainSegmentOnly && bri == 0) {
for (size_t s=0; s < strip.getSegmentsNum(); s++) {
strip.getSegment(s).freeze = true;
}
}
} }
// if strip is off (bri==0) and not already in RTM // if strip is off (bri==0) and not already in RTM
if (briT == 0 && !realtimeMode && !realtimeOverride) { if (briT == 0 && !realtimeMode && !realtimeOverride) {
@ -510,12 +510,10 @@ void handleNotifications()
rgbUdp.read(lbuf, packetSize); rgbUdp.read(lbuf, packetSize);
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION); realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
unsigned id = 0;
unsigned totalLen = strip.getLengthTotal(); unsigned totalLen = strip.getLengthTotal();
for (size_t i = 0; i < packetSize -2; i += 3) if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
{ for (size_t i = 0, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++) {
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0); setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
id++; if (id >= totalLen) break;
} }
if (!(realtimeMode && useMainSegmentOnly)) strip.show(); if (!(realtimeMode && useMainSegmentOnly)) strip.show();
return; return;
@ -595,17 +593,11 @@ void handleNotifications()
unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
unsigned totalLen = strip.getLengthTotal(); unsigned totalLen = strip.getLengthTotal();
for (size_t i = 6; i < tpmPayloadFrameSize + 4U; i += 3) if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
{ for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) {
if (id < totalLen)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++;
} }
else break; if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received
}
if (tpmPacketCount == numPackets) //reset packet count and show if all packets were received
{
tpmPacketCount = 0; tpmPacketCount = 0;
strip.show(); strip.show();
} }
@ -629,6 +621,7 @@ void handleNotifications()
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
unsigned totalLen = strip.getLengthTotal(); unsigned totalLen = strip.getLengthTotal();
if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
if (udpIn[0] == 1 && packetSize > 5) //warls if (udpIn[0] == 1 && packetSize > 5) //warls
{ {
for (size_t i = 2; i < packetSize -3; i += 4) for (size_t i = 2; i < packetSize -3; i += 4)
@ -637,39 +630,29 @@ void handleNotifications()
} }
} else if (udpIn[0] == 2 && packetSize > 4) //drgb } else if (udpIn[0] == 2 && packetSize > 4) //drgb
{ {
unsigned id = 0; for (size_t i = 2, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++)
for (size_t i = 2; i < packetSize -2; i += 3)
{ {
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++; if (id >= totalLen) break;
} }
} else if (udpIn[0] == 3 && packetSize > 6) //drgbw } else if (udpIn[0] == 3 && packetSize > 6) //drgbw
{ {
unsigned id = 0; for (size_t i = 2, id = 0; i < packetSize -3 && id < totalLen; i += 4, id++)
for (size_t i = 2; i < packetSize -3; i += 4)
{ {
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]); setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
id++; if (id >= totalLen) break;
} }
} else if (udpIn[0] == 4 && packetSize > 7) //dnrgb } else if (udpIn[0] == 4 && packetSize > 7) //dnrgb
{ {
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00); unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (size_t i = 4; i < packetSize -2; i += 3) for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 3, id++)
{ {
if (id >= totalLen) break;
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++;
} }
} else if (udpIn[0] == 5 && packetSize > 8) //dnrgbw } else if (udpIn[0] == 5 && packetSize > 8) //dnrgbw
{ {
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00); unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
for (size_t i = 4; i < packetSize -2; i += 4) for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 4, id++)
{ {
if (id >= totalLen) break;
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]); setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
id++;
} }
} }
strip.show(); strip.show();
@ -705,8 +688,7 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
w = gamma8(w); w = gamma8(w);
} }
if (useMainSegmentOnly) { if (useMainSegmentOnly) {
Segment &seg = strip.getMainSegment(); strip.getMainSegment().setPixelColor(pix, r, g, b, w); // this expects that strip.getMainSegment().beginDraw() has been called in handleNotification()
if (pix<seg.length()) seg.setPixelColor(pix, r, g, b, w);
} else { } else {
strip.setPixelColor(pix, r, g, b, w); strip.setPixelColor(pix, r, g, b, w);
} }

View File

@ -152,6 +152,7 @@ void getSettingsJS(byte subPage, Print& settingsScript)
DEBUG_PRINTF_P(PSTR("settings resp %u\n"), (unsigned)subPage); DEBUG_PRINTF_P(PSTR("settings resp %u\n"), (unsigned)subPage);
if (subPage <0 || subPage >10) return; if (subPage <0 || subPage >10) return;
char nS[32];
if (subPage == SUBPAGE_MENU) if (subPage == SUBPAGE_MENU)
{ {
@ -259,8 +260,6 @@ void getSettingsJS(byte subPage, Print& settingsScript)
if (subPage == SUBPAGE_LEDS) if (subPage == SUBPAGE_LEDS)
{ {
char nS[32];
appendGPIOinfo(settingsScript); appendGPIOinfo(settingsScript);
settingsScript.print(SET_F("d.ledTypes=")); settingsScript.print(BusManager::getLEDTypesJSONString().c_str()); settingsScript.print(";"); settingsScript.print(SET_F("d.ledTypes=")); settingsScript.print(BusManager::getLEDTypesJSONString().c_str()); settingsScript.print(";");
@ -399,7 +398,6 @@ void getSettingsJS(byte subPage, Print& settingsScript)
if (subPage == SUBPAGE_SYNC) if (subPage == SUBPAGE_SYNC)
{ {
[[maybe_unused]] char nS[32];
printSetFormValue(settingsScript,PSTR("UP"),udpPort); printSetFormValue(settingsScript,PSTR("UP"),udpPort);
printSetFormValue(settingsScript,PSTR("U2"),udpPort2); printSetFormValue(settingsScript,PSTR("U2"),udpPort2);
#ifndef WLED_DISABLE_ESPNOW #ifndef WLED_DISABLE_ESPNOW