Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1f57fb9
PoC working but just a hack
DedeHai Feb 14, 2026
0ae6fbb
full refactoring, partially working
DedeHai Feb 14, 2026
e1ae3e2
refactoring, fixed some bugs
DedeHai Feb 14, 2026
a81d5cf
add new tiny font, remove debug output,
DedeHai Feb 14, 2026
cada48b
fixes, optimizations still not fully working
DedeHai Feb 15, 2026
a09e296
add support for flash fonts back, unified functions. custom glyphs cu…
DedeHai Feb 15, 2026
c6e10f9
minor fix
DedeHai Feb 15, 2026
1339593
bugfix, now file fonts work again with extended chars
DedeHai Feb 15, 2026
0f978bc
lost line
DedeHai Feb 15, 2026
f61cbd7
another
DedeHai Feb 15, 2026
f729dc0
update to latest header format using 12 bytes
DedeHai Feb 15, 2026
e50dc58
fixed up the fonts
DedeHai Feb 15, 2026
5d3c554
fix off by one, new font uses full 0-127 ASCII
DedeHai Feb 15, 2026
619d700
bugfix, update some comments
DedeHai Feb 15, 2026
76a3ea4
fix reasonable rabbit suggestions
DedeHai Feb 16, 2026
3962c6b
code cleanup, WIP
DedeHai Feb 24, 2026
da492b1
add font file helper, also cache flash fonts (reduces complexity)
DedeHai Feb 24, 2026
2fec051
update built-in fonts with similar but nicer ones
DedeHai Feb 25, 2026
f75a570
some code claenaup
DedeHai Feb 25, 2026
c66d697
started code cleanup
DedeHai Feb 26, 2026
3804f3e
more code cleanup, remove obsolete variables and functions
DedeHai Feb 26, 2026
f8d0a5c
prevent crash if font file is invalid
DedeHai Feb 26, 2026
6092ff7
reorder functions, minor cleanup
DedeHai Feb 26, 2026
d355ab4
bugfixes in FX calculations (size/position) rename & fix font
DedeHai Feb 26, 2026
4970c41
minor fixes
DedeHai Feb 27, 2026
087c06b
add support for any wbf file name, dropping the fixed name scheme (at…
DedeHai Feb 27, 2026
a62be1b
remove drawCharacter() declarations from segment, fix overflow with u…
DedeHai Feb 27, 2026
7606ac6
add padding to glyph entry
DedeHai Feb 27, 2026
8698089
fix accidental removal of bitmap
DedeHai Feb 27, 2026
9474de3
add comment
DedeHai Mar 7, 2026
2627cc1
refactor: move fontmanager into its own files
DedeHai Mar 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 97 additions & 46 deletions wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6302,32 +6302,24 @@ static const char _data_FX_MODE_2DBLOBS[] PROGMEM = "Blobs@!,# blobs,Blur,Trail;
////////////////////////////
// 2D Scrolling text //
////////////////////////////

void mode_2Dscrollingtext(void) {
if (!strip.isMatrix || !SEGMENT.is2D()) FX_FALLBACK_STATIC; // not a 2D set-up

FontManager fontManager(&SEGMENT);
const int cols = SEG_W;
const int rows = SEG_H;

unsigned letterWidth, rotLW;
unsigned letterHeight, rotLH;
switch (map(SEGMENT.custom2, 0, 255, 1, 5)) {
default:
case 1: letterWidth = 4; letterHeight = 6; break;
case 2: letterWidth = 5; letterHeight = 8; break;
case 3: letterWidth = 6; letterHeight = 8; break;
case 4: letterWidth = 7; letterHeight = 9; break;
case 5: letterWidth = 5; letterHeight = 12; break;
}
// Font selection
const uint8_t* selectedFont = nullptr;
char fileName[32];
bool useCustomFont = SEGMENT.check2;
uint8_t fontNum = map(SEGMENT.custom2, 0, 255, 0, 4);
bool init = (SEGENV.call == 0);

// letters are rotated
const int8_t rotate = map(SEGMENT.custom3, 0, 31, -2, 2);
if (rotate == 1 || rotate == -1) {
rotLH = letterWidth;
rotLW = letterHeight;
} else {
rotLW = letterWidth;
rotLH = letterHeight;
}

// generate time/date if there are any # tokens
char text[WLED_MAX_SEGNAME_LEN+1] = {'\0'};
size_t result_pos = 0;
char sec[5];
Expand Down Expand Up @@ -6374,7 +6366,7 @@ void mode_2Dscrollingtext(void) {
else if (!strncmp_P(token,PSTR("#YY"),3)) { sprintf (temp, ("%02d") , year(localTime)%100); advance = 3; }
else if (!strncmp_P(token,PSTR("#HH"),3)) { sprintf (temp, zero? ("%02d") : ("%d"), AmPmHour); advance = 3; }
else if (!strncmp_P(token,PSTR("#MM"),3)) { sprintf (temp, zero? ("%02d") : ("%d"), minute(localTime)); advance = 3; }
else if (!strncmp_P(token,PSTR("#SS"),3)) { sprintf (temp, zero? ("%02d") : ("%d"), second(localTime)); advance = 3; }
else if (!strncmp_P(token,PSTR("#SS"),3)) { sprintf (temp, zero? ("%02d") : ("%d"), second(localTime)); advance = 3; fontManager.setCacheNumbers(true);} // cache all numbers
else if (!strncmp_P(token,PSTR("#MON"),4)) { sprintf (temp, ("%s") , monthShortStr(month(localTime))); advance = 4; }
else if (!strncmp_P(token,PSTR("#MO"),3)) { sprintf (temp, zero? ("%02d") : ("%d"), month(localTime)); advance = 3; }
else if (!strncmp_P(token,PSTR("#DAY"),4)) { sprintf (temp, ("%s") , dayShortStr(weekday(localTime))); advance = 4; }
Expand All @@ -6399,52 +6391,111 @@ void mode_2Dscrollingtext(void) {
}
}

const int numberOfLetters = strlen(text);
int width = (numberOfLetters * rotLW);
int yoffset = map(SEGMENT.intensity, 0, 255, -rows/2, rows/2) + (rows-rotLH)/2;
if (width <= cols) {
// scroll vertically (e.g. ^^ Way out ^^) if it fits
// Load the font
fontManager.loadFont(fontNum, useCustomFont); // TODO: simplify this code, prepare is not really needed as a separate function.
fontManager.prepare(text);

// Get font dimensions
uint8_t letterHeight = fontManager.getFontHeight();
uint8_t letterWidth = fontManager.getFontWidth(); // for fonts with variable width, this is the max letter width TODO: actually use variable width
uint8_t letterSpacing = fontManager.getFontSpacing();

// Calculate rotated dimensions
unsigned rotLW, rotLH;
if (rotate == 1 || rotate == -1) {
rotLH = letterWidth;
rotLW = letterHeight;
} else {
rotLW = letterWidth;
rotLH = letterHeight;
}

// Calculate total text width
int totalTextWidth = 0;
int idx = 0;
const int numberOfChars = utf8_strlen(text);

for (int c = 0; c < numberOfChars; c++) {
uint8_t charLen;
uint32_t unicode = utf8_decode(&text[idx], &charLen);
idx += charLen;

if (rotate == 1 || rotate == -1) {
totalTextWidth += letterHeight; // Fixed dimension when rotated
} else {
uint8_t w = fontManager.getGlyphWidth(unicode);
totalTextWidth += w;
}
if (c < numberOfChars - 1) totalTextWidth += letterSpacing;
}

// Y offset calculation
int yoffset = map(SEGMENT.intensity, 0, 255, -rows / 2, rows / 2) + (rows - rotLH) / 2;

if (totalTextWidth <= cols) {
// scroll vertically
int speed = map(SEGMENT.speed, 0, 255, 5000, 1000);
int frac = strip.now % speed + 1;
if (SEGMENT.intensity == 255) {
yoffset = (2 * frac * rows)/speed - rows;
yoffset = (2 * frac * rows) / speed - rows;
} else if (SEGMENT.intensity == 0) {
yoffset = rows - (2 * frac * rows)/speed;
yoffset = rows - (2 * frac * rows) / speed;
}
}

// Animation step
if (SEGENV.step < strip.now) {
// calculate start offset
if (width > cols) {
if (totalTextWidth > cols) {
if (SEGMENT.check3) {
if (SEGENV.aux0 == 0) SEGENV.aux0 = width + cols - 1;
else --SEGENV.aux0;
} else ++SEGENV.aux0 %= width + cols;
} else SEGENV.aux0 = (cols + width)/2;
++SEGENV.aux1 &= 0xFF; // color shift
SEGENV.step = strip.now + map(SEGMENT.speed, 0, 255, 250, 50); // shift letters every ~250ms to ~50ms
if (SEGENV.aux0 == 0) SEGENV.aux0 = totalTextWidth + cols - 1;
else --SEGENV.aux0;
} else {
++SEGENV.aux0 %= totalTextWidth + cols;
}
} else {
SEGENV.aux0 = (cols - totalTextWidth) / 2; // Center
}
++SEGENV.aux1 &= 0xFF;
SEGENV.step = strip.now + map(SEGMENT.speed, 0, 255, 250, 50);
}

SEGMENT.fade_out(255 - (SEGMENT.custom1>>4)); // trail
SEGMENT.fade_out(255 - (SEGMENT.custom1 >> 4));
uint32_t col1 = SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0);
uint32_t col2 = BLACK;
// if gradient is selected and palette is default (0) drawCharacter() uses gradient from SEGCOLOR(0) to SEGCOLOR(2)
// otherwise col2 == BLACK means use currently selected palette for gradient
// if gradient is not selected set both colors the same
if (SEGMENT.check1) { // use gradient
if (SEGMENT.palette == 0) { // use colors for gradient

if (SEGMENT.check1) {
if (SEGMENT.palette == 0) {
col1 = SEGCOLOR(0);
col2 = SEGCOLOR(2);
}
} else col2 = col1; // force characters to use single color (from palette)
} else {
col2 = col1;
}

// Draw characters
idx = 0;
int currentXOffset = 0;

for (int c = 0; c < numberOfChars; c++) {
uint8_t charLen;
uint32_t unicode = utf8_decode(&text[idx], &charLen);
idx += charLen;
uint8_t glyphWidth = fontManager.getGlyphWidth(unicode);
int drawX = int(cols) - int(SEGENV.aux0) + currentXOffset;
int advance = (rotate == 1 || rotate == -1) ? letterHeight : glyphWidth;

// Skip if off-screen
if (drawX + advance < 0) {
currentXOffset += advance + letterSpacing;
continue;
}
if (drawX >= cols) break;

for (int i = 0; i < numberOfLetters; i++) {
int xoffset = int(cols) - int(SEGENV.aux0) + rotLW*i;
if (xoffset + rotLW < 0) continue; // don't draw characters off-screen
SEGMENT.drawCharacter(text[i], xoffset, yoffset, letterWidth, letterHeight, col1, col2, rotate);
fontManager.drawCharacter(unicode, drawX, yoffset, col1, col2, rotate);
currentXOffset += advance + letterSpacing;
}
}
static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size,Rotate,Gradient,,Reverse;!,!,Gradient;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0";
static const char _data_FX_MODE_2DSCROLLTEXT[] PROGMEM = "Scrolling Text@!,Y Offset,Trail,Font size,Rotate,Gradient,Custom Font,Reverse;!,!,Gradient;!;2;ix=128,c1=0,rev=0,mi=0,rY=0,mY=0";


////////////////////////////
Expand Down
Loading