@@ -1259,171 +1259,194 @@ static void mode_morsecode(void) {
12591259}
12601260static const char _data_FX_MODE_MORSECODE[] PROGMEM = " Morse Code@Speed,,,,Color mode,Color by Word,Punctuation,EndOfMessage;;!;1;sx=192,c3=8,o1=1,o2=1" ;
12611261
1262-
1263-
12641262/* *********************************************************************************************
12651263 * BrushWalker
12661264 * Uses palette for the trails and background color as fade target.
1267- * Walkers spawn randomly from the edges and move in straight lines across the matrix,
1268- * changing color as they go, leaving (fading) trails of "painted" color behind them.
1269- * Tries to avoid spawning new walkers too close to existing ones
1265+ * Walkers spawn randomly from the edges and move in straight lines across the
1266+ * matrix, changing color as they go, leaving (fading) trails of "painted" color
1267+ * behind them. Tries to avoid spawning new walkers too close to existing ones
12701268 * to prevent overcrowding and create a more visually appealing distribution.
1271- * Inspired by the concept of "Matrix", but with a more vivid, undirected and colorful twist.
1272- * First implementation 2019 with FastLED, but without WLED framework.
1273- * Redesigned and adapted for WLED in 2026, with parts from claude.ai, Gemini, chatGPT, Grok.
1274- * Controls: Speed, Spawn Chance, Fade Rate, Palette Step, Max Walkers (up to 32)
1269+ * Inspired by the concept of "Matrix", but with a more vivid, undirected and
1270+ * colorful twist. First implementation 2019 with FastLED, but without WLED
1271+ * framework. Redesigned and adapted for WLED in 2026, with parts from
1272+ * claude.ai, Gemini, chatGPT, Grok. Controls: Speed, Spawn Chance, Fade Rate,
1273+ * Palette Step, Max Walkers (up to 32)
12751274 *
12761275 * @author suromark 2019,2026
12771276 *
12781277 */
12791278namespace BrushWalkerFX {
12801279
1281- struct Walker {
1282- bool active;
1283- int16_t x, y;
1284- int8_t dx, dy;
1285- uint8_t colorIndex;
1280+ struct Walker {
1281+ bool active;
1282+ int16_t x, y;
1283+ int8_t dx, dy;
1284+ uint8_t colorIndex;
12861285
1287- void reset () {
1288- active = false ;
1289- x = y = dx = dy = colorIndex = 0 ;
1290- }
1286+ void reset () {
1287+ active = false ;
1288+ x = y = dx = dy = colorIndex = 0 ;
1289+ }
12911290
1292- // Generates a starting position and direction
1293- void makeCandidate (uint16_t cols, uint16_t rows) {
1294- uint8_t side = hw_random8 (4 );
1295- switch (side) {
1296- case 0 : x = hw_random16 (cols); y = 0 ; dx = 0 ; dy = 1 ; break ; // top
1297- case 1 : x = hw_random16 (cols); y = rows - 1 ; dx = 0 ; dy = -1 ; break ; // bottom
1298- case 2 : x = 0 ; y = hw_random16 (rows); dx = 1 ; dy = 0 ; break ; // left
1299- default : x = cols - 1 ; y = hw_random16 (rows); dx = -1 ; dy = 0 ; break ; // right
1300- }
1301- colorIndex = hw_random8 ();
1302- active = true ;
1291+ // Generates a starting position and direction
1292+ void makeCandidate (uint16_t cols, uint16_t rows) {
1293+ uint8_t side = hw_random8 (4 );
1294+ switch (side) {
1295+ case 0 :
1296+ x = hw_random16 (cols);
1297+ y = 0 ;
1298+ dx = 0 ;
1299+ dy = 1 ;
1300+ break ; // top
1301+ case 1 :
1302+ x = hw_random16 (cols);
1303+ y = rows - 1 ;
1304+ dx = 0 ;
1305+ dy = -1 ;
1306+ break ; // bottom
1307+ case 2 :
1308+ x = 0 ;
1309+ y = hw_random16 (rows);
1310+ dx = 1 ;
1311+ dy = 0 ;
1312+ break ; // left
1313+ default :
1314+ x = cols - 1 ;
1315+ y = hw_random16 (rows);
1316+ dx = -1 ;
1317+ dy = 0 ;
1318+ break ; // right
13031319 }
1320+ colorIndex = hw_random8 ();
1321+ active = true ;
1322+ }
13041323
1305- // Logic to prevent overcrowding
1306- bool hasConflict (const Walker *walkers, uint8_t maxCount, uint8_t minGap) {
1307- for (uint8_t i = 0 ; i < maxCount; i++) {
1308- const Walker &other = walkers[i];
1309- if (!other.active || &other == this ) continue ;
1310- if (other.dx != dx || other.dy != dy) continue ;
1311- if (dy == 0 && other.y == y && abs (other.x - x) < minGap) return true ;
1312- if (dx == 0 && other.x == x && abs (other.y - y) < minGap) return true ;
1313- }
1314- return false ;
1324+ // Logic to prevent overcrowding
1325+ bool hasConflict (const Walker* walkers, uint8_t maxCount, uint8_t minGap) {
1326+ for (uint8_t i = 0 ; i < maxCount; i++) {
1327+ const Walker& other = walkers[i];
1328+ if (!other.active || &other == this ) continue ;
1329+ if (other.dx != dx || other.dy != dy) continue ;
1330+ if (dy == 0 && other.y == y && abs (other.x - x) < minGap) return true ;
1331+ if (dx == 0 && other.x == x && abs (other.y - y) < minGap) return true ;
13151332 }
1333+ return false ;
1334+ }
13161335
1317- // Moves the walker and paints the pixel
1318- void update (uint16_t cols, uint16_t rows, uint8_t palStep) {
1319- if (!active) return ;
1320-
1321- uint32_t c = (SEGMENT.palette > 0 )
1322- ? SEGMENT.color_from_palette (colorIndex, false , PALETTE_SOLID_WRAP, 0 )
1323- : SEGCOLOR (0 );
1324-
1325- SEGMENT.setPixelColorXY (x, y, c);
1326-
1327- x += dx;
1328- y += dy;
1329- colorIndex += palStep;
1330-
1331- if (x < 0 || y < 0 || x >= (int16_t )cols || y >= (int16_t )rows) {
1332- active = false ;
1333- }
1334- }
1335- };
1336+ // Moves the walker and paints the pixel
1337+ void update (uint16_t cols, uint16_t rows, uint8_t palStep) {
1338+ if (!active) return ;
13361339
1337- static void trySpawn (Walker *walkers, uint8_t maxCount, uint16_t cols, uint16_t rows) {
1338- int freeSlot = -1 ;
1339- for (uint8_t i = 0 ; i < maxCount; i++) {
1340- if (!walkers[i].active ) { freeSlot = i; break ; }
1341- }
1342- if (freeSlot < 0 ) return ;
1340+ uint32_t c = (SEGMENT.palette > 0 )
1341+ ? SEGMENT.color_from_palette (colorIndex, false , PALETTE_SOLID_WRAP, 0 )
1342+ : SEGCOLOR (0 );
1343+
1344+ SEGMENT.setPixelColorXY (x, y, c);
13431345
1344- const uint8_t minGap = 8 ;
1345- for (uint8_t retry = 0 ; retry < 2 ; retry++) {
1346- walkers[freeSlot].makeCandidate (cols, rows);
1347- if (!walkers[freeSlot].hasConflict (walkers, maxCount, minGap)) return ;
1346+ x += dx;
1347+ y += dy;
1348+ colorIndex += palStep;
1349+
1350+ if (x < 0 || y < 0 || x >= (int16_t )cols || y >= (int16_t )rows) {
1351+ active = false ;
13481352 }
1349- walkers[freeSlot].active = false ;
13501353 }
1354+ };
13511355
1352- static void mode_brushwalker_core (uint8_t triggerMode) {
1353- const uint8_t absoluteMaxWalkers = 32 ;
1354- if (!strip.isMatrix || !SEGMENT.is2D ()) {
1355- SEGMENT.fill (SEGCOLOR (1 ));
1356- return ;
1356+ static void trySpawn (Walker* walkers, uint8_t maxCount, uint16_t cols, uint16_t rows) {
1357+ int freeSlot = -1 ;
1358+ for (uint8_t i = 0 ; i < maxCount; i++) {
1359+ if (!walkers[i].active ) {
1360+ freeSlot = i;
1361+ break ;
13571362 }
1363+ }
1364+ if (freeSlot < 0 ) return ;
13581365
1359- const uint16_t cols = SEG_W;
1360- const uint16_t rows = SEG_H;
1361- Walker *walkers = reinterpret_cast <Walker *>(SEGENV.data );
1366+ const uint8_t minGap = 8 ;
1367+ for (uint8_t retry = 0 ; retry < 2 ; retry++) {
1368+ walkers[freeSlot].makeCandidate (cols, rows);
1369+ if (!walkers[freeSlot].hasConflict (walkers, maxCount, minGap)) return ;
1370+ }
1371+ walkers[freeSlot].active = false ;
1372+ }
13621373
1363- if (SEGENV. call == 0 ) {
1364- if (!SEGENV. allocateData ( sizeof (Walker) * absoluteMaxWalkers)) return ;
1365- for ( uint8_t i = 0 ; i < absoluteMaxWalkers; i++) walkers[i]. reset ();
1366- SEGMENT.fill (SEGCOLOR (1 ));
1367- SEGENV. step = strip. now ;
1368- }
1374+ static void mode_brushwalker_core ( uint8_t triggerMode ) {
1375+ const uint8_t absoluteMaxWalkers = 32 ;
1376+ if (!strip. isMatrix || !SEGMENT. is2D ()) {
1377+ SEGMENT.fill (SEGCOLOR (1 ));
1378+ return ;
1379+ }
13691380
1370- uint16_t interval = 8 + ((255 - SEGMENT.speed ) >> 1 );
1371- if (strip.now - SEGENV.step < interval) return ;
1381+ const uint16_t cols = SEG_W;
1382+ const uint16_t rows = SEG_H;
1383+ Walker* walkers = reinterpret_cast <Walker*>(SEGENV.data );
1384+
1385+ if (SEGENV.call == 0 ) {
1386+ if (!SEGENV.allocateData (sizeof (Walker) * absoluteMaxWalkers)) return ;
1387+ for (uint8_t i = 0 ; i < absoluteMaxWalkers; i++) walkers[i].reset ();
1388+ SEGMENT.fill (SEGCOLOR (1 ));
13721389 SEGENV.step = strip.now ;
1390+ }
13731391
1374- uint8_t sensitivity = SEGMENT.intensity ;
1375- uint8_t fadeRate = SEGMENT.custom1 >> 1 ;
1376- uint8_t palStep = SEGMENT.custom2 >> 4 ;
1377- uint8_t maxWalkers = min ((int )(1 + SEGMENT.custom3 ), (int )absoluteMaxWalkers);
1378-
1379- SEGMENT.fadeToSecondaryBy (fadeRate);
1380-
1381- // Trigger Logic
1382- bool shouldSpawn = false ;
1383- if (triggerMode == 1 ) {
1384- um_data_t *um_data;
1385- if (!UsermodManager::getUMData (&um_data, USERMOD_ID_AUDIOREACTIVE))
1386- um_data = simulateSound (SEGMENT.soundSim );
1387- if (um_data && (*(uint8_t *)um_data->u_data [2 ] || hw_random8 () < sensitivity))
1388- shouldSpawn = true ;
1389- } else {
1390- if (hw_random8 () < sensitivity) shouldSpawn = true ;
1391- }
1392+ uint16_t interval = 8 + ((255 - SEGMENT.speed ) >> 1 );
1393+ if (strip.now - SEGENV.step < interval) return ;
1394+ SEGENV.step = strip.now ;
1395+
1396+ uint8_t sensitivity = SEGMENT.intensity ;
1397+ uint8_t fadeRate = SEGMENT.custom1 >> 1 ;
1398+ uint8_t palStep = SEGMENT.custom2 >> 4 ;
1399+ uint8_t maxWalkers = min ((int )(1 + SEGMENT.custom3 ), (int )absoluteMaxWalkers);
1400+
1401+ SEGMENT.fadeToSecondaryBy (fadeRate);
1402+
1403+ // Trigger Logic
1404+ bool shouldSpawn = false ;
1405+ if (triggerMode == 1 ) {
1406+ um_data_t * um_data;
1407+ if (!UsermodManager::getUMData (&um_data, USERMOD_ID_AUDIOREACTIVE))
1408+ um_data = simulateSound (SEGMENT.soundSim );
1409+ if (um_data &&
1410+ (*(uint8_t *)um_data->u_data [2 ] || hw_random8 () < sensitivity))
1411+ shouldSpawn = true ;
1412+ } else {
1413+ if (hw_random8 () < sensitivity) shouldSpawn = true ;
1414+ }
13921415
1393- if (shouldSpawn) trySpawn (walkers, maxWalkers, cols, rows);
1416+ if (shouldSpawn) trySpawn (walkers, maxWalkers, cols, rows);
13941417
1395- // Object-Oriented Update Loop
1396- for (uint8_t i = 0 ; i < maxWalkers; i++) {
1397- walkers[i].update (cols, rows, palStep);
1398- }
1418+ // Object-Oriented Update Loop
1419+ for (uint8_t i = 0 ; i < maxWalkers; i++) {
1420+ walkers[i].update (cols, rows, palStep);
13991421 }
1422+ }
14001423
1401- } // end namespace BrushWalkerFX
1402-
1424+ } // end namespace BrushWalkerFX
14031425
14041426/* *
1405- * @brief Brushwalker mode with random spawning only - if random chance based on sensitivity slider hits, a new walker will spawn
1406- *
1427+ * @brief Brushwalker mode with random spawning only - if random chance based on
1428+ * sensitivity slider hits, a new walker will spawn
1429+ *
14071430 */
1408- static void mode_brushwalker (void )
1409- {
1410- BrushWalkerFX::mode_brushwalker_core (0 );
1411- }
1431+ static void mode_brushwalker (void ) { BrushWalkerFX::mode_brushwalker_core (0 ); }
14121432// The metadata string consists of up to five sections, separated by semicolons:
14131433// <Effect parameters>;<Colors>;<Palette>;<Flags>;<Defaults>
14141434static const char _data_FX_MODE_BRUSHWALKER[] PROGMEM =
1415- " Brush Walker@!,Spawn,Fade,Palette Step,Max Walkers;,!;!;2;pal=11,sx=200,ix=64,c1=48,c2=24,c3=16" ;
1435+ " Brush Walker@!,Spawn,Fade,Palette Step,Max "
1436+ " Walkers;,!;!;2;pal=11,sx=200,ix=64,c1=48,c2=24,c3=16" ;
14161437
1417- /* *
1418- * @brief Brushwalker mode with audioreactive triggering - if a peak is detected, or if random chance based on sensitivity slider hits, a new walker will spawn
1419- */
1420- static void mode_brushwalker_ar (void )
1421- {
1438+ /* *
1439+ * @brief Brushwalker mode with audioreactive triggering - if a peak is
1440+ * detected, or if random chance based on sensitivity slider hits, a new walker
1441+ * will spawn
1442+ */
1443+ static void mode_brushwalker_ar (void ) {
14221444 BrushWalkerFX::mode_brushwalker_core (1 );
14231445}
14241446
14251447static const char _data_FX_MODE_BRUSHWALKER_AR[] PROGMEM =
1426- " Brush Walker AR@!,Sensitivity,Fade,Palette Step,Max Walkers;,!;!;2v;pal=11,sx=200,ix=64,c1=48,c2=24,c3=16" ;
1448+ " Brush Walker AR@!,Sensitivity,Fade,Palette Step,Max "
1449+ " Walkers;,!;!;2v;pal=11,sx=200,ix=64,c1=48,c2=24,c3=16" ;
14271450
14281451// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
14291452// END BrushWalker
0 commit comments