Skip to content

Commit e90c97a

Browse files
committed
Tetrix fix and realloc robustness
1 parent 0dca0ab commit e90c97a

File tree

5 files changed

+59
-61
lines changed

5 files changed

+59
-61
lines changed

src/MoonLight/Nodes/Drivers/D__Sandbox.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
// add documentation in /docs/moonlight/drivers.md
1717
class ExampleDriver : public Node {
1818
public:
19-
static const char* name() { return "Example Driver"; }
19+
static const char* name() { return "Example"; }
2020
static uint8_t dim() { return _NoD; } // Dimensions not relevant for drivers?
2121
static const char* tags() { return "☸️⏳"; } // use emojis see https://moonmodules.org/MoonLight/moonlight/overview/#emoji-coding, ☸️ for drivers
2222

src/MoonLight/Nodes/Effects/E_MoonLight.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,16 +1329,15 @@ class SpiralFireEffect : public Node {
13291329
}
13301330
};
13311331

1332-
const uint32_t colors[] = {0x000000, 0x100000, 0x300000, 0x600000, 0x800000, 0xA00000, 0xC02000, 0xC04000, 0xC06000, 0xC08000, 0x807080};
1333-
13341332
// https://github.com/toggledbits/MatrixFireFast/blob/master/MatrixFireFast/MatrixFireFast.ino
13351333
class FireEffect : public Node {
13361334
public:
13371335
static const char* name() { return "Fire"; }
13381336
static uint8_t dim() { return _2D; }
13391337
static const char* tags() { return "💫"; }
13401338

1341-
uint8_t NCOLORS = std::size(colors);
1339+
const uint32_t colors[11] = {0x000000, 0x100000, 0x300000, 0x600000, 0x800000, 0xA00000, 0xC02000, 0xC04000, 0xC06000, 0xC08000, 0x807080};
1340+
const uint8_t NCOLORS = std::size(colors);
13421341

13431342
void glow(int x, int y, int z, uint8_t flareDecay, bool usePalette) {
13441343
int b = z * 10 / flareDecay + 1;

src/MoonLight/Nodes/Effects/E_WLED.h

Lines changed: 54 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {
535541
class 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

src/MoonLight/Nodes/Layouts/L__Sandbox.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
// add documentation in /docs/moonlight/layouts.md
1717
class ExampleLayout : public Node {
1818
public:
19-
static const char* name() { return "Example Layout"; }
19+
static const char* name() { return "Example"; }
2020
static uint8_t dim() { return _3D; } // dimensions supported
2121
static const char* tags() { return "🚥⏳"; } // use emojis see https://moonmoduÍles.org/MoonLight/moonlight/overview/#emoji-coding, 🚥 for layout
2222

src/MoonLight/Nodes/Modifiers/M__Sandbox.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
// add documentation in /docs/moonlight/modifiers.md
1717
class ExampleModifier : public Node {
1818
public:
19-
static const char* name() { return "Example Modifier"; }
19+
static const char* name() { return "Example"; }
2020
static uint8_t dim() { return _3D; } // for which effect dimension this modifier can be used, preferably 3D
2121
static const char* tags() { return "💎⏳"; } // use emojis see https://moonmodules.org/MoonLight/moonlight/overview/#emoji-coding, 💎 for modifier
2222

0 commit comments

Comments
 (0)