From 8a03b274ec48058439a4b97ffeca44f0f524c2d7 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 2 Feb 2026 23:30:41 +0100 Subject: [PATCH 1/2] spots effect improvements * avoid gaps on left/light side of strip, by using higher accuracy zoneLength * prevent overflows * ensure that zones calculation are performed in full 32bit * fix wrong slider name in "spots fade" --- wled00/FX.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index d60c525261..b8bfe24d51 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2952,20 +2952,21 @@ static uint16_t spots_base(uint16_t threshold) if (SEGLEN <= 1) return mode_static(); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); - unsigned maxZones = SEGLEN >> 2; - unsigned zones = 1 + ((SEGMENT.intensity * maxZones) >> 8); + unsigned maxZones = max(1U, SEGLEN >> 2); // prevents "0 zones" + unsigned zones = 1U + ((uint32_t(SEGMENT.intensity) * maxZones) >> 8); unsigned zoneLen = SEGLEN / zones; - unsigned offset = (SEGLEN - zones * zoneLen) >> 1; + unsigned zoneLen8 = zones < 8 ? zoneLen * 8 : SEGLEN / (zones >> 3); // zoneLength * 8 -> avoids gaps at right/left sides + unsigned offset = (uint32_t(SEGLEN) - ((zones * zoneLen8)>>3)) >> 1; for (unsigned z = 0; z < zones; z++) { - unsigned pos = offset + z * zoneLen; + unsigned pos = offset +((z * zoneLen8)>>3); for (unsigned i = 0; i < zoneLen; i++) { unsigned wave = triwave16((i * 0xFFFF) / zoneLen); if (wave > threshold) { - unsigned index = 0 + pos + i; - unsigned s = (wave - threshold)*255 / (0xFFFF - threshold); + unsigned index = pos + i; + unsigned s = ((wave - threshold)*255 / (0xFFFF - threshold)) & 0xFF; // & 0xFF prevents overflow in next line SEGMENT.setPixelColor(index, color_blend(SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), uint8_t(255-s))); } } @@ -2991,7 +2992,7 @@ uint16_t mode_spots_fade() unsigned tr = (t >> 1) + (t >> 2); return spots_base(tr); } -static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Spread,Width,,,,,Overlay;!,!;!"; +static const char _data_FX_MODE_SPOTS_FADE[] PROGMEM = "Spots Fade@Speed,Width,,,,,Overlay;!,!;!"; //each needs 12 bytes typedef struct Ball { From e2bee4fdb27a753f79ede1d7e633d8a7dbff5da8 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 2 Feb 2026 23:56:30 +0100 Subject: [PATCH 2/2] fixpoint scaling bugfix * use named constants for fixed point scaling * remove buggy "SEGLEN / (zones >>3)" shortcut * remove an unnecessary casts to uint32_t --- wled00/FX.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index b8bfe24d51..47e5a2c700 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2952,15 +2952,19 @@ static uint16_t spots_base(uint16_t threshold) if (SEGLEN <= 1) return mode_static(); if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1)); + // constants for fixed point scaling + constexpr uint8_t ZONELEN_FP_SHIFT = 3; + constexpr uint32_t ZONELEN_FP_SCALE = 1U << ZONELEN_FP_SHIFT; + unsigned maxZones = max(1U, SEGLEN >> 2); // prevents "0 zones" unsigned zones = 1U + ((uint32_t(SEGMENT.intensity) * maxZones) >> 8); - unsigned zoneLen = SEGLEN / zones; - unsigned zoneLen8 = zones < 8 ? zoneLen * 8 : SEGLEN / (zones >> 3); // zoneLength * 8 -> avoids gaps at right/left sides - unsigned offset = (uint32_t(SEGLEN) - ((zones * zoneLen8)>>3)) >> 1; + unsigned zoneLen = SEGLEN / zones; + unsigned zoneLen8 = (SEGLEN * ZONELEN_FP_SCALE) / zones; // zoneLength * 8 (fixed‑point) -> avoids gaps at right/left sides + unsigned offset = (SEGLEN - ((zones * zoneLen8) >> ZONELEN_FP_SHIFT)) >> 1; for (unsigned z = 0; z < zones; z++) { - unsigned pos = offset +((z * zoneLen8)>>3); + unsigned pos = offset + ((z * zoneLen8) >> ZONELEN_FP_SHIFT); for (unsigned i = 0; i < zoneLen; i++) { unsigned wave = triwave16((i * 0xFFFF) / zoneLen);