FastLED 3.10.8
Loading...
Searching...
No Matches
pixel_iterator.h
Go to the documentation of this file.
1
3
4#pragma once
5
6#include "fl/stl/stdint.h"
7#include "fl/stl/string.h"
8#include "fl/stl/iterator.h"
10#include "fl/gfx/rgbw.h"
11#include "fl/gfx/rgbww.h"
12#include "crgb.h"
13#include "fl/math/intmap.h"
14#include "fl/system/sketch_macros.h" // IWYU pragma: keep (FL_PLATFORM_HAS_TINY_MEMORY)
15#include "fl/stl/type_traits.h" // IWYU pragma: keep (declval for WideLoadBinder)
24#include "fl/gfx/five_bit_hd_gamma.h" // five_bit_hd_solve16 (managed HD, #4042)
29
30// Include adapter class definitions (but not implementations yet)
31// This provides the full definitions of ScaledPixelIterator* classes
32// and makeScaledPixelRange* helper functions
34#include "fl/stl/noexcept.h"
35
36namespace fl {
37
38// Forward declaration
39class PixelIterator;
40
41// NOTE: FASTLED_PIXEL_ITERATOR_HAS_APA102_HD flag removed - HD functions moved to encoder files
42// loadAndScale_APA102_HD() moved to src/fl/chipsets/encoders/apa102.h
43// loadAndScale_WS2816_HD() moved to src/fl/chipsets/encoders/ws2816.h
44
45// Due to to the template nature of the PixelController class, the only way we can make
46// it a concrete polymorphic class is to manually bind the functions and make our own
47// vtable. The PixelControllerVtable is cheaper than doing fl::function<>.
48template<typename PixelControllerT>
50 static void loadAndScaleRGBW(void* pixel_controller, const Rgbw& rgbw, u8* b0_out, u8* b1_out, u8* b2_out, u8* b3_out) FL_NO_EXCEPT {
51 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
52 pc->loadAndScaleRGBW(rgbw, b0_out, b1_out, b2_out, b3_out);
53 }
54
55 // 5-channel RGBWW path (issue #2558, Phase C of #2545). Same vtable
56 // pattern as loadAndScaleRGBW but produces 5 output bytes (RGB + warm-W
57 // + cool-W) per pixel in EOrder + EOrderWW wire order.
58 static void loadAndScaleRGBWW(void* pixel_controller, Rgbww rgbww,
59 u8* b0_out, u8* b1_out, u8* b2_out,
60 u8* b3_out, u8* b4_out) FL_NO_EXCEPT {
61 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
62 pc->loadAndScaleRGBWW(rgbww, b0_out, b1_out, b2_out, b3_out, b4_out);
63 }
64
65 // Order-free loads, bound only for the RGB instantiation (see
66 // RgbwLoadBinder). PixelIterator applies the colour order itself, so one
67 // PixelController<RGB> serves every order and the other five instantiations
68 // -- a full vtable set each -- are never referenced (FastLED#4402).
69 static void loadAndScaleRGBWUnordered(void* pixel_controller, const Rgbw& rgbw, u8* r_out, u8* g_out, u8* b_out, u8* w_out) FL_NO_EXCEPT {
70 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
71 pc->loadAndScaleRGBWUnordered(rgbw, r_out, g_out, b_out, w_out);
72 }
73 static void loadAndScaleRGBWWUnordered(void* pixel_controller, Rgbww rgbww, u8* r_out, u8* g_out, u8* b_out, u8* ww_out, u8* wc_out) FL_NO_EXCEPT {
74 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
75 pc->loadAndScaleRGBWWUnordered(rgbww, r_out, g_out, b_out, ww_out, wc_out);
76 }
77
82 static void loadRawPremixed(void* pixel_controller, u8* raw, u8* premix) FL_NO_EXCEPT {
83 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
84 raw[0] = pc->mData[0];
85 raw[1] = pc->mData[1];
86 raw[2] = pc->mData[2];
87 premix[0] = pc->mColorAdjustment.premixed.r;
88 premix[1] = pc->mColorAdjustment.premixed.g;
89 premix[2] = pc->mColorAdjustment.premixed.b;
90 }
91 static void loadAndScaleRGB(void* pixel_controller, u8* r_out, u8* g_out, u8* b_out) FL_NO_EXCEPT {
92 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
93 pc->loadAndScaleRGB(r_out, g_out, b_out);
94 }
95
96#if !FL_PLATFORM_HAS_TINY_MEMORY
97 // Wide load (P8, #4042), bound only for sources that actually have one.
98 //
99 // Measured: binding it for every source cost 750 B on an ESP32-S3 Blink
100 // build -- six copies of this thunk at 125 B, one per EOrder
101 // instantiation, all doing the identical widening. Only a colour-managed
102 // source has a wider pixel to offer; every PixelController just widens its
103 // 8-bit one, and PixelIterator can do that once for all of them.
104 static void loadAndScaleRGB16(void* pixel_controller, u16* r_out, u16* g_out, u16* b_out) FL_NO_EXCEPT {
105 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
106 pc->loadAndScaleRGB16(r_out, g_out, b_out);
107 }
108#endif
109
110 // NOTE: loadAndScale_APA102_HD() removed - use fl::loadAndScale_APA102_HD<RGB_ORDER>() from apa102.h encoder
111 // NOTE: loadAndScale_WS2816_HD() removed - use fl::loadAndScale_WS2816_HD<RGB_ORDER>() from ws2816.h encoder
112
113 static void stepDithering(void* pixel_controller) FL_NO_EXCEPT {
114 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
115 pc->stepDithering();
116 }
117
118 static void advanceData(void* pixel_controller) FL_NO_EXCEPT {
119 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
120 pc->advanceData();
121 }
122
123 static int size(void* pixel_controller) FL_NO_EXCEPT {
124 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
125 return pc->size();
126 }
127 static bool has(void* pixel_controller, int n) FL_NO_EXCEPT {
128 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
129 return pc->has(n);
130 }
131
132 // function for loadRGBScaleAndBrightness
133 #if FASTLED_HD_COLOR_MIXING
134 static void loadRGBScaleAndBrightness(void* pixel_controller, u8* c0, u8* c1, u8* c2, u8* brightness) FL_NO_EXCEPT {
135 PixelControllerT* pc = static_cast<PixelControllerT*>(pixel_controller);
136 pc->loadRGBScaleAndBrightness(c0, c1, c2, brightness);
137 }
138
139 // Deprecated: for backwards compatibility
140 static void getHdScale(void* pixel_controller, u8* c0, u8* c1, u8* c2, u8* brightness) FL_NO_EXCEPT {
141 loadRGBScaleAndBrightness(pixel_controller, c0, c1, c2, brightness);
142 }
143 #endif
144};
145
146typedef void (*loadAndScaleRGBWFunction)(void* pixel_controller, const Rgbw& rgbw, u8* b0_out, u8* b1_out, u8* b2_out, u8* b3_out);
147typedef void (*loadAndScaleRGBWWFunction)(void* pixel_controller, Rgbww rgbww, u8* b0_out, u8* b1_out, u8* b2_out, u8* b3_out, u8* b4_out);
148typedef void (*loadAndScaleRGBFunction)(void* pixel_controller, u8* r_out, u8* g_out, u8* b_out);
149#if !FL_PLATFORM_HAS_TINY_MEMORY
150typedef void (*loadAndScaleRGB16Function)(void* pixel_controller, u16* r_out, u16* g_out, u16* b_out);
151
157template <typename T, typename = void>
159 static loadAndScaleRGB16Function get() FL_NO_EXCEPT { return nullptr; }
160};
161
162template <typename T>
163struct WideLoadBinder<T, decltype(static_cast<void>(
164 fl::declval<T&>().loadAndScaleRGB16(
165 static_cast<u16*>(nullptr),
166 static_cast<u16*>(nullptr),
167 static_cast<u16*>(nullptr))))> {
171};
172#endif
173// NOTE: loadAndScale_APA102_HDFunction removed - use fl::loadAndScale_APA102_HD<RGB_ORDER>() from apa102.h encoder
174// NOTE: loadAndScale_WS2816_HDFunction removed - use fl::loadAndScale_WS2816_HD<RGB_ORDER>() from ws2816.h encoder
175typedef void (*loadAndScaleRGBWUnorderedFunction)(void* pixel_controller, const Rgbw& rgbw, u8* r_out, u8* g_out, u8* b_out, u8* w_out);
176typedef void (*loadRawPremixedFunction)(void* pixel_controller, u8* raw, u8* premix);
177typedef void (*loadAndScaleRGBWWUnorderedFunction)(void* pixel_controller, Rgbww rgbww, u8* r_out, u8* g_out, u8* b_out, u8* ww_out, u8* wc_out);
178
179namespace detail {
182template <bool B> struct OnlyIf {};
183template <> struct OnlyIf<true> { typedef void type; };
184} // namespace detail
185
194template <typename T, typename = void>
201#if defined(FL_IS_AVR)
202template <typename T>
203struct RgbwLoadBinder<T, typename detail::OnlyIf<(T::kColorOrder == RGB)>::type> {
204 static loadAndScaleRGBWFunction ordered() FL_NO_EXCEPT { return nullptr; }
205 static loadAndScaleRGBWWFunction orderedWW() FL_NO_EXCEPT { return nullptr; }
208};
209#else
213template <typename T>
214struct RgbwLoadBinder<T, typename detail::OnlyIf<(T::kColorOrder == T::kColorOrder)>::type> {
215 static loadAndScaleRGBWFunction ordered() FL_NO_EXCEPT { return nullptr; }
219};
220#endif
221
225template <typename T, typename = void>
227 static loadRawPremixedFunction get() FL_NO_EXCEPT { return nullptr; }
228 static EOrder order() FL_NO_EXCEPT { return RGB; }
229};
230#if !defined(FL_IS_AVR)
231template <typename T>
232struct RawPremixBinder<T, typename detail::OnlyIf<(T::kColorOrder == T::kColorOrder)>::type> {
234 static EOrder order() FL_NO_EXCEPT { return T::kColorOrder; }
235};
236#endif
237
238typedef void (*stepDitheringFunction)(void* pixel_controller);
239typedef void (*advanceDataFunction)(void* pixel_controller);
240typedef int (*sizeFunction)(void* pixel_controller);
241typedef bool (*hasFunction)(void* pixel_controller, int n);
242typedef u8 (*globalBrightness)(void* pixel_controller);
243typedef void (*loadRGBScaleAndBrightnessFunction)(void* pixel_controller, u8* c0, u8* c1, u8* c2, u8* brightness);
244typedef void (*getHdScaleFunction)(void* pixel_controller, u8* c0, u8* c1, u8* c2, u8* brightness);
245
246
247// PixelIterator is turns a PixelController<> into a concrete object that can be used to iterate
248// over pixels and transform them into driver data. See PixelController<>::as_iterator() for how
249// to create a PixelIterator.
250// Note: This is designed for micro-controllers with a lot of memory. DO NOT use this in the core library
251// as a PixelIterator consumes a *lot* more instruction data than an instance of PixelController<RGB_ORDER>.
252// This iterator is designed for code in src/platforms/**.
254 public:
255 template<typename PixelControllerT>
256 PixelIterator(PixelControllerT* pc, const Rgbw& rgbw,
258 : mPixelController(pc), mRgbw(rgbw), mRgbww(rgbww) {
259 // Manually build up a vtable.
260 // Wait... what? Stupid nerds trying to show off how smart they are...
261 // Why not just use a virtual function?!
262 //
263 // Before you think this then you should know that the alternative straight
264 // forward way is to have a virtual interface class that PixelController inherits from.
265 // ...and that was already tried. And if you try to do this yourself
266 // this then let me tell you what is going to happen...
267 //
268 // EVERY SINGLE PLATFORM THAT HAS A COMPILED BINARY SIZE CHECK WILL IMMEDIATELY
269 // FAIL AS THE BINARY BLOWS UP BY 10-30%!!! It doesn't matter if only one PixelController
270 // with a vtable is used, gcc seems not to de-virtualize the calls. And we really care
271 // about binary size since FastLED needs to run on those tiny little microcontrollers like
272 // the Attiny85 (and family) which are in the sub $1 range used for commercial products.
273 //
274 // So to satisfy these tight memory requirements we make the dynamic dispatch used in PixelIterator
275 // an optional zero-cost abstraction which doesn't affect the binary size for platforms that
276 // don't use it. So that's why we are using this manual construction of the vtable that is built
277 // up using template magic. If your platform has lots of memory then you'll gladly trade
278 // a sliver of memory for the convenience of having a concrete implementation of
279 // PixelController that you can use without having to make all your driver code a template.
280 //
281 // Btw, this pattern in C++ is called the "type-erasure pattern". It allows non virtual
282 // polymorphism by leveraging the C++ template system to ensure type safety.
290 if (mLoadRawPremixed != nullptr) {
291 mRgbwConvert = mRgbw.active() ? detail::rgbw_conversion() : nullptr;
292 mRgbwwConvert = mRgbww.active() ? detail::rgbww_conversion() : nullptr;
294 }
295 mLoadAndScaleRGB = &Vtable::loadAndScaleRGB;
296#if !FL_PLATFORM_HAS_TINY_MEMORY
298#endif
299 // NOTE: mLoadAndScale_APA102_HD removed - use fl::loadAndScale_APA102_HD<RGB_ORDER>() from apa102.h encoder
300 // NOTE: mLoadAndScale_WS2816_HD removed - use fl::loadAndScale_WS2816_HD<RGB_ORDER>() from ws2816.h encoder
301 mStepDithering = &Vtable::stepDithering;
302 mAdvanceData = &Vtable::advanceData;
303 mSize = &Vtable::size;
304 mHas = &Vtable::has;
305 #if FASTLED_HD_COLOR_MIXING
306 mLoadRGBScaleAndBrightness = &Vtable::loadRGBScaleAndBrightness;
307 mGetHdScale = &Vtable::getHdScale;
308 #endif
309 }
310
311 bool has(int n) FL_NO_EXCEPT { return mHas(mPixelController, n); }
317 // Same bit layout as RGB_BYTE(order, i) in pixel_controller.h.
318 for (int i = 0; i < 3; ++i) {
319 mOrder[i] = static_cast<u8>((static_cast<int>(order) >> (3 * (2 - i))) & 0x3);
320 }
322 }
323
324 private:
329 for (int i = 0; i < 3; ++i) {
330 mWireOrder[i] = static_cast<u8>(
331 (static_cast<fl::i32>(mSourceOrder) >> (3 * (2 - mOrder[i]))) & 0x3);
332 }
333 }
334
335 public:
336
337 void loadAndScaleRGBW(u8 *b0_out, u8 *b1_out, u8 *b2_out, u8 *w_out) FL_NO_EXCEPT {
338 if (mLoadRawPremixed != nullptr) {
339 // Type-erased RGBW: the conversion is installed by active Rgbw
340 // construction / setRgbw(), so RGB-only programs never link it
341 // (#4795). Cached at construction (the Rgbw already exists then).
342 u8 raw[3];
343 u8 premix[3];
345 if (mRgbwConvert != nullptr) {
346 mRgbwConvert(mRgbw, raw, premix, mWireOrder, b0_out, b1_out, b2_out, w_out);
347 return;
348 }
349 // Not installed: only an inactive Rgbw can reach here. Exactly what
350 // rgb_2_rgbw(kRGBWInvalid) produced: premix-scaled RGB, white off,
351 // then the W placement.
352 u8 c[3];
353 u8 w = 0;
354 rgb_2_rgbw_null_white_pixel(mRgbw.white_color_temp, raw[0], raw[1], raw[2],
355 premix[0], premix[1], premix[2],
356 &c[0], &c[1], &c[2], &w);
357 rgbw_partial_reorder(mRgbw.w_placement, c[mWireOrder[0]], c[mWireOrder[1]],
358 c[mWireOrder[2]], w, b0_out, b1_out, b2_out, w_out);
359 return;
360 }
361#if defined(FL_IS_AVR)
362 // AVR keeps the order-free thunk (no type-erased conversion there).
363 if (mLoadAndScaleRGBWUnordered != nullptr) {
364 // Source-order RGB plus W, then the same two steps the templated
365 // `loadAndScaleRGBW` takes: permute RGB, place W.
366 u8 c[3];
367 u8 w = 0;
368 mLoadAndScaleRGBWUnordered(mPixelController, mRgbw, &c[0], &c[1], &c[2], &w);
369 rgbw_partial_reorder(mRgbw.w_placement, c[mOrder[0]], c[mOrder[1]], c[mOrder[2]], w,
370 b0_out, b1_out, b2_out, w_out);
371 return;
372 }
373#endif
374 mLoadAndScaleRGBW(mPixelController, mRgbw, b0_out, b1_out, b2_out, w_out);
375 }
376 void loadAndScaleRGBWW(u8 *b0_out, u8 *b1_out, u8 *b2_out,
377 u8 *b3_out, u8 *b4_out) FL_NO_EXCEPT {
378 if (mLoadRawPremixed != nullptr) {
379 if (mRgbwwConvert != nullptr) {
380 u8 raw[3];
381 u8 premix[3];
383 mRgbwwConvert(mRgbww, raw, premix, mWireOrder, b0_out, b1_out, b2_out,
384 b3_out, b4_out);
385 return;
386 }
387 // Not installed: only an inactive Rgbww can reach here, and
388 // rgb_2_rgbww(kRGBWWInvalid) emits zeros on all five channels.
389 *b0_out = *b1_out = *b2_out = *b3_out = *b4_out = 0;
390 return;
391 }
392#if defined(FL_IS_AVR)
393 if (mLoadAndScaleRGBWWUnordered != nullptr) {
394 u8 c[3];
395 u8 ww = 0;
396 u8 wc = 0;
397 mLoadAndScaleRGBWWUnordered(mPixelController, mRgbww, &c[0], &c[1], &c[2], &ww, &wc);
398 rgbww_partial_reorder(mRgbww.w_placement, c[mOrder[0]], c[mOrder[1]], c[mOrder[2]], ww, wc,
399 b0_out, b1_out, b2_out, b3_out, b4_out);
400 return;
401 }
402#endif
403 mLoadAndScaleRGBWW(mPixelController, mRgbww, b0_out, b1_out, b2_out, b3_out, b4_out);
404 }
405 void loadAndScaleRGB(u8 *r_out, u8 *g_out, u8 *b_out) FL_NO_EXCEPT {
406 // The source's own order first (identity for PixelController<RGB>),
407 // then this iterator's. `loadAndScale<SLOT>` is per source channel --
408 // data, dither table and scale all indexed by the same channel -- so
409 // reordering after the fact is the same bytes.
410 u8 c[3];
411 mLoadAndScaleRGB(mPixelController, &c[0], &c[1], &c[2]);
412 *r_out = c[mOrder[0]];
413 *g_out = c[mOrder[1]];
414 *b_out = c[mOrder[2]];
415 }
416#if !FL_PLATFORM_HAS_TINY_MEMORY
422 void loadAndScaleRGB16(u16 *r_out, u16 *g_out, u16 *b_out) FL_NO_EXCEPT {
423 if (mLoadAndScaleRGB16 != nullptr) {
424 mLoadAndScaleRGB16(mPixelController, r_out, g_out, b_out);
425 return;
426 }
427 // The source has no wider pixel than its 8-bit one. Widening exactly,
428 // here rather than in a per-source thunk.
429 u8 r8, g8, b8;
430 loadAndScaleRGB(&r8, &g8, &b8);
431 *r_out = fl::map8_to_16(r8);
432 *g_out = fl::map8_to_16(g8);
433 *b_out = fl::map8_to_16(b8);
434 }
435#endif
436 // NOTE: loadAndScale_APA102_HD() removed - use fl::loadAndScale_APA102_HD<RGB_ORDER>() from apa102.h encoder
437 // NOTE: loadAndScale_WS2816_HD() removed - use fl::loadAndScale_WS2816_HD<RGB_ORDER>() from ws2816.h encoder
441
443 mRgbw = rgbw;
444 if (mLoadRawPremixed != nullptr) {
445 mRgbwConvert = mRgbw.active() ? detail::rgbw_conversion() : nullptr;
446 }
447 }
448 Rgbw get_rgbw() const FL_NO_EXCEPT { return mRgbw; }
449
451 mRgbww = rgbww;
452 if (mLoadRawPremixed != nullptr) {
453 mRgbwwConvert = mRgbww.active() ? detail::rgbww_conversion() : nullptr;
454 }
455 }
456 Rgbww get_rgbww() const FL_NO_EXCEPT { return mRgbww; }
457
458 #if FASTLED_HD_COLOR_MIXING
459 void loadRGBScaleAndBrightness(u8* c0, u8* c1, u8* c2, u8* brightness) FL_NO_EXCEPT {
460 // Per-slot scale, so it takes the same permutation as the pixel.
461 u8 c[3];
462 mLoadRGBScaleAndBrightness(mPixelController, &c[0], &c[1], &c[2], brightness);
463 *c0 = c[mOrder[0]];
464 *c1 = c[mOrder[1]];
465 *c2 = c[mOrder[2]];
466 }
467
468 FL_DEPRECATED("Use loadRGBScaleAndBrightness() instead")
469 void getHdScale(u8* c0, u8* c1, u8* c2, u8* brightness) FL_NO_EXCEPT {
470 loadRGBScaleAndBrightness(c0, c1, c2, brightness);
471 }
472 #endif
473
474 template <typename CONTAINER_UIN8_T>
475 void writeWS2812(CONTAINER_UIN8_T* out) FL_NO_EXCEPT {
476 auto back_ins = fl::back_inserter(*out);
477 // (#2558) Dispatch order: RGBWW > RGBW > RGB. The variant migration
478 // makes these mutually exclusive — at most one alternative is active.
479 if (mRgbww.active()) {
480 auto range = makeScaledPixelRangeRGBWW(this);
481 encodeWS2812_RGBWW(range.first, range.second, back_ins);
482 } else if (mRgbw.active()) {
483 auto range = makeScaledPixelRangeRGBW(this);
484 encodeWS2812_RGBW(range.first, range.second, back_ins);
485 } else {
486 auto range = makeScaledPixelRangeRGB(this);
487 encodeWS2812_RGB(range.first, range.second, back_ins);
488 }
489 }
490
492 template <typename CONTAINER_UIN8_T>
493 void writeTM1812RGBWW(CONTAINER_UIN8_T* out) FL_NO_EXCEPT {
494 auto back_ins = fl::back_inserter(*out);
495 auto range = makeScaledPixelRangeRGBWW(this);
496 encodeTM1812_RGBWW(range.first, range.second, back_ins);
497 }
498
500 template <typename CONTAINER_UIN8_T>
501 void writeTM1908(CONTAINER_UIN8_T* out) FL_NO_EXCEPT {
502 auto back_ins = fl::back_inserter(*out);
503 auto range = makeScaledPixelRangeRGB(this);
504 encodeTM1908(range.first, range.second, back_ins);
505 }
506
511 template <typename CONTAINER_UIN8_T>
512 void writeAPA102(CONTAINER_UIN8_T* out, bool hd_gamma = false) FL_NO_EXCEPT {
513 FL_UNUSED(hd_gamma); // only read under FASTLED_HD_COLOR_MIXING
514 auto back_ins = fl::back_inserter(*out);
515
516 #if FASTLED_HD_COLOR_MIXING
517 if (hd_gamma) {
518 // HD gamma mode: per-LED brightness
519 auto pixel_range = makeScaledPixelRangeRGB(this);
520 auto brightness = makeScaledBrightness(this);
521 encodeAPA102_HD(pixel_range.first, pixel_range.second,
522 brightness, back_ins);
523 return;
524 }
525 #endif
526
527 #if FASTLED_USE_GLOBAL_BRIGHTNESS == 1
528 // Global brightness mode: extract from first pixel
529 auto pixel_range = makeScaledPixelRangeRGB(this);
530 encodeAPA102_AutoBrightness(pixel_range.first, pixel_range.second,
531 back_ins);
532 #else
533 // Full brightness mode
534 auto pixel_range = makeScaledPixelRangeRGB(this);
535 encodeAPA102(pixel_range.first, pixel_range.second,
536 back_ins, 31);
537 #endif
538 }
539
544 template <typename CONTAINER_UIN8_T>
545 void writeSK9822(CONTAINER_UIN8_T* out, bool hd_gamma = false) FL_NO_EXCEPT {
546 FL_UNUSED(hd_gamma); // only read under FASTLED_HD_COLOR_MIXING
547 auto back_ins = fl::back_inserter(*out);
548
549 #if FASTLED_HD_COLOR_MIXING
550 if (hd_gamma) {
551 // HD gamma mode: per-LED brightness
552 auto pixel_range = makeScaledPixelRangeRGB(this);
553 auto brightness = makeScaledBrightness(this);
554 encodeSK9822_HD(pixel_range.first, pixel_range.second,
555 brightness, back_ins);
556 return;
557 }
558 #endif
559
560 #if FASTLED_USE_GLOBAL_BRIGHTNESS == 1
561 // Global brightness mode: extract from first pixel
562 auto pixel_range = makeScaledPixelRangeRGB(this);
563 encodeSK9822_AutoBrightness(pixel_range.first, pixel_range.second,
564 back_ins);
565 #else
566 // Full brightness mode
567 auto pixel_range = makeScaledPixelRangeRGB(this);
568 encodeSK9822(pixel_range.first, pixel_range.second,
569 back_ins, 31);
570 #endif
571 }
572
573#if !FL_PLATFORM_HAS_TINY_MEMORY
580 template <typename OutputIterator>
581 void writeLPD8806Wide(OutputIterator back_ins) FL_NO_EXCEPT {
582 fl::size num_leds = 0;
583 while (has(1)) {
584 u16 w[3];
585 loadAndScaleRGB16(&w[0], &w[1], &w[2]); // wire order
586 for (int c = 0; c < 3; ++c) {
587 const u32 code = (static_cast<u32>(w[c]) * 127u + 32767u) / 65535u;
588 *back_ins++ = static_cast<u8>(0x80 | code);
589 }
591 advanceData();
592 ++num_leds;
593 }
594 const fl::size latch = (num_leds * 3 + 63) / 64;
595 for (fl::size i = 0; i < latch; ++i) {
596 *back_ins++ = 0x00;
597 }
598 }
599
604 template <typename OutputIterator>
605 void writeLPD6803Wide(OutputIterator back_ins) FL_NO_EXCEPT {
606 for (int i = 0; i < 4; ++i) {
607 *back_ins++ = 0x00;
608 }
609 fl::size num_leds = 0;
610 while (has(1)) {
611 u16 w[3];
612 loadAndScaleRGB16(&w[0], &w[1], &w[2]); // wire order
613 u16 command = 0x8000;
614 for (int c = 0; c < 3; ++c) {
615 const u32 code = (static_cast<u32>(w[c]) * 31u + 32767u) / 65535u;
616 command = static_cast<u16>(command | (code << (10 - 5 * c)));
617 }
618 *back_ins++ = static_cast<u8>(command >> 8);
619 *back_ins++ = static_cast<u8>(command & 0xFF);
621 advanceData();
622 ++num_leds;
623 }
624 const fl::size end_dwords = num_leds / 32;
625 for (fl::size i = 0; i < end_dwords; ++i) {
626 *back_ins++ = 0xFF;
627 *back_ins++ = 0x00;
628 *back_ins++ = 0x00;
629 *back_ins++ = 0x00;
630 }
631 }
632#endif
633
634#if FASTLED_HD_COLOR_MIXING && !FL_PLATFORM_HAS_TINY_MEMORY
640 template <typename OutputIterator>
641 void writeFiveBitWide(OutputIterator back_ins, u8 min_field) FL_NO_EXCEPT {
642 for (int i = 0; i < 4; ++i) {
643 *back_ins++ = 0x00;
644 }
645 fl::size num_leds = 0;
646 while (has(1)) {
647 u16 w0, w1, w2;
648 loadAndScaleRGB16(&w0, &w1, &w2); // wire order
649 CRGB codes;
650 u8 field = 31;
651 detail::five_bit_hd_solve16(w0, w1, w2, min_field, &codes, &field);
652 *back_ins++ = static_cast<u8>(0xE0 | (field & 0x1F));
653 *back_ins++ = codes.raw[0];
654 *back_ins++ = codes.raw[1];
655 *back_ins++ = codes.raw[2];
657 advanceData();
658 ++num_leds;
659 }
660 const fl::size end_dwords = (num_leds / 32) + 1;
661 for (fl::size i = 0; i < end_dwords * 4; ++i) {
662 *back_ins++ = 0xFF;
663 }
664 }
665#endif
666
667 // ========== SPI Chipset Encoders ==========
668 // Refactored to use standalone encoder functions in src/fl/chipsets/encoders/
669
674 template <typename CONTAINER_UIN8_T>
675 void writeWS2801(CONTAINER_UIN8_T* out) FL_NO_EXCEPT {
676 auto back_ins = fl::back_inserter(*out);
677 auto pixel_range = makeScaledPixelRangeRGB(this);
678 encodeWS2801(pixel_range.first, pixel_range.second, back_ins);
679 }
680
685 template <typename CONTAINER_UIN8_T>
686 void writeWS2803(CONTAINER_UIN8_T* out) FL_NO_EXCEPT {
687 auto back_ins = fl::back_inserter(*out);
688 auto pixel_range = makeScaledPixelRangeRGB(this);
689 encodeWS2803(pixel_range.first, pixel_range.second, back_ins);
690 }
691
695 template <typename CONTAINER_UIN8_T>
696 void writeP9813(CONTAINER_UIN8_T* out) FL_NO_EXCEPT {
697 auto back_ins = fl::back_inserter(*out);
698 auto pixel_range = makeScaledPixelRangeRGB(this);
699 encodeP9813(pixel_range.first, pixel_range.second, back_ins);
700 }
701
705 template <typename CONTAINER_UIN8_T>
706 void writeLPD8806(CONTAINER_UIN8_T* out) FL_NO_EXCEPT {
707 auto back_ins = fl::back_inserter(*out);
708 auto pixel_range = makeScaledPixelRangeRGB(this);
709 encodeLPD8806(pixel_range.first, pixel_range.second, back_ins);
710 }
711
715 template <typename CONTAINER_UIN8_T>
716 void writeLPD6803(CONTAINER_UIN8_T* out) FL_NO_EXCEPT {
717 auto back_ins = fl::back_inserter(*out);
718 auto pixel_range = makeScaledPixelRangeRGB(this);
719 encodeLPD6803(pixel_range.first, pixel_range.second, back_ins);
720 }
721
725 template <typename CONTAINER_UIN8_T>
726 void writeSM16716(CONTAINER_UIN8_T* out) FL_NO_EXCEPT {
727 auto back_ins = fl::back_inserter(*out);
728 auto pixel_range = makeScaledPixelRangeRGB(this);
729 encodeSM16716(pixel_range.first, pixel_range.second, back_ins);
730 }
731
739 template <typename CONTAINER_UIN8_T>
740 void writeHD108(CONTAINER_UIN8_T* out, bool managed = false) FL_NO_EXCEPT {
741 auto back_ins = fl::back_inserter(*out);
742
743 // One loop for both sources. This used to be two: the managed path
744 // written out by hand here, and the 8-bit path routed through
745 // `encodeHD108` over `makeScaledPixelRangeRGB`. Each carried its own
746 // copy of the framing -- the 8-byte start frame, the per-LED emit of
747 // header + three big-endian channels, the latch -- and together they
748 // made this the largest encoder body in a Blink build (481 B on
749 // esp32dev, ahead of `writeWS2812`, the only one Blink runs). The only
750 // thing that differed was where the 16-bit channels came from, so
751 // that is now the only branch (FastLED#4402).
752 //
753 // Byte-identical to the iterator path by construction:
754 // `ScaledPixelIteratorRGB::advance()` is exactly `has(1)`,
755 // `loadAndScaleRGB` into wire order, `stepDithering`, `advanceData`,
756 // once per pixel; the bytes it hands `encodeHD108` are captured before
757 // the step, which is what this loop does too.
758 //
759 // Inline rather than an `encodeHD108_wide` in hd108.h: that header is
760 // included *by* this one, before `PixelIterator` exists, and a
761 // concrete `PixelIterator&` parameter is not a dependent type -- so
762 // its body would be checked there and fail (#4326).
763#if FL_PLATFORM_HAS_TINY_MEMORY
764 // No wide source exists on TINY, so the flag selects nothing there.
765 FL_UNUSED(managed);
766#endif
767 for (int i = 0; i < 8; i++) {
768 *back_ins++ = 0x00; // start frame
769 }
770 // `hd108BrightnessHeader` discards its argument and pins every gain
771 // at 31, so this is 0xFF 0xFF whatever is passed (#4402).
772 u8 f0, f1;
773 hd108BrightnessHeader(0, &f0, &f1);
774 fl::size num_leds = 0;
775 while (has(1)) {
776 u16 r16, g16, b16;
777#if !FL_PLATFORM_HAS_TINY_MEMORY
778 if (managed) {
779 // The managed source has already quantized its device drive
780 // once, to 16 bits. `hd108GammaCorrect` exists to widen an
781 // 8-bit pixel to the 16 this chipset carries; a fixed 2.8
782 // curve on top of a solved drive is the second shaping stage
783 // B1 and section 6 of the spec forbid after the device
784 // solve, and unlike UCS7604's `mGamma.value_or(2.8f)` this
785 // one is hardcoded -- no caller could have chosen otherwise.
786 loadAndScaleRGB16(&r16, &g16, &b16);
787 } else
788#endif
789 {
790 u8 b0, b1, b2;
791 loadAndScaleRGB(&b0, &b1, &b2); // wire order
792 r16 = hd108GammaCorrect(b0);
793 g16 = hd108GammaCorrect(b1);
794 b16 = hd108GammaCorrect(b2);
795 }
796 *back_ins++ = f0;
797 *back_ins++ = f1;
798 *back_ins++ = static_cast<u8>(r16 >> 8);
799 *back_ins++ = static_cast<u8>(r16 & 0xFF);
800 *back_ins++ = static_cast<u8>(g16 >> 8);
801 *back_ins++ = static_cast<u8>(g16 & 0xFF);
802 *back_ins++ = static_cast<u8>(b16 >> 8);
803 *back_ins++ = static_cast<u8>(b16 & 0xFF);
805 advanceData();
806 ++num_leds;
807 }
808 const fl::size latch = num_leds / 2 + 4;
809 for (fl::size i = 0; i < latch; i++) {
810 *back_ins++ = 0xFF; // end frame
811 }
812 }
813
814 private:
815 // vtable emulation
816 void* mPixelController = nullptr;
828 u8 mWireOrder[3] = {0, 1, 2};
829#if !FL_PLATFORM_HAS_TINY_MEMORY
831#endif
832 // Wire byte i comes from source channel mOrder[i]. Identity unless
833 // setColorOrder() is called; PixelIteratorAny is the caller.
834 u8 mOrder[3] = {0, 1, 2};
835 // NOTE: mLoadAndScale_APA102_HD removed - use fl::loadAndScale_APA102_HD<RGB_ORDER>() from apa102.h encoder
836 // NOTE: mLoadAndScale_WS2816_HD removed - use fl::loadAndScale_WS2816_HD<RGB_ORDER>() from ws2816.h encoder
840 hasFunction mHas = nullptr;
841 #if FASTLED_HD_COLOR_MIXING
842 loadRGBScaleAndBrightnessFunction mLoadRGBScaleAndBrightness = nullptr;
843 getHdScaleFunction mGetHdScale = nullptr;
844 #endif
845};
846
847
848// ===========================================================================
849// Implementation of adapter advance() methods
850// ===========================================================================
851// These implementations are defined here (after PixelIterator is complete)
852// because they require calling methods on the fully-defined PixelIterator type.
853
854namespace detail {
855
856// ScaledPixelIteratorRGB implementation
858 if (!mPixels) {
859 mHasValue = false;
860 return;
861 }
862
863 if (mPixels->has(1)) {
864 u8 b0, b1, b2;
865 mPixels->loadAndScaleRGB(&b0, &b1, &b2);
866 mCurrent = array<u8, 3>{{b0, b1, b2}}; // Wire order bytes
867 mPixels->stepDithering();
868 mPixels->advanceData();
869 mHasValue = true;
870 } else {
871 mHasValue = false;
872 }
873}
874
875// ScaledPixelIteratorRGBW implementation
877 if (!mPixels) {
878 mHasValue = false;
879 return;
880 }
881
882 if (mPixels->has(1)) {
883 u8 b0, b1, b2, b3;
884 mPixels->loadAndScaleRGBW(&b0, &b1, &b2, &b3);
885 mCurrent = array<u8, 4>{{b0, b1, b2, b3}}; // Wire order bytes
886 mPixels->stepDithering();
887 mPixels->advanceData();
888 mHasValue = true;
889 } else {
890 mHasValue = false;
891 }
892}
893
894// ScaledPixelIteratorRGBWW implementation (issue #2558)
896 if (!mPixels) {
897 mHasValue = false;
898 return;
899 }
900
901 if (mPixels->has(1)) {
902 u8 b0, b1, b2, b3, b4;
903 mPixels->loadAndScaleRGBWW(&b0, &b1, &b2, &b3, &b4);
904 mCurrent = array<u8, 5>{{b0, b1, b2, b3, b4}}; // Wire-order 5 bytes
905 mPixels->stepDithering();
906 mPixels->advanceData();
907 mHasValue = true;
908 } else {
909 mHasValue = false;
910 }
911}
912
913#if FASTLED_HD_COLOR_MIXING
914// ScaledPixelIteratorBrightness implementation
915//
916// Named load() rather than advance() because it advances nothing. It must not
917// call stepDithering()/advanceData(): the RGB adapter alongside owns the
918// shared cursor, and both moving it consumed two source pixels per emitted
919// LED and halved the strip (#4321).
920inline void ScaledPixelIteratorBrightness::load() FL_NO_EXCEPT {
921 if (!mPixels) {
922 return;
923 }
924
925 // ColorAdjustment::brightness -- a per-strip constant, so the same value
926 // is correct at every position and no cursor movement is needed.
927 u8 r, g, b, brightness;
928 mPixels->loadRGBScaleAndBrightness(&r, &g, &b, &brightness);
929 mCurrent = brightness;
930}
931#endif // FASTLED_HD_COLOR_MIXING
932
933// ScaledPixelIteratorRGB16 implementation
935 if (!mPixels) {
936 mHasValue = false;
937 return;
938 }
939
940 if (mPixels->has(1)) {
941 // Wire-ordered, colour-corrected, brightness-scaled pixel bytes.
942 //
943 // This used to branch on FASTLED_HD_COLOR_MIXING and call
944 // loadRGBScaleAndBrightness() here, treating its three outputs as the
945 // pixel. They are not the pixel: that call returns
946 // ColorAdjustment::color -- the correction *scale* at full
947 // brightness, a per-strip constant -- for a caller that will apply it
948 // to a pixel itself. So every LED came out the same colour and the
949 // frame never reached the wire (#4323). WS2816, the only user of this
950 // range, showed one flat tint on every non-AVR build.
951 //
952 // loadAndScaleRGB() is the call that loads the pixel. It applies
953 // `premixed`, which already carries brightness, so there is no
954 // separate brightness step left to do. The old branch existed to
955 // defer brightness to 16-bit precision, but it was producing a
956 // constant rather than extra precision, so nothing is given up by
957 // dropping it. Doing that properly needs a primitive that loads the
958 // pixel scaled at full brightness, which PixelIterator does not
959 // expose today.
960#if !FL_PLATFORM_HAS_TINY_MEMORY
961 // The wide load the comment above asks for (P8, #4042). For an
962 // ordinary controller it is `map8_to_16` of the same 8-bit pixel, so
963 // an unbound channel is byte-identical to what this did before. A
964 // colour-managed source instead quantizes its s16.16 drive straight
965 // to 16 bits, which is what lets a 16-bit encoder reach more than 256
966 // levels.
967 u16 r16, g16, b16;
968 mPixels->loadAndScaleRGB16(&r16, &g16, &b16);
969#else
970 // TINY carries no colour pipeline, so there is nothing wider than the
971 // 8-bit pixel to load and the extra function pointer is not spent.
972 u8 b0, b1, b2;
973 mPixels->loadAndScaleRGB(&b0, &b1, &b2);
974
975 const u16 r16 = fl::map8_to_16(b0);
976 const u16 g16 = fl::map8_to_16(b1);
977 const u16 b16 = fl::map8_to_16(b2);
978#endif
979
980 mCurrent = array<u16, 3>{{r16, g16, b16}}; // Wire order 16-bit channels
981 mPixels->stepDithering();
982 mPixels->advanceData();
983 mHasValue = true;
984 } else {
985 mHasValue = false;
986 }
987}
988
989} // namespace detail
990
991
992} // namespace fl
fl::UISlider brightness("Brightness", BRIGHTNESS, 0, 255)
Rgbw rgbw
void writeHD108(CONTAINER_UIN8_T *out, bool managed=false) FL_NO_EXCEPT
Encode pixels in HD108 format (zero allocation)
void writeLPD6803(CONTAINER_UIN8_T *out) FL_NO_EXCEPT
Encode pixels in LPD6803 format (zero allocation)
loadAndScaleRGBWWUnorderedFunction mLoadAndScaleRGBWWUnordered
void writeSM16716(CONTAINER_UIN8_T *out) FL_NO_EXCEPT
Encode pixels in SM16716 format (zero allocation)
void writeWS2803(CONTAINER_UIN8_T *out) FL_NO_EXCEPT
Encode pixels in WS2803 format (zero allocation)
void writeTM1908(CONTAINER_UIN8_T *out) FL_NO_EXCEPT
Encode RGB pixels with the required TM1908 command prefix.
Rgbw get_rgbw() const FL_NO_EXCEPT
void advanceData() FL_NO_EXCEPT
int size() FL_NO_EXCEPT
detail::RgbwConvertFn mRgbwConvert
void writeTM1812RGBWW(CONTAINER_UIN8_T *out) FL_NO_EXCEPT
Encode RGBWW pixels into 12-channel TM1812 IC frames.
loadAndScaleRGBWUnorderedFunction mLoadAndScaleRGBWUnordered
loadRawPremixedFunction mLoadRawPremixed
void loadAndScaleRGBWW(u8 *b0_out, u8 *b1_out, u8 *b2_out, u8 *b3_out, u8 *b4_out) FL_NO_EXCEPT
void loadAndScaleRGB(u8 *r_out, u8 *g_out, u8 *b_out) FL_NO_EXCEPT
stepDitheringFunction mStepDithering
void loadAndScaleRGB16(u16 *r_out, u16 *g_out, u16 *b_out) FL_NO_EXCEPT
One pixel at the source's own precision, wire-ordered.
advanceDataFunction mAdvanceData
void writeWS2812(CONTAINER_UIN8_T *out) FL_NO_EXCEPT
void writeLPD6803Wide(OutputIterator back_ins) FL_NO_EXCEPT
LPD6803 over a colour-managed channel's 16-bit drives, quantized once to the chip's 5 bits per channe...
void writeWS2801(CONTAINER_UIN8_T *out) FL_NO_EXCEPT
Encode pixels in WS2801 format (zero allocation)
detail::RgbwwConvertFn mRgbwwConvert
bool has(int n) FL_NO_EXCEPT
loadAndScaleRGBWWFunction mLoadAndScaleRGBWW
void writeAPA102(CONTAINER_UIN8_T *out, bool hd_gamma=false) FL_NO_EXCEPT
Encode pixels in APA102/DOTSTAR format (zero allocation)
loadAndScaleRGBFunction mLoadAndScaleRGB
void set_rgbww(Rgbww rgbww) FL_NO_EXCEPT
void setColorOrder(EOrder order) FL_NO_EXCEPT
Wire colour order, applied here rather than by instantiating a PixelController per order.
loadAndScaleRGB16Function mLoadAndScaleRGB16
void set_rgbw(const Rgbw &rgbw) FL_NO_EXCEPT
void writeLPD8806(CONTAINER_UIN8_T *out) FL_NO_EXCEPT
Encode pixels in LPD8806 format (zero allocation)
void loadAndScaleRGBW(u8 *b0_out, u8 *b1_out, u8 *b2_out, u8 *w_out) FL_NO_EXCEPT
loadAndScaleRGBWFunction mLoadAndScaleRGBW
void writeP9813(CONTAINER_UIN8_T *out) FL_NO_EXCEPT
Encode pixels in P9813 format (zero allocation)
PixelIterator(PixelControllerT *pc, const Rgbw &rgbw, Rgbww rgbww=RgbwwInvalid::value()) FL_NO_EXCEPT
Rgbww get_rgbww() const FL_NO_EXCEPT
void refreshWireOrder() FL_NO_EXCEPT
Recompute the cached source channel of each wire RGB byte: this iterator's order on top of the source...
void stepDithering() FL_NO_EXCEPT
void writeSK9822(CONTAINER_UIN8_T *out, bool hd_gamma=false) FL_NO_EXCEPT
Encode pixels in SK9822 format (zero allocation)
void writeLPD8806Wide(OutputIterator back_ins) FL_NO_EXCEPT
LPD8806 over a colour-managed channel's 16-bit drives, quantized once to the chip's 7 bits (B3: one f...
A fixed-size array implementation similar to std::array.
Definition array.h:27
void advance() FL_NO_EXCEPT
Advance to next pixel (or mark as end)
PixelIterator * mPixels
Underlying PixelIterator.
array< u16, 3 > mCurrent
Current pixel value (cached, wire order, 16-bit)
bool mHasValue
true if current pixel is valid
PixelIterator * mPixels
Underlying PixelIterator.
array< u8, 3 > mCurrent
Current pixel value (cached, wire order)
void advance() FL_NO_EXCEPT
Advance to next pixel (or mark as end)
bool mHasValue
true if current pixel is valid
array< u8, 4 > mCurrent
Current pixel value (cached, wire order)
void advance() FL_NO_EXCEPT
Advance to next pixel (or mark as end)
bool mHasValue
true if current pixel is valid
PixelIterator * mPixels
Underlying PixelIterator.
#define FL_UNUSED(x)
#define FL_DEPRECATED(msg)
APA102/DOTSTAR SPI chipset encoder.
HD108 SPI chipset encoder.
P9813 SPI chipset encoder.
SM16716 SPI chipset encoder.
WS2801/WS2803 SPI chipset encoder.
Declares functions for five-bit gamma correction.
Functions for red, green, blue, white (RGBW) output.
Integer mapping functions between different integer sizes.
fl::CRGB CRGB
Definition crgb.h:25
u16 map8_to_16(u8 x) FL_NO_EXCEPT
Definition intmap.h:48
unsigned char u8
Definition stdint.h:131
LPD6803 SPI chipset encoder.
LPD8806 SPI chipset encoder.
void(*)(const Rgbw &rgbw, const u8(&raw)[3], const u8(&premix)[3], const u8(&order)[3], u8 *b0, u8 *b1, u8 *b2, u8 *b3) RgbwConvertFn
Per-pixel RGBW conversion: raw source-order RGB + premixed scale -> 4 wire bytes.
Definition rgbw.h:220
void(*)(const Rgbww &rgbww, const fl::u8(&raw)[3], const fl::u8(&premix)[3], const fl::u8(&order)[3], fl::u8 *b0, fl::u8 *b1, fl::u8 *b2, fl::u8 *b3, fl::u8 *b4) RgbwwConvertFn
Definition rgbww.h:67
RgbwwConvertFn rgbww_conversion() FL_NO_EXCEPT
void five_bit_hd_solve16(u16 r16, u16 g16, u16 b16, u8 min_field, CRGB *out, u8 *out_field) FL_NO_EXCEPT
RgbwConvertFn rgbw_conversion() FL_NO_EXCEPT
Null until enable_rgbw_conversion() has run.
Definition rgbw.cpp.hpp:738
Compile-time linker keep-alive hook for a single fl::Bus.
Definition bus_info.h:57
type exists only when B is true: a self-contained enable_if so the binder below can key on a constant...
back_insert_iterator< Container > back_inserter(Container &c) FL_NO_EXCEPT
Helper function to create a back_insert_iterator.
Definition iterator.h:139
void encodeP9813(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode pixel data in P9813 format.
Definition p9813.h:33
unsigned char u8
Definition stdint.h:131
void encodeTM1812_RGBWW(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Pack 5-channel RGBCCT pixels into TM1812 12-channel frames.
Definition tm1812.h:24
void encodeLPD8806(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode pixel data in LPD8806 format.
Definition lpd8806.h:33
void rgbww_partial_reorder(EOrderWW ww_placement, u8 b0, u8 b1, u8 b2, u8 ww, u8 wc, u8 *out_b0, u8 *out_b1, u8 *out_b2, u8 *out_b3, u8 *out_b4) FL_NO_EXCEPT
Dispatch RGB->RGBWW for a given mode.
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
void(* loadAndScaleRGBWUnorderedFunction)(void *pixel_controller, const Rgbw &rgbw, u8 *r_out, u8 *g_out, u8 *b_out, u8 *w_out)
void rgb_2_rgbw_null_white_pixel(u16 w_color_temperature, u8 r, u8 g, u8 b, u8 r_scale, u8 g_scale, u8 b_scale, u8 *out_r, u8 *out_g, u8 *out_b, u8 *out_w) FL_NO_EXCEPT
Converts RGB to RGBW with the W channel set to black, always.
Definition rgbw.cpp.hpp:110
void hd108BrightnessHeader(u8 brightness_8bit, u8 *f0_out, u8 *f1_out) FL_NO_EXCEPT
Generate HD108 per-channel gain header bytes.
void(* stepDitheringFunction)(void *pixel_controller)
FL_NO_INLINE_IF_AVR FL_OPTIMIZE_O2 void encodeAPA102_AutoBrightness(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode pixel data in APA102 format (auto-detected brightness from first pixel)
Definition apa102.h:131
void encodeWS2812_RGBWW(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode 5-byte pixel data in WS2812 format (issue #2558, RGBWW).
Definition ws2812.h:86
add_rvalue_reference< T >::type declval() FL_NO_EXCEPT
void encodeWS2812_RGBW(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode 4-byte pixel data in WS2812 format.
Definition ws2812.h:53
void(* loadAndScaleRGBWWUnorderedFunction)(void *pixel_controller, Rgbww rgbww, u8 *r_out, u8 *g_out, u8 *b_out, u8 *ww_out, u8 *wc_out)
void encodeWS2803(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode pixel data in WS2803 format (alias for WS2801)
Definition ws2803.h:31
int(* sizeFunction)(void *pixel_controller)
void(* loadAndScaleRGBWFunction)(void *pixel_controller, const Rgbw &rgbw, u8 *b0_out, u8 *b1_out, u8 *b2_out, u8 *b3_out)
void encodeSM16716(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode pixel data in SM16716 format.
Definition sm16716.h:32
void encodeTM1908(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode one complete TM1908 frame.
Definition tm1908.h:18
void rgbw_partial_reorder(EOrderW w_placement, u8 b0, u8 b1, u8 b2, u8 w, u8 *out_b0, u8 *out_b1, u8 *out_b2, u8 *out_b3) FL_NO_EXCEPT
Definition rgbw.cpp.hpp:679
void encodeLPD6803(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode pixel data in LPD6803 format.
Definition lpd6803.h:35
void(* loadRawPremixedFunction)(void *pixel_controller, u8 *raw, u8 *premix)
void encodeAPA102_HD(InputIterator first, InputIterator last, BrightnessIterator brightness_first, OutputIterator out) FL_NO_EXCEPT
Encode pixel data in APA102 format with per-LED brightness.
Definition apa102.h:86
void encodeSK9822_HD(InputIterator first, InputIterator last, BrightnessIterator brightness_first, OutputIterator out) FL_NO_EXCEPT
Encode pixel data in SK9822 format with per-LED brightness.
Definition sk9822.h:79
void encodeWS2801(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode pixel data in WS2801/WS2803 format.
Definition ws2801.h:41
pair< detail::ScaledPixelIteratorRGBW, detail::ScaledPixelIteratorRGBW > makeScaledPixelRangeRGBW(PixelIterator *pixels) FL_NO_EXCEPT
Create RGBW input iterator range from PixelIterator.
void(* getHdScaleFunction)(void *pixel_controller, u8 *c0, u8 *c1, u8 *c2, u8 *brightness)
bool(* hasFunction)(void *pixel_controller, int n)
FL_NO_INLINE_IF_AVR void encodeSK9822_AutoBrightness(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode pixel data in SK9822 format (auto-detected brightness from first pixel)
Definition sk9822.h:122
void(* loadAndScaleRGBFunction)(void *pixel_controller, u8 *r_out, u8 *g_out, u8 *b_out)
EOrder
RGB color channel orderings, used when instantiating controllers to determine what order the controll...
Definition eorder.h:15
InputGamut g
Definition rgbw.h:125
void encodeWS2812_RGB(InputIterator first, InputIterator last, OutputIterator out) FL_NO_EXCEPT
Encode 3-byte pixel data in WS2812 format.
Definition ws2812.h:35
void(* loadAndScaleRGBWWFunction)(void *pixel_controller, Rgbww rgbww, u8 *b0_out, u8 *b1_out, u8 *b2_out, u8 *b3_out, u8 *b4_out)
u8(* globalBrightness)(void *pixel_controller)
u16 hd108GammaCorrect(u8 value) FL_NO_EXCEPT
Convert 8-bit color to HD108 16-bit gamma-corrected value (gamma 2.8)
void(* advanceDataFunction)(void *pixel_controller)
void(* loadRGBScaleAndBrightnessFunction)(void *pixel_controller, u8 *c0, u8 *c1, u8 *c2, u8 *brightness)
void encodeAPA102(InputIterator first, InputIterator last, OutputIterator out, u8 global_brightness=31) FL_NO_EXCEPT
Encode pixel data in APA102 format with global brightness.
Definition apa102.h:45
pair< detail::ScaledPixelIteratorRGB, detail::ScaledPixelIteratorRGB > makeScaledPixelRangeRGB(PixelIterator *pixels) FL_NO_EXCEPT
Create RGB input iterator range from PixelIterator.
void encodeSK9822(InputIterator first, InputIterator last, OutputIterator out, u8 global_brightness=31) FL_NO_EXCEPT
Encode pixel data in SK9822 format with global brightness.
Definition sk9822.h:37
pair< detail::ScaledPixelIteratorRGBWW, detail::ScaledPixelIteratorRGBWW > makeScaledPixelRangeRGBWW(PixelIterator *pixels) FL_NO_EXCEPT
Create RGBWW input iterator range from PixelIterator (issue #2558)
void(* loadAndScaleRGB16Function)(void *pixel_controller, u16 *r_out, u16 *g_out, u16 *b_out)
Base definition for an LED controller.
Definition crgb.hpp:179
Adapter layer bridging PixelIterator to encoder input iterators.
5-channel RGB + warm-W + cool-W (RGBWW / RGBCCT) configuration types (issue #2558,...
#define FL_NO_EXCEPT
SK9822 SPI chipset encoder.
static int size(void *pixel_controller) FL_NO_EXCEPT
static void loadAndScaleRGBWW(void *pixel_controller, Rgbww rgbww, u8 *b0_out, u8 *b1_out, u8 *b2_out, u8 *b3_out, u8 *b4_out) FL_NO_EXCEPT
static bool has(void *pixel_controller, int n) FL_NO_EXCEPT
static void advanceData(void *pixel_controller) FL_NO_EXCEPT
static void loadAndScaleRGB(void *pixel_controller, u8 *r_out, u8 *g_out, u8 *b_out) FL_NO_EXCEPT
static void loadRawPremixed(void *pixel_controller, u8 *raw, u8 *premix) FL_NO_EXCEPT
Raw source-order pixel plus premixed scale: everything the RGBW/RGBWW conversion reads,...
static void loadAndScaleRGBWUnordered(void *pixel_controller, const Rgbw &rgbw, u8 *r_out, u8 *g_out, u8 *b_out, u8 *w_out) FL_NO_EXCEPT
static void stepDithering(void *pixel_controller) FL_NO_EXCEPT
static void loadAndScaleRGB16(void *pixel_controller, u16 *r_out, u16 *g_out, u16 *b_out) FL_NO_EXCEPT
static void loadAndScaleRGBW(void *pixel_controller, const Rgbw &rgbw, u8 *b0_out, u8 *b1_out, u8 *b2_out, u8 *b3_out) FL_NO_EXCEPT
static void loadAndScaleRGBWWUnordered(void *pixel_controller, Rgbww rgbww, u8 *r_out, u8 *g_out, u8 *b_out, u8 *ww_out, u8 *wc_out) FL_NO_EXCEPT
static loadRawPremixedFunction get() FL_NO_EXCEPT
static EOrder order() FL_NO_EXCEPT
Raw-pixel thunk + the source's own colour order, for PixelController sources on non-AVR targets.
static loadAndScaleRGBWWFunction orderedWW() FL_NO_EXCEPT
static loadAndScaleRGBWFunction ordered() FL_NO_EXCEPT
static loadAndScaleRGBWUnorderedFunction unordered() FL_NO_EXCEPT
static loadAndScaleRGBWWUnorderedFunction unorderedWW() FL_NO_EXCEPT
Per-type RGBW/RGBWW thunks.
static Rgbww value() FL_NO_EXCEPT
Definition rgbww.h:111
static loadAndScaleRGB16Function get() FL_NO_EXCEPT
Binds the wide thunk only when T declares loadAndScaleRGB16.
TM1812 12-channel encoder for two RGBWW pixels per IC.
TM1908 mode/current command prefix and RGB pixel encoder.
WS2803 SPI chipset encoder (WS2801 alias)
WS2812/WS2812B/WS2813/NeoPixel encoder.