Skip to content
Draft
Changes from all commits
Commits
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
21 changes: 13 additions & 8 deletions wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2914,20 +2914,25 @@ static void spots_base(uint16_t threshold)
if (SEGLEN <= 1) FX_FALLBACK_STATIC;
if (!SEGMENT.check2) SEGMENT.fill(SEGCOLOR(1));

unsigned maxZones = SEGLEN >> 2;
unsigned zones = 1 + ((SEGMENT.intensity * maxZones) >> 8);
unsigned zoneLen = SEGLEN / zones;
unsigned offset = (SEGLEN - zones * zoneLen) >> 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 = (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 * zoneLen;
unsigned pos = offset + ((z * zoneLen8) >> ZONELEN_FP_SHIFT);
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
Comment on lines +2921 to +2935
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use boundary-derived widths to keep the spots evenly spaced.

Line 2923 still fixes every zone to SEGLEN / zones, while Line 2929 places starts on fractional boundaries. On lengths that do not divide evenly, the leftover pixels turn into visible holes instead of evenly spaced spots. Derive each zone width from the next boundary instead of reusing the truncated integer width.

♻️ Proposed fix
-  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;
+  unsigned zoneLen8 = (uint32_t(SEGLEN) * ZONELEN_FP_SCALE) / zones; // zoneLength * 8 (fixed-point) -> avoids gaps at right/left sides
+  unsigned offset   = (SEGLEN - ((uint32_t(zones) * zoneLen8) >> ZONELEN_FP_SHIFT)) >> 1;

   for (unsigned z = 0; z < zones; z++)
   {
-    unsigned pos = offset + ((z * zoneLen8) >> ZONELEN_FP_SHIFT);
+    unsigned pos = offset + ((uint32_t(z) * zoneLen8) >> ZONELEN_FP_SHIFT);
+    unsigned nextPos = (z + 1 == zones)
+      ? (SEGLEN - offset)
+      : offset + ((uint32_t(z + 1) * zoneLen8) >> ZONELEN_FP_SHIFT);
+    unsigned zoneLen = nextPos - pos;
     for (unsigned i = 0; i < zoneLen; i++)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wled00/FX.cpp` around lines 2921 - 2935, The loop currently computes a
uniform zoneLen (SEGLEN / zones) but computes per-zone start positions using
fractional boundaries (offset + ((z * zoneLen8) >> ZONELEN_FP_SHIFT)), causing
leftover pixels to become gaps; change the inner loop to derive each zone's
width from the next fractional boundary instead of reusing zoneLen: compute pos
for zone z using the existing fractional formula (pos = offset + ((z * zoneLen8)
>> ZONELEN_FP_SHIFT)) and posNext for z+1 similarly, then set the per-zone width
as zoneWidth = posNext - pos (for the last zone use SEGLEN - pos), and iterate i
from 0 to zoneWidth so spots fill evenly; update uses of zoneLen and any
dependent indexing (variables: zones, zoneLen, zoneLen8, offset, pos)
accordingly.

SEGMENT.setPixelColor(index, color_blend(SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0), SEGCOLOR(1), uint8_t(255-s)));
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}
Expand All @@ -2951,7 +2956,7 @@ void mode_spots_fade()
unsigned tr = (t >> 1) + (t >> 2);
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;!,!;!";
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while you are at it: rename "Width" to "Density" for both variants?


//each needs 12 bytes
typedef struct Ball {
Expand Down
Loading