diff options
Diffstat (limited to 'colorutils.h')
-rw-r--r-- | colorutils.h | 473 |
1 files changed, 472 insertions, 1 deletions
diff --git a/colorutils.h b/colorutils.h index f27e0f4c..18a052fb 100644 --- a/colorutils.h +++ b/colorutils.h @@ -4,6 +4,7 @@ ///@file colorutils.h /// functions for color fill, paletters, blending, and more +#include "FastLED.h" #include "pixeltypes.h" #include "fastled_progmem.h" @@ -391,12 +392,17 @@ CRGB HeatColor( uint8_t temperature); // class CRGBPalette16; +class CRGBPalette32; class CRGBPalette256; class CHSVPalette16; +class CHSVPalette32; class CHSVPalette256; typedef uint32_t TProgmemRGBPalette16[16]; typedef uint32_t TProgmemHSVPalette16[16]; #define TProgmemPalette16 TProgmemRGBPalette16 +typedef uint32_t TProgmemRGBPalette32[32]; +typedef uint32_t TProgmemHSVPalette32[32]; +#define TProgmemPalette32 TProgmemRGBPalette32 typedef const uint8_t TProgmemRGBGradientPalette_byte ; typedef const TProgmemRGBGradientPalette_byte *TProgmemRGBGradientPalette_bytes; @@ -420,6 +426,14 @@ typedef TDynamicRGBGradientPalette_bytes TDynamicRGBGradientPalettePtr; void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette256& destpal256); void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette256& destpal256); +// Convert a 16-entry palette to a 32-entry palette +void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette32& destpal32); +void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette32& destpal32); + +// Convert a 32-entry palette to a 256-entry palette +void UpscalePalette(const struct CRGBPalette32& srcpal32, struct CRGBPalette256& destpal256); +void UpscalePalette(const struct CHSVPalette32& srcpal32, struct CHSVPalette256& destpal256); + class CHSVPalette16 { public: @@ -648,11 +662,20 @@ public: { memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries)); } + CRGBPalette16( const CRGB rhs[16]) + { + memmove8( &(entries[0]), &(rhs[0]), sizeof( entries)); + } CRGBPalette16& operator=( const CRGBPalette16& rhs) { memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries)); return *this; } + CRGBPalette16& operator=( const CRGB rhs[16]) + { + memmove8( &(entries[0]), &(rhs[0]), sizeof( entries)); + return *this; + } CRGBPalette16( const CHSVPalette16& rhs) { @@ -660,6 +683,12 @@ public: entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion } } + CRGBPalette16( const CHSV rhs[16]) + { + for( uint8_t i = 0; i < 16; i++) { + entries[i] = rhs[i]; // implicit HSV-to-RGB conversion + } + } CRGBPalette16& operator=( const CHSVPalette16& rhs) { for( uint8_t i = 0; i < 16; i++) { @@ -667,6 +696,13 @@ public: } return *this; } + CRGBPalette16& operator=( const CHSV rhs[16]) + { + for( uint8_t i = 0; i < 16; i++) { + entries[i] = rhs[i]; // implicit HSV-to-RGB conversion + } + return *this; + } CRGBPalette16( const TProgmemRGBPalette16& rhs) { @@ -871,6 +907,405 @@ public: }; + + +class CHSVPalette32 { +public: + CHSV entries[32]; + CHSVPalette32() {}; + CHSVPalette32( const CHSV& c00,const CHSV& c01,const CHSV& c02,const CHSV& c03, + const CHSV& c04,const CHSV& c05,const CHSV& c06,const CHSV& c07, + const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11, + const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 ) + { + for( uint8_t i = 0; i < 2; i++) { + entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03; + entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07; + entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11; + entries[24+i]=c12; entries[26+i]=c13; entries[28+i]=c14; entries[30+i]=c15; + } + }; + + CHSVPalette32( const CHSVPalette32& rhs) + { + memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries)); + } + CHSVPalette32& operator=( const CHSVPalette32& rhs) + { + memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries)); + return *this; + } + + CHSVPalette32( const TProgmemHSVPalette32& rhs) + { + for( uint8_t i = 0; i < 32; i++) { + CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i); + entries[i].hue = xyz.red; + entries[i].sat = xyz.green; + entries[i].val = xyz.blue; + } + } + CHSVPalette32& operator=( const TProgmemHSVPalette32& rhs) + { + for( uint8_t i = 0; i < 32; i++) { + CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i); + entries[i].hue = xyz.red; + entries[i].sat = xyz.green; + entries[i].val = xyz.blue; + } + return *this; + } + + inline CHSV& operator[] (uint8_t x) __attribute__((always_inline)) + { + return entries[x]; + } + inline const CHSV& operator[] (uint8_t x) const __attribute__((always_inline)) + { + return entries[x]; + } + + inline CHSV& operator[] (int x) __attribute__((always_inline)) + { + return entries[(uint8_t)x]; + } + inline const CHSV& operator[] (int x) const __attribute__((always_inline)) + { + return entries[(uint8_t)x]; + } + + operator CHSV*() + { + return &(entries[0]); + } + + bool operator==( const CHSVPalette32 rhs) + { + const uint8_t* p = (const uint8_t*)(&(this->entries[0])); + const uint8_t* q = (const uint8_t*)(&(rhs.entries[0])); + if( p == q) return true; + for( uint8_t i = 0; i < (sizeof( entries)); i++) { + if( *p != *q) return false; + p++; + q++; + } + return true; + } + bool operator!=( const CHSVPalette32 rhs) + { + return !( *this == rhs); + } + + CHSVPalette32( const CHSV& c1) + { + fill_solid( &(entries[0]), 32, c1); + } + CHSVPalette32( const CHSV& c1, const CHSV& c2) + { + fill_gradient( &(entries[0]), 32, c1, c2); + } + CHSVPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3) + { + fill_gradient( &(entries[0]), 32, c1, c2, c3); + } + CHSVPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4) + { + fill_gradient( &(entries[0]), 32, c1, c2, c3, c4); + } + +}; + +class CRGBPalette32 { +public: + CRGB entries[32]; + CRGBPalette32() {}; + CRGBPalette32( const CRGB& c00,const CRGB& c01,const CRGB& c02,const CRGB& c03, + const CRGB& c04,const CRGB& c05,const CRGB& c06,const CRGB& c07, + const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11, + const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 ) + { + for( uint8_t i = 0; i < 2; i++) { + entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03; + entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07; + entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11; + entries[24+i]=c12; entries[26+i]=c13; entries[28+i]=c14; entries[30+i]=c15; + } + }; + + CRGBPalette32( const CRGBPalette32& rhs) + { + memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries)); + } + CRGBPalette32( const CRGB rhs[32]) + { + memmove8( &(entries[0]), &(rhs[0]), sizeof( entries)); + } + CRGBPalette32& operator=( const CRGBPalette32& rhs) + { + memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries)); + return *this; + } + CRGBPalette32& operator=( const CRGB rhs[32]) + { + memmove8( &(entries[0]), &(rhs[0]), sizeof( entries)); + return *this; + } + + CRGBPalette32( const CHSVPalette32& rhs) + { + for( uint8_t i = 0; i < 32; i++) { + entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion + } + } + CRGBPalette32( const CHSV rhs[32]) + { + for( uint8_t i = 0; i < 32; i++) { + entries[i] = rhs[i]; // implicit HSV-to-RGB conversion + } + } + CRGBPalette32& operator=( const CHSVPalette32& rhs) + { + for( uint8_t i = 0; i < 32; i++) { + entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion + } + return *this; + } + CRGBPalette32& operator=( const CHSV rhs[32]) + { + for( uint8_t i = 0; i < 32; i++) { + entries[i] = rhs[i]; // implicit HSV-to-RGB conversion + } + return *this; + } + + CRGBPalette32( const TProgmemRGBPalette32& rhs) + { + for( uint8_t i = 0; i < 32; i++) { + entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i); + } + } + CRGBPalette32& operator=( const TProgmemRGBPalette32& rhs) + { + for( uint8_t i = 0; i < 32; i++) { + entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i); + } + return *this; + } + + bool operator==( const CRGBPalette32 rhs) + { + const uint8_t* p = (const uint8_t*)(&(this->entries[0])); + const uint8_t* q = (const uint8_t*)(&(rhs.entries[0])); + if( p == q) return true; + for( uint8_t i = 0; i < (sizeof( entries)); i++) { + if( *p != *q) return false; + p++; + q++; + } + return true; + } + bool operator!=( const CRGBPalette32 rhs) + { + return !( *this == rhs); + } + + inline CRGB& operator[] (uint8_t x) __attribute__((always_inline)) + { + return entries[x]; + } + inline const CRGB& operator[] (uint8_t x) const __attribute__((always_inline)) + { + return entries[x]; + } + + inline CRGB& operator[] (int x) __attribute__((always_inline)) + { + return entries[(uint8_t)x]; + } + inline const CRGB& operator[] (int x) const __attribute__((always_inline)) + { + return entries[(uint8_t)x]; + } + + operator CRGB*() + { + return &(entries[0]); + } + + CRGBPalette32( const CHSV& c1) + { + fill_solid( &(entries[0]), 32, c1); + } + CRGBPalette32( const CHSV& c1, const CHSV& c2) + { + fill_gradient( &(entries[0]), 32, c1, c2); + } + CRGBPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3) + { + fill_gradient( &(entries[0]), 32, c1, c2, c3); + } + CRGBPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4) + { + fill_gradient( &(entries[0]), 32, c1, c2, c3, c4); + } + + CRGBPalette32( const CRGB& c1) + { + fill_solid( &(entries[0]), 32, c1); + } + CRGBPalette32( const CRGB& c1, const CRGB& c2) + { + fill_gradient_RGB( &(entries[0]), 32, c1, c2); + } + CRGBPalette32( const CRGB& c1, const CRGB& c2, const CRGB& c3) + { + fill_gradient_RGB( &(entries[0]), 32, c1, c2, c3); + } + CRGBPalette32( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4) + { + fill_gradient_RGB( &(entries[0]), 32, c1, c2, c3, c4); + } + + + CRGBPalette32( const CRGBPalette16& rhs16) + { + UpscalePalette( rhs16, *this); + } + CRGBPalette32& operator=( const CRGBPalette16& rhs16) + { + UpscalePalette( rhs16, *this); + return *this; + } + + CRGBPalette32( const TProgmemRGBPalette16& rhs) + { + CRGBPalette16 p16(rhs); + *this = p16; + } + CRGBPalette32& operator=( const TProgmemRGBPalette16& rhs) + { + CRGBPalette16 p16(rhs); + *this = p16; + return *this; + } + + + // Gradient palettes are loaded into CRGB16Palettes in such a way + // that, if possible, every color represented in the gradient palette + // is also represented in the CRGBPalette32. + // For example, consider a gradient palette that is all black except + // for a single, one-element-wide (1/256th!) spike of red in the middle: + // 0, 0,0,0 + // 124, 0,0,0 + // 125, 255,0,0 // one 1/256th-palette-wide red stripe + // 126, 0,0,0 + // 255, 0,0,0 + // A naive conversion of this 256-element palette to a 16-element palette + // might accidentally completely eliminate the red spike, rendering the + // palette completely black. + // However, the conversions provided here would attempt to include a + // the red stripe in the output, more-or-less as faithfully as possible. + // So in this case, the resulting CRGBPalette32 palette would have a red + // stripe in the middle which was 1/16th of a palette wide -- the + // narrowest possible in a CRGBPalette32. + // This means that the relative width of stripes in a CRGBPalette32 + // will be, by definition, different from the widths in the gradient + // palette. This code attempts to preserve "all the colors", rather than + // the exact stripe widths at the expense of dropping some colors. + CRGBPalette32( TProgmemRGBGradientPalette_bytes progpal ) + { + *this = progpal; + } + CRGBPalette32& operator=( TProgmemRGBGradientPalette_bytes progpal ) + { + TRGBGradientPaletteEntryUnion* progent = (TRGBGradientPaletteEntryUnion*)(progpal); + TRGBGradientPaletteEntryUnion u; + + // Count entries + uint8_t count = 0; + do { + u.dword = FL_PGM_READ_DWORD_NEAR(progent + count); + count++;; + } while ( u.index != 255); + + int8_t lastSlotUsed = -1; + + u.dword = FL_PGM_READ_DWORD_NEAR( progent); + CRGB rgbstart( u.r, u.g, u.b); + + int indexstart = 0; + uint8_t istart8 = 0; + uint8_t iend8 = 0; + while( indexstart < 255) { + progent++; + u.dword = FL_PGM_READ_DWORD_NEAR( progent); + int indexend = u.index; + CRGB rgbend( u.r, u.g, u.b); + istart8 = indexstart / 8; + iend8 = indexend / 8; + if( count < 16) { + if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) { + istart8 = lastSlotUsed + 1; + if( iend8 < istart8) { + iend8 = istart8; + } + } + lastSlotUsed = iend8; + } + fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend); + indexstart = indexend; + rgbstart = rgbend; + } + return *this; + } + CRGBPalette32& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal ) + { + TRGBGradientPaletteEntryUnion* ent = (TRGBGradientPaletteEntryUnion*)(gpal); + TRGBGradientPaletteEntryUnion u; + + // Count entries + uint8_t count = 0; + do { + u = *(ent + count); + count++;; + } while ( u.index != 255); + + int8_t lastSlotUsed = -1; + + + u = *ent; + CRGB rgbstart( u.r, u.g, u.b); + + int indexstart = 0; + uint8_t istart8 = 0; + uint8_t iend8 = 0; + while( indexstart < 255) { + ent++; + u = *ent; + int indexend = u.index; + CRGB rgbend( u.r, u.g, u.b); + istart8 = indexstart / 8; + iend8 = indexend / 8; + if( count < 16) { + if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) { + istart8 = lastSlotUsed + 1; + if( iend8 < istart8) { + iend8 = istart8; + } + } + lastSlotUsed = iend8; + } + fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend); + indexstart = indexend; + rgbstart = rgbend; + } + return *this; + } + +}; + + + class CRGBPalette256 { public: CRGB entries[256]; @@ -889,11 +1324,20 @@ public: { memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries)); } + CRGBPalette256( const CRGB rhs[256]) + { + memmove8( &(entries[0]), &(rhs[0]), sizeof( entries)); + } CRGBPalette256& operator=( const CRGBPalette256& rhs) { memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries)); return *this; } + CRGBPalette256& operator=( const CRGB rhs[256]) + { + memmove8( &(entries[0]), &(rhs[0]), sizeof( entries)); + return *this; + } CRGBPalette256( const CHSVPalette256& rhs) { @@ -901,6 +1345,12 @@ public: entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion } } + CRGBPalette256( const CHSV rhs[256]) + { + for( int i = 0; i < 256; i++) { + entries[i] = rhs[i]; // implicit HSV-to-RGB conversion + } + } CRGBPalette256& operator=( const CHSVPalette256& rhs) { for( int i = 0; i < 256; i++) { @@ -908,6 +1358,13 @@ public: } return *this; } + CRGBPalette256& operator=( const CHSV rhs[256]) + { + for( int i = 0; i < 256; i++) { + entries[i] = rhs[i]; // implicit HSV-to-RGB conversion + } + return *this; + } CRGBPalette256( const CRGBPalette16& rhs16) { @@ -1051,7 +1508,6 @@ public: - typedef enum { NOBLEND=0, LINEARBLEND=1 } TBlendType; CRGB ColorFromPalette( const CRGBPalette16& pal, @@ -1079,6 +1535,21 @@ CHSV ColorFromPalette( const CHSVPalette256& pal, uint8_t brightness=255, TBlendType blendType=NOBLEND ); +CRGB ColorFromPalette( const CRGBPalette32& pal, + uint8_t index, + uint8_t brightness=255, + TBlendType blendType=LINEARBLEND); + +CRGB ColorFromPalette( const TProgmemRGBPalette32& pal, + uint8_t index, + uint8_t brightness=255, + TBlendType blendType=LINEARBLEND); + +CHSV ColorFromPalette( const CHSVPalette32& pal, + uint8_t index, + uint8_t brightness=255, + TBlendType blendType=LINEARBLEND); + // Fill a range of LEDs with a sequece of entryies from a palette template <typename PALETTE> |