FastLED 3.9.15
Loading...
Searching...
No Matches

◆ init_binary_dithering()

template<EOrder RGB_ORDER, int LANES = 1, fl::u32 MASK = 0xFFFFFFFF>
void PixelController< RGB_ORDER, LANES, MASK >::init_binary_dithering ( )
inline

Set up the values for binary dithering.

See also
"TEMPORAL DITHERING: THE COMPLETE GUIDE" section above (line 195)

Definition at line 309 of file pixel_controller.h.

309 {
310#if !defined(NO_DITHERING) || (NO_DITHERING != 1)
311 // STEP 1: Increment frame counter (creates temporal variation)
312 static fl::u8 R = 0; // okay static in header
313 ++R;
314
315 // STEP 2: Wrap counter at 2^ditherBits (creates 8-frame cycle: 0,1,2,3,4,5,6,7,0...)
317 R &= (0x01 << ditherBits) - 1;
318
319 // STEP 3: Bit-reverse R to create maximally-spaced pattern Q
320 // Why? Prevents visible ramping patterns. Turns 0,1,2,3,4,5,6,7 → 0,128,64,192,32,160,96,224
321 fl::u8 Q = 0;
322
323 // Bit reversal magic: mirrors bit positions (bit 0 ↔ bit 7, bit 1 ↔ bit 6, etc.)
324 {
325 if(R & 0x01) { Q |= 0x80; }
326 if(R & 0x02) { Q |= 0x40; }
327 if(R & 0x04) { Q |= 0x20; }
328 if(R & 0x08) { Q |= 0x10; }
329 if(R & 0x10) { Q |= 0x08; }
330 if(R & 0x20) { Q |= 0x04; }
331 if(R & 0x40) { Q |= 0x02; }
332 if(R & 0x80) { Q |= 0x01; }
333 }
334
335 // STEP 4: Center the pattern (shifts values to middle of quantization bins)
336 // Example: 0,128,64,192 becomes 16,144,80,208 (adds 16 when ditherBits=3)
337 if( ditherBits < 8) {
338 Q += 0x01 << (7 - ditherBits);
339 }
340
341 // STEP 5: Scale per-channel based on brightness
342 // Key insight: Lower brightness needs BIGGER dithering offsets!
343 // e[i] = max dither range (inversely proportional to brightness)
344 // d[i] = current dither offset (Q scaled by e[i])
345 for(int i = 0; i < 3; ++i) {
346 fl::u8 s = mColorAdjustment.premixed.raw[i]; // Brightness scale factor
347
348 // Calculate max dither range: e = 256/brightness
349 // At 100% (255): e≈1 (tiny range), At 20% (51): e≈5 (large range)
350 e[i] = s ? (256/s) + 1 : 0;
351
352 // Scale Q by the dither range to get current offset
353 d[i] = fl::scale8(Q, e[i]);
354
355#if (FASTLED_SCALE8_FIXED == 1)
356 // Adjust for scale8 implementation quirk
357 if(d[i]) (--d[i]);
358#endif
359 // Finalize e[i] value for later toggling
360 if(e[i]) --e[i];
361 }
362#endif
363 }
fl::u8 e[3]
[DITHER] Max dither range per R,G,B channel (inversely proportional to brightness)
fl::u8 d[3]
[DITHER] Current dither offset per R,G,B channel (toggles via stepDithering)
ColorAdjustment mColorAdjustment
Pixel controller class.

References d, e, mColorAdjustment, and VIRTUAL_BITS.

Referenced by enable_dithering().

+ Here is the caller graph for this function: