Skip to content

Commit 8254352

Browse files
committed
Reworked brushwalker fx code styling, fixed mistaken edit of platformio.ini.
1 parent f1b7727 commit 8254352

2 files changed

Lines changed: 147 additions & 125 deletions

File tree

platformio.ini

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
# ------------------------------------------------------------------------------
1111

1212
# CI/release binaries
13-
default_envs =
14-
nodemcuv2
13+
default_envs = nodemcuv2
1514
esp8266_2m
1615
esp01_1m_full
1716
nodemcuv2_160

usermods/user_fx/user_fx.cpp

Lines changed: 146 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,171 +1259,194 @@ static void mode_morsecode(void) {
12591259
}
12601260
static 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
*/
12791278
namespace 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>
14141434
static 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

14251447
static 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

Comments
 (0)