@@ -26,15 +26,18 @@ class BouncingBallsEffect : public Node {
2626 }
2727
2828 Ball (*balls)[maxNumBalls] = nullptr ; // [maxColumns][maxNumBalls];
29+ uint16_t ballsSize = 0 ;
2930
3031 ~BouncingBallsEffect () override { freeMB (balls); }
3132
3233 void onSizeChanged (const Coord3D& prevSize) override {
33- freeMB (balls);
34- balls = allocMB<Ball[maxNumBalls]>(layer->size .y );
34+ Ball (*newAlloc)[maxNumBalls] = reallocMB<Ball[maxNumBalls]>(balls, layer->size .y );
3535
36- if (!balls) {
37- EXT_LOGE (ML_TAG, " allocate balls failed" );
36+ if (newAlloc) {
37+ balls = newAlloc;
38+ ballsSize = layer->size .x ;
39+ } else {
40+ EXT_LOGE (ML_TAG, " (re)allocate balls failed" );
3841 }
3942 }
4043
@@ -53,7 +56,7 @@ class BouncingBallsEffect : public Node {
5356 // for (size_t i = 0; i < maxNumBalls; i++) balls[i].lastBounceTime = time;
5457 // }
5558
56- for (int y = 0 ; y < layer->size .y ; y++) {
59+ for (int y = 0 ; y < MIN ( layer->size .y , ballsSize) ; y++) {
5760 for (size_t i = 0 ; i < MIN (numBalls, maxNumBalls); i++) {
5861 float timeSinceLastBounce = (time - balls[y][i].lastBounceTime ) / ((255 - grav) / 64 + 1 );
5962 float timeSec = timeSinceLastBounce / 1000 .0f ;
@@ -328,15 +331,18 @@ class GEQEffect : public Node {
328331 step = millis ();
329332 }
330333
331- uint16_t * previousBarHeight = nullptr ; // array
334+ uint16_t * previousBarHeight = nullptr ;
335+ uint8_t previousBarHeightSize = 0 ;
332336
333337 ~GEQEffect () { freeMB (previousBarHeight); }
334338
335339 void onSizeChanged (const Coord3D& prevSize) override {
336- freeMB (previousBarHeight);
337- previousBarHeight = allocMB<uint16_t >(layer->size .x );
338- if (!previousBarHeight) {
339- EXT_LOGE (ML_TAG, " allocate previousBarHeight failed" );
340+ uint16_t * newAlloc = reallocMB<uint16_t >(previousBarHeight, layer->size .x );
341+ if (newAlloc) {
342+ previousBarHeight = newAlloc;
343+ previousBarHeightSize = layer->size .x ;
344+ } else {
345+ EXT_LOGE (ML_TAG, " (re)allocate previousBarHeight failed" );
340346 }
341347 }
342348
@@ -409,7 +415,7 @@ class GEQEffect : public Node {
409415 layer->setRGB (Coord3D (pos.x , layer->size .y - 1 - pos.y ), ledColor);
410416 }
411417
412- if (previousBarHeight) {
418+ if (previousBarHeight && pos. x < previousBarHeightSize ) {
413419 if (barHeight > previousBarHeight[pos.x ]) previousBarHeight[pos.x ] = barHeight; // drive the peak up
414420 if ((ripple > 0 ) && (previousBarHeight[pos.x ] > 0 ) && (previousBarHeight[pos.x ] < layer->size .y )) // WLEDMM avoid "overshooting" into other segments
415421 layer->setRGB (Coord3D (pos.x , layer->size .y - previousBarHeight[pos.x ]), (CRGB)CHSV (millis () / 50 , 255 , 255 )); // take millis()/50 color for the time being
@@ -535,12 +541,12 @@ typedef struct PacManChars {
535541class PacManEffect : public Node {
536542 public:
537543 static const char * name () { return " PacMan" ; }
538- static uint8_t dim () { return _1D; } // it is a 1D effect, todo: 2D
544+ static uint8_t dim () { return _1D; } // it is a 1D effect, todo: 2D
539545 static const char * tags () { return " 🔥🐙" ; }
540546
541547 // static const char _data_FX_MODE_PACMAN[] PROGMEM = "PacMan@Speed,# of PowerDots,Blink distance,Blur,# of Ghosts,Dots,Smear,Compact;;!;1;m12=0,sx=192,ix=64,c1=64,c2=0,c3=12,o1=1,o2=0";
542548 uint8_t speed = 192 ;
543- uint8_t numPowerDotsUI = 64 ;
549+ uint8_t numPowerDotsControl = 64 ;
544550 uint8_t blinkDistance = 64 ;
545551 uint8_t blur = 0 ;
546552 uint8_t numGhosts = 4 ;
@@ -550,7 +556,7 @@ class PacManEffect : public Node {
550556
551557 void setup () override {
552558 addControl (speed, " speed" , " slider" );
553- addControl (numPowerDotsUI , " #powerdots" , " slider" );
559+ addControl (numPowerDotsControl , " #powerdots" , " slider" );
554560 addControl (blinkDistance, " blinkDistance" , " slider" , 20 , 255 );
555561 addControl (blur, " blur" , " slider" );
556562 addControl (numGhosts, " #ghosts" , " slider" , 2 , 8 );
@@ -583,16 +589,16 @@ class PacManEffect : public Node {
583589 const uint32_t ghostColors[4 ] = {CRGB::Red, PURPLEISH, CRGB::Cyan, ORANGEISH};
584590
585591 void initializePacMan () {
586- numPowerDots = MIN (layer->nrOfLights / 10U , numPowerDotsUI ); // cap the max so packed state fits in 8 bits: ML: keep the nr visible in the UI
592+ numPowerDots = MIN (layer->nrOfLights / 10U , numPowerDotsControl ); // cap the max so packed state fits in 8 bits: ML: keep the nr visible in the UI
587593
588- EXT_LOGD (ML_TAG, " #l:%d #pd:%d #g:%d #pd:%d" , layer->nrOfLights , numPowerDotsUI , numGhosts, numPowerDots);
594+ EXT_LOGD (ML_TAG, " #l:%d #pd:%d #g:%d #pd:%d" , layer->nrOfLights , numPowerDotsControl , numGhosts, numPowerDots);
589595
590596 pacmancharacters_t * newAlloc = reallocMB<pacmancharacters_t >(character, numGhosts + numPowerDots + 1 ); // +1 is the PacMan character
591597 if (newAlloc) {
592598 character = newAlloc;
593599 nrOfCharacters = numGhosts + numPowerDots + 1 ;
594600 } else {
595- EXT_LOGE (ML_TAG, " allocate character failed" ); // keep old (if existed)
601+ EXT_LOGE (ML_TAG, " (re) allocate character failed" ); // keep old (if existed)
596602 }
597603
598604 if (nrOfCharacters > 0 ) {
@@ -769,15 +775,15 @@ class TetrixEffect : public Node {
769775 static uint8_t dim () { return _2D; }
770776 static const char * tags () { return " 🔥🐙🎨" ; } // use emojis see https://moonmodules.org/MoonLight/moonlight/overview/#emoji-coding, 🔥 for effect, 🎨 if palette used (recommended)
771777
772- uint8_t speed = 0 ; // 1 beat per second
778+ uint8_t speedControl = 0 ; // 1 beat per second
773779 uint8_t width = 0 ;
774780 bool oneColor = false ;
775781 // static const char _data_FX_MODE_TETRIX[] PROGMEM = "Tetrix@!,Width,,,,One color;!,!;!;1.5d;sx=0,ix=0,pal=11,m12=1"; // WLEDMM 1.5d
776782
777783 void setup () override {
778784 // controls will show in the UI
779785 // for different type of controls see other Nodes
780- addControl (speed , " speed" , " slider" );
786+ addControl (speedControl , " speed" , " slider" );
781787 addControl (width, " width" , " slider" );
782788 addControl (oneColor, " oneColor" , " checkbox" );
783789 }
@@ -791,7 +797,7 @@ class TetrixEffect : public Node {
791797 drops = newAlloc;
792798 nrOfDrops = layer->size .y ;
793799 } else {
794- EXT_LOGE (ML_TAG, " allocate character failed" ); // keep old (if existed)
800+ EXT_LOGE (ML_TAG, " (re) allocate drops failed" ); // keep old (if existed)
795801 }
796802 for (int i = 0 ; i < nrOfDrops; i++) {
797803 drops[i].stack = 0 ; // reset brick stack size
@@ -802,14 +808,6 @@ class TetrixEffect : public Node {
802808
803809 ~TetrixEffect () override { freeMB (drops); };
804810
805- void onUpdate (const Char<20 >& oldValue, const JsonObject& control) {
806- // add your custom onUpdate code here
807- if (control[" name" ] == " bpm" ) {
808- if (control[" value" ] == 0 ) {
809- }
810- }
811- }
812-
813811 void loop () override {
814812 if (!drops) return ;
815813
@@ -823,14 +821,14 @@ class TetrixEffect : public Node {
823821 if (drops[y].step == 0 ) { // init brick
824822 // speed calculation: a single brick should reach bottom of strip in X seconds
825823 // if the speed is set to 1 this should take 5s and at 255 it should take 0.25s
826- // as this is dependant on layer->nrOfLights it should be taken into account and the fact that effect runs every FRAMETIME s
827- int speed = speed ? speed : random8 (1 , 255 );
828- speed = map (speed, 1 , 255 , 5000 , 250 ); // time taken for full (layer->nrOfLights ) drop
829- drops[y].speed = float (layer->nrOfLights * FRAMETIME) / float (speed); // set speed
830- drops[y].pos = layer->nrOfLights ; // start at end of segment (no need to subtract 1)
831- if (!oneColor) drops[y].col = random8 (0 , 15 ) << 4 ; // limit color choices so there is enough HUE gap
832- drops[y].step = 1 ; // drop state (0 init, 1 forming, 2 falling)
833- drops[y].brick = (width ? (width >> 5 ) + 1 : random8 (1 , 5 )) * (1 + (layer->nrOfLights >> 6 )); // size of brick
824+ // as this is dependant on layer->size.x it should be taken into account and the fact that effect runs every FRAMETIME s
825+ int speed = speedControl ? speedControl : random8 (1 , 255 );
826+ speed = map (speed, 1 , 255 , 5000 , 250 ); // time taken for full (layer->size.x ) drop
827+ drops[y].speed = float (layer->size . x * FRAMETIME) / float (speed); // set speed
828+ drops[y].pos = layer->size . x ; // start at end of segment (no need to subtract 1)
829+ if (!oneColor) drops[y].col = random8 (0 , 15 ) << 4 ; // limit color choices so there is enough HUE gap
830+ drops[y].step = 1 ; // drop state (0 init, 1 forming, 2 falling)
831+ drops[y].brick = (width ? (width >> 5 ) + 1 : random8 (1 , 5 )) * (1 + (layer->size . x >> 6 )); // size of brick
834832 }
835833
836834 if (drops[y].step == 1 ) { // forming
@@ -842,23 +840,23 @@ class TetrixEffect : public Node {
842840 if (drops[y].step == 2 ) { // falling
843841 if (drops[y].pos > drops[y].stack ) { // fall until top of stack
844842 drops[y].pos -= drops[y].speed ; // may add gravity as: speed += gravity
845- if (int ( drops[y].pos ) < int ( drops[y].stack ) ) drops[y].pos = drops[y].stack ;
846- for (int i = int ( drops[y].pos ) ; i < layer->nrOfLights ; i++) {
847- CRGB col = i < int ( drops[y].pos ) + drops[y].brick ? ColorFromPalette (layerP.palette , drops[y].col ) : CRGB::Black;
843+ if (drops[y].pos < drops[y].stack ) drops[y].pos = drops[y].stack ;
844+ for (int i = drops[y].pos ; i < layer->size . x ; i++) {
845+ CRGB col = i < drops[y].pos + drops[y].brick ? ColorFromPalette (layerP.palette , drops[y].col ) : CRGB::Black;
848846 layer->setRGB (Coord3D (i, y), col);
849847 }
850- } else { // we hit bottom
851- drops[y].step = 0 ; // proceed with next brick, go back to init
852- drops[y].stack += drops[y].brick ; // increase the stack size
853- if (drops[y].stack >= layer->nrOfLights ) drops[y].step = millis () + 2000 ; // fade out stack
848+ } else { // we hit bottom
849+ drops[y].step = 0 ; // proceed with next brick, go back to init
850+ drops[y].stack += drops[y].brick ; // increase the stack size
851+ if (drops[y].stack >= layer->size . x ) drops[y].step = millis () + 2000 ; // fade out stack
854852 }
855853 }
856854
857855 if (drops[y].step > 2 ) { // fade strip
858856 drops[y].brick = 0 ; // reset brick size (no more growing)
859857 if (drops[y].step > millis ()) {
860858 // allow fading of virtual strip
861- for (int i = 0 ; i < layer->nrOfLights ; i++) layer->blendColor (Coord3D (i, y), CRGB::Black, 25 ); // 10% blend
859+ for (int i = 0 ; i < layer->size . x ; i++) layer->blendColor (Coord3D (i, y), CRGB::Black, 25 ); // 10% blend
862860 } else {
863861 drops[y].stack = 0 ; // reset brick stack size
864862 drops[y].step = 0 ; // proceed with next brick
@@ -1137,6 +1135,7 @@ class OctopusEffect : public Node {
11371135
11381136 Coord3D prevLedSize;
11391137 Map_t* rMap = nullptr ;
1138+ uint16_t rMapSize = 0 ;
11401139 uint32_t step;
11411140
11421141 ~OctopusEffect () { freeMB (rMap); }
@@ -1158,13 +1157,13 @@ class OctopusEffect : public Node {
11581157 }
11591158
11601159 void onSizeChanged (const Coord3D& prevSize) override {
1161- // freeMB(rMap);
11621160 Map_t* newAlloc = reallocMB<Map_t>(rMap, layer->size .x * layer->size .y );
1163- if (!newAlloc) {
1164- EXT_LOGE (ML_TAG, " allocate rMap failed" );
1165- } else {
1161+ if (newAlloc) {
11661162 rMap = newAlloc;
1163+ rMapSize = layer->size .x * layer->size .y ;
11671164 setRMap ();
1165+ } else {
1166+ EXT_LOGE (ML_TAG, " (re)allocate rMap failed" );
11681167 }
11691168 }
11701169
@@ -1181,7 +1180,7 @@ class OctopusEffect : public Node {
11811180 for (pos.x = 0 ; pos.x < layer->size .x ; pos.x ++) {
11821181 for (pos.y = 0 ; pos.y < layer->size .y ; pos.y ++) {
11831182 uint16_t indexV = layer->XYZUnModified (pos);
1184- if (indexV < layer-> size . x * layer-> size . y ) { // excluding UINT16_MAX from XY if out of bounds due to projection
1183+ if (indexV < rMapSize ) { // excluding UINT16_MAX from XY if out of bounds due to projection
11851184 byte angle = rMap[indexV].angle ;
11861185 byte radius = rMap[indexV].radius ;
11871186 uint16_t intensity;
@@ -1428,11 +1427,11 @@ class FlowEffect : public Node {
14281427 static const char * tags () { return " 🐙" ; } // 🐙 means wled origin
14291428
14301429 uint8_t speed = 128 ;
1431- uint8_t zonesUI = 128 ;
1430+ uint8_t zonesControl = 128 ;
14321431
14331432 void setup () override {
14341433 addControl (speed, " speed" , " slider" );
1435- addControl (zonesUI , " zones" , " slider" );
1434+ addControl (zonesControl , " zones" , " slider" );
14361435 }
14371436
14381437 void loop () override {
@@ -1443,7 +1442,7 @@ class FlowEffect : public Node {
14431442 }
14441443
14451444 uint16_t maxZones = layer->size .x / 6 ; // only looks good if each zone has at least 6 LEDs
1446- uint16_t zones = (zonesUI * maxZones) >> 8 ;
1445+ uint16_t zones = (zonesControl * maxZones) >> 8 ;
14471446 if (zones & 0x01 ) zones++; // zones must be even
14481447 if (zones < 2 ) zones = 2 ;
14491448 uint16_t zoneLen = layer->size .x / zones;
@@ -1581,13 +1580,13 @@ class DripEffect : public Node {
15811580 static uint8_t dim () { return _1D; }
15821581 static const char * tags () { return " 🐙💫" ; }
15831582
1584- uint8_t gravityUI = 128 ;
1583+ uint8_t gravityControl = 128 ;
15851584 uint8_t drips = 4 ;
15861585 uint8_t swell = 4 ;
15871586 bool invert = false ;
15881587
15891588 void setup () override {
1590- addControl (gravityUI , " gravity" , " slider" , 1 , 255 );
1589+ addControl (gravityControl , " gravity" , " slider" , 1 , 255 );
15911590 addControl (drips, " drips" , " slider" , 1 , 6 );
15921591 addControl (swell, " swell" , " slider" , 1 , 6 );
15931592 addControl (invert, " invert" , " checkbox" );
@@ -1600,7 +1599,7 @@ class DripEffect : public Node {
16001599 // layer->fadeToBlackBy(90);
16011600 layer->fill_solid (CRGB::Black);
16021601
1603- float gravity = -0 .0005f - (gravityUI / 25000 .0f ); // increased gravity (50000 to 25000)
1602+ float gravity = -0 .0005f - (gravityControl / 25000 .0f ); // increased gravity (50000 to 25000)
16041603 gravity *= max (1 , layer->size .x - 1 );
16051604 int sourcedrop = 12 ;
16061605
0 commit comments