FastLED 3.10.6
Loading...
Searching...
No Matches
pixel_controller.h
Go to the documentation of this file.
1#pragma once
2
5
6// Note that new code should use the PixelIterator concrete object to write out
7// led data.
8// Using this class deep in driver code is deprecated because it's templates will
9// infact everything it touches. PixelIterator is concrete and doesn't have these
10// problems. See PixelController::as_iterator() for how to create a PixelIterator.
11
12
13#include "fl/math/intmap.h"
14#include "fl/system/sketch_macros.h" // IWYU pragma: keep (FL_PLATFORM_HAS_TINY_MEMORY)
15#include "fl/math/math8.h"
16#include "platforms/is_platform.h"
17
18#include "rgbw.h"
19#include "fl/gfx/rgbww.h"
21#include "fl/log/log.h"
24#include "fl/math/scale8.h"
25#include "fl/math/math8.h"
26#include "eorder.h"
27#include "dither_mode.h"
28#include "pixel_iterator.h"
29#include "crgb.h"
30#include "fl/stl/variant.h" // for PixelControllerAny.
31#include "fl/gfx/binary_dither.h" // last: reads NO_DITHERING, like the code it replaced
32
37
38
39
40
41
48#define RO(X) RGB_BYTE(RGB_ORDER, X)
49
56#define RGB_BYTE(RO,X) ((static_cast<int>(RO)>>(3*(2-(X)))) & 0x3)
57
60#define RGB_BYTE0(RO) ((static_cast<int>(RO)>>6) & 0x3)
63#define RGB_BYTE1(RO) ((static_cast<int>(RO)>>3) & 0x3)
66#define RGB_BYTE2(RO) (static_cast<int>(RO) & 0x3)
67
68// operator byte *(struct CRGB[] arr) { return (byte*)arr; }
69
78 #if FASTLED_HD_COLOR_MIXING
79 CRGB color;
81 #endif
82
87 adj.premixed = CRGB(255, 255, 255);
88 #if FASTLED_HD_COLOR_MIXING
89 adj.color = CRGB(255, 255, 255);
90 adj.brightness = 255;
91 #endif
92 return adj;
93 }
94};
95
96
103template<EOrder RGB_ORDER, int LANES=1, fl::u32 MASK=0xFFFFFFFF>
105 const fl::u8 *mData;
106 int mLen;
111 int mOffsets[LANES];
113
114 enum {
115 kLanes = LANES,
116 kMask = MASK
117 };
121 static constexpr EOrder kColorOrder = RGB_ORDER;
122
126
128 #if FASTLED_HD_COLOR_MIXING
129 mColorAdjustment.premixed = CRGB(mColorAdjustment.brightness, mColorAdjustment.brightness, mColorAdjustment.brightness);
130 mColorAdjustment.color = CRGB(0xff, 0xff, 0xff);
131 #endif
132 }
133
137 copy(other);
138 }
139
144 if (this != &other) {
145 copy(other);
146 }
147 return *this;
148 }
149
150 template<EOrder RGB_ORDER_OTHER>
154
155 template<typename PixelControllerT>
156 void copy(const PixelControllerT& other) {
157 FL_STATIC_ASSERT(int(kLanes) == int(PixelControllerT::kLanes), "PixelController lanes must match or mOffsets will be wrong");
158 FL_STATIC_ASSERT(int(kMask) == int(PixelControllerT::kMask), "PixelController mask must match or else one or the other controls different lanes");
159 d[0] = other.d[0];
160 d[1] = other.d[1];
161 d[2] = other.d[2];
162 e[0] = other.e[0];
163 e[1] = other.e[1];
164 e[2] = other.e[2];
165 mData = other.mData;
166 mColorAdjustment = other.mColorAdjustment;
167 mAdvance = other.mAdvance;
168 mLenRemaining = mLen = other.mLen;
169 for(int i = 0; i < LANES; ++i) { mOffsets[i] = other.mOffsets[i]; }
170 }
171
174 void initOffsets(int len) {
175 int nOffset = 0;
176 for(int i = 0; i < LANES; ++i) {
177 mOffsets[i] = nOffset;
178 if((1<<i) & MASK) { nOffset += (len * mAdvance); }
179 }
180 }
181
190 const fl::u8 *d, int len, ColorAdjustment color_adjustment,
191 EDitherMode dither, bool advance, fl::u8 skip)
192 : mData(d), mLen(len), mLenRemaining(len), mColorAdjustment(color_adjustment) {
194 mData += skip;
195 mAdvance = (advance) ? 3+skip : 0;
196 initOffsets(len);
197 }
198
205 const CRGB *d, int len, ColorAdjustment color_adjustment,
207 : mData((const fl::u8*)d), mLen(len), mLenRemaining(len), mColorAdjustment(color_adjustment) {
209 mAdvance = 3;
210 initOffsets(len);
211 }
212
219 const CRGB &d, int len, ColorAdjustment color_adjustment, EDitherMode dither)
220 : mData((const fl::u8*)&d), mLen(len), mLenRemaining(len), mColorAdjustment(color_adjustment) {
222 mAdvance = 0;
223 initOffsets(len);
224 }
225
226 #if FASTLED_HD_COLOR_MIXING
227 fl::u8 global_brightness() const {
228 return mColorAdjustment.brightness;
229 }
230 #endif
231
235 const fl::u8* getRawPixelData() const {
236 return mData;
237 }
238
239
240 // ------------------------------------------------------------------------
241 // Temporal dithering. The algorithm, its documentation and its tests live
242 // in fl/gfx/binary_dither.h (#4672); these members only bind it to this
243 // controller's `d`/`e` state and brightness. `NO_DITHERING=1` selects
244 // fl::NoDither, under which all of them compile to nothing except the
245 // zeroing of `d`/`e` that hand-written drivers read.
246 // ------------------------------------------------------------------------
247
250 fl::u8 frame = 0;
252#if FL_PLATFORM_HAS_TINY_MEMORY
253 // Tiny targets retain their one-byte local phase counter.
254 static fl::u8 R = 0; // okay static in header: preserves the tiny-target footprint
255 frame = ++R;
256#else
257 // Other targets share a phase once per logical frame.
258 frame = fl::detail::ditherFrame();
259#endif
260 }
261 fl::Dither::init(d, e, mColorAdjustment.premixed.raw, frame);
262 }
263
272
275 return fl::Dither::active(e);
276 }
277
282 return mLenRemaining >= n;
283 }
284
288 switch(dither) {
289 case BINARY_DITHER: init_binary_dithering(); break; // Initialize dithering algorithm
290 default: fl::Dither::clear(d, e); break; // Clear dither values (disabled)
291 }
292 }
293
296 FASTLED_FORCE_INLINE int size() const { return mLen; }
297
300 FASTLED_FORCE_INLINE int lanes() { return LANES; }
301
305
308
312 // Toggles d between two values: if d=2 and e=5, becomes 3, then back to 2, etc.
313 // This spreads dithering spatially along the strip, preventing visible patterns
315 }
316
321
325
329 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 loadByte(PixelController & pc) { return pc.mData[RO(SLOT)]; }
330
335 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 loadByte(PixelController & pc, int lane) { return pc.mData[pc.mOffsets[lane] + RO(SLOT)]; }
336
342 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 dither(PixelController & pc, fl::u8 b) { return fl::Dither::apply(b, pc.d[RO(SLOT)]); }
343
349 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 dither(PixelController & , fl::u8 b, fl::u8 d) { return fl::Dither::apply(b, d); }
350
356 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 scale(PixelController & pc, fl::u8 b) { return fl::scale8(b, pc.mColorAdjustment.premixed.raw[RO(SLOT)]); }
357
362 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 scale(PixelController & , fl::u8 b, fl::u8 scale) { return fl::scale8(b, scale); }
363
369
370
373 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 loadAndScale(PixelController & pc) {
374 return scale<SLOT>(pc, pc.dither<SLOT>(pc, pc.loadByte<SLOT>(pc)));
375 }
376
378 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 loadAndScale(PixelController & pc, int lane) {
379 return scale<SLOT>(pc, pc.dither<SLOT>(pc, pc.loadByte<SLOT>(pc, lane)));
380 }
381
383 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 loadAndScale(PixelController & pc, int lane, fl::u8 d, fl::u8 scale) {
384 return fl::scale8(pc.dither<SLOT>(pc, pc.loadByte<SLOT>(pc, lane), d), scale);
385 }
386
392 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 loadAndScale(PixelController & pc, int lane, fl::u8 scale) { return fl::scale8(pc.loadByte<SLOT>(pc, lane), scale); }
393
394
397 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 advanceAndLoadAndScale(PixelController & pc) { pc.advanceData(); return pc.loadAndScale<SLOT>(pc); }
398
402 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 advanceAndLoadAndScale(PixelController & pc, int lane) { pc.advanceData(); return pc.loadAndScale<SLOT>(pc, lane); }
403
408 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 advanceAndLoadAndScale(PixelController & pc, int lane, fl::u8 scale) { pc.advanceData(); return pc.loadAndScale<SLOT>(pc, lane, scale); }
409
411
412
417
423 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 getd(PixelController & pc) { return pc.d[RO(SLOT)]; }
424
430 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 getscale(PixelController & pc) { return pc.mColorAdjustment.premixed.raw[RO(SLOT)]; }
431
433
434
436
437 // Helper functions to get around gcc stupidities
443
444 FASTLED_FORCE_INLINE fl::u8 loadAndScale0(int lane) { return loadAndScale<0>(*this, lane); }
445 FASTLED_FORCE_INLINE fl::u8 loadAndScale1(int lane) { return loadAndScale<1>(*this, lane); }
446 FASTLED_FORCE_INLINE fl::u8 loadAndScale2(int lane) { return loadAndScale<2>(*this, lane); }
449
450 // LoadAndScale0 loads the pixel data in the order specified by RGB_ORDER and then scales it by the color correction values
451 // For example in color order GRB, loadAndScale0() will return the green channel scaled by the color correction value for green.
457
461
462 #if FASTLED_HD_COLOR_MIXING
463 template<int SLOT> FASTLED_FORCE_INLINE static fl::u8 getScaleFullBrightness(PixelController & pc) { return pc.mColorAdjustment.color.raw[RO(SLOT)]; }
464
469 FASTLED_FORCE_INLINE void loadRGBScaleAndBrightness(fl::u8* c0, fl::u8* c1, fl::u8* c2, fl::u8* brightness) {
470 *c0 = getScaleFullBrightness<0>(*this);
471 *c1 = getScaleFullBrightness<1>(*this);
472 *c2 = getScaleFullBrightness<2>(*this);
473 *brightness = mColorAdjustment.brightness;
474 }
475
477 FL_DEPRECATED("Use loadRGBScaleAndBrightness() instead")
478 FASTLED_FORCE_INLINE void getHdScale(fl::u8* c0, fl::u8* c1, fl::u8* c2, fl::u8* brightness) {
479 loadRGBScaleAndBrightness(c0, c1, c2, brightness);
480 }
481
484 FASTLED_FORCE_INLINE fl::u8 getBrightness() {
485 return mColorAdjustment.brightness;
486 }
487 #endif
488
489 // NOTE: loadAndScale_APA102_HD() has been moved to src/fl/chipsets/encoders/apa102.h
490 // Use fl::loadAndScale_APA102_HD<RGB_ORDER>(pixels, ...) instead
491
493 fl::u8 *b2_out) {
494 *b0_out = loadAndScale0();
495 *b1_out = loadAndScale1();
496 *b2_out = loadAndScale2();
497 }
498
499 // NOTE: loadAndScale_WS2816_HD() has been moved to src/fl/chipsets/encoders/ws2816.h
500 // Use fl::loadAndScale_WS2816_HD<RGB_ORDER>(pixels, ...) instead
501
508 const fl::u8 b = mData[c];
509 return fl::scale8(fl::Dither::apply(b, d[c]), mColorAdjustment.premixed.raw[c]);
510 }
511
517 const Rgbw& rgbw, fl::u8 *r_out, fl::u8 *g_out, fl::u8 *b_out,
518 fl::u8 *w_out) {
519#ifdef FL_IS_AVR
521 // No RGBW conversion on AVR; W stays black, as in loadAndScaleRGBW.
522 *r_out = loadAndScaleChannel(0);
523 *g_out = loadAndScaleChannel(1);
524 *b_out = loadAndScaleChannel(2);
525 *w_out = 0;
526#else
527 const CRGB rgb(mData[0], mData[1], mData[2]);
528 *w_out = 0;
530 rgb.r, rgb.g, rgb.b,
531 mColorAdjustment.premixed.r, mColorAdjustment.premixed.g, mColorAdjustment.premixed.b,
532 r_out, g_out, b_out, w_out);
533#endif
534 }
535
538 fl::Rgbww rgbww, fl::u8 *r_out, fl::u8 *g_out, fl::u8 *b_out,
539 fl::u8 *ww_out, fl::u8 *wc_out) {
540#ifdef FL_IS_AVR
541 FL_UNUSED(rgbww);
542 FL_WARN_ONCE("RGBWW colorimetric is not supported on AVR -- the warm "
543 "and cool white channels will be black. Use an ESP32 / "
544 "Teensy / RP2040 target for full RGBWW support.");
545 *r_out = loadAndScaleChannel(0);
546 *g_out = loadAndScaleChannel(1);
547 *b_out = loadAndScaleChannel(2);
548 *ww_out = 0;
549 *wc_out = 0;
550#else
551 const CRGB rgb(mData[0], mData[1], mData[2]);
552 *ww_out = 0;
553 *wc_out = 0;
554 fl::rgb_2_rgbww(rgbww,
555 rgb.r, rgb.g, rgb.b,
556 mColorAdjustment.premixed.r,
557 mColorAdjustment.premixed.g,
558 mColorAdjustment.premixed.b,
559 r_out, g_out, b_out, ww_out, wc_out);
560#endif
561 }
562
564 const Rgbw& rgbw, fl::u8 *b0_out, fl::u8 *b1_out,
565 fl::u8 *b2_out, fl::u8 *b3_out) {
566#ifdef FL_IS_AVR
567 // Don't do RGBW conversion for AVR, just set the W pixel to black.
568 fl::u8 out[4] = {
569 // Get the pixels in native order.
573 0,
574 };
575 EOrderW w_placement = rgbw.w_placement;
576 // Apply w-component insertion.
578 w_placement, out[0], out[1], out[2],
579 0, // Pre-ordered RGB data with a 0 white component.
580 b0_out, b1_out, b2_out, b3_out);
581#else
582 const fl::u8 b0_index = RGB_BYTE0(RGB_ORDER); // Needed to re-order RGB back into led native order.
583 const fl::u8 b1_index = RGB_BYTE1(RGB_ORDER);
584 const fl::u8 b2_index = RGB_BYTE2(RGB_ORDER);
585 // Source-order RGB after white extraction, then the wire reorder.
586 CRGB rgb;
587 fl::u8 w = 0;
588 loadAndScaleRGBWUnordered(rgbw, &rgb.r, &rgb.g, &rgb.b, &w);
589 // Now finish the ordering so that the output is in the native led order for all of RGBW.
591 rgbw.w_placement,
592 rgb.raw[b0_index], // in-place re-ordering for the RGB data.
593 rgb.raw[b1_index],
594 rgb.raw[b2_index],
595 w, // The white component is not ordered in this call.
596 b0_out, b1_out, b2_out, b3_out); // RGBW data now in total native led order.
597#endif
598 }
599
605 fl::u8 *b0_out, fl::u8 *b1_out,
606 fl::u8 *b2_out, fl::u8 *b3_out,
607 fl::u8 *b4_out) {
608#ifdef FL_IS_AVR
609 // AVR: float colorimetric math is too expensive on the 8-bit core;
610 // the strip will get RGB-only output with both white channels black.
611 // Surface this with a FL_WARN_ONCE so the silent dropout is visible
612 // when debugging — a user configuring RGBWW on an AVR target almost
613 // certainly didn't expect their warm/cool W channels to be inert.
614 FL_WARN_ONCE("RGBWW colorimetric is not supported on AVR — the warm "
615 "and cool white channels will be black. Use an ESP32 / "
616 "Teensy / RP2040 target for full RGBWW support.");
617 fl::u8 r_pre = loadAndScale0();
618 fl::u8 g_pre = loadAndScale1();
619 fl::u8 b_pre = loadAndScale2();
621 rgbww.w_placement,
622 r_pre, g_pre, b_pre,
623 0, 0,
624 b0_out, b1_out, b2_out, b3_out, b4_out);
625#else
626 const fl::u8 b0_index = RGB_BYTE0(RGB_ORDER);
627 const fl::u8 b1_index = RGB_BYTE1(RGB_ORDER);
628 const fl::u8 b2_index = RGB_BYTE2(RGB_ORDER);
629 CRGB rgb;
630 fl::u8 ww = 0;
631 fl::u8 wc = 0;
632 loadAndScaleRGBWWUnordered(rgbww, &rgb.r, &rgb.g, &rgb.b, &ww, &wc);
634 rgbww.w_placement,
635 rgb.raw[b0_index],
636 rgb.raw[b1_index],
637 rgb.raw[b2_index],
638 ww, wc,
639 b0_out, b1_out, b2_out, b3_out, b4_out);
640#endif
641 }
642};
643
644/*
645using fl::RGB;
646using fl::RBG;
647using fl::GRB;
648using fl::GBR;
649using fl::BRG;
650using fl::BGR;
651*/
652
653
654
655
656
657
658
fl::UISlider brightness("Brightness", BRIGHTNESS, 0, 255)
fl::UISlider scale("Scale", 4,.1, 4,.1)
#define RGB_ORDER
Rgbw rgbw
Temporal binary dithering, as one self-contained, testable unit (#4672).
#define FL_DISABLE_WARNING_IMPLICIT_INT_CONVERSION
#define FASTLED_FORCE_INLINE
#define FL_UNUSED(x)
#define FL_DISABLE_WARNING_PUSH
#define FL_DEPRECATED(msg)
#define FL_DISABLE_WARNING_SIGN_CONVERSION
#define FL_DISABLE_WARNING_POP
#define FL_DISABLE_WARNING_FLOAT_CONVERSION
Legacy header.
#define BINARY_DITHER
Enable dithering using binary dithering (only option)
Definition dither_mode.h:16
fl::u8 EDitherMode
The dither setting, either DISABLE_DITHER or BINARY_DITHER.
Definition dither_mode.h:19
Declares dithering options and types.
fl::EOrderW EOrderW
Definition eorder.h:13
fl::EOrder EOrder
Definition eorder.h:12
Defines color channel ordering enumerations.
Declares functions for five-bit gamma correction.
Integer mapping functions between different integer sizes.
Legacy compatibility header for 8-bit math functions.
Legacy compatibility header for 8-bit scaling functions.
fl::CRGB CRGB
Definition crgb.h:25
unsigned char u8
Definition stdint.h:131
#define FL_WARN_ONCE(...)
Definition log.h:442
Centralized logging categories for FastLED hardware interfaces and subsystems.
u8 ditherFrame() FL_NO_EXCEPT
Return the temporal-dither phase shared by all controllers in this frame.
unsigned char u8
Definition stdint.h:131
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.
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)
Definition rgbw.cpp.hpp:678
FASTLED_FORCE_INLINE void rgb_2_rgbw(const Rgbw &cfg, 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 using one of the functions.
Definition rgbw.h:380
signed char i8
Definition stdint.h:130
FASTLED_FORCE_INLINE void rgb_2_rgbww(const Rgbww &cfg, fl::u8 r, fl::u8 g, fl::u8 b, fl::u8 r_scale, fl::u8 g_scale, fl::u8 b_scale, fl::u8 *out_r, fl::u8 *out_g, fl::u8 *out_b, fl::u8 *out_ww, fl::u8 *out_wc) FL_NO_EXCEPT
Definition rgbww.h:173
Base definition for an LED controller.
Definition crgb.hpp:179
#define RGB_BYTE2(RO)
Gets the color channel for byte 2.
#define RGB_BYTE1(RO)
Gets the color channel for byte 1.
#define RGB_BYTE0(RO)
Gets the color channel for byte 0.
#define RO(X)
Gets the assigned color channel for a byte's position in the output, using the color order (EOrder) t...
Legacy header.
Functions for red, green, blue, white (RGBW) output.
5-channel RGB + warm-W + cool-W (RGBWW / RGBCCT) configuration types (issue #2558,...
#define FL_STATIC_ASSERT(...)
Portable compile-time assertion wrapper.
static ColorAdjustment noAdjustment()
the per-channel scale values premixed with brightness.
Color adjustment structure for pixel output.
static FASTLED_FORCE_INLINE fl::u8 loadAndScale(PixelController &pc, int lane, fl::u8 d, fl::u8 scale)
Complete pipeline: load → dither → scale (explicit dither/scale values)
static FASTLED_FORCE_INLINE fl::u8 advanceAndLoadAndScale(PixelController &pc, int lane)
A version of loadAndScale() that advances the output data pointer.
FASTLED_FORCE_INLINE fl::u8 loadAndScale1()
non-template alias of loadAndScale<1>()
FASTLED_FORCE_INLINE int size() const
Get the length of the LED strip.
PixelController(const fl::u8 *d, int len, ColorAdjustment color_adjustment, EDitherMode dither, bool advance, fl::u8 skip)
Constructor.
static FASTLED_FORCE_INLINE fl::u8 scale(PixelController &, fl::u8 b, fl::u8 scale)
Scale a value.
static FASTLED_FORCE_INLINE fl::u8 loadByte(PixelController &pc)
Read a byte of LED data.
void init_binary_dithering()
Set up the values for binary dithering from the shared frame phase.
static FASTLED_FORCE_INLINE fl::u8 advanceAndLoadAndScale(PixelController &pc, int lane, fl::u8 scale)
A version of loadAndScale() that advances the output data pointer without dithering.
int mLenRemaining
counter for the number of LEDs left to process
void initOffsets(int len)
Initialize the PixelController::mOffsets array based on the length of the strip.
FASTLED_FORCE_INLINE fl::u8 stepAdvanceAndLoadAndScale0(int lane, fl::u8 scale)
stepDithering() and advanceAndLoadAndScale0()
FASTLED_FORCE_INLINE void loadAndScaleRGBWWUnordered(fl::Rgbww rgbww, fl::u8 *r_out, fl::u8 *g_out, fl::u8 *b_out, fl::u8 *ww_out, fl::u8 *wc_out)
loadAndScaleRGBWW before its wire reorder. See loadAndScaleRGBWUnordered.
FASTLED_FORCE_INLINE fl::u8 getScale1()
non-template alias of getscale<1>()
FASTLED_FORCE_INLINE void preStepFirstByteDithering()
Some chipsets pre-cycle the first byte, which means we want to cycle byte 0's dithering separately.
fl::u8 e[3]
[DITHER] Max dither range per R,G,B channel (inversely proportional to brightness)
FASTLED_FORCE_INLINE void loadAndScaleRGBWW(fl::Rgbww rgbww, fl::u8 *b0_out, fl::u8 *b1_out, fl::u8 *b2_out, fl::u8 *b3_out, fl::u8 *b4_out)
Load + scale a single pixel to 5-channel RGBWW (issue #2558).
FASTLED_FORCE_INLINE fl::u8 loadAndScale0()
non-template alias of loadAndScale<0>()
FASTLED_FORCE_INLINE int advanceBy()
Get the amount to advance the pointer by.
static FASTLED_FORCE_INLINE fl::u8 loadAndScale(PixelController &pc, int lane)
Complete pipeline: load → dither → scale (parallel output version)
static FASTLED_FORCE_INLINE fl::u8 loadByte(PixelController &pc, int lane)
Read a byte of LED data for parallel output.
static FASTLED_FORCE_INLINE fl::u8 scale(PixelController &pc, fl::u8 b)
Scale a value using the per-channel scale data.
FASTLED_FORCE_INLINE int lanes()
Get the number of lanes of the Controller.
FASTLED_FORCE_INLINE void loadAndScaleRGBW(const Rgbw &rgbw, fl::u8 *b0_out, fl::u8 *b1_out, fl::u8 *b2_out, fl::u8 *b3_out)
fl::u8 d[3]
[DITHER] Current dither offset per R,G,B channel (toggles via stepDithering)
FASTLED_FORCE_INLINE fl::u8 stepAdvanceAndLoadAndScale0()
stepDithering() and advanceAndLoadAndScale0()
int mOffsets[LANES]
the number of bytes to offset each lane from the starting pointer
FASTLED_FORCE_INLINE fl::u8 loadAndScale2()
non-template alias of loadAndScale<2>()
static FASTLED_FORCE_INLINE fl::u8 getscale(PixelController &pc)
Gets the scale data for the provided output slot.
PixelController(const PixelController< RGB_ORDER_OTHER, LANES, MASK > &other)
PixelController(const CRGB &d, int len, ColorAdjustment color_adjustment, EDitherMode dither)
Constructor.
ColorAdjustment mColorAdjustment
const fl::u8 * mData
pointer to the underlying LED data
void reseed_binary_dithering(fl::u8 R)
Re-point binary dithering at phase R after construction, leaving the per-channel ranges e[] as init_b...
FASTLED_FORCE_INLINE void loadAndScaleRGB(fl::u8 *b0_out, fl::u8 *b1_out, fl::u8 *b2_out)
int mLen
number of LEDs in the data for one lane
FASTLED_FORCE_INLINE bool ditherActive() const
Is temporal dithering on for this frame? (any channel has a range)
static constexpr EOrder kColorOrder
The colour order this instantiation writes, as a value.
FASTLED_FORCE_INLINE fl::u8 loadAndScale0(int lane, fl::u8 scale)
non-template alias of loadAndScale<0>()
PixelController & operator=(const PixelController &other)
Copy assignment, through the same copy() as the copy constructor.
FASTLED_FORCE_INLINE fl::u8 loadAndScale2(int lane)
non-template alias of loadAndScale<2>()
FASTLED_FORCE_INLINE fl::u8 loadAndScaleChannel(fl::u8 c)
One source channel, loaded, dithered and scaled – loadAndScale<SLOT> with RO(SLOT) replaced by a runt...
const fl::u8 * getRawPixelData() const
Get read-only access to the current pixel data Used by encoders to access raw RGB values for HD proce...
static FASTLED_FORCE_INLINE fl::u8 advanceAndLoadAndScale(PixelController &pc)
A version of loadAndScale() that advances the output data pointer.
FASTLED_FORCE_INLINE fl::u8 advanceAndLoadAndScale0()
non-template alias of advanceAndLoadAndScale<0>()
void enable_dithering(EDitherMode dither)
Toggle dithering enable/disable.
FASTLED_FORCE_INLINE fl::u8 getScale0()
non-template alias of getscale<0>()
FASTLED_FORCE_INLINE void advanceData()
Advance the data pointer forward, adjust position counter.
static FASTLED_FORCE_INLINE fl::u8 dither(PixelController &, fl::u8 b, fl::u8 d)
Add explicit dither offset to pixel value (BEFORE scaling).
FASTLED_FORCE_INLINE fl::u8 loadAndScale1(int lane, fl::u8 scale)
non-template alias of loadAndScale<1>()
FASTLED_FORCE_INLINE fl::u8 stepAdvanceAndLoadAndScale0(int lane)
stepDithering() and advanceAndLoadAndScale0()
FASTLED_FORCE_INLINE fl::u8 advanceAndLoadAndScale0(int lane, fl::u8 scale)
non-template alias of advanceAndLoadAndScale<0>()
FASTLED_FORCE_INLINE bool has(int n)
Do we have n pixels left to process?
static FASTLED_FORCE_INLINE fl::u8 getd(PixelController &pc)
Gets the dithering data for the provided output slot.
PixelController(const CRGB *d, int len, ColorAdjustment color_adjustment, EDitherMode dither)
Constructor.
FASTLED_FORCE_INLINE void stepDithering()
Step the dithering forward - creates triangular wave that toggles between pixels.
FASTLED_FORCE_INLINE fl::u8 loadAndScale2(int lane, fl::u8 scale)
non-template alias of loadAndScale<2>()
FASTLED_FORCE_INLINE fl::PixelIterator as_iterator(const Rgbw &rgbw)
static FASTLED_FORCE_INLINE fl::u8 loadAndScale(PixelController &pc)
Complete pipeline: load → dither → scale (THE MAGIC HAPPENS HERE!) Order is critical: pixel + dit...
FASTLED_FORCE_INLINE fl::u8 loadAndScale1(int lane)
non-template alias of loadAndScale<1>()
PixelController(const PixelController &other)
Copy constructor.
FASTLED_FORCE_INLINE fl::u8 getScale2()
non-template alias of getscale<2>()
static FASTLED_FORCE_INLINE fl::u8 loadAndScale(PixelController &pc, int lane, fl::u8 scale)
Loads and scales a single byte for a given output slot and lane.
static FASTLED_FORCE_INLINE fl::u8 dither(PixelController &pc, fl::u8 b)
Add dither offset to pixel value (BEFORE scaling).
void copy(const PixelControllerT &other)
FASTLED_FORCE_INLINE fl::u8 advanceAndLoadAndScale0(int lane)
non-template alias of advanceAndLoadAndScale<0>()
FASTLED_FORCE_INLINE void loadAndScaleRGBWUnordered(const Rgbw &rgbw, fl::u8 *r_out, fl::u8 *g_out, fl::u8 *b_out, fl::u8 *w_out)
loadAndScaleRGBW before its wire reorder: RGB in source order plus W.
fl::i8 mAdvance
how many bytes to advance the pointer by each time. For CRGB this is 3.
FASTLED_FORCE_INLINE fl::u8 loadAndScale0(int lane)
non-template alias of loadAndScale<0>()
Pixel controller class.
static FASTLED_FORCE_INLINE bool active(const u8(&e)[3]) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE void stepChannel(u8(&d)[3], const u8(&e)[3], int c) FL_NO_EXCEPT
step for a single channel (drivers that pre-step their first byte).
static FASTLED_FORCE_INLINE void reseed(u8(&d)[3], const u8(&e)[3], u8 frame) FL_NO_EXCEPT
Re-point d at frame, keeping the ranges init left in e.
static FASTLED_FORCE_INLINE void clear(u8(&d)[3], u8(&e)[3]) FL_NO_EXCEPT
static FASTLED_FORCE_INLINE u8 apply(u8 b, u8 d) FL_NO_EXCEPT
Add the offset to a source byte, before scaling. Black is never lifted.
static FASTLED_FORCE_INLINE void init(u8(&d)[3], u8(&e)[3], const u8(&scale)[3], u8 frame) FL_NO_EXCEPT
Set up e from the per-channel brightness scale and d from frame.
static FASTLED_FORCE_INLINE void step(u8(&d)[3], const u8(&e)[3]) FL_NO_EXCEPT
Next pixel: toggle each offset to its complement in [0, e], so neighbours dither in opposite directio...
EOrderWW w_placement
Definition rgbww.h:72
Per-strip RGBWW configuration.
Definition rgbww.h:60