diff --git a/wled00/FX.h b/wled00/FX.h index 4354b3f9..edcd3bcc 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -429,7 +429,7 @@ typedef struct Segment { //uint16_t _aux0, _aux1; // previous mode/effect runtime data //uint32_t _step, _call; // previous mode/effect runtime data //byte *_data; // previous mode/effect runtime data - uint32_t _start; + unsigned long _start; // must accommodate millis() uint16_t _dur; Transition(uint16_t dur=750) : _briT(255) @@ -518,8 +518,8 @@ typedef struct Segment { #endif if (!Segment::_globalLeds && (ledsrgb != nullptr)) {free(ledsrgb); ledsrgb = nullptr;} - if (name) delete[] name; - if (_t) delete _t; + if (name) { delete[] name; name = nullptr; } + if (_t) { transitional = false; delete _t; _t = nullptr; } deallocateData(); } @@ -537,7 +537,7 @@ typedef struct Segment { inline bool hasRGB(void) const { return _isRGB; } inline bool hasWhite(void) const { return _hasW; } inline bool isCCT(void) const { return _isCCT; } - inline uint16_t width(void) const { return (stop > start) ? (stop - start) : 0; } // segment width in physical pixels (length if 1D) + inline uint16_t width(void) const { return isActive() ? (stop - start) : 0; } // segment width in physical pixels (length if 1D) inline uint16_t height(void) const { return (stopY > startY) ? (stopY - startY) : 0; } // segment height (if 2D) in physical pixels // WLEDMM make sure its always > 0 inline uint16_t length(void) const { return width() * height(); } // segment length (count) in physical pixels inline uint16_t groupLength(void) const { return max(1, grouping + spacing); } // WLEDMM length = 0 could lead to div/0 in virtualWidth() and virtualHeight() diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 11d9ccb1..6dfc77b3 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -306,6 +306,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa, bool fast // returns RGBW values of pixel uint32_t Segment::getPixelColorXY(uint16_t x, uint16_t y) { + if (!isActive()) return 0; // not active int i = XY(x,y); if (ledsrgb) return RGBW32(ledsrgb[i].r, ledsrgb[i].g, ledsrgb[i].b, 0); if (reverse ) x = virtualWidth() - x - 1; @@ -324,6 +325,7 @@ void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t // Adds the specified color with the existing pixel color perserving color balance. void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) { + 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 uint32_t col = getPixelColorXY(x,y); uint8_t r = R(col); @@ -343,12 +345,14 @@ void Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) { } void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { + if (!isActive()) return; // not active CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade); setPixelColorXY(x, y, pix); } // blurRow: perform a blur on a row of a rectangular matrix void Segment::blurRow(uint16_t row, fract8 blur_amount) { + if (!isActive()) return; // not active const uint_fast16_t cols = virtualWidth(); const uint_fast16_t rows = virtualHeight(); @@ -376,6 +380,7 @@ void Segment::blurRow(uint16_t row, fract8 blur_amount) { // blurCol: perform a blur on a column of a rectangular matrix void Segment::blurCol(uint16_t col, fract8 blur_amount) { + if (!isActive()) return; // not active const uint_fast16_t cols = virtualWidth(); const uint_fast16_t rows = virtualHeight(); @@ -455,6 +460,7 @@ void Segment::blur1d(fract8 blur_amount) { //WLEDMM: use fast types } void Segment::moveX(int8_t delta, bool wrap) { + if (!isActive()) return; // not active const uint16_t cols = virtualWidth(); const uint16_t rows = virtualHeight(); if (!delta || abs(delta) >= cols) return; @@ -472,6 +478,7 @@ void Segment::moveX(int8_t delta, bool wrap) { } void Segment::moveY(int8_t delta, bool wrap) { + if (!isActive()) return; // not active const uint16_t cols = virtualWidth(); const uint16_t rows = virtualHeight(); if (!delta || abs(delta) >= rows) return; @@ -507,6 +514,7 @@ void Segment::move(uint8_t dir, uint8_t delta, bool wrap) { } void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { + if (!isActive()) return; // not active // Bresenham’s Algorithm int d = 3 - (2*radius); int y = radius, x = 0; @@ -531,6 +539,7 @@ void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { // by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { + if (!isActive()) return; // not active const uint16_t cols = virtualWidth(); const uint16_t rows = virtualHeight(); for (int16_t y = -radius; y <= radius; y++) { @@ -544,6 +553,7 @@ void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { } void Segment::nscale8(uint8_t scale) { //WLEDMM: use fast types + if (!isActive()) return; // not active const uint_fast16_t cols = virtualWidth(); const uint_fast16_t rows = virtualHeight(); for(uint_fast16_t y = 0; y < rows; y++) for (uint_fast16_t x = 0; x < cols; x++) { @@ -553,6 +563,7 @@ void Segment::nscale8(uint8_t scale) { //WLEDMM: use fast types //line function void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) { + if (!isActive()) return; // not active const uint16_t cols = virtualWidth(); const uint16_t rows = virtualHeight(); if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return; @@ -569,6 +580,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 } void Segment::drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color, uint32_t fillColor) { + if (!isActive()) return; // not active // float step = degrees / (2.85f*MAX(radius,1)); // for (float rad = 0.0f; rad <= degrees+step/2; rad += step) { // // may want to try float version as well (with or without antialiasing) @@ -637,6 +649,7 @@ bool Segment::jsonToPixels(char * name, uint8_t fileNr) { // draws a raster font character on canvas // only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2) { + if (!isActive()) return; // not active if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported chr -= 32; // align with font table entries const uint16_t cols = virtualWidth(); @@ -672,6 +685,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, #define WU_WEIGHT(a,b) ((uint8_t) (((a)*(b)+(a)+(b))>>8)) void Segment::wu_pixel(uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel procedure by reddit u/sutaburosu + if (!isActive()) return; // not active // extract the fractional parts and derive their inverses uint8_t xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy; // calculate the intensities for each affected pixel diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 5ecf66d2..21b199b1 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -96,6 +96,7 @@ uint16_t Segment::maxHeight = 1; Segment::Segment(const Segment &orig) { USER_PRINTLN(F("-- Copy segment constructor --")); memcpy((void*)this, (void*)&orig, sizeof(Segment)); //WLEDMM copy to this + transitional = false; // copied segment cannot be in transition name = nullptr; data = nullptr; _dataLen = 0; @@ -103,8 +104,8 @@ Segment::Segment(const Segment &orig) { if (ledsrgb && !Segment::_globalLeds) {ledsrgb = nullptr; ledsrgbSize = 0;} // WLEDMM if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } - if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } - else markForReset(); // WLEDMM + //if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } + //else markForReset(); // WLEDMM // if (orig.ledsrgb && !Segment::_globalLeds) { allocLeds(); if (ledsrgb) memcpy(ledsrgb, orig.ledsrgb, sizeof(CRGB)*length()); } // WLEDMM jMap = nullptr; //WLEDMM jMap } @@ -136,6 +137,7 @@ void Segment::allocLeds() { Segment::Segment(Segment &&orig) noexcept { USER_PRINTLN(F("-- Move segment constructor --")); memcpy((void*)this, (void*)&orig, sizeof(Segment)); + orig.transitional = false; // old segment cannot be in transition any more orig.name = nullptr; orig.data = nullptr; orig._dataLen = 0; @@ -150,6 +152,7 @@ Segment& Segment::operator= (const Segment &orig) { USER_PRINTLN(F("-- Copy-assignment segment --")); if (this != &orig) { // clean destination + transitional = false; // copied segment cannot be in transition if (name) delete[] name; if (_t) delete _t; CRGB* oldLeds = ledsrgb; @@ -158,6 +161,7 @@ Segment& Segment::operator= (const Segment &orig) { deallocateData(); // copy source memcpy((void*)this, (void*)&orig, sizeof(Segment)); + transitional = false; // erase pointers to allocated data name = nullptr; data = nullptr; @@ -168,8 +172,8 @@ Segment& Segment::operator= (const Segment &orig) { // copy source data if (orig.name) { name = new char[strlen(orig.name)+1]; if (name) strcpy(name, orig.name); } if (orig.data) { if (allocateData(orig._dataLen)) memcpy(data, orig.data, orig._dataLen); } - if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } - else markForReset(); // WLEDMM + //if (orig._t) { _t = new Transition(orig._t->_dur, orig._t->_briT, orig._t->_cctT, orig._t->_colorT); } + //else markForReset(); // WLEDMM //if (orig.ledsrgb && !Segment::_globalLeds) { allocLeds(); if (ledsrgb) memcpy(ledsrgb, orig.ledsrgb, sizeof(CRGB)*length()); } // WLEDMM don't copy old buffer jMap = nullptr; //WLEDMM jMap } @@ -180,9 +184,10 @@ Segment& Segment::operator= (const Segment &orig) { Segment& Segment::operator= (Segment &&orig) noexcept { USER_PRINTLN(F("-- Move-assignment segment --")); if (this != &orig) { - if (name) delete[] name; // free old name + transitional = false; // just temporary + if (name) { delete[] name; name = nullptr; } // free old name deallocateData(); // free old runtime data - if (_t) delete _t; + if (_t) { delete _t; _t = nullptr; } if (ledsrgb && !Segment::_globalLeds) free(ledsrgb); //WLEDMM: not needed anymore as we will use leds from copy. no need to nullify ledsrgb as it gets new value in memcpy memcpy((void*)this, (void*)&orig, sizeof(Segment)); orig.name = nullptr; @@ -408,16 +413,16 @@ void Segment::startTransition(uint16_t dur) { // transition progression between 0-65535 uint16_t Segment::progress() { if (!transitional || !_t) return 0xFFFFU; - uint32_t timeNow = millis(); + unsigned long timeNow = millis(); if (timeNow - _t->_start > _t->_dur || _t->_dur == 0) return 0xFFFFU; return (timeNow - _t->_start) * 0xFFFFU / _t->_dur; } uint8_t Segment::currentBri(uint8_t briNew, bool useCct) { - if (transitional && _t) { - uint32_t prog = progress() + 1; - if (useCct) return ((briNew * prog) + _t->_cctT * (0x10000 - prog)) >> 16; - else return ((briNew * prog) + _t->_briT * (0x10000 - prog)) >> 16; + uint32_t prog = progress(); + if (transitional && _t && prog < 0xFFFFU) { + if (useCct) return ((briNew * prog) + _t->_cctT * (0xFFFFU - prog)) >> 16; + else return ((briNew * prog) + _t->_briT * (0xFFFFU - prog)) >> 16; } else { return briNew; } @@ -437,7 +442,7 @@ CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal // blend palettes // there are about 255 blend passes of 48 "blends" to completely blend two palettes (in _dur time) // minimum blend time is 100ms maximum is 65535ms - uint32_t timeMS = millis() - _t->_start; + unsigned long timeMS = millis() - _t->_start; uint16_t noOfBlends = (255U * timeMS / _t->_dur) - _t->_prevPaletteBlends; for (int i=0; i_prevPaletteBlends++) nblendPaletteTowardPalette(_t->_palT, targetPalette, 48); targetPalette = _t->_palT; // copy transitioning/temporary palette @@ -828,6 +833,7 @@ void xyFromBlock(uint16_t &x,uint16_t &y, uint16_t i, uint16_t vW, uint16_t vH, void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATTR conditionaly { + if (!isActive()) return; // not active #ifndef WLED_DISABLE_2D int vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows) #endif @@ -974,6 +980,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT // anti-aliased normalized version of setPixelColor() void Segment::setPixelColor(float i, uint32_t col, bool aa) { + if (!isActive()) return; // not active int vStrip = int(i/10.0f); // hack to allow running on virtual strips (2D segment columns/rows) i -= int(i); @@ -1005,6 +1012,7 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa) uint32_t Segment::getPixelColor(int i) { + if (!isActive()) return 0; // not active #ifndef WLED_DISABLE_2D int vStrip = i>>16; #endif @@ -1099,6 +1107,11 @@ void Segment::refreshLightCapabilities() { uint16_t segStartIdx = 0xFFFFU; uint16_t segStopIdx = 0; + if (!isActive()) { + _capabilities = 0; + return; + } + if (start < Segment::maxWidth * Segment::maxHeight) { // we are withing 2D matrix (includes 1D segments) for (int y = startY; y < stopY; y++) for (int x = start; x < stop; x++) { @@ -1143,6 +1156,7 @@ void Segment::refreshLightCapabilities() { * Fills segment with color */ void Segment::fill(uint32_t c) { + if (!isActive()) return; // not active const uint_fast16_t cols = is2D() ? virtualWidth() : virtualLength(); // WLEDMM use fast int types const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D for(uint_fast16_t y = 0; y < rows; y++) for (uint_fast16_t x = 0; x < cols; x++) { @@ -1158,6 +1172,7 @@ void Segment::blendPixelColor(int n, uint32_t color, uint8_t blend) { // Adds the specified color with the existing pixel color perserving color balance. void Segment::addPixelColor(int n, uint32_t color, bool fast) { + if (!isActive()) return; // not active uint32_t col = getPixelColor(n); uint8_t r = R(col); uint8_t g = G(col); @@ -1176,6 +1191,7 @@ void Segment::addPixelColor(int n, uint32_t color, bool fast) { } void Segment::fadePixelColor(uint16_t n, uint8_t fade) { + if (!isActive()) return; // not active CRGB pix = CRGB(getPixelColor(n)).nscale8_video(fade); setPixelColor(n, pix); } @@ -1184,6 +1200,7 @@ void Segment::fadePixelColor(uint16_t n, uint8_t fade) { * fade out function, higher rate = quicker fade */ void Segment::fade_out(uint8_t rate) { + if (!isActive()) return; // not active const uint_fast16_t cols = is2D() ? virtualWidth() : virtualLength(); // WLEDMM use fast int types const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D @@ -1222,7 +1239,7 @@ void Segment::fade_out(uint8_t rate) { // fades all pixels to black using nscale8() void Segment::fadeToBlackBy(uint8_t fadeBy) { - if (fadeBy == 0) return; // optimization - no scaling to apply + if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply const uint_fast16_t cols = is2D() ? virtualWidth() : virtualLength(); // WLEDMM use fast int types const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D const uint_fast8_t scaledown = 255-fadeBy; // WLEDMM faster to pre-compute this @@ -1244,7 +1261,7 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) { */ void Segment::blur(uint8_t blur_amount) { - if (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 if (is2D()) { // compatibility with 2D