FastLED 3.9.15
Loading...
Searching...
No Matches
colorutils.h
Go to the documentation of this file.
1#pragma once
2
5
6// #include "FastLED.h"
7
8#include "fl/stl/int.h"
9#include "fl/stl/span.h"
10#include "crgb.h" // IWYU pragma: keep
11#include "fastled_progmem.h"
12#include "fl/gfx/blur.h" // IWYU pragma: keep
13#include "fl/gfx/crgb16.h"
15#include "fl/gfx/fill.h"
16#include "fl/math/xymap.h" // IWYU pragma: keep
17#include "fl/math/memmove.h"
19#include "fl/stl/cstring.h"
20#include "fl/log/log.h" // IWYU pragma: keep
21#include "platforms/is_platform.h" // IWYU pragma: keep
22#include "fl/stl/noexcept.h"
23
24// #include "pixeltypes.h" // pulls in FastLED.h, beware.
25
32
33#if !defined(FASTLED_USE_32_BIT_GRADIENT_FILL)
34#if defined(FL_IS_AVR)
35#define FASTLED_USE_32_BIT_GRADIENT_FILL 0
36#else
37#define FASTLED_USE_32_BIT_GRADIENT_FILL 1
38#endif
39#endif
40
43
44namespace fl {
45
47
51
57void fadeLightBy(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy) FL_NOEXCEPT;
58
61 fadeLightBy(leds.data(), static_cast<fl::u16>(leds.size()), fadeBy);
62}
63
65void fade_video(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy) FL_NOEXCEPT;
66
68inline void fade_video(fl::span<CRGB> leds, fl::u8 fadeBy) FL_NOEXCEPT {
69 fade_video(leds.data(), static_cast<fl::u16>(leds.size()), fadeBy);
70}
71
77void nscale8_video(CRGB *leds, fl::u16 num_leds, fl::u8 scale) FL_NOEXCEPT;
78
81 nscale8_video(leds.data(), static_cast<fl::u16>(leds.size()), scale);
82}
83
89void fadeToBlackBy(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy) FL_NOEXCEPT;
90
93 fadeToBlackBy(leds.data(), static_cast<fl::u16>(leds.size()), fadeBy);
94}
95
97void fade_raw(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy) FL_NOEXCEPT;
98
100inline void fade_raw(fl::span<CRGB> leds, fl::u8 fadeBy) FL_NOEXCEPT {
101 fade_raw(leds.data(), static_cast<fl::u16>(leds.size()), fadeBy);
102}
103
110void nscale8(CRGB *leds, fl::u16 num_leds, fl::u8 scale) FL_NOEXCEPT;
111
114 nscale8(leds.data(), static_cast<fl::u16>(leds.size()), scale);
115}
116
128void fadeUsingColor(CRGB *leds, fl::u16 numLeds, const CRGB &colormask) FL_NOEXCEPT;
129
131inline void fadeUsingColor(fl::span<CRGB> leds, const CRGB &colormask) FL_NOEXCEPT {
132 fadeUsingColor(leds.data(), static_cast<fl::u16>(leds.size()), colormask);
133}
134
136
140
146CRGB blend(const CRGB &p1, const CRGB &p2, fract8 amountOfP2) FL_NOEXCEPT;
147
150CHSV blend(const CHSV &p1, const CHSV &p2, fract8 amountOfP2,
152
161CRGB *blend(const CRGB *src1, const CRGB *src2, CRGB *dest, fl::u16 count,
162 fract8 amountOfsrc2) FL_NOEXCEPT;
163
165inline void blend(fl::span<const CRGB> src1, fl::span<const CRGB> src2,
166 fl::span<CRGB> dest, fract8 amountOfsrc2) FL_NOEXCEPT {
167 blend(src1.data(), src2.data(), dest.data(),
168 static_cast<fl::u16>(dest.size()), amountOfsrc2);
169}
170
173CHSV *blend(const CHSV *src1, const CHSV *src2, CHSV *dest, fl::u16 count,
174 fract8 amountOfsrc2,
176
182CRGB &nblend(CRGB &existing, const CRGB &overlay, fract8 amountOfOverlay) FL_NOEXCEPT;
183
186CHSV &nblend(CHSV &existing, const CHSV &overlay, fract8 amountOfOverlay,
188
195void nblend(CRGB *existing, const CRGB *overlay, fl::u16 count,
196 fract8 amountOfOverlay) FL_NOEXCEPT;
197
199inline void nblend(fl::span<CRGB> existing, fl::span<const CRGB> overlay,
200 fract8 amountOfOverlay) FL_NOEXCEPT {
201 nblend(existing.data(), overlay.data(),
202 static_cast<fl::u16>(existing.size()), amountOfOverlay);
203}
204
207void nblend(CHSV *existing, const CHSV *overlay, fl::u16 count,
208 fract8 amountOfOverlay,
210
212
215
221CRGB HeatColor(fl::u8 temperature) FL_NOEXCEPT;
222
225
293
300
301class CRGBPalette16; // IWYU pragma: keep
302class CRGBPalette32; // IWYU pragma: keep
303class CRGBPalette256; // IWYU pragma: keep
304class CHSVPalette16; // IWYU pragma: keep
305class CHSVPalette32; // IWYU pragma: keep
306class CHSVPalette256; // IWYU pragma: keep
307
312typedef union {
313 struct {
314 fl::u8 index;
315 fl::u8 r;
316 fl::u8 g;
317 fl::u8 b;
318 };
319 fl::u32 dword;
320 fl::u8 bytes[4];
321} TRGBGradientPaletteEntryUnion;
322
326#define FASTLED_MAX_GRADIENT_PALETTE_ENTRIES 256
327
328typedef fl::u8
329 TDynamicRGBGradientPalette_byte;
331typedef const TDynamicRGBGradientPalette_byte
332 *TDynamicRGBGradientPalette_bytes;
334typedef TDynamicRGBGradientPalette_bytes
335 TDynamicRGBGradientPaletteRef;
337
339
343
347void UpscalePalette(const class CRGBPalette16 &srcpal16,
348 class CRGBPalette256 &destpal256) FL_NOEXCEPT;
350void UpscalePalette(const class CHSVPalette16 &srcpal16,
351 class CHSVPalette256 &destpal256) FL_NOEXCEPT;
352
356void UpscalePalette(const class CRGBPalette16 &srcpal16,
357 class CRGBPalette32 &destpal32) FL_NOEXCEPT;
359void UpscalePalette(const class CHSVPalette16 &srcpal16,
360 class CHSVPalette32 &destpal32) FL_NOEXCEPT;
361
365void UpscalePalette(const class CRGBPalette32 &srcpal32,
366 class CRGBPalette256 &destpal256) FL_NOEXCEPT;
368void UpscalePalette(const class CHSVPalette32 &srcpal32,
369 class CHSVPalette256 &destpal256) FL_NOEXCEPT;
370
372
375
376namespace detail {
377
378template <typename TColor>
379struct PaletteFillTraits;
380
381template <>
382struct PaletteFillTraits<CHSV> {
383 static void fillSolid(CHSV *entries, fl::u16 size, const CHSV &color) FL_NOEXCEPT {
384 fill_solid(entries, static_cast<int>(size), color);
385 }
386
387 static void fillGradient(CHSV *entries, fl::u16 size, const CHSV &c1,
388 const CHSV &c2) FL_NOEXCEPT {
389 fill_gradient(entries, size, c1, c2);
390 }
391
392 static void fillGradient(CHSV *entries, fl::u16 size, const CHSV &c1,
393 const CHSV &c2, const CHSV &c3) FL_NOEXCEPT {
394 fill_gradient(entries, size, c1, c2, c3);
395 }
396
397 static void fillGradient(CHSV *entries, fl::u16 size, const CHSV &c1,
398 const CHSV &c2, const CHSV &c3,
399 const CHSV &c4) FL_NOEXCEPT {
400 fill_gradient(entries, size, c1, c2, c3, c4);
401 }
402};
403
404template <>
405struct PaletteFillTraits<CRGB> {
406 static void fillSolid(CRGB *entries, fl::u16 size, const CRGB &color) FL_NOEXCEPT {
407 fill_solid(entries, static_cast<int>(size), color);
408 }
409
410 static void fillGradient(CRGB *entries, fl::u16 size, const CRGB &c1,
411 const CRGB &c2) FL_NOEXCEPT {
412 fill_gradient_RGB(entries, size, c1, c2);
413 }
414
415 static void fillGradient(CRGB *entries, fl::u16 size, const CRGB &c1,
416 const CRGB &c2, const CRGB &c3) FL_NOEXCEPT {
417 fill_gradient_RGB(entries, size, c1, c2, c3);
418 }
419
420 static void fillGradient(CRGB *entries, fl::u16 size, const CRGB &c1,
421 const CRGB &c2, const CRGB &c3,
422 const CRGB &c4) FL_NOEXCEPT {
423 fill_gradient_RGB(entries, size, c1, c2, c3, c4);
424 }
425};
426
427template <typename TColor, fl::u16 Size>
428class TColorPalette {
429 public:
430 TColor entries[Size];
431
432 TColorPalette() FL_NOEXCEPT {}
433
434 TColorPalette(const TColorPalette &rhs) FL_NOEXCEPT { copyBytes(rhs.entries); }
435
436 TColorPalette(const TColor (&rhs)[Size]) FL_NOEXCEPT { copyBytes(rhs); }
437
438 TColorPalette &operator=(const TColorPalette &rhs) FL_NOEXCEPT {
439 copyBytes(rhs.entries);
440 return *this;
441 }
442
443 TColorPalette &operator=(const TColor (&rhs)[Size]) FL_NOEXCEPT {
444 copyBytes(rhs);
445 return *this;
446 }
447
448 TColorPalette(const TColor &c1) FL_NOEXCEPT {
449 PaletteFillTraits<TColor>::fillSolid(entries, Size, c1);
450 }
451
452 TColorPalette(const TColor &c1, const TColor &c2) FL_NOEXCEPT {
453 PaletteFillTraits<TColor>::fillGradient(entries, Size, c1, c2);
454 }
455
456 TColorPalette(const TColor &c1, const TColor &c2,
457 const TColor &c3) FL_NOEXCEPT {
458 PaletteFillTraits<TColor>::fillGradient(entries, Size, c1, c2, c3);
459 }
460
461 TColorPalette(const TColor &c1, const TColor &c2, const TColor &c3,
462 const TColor &c4) FL_NOEXCEPT {
463 PaletteFillTraits<TColor>::fillGradient(entries, Size, c1, c2, c3, c4);
464 }
465
466 inline TColor &operator[](fl::u8 x) FL_NOEXCEPT __attribute__((always_inline)) {
467 return entries[x];
468 }
469
470 inline const TColor &operator[](fl::u8 x) const FL_NOEXCEPT
471 __attribute__((always_inline)) {
472 return entries[x];
473 }
474
475 inline TColor &operator[](int x) FL_NOEXCEPT __attribute__((always_inline)) {
476 return entries[(fl::u8)x];
477 }
478
479 inline const TColor &operator[](int x) const FL_NOEXCEPT
480 __attribute__((always_inline)) {
481 return entries[(fl::u8)x];
482 }
483
484 operator TColor *() FL_NOEXCEPT { return &(entries[0]); }
485
486 // Hidden friends — C++20 deprecates synthesizing a reversed candidate
487 // for member operator==, producing -Wambiguous-reversed-operator at every
488 // call site. Defining the comparison as a non-member friend declared
489 // inside the class body solves that cleanly (found only via ADL on the
490 // palette type, no reverse-candidate synthesis applies). Derived classes
491 // get these for free through ADL on the base, so the prior
492 // `using Base::operator==/!=` injections are no longer needed. #2724
493 friend bool operator==(const TColorPalette &lhs,
494 const TColorPalette &rhs) FL_NOEXCEPT {
495 const TColor *lhs_entries = &(lhs.entries[0]);
496 const TColor *rhs_entries = &(rhs.entries[0]);
497 if (lhs_entries == rhs_entries) {
498 return true;
499 }
500 return fl::memcmp(lhs_entries, rhs_entries, sizeof(lhs.entries)) == 0;
501 }
502
503 friend bool operator!=(const TColorPalette &lhs,
504 const TColorPalette &rhs) FL_NOEXCEPT {
505 return !(lhs == rhs);
506 }
507
508 protected:
509 void copyBytes(const TColor *rhs) FL_NOEXCEPT {
510 memmove8((void *)&(entries[0]), rhs, sizeof(entries));
511 }
512
513 template <typename TOtherColor>
514 void copyConverted(const TOtherColor *rhs) FL_NOEXCEPT {
515 for (fl::u16 i = 0; i < Size; ++i) {
516 entries[i] = rhs[i];
517 }
518 }
519};
520
521template <fl::u16 Size>
522class TCRGBPalette : public TColorPalette<CRGB, Size> {
523 public:
524 using Base = TColorPalette<CRGB, Size>;
525 using Base::Base;
526 using Base::entries;
527 // operator== / operator!= are hidden friends on Base (#2724); they reach
528 // derived classes automatically via ADL, so no using-declaration needed.
529 using Base::operator=;
530 using Base::operator[];
531 using Base::operator CRGB*;
532
533 TCRGBPalette() FL_NOEXCEPT {}
534
535 // Explicit Rule of 5 — the user-defined ctors below otherwise force the
536 // copy-assign / destructor to be implicitly-declared, which C++11+
537 // deprecates (-Wdeprecated-copy, ~472 hits across teensy30/31/40/41/LC).
538 // Mirrors what CRGBPalette16 already does at lines 699-701. #2725
539 TCRGBPalette(const TCRGBPalette &) FL_NOEXCEPT = default;
540 TCRGBPalette &operator=(const TCRGBPalette &) FL_NOEXCEPT = default;
541 ~TCRGBPalette() FL_NOEXCEPT = default;
542
543 TCRGBPalette(const TColorPalette<CHSV, Size> &rhs) FL_NOEXCEPT {
544 Base::copyConverted(rhs.entries);
545 }
546
547 TCRGBPalette(const CHSV (&rhs)[Size]) FL_NOEXCEPT {
548 Base::copyConverted(rhs);
549 }
550
551 TCRGBPalette &operator=(const TColorPalette<CHSV, Size> &rhs) FL_NOEXCEPT {
552 Base::copyConverted(rhs.entries);
553 return *this;
554 }
555
556 TCRGBPalette &operator=(const CHSV (&rhs)[Size]) FL_NOEXCEPT {
557 Base::copyConverted(rhs);
558 return *this;
559 }
560
561 TCRGBPalette(const CHSV &c1) FL_NOEXCEPT {
562 fill_solid(&(entries[0]), static_cast<int>(Size), c1);
563 }
564
565 TCRGBPalette(const CHSV &c1, const CHSV &c2) FL_NOEXCEPT {
566 fill_gradient(&(entries[0]), Size, c1, c2);
567 }
568
569 TCRGBPalette(const CHSV &c1, const CHSV &c2,
570 const CHSV &c3) FL_NOEXCEPT {
571 fill_gradient(&(entries[0]), Size, c1, c2, c3);
572 }
573
574 TCRGBPalette(const CHSV &c1, const CHSV &c2, const CHSV &c3,
575 const CHSV &c4) FL_NOEXCEPT {
576 fill_gradient(&(entries[0]), Size, c1, c2, c3, c4);
577 }
578};
579
580inline void loadProgmemPalette(CRGB *entries, const fl::u32 *rhs,
581 fl::u16 count) FL_NOEXCEPT {
582 for (fl::u16 i = 0; i < count; ++i) {
583 entries[i] = FL_PGM_READ_DWORD_NEAR(rhs + i);
584 }
585}
586
587inline void loadProgmemPalette(CHSV *entries, const fl::u32 *rhs,
588 fl::u16 count) FL_NOEXCEPT {
589 for (fl::u16 i = 0; i < count; ++i) {
590 CRGB xyz(FL_PGM_READ_DWORD_NEAR(rhs + i));
591 entries[i].hue = xyz.red;
592 entries[i].sat = xyz.green;
593 entries[i].val = xyz.blue;
594 }
595}
596
597template <typename TPalette16, typename TColor>
598void initPalette16(TPalette16 &palette, const TColor &c00, const TColor &c01,
599 const TColor &c02, const TColor &c03, const TColor &c04,
600 const TColor &c05, const TColor &c06, const TColor &c07,
601 const TColor &c08, const TColor &c09, const TColor &c10,
602 const TColor &c11, const TColor &c12, const TColor &c13,
603 const TColor &c14, const TColor &c15) FL_NOEXCEPT {
604 const TColor colors[16] = {c00, c01, c02, c03, c04, c05, c06, c07,
605 c08, c09, c10, c11, c12, c13, c14, c15};
606 palette = colors;
607}
608
609} // namespace detail
610
612class CHSVPalette16 : public detail::TColorPalette<CHSV, 16> {
613 public:
614 using Base = detail::TColorPalette<CHSV, 16>;
615 using Base::Base;
616 using Base::entries;
617 // operator== / operator!= are hidden friends on Base (#2724); they reach
618 // derived classes automatically via ADL, so no using-declaration needed.
619 using Base::operator=;
620 using Base::operator[];
621 using Base::operator CHSV*;
622
623 CHSVPalette16() FL_NOEXCEPT = default;
624 CHSVPalette16(const CHSVPalette16 &rhs) FL_NOEXCEPT = default;
625 CHSVPalette16 &operator=(const CHSVPalette16 &rhs) FL_NOEXCEPT = default;
626
627 CHSVPalette16(const CHSV &c00, const CHSV &c01, const CHSV &c02,
628 const CHSV &c03, const CHSV &c04, const CHSV &c05,
629 const CHSV &c06, const CHSV &c07, const CHSV &c08,
630 const CHSV &c09, const CHSV &c10, const CHSV &c11,
631 const CHSV &c12, const CHSV &c13, const CHSV &c14,
632 const CHSV &c15) FL_NOEXCEPT {
633 detail::initPalette16(*this, c00, c01, c02, c03, c04, c05, c06, c07,
634 c08, c09, c10, c11, c12, c13, c14, c15);
635 }
636
637 CHSVPalette16(const TProgmemHSVPalette16 &rhs) FL_NOEXCEPT {
638 detail::loadProgmemPalette(entries, rhs, 16);
639 }
640
641 CHSVPalette16 &operator=(const TProgmemHSVPalette16 &rhs) FL_NOEXCEPT {
642 detail::loadProgmemPalette(entries, rhs, 16);
643 return *this;
644 }
645};
646
648class CHSVPalette256 : public detail::TColorPalette<CHSV, 256> {
649 public:
650 using Base = detail::TColorPalette<CHSV, 256>;
651 using Base::Base;
652 using Base::entries;
653 // operator== / operator!= are hidden friends on Base (#2724); they reach
654 // derived classes automatically via ADL, so no using-declaration needed.
655 using Base::operator=;
656 using Base::operator[];
657 using Base::operator CHSV*;
658
659 CHSVPalette256() FL_NOEXCEPT = default;
660 CHSVPalette256(const CHSVPalette256 &rhs) FL_NOEXCEPT = default;
661 CHSVPalette256 &operator=(const CHSVPalette256 &rhs) FL_NOEXCEPT = default;
662
663 CHSVPalette256(const CHSV &c00, const CHSV &c01, const CHSV &c02,
664 const CHSV &c03, const CHSV &c04, const CHSV &c05,
665 const CHSV &c06, const CHSV &c07, const CHSV &c08,
666 const CHSV &c09, const CHSV &c10, const CHSV &c11,
667 const CHSV &c12, const CHSV &c13, const CHSV &c14,
668 const CHSV &c15) FL_NOEXCEPT {
669 CHSVPalette16 p16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
670 c10, c11, c12, c13, c14, c15);
671 *this = p16;
672 }
673
674 CHSVPalette256(const CHSVPalette16 &rhs16) FL_NOEXCEPT { UpscalePalette(rhs16, *this); }
675
676 CHSVPalette256(const CHSVPalette32 &rhs32) FL_NOEXCEPT { UpscalePalette(rhs32, *this); }
677
678 CHSVPalette256 &operator=(const CHSVPalette16 &rhs16) FL_NOEXCEPT {
679 UpscalePalette(rhs16, *this);
680 return *this;
681 }
682
683 CHSVPalette256 &operator=(const CHSVPalette32 &rhs32) FL_NOEXCEPT {
684 UpscalePalette(rhs32, *this);
685 return *this;
686 }
687
688 CHSVPalette256(const TProgmemHSVPalette16 &rhs) FL_NOEXCEPT {
689 CHSVPalette16 p16(rhs);
690 *this = p16;
691 }
692
693 CHSVPalette256 &operator=(const TProgmemHSVPalette16 &rhs) FL_NOEXCEPT {
694 CHSVPalette16 p16(rhs);
695 *this = p16;
696 return *this;
697 }
698
699 CHSVPalette256(const TProgmemHSVPalette32 &rhs) FL_NOEXCEPT;
700
701 CHSVPalette256 &operator=(const TProgmemHSVPalette32 &rhs) FL_NOEXCEPT;
702};
703
705class CRGBPalette16 : public detail::TCRGBPalette<16> {
706 public:
707 using Base = detail::TCRGBPalette<16>;
708 using Base::Base;
709 using Base::entries;
710 // operator== / operator!= are hidden friends on Base (#2724); they reach
711 // derived classes automatically via ADL, so no using-declaration needed.
712 using Base::operator=;
713 using Base::operator[];
714 using Base::operator CRGB*;
715
716 CRGBPalette16() FL_NOEXCEPT = default;
717 CRGBPalette16(const CRGBPalette16 &rhs) FL_NOEXCEPT = default;
718 CRGBPalette16 &operator=(const CRGBPalette16 &rhs) FL_NOEXCEPT = default;
719
720 CRGBPalette16(const CRGB &c00, const CRGB &c01, const CRGB &c02,
721 const CRGB &c03, const CRGB &c04, const CRGB &c05,
722 const CRGB &c06, const CRGB &c07, const CRGB &c08,
723 const CRGB &c09, const CRGB &c10, const CRGB &c11,
724 const CRGB &c12, const CRGB &c13, const CRGB &c14,
725 const CRGB &c15) FL_NOEXCEPT {
726 detail::initPalette16(*this, c00, c01, c02, c03, c04, c05, c06, c07,
727 c08, c09, c10, c11, c12, c13, c14, c15);
728 }
729
730 CRGBPalette16(const TProgmemRGBPalette16 &rhs) FL_NOEXCEPT {
731 detail::loadProgmemPalette(entries, rhs, 16);
732 }
733
734 CRGBPalette16 &operator=(const TProgmemRGBPalette16 &rhs) FL_NOEXCEPT {
735 detail::loadProgmemPalette(entries, rhs, 16);
736 return *this;
737 }
738
768 CRGBPalette16(TProgmemRGBGradientPalette_bytes progpal) FL_NOEXCEPT { *this = progpal; }
770 CRGBPalette16 &operator=(TProgmemRGBGradientPalette_bytes progpal) FL_NOEXCEPT {
771 TRGBGradientPaletteEntryUnion *progent =
772 // (TRGBGradientPaletteEntryUnion *)(progpal);
774 TRGBGradientPaletteEntryUnion u;
775
776 // Count entries with safety limit to prevent buffer overrun
777 fl::u16 count = 0;
778 bool has_terminator = false;
779 do {
780 u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
781 ++count;
782 if (u.index == 255) {
783 has_terminator = true;
784 break;
785 }
787 FL_WARN("DEFINE_GRADIENT_PALETTE missing index=255 terminator! "
788 "This will cause buffer overruns and crashes. "
789 "Auto-correcting but please fix your gradient definition.");
790 break;
791 }
792 } while (true);
793
794 fl::i8 lastSlotUsed = -1;
795
796 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
797 CRGB rgbstart(u.r, u.g, u.b);
798
799 int indexstart = 0;
800 fl::u8 istart8 = 0;
801 fl::u8 iend8 = 0;
802 fl::u16 entries_processed = 0;
803 while (indexstart < 255) {
804 // Safety: check BEFORE reading to prevent buffer overrun
805 if (!has_terminator && entries_processed + 1 >= count) {
806 // No more validated entries - extend current color to 255
807 istart8 = indexstart / 16;
808 iend8 = 255 / 16;
809 if (count < 16) {
810 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
811 istart8 = lastSlotUsed + 1;
812 if (iend8 < istart8) {
813 iend8 = istart8;
814 }
815 }
816 }
817 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbstart);
818 break;
819 }
820
821 ++progent;
822 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
823 int indexend = u.index;
824 CRGB rgbend(u.r, u.g, u.b);
825
826 istart8 = indexstart / 16;
827 iend8 = indexend / 16;
828 if (count < 16) {
829 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
830 istart8 = lastSlotUsed + 1;
831 if (iend8 < istart8) {
832 iend8 = istart8;
833 }
834 }
835 lastSlotUsed = iend8;
836 }
837 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbend);
838 indexstart = indexend;
839 rgbstart = rgbend;
840 ++entries_processed;
841 }
842 return *this;
843 }
847 CRGBPalette16 &
848 loadDynamicGradientPalette(TDynamicRGBGradientPalette_bytes gpal) FL_NOEXCEPT {
849 TRGBGradientPaletteEntryUnion *ent =
850 // (TRGBGradientPaletteEntryUnion *)(gpal);
852 TRGBGradientPaletteEntryUnion u;
853
854 // Count entries with safety limit to prevent buffer overrun
855 fl::u16 count = 0;
856 bool has_terminator = false;
857 do {
858 u = *(ent + count);
859 ++count;
860 if (u.index == 255) {
861 has_terminator = true;
862 break;
863 }
865 FL_WARN("Dynamic gradient palette missing index=255 terminator! "
866 "This will cause buffer overruns and crashes. "
867 "Auto-correcting but please fix your gradient definition.");
868 break;
869 }
870 } while (true);
871
872 fl::i8 lastSlotUsed = -1;
873
874 u = *ent;
875 CRGB rgbstart(u.r, u.g, u.b);
876
877 int indexstart = 0;
878 fl::u8 istart8 = 0;
879 fl::u8 iend8 = 0;
880 fl::u16 entries_processed = 0;
881 while (indexstart < 255) {
882 // Safety: check BEFORE reading to prevent buffer overrun
883 if (!has_terminator && entries_processed + 1 >= count) {
884 // No more validated entries - extend current color to 255
885 istart8 = indexstart / 16;
886 iend8 = 255 / 16;
887 if (count < 16) {
888 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
889 istart8 = lastSlotUsed + 1;
890 if (iend8 < istart8) {
891 iend8 = istart8;
892 }
893 }
894 }
895 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbstart);
896 break;
897 }
898
899 ++ent;
900 u = *ent;
901 int indexend = u.index;
902 CRGB rgbend(u.r, u.g, u.b);
903
904 istart8 = indexstart / 16;
905 iend8 = indexend / 16;
906 if (count < 16) {
907 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
908 istart8 = lastSlotUsed + 1;
909 if (iend8 < istart8) {
910 iend8 = istart8;
911 }
912 }
913 lastSlotUsed = iend8;
914 }
915 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbend);
916 indexstart = indexend;
917 rgbstart = rgbend;
918 ++entries_processed;
919 }
920 return *this;
921 }
922};
923
925class CHSVPalette32 : public detail::TColorPalette<CHSV, 32> {
926 public:
927 using Base = detail::TColorPalette<CHSV, 32>;
928 using Base::Base;
929 using Base::entries;
930 // operator== / operator!= are hidden friends on Base (#2724); they reach
931 // derived classes automatically via ADL, so no using-declaration needed.
932 using Base::operator=;
933 using Base::operator[];
934 using Base::operator CHSV*;
935
936 CHSVPalette32() FL_NOEXCEPT = default;
937 CHSVPalette32(const CHSVPalette32 &rhs) FL_NOEXCEPT = default;
938 CHSVPalette32 &operator=(const CHSVPalette32 &rhs) FL_NOEXCEPT = default;
939
940 CHSVPalette32(const CHSV &c00, const CHSV &c01, const CHSV &c02,
941 const CHSV &c03, const CHSV &c04, const CHSV &c05,
942 const CHSV &c06, const CHSV &c07, const CHSV &c08,
943 const CHSV &c09, const CHSV &c10, const CHSV &c11,
944 const CHSV &c12, const CHSV &c13, const CHSV &c14,
945 const CHSV &c15) FL_NOEXCEPT {
946 CHSVPalette16 p16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
947 c10, c11, c12, c13, c14, c15);
948 *this = p16;
949 }
950
951 CHSVPalette32(const CHSVPalette16 &rhs16) FL_NOEXCEPT { UpscalePalette(rhs16, *this); }
952
953 CHSVPalette32 &operator=(const CHSVPalette16 &rhs16) FL_NOEXCEPT {
954 UpscalePalette(rhs16, *this);
955 return *this;
956 }
957
958 CHSVPalette32(const TProgmemHSVPalette16 &rhs) FL_NOEXCEPT {
959 CHSVPalette16 p16(rhs);
960 *this = p16;
961 }
962
963 CHSVPalette32 &operator=(const TProgmemHSVPalette16 &rhs) FL_NOEXCEPT {
964 CHSVPalette16 p16(rhs);
965 *this = p16;
966 return *this;
967 }
968
969 CHSVPalette32(const TProgmemHSVPalette32 &rhs) FL_NOEXCEPT {
970 detail::loadProgmemPalette(entries, rhs, 32);
971 }
972
973 CHSVPalette32 &operator=(const TProgmemHSVPalette32 &rhs) FL_NOEXCEPT {
974 detail::loadProgmemPalette(entries, rhs, 32);
975 return *this;
976 }
977};
978
979inline CHSVPalette256::CHSVPalette256(const TProgmemHSVPalette32 &rhs) FL_NOEXCEPT {
980 CHSVPalette32 p32(rhs);
981 *this = p32;
982}
983
984inline CHSVPalette256 &
985CHSVPalette256::operator=(const TProgmemHSVPalette32 &rhs) FL_NOEXCEPT {
986 CHSVPalette32 p32(rhs);
987 *this = p32;
988 return *this;
989}
990
992class CRGBPalette32 : public detail::TCRGBPalette<32> {
993 public:
994 using Base = detail::TCRGBPalette<32>;
995 using Base::Base;
996 using Base::entries;
997 // operator== / operator!= are hidden friends on Base (#2724); they reach
998 // derived classes automatically via ADL, so no using-declaration needed.
999 using Base::operator=;
1000 using Base::operator[];
1001 using Base::operator CRGB*;
1002
1003 CRGBPalette32() FL_NOEXCEPT = default;
1004 CRGBPalette32(const CRGBPalette32 &rhs) FL_NOEXCEPT = default;
1005 CRGBPalette32 &operator=(const CRGBPalette32 &rhs) FL_NOEXCEPT = default;
1006
1007 CRGBPalette32(const CRGB &c00, const CRGB &c01, const CRGB &c02,
1008 const CRGB &c03, const CRGB &c04, const CRGB &c05,
1009 const CRGB &c06, const CRGB &c07, const CRGB &c08,
1010 const CRGB &c09, const CRGB &c10, const CRGB &c11,
1011 const CRGB &c12, const CRGB &c13, const CRGB &c14,
1012 const CRGB &c15) FL_NOEXCEPT {
1013 CRGBPalette16 p16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
1014 c10, c11, c12, c13, c14, c15);
1015 *this = p16;
1016 }
1017
1018 CRGBPalette32(const CRGBPalette16 &rhs16) FL_NOEXCEPT { UpscalePalette(rhs16, *this); }
1019
1020 CRGBPalette32 &operator=(const CRGBPalette16 &rhs16) FL_NOEXCEPT {
1021 UpscalePalette(rhs16, *this);
1022 return *this;
1023 }
1024
1025 CRGBPalette32(const TProgmemRGBPalette16 &rhs) FL_NOEXCEPT {
1026 CRGBPalette16 p16(rhs);
1027 *this = p16;
1028 }
1029
1030 CRGBPalette32 &operator=(const TProgmemRGBPalette16 &rhs) FL_NOEXCEPT {
1031 CRGBPalette16 p16(rhs);
1032 *this = p16;
1033 return *this;
1034 }
1035
1036 CRGBPalette32(const TProgmemRGBPalette32 &rhs) FL_NOEXCEPT {
1037 detail::loadProgmemPalette(entries, rhs, 32);
1038 }
1039
1040 CRGBPalette32 &operator=(const TProgmemRGBPalette32 &rhs) FL_NOEXCEPT {
1041 detail::loadProgmemPalette(entries, rhs, 32);
1042 return *this;
1043 }
1044
1046 CRGBPalette32(TProgmemRGBGradientPalette_bytes progpal) FL_NOEXCEPT { *this = progpal; }
1048 CRGBPalette32 &operator=(TProgmemRGBGradientPalette_bytes progpal) FL_NOEXCEPT {
1049 TRGBGradientPaletteEntryUnion *progent =
1050 //(TRGBGradientPaletteEntryUnion *)(progpal);
1052 TRGBGradientPaletteEntryUnion u;
1053
1054 // Count entries with safety limit to prevent buffer overrun
1055 fl::u16 count = 0;
1056 bool has_terminator = false;
1057 do {
1058 u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
1059 ++count;
1060 if (u.index == 255) {
1061 has_terminator = true;
1062 break;
1063 }
1065 FL_WARN("DEFINE_GRADIENT_PALETTE missing index=255 terminator! "
1066 "This will cause buffer overruns and crashes. "
1067 "Auto-correcting but please fix your gradient definition.");
1068 break;
1069 }
1070 } while (true);
1071
1072 fl::i8 lastSlotUsed = -1;
1073
1074 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
1075 CRGB rgbstart(u.r, u.g, u.b);
1076
1077 int indexstart = 0;
1078 fl::u8 istart8 = 0;
1079 fl::u8 iend8 = 0;
1080 fl::u16 entries_processed = 0;
1081 while (indexstart < 255) {
1082 // Safety: check BEFORE reading to prevent buffer overrun
1083 if (!has_terminator && entries_processed + 1 >= count) {
1084 // No more validated entries - extend current color to 255
1085 istart8 = indexstart / 8;
1086 iend8 = 255 / 8;
1087 if (count < 16) {
1088 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1089 istart8 = lastSlotUsed + 1;
1090 if (iend8 < istart8) {
1091 iend8 = istart8;
1092 }
1093 }
1094 }
1095 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbstart);
1096 break;
1097 }
1098
1099 ++progent;
1100 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
1101 int indexend = u.index;
1102 CRGB rgbend(u.r, u.g, u.b);
1103
1104
1105 istart8 = indexstart / 8;
1106 iend8 = indexend / 8;
1107 if (count < 16) {
1108 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1109 istart8 = lastSlotUsed + 1;
1110 if (iend8 < istart8) {
1111 iend8 = istart8;
1112 }
1113 }
1114 lastSlotUsed = iend8;
1115 }
1116 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbend);
1117 indexstart = indexend;
1118 rgbstart = rgbend;
1119 ++entries_processed;
1120 }
1121 return *this;
1122 }
1125 CRGBPalette32 &
1126 loadDynamicGradientPalette(TDynamicRGBGradientPalette_bytes gpal) FL_NOEXCEPT {
1127 TRGBGradientPaletteEntryUnion *ent =
1128 // (TRGBGradientPaletteEntryUnion *)(gpal);
1130 TRGBGradientPaletteEntryUnion u;
1131
1132 // Count entries with safety limit to prevent buffer overrun
1133 fl::u16 count = 0;
1134 bool has_terminator = false;
1135 do {
1136 u = *(ent + count);
1137 ++count;
1138 if (u.index == 255) {
1139 has_terminator = true;
1140 break;
1141 }
1143 FL_WARN("Dynamic gradient palette missing index=255 terminator! "
1144 "This will cause buffer overruns and crashes. "
1145 "Auto-correcting but please fix your gradient definition.");
1146 break;
1147 }
1148 } while (true);
1149
1150 fl::i8 lastSlotUsed = -1;
1151
1152 u = *ent;
1153 CRGB rgbstart(u.r, u.g, u.b);
1154
1155 int indexstart = 0;
1156 fl::u8 istart8 = 0;
1157 fl::u8 iend8 = 0;
1158 fl::u16 entries_processed = 0;
1159 while (indexstart < 255) {
1160 // Safety: check BEFORE reading to prevent buffer overrun
1161 if (!has_terminator && entries_processed + 1 >= count) {
1162 // No more validated entries - extend current color to 255
1163 istart8 = indexstart / 8;
1164 iend8 = 255 / 8;
1165 if (count < 16) {
1166 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1167 istart8 = lastSlotUsed + 1;
1168 if (iend8 < istart8) {
1169 iend8 = istart8;
1170 }
1171 }
1172 }
1173 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbstart);
1174 break;
1175 }
1176
1177 ++ent;
1178 u = *ent;
1179 int indexend = u.index;
1180 CRGB rgbend(u.r, u.g, u.b);
1181
1182
1183 istart8 = indexstart / 8;
1184 iend8 = indexend / 8;
1185 if (count < 16) {
1186 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1187 istart8 = lastSlotUsed + 1;
1188 if (iend8 < istart8) {
1189 iend8 = istart8;
1190 }
1191 }
1192 lastSlotUsed = iend8;
1193 }
1194 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbend);
1195 indexstart = indexend;
1196 rgbstart = rgbend;
1197 ++entries_processed;
1198 }
1199 return *this;
1200 }
1201};
1202
1204class CRGBPalette256 : public detail::TCRGBPalette<256> {
1205 public:
1206 using Base = detail::TCRGBPalette<256>;
1207 using Base::Base;
1208 using Base::entries;
1209 // operator== / operator!= are hidden friends on Base (#2724); they reach
1210 // derived classes automatically via ADL, so no using-declaration needed.
1211 using Base::operator=;
1212 using Base::operator[];
1213 using Base::operator CRGB*;
1214
1215 CRGBPalette256() FL_NOEXCEPT = default;
1216 CRGBPalette256(const CRGBPalette256 &rhs) FL_NOEXCEPT = default;
1217 CRGBPalette256 &operator=(const CRGBPalette256 &rhs) FL_NOEXCEPT = default;
1218
1219 CRGBPalette256(const CRGB &c00, const CRGB &c01, const CRGB &c02,
1220 const CRGB &c03, const CRGB &c04, const CRGB &c05,
1221 const CRGB &c06, const CRGB &c07, const CRGB &c08,
1222 const CRGB &c09, const CRGB &c10, const CRGB &c11,
1223 const CRGB &c12, const CRGB &c13, const CRGB &c14,
1224 const CRGB &c15) FL_NOEXCEPT {
1225 CRGBPalette16 p16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
1226 c10, c11, c12, c13, c14, c15);
1227 *this = p16;
1228 }
1229
1230 CRGBPalette256(const CRGBPalette16 &rhs16) FL_NOEXCEPT { UpscalePalette(rhs16, *this); }
1231 CRGBPalette256(const CRGBPalette32 &rhs32) FL_NOEXCEPT { UpscalePalette(rhs32, *this); }
1232
1233 CRGBPalette256 &operator=(const CRGBPalette16 &rhs16) FL_NOEXCEPT {
1234 UpscalePalette(rhs16, *this);
1235 return *this;
1236 }
1237
1238 CRGBPalette256 &operator=(const CRGBPalette32 &rhs32) FL_NOEXCEPT {
1239 UpscalePalette(rhs32, *this);
1240 return *this;
1241 }
1242
1243 CRGBPalette256(const TProgmemRGBPalette16 &rhs) FL_NOEXCEPT {
1244 CRGBPalette16 p16(rhs);
1245 *this = p16;
1246 }
1247
1248 CRGBPalette256 &operator=(const TProgmemRGBPalette16 &rhs) FL_NOEXCEPT {
1249 CRGBPalette16 p16(rhs);
1250 *this = p16;
1251 return *this;
1252 }
1253
1254 CRGBPalette256(const TProgmemRGBPalette32 &rhs) FL_NOEXCEPT {
1255 CRGBPalette32 p32(rhs);
1256 *this = p32;
1257 }
1258
1259 CRGBPalette256 &operator=(const TProgmemRGBPalette32 &rhs) FL_NOEXCEPT {
1260 CRGBPalette32 p32(rhs);
1261 *this = p32;
1262 return *this;
1263 }
1264
1266 CRGBPalette256(TProgmemRGBGradientPalette_bytes progpal) FL_NOEXCEPT {
1267 *this = progpal;
1268 }
1270 CRGBPalette256 &operator=(TProgmemRGBGradientPalette_bytes progpal) FL_NOEXCEPT {
1271 TRGBGradientPaletteEntryUnion *progent =
1272 // (TRGBGradientPaletteEntryUnion *)(progpal);
1274 TRGBGradientPaletteEntryUnion u;
1275 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
1276 CRGB rgbstart(u.r, u.g, u.b);
1277
1278 int indexstart = 0;
1279 fl::u16 entries_processed = 0;
1280 while (indexstart < 255) {
1281 // Safety: check BEFORE reading to prevent buffer overrun
1282 if (entries_processed >= FASTLED_MAX_GRADIENT_PALETTE_ENTRIES) {
1283 FL_WARN("DEFINE_GRADIENT_PALETTE missing index=255 terminator! "
1284 "This will cause buffer overruns and crashes. "
1285 "Auto-correcting but please fix your gradient definition.");
1286 // Extend current color to 255
1287 fill_gradient_RGB(&(entries[0]), indexstart, rgbstart, 255, rgbstart);
1288 break;
1289 }
1290
1291 ++progent;
1292 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
1293 int indexend = u.index;
1294 CRGB rgbend(u.r, u.g, u.b);
1295
1296 fill_gradient_RGB(&(entries[0]), indexstart, rgbstart, indexend,
1297 rgbend);
1298 indexstart = indexend;
1299 rgbstart = rgbend;
1300 ++entries_processed;
1301 }
1302 return *this;
1303 }
1306 CRGBPalette256 &
1307 loadDynamicGradientPalette(TDynamicRGBGradientPalette_bytes gpal) FL_NOEXCEPT {
1308 TRGBGradientPaletteEntryUnion *ent =
1309 //(TRGBGradientPaletteEntryUnion *)(gpal);
1311 TRGBGradientPaletteEntryUnion u;
1312 u = *ent;
1313 CRGB rgbstart(u.r, u.g, u.b);
1314
1315 int indexstart = 0;
1316 fl::u16 entries_processed = 0;
1317 while (indexstart < 255) {
1318 // Safety: check BEFORE reading to prevent buffer overrun
1319 if (entries_processed >= FASTLED_MAX_GRADIENT_PALETTE_ENTRIES) {
1320 FL_WARN("Dynamic gradient palette missing index=255 terminator! "
1321 "This will cause buffer overruns and crashes. "
1322 "Auto-correcting but please fix your gradient definition.");
1323 // Extend current color to 255
1324 fill_gradient_RGB(&(entries[0]), indexstart, rgbstart, 255, rgbstart);
1325 break;
1326 }
1327
1328 ++ent;
1329 u = *ent;
1330 int indexend = u.index;
1331 CRGB rgbend(u.r, u.g, u.b);
1332
1333 fill_gradient_RGB(&(entries[0]), indexstart, rgbstart, indexend,
1334 rgbend);
1335 indexstart = indexend;
1336 rgbstart = rgbend;
1337 ++entries_processed;
1338 }
1339 return *this;
1340 }
1341};
1342
1344
1348
1350typedef enum {
1351 NOBLEND = 0,
1352 BLEND = 1,
1353 LINEARBLEND = 1,
1355 LINEARBLEND_NOWRAP =
1356 2
1357} TBlendType;
1358
1369CRGB ColorFromPalette(const CRGBPalette16 &pal, fl::u8 index,
1370 fl::u8 brightness = 255,
1371 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1372
1379CRGB ColorFromPaletteExtended(const CRGBPalette16 &pal, fl::u16 index,
1380 fl::u8 brightness, TBlendType blendType) FL_NOEXCEPT;
1381
1387CRGB16 ColorFromPaletteHD(const CRGBPalette16 &pal, fl::u16 index,
1389 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1390
1392inline CRGB16 ColorFromPaletteHD(const CRGBPalette16 &pal, fl::u16 index,
1394 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT {
1395 const fl::u16 raw = brightness == 255 ? fl::u16(256) : brightness;
1396 return ColorFromPaletteHD(pal, index, fl::u8x8::from_raw(raw), blendType);
1397}
1398
1404CRGB ColorFromPaletteExtended(const CRGBPalette32 &pal, fl::u16 index,
1405 fl::u8 brightness, TBlendType blendType) FL_NOEXCEPT;
1406
1408CRGB16 ColorFromPaletteHD(const CRGBPalette32 &pal, fl::u16 index,
1410 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1411
1413inline CRGB16 ColorFromPaletteHD(const CRGBPalette32 &pal, fl::u16 index,
1415 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT {
1416 const fl::u16 raw = brightness == 255 ? fl::u16(256) : brightness;
1417 return ColorFromPaletteHD(pal, index, fl::u8x8::from_raw(raw), blendType);
1418}
1419
1421CRGB ColorFromPaletteExtended(const TProgmemRGBPalette16 &pal, fl::u16 index,
1422 fl::u8 brightness = 255,
1423 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1424
1426CRGB16 ColorFromPaletteHD(const TProgmemRGBPalette16 &pal, fl::u16 index,
1428 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1429
1431inline CRGB16 ColorFromPaletteHD(const TProgmemRGBPalette16 &pal, fl::u16 index,
1433 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT {
1434 const fl::u16 raw = brightness == 255 ? fl::u16(256) : brightness;
1435 return ColorFromPaletteHD(pal, index, fl::u8x8::from_raw(raw), blendType);
1436}
1437
1439CRGB ColorFromPaletteExtended(const TProgmemRGBPalette32 &pal, fl::u16 index,
1440 fl::u8 brightness = 255,
1441 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1442
1444CRGB16 ColorFromPaletteHD(const TProgmemRGBPalette32 &pal, fl::u16 index,
1446 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1447
1449inline CRGB16 ColorFromPaletteHD(const TProgmemRGBPalette32 &pal, fl::u16 index,
1451 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT {
1452 const fl::u16 raw = brightness == 255 ? fl::u16(256) : brightness;
1453 return ColorFromPaletteHD(pal, index, fl::u8x8::from_raw(raw), blendType);
1454}
1455
1459 fl::u8 brightness = 255,
1460 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1461
1464CRGB ColorFromPalette(const CRGBPalette256 &pal, fl::u8 index,
1465 fl::u8 brightness = 255, TBlendType blendType = NOBLEND) FL_NOEXCEPT;
1466
1467// @author https://github.com/generalelectrix
1468CRGB ColorFromPaletteExtended(const CRGBPalette256 &pal, fl::u16 index,
1469 fl::u8 brightness = 255,
1470 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1471
1473CRGB16 ColorFromPaletteHD(const CRGBPalette256 &pal, fl::u16 index,
1475 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1476
1478inline CRGB16 ColorFromPaletteHD(const CRGBPalette256 &pal, fl::u16 index,
1480 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT {
1481 const fl::u16 raw = brightness == 255 ? fl::u16(256) : brightness;
1482 return ColorFromPaletteHD(pal, index, fl::u8x8::from_raw(raw), blendType);
1483}
1484
1487CHSV ColorFromPalette(const CHSVPalette16 &pal, fl::u8 index,
1488 fl::u8 brightness = 255,
1489 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1490
1493CHSV ColorFromPalette(const CHSVPalette256 &pal, fl::u8 index,
1494 fl::u8 brightness = 255, TBlendType blendType = NOBLEND) FL_NOEXCEPT;
1495
1498CRGB ColorFromPalette(const CRGBPalette32 &pal, fl::u8 index,
1499 fl::u8 brightness = 255,
1500 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1501
1505 fl::u8 brightness = 255,
1506 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1507
1510CHSV ColorFromPalette(const CHSVPalette32 &pal, fl::u8 index,
1511 fl::u8 brightness = 255,
1512 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT;
1513
1524template <typename PALETTE>
1525void fill_palette(CRGB *L, fl::u16 N, fl::u8 startIndex, fl::u8 incIndex,
1526 const PALETTE &pal, fl::u8 brightness = 255,
1527 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT {
1528 fl::u8 colorIndex = startIndex;
1529 for (fl::u16 i = 0; i < N; ++i) {
1530 L[i] = ColorFromPalette(pal, colorIndex, brightness, blendType);
1531 colorIndex += incIndex;
1532 }
1533}
1534
1536template <typename PALETTE>
1537inline void fill_palette(fl::span<CRGB> L, fl::u8 startIndex, fl::u8 incIndex,
1538 const PALETTE &pal, fl::u8 brightness = 255,
1539 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT {
1540 fill_palette(L.data(), static_cast<fl::u16>(L.size()), startIndex, incIndex,
1541 pal, brightness, blendType);
1542}
1543
1555template <typename PALETTE>
1556void fill_palette_circular(CRGB *L, fl::u16 N, fl::u8 startIndex,
1557 const PALETTE &pal, fl::u8 brightness = 255,
1558 TBlendType blendType = LINEARBLEND,
1559 bool reversed = false) FL_NOEXCEPT {
1560 if (N == 0)
1561 return; // avoiding div/0
1562
1563 const fl::u16 colorChange =
1564 65535 / N; // color change for each LED, * 256 for precision
1565 fl::u16 colorIndex = ((fl::u16)startIndex)
1566 << 8; // offset for color index, with precision (*256)
1567
1568 for (fl::u16 i = 0; i < N; ++i) {
1569 L[i] = ColorFromPalette(pal, (colorIndex >> 8), brightness, blendType);
1570 if (reversed)
1571 colorIndex -= colorChange;
1572 else
1573 colorIndex += colorChange;
1574 }
1575}
1576
1578template <typename PALETTE>
1579inline void fill_palette_circular(fl::span<CRGB> L, fl::u8 startIndex,
1580 const PALETTE &pal, fl::u8 brightness = 255,
1581 TBlendType blendType = LINEARBLEND,
1582 bool reversed = false) FL_NOEXCEPT {
1583 fill_palette_circular(L.data(), static_cast<fl::u16>(L.size()), startIndex,
1584 pal, brightness, blendType, reversed);
1585}
1586
1606template <typename PALETTE>
1607void map_data_into_colors_through_palette(
1608 fl::u8 *dataArray, fl::u16 dataCount, CRGB *targetColorArray,
1609 const PALETTE &pal, fl::u8 brightness = 255, fl::u8 opacity = 255,
1610 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT {
1611 for (fl::u16 i = 0; i < dataCount; ++i) {
1612 fl::u8 d = dataArray[i];
1613 CRGB rgb = ColorFromPalette(pal, d, brightness, blendType);
1614 if (opacity == 255) {
1615 targetColorArray[i] = rgb;
1616 } else {
1617 targetColorArray[i].nscale8(256 - opacity);
1618 rgb.nscale8_video(opacity);
1619 targetColorArray[i] += rgb;
1620 }
1621 }
1622}
1623
1625template <typename PALETTE>
1626inline void map_data_into_colors_through_palette(
1627 fl::span<fl::u8> dataArray, fl::span<CRGB> targetColorArray,
1628 const PALETTE &pal, fl::u8 brightness = 255, fl::u8 opacity = 255,
1629 TBlendType blendType = LINEARBLEND) FL_NOEXCEPT {
1630 map_data_into_colors_through_palette(
1631 dataArray.data(), static_cast<fl::u16>(dataArray.size()),
1632 targetColorArray.data(), pal, brightness, opacity, blendType);
1633}
1634
1673void nblendPaletteTowardPalette(CRGBPalette16 &currentPalette,
1674 CRGBPalette16 &targetPalette,
1675 fl::u8 maxChanges = 24) FL_NOEXCEPT;
1676
1678
1680
1712
1718
1723CRGB applyGamma_video(const CRGB &orig, float gamma) FL_NOEXCEPT;
1724
1731CRGB applyGamma_video(const CRGB &orig, float gammaR, float gammaG,
1732 float gammaB) FL_NOEXCEPT;
1733
1738
1744CRGB &napplyGamma_video(CRGB &rgb, float gammaR, float gammaG, float gammaB) FL_NOEXCEPT;
1745
1751void napplyGamma_video(CRGB *rgbarray, fl::u16 count, float gamma) FL_NOEXCEPT;
1752
1754inline void napplyGamma_video(fl::span<CRGB> rgbarray, float gamma) FL_NOEXCEPT {
1755 napplyGamma_video(rgbarray.data(), static_cast<fl::u16>(rgbarray.size()),
1756 gamma);
1757}
1758
1766void napplyGamma_video(CRGB *rgbarray, fl::u16 count, float gammaR,
1767 float gammaG, float gammaB) FL_NOEXCEPT;
1768
1770inline void napplyGamma_video(fl::span<CRGB> rgbarray, float gammaR,
1771 float gammaG, float gammaB) FL_NOEXCEPT {
1772 napplyGamma_video(rgbarray.data(), static_cast<fl::u16>(rgbarray.size()),
1773 gammaR, gammaG, gammaB);
1774}
1775
1777
1778} // namespace fl
1779
fl::CRGB leds[NUM_LEDS]
fl::UISlider brightness("Brightness", BRIGHTNESS, 0, 255)
int x
Definition simple.h:92
CRGBPalette16 currentPalette
UINumberField palette("Palette", 0, 0, 2)
fl::UISlider scale("Scale", 4,.1, 4,.1)
static constexpr FASTLED_FORCE_INLINE u8x8 from_raw(u16 raw) FL_NOEXCEPT
Definition u8x8.h:53
TGradientDirectionCode
Hue direction for calculating fill gradients.
void UpscalePalette(const class CRGBPalette16 &srcpal16, class CRGBPalette256 &destpal256)
@ SHORTEST_HUES
Hue goes whichever way is shortest.
void fill_gradient(T *targetArray, u16 startpos, CHSV startcolor, u16 endpos, CHSV endcolor, TGradientDirectionCode directionCode=SHORTEST_HUES) FL_NOEXCEPT
Fill a range of LEDs with a smooth HSV gradient between two HSV colors.
Definition fill.h:105
void fill_gradient_RGB(CRGB *leds, u16 startpos, CRGB startcolor, u16 endpos, CRGB endcolor) FL_NOEXCEPT
Fill a range of LEDs with a smooth RGB gradient between two RGB colors.
Definition fill.cpp.hpp:107
void fill_solid(CRGB *targetArray, int numToFill, const CRGB &color) FL_NOEXCEPT
Fill a range of LEDs with a solid color.
Definition fill.cpp.hpp:9
fl::u32 TProgmemHSVPalette32[32]
CHSVPalette32 entries stored in PROGMEM memory.
const TProgmemRGBGradientPalette_byte * TProgmemRGBGradientPalette_bytes
Pointer to bytes of an RGB gradient, stored in PROGMEM memory.
fl::u32 TProgmemRGBPalette32[32]
CRGBPalette32 entries stored in PROGMEM memory.
fl::u32 TProgmemHSVPalette16[16]
CHSVPalette16 entries stored in PROGMEM memory.
fl::u32 TProgmemRGBPalette16[16]
CRGBPalette16 entries stored in PROGMEM memory.
#define FL_PGM_READ_DWORD_NEAR(x)
Read a double word (32-bit) from PROGMEM memory.
Wrapper definitions to allow seamless use of PROGMEM in environments that have it.
#define FASTLED_MAX_GRADIENT_PALETTE_ENTRIES
Defines the 8-bit red, green, and blue (RGB) pixel type in the fl namespace.
void * memmove8(void *dst, const void *src, fl::u16 num)
Faster alternative to memmove() on AVR.
fl::hsv8 CHSV
Definition chsv.h:11
fl::CRGB CRGB
Definition crgb.h:25
#define FL_WARN(X)
Definition log.h:276
Centralized logging categories for FastLED hardware interfaces and subsystems.
u8 fract8
Fixed-Point Fractional Types.
Definition s16x16x4.h:161
unsigned char u8
Definition stdint.h:131
void fadeUsingColor(CRGB *leds, fl::u16 numLeds, const CRGB &colormask)
void UpscalePalette(const class CRGBPalette16 &srcpal16, class CRGBPalette256 &destpal256)
void fadeToBlackBy(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy)
CRGB ColorFromPalette(const CRGBPalette16 &pal, fl::u8 index, fl::u8 brightness, TBlendType blendType)
void nscale8(CRGB *leds, fl::u16 num_leds, fl::u8 scale)
int memcmp(const void *s1, const void *s2, size_t n) FL_NOEXCEPT
void fade_raw(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy)
void fade_video(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy)
CRGB ColorFromPaletteExtended(const CRGBPalette32 &pal, fl::u16 index, fl::u8 brightness, TBlendType blendType)
CRGB16 ColorFromPaletteHD(const CRGBPalette32 &pal, fl::u16 index, fl::u8x8 brightness, TBlendType blendType)
fl::u8 applyGamma_video(fl::u8 brightness, float gamma)
CRGB blend(const CRGB &p1, const CRGB &p2, fract8 amountOfP2)
CRGB & nblend(CRGB &existing, const CRGB &overlay, fract8 amountOfOverlay)
CRGB HeatColor(fl::u8 temperature)
constexpr u32 gamma(float g) FL_NOEXCEPT
Definition gamma_lut.h:36
void fadeLightBy(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy)
signed char i8
Definition stdint.h:130
CRGB & napplyGamma_video(CRGB &rgb, float gamma)
To bit_cast(const From &from) FL_NOEXCEPT
Definition bit_cast.h:48
void nblendPaletteTowardPalette(CRGBPalette16 &current, CRGBPalette16 &target, fl::u8 maxChanges)
void nscale8_video(CRGB *leds, fl::u16 num_leds, fl::u8 scale)
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_DISABLE_WARNING(warning)
#define FL_DISABLE_WARNING_RETURN_TYPE
#define FL_DISABLE_WARNING_IMPLICIT_INT_CONVERSION
#define FL_DISABLE_WARNING_PUSH
#define FL_DISABLE_WARNING_SIGN_CONVERSION
#define FL_DISABLE_WARNING_POP
#define FL_DISABLE_WARNING_UNUSED_PARAMETER
#define FL_DISABLE_WARNING_FLOAT_CONVERSION
#define FL_NOEXCEPT
CRGB & nscale8(u8 scaledown) FL_NOEXCEPT
Scale down a RGB to N/256ths of its current brightness, using "plain math" dimming rules.
Definition crgb.cpp.hpp:88
FASTLED_FORCE_INLINE CRGB & nscale8_video(u8 scaledown) FL_NOEXCEPT
Scale down a RGB to N/256ths of it's current brightness using "video" dimming rules.
Definition crgb.hpp:72