FastLED 3.10.8
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_NO_EXCEPT;
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_NO_EXCEPT;
66
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_NO_EXCEPT;
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_NO_EXCEPT;
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_NO_EXCEPT;
98
100inline void fade_raw(fl::span<CRGB> leds, fl::u8 fadeBy) FL_NO_EXCEPT {
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_NO_EXCEPT;
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_NO_EXCEPT;
129
131inline void fadeUsingColor(fl::span<CRGB> leds, const CRGB &colormask) FL_NO_EXCEPT {
132 fadeUsingColor(leds.data(), static_cast<fl::u16>(leds.size()), colormask);
133}
134
136
140
153CRGB blend(const CRGB &p1, const CRGB &p2, fract8 amountOfP2) FL_NO_EXCEPT;
154
166CRGB blend_oklab(const CRGB &p1, const CRGB &p2,
167 fract8 amountOfP2) FL_NO_EXCEPT;
168
182CHSV blend(const CHSV &p1, const CHSV &p2, fract8 amountOfP2,
184
193CRGB *blend(const CRGB *src1, const CRGB *src2, CRGB *dest, fl::u16 count,
194 fract8 amountOfsrc2) FL_NO_EXCEPT;
195
197inline void blend(fl::span<const CRGB> src1, fl::span<const CRGB> src2,
198 fl::span<CRGB> dest, fract8 amountOfsrc2) FL_NO_EXCEPT {
199 blend(src1.data(), src2.data(), dest.data(),
200 static_cast<fl::u16>(dest.size()), amountOfsrc2);
201}
202
205CHSV *blend(const CHSV *src1, const CHSV *src2, CHSV *dest, fl::u16 count,
206 fract8 amountOfsrc2,
208
214CRGB &nblend(CRGB &existing, const CRGB &overlay, fract8 amountOfOverlay) FL_NO_EXCEPT;
215
218CHSV &nblend(CHSV &existing, const CHSV &overlay, fract8 amountOfOverlay,
220
227void nblend(CRGB *existing, const CRGB *overlay, fl::u16 count,
228 fract8 amountOfOverlay) FL_NO_EXCEPT;
229
231inline void nblend(fl::span<CRGB> existing, fl::span<const CRGB> overlay,
232 fract8 amountOfOverlay) FL_NO_EXCEPT {
233 nblend(existing.data(), overlay.data(),
234 static_cast<fl::u16>(existing.size()), amountOfOverlay);
235}
236
239void nblend(CHSV *existing, const CHSV *overlay, fl::u16 count,
240 fract8 amountOfOverlay,
242
244
247
253CRGB HeatColor(fl::u8 temperature) FL_NO_EXCEPT;
254
257
325
332
333class CRGBPalette16; // IWYU pragma: keep
334class CRGBPalette32; // IWYU pragma: keep
335class CRGBPalette256; // IWYU pragma: keep
336class CHSVPalette16; // IWYU pragma: keep
337class CHSVPalette32; // IWYU pragma: keep
338class CHSVPalette256; // IWYU pragma: keep
339
344typedef union {
345 struct {
346 fl::u8 index;
347 fl::u8 r;
348 fl::u8 g;
349 fl::u8 b;
350 };
351 fl::u32 dword;
352 fl::u8 bytes[4];
353} TRGBGradientPaletteEntryUnion;
354
358#define FASTLED_MAX_GRADIENT_PALETTE_ENTRIES 256
359
360typedef fl::u8
361 TDynamicRGBGradientPalette_byte;
363typedef const TDynamicRGBGradientPalette_byte
364 *TDynamicRGBGradientPalette_bytes;
366typedef TDynamicRGBGradientPalette_bytes
367 TDynamicRGBGradientPaletteRef;
369
371
375
379void UpscalePalette(const class CRGBPalette16 &srcpal16,
380 class CRGBPalette256 &destpal256) FL_NO_EXCEPT;
382void UpscalePalette(const class CHSVPalette16 &srcpal16,
383 class CHSVPalette256 &destpal256) FL_NO_EXCEPT;
384
388void UpscalePalette(const class CRGBPalette16 &srcpal16,
389 class CRGBPalette32 &destpal32) FL_NO_EXCEPT;
391void UpscalePalette(const class CHSVPalette16 &srcpal16,
392 class CHSVPalette32 &destpal32) FL_NO_EXCEPT;
393
397void UpscalePalette(const class CRGBPalette32 &srcpal32,
398 class CRGBPalette256 &destpal256) FL_NO_EXCEPT;
400void UpscalePalette(const class CHSVPalette32 &srcpal32,
401 class CHSVPalette256 &destpal256) FL_NO_EXCEPT;
402
404
407
408namespace detail {
409
410template <typename TColor>
411struct PaletteFillTraits;
412
413template <>
414struct PaletteFillTraits<CHSV> {
415 static void fillSolid(CHSV *entries, fl::u16 size, const CHSV &color) FL_NO_EXCEPT {
416 fill_solid(entries, static_cast<int>(size), color);
417 }
418
419 static void fillGradient(CHSV *entries, fl::u16 size, const CHSV &c1,
420 const CHSV &c2) FL_NO_EXCEPT {
421 fill_gradient(entries, size, c1, c2);
422 }
423
424 static void fillGradient(CHSV *entries, fl::u16 size, const CHSV &c1,
425 const CHSV &c2, const CHSV &c3) FL_NO_EXCEPT {
426 fill_gradient(entries, size, c1, c2, c3);
427 }
428
429 static void fillGradient(CHSV *entries, fl::u16 size, const CHSV &c1,
430 const CHSV &c2, const CHSV &c3,
431 const CHSV &c4) FL_NO_EXCEPT {
432 fill_gradient(entries, size, c1, c2, c3, c4);
433 }
434};
435
436template <>
437struct PaletteFillTraits<CRGB> {
438 static void fillSolid(CRGB *entries, fl::u16 size, const CRGB &color) FL_NO_EXCEPT {
439 fill_solid(entries, static_cast<int>(size), color);
440 }
441
442 static void fillGradient(CRGB *entries, fl::u16 size, const CRGB &c1,
443 const CRGB &c2) FL_NO_EXCEPT {
444 fill_gradient_RGB(entries, size, c1, c2);
445 }
446
447 static void fillGradient(CRGB *entries, fl::u16 size, const CRGB &c1,
448 const CRGB &c2, const CRGB &c3) FL_NO_EXCEPT {
449 fill_gradient_RGB(entries, size, c1, c2, c3);
450 }
451
452 static void fillGradient(CRGB *entries, fl::u16 size, const CRGB &c1,
453 const CRGB &c2, const CRGB &c3,
454 const CRGB &c4) FL_NO_EXCEPT {
455 fill_gradient_RGB(entries, size, c1, c2, c3, c4);
456 }
457};
458
459template <typename TColor, fl::u16 Size>
460class TColorPalette {
461 public:
462 TColor entries[Size];
463
464 TColorPalette() FL_NO_EXCEPT {}
465
466 TColorPalette(const TColorPalette &rhs) FL_NO_EXCEPT { copyBytes(rhs.entries); }
467
468 TColorPalette(const TColor (&rhs)[Size]) FL_NO_EXCEPT { copyBytes(rhs); }
469
470 TColorPalette &operator=(const TColorPalette &rhs) FL_NO_EXCEPT {
471 copyBytes(rhs.entries);
472 return *this;
473 }
474
475 TColorPalette &operator=(const TColor (&rhs)[Size]) FL_NO_EXCEPT {
476 copyBytes(rhs);
477 return *this;
478 }
479
480 TColorPalette(const TColor &c1) FL_NO_EXCEPT {
481 PaletteFillTraits<TColor>::fillSolid(entries, Size, c1);
482 }
483
484 TColorPalette(const TColor &c1, const TColor &c2) FL_NO_EXCEPT {
485 PaletteFillTraits<TColor>::fillGradient(entries, Size, c1, c2);
486 }
487
488 TColorPalette(const TColor &c1, const TColor &c2,
489 const TColor &c3) FL_NO_EXCEPT {
490 PaletteFillTraits<TColor>::fillGradient(entries, Size, c1, c2, c3);
491 }
492
493 TColorPalette(const TColor &c1, const TColor &c2, const TColor &c3,
494 const TColor &c4) FL_NO_EXCEPT {
495 PaletteFillTraits<TColor>::fillGradient(entries, Size, c1, c2, c3, c4);
496 }
497
498 inline TColor &operator[](fl::u8 x) FL_NO_EXCEPT __attribute__((always_inline)) {
499 return entries[x];
500 }
501
502 inline const TColor &operator[](fl::u8 x) const FL_NO_EXCEPT
503 __attribute__((always_inline)) {
504 return entries[x];
505 }
506
507 inline TColor &operator[](int x) FL_NO_EXCEPT __attribute__((always_inline)) {
508 return entries[(fl::u8)x];
509 }
510
511 inline const TColor &operator[](int x) const FL_NO_EXCEPT
512 __attribute__((always_inline)) {
513 return entries[(fl::u8)x];
514 }
515
516 operator TColor *() FL_NO_EXCEPT { return &(entries[0]); }
517
518 // Hidden friends — C++20 deprecates synthesizing a reversed candidate
519 // for member operator==, producing -Wambiguous-reversed-operator at every
520 // call site. Defining the comparison as a non-member friend declared
521 // inside the class body solves that cleanly (found only via ADL on the
522 // palette type, no reverse-candidate synthesis applies). Derived classes
523 // get these for free through ADL on the base, so the prior
524 // `using Base::operator==/!=` injections are no longer needed. #2724
525 friend bool operator==(const TColorPalette &lhs,
526 const TColorPalette &rhs) FL_NO_EXCEPT {
527 const TColor *lhs_entries = &(lhs.entries[0]);
528 const TColor *rhs_entries = &(rhs.entries[0]);
529 if (lhs_entries == rhs_entries) {
530 return true;
531 }
532 return fl::memcmp(lhs_entries, rhs_entries, sizeof(lhs.entries)) == 0;
533 }
534
535 friend bool operator!=(const TColorPalette &lhs,
536 const TColorPalette &rhs) FL_NO_EXCEPT {
537 return !(lhs == rhs);
538 }
539
540 protected:
541 void copyBytes(const TColor *rhs) FL_NO_EXCEPT {
542 memmove8((void *)&(entries[0]), rhs, sizeof(entries));
543 }
544
545 template <typename TOtherColor>
546 void copyConverted(const TOtherColor *rhs) FL_NO_EXCEPT {
547 for (fl::u16 i = 0; i < Size; ++i) {
548 entries[i] = rhs[i];
549 }
550 }
551};
552
553template <fl::u16 Size>
554class TCRGBPalette : public TColorPalette<CRGB, Size> {
555 public:
556 using Base = TColorPalette<CRGB, Size>;
557 using Base::Base;
558 using Base::entries;
559 // operator== / operator!= are hidden friends on Base (#2724); they reach
560 // derived classes automatically via ADL, so no using-declaration needed.
561 using Base::operator=;
562 using Base::operator[];
563 using Base::operator CRGB*;
564
565 TCRGBPalette() FL_NO_EXCEPT {}
566
567 // Explicit Rule of 5 — the user-defined ctors below otherwise force the
568 // copy-assign / destructor to be implicitly-declared, which C++11+
569 // deprecates (-Wdeprecated-copy, ~472 hits across teensy30/31/40/41/LC).
570 // Mirrors what CRGBPalette16 already does at lines 699-701. #2725
571 TCRGBPalette(const TCRGBPalette &) FL_NO_EXCEPT = default;
572 TCRGBPalette &operator=(const TCRGBPalette &) FL_NO_EXCEPT = default;
573 ~TCRGBPalette() FL_NO_EXCEPT = default;
574
575 TCRGBPalette(const TColorPalette<CHSV, Size> &rhs) FL_NO_EXCEPT {
576 Base::copyConverted(rhs.entries);
577 }
578
579 TCRGBPalette(const CHSV (&rhs)[Size]) FL_NO_EXCEPT {
580 Base::copyConverted(rhs);
581 }
582
583 TCRGBPalette &operator=(const TColorPalette<CHSV, Size> &rhs) FL_NO_EXCEPT {
584 Base::copyConverted(rhs.entries);
585 return *this;
586 }
587
588 TCRGBPalette &operator=(const CHSV (&rhs)[Size]) FL_NO_EXCEPT {
589 Base::copyConverted(rhs);
590 return *this;
591 }
592
593 TCRGBPalette(const CHSV &c1) FL_NO_EXCEPT {
594 fill_solid(&(entries[0]), static_cast<int>(Size), c1);
595 }
596
597 TCRGBPalette(const CHSV &c1, const CHSV &c2) FL_NO_EXCEPT {
598 fill_gradient(&(entries[0]), Size, c1, c2);
599 }
600
601 TCRGBPalette(const CHSV &c1, const CHSV &c2,
602 const CHSV &c3) FL_NO_EXCEPT {
603 fill_gradient(&(entries[0]), Size, c1, c2, c3);
604 }
605
606 TCRGBPalette(const CHSV &c1, const CHSV &c2, const CHSV &c3,
607 const CHSV &c4) FL_NO_EXCEPT {
608 fill_gradient(&(entries[0]), Size, c1, c2, c3, c4);
609 }
610};
611
612inline void loadProgmemPalette(CRGB *entries, const fl::u32 *rhs,
613 fl::u16 count) FL_NO_EXCEPT {
614 for (fl::u16 i = 0; i < count; ++i) {
615 entries[i] = FL_PGM_READ_DWORD_NEAR(rhs + i);
616 }
617}
618
619inline void loadProgmemPalette(CHSV *entries, const fl::u32 *rhs,
620 fl::u16 count) FL_NO_EXCEPT {
621 for (fl::u16 i = 0; i < count; ++i) {
622 CRGB xyz(FL_PGM_READ_DWORD_NEAR(rhs + i));
623 entries[i].hue = xyz.red;
624 entries[i].sat = xyz.green;
625 entries[i].val = xyz.blue;
626 }
627}
628
629template <typename TPalette16, typename TColor>
630void initPalette16(TPalette16 &palette, const TColor &c00, const TColor &c01,
631 const TColor &c02, const TColor &c03, const TColor &c04,
632 const TColor &c05, const TColor &c06, const TColor &c07,
633 const TColor &c08, const TColor &c09, const TColor &c10,
634 const TColor &c11, const TColor &c12, const TColor &c13,
635 const TColor &c14, const TColor &c15) FL_NO_EXCEPT {
636 const TColor colors[16] = {c00, c01, c02, c03, c04, c05, c06, c07,
637 c08, c09, c10, c11, c12, c13, c14, c15};
638 palette = colors;
639}
640
641} // namespace detail
642
644class CHSVPalette16 : public detail::TColorPalette<CHSV, 16> {
645 public:
646 using Base = detail::TColorPalette<CHSV, 16>;
647 using Base::Base;
648 using Base::entries;
649 // operator== / operator!= are hidden friends on Base (#2724); they reach
650 // derived classes automatically via ADL, so no using-declaration needed.
651 using Base::operator=;
652 using Base::operator[];
653 using Base::operator CHSV*;
654
655 CHSVPalette16() FL_NO_EXCEPT = default;
656 CHSVPalette16(const CHSVPalette16 &rhs) FL_NO_EXCEPT = default;
657 CHSVPalette16 &operator=(const CHSVPalette16 &rhs) FL_NO_EXCEPT = default;
658
659 CHSVPalette16(const CHSV &c00, const CHSV &c01, const CHSV &c02,
660 const CHSV &c03, const CHSV &c04, const CHSV &c05,
661 const CHSV &c06, const CHSV &c07, const CHSV &c08,
662 const CHSV &c09, const CHSV &c10, const CHSV &c11,
663 const CHSV &c12, const CHSV &c13, const CHSV &c14,
664 const CHSV &c15) FL_NO_EXCEPT {
665 detail::initPalette16(*this, c00, c01, c02, c03, c04, c05, c06, c07,
666 c08, c09, c10, c11, c12, c13, c14, c15);
667 }
668
669 CHSVPalette16(const TProgmemHSVPalette16 &rhs) FL_NO_EXCEPT {
670 detail::loadProgmemPalette(entries, rhs, 16);
671 }
672
673 CHSVPalette16 &operator=(const TProgmemHSVPalette16 &rhs) FL_NO_EXCEPT {
674 detail::loadProgmemPalette(entries, rhs, 16);
675 return *this;
676 }
677};
678
680class CHSVPalette256 : public detail::TColorPalette<CHSV, 256> {
681 public:
682 using Base = detail::TColorPalette<CHSV, 256>;
683 using Base::Base;
684 using Base::entries;
685 // operator== / operator!= are hidden friends on Base (#2724); they reach
686 // derived classes automatically via ADL, so no using-declaration needed.
687 using Base::operator=;
688 using Base::operator[];
689 using Base::operator CHSV*;
690
691 CHSVPalette256() FL_NO_EXCEPT = default;
692 CHSVPalette256(const CHSVPalette256 &rhs) FL_NO_EXCEPT = default;
693 CHSVPalette256 &operator=(const CHSVPalette256 &rhs) FL_NO_EXCEPT = default;
694
695 CHSVPalette256(const CHSV &c00, const CHSV &c01, const CHSV &c02,
696 const CHSV &c03, const CHSV &c04, const CHSV &c05,
697 const CHSV &c06, const CHSV &c07, const CHSV &c08,
698 const CHSV &c09, const CHSV &c10, const CHSV &c11,
699 const CHSV &c12, const CHSV &c13, const CHSV &c14,
700 const CHSV &c15) FL_NO_EXCEPT {
701 CHSVPalette16 p16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
702 c10, c11, c12, c13, c14, c15);
703 *this = p16;
704 }
705
706 CHSVPalette256(const CHSVPalette16 &rhs16) FL_NO_EXCEPT { UpscalePalette(rhs16, *this); }
707
708 CHSVPalette256(const CHSVPalette32 &rhs32) FL_NO_EXCEPT { UpscalePalette(rhs32, *this); }
709
710 CHSVPalette256 &operator=(const CHSVPalette16 &rhs16) FL_NO_EXCEPT {
711 UpscalePalette(rhs16, *this);
712 return *this;
713 }
714
715 CHSVPalette256 &operator=(const CHSVPalette32 &rhs32) FL_NO_EXCEPT {
716 UpscalePalette(rhs32, *this);
717 return *this;
718 }
719
720 CHSVPalette256(const TProgmemHSVPalette16 &rhs) FL_NO_EXCEPT {
721 CHSVPalette16 p16(rhs);
722 *this = p16;
723 }
724
725 CHSVPalette256 &operator=(const TProgmemHSVPalette16 &rhs) FL_NO_EXCEPT {
726 CHSVPalette16 p16(rhs);
727 *this = p16;
728 return *this;
729 }
730
731 CHSVPalette256(const TProgmemHSVPalette32 &rhs) FL_NO_EXCEPT;
732
733 CHSVPalette256 &operator=(const TProgmemHSVPalette32 &rhs) FL_NO_EXCEPT;
734};
735
737class CRGBPalette16 : public detail::TCRGBPalette<16> {
738 public:
739 using Base = detail::TCRGBPalette<16>;
740 using Base::Base;
741 using Base::entries;
742 // operator== / operator!= are hidden friends on Base (#2724); they reach
743 // derived classes automatically via ADL, so no using-declaration needed.
744 using Base::operator=;
745 using Base::operator[];
746 using Base::operator CRGB*;
747
748 CRGBPalette16() FL_NO_EXCEPT = default;
749 CRGBPalette16(const CRGBPalette16 &rhs) FL_NO_EXCEPT = default;
750 CRGBPalette16 &operator=(const CRGBPalette16 &rhs) FL_NO_EXCEPT = default;
751
752 CRGBPalette16(const CRGB &c00, const CRGB &c01, const CRGB &c02,
753 const CRGB &c03, const CRGB &c04, const CRGB &c05,
754 const CRGB &c06, const CRGB &c07, const CRGB &c08,
755 const CRGB &c09, const CRGB &c10, const CRGB &c11,
756 const CRGB &c12, const CRGB &c13, const CRGB &c14,
757 const CRGB &c15) FL_NO_EXCEPT {
758 detail::initPalette16(*this, c00, c01, c02, c03, c04, c05, c06, c07,
759 c08, c09, c10, c11, c12, c13, c14, c15);
760 }
761
762 CRGBPalette16(const TProgmemRGBPalette16 &rhs) FL_NO_EXCEPT {
763 detail::loadProgmemPalette(entries, rhs, 16);
764 }
765
766 CRGBPalette16 &operator=(const TProgmemRGBPalette16 &rhs) FL_NO_EXCEPT {
767 detail::loadProgmemPalette(entries, rhs, 16);
768 return *this;
769 }
770
800 CRGBPalette16(TProgmemRGBGradientPalette_bytes progpal) FL_NO_EXCEPT { *this = progpal; }
802 CRGBPalette16 &operator=(TProgmemRGBGradientPalette_bytes progpal) FL_NO_EXCEPT {
803 TRGBGradientPaletteEntryUnion *progent =
804 // (TRGBGradientPaletteEntryUnion *)(progpal);
806 TRGBGradientPaletteEntryUnion u;
807
808 // Count entries with safety limit to prevent buffer overrun
809 fl::u16 count = 0;
810 bool has_terminator = false;
811 do {
812 u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
813 ++count;
814 if (u.index == 255) {
815 has_terminator = true;
816 break;
817 }
819 FL_WARN("DEFINE_GRADIENT_PALETTE missing index=255 terminator! "
820 "This will cause buffer overruns and crashes. "
821 "Auto-correcting but please fix your gradient definition.");
822 break;
823 }
824 } while (true);
825
826 fl::i8 lastSlotUsed = -1;
827
828 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
829 CRGB rgbstart(u.r, u.g, u.b);
830
831 int indexstart = 0;
832 fl::u8 istart8 = 0;
833 fl::u8 iend8 = 0;
834 fl::u16 entries_processed = 0;
835 while (indexstart < 255) {
836 // Safety: check BEFORE reading to prevent buffer overrun
837 if (!has_terminator && entries_processed + 1 >= count) {
838 // No more validated entries - extend current color to 255
839 istart8 = indexstart / 16;
840 iend8 = 255 / 16;
841 if (count < 16) {
842 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
843 istart8 = lastSlotUsed + 1;
844 if (iend8 < istart8) {
845 iend8 = istart8;
846 }
847 }
848 }
849 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbstart);
850 break;
851 }
852
853 ++progent;
854 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
855 int indexend = u.index;
856 CRGB rgbend(u.r, u.g, u.b);
857
858 istart8 = indexstart / 16;
859 iend8 = indexend / 16;
860 if (count < 16) {
861 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
862 istart8 = lastSlotUsed + 1;
863 if (iend8 < istart8) {
864 iend8 = istart8;
865 }
866 }
867 lastSlotUsed = iend8;
868 }
869 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbend);
870 indexstart = indexend;
871 rgbstart = rgbend;
872 ++entries_processed;
873 }
874 return *this;
875 }
879 CRGBPalette16 &
880 loadDynamicGradientPalette(TDynamicRGBGradientPalette_bytes gpal) FL_NO_EXCEPT {
881 TRGBGradientPaletteEntryUnion *ent =
882 // (TRGBGradientPaletteEntryUnion *)(gpal);
884 TRGBGradientPaletteEntryUnion u;
885
886 // Count entries with safety limit to prevent buffer overrun
887 fl::u16 count = 0;
888 bool has_terminator = false;
889 do {
890 u = *(ent + count);
891 ++count;
892 if (u.index == 255) {
893 has_terminator = true;
894 break;
895 }
897 FL_WARN("Dynamic gradient palette missing index=255 terminator! "
898 "This will cause buffer overruns and crashes. "
899 "Auto-correcting but please fix your gradient definition.");
900 break;
901 }
902 } while (true);
903
904 fl::i8 lastSlotUsed = -1;
905
906 u = *ent;
907 CRGB rgbstart(u.r, u.g, u.b);
908
909 int indexstart = 0;
910 fl::u8 istart8 = 0;
911 fl::u8 iend8 = 0;
912 fl::u16 entries_processed = 0;
913 while (indexstart < 255) {
914 // Safety: check BEFORE reading to prevent buffer overrun
915 if (!has_terminator && entries_processed + 1 >= count) {
916 // No more validated entries - extend current color to 255
917 istart8 = indexstart / 16;
918 iend8 = 255 / 16;
919 if (count < 16) {
920 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
921 istart8 = lastSlotUsed + 1;
922 if (iend8 < istart8) {
923 iend8 = istart8;
924 }
925 }
926 }
927 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbstart);
928 break;
929 }
930
931 ++ent;
932 u = *ent;
933 int indexend = u.index;
934 CRGB rgbend(u.r, u.g, u.b);
935
936 istart8 = indexstart / 16;
937 iend8 = indexend / 16;
938 if (count < 16) {
939 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
940 istart8 = lastSlotUsed + 1;
941 if (iend8 < istart8) {
942 iend8 = istart8;
943 }
944 }
945 lastSlotUsed = iend8;
946 }
947 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbend);
948 indexstart = indexend;
949 rgbstart = rgbend;
950 ++entries_processed;
951 }
952 return *this;
953 }
954};
955
957class CHSVPalette32 : public detail::TColorPalette<CHSV, 32> {
958 public:
959 using Base = detail::TColorPalette<CHSV, 32>;
960 using Base::Base;
961 using Base::entries;
962 // operator== / operator!= are hidden friends on Base (#2724); they reach
963 // derived classes automatically via ADL, so no using-declaration needed.
964 using Base::operator=;
965 using Base::operator[];
966 using Base::operator CHSV*;
967
968 CHSVPalette32() FL_NO_EXCEPT = default;
969 CHSVPalette32(const CHSVPalette32 &rhs) FL_NO_EXCEPT = default;
970 CHSVPalette32 &operator=(const CHSVPalette32 &rhs) FL_NO_EXCEPT = default;
971
972 CHSVPalette32(const CHSV &c00, const CHSV &c01, const CHSV &c02,
973 const CHSV &c03, const CHSV &c04, const CHSV &c05,
974 const CHSV &c06, const CHSV &c07, const CHSV &c08,
975 const CHSV &c09, const CHSV &c10, const CHSV &c11,
976 const CHSV &c12, const CHSV &c13, const CHSV &c14,
977 const CHSV &c15) FL_NO_EXCEPT {
978 CHSVPalette16 p16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
979 c10, c11, c12, c13, c14, c15);
980 *this = p16;
981 }
982
983 CHSVPalette32(const CHSVPalette16 &rhs16) FL_NO_EXCEPT { UpscalePalette(rhs16, *this); }
984
985 CHSVPalette32 &operator=(const CHSVPalette16 &rhs16) FL_NO_EXCEPT {
986 UpscalePalette(rhs16, *this);
987 return *this;
988 }
989
990 CHSVPalette32(const TProgmemHSVPalette16 &rhs) FL_NO_EXCEPT {
991 CHSVPalette16 p16(rhs);
992 *this = p16;
993 }
994
995 CHSVPalette32 &operator=(const TProgmemHSVPalette16 &rhs) FL_NO_EXCEPT {
996 CHSVPalette16 p16(rhs);
997 *this = p16;
998 return *this;
999 }
1000
1001 CHSVPalette32(const TProgmemHSVPalette32 &rhs) FL_NO_EXCEPT {
1002 detail::loadProgmemPalette(entries, rhs, 32);
1003 }
1004
1005 CHSVPalette32 &operator=(const TProgmemHSVPalette32 &rhs) FL_NO_EXCEPT {
1006 detail::loadProgmemPalette(entries, rhs, 32);
1007 return *this;
1008 }
1009};
1010
1011inline CHSVPalette256::CHSVPalette256(const TProgmemHSVPalette32 &rhs) FL_NO_EXCEPT {
1012 CHSVPalette32 p32(rhs);
1013 *this = p32;
1014}
1015
1016inline CHSVPalette256 &
1017CHSVPalette256::operator=(const TProgmemHSVPalette32 &rhs) FL_NO_EXCEPT {
1018 CHSVPalette32 p32(rhs);
1019 *this = p32;
1020 return *this;
1021}
1022
1024class CRGBPalette32 : public detail::TCRGBPalette<32> {
1025 public:
1026 using Base = detail::TCRGBPalette<32>;
1027 using Base::Base;
1028 using Base::entries;
1029 // operator== / operator!= are hidden friends on Base (#2724); they reach
1030 // derived classes automatically via ADL, so no using-declaration needed.
1031 using Base::operator=;
1032 using Base::operator[];
1033 using Base::operator CRGB*;
1034
1035 CRGBPalette32() FL_NO_EXCEPT = default;
1036 CRGBPalette32(const CRGBPalette32 &rhs) FL_NO_EXCEPT = default;
1037 CRGBPalette32 &operator=(const CRGBPalette32 &rhs) FL_NO_EXCEPT = default;
1038
1039 CRGBPalette32(const CRGB &c00, const CRGB &c01, const CRGB &c02,
1040 const CRGB &c03, const CRGB &c04, const CRGB &c05,
1041 const CRGB &c06, const CRGB &c07, const CRGB &c08,
1042 const CRGB &c09, const CRGB &c10, const CRGB &c11,
1043 const CRGB &c12, const CRGB &c13, const CRGB &c14,
1044 const CRGB &c15) FL_NO_EXCEPT {
1045 CRGBPalette16 p16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
1046 c10, c11, c12, c13, c14, c15);
1047 *this = p16;
1048 }
1049
1050 CRGBPalette32(const CRGBPalette16 &rhs16) FL_NO_EXCEPT { UpscalePalette(rhs16, *this); }
1051
1052 CRGBPalette32 &operator=(const CRGBPalette16 &rhs16) FL_NO_EXCEPT {
1053 UpscalePalette(rhs16, *this);
1054 return *this;
1055 }
1056
1057 CRGBPalette32(const TProgmemRGBPalette16 &rhs) FL_NO_EXCEPT {
1058 CRGBPalette16 p16(rhs);
1059 *this = p16;
1060 }
1061
1062 CRGBPalette32 &operator=(const TProgmemRGBPalette16 &rhs) FL_NO_EXCEPT {
1063 CRGBPalette16 p16(rhs);
1064 *this = p16;
1065 return *this;
1066 }
1067
1068 CRGBPalette32(const TProgmemRGBPalette32 &rhs) FL_NO_EXCEPT {
1069 detail::loadProgmemPalette(entries, rhs, 32);
1070 }
1071
1072 CRGBPalette32 &operator=(const TProgmemRGBPalette32 &rhs) FL_NO_EXCEPT {
1073 detail::loadProgmemPalette(entries, rhs, 32);
1074 return *this;
1075 }
1076
1078 CRGBPalette32(TProgmemRGBGradientPalette_bytes progpal) FL_NO_EXCEPT { *this = progpal; }
1080 CRGBPalette32 &operator=(TProgmemRGBGradientPalette_bytes progpal) FL_NO_EXCEPT {
1081 TRGBGradientPaletteEntryUnion *progent =
1082 //(TRGBGradientPaletteEntryUnion *)(progpal);
1084 TRGBGradientPaletteEntryUnion u;
1085
1086 // Count entries with safety limit to prevent buffer overrun
1087 fl::u16 count = 0;
1088 bool has_terminator = false;
1089 do {
1090 u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
1091 ++count;
1092 if (u.index == 255) {
1093 has_terminator = true;
1094 break;
1095 }
1097 FL_WARN("DEFINE_GRADIENT_PALETTE missing index=255 terminator! "
1098 "This will cause buffer overruns and crashes. "
1099 "Auto-correcting but please fix your gradient definition.");
1100 break;
1101 }
1102 } while (true);
1103
1104 fl::i8 lastSlotUsed = -1;
1105
1106 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
1107 CRGB rgbstart(u.r, u.g, u.b);
1108
1109 int indexstart = 0;
1110 fl::u8 istart8 = 0;
1111 fl::u8 iend8 = 0;
1112 fl::u16 entries_processed = 0;
1113 while (indexstart < 255) {
1114 // Safety: check BEFORE reading to prevent buffer overrun
1115 if (!has_terminator && entries_processed + 1 >= count) {
1116 // No more validated entries - extend current color to 255
1117 istart8 = indexstart / 8;
1118 iend8 = 255 / 8;
1119 if (count < 16) {
1120 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1121 istart8 = lastSlotUsed + 1;
1122 if (iend8 < istart8) {
1123 iend8 = istart8;
1124 }
1125 }
1126 }
1127 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbstart);
1128 break;
1129 }
1130
1131 ++progent;
1132 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
1133 int indexend = u.index;
1134 CRGB rgbend(u.r, u.g, u.b);
1135
1136
1137 istart8 = indexstart / 8;
1138 iend8 = indexend / 8;
1139 if (count < 16) {
1140 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1141 istart8 = lastSlotUsed + 1;
1142 if (iend8 < istart8) {
1143 iend8 = istart8;
1144 }
1145 }
1146 lastSlotUsed = iend8;
1147 }
1148 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbend);
1149 indexstart = indexend;
1150 rgbstart = rgbend;
1151 ++entries_processed;
1152 }
1153 return *this;
1154 }
1157 CRGBPalette32 &
1158 loadDynamicGradientPalette(TDynamicRGBGradientPalette_bytes gpal) FL_NO_EXCEPT {
1159 TRGBGradientPaletteEntryUnion *ent =
1160 // (TRGBGradientPaletteEntryUnion *)(gpal);
1162 TRGBGradientPaletteEntryUnion u;
1163
1164 // Count entries with safety limit to prevent buffer overrun
1165 fl::u16 count = 0;
1166 bool has_terminator = false;
1167 do {
1168 u = *(ent + count);
1169 ++count;
1170 if (u.index == 255) {
1171 has_terminator = true;
1172 break;
1173 }
1175 FL_WARN("Dynamic gradient palette missing index=255 terminator! "
1176 "This will cause buffer overruns and crashes. "
1177 "Auto-correcting but please fix your gradient definition.");
1178 break;
1179 }
1180 } while (true);
1181
1182 fl::i8 lastSlotUsed = -1;
1183
1184 u = *ent;
1185 CRGB rgbstart(u.r, u.g, u.b);
1186
1187 int indexstart = 0;
1188 fl::u8 istart8 = 0;
1189 fl::u8 iend8 = 0;
1190 fl::u16 entries_processed = 0;
1191 while (indexstart < 255) {
1192 // Safety: check BEFORE reading to prevent buffer overrun
1193 if (!has_terminator && entries_processed + 1 >= count) {
1194 // No more validated entries - extend current color to 255
1195 istart8 = indexstart / 8;
1196 iend8 = 255 / 8;
1197 if (count < 16) {
1198 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1199 istart8 = lastSlotUsed + 1;
1200 if (iend8 < istart8) {
1201 iend8 = istart8;
1202 }
1203 }
1204 }
1205 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbstart);
1206 break;
1207 }
1208
1209 ++ent;
1210 u = *ent;
1211 int indexend = u.index;
1212 CRGB rgbend(u.r, u.g, u.b);
1213
1214
1215 istart8 = indexstart / 8;
1216 iend8 = indexend / 8;
1217 if (count < 16) {
1218 if ((istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1219 istart8 = lastSlotUsed + 1;
1220 if (iend8 < istart8) {
1221 iend8 = istart8;
1222 }
1223 }
1224 lastSlotUsed = iend8;
1225 }
1226 fill_gradient_RGB(&(entries[0]), istart8, rgbstart, iend8, rgbend);
1227 indexstart = indexend;
1228 rgbstart = rgbend;
1229 ++entries_processed;
1230 }
1231 return *this;
1232 }
1233};
1234
1236class CRGBPalette256 : public detail::TCRGBPalette<256> {
1237 public:
1238 using Base = detail::TCRGBPalette<256>;
1239 using Base::Base;
1240 using Base::entries;
1241 // operator== / operator!= are hidden friends on Base (#2724); they reach
1242 // derived classes automatically via ADL, so no using-declaration needed.
1243 using Base::operator=;
1244 using Base::operator[];
1245 using Base::operator CRGB*;
1246
1247 CRGBPalette256() FL_NO_EXCEPT = default;
1248 CRGBPalette256(const CRGBPalette256 &rhs) FL_NO_EXCEPT = default;
1249 CRGBPalette256 &operator=(const CRGBPalette256 &rhs) FL_NO_EXCEPT = default;
1250
1251 CRGBPalette256(const CRGB &c00, const CRGB &c01, const CRGB &c02,
1252 const CRGB &c03, const CRGB &c04, const CRGB &c05,
1253 const CRGB &c06, const CRGB &c07, const CRGB &c08,
1254 const CRGB &c09, const CRGB &c10, const CRGB &c11,
1255 const CRGB &c12, const CRGB &c13, const CRGB &c14,
1256 const CRGB &c15) FL_NO_EXCEPT {
1257 CRGBPalette16 p16(c00, c01, c02, c03, c04, c05, c06, c07, c08, c09,
1258 c10, c11, c12, c13, c14, c15);
1259 *this = p16;
1260 }
1261
1262 CRGBPalette256(const CRGBPalette16 &rhs16) FL_NO_EXCEPT { UpscalePalette(rhs16, *this); }
1263 CRGBPalette256(const CRGBPalette32 &rhs32) FL_NO_EXCEPT { UpscalePalette(rhs32, *this); }
1264
1265 CRGBPalette256 &operator=(const CRGBPalette16 &rhs16) FL_NO_EXCEPT {
1266 UpscalePalette(rhs16, *this);
1267 return *this;
1268 }
1269
1270 CRGBPalette256 &operator=(const CRGBPalette32 &rhs32) FL_NO_EXCEPT {
1271 UpscalePalette(rhs32, *this);
1272 return *this;
1273 }
1274
1275 CRGBPalette256(const TProgmemRGBPalette16 &rhs) FL_NO_EXCEPT {
1276 CRGBPalette16 p16(rhs);
1277 *this = p16;
1278 }
1279
1280 CRGBPalette256 &operator=(const TProgmemRGBPalette16 &rhs) FL_NO_EXCEPT {
1281 CRGBPalette16 p16(rhs);
1282 *this = p16;
1283 return *this;
1284 }
1285
1286 CRGBPalette256(const TProgmemRGBPalette32 &rhs) FL_NO_EXCEPT {
1287 CRGBPalette32 p32(rhs);
1288 *this = p32;
1289 }
1290
1291 CRGBPalette256 &operator=(const TProgmemRGBPalette32 &rhs) FL_NO_EXCEPT {
1292 CRGBPalette32 p32(rhs);
1293 *this = p32;
1294 return *this;
1295 }
1296
1298 CRGBPalette256(TProgmemRGBGradientPalette_bytes progpal) FL_NO_EXCEPT {
1299 *this = progpal;
1300 }
1302 CRGBPalette256 &operator=(TProgmemRGBGradientPalette_bytes progpal) FL_NO_EXCEPT {
1303 TRGBGradientPaletteEntryUnion *progent =
1304 // (TRGBGradientPaletteEntryUnion *)(progpal);
1306 TRGBGradientPaletteEntryUnion u;
1307 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
1308 CRGB rgbstart(u.r, u.g, u.b);
1309
1310 int indexstart = 0;
1311 fl::u16 entries_processed = 0;
1312 while (indexstart < 255) {
1313 // Safety: check BEFORE reading to prevent buffer overrun
1314 if (entries_processed >= FASTLED_MAX_GRADIENT_PALETTE_ENTRIES) {
1315 FL_WARN("DEFINE_GRADIENT_PALETTE missing index=255 terminator! "
1316 "This will cause buffer overruns and crashes. "
1317 "Auto-correcting but please fix your gradient definition.");
1318 // Extend current color to 255
1319 fill_gradient_RGB(&(entries[0]), indexstart, rgbstart, 255, rgbstart);
1320 break;
1321 }
1322
1323 ++progent;
1324 u.dword = FL_PGM_READ_DWORD_NEAR(progent);
1325 int indexend = u.index;
1326 CRGB rgbend(u.r, u.g, u.b);
1327
1328 fill_gradient_RGB(&(entries[0]), indexstart, rgbstart, indexend,
1329 rgbend);
1330 indexstart = indexend;
1331 rgbstart = rgbend;
1332 ++entries_processed;
1333 }
1334 return *this;
1335 }
1338 CRGBPalette256 &
1339 loadDynamicGradientPalette(TDynamicRGBGradientPalette_bytes gpal) FL_NO_EXCEPT {
1340 TRGBGradientPaletteEntryUnion *ent =
1341 //(TRGBGradientPaletteEntryUnion *)(gpal);
1343 TRGBGradientPaletteEntryUnion u;
1344 u = *ent;
1345 CRGB rgbstart(u.r, u.g, u.b);
1346
1347 int indexstart = 0;
1348 fl::u16 entries_processed = 0;
1349 while (indexstart < 255) {
1350 // Safety: check BEFORE reading to prevent buffer overrun
1351 if (entries_processed >= FASTLED_MAX_GRADIENT_PALETTE_ENTRIES) {
1352 FL_WARN("Dynamic gradient palette missing index=255 terminator! "
1353 "This will cause buffer overruns and crashes. "
1354 "Auto-correcting but please fix your gradient definition.");
1355 // Extend current color to 255
1356 fill_gradient_RGB(&(entries[0]), indexstart, rgbstart, 255, rgbstart);
1357 break;
1358 }
1359
1360 ++ent;
1361 u = *ent;
1362 int indexend = u.index;
1363 CRGB rgbend(u.r, u.g, u.b);
1364
1365 fill_gradient_RGB(&(entries[0]), indexstart, rgbstart, indexend,
1366 rgbend);
1367 indexstart = indexend;
1368 rgbstart = rgbend;
1369 ++entries_processed;
1370 }
1371 return *this;
1372 }
1373};
1374
1376
1380
1382typedef enum {
1383 NOBLEND = 0,
1384 BLEND = 1,
1385 LINEARBLEND = 1,
1387 LINEARBLEND_NOWRAP =
1388 2
1389} TBlendType;
1390
1401CRGB ColorFromPalette(const CRGBPalette16 &pal, fl::u8 index,
1402 fl::u8 brightness = 255,
1403 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1404
1411CRGB ColorFromPaletteExtended(const CRGBPalette16 &pal, fl::u16 index,
1412 fl::u8 brightness, TBlendType blendType) FL_NO_EXCEPT;
1413
1419CRGB16 ColorFromPaletteHD(const CRGBPalette16 &pal, fl::u16 index,
1421 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1422
1424inline CRGB16 ColorFromPaletteHD(const CRGBPalette16 &pal, fl::u16 index,
1426 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT {
1427 const fl::u16 raw = brightness == 255 ? fl::u16(256) : brightness;
1428 return ColorFromPaletteHD(pal, index, fl::u8x8::from_raw(raw), blendType);
1429}
1430
1436CRGB ColorFromPaletteExtended(const CRGBPalette32 &pal, fl::u16 index,
1437 fl::u8 brightness, TBlendType blendType) FL_NO_EXCEPT;
1438
1440CRGB16 ColorFromPaletteHD(const CRGBPalette32 &pal, fl::u16 index,
1442 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1443
1445inline CRGB16 ColorFromPaletteHD(const CRGBPalette32 &pal, fl::u16 index,
1447 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT {
1448 const fl::u16 raw = brightness == 255 ? fl::u16(256) : brightness;
1449 return ColorFromPaletteHD(pal, index, fl::u8x8::from_raw(raw), blendType);
1450}
1451
1453CRGB ColorFromPaletteExtended(const TProgmemRGBPalette16 &pal, fl::u16 index,
1454 fl::u8 brightness = 255,
1455 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1456
1458CRGB16 ColorFromPaletteHD(const TProgmemRGBPalette16 &pal, fl::u16 index,
1460 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1461
1463inline CRGB16 ColorFromPaletteHD(const TProgmemRGBPalette16 &pal, fl::u16 index,
1465 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT {
1466 const fl::u16 raw = brightness == 255 ? fl::u16(256) : brightness;
1467 return ColorFromPaletteHD(pal, index, fl::u8x8::from_raw(raw), blendType);
1468}
1469
1471CRGB ColorFromPaletteExtended(const TProgmemRGBPalette32 &pal, fl::u16 index,
1472 fl::u8 brightness = 255,
1473 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1474
1476CRGB16 ColorFromPaletteHD(const TProgmemRGBPalette32 &pal, fl::u16 index,
1478 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1479
1481inline CRGB16 ColorFromPaletteHD(const TProgmemRGBPalette32 &pal, fl::u16 index,
1483 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT {
1484 const fl::u16 raw = brightness == 255 ? fl::u16(256) : brightness;
1485 return ColorFromPaletteHD(pal, index, fl::u8x8::from_raw(raw), blendType);
1486}
1487
1491 fl::u8 brightness = 255,
1492 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1493
1496CRGB ColorFromPalette(const CRGBPalette256 &pal, fl::u8 index,
1497 fl::u8 brightness = 255, TBlendType blendType = NOBLEND) FL_NO_EXCEPT;
1498
1499// @author https://github.com/generalelectrix
1500CRGB ColorFromPaletteExtended(const CRGBPalette256 &pal, fl::u16 index,
1501 fl::u8 brightness = 255,
1502 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1503
1505CRGB16 ColorFromPaletteHD(const CRGBPalette256 &pal, fl::u16 index,
1507 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1508
1510inline CRGB16 ColorFromPaletteHD(const CRGBPalette256 &pal, fl::u16 index,
1512 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT {
1513 const fl::u16 raw = brightness == 255 ? fl::u16(256) : brightness;
1514 return ColorFromPaletteHD(pal, index, fl::u8x8::from_raw(raw), blendType);
1515}
1516
1519CHSV ColorFromPalette(const CHSVPalette16 &pal, fl::u8 index,
1520 fl::u8 brightness = 255,
1521 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1522
1525CHSV ColorFromPalette(const CHSVPalette256 &pal, fl::u8 index,
1526 fl::u8 brightness = 255, TBlendType blendType = NOBLEND) FL_NO_EXCEPT;
1527
1530CRGB ColorFromPalette(const CRGBPalette32 &pal, fl::u8 index,
1531 fl::u8 brightness = 255,
1532 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1533
1537 fl::u8 brightness = 255,
1538 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1539
1542CHSV ColorFromPalette(const CHSVPalette32 &pal, fl::u8 index,
1543 fl::u8 brightness = 255,
1544 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT;
1545
1556template <typename PALETTE>
1557void fill_palette(CRGB *L, fl::u16 N, fl::u8 startIndex, fl::u8 incIndex,
1558 const PALETTE &pal, fl::u8 brightness = 255,
1559 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT {
1560 fl::u8 colorIndex = startIndex;
1561 for (fl::u16 i = 0; i < N; ++i) {
1562 L[i] = ColorFromPalette(pal, colorIndex, brightness, blendType);
1563 colorIndex += incIndex;
1564 }
1565}
1566
1568template <typename PALETTE>
1569inline void fill_palette(fl::span<CRGB> L, fl::u8 startIndex, fl::u8 incIndex,
1570 const PALETTE &pal, fl::u8 brightness = 255,
1571 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT {
1572 fill_palette(L.data(), static_cast<fl::u16>(L.size()), startIndex, incIndex,
1573 pal, brightness, blendType);
1574}
1575
1587template <typename PALETTE>
1588void fill_palette_circular(CRGB *L, fl::u16 N, fl::u8 startIndex,
1589 const PALETTE &pal, fl::u8 brightness = 255,
1590 TBlendType blendType = LINEARBLEND,
1591 bool reversed = false) FL_NO_EXCEPT {
1592 if (N == 0)
1593 return; // avoiding div/0
1594
1595 const fl::u16 colorChange =
1596 65535 / N; // color change for each LED, * 256 for precision
1597 fl::u16 colorIndex = ((fl::u16)startIndex)
1598 << 8; // offset for color index, with precision (*256)
1599
1600 for (fl::u16 i = 0; i < N; ++i) {
1601 L[i] = ColorFromPalette(pal, (colorIndex >> 8), brightness, blendType);
1602 if (reversed)
1603 colorIndex -= colorChange;
1604 else
1605 colorIndex += colorChange;
1606 }
1607}
1608
1610template <typename PALETTE>
1611inline void fill_palette_circular(fl::span<CRGB> L, fl::u8 startIndex,
1612 const PALETTE &pal, fl::u8 brightness = 255,
1613 TBlendType blendType = LINEARBLEND,
1614 bool reversed = false) FL_NO_EXCEPT {
1615 fill_palette_circular(L.data(), static_cast<fl::u16>(L.size()), startIndex,
1616 pal, brightness, blendType, reversed);
1617}
1618
1638template <typename PALETTE>
1639void map_data_into_colors_through_palette(
1640 fl::u8 *dataArray, fl::u16 dataCount, CRGB *targetColorArray,
1641 const PALETTE &pal, fl::u8 brightness = 255, fl::u8 opacity = 255,
1642 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT {
1643 if (opacity == 0) {
1644 return;
1645 }
1646 for (fl::u16 i = 0; i < dataCount; ++i) {
1647 fl::u8 d = dataArray[i];
1648 CRGB rgb = ColorFromPalette(pal, d, brightness, blendType);
1649 if (opacity == 255) {
1650 targetColorArray[i] = rgb;
1651 } else {
1652 targetColorArray[i].nscale8(256 - opacity);
1653 rgb.nscale8_video(opacity);
1654 targetColorArray[i] += rgb;
1655 }
1656 }
1657}
1658
1662template <typename PALETTE>
1663inline void map_data_into_colors_through_palette(
1664 fl::span<fl::u8> dataArray, fl::span<CRGB> targetColorArray,
1665 const PALETTE &pal, fl::u8 brightness = 255, fl::u8 opacity = 255,
1666 TBlendType blendType = LINEARBLEND) FL_NO_EXCEPT {
1667 const fl::u16 count = static_cast<fl::u16>(
1668 dataArray.size() < targetColorArray.size() ? dataArray.size()
1669 : targetColorArray.size());
1670 map_data_into_colors_through_palette(
1671 dataArray.data(), count, targetColorArray.data(), pal, brightness,
1672 opacity, blendType);
1673}
1674
1713void nblendPaletteTowardPalette(CRGBPalette16 &currentPalette,
1714 CRGBPalette16 &targetPalette,
1715 fl::u8 maxChanges = 24) FL_NO_EXCEPT;
1716
1718
1720
1752
1758
1763CRGB applyGamma_video(const CRGB &orig, float gamma) FL_NO_EXCEPT;
1764
1771CRGB applyGamma_video(const CRGB &orig, float gammaR, float gammaG,
1772 float gammaB) FL_NO_EXCEPT;
1773
1778
1784CRGB &napplyGamma_video(CRGB &rgb, float gammaR, float gammaG, float gammaB) FL_NO_EXCEPT;
1785
1791void napplyGamma_video(CRGB *rgbarray, fl::u16 count, float gamma) FL_NO_EXCEPT;
1792
1794inline void napplyGamma_video(fl::span<CRGB> rgbarray, float gamma) FL_NO_EXCEPT {
1795 napplyGamma_video(rgbarray.data(), static_cast<fl::u16>(rgbarray.size()),
1796 gamma);
1797}
1798
1806void napplyGamma_video(CRGB *rgbarray, fl::u16 count, float gammaR,
1807 float gammaG, float gammaB) FL_NO_EXCEPT;
1808
1810inline void napplyGamma_video(fl::span<CRGB> rgbarray, float gammaR,
1811 float gammaG, float gammaB) FL_NO_EXCEPT {
1812 napplyGamma_video(rgbarray.data(), static_cast<fl::u16>(rgbarray.size()),
1813 gammaR, gammaG, gammaB);
1814}
1815
1817
1818} // namespace fl
1819
CRGB leds[1]
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_NO_EXCEPT
Definition u8x8.h:53
TGradientDirectionCode
Hue direction for calculating fill gradients.
void fill_gradient(T *targetArray, u16 startpos, CHSV startcolor, u16 endpos, CHSV endcolor, TGradientDirectionCode directionCode=SHORTEST_HUES) FL_NO_EXCEPT
Fill a range of LEDs with a smooth HSV gradient between two HSV colors.
Definition fill.h:105
@ SHORTEST_HUES
Hue goes whichever way is shortest.
void fill_solid(CRGB *targetArray, int numToFill, const CRGB &color) FL_NO_EXCEPT
Fill a range of LEDs with a solid color.
Definition fill.cpp.hpp:10
void UpscalePalette(const class CRGBPalette16 &srcpal16, class CRGBPalette256 &destpal256) FL_NO_EXCEPT
void fill_gradient_RGB(CRGB *leds, u16 startpos, CRGB startcolor, u16 endpos, CRGB endcolor) FL_NO_EXCEPT
Fill a range of LEDs with a smooth RGB gradient between two RGB colors.
Definition fill.cpp.hpp:108
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 TProgmemRGBPalette16[16]
CRGBPalette16 entries stored in PROGMEM memory.
#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_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(...)
Definition log.h:437
Centralized logging categories for FastLED hardware interfaces and subsystems.
unsigned char u8
Definition stdint.h:131
void fadeUsingColor(CRGB *leds, fl::u16 numLeds, const CRGB &colormask) FL_NO_EXCEPT
CRGB16 ColorFromPaletteHD(const CRGBPalette32 &pal, fl::u16 index, fl::u8x8 brightness, TBlendType blendType) FL_NO_EXCEPT
constexpr u32 gamma(float g) FL_NO_EXCEPT
Definition gamma_lut.h:36
FASTLED_FORCE_INLINE int memcmp(const void *s1, const void *s2, size_t n) FL_NO_EXCEPT
Definition cstring.h:140
void fadeToBlackBy(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy) FL_NO_EXCEPT
void fade_raw(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy) FL_NO_EXCEPT
u8 fract8
Fixed-Point Fractional Types.
Definition stdint.h:160
CRGB ColorFromPaletteExtended(const CRGBPalette32 &pal, fl::u16 index, fl::u8 brightness, TBlendType blendType) FL_NO_EXCEPT
fl::u8 applyGamma_video(fl::u8 brightness, float gamma) FL_NO_EXCEPT
void nscale8(CRGB *leds, fl::u16 num_leds, fl::u8 scale) FL_NO_EXCEPT
void nscale8_video(CRGB *leds, fl::u16 num_leds, fl::u8 scale) FL_NO_EXCEPT
void fade_video(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy) FL_NO_EXCEPT
CRGB blend(const CRGB &p1, const CRGB &p2, fract8 amountOfP2) FL_NO_EXCEPT
CRGB & napplyGamma_video(CRGB &rgb, float gamma) FL_NO_EXCEPT
CRGB & nblend(CRGB &existing, const CRGB &overlay, fract8 amountOfOverlay) FL_NO_EXCEPT
To bit_cast(const From &from) FL_NO_EXCEPT
Definition bit_cast.h:48
void UpscalePalette(const class CRGBPalette16 &srcpal16, class CRGBPalette256 &destpal256) FL_NO_EXCEPT
CRGB HeatColor(fl::u8 temperature) FL_NO_EXCEPT
CRGB ColorFromPalette(const CRGBPalette16 &pal, fl::u8 index, fl::u8 brightness, TBlendType blendType) FL_NO_EXCEPT
void nblendPaletteTowardPalette(CRGBPalette16 &current, CRGBPalette16 &target, fl::u8 maxChanges) FL_NO_EXCEPT
signed char i8
Definition stdint.h:130
void fadeLightBy(CRGB *leds, fl::u16 num_leds, fl::u8 fadeBy) FL_NO_EXCEPT
CRGB blend_oklab(const CRGB &p1, const CRGB &p2, fract8 amountOfP2) FL_NO_EXCEPT
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NO_EXCEPT
CHSVPalette16 entries stored in PROGMEM memory.
CHSVPalette32 entries stored in PROGMEM memory.
FASTLED_FORCE_INLINE CRGB & nscale8_video(u8 scaledown) FL_NO_EXCEPT
Scale down a RGB to N/256ths of it's current brightness using "video" dimming rules.
Definition crgb.hpp:72
CRGB & nscale8(u8 scaledown) FL_NO_EXCEPT
Scale down a RGB to N/256ths of its current brightness, using "plain math" dimming rules.
Definition crgb.cpp.hpp:87