Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'colorutils.h')
-rw-r--r--colorutils.h513
1 files changed, 437 insertions, 76 deletions
diff --git a/colorutils.h b/colorutils.h
index 9034c1ee..209e6410 100644
--- a/colorutils.h
+++ b/colorutils.h
@@ -1,27 +1,36 @@
#ifndef __INC_COLORUTILS_H
#define __INC_COLORUTILS_H
-#include <avr/pgmspace.h>
+///@file colorutils.h
+/// functions for color fill, paletters, blending, and more
#include "pixeltypes.h"
+#include "fastled_progmem.h"
+FASTLED_NAMESPACE_BEGIN
+///@defgroup Colorutils Color utility functions
+///A variety of functions for working with color, palletes, and leds
+///@{
-// fill_solid - fill a range of LEDs with a solid color
-// Example: fill_solid( leds, NUM_LEDS, CRGB(50,0,200));
-
+/// fill_solid - fill a range of LEDs with a solid color
+/// Example: fill_solid( leds, NUM_LEDS, CRGB(50,0,200));
void fill_solid( struct CRGB * leds, int numToFill,
const struct CRGB& color);
+/// fill_solid - fill a range of LEDs with a solid color
+/// Example: fill_solid( leds, NUM_LEDS, CRGB(50,0,200));
void fill_solid( struct CHSV* targetArray, int numToFill,
const struct CHSV& hsvColor);
-
-// fill_rainbow - fill a range of LEDs with a rainbow of colors, at
-// full saturation and full value (brightness)
+
+/// fill_rainbow - fill a range of LEDs with a rainbow of colors, at
+/// full saturation and full value (brightness)
void fill_rainbow( struct CRGB * pFirstLED, int numToFill,
uint8_t initialhue,
uint8_t deltahue = 5);
-
+
+/// fill_rainbow - fill a range of LEDs with a rainbow of colors, at
+/// full saturation and full value (brightness)
void fill_rainbow( struct CHSV * targetArray, int numToFill,
uint8_t initialhue,
uint8_t deltahue = 5);
@@ -43,11 +52,11 @@ void fill_rainbow( struct CHSV * targetArray, int numToFill,
//
// fill_gradient can write the gradient colors EITHER
// (1) into an array of CRGBs (e.g., into leds[] array, or an RGB Palette)
-// OR
+// OR
// (2) into an array of CHSVs (e.g. an HSV Palette).
//
-// In the case of writing into a CRGB array, the gradient is
-// computed in HSV space, and then HSV values are converted to RGB
+// In the case of writing into a CRGB array, the gradient is
+// computed in HSV space, and then HSV values are converted to RGB
// as they're written into the RGB array.
typedef enum { FORWARD_HUES, BACKWARD_HUES, SHORTEST_HUES, LONGEST_HUES } TGradientDirectionCode;
@@ -56,6 +65,30 @@ typedef enum { FORWARD_HUES, BACKWARD_HUES, SHORTEST_HUES, LONGEST_HUES } TGradi
#define saccum87 int16_t
+/// fill_gradient - fill an array of colors with a smooth HSV gradient
+/// between two specified HSV colors.
+/// Since 'hue' is a value around a color wheel,
+/// there are always two ways to sweep from one hue
+/// to another.
+/// This function lets you specify which way you want
+/// the hue gradient to sweep around the color wheel:
+///
+/// FORWARD_HUES: hue always goes clockwise
+/// BACKWARD_HUES: hue always goes counter-clockwise
+/// SHORTEST_HUES: hue goes whichever way is shortest
+/// LONGEST_HUES: hue goes whichever way is longest
+///
+/// The default is SHORTEST_HUES, as this is nearly
+/// always what is wanted.
+///
+/// fill_gradient can write the gradient colors EITHER
+/// (1) into an array of CRGBs (e.g., into leds[] array, or an RGB Palette)
+/// OR
+/// (2) into an array of CHSVs (e.g. an HSV Palette).
+///
+/// In the case of writing into a CRGB array, the gradient is
+/// computed in HSV space, and then HSV values are converted to RGB
+/// as they're written into the RGB array.
template <typename T>
void fill_gradient( T* targetArray,
uint16_t startpos, CHSV startcolor,
@@ -66,12 +99,12 @@ void fill_gradient( T* targetArray,
if( endpos < startpos ) {
uint16_t t = endpos;
CHSV tc = endcolor;
- startpos = t;
- startcolor = tc;
endcolor = startcolor;
endpos = startpos;
+ startpos = t;
+ startcolor = tc;
}
-
+
// If we're fading toward black (val=0) or white (sat=0),
// then set the endhue to the starthue.
// This lets us ramp smoothly to black or white, regardless
@@ -79,7 +112,7 @@ void fill_gradient( T* targetArray,
if( endcolor.value == 0 || endcolor.saturation == 0) {
endcolor.hue = startcolor.hue;
}
-
+
// Similarly, if we're fading in from black (val=0) or white (sat=0)
// then set the starthue to the endhue.
// This lets us ramp smoothly up from black or white, regardless
@@ -87,30 +120,30 @@ void fill_gradient( T* targetArray,
if( startcolor.value == 0 || startcolor.saturation == 0) {
startcolor.hue = endcolor.hue;
}
-
+
saccum87 huedistance87;
saccum87 satdistance87;
saccum87 valdistance87;
-
+
satdistance87 = (endcolor.sat - startcolor.sat) << 7;
valdistance87 = (endcolor.val - startcolor.val) << 7;
-
+
uint8_t huedelta8 = endcolor.hue - startcolor.hue;
-
+
if( directionCode == SHORTEST_HUES ) {
directionCode = FORWARD_HUES;
if( huedelta8 > 127) {
directionCode = BACKWARD_HUES;
}
}
-
+
if( directionCode == LONGEST_HUES ) {
directionCode = FORWARD_HUES;
if( huedelta8 < 128) {
directionCode = BACKWARD_HUES;
}
}
-
+
if( directionCode == FORWARD_HUES) {
huedistance87 = huedelta8 << 7;
}
@@ -119,18 +152,18 @@ void fill_gradient( T* targetArray,
huedistance87 = (uint8_t)(256 - huedelta8) << 7;
huedistance87 = -huedistance87;
}
-
+
uint16_t pixeldistance = endpos - startpos;
int16_t divisor = pixeldistance ? pixeldistance : 1;
-
+
saccum87 huedelta87 = huedistance87 / divisor;
saccum87 satdelta87 = satdistance87 / divisor;
saccum87 valdelta87 = valdistance87 / divisor;
-
+
huedelta87 *= 2;
satdelta87 *= 2;
valdelta87 *= 2;
-
+
accum88 hue88 = startcolor.hue << 8;
accum88 sat88 = startcolor.sat << 8;
accum88 val88 = startcolor.val << 8;
@@ -146,7 +179,7 @@ void fill_gradient( T* targetArray,
// Convenience functions to fill an array of colors with a
// two-color, three-color, or four-color gradient
template <typename T>
-void fill_gradient( T* targetArray, uint16_t numLeds, const CHSV& c1, const CHSV& c2,
+void fill_gradient( T* targetArray, uint16_t numLeds, const CHSV& c1, const CHSV& c2,
TGradientDirectionCode directionCode = SHORTEST_HUES )
{
uint16_t last = numLeds - 1;
@@ -154,8 +187,8 @@ void fill_gradient( T* targetArray, uint16_t numLeds, const CHSV& c1, const CHSV
}
template <typename T>
-void fill_gradient( T* targetArray, uint16_t numLeds,
- const CHSV& c1, const CHSV& c2, const CHSV& c3,
+void fill_gradient( T* targetArray, uint16_t numLeds,
+ const CHSV& c1, const CHSV& c2, const CHSV& c3,
TGradientDirectionCode directionCode = SHORTEST_HUES )
{
uint16_t half = (numLeds / 2);
@@ -165,8 +198,8 @@ void fill_gradient( T* targetArray, uint16_t numLeds,
}
template <typename T>
-void fill_gradient( T* targetArray, uint16_t numLeds,
- const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4,
+void fill_gradient( T* targetArray, uint16_t numLeds,
+ const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4,
TGradientDirectionCode directionCode = SHORTEST_HUES )
{
uint16_t onethird = (numLeds / 3);
@@ -219,6 +252,19 @@ void fade_raw( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
// way down to black even if 'scale' is not zero.
void nscale8( CRGB* leds, uint16_t num_leds, uint8_t scale);
+// fadeUsingColor - scale down the brightness of an array of pixels,
+// as though it were seen through a transparent
+// filter with the specified color.
+// For example, if the colormask is
+// CRGB( 200, 100, 50)
+// then the pixels' red will be faded to 200/256ths,
+// their green to 100/256ths, and their blue to 50/256ths.
+// This particular example give a 'hot fade' look,
+// with white fading to yellow, then red, then black.
+// You can also use colormasks like CRGB::Blue to
+// zero out the red and green elements, leaving blue
+// (largely) the same.
+void fadeUsingColor( CRGB* leds, uint16_t numLeds, const CRGB& colormask);
// Pixel blending
@@ -256,6 +302,27 @@ void nblend( CHSV* existing, CHSV* overlay, uint16_t count, fract8 amountOfOver
TGradientDirectionCode directionCode = SHORTEST_HUES);
+// blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors.
+// blur2d: two-dimensional blur filter. Spreads light to 8 XY neighbors.
+//
+// 0 = no spread at all
+// 64 = moderate spreading
+// 172 = maximum smooth, even spreading
+//
+// 173..255 = wider spreading, but increasing flicker
+//
+// Total light is NOT entirely conserved, so many repeated
+// calls to 'blur' will also result in the light fading,
+// eventually all the way to black; this is by design so that
+// it can be used to (slowly) clear the LEDs to black.
+void blur1d( CRGB* leds, uint16_t numLeds, fract8 blur_amount);
+void blur2d( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
+
+// blurRows: perform a blur1d on every row of a rectangular matrix
+void blurRows( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
+// blurColumns: perform a blur1d on each column of a rectangular matrix
+void blurColumns(CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
+
// CRGB HeatColor( uint8_t temperature)
//
@@ -329,12 +396,31 @@ class CHSVPalette16;
class CHSVPalette256;
typedef uint32_t TProgmemRGBPalette16[16];
typedef uint32_t TProgmemHSVPalette16[16];
-#define TProgmemPalette16 TProgmemRGBPalette16
+#define TProgmemPalette16 TProgmemRGBPalette16
+
+typedef const uint8_t TProgmemRGBGradientPalette_byte ;
+typedef const TProgmemRGBGradientPalette_byte *TProgmemRGBGradientPalette_bytes;
+typedef TProgmemRGBGradientPalette_bytes TProgmemRGBGradientPalettePtr;
+typedef union {
+ struct {
+ uint8_t index;
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ };
+ uint32_t dword;
+ uint8_t bytes[4];
+} TRGBGradientPaletteEntryUnion;
+
+typedef uint8_t TDynamicRGBGradientPalette_byte ;
+typedef const TDynamicRGBGradientPalette_byte *TDynamicRGBGradientPalette_bytes;
+typedef TDynamicRGBGradientPalette_bytes TDynamicRGBGradientPalettePtr;
// Convert a 16-entry palette to a 256-entry palette
void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette256& destpal256);
void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette256& destpal256);
+
class CHSVPalette16 {
public:
CHSV entries[16];
@@ -349,7 +435,7 @@ public:
entries[8]=c08; entries[9]=c09; entries[10]=c10; entries[11]=c11;
entries[12]=c12; entries[13]=c13; entries[14]=c14; entries[15]=c15;
};
-
+
CHSVPalette16( const CHSVPalette16& rhs)
{
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
@@ -359,11 +445,11 @@ public:
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
-
+
CHSVPalette16( const TProgmemHSVPalette16& rhs)
{
for( uint8_t i = 0; i < 16; i++) {
- CRGB xyz = pgm_read_dword_near( rhs + 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;
@@ -372,14 +458,14 @@ public:
CHSVPalette16& operator=( const TProgmemHSVPalette16& rhs)
{
for( uint8_t i = 0; i < 16; i++) {
- CRGB xyz = pgm_read_dword_near( rhs + 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];
@@ -388,7 +474,7 @@ public:
{
return entries[x];
}
-
+
inline CHSV& operator[] (int x) __attribute__((always_inline))
{
return entries[(uint8_t)x];
@@ -397,12 +483,12 @@ public:
{
return entries[(uint8_t)x];
}
-
+
operator CHSV*()
{
return &(entries[0]);
}
-
+
CHSVPalette16( const CHSV& c1)
{
fill_solid( &(entries[0]), 16, c1);
@@ -419,7 +505,7 @@ public:
{
fill_gradient( &(entries[0]), 16, c1, c2, c3, c4);
}
-
+
};
class CHSVPalette256 {
@@ -435,7 +521,7 @@ public:
c08,c09,c10,c11,c12,c13,c14,c15);
*this = p16;
};
-
+
CHSVPalette256( const CHSVPalette256& rhs)
{
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
@@ -445,7 +531,7 @@ public:
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
-
+
CHSVPalette256( const CHSVPalette16& rhs16)
{
UpscalePalette( rhs16, *this);
@@ -455,7 +541,7 @@ public:
UpscalePalette( rhs16, *this);
return *this;
}
-
+
CHSVPalette256( const TProgmemRGBPalette16& rhs)
{
CHSVPalette16 p16(rhs);
@@ -467,7 +553,7 @@ public:
*this = p16;
return *this;
}
-
+
inline CHSV& operator[] (uint8_t x) __attribute__((always_inline))
{
return entries[x];
@@ -476,7 +562,7 @@ public:
{
return entries[x];
}
-
+
inline CHSV& operator[] (int x) __attribute__((always_inline))
{
return entries[(uint8_t)x];
@@ -490,7 +576,7 @@ public:
{
return &(entries[0]);
}
-
+
CHSVPalette256( const CHSV& c1)
{
fill_solid( &(entries[0]), 256, c1);
@@ -523,7 +609,7 @@ public:
entries[8]=c08; entries[9]=c09; entries[10]=c10; entries[11]=c11;
entries[12]=c12; entries[13]=c13; entries[14]=c14; entries[15]=c15;
};
-
+
CRGBPalette16( const CRGBPalette16& rhs)
{
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
@@ -533,13 +619,13 @@ public:
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
-
+
CRGBPalette16( const CHSVPalette16& rhs)
{
for( uint8_t i = 0; i < 16; i++) {
entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
}
- }
+ }
CRGBPalette16& operator=( const CHSVPalette16& rhs)
{
for( uint8_t i = 0; i < 16; i++) {
@@ -551,17 +637,17 @@ public:
CRGBPalette16( const TProgmemRGBPalette16& rhs)
{
for( uint8_t i = 0; i < 16; i++) {
- entries[i] = pgm_read_dword_near( rhs + i);
+ entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
}
}
CRGBPalette16& operator=( const TProgmemRGBPalette16& rhs)
{
for( uint8_t i = 0; i < 16; i++) {
- entries[i] = pgm_read_dword_near( rhs + i);
+ entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
}
return *this;
}
-
+
inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
{
return entries[x];
@@ -570,7 +656,7 @@ public:
{
return entries[x];
}
-
+
inline CRGB& operator[] (int x) __attribute__((always_inline))
{
return entries[(uint8_t)x];
@@ -579,12 +665,12 @@ public:
{
return entries[(uint8_t)x];
}
-
+
operator CRGB*()
{
return &(entries[0]);
}
-
+
CRGBPalette16( const CHSV& c1)
{
fill_solid( &(entries[0]), 16, c1);
@@ -601,7 +687,7 @@ public:
{
fill_gradient( &(entries[0]), 16, c1, c2, c3, c4);
}
-
+
CRGBPalette16( const CRGB& c1)
{
fill_solid( &(entries[0]), 16, c1);
@@ -618,7 +704,119 @@ public:
{
fill_gradient_RGB( &(entries[0]), 16, c1, c2, c3, c4);
}
-
+
+
+ // 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 CRGBPalette16.
+ // 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 CRGBPalette16 palette would have a red
+ // stripe in the middle which was 1/16th of a palette wide -- the
+ // narrowest possible in a CRGBPalette16.
+ // This means that the relative width of stripes in a CRGBPalette16
+ // 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.
+ CRGBPalette16( TProgmemRGBGradientPalette_bytes progpal )
+ {
+ *this = progpal;
+ }
+ CRGBPalette16& 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 / 16;
+ iend8 = indexend / 16;
+ if( count < 16) {
+ if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
+ 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;
+ }
+ CRGBPalette16& 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 / 16;
+ iend8 = indexend / 16;
+ if( count < 16) {
+ if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
+ 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;
+ }
};
@@ -635,7 +833,7 @@ public:
c08,c09,c10,c11,c12,c13,c14,c15);
*this = p16;
};
-
+
CRGBPalette256( const CRGBPalette256& rhs)
{
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
@@ -645,7 +843,7 @@ public:
memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
-
+
CRGBPalette256( const CHSVPalette256& rhs)
{
for( int i = 0; i < 256; i++) {
@@ -669,7 +867,7 @@ public:
UpscalePalette( rhs16, *this);
return *this;
}
-
+
CRGBPalette256( const TProgmemRGBPalette16& rhs)
{
CRGBPalette16 p16(rhs);
@@ -681,7 +879,7 @@ public:
*this = p16;
return *this;
}
-
+
inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
{
return entries[x];
@@ -690,7 +888,7 @@ public:
{
return entries[x];
}
-
+
inline CRGB& operator[] (int x) __attribute__((always_inline))
{
return entries[(uint8_t)x];
@@ -704,7 +902,7 @@ public:
{
return &(entries[0]);
}
-
+
CRGBPalette256( const CHSV& c1)
{
fill_solid( &(entries[0]), 256, c1);
@@ -721,7 +919,7 @@ public:
{
fill_gradient( &(entries[0]), 256, c1, c2, c3, c4);
}
-
+
CRGBPalette256( const CRGB& c1)
{
fill_solid( &(entries[0]), 256, c1);
@@ -738,18 +936,65 @@ public:
{
fill_gradient_RGB( &(entries[0]), 256, c1, c2, c3, c4);
}
-
+
+ CRGBPalette256( TProgmemRGBGradientPalette_bytes progpal )
+ {
+ *this = progpal;
+ }
+ CRGBPalette256& operator=( TProgmemRGBGradientPalette_bytes progpal )
+ {
+ TRGBGradientPaletteEntryUnion* progent = (TRGBGradientPaletteEntryUnion*)(progpal);
+ TRGBGradientPaletteEntryUnion u;
+ u.dword = FL_PGM_READ_DWORD_NEAR( progent);
+ CRGB rgbstart( u.r, u.g, u.b);
+
+ int indexstart = 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);
+ fill_gradient_RGB( &(entries[0]), indexstart, rgbstart, indexend, rgbend);
+ indexstart = indexend;
+ rgbstart = rgbend;
+ }
+ return *this;
+ }
+ CRGBPalette256& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal )
+ {
+ TRGBGradientPaletteEntryUnion* ent = (TRGBGradientPaletteEntryUnion*)(gpal);
+ TRGBGradientPaletteEntryUnion u;
+ u = *ent;
+ CRGB rgbstart( u.r, u.g, u.b);
+
+ int indexstart = 0;
+ while( indexstart < 255) {
+ ent++;
+ u = *ent;
+ int indexend = u.index;
+ CRGB rgbend( u.r, u.g, u.b);
+ fill_gradient_RGB( &(entries[0]), indexstart, rgbstart, indexend, rgbend);
+ indexstart = indexend;
+ rgbstart = rgbend;
+ }
+ return *this;
+ }
};
-typedef enum { NOBLEND=0, BLEND=1 } TBlendType;
+typedef enum { NOBLEND=0, LINEARBLEND=1 } TBlendType;
CRGB ColorFromPalette( const CRGBPalette16& pal,
+ uint8_t index,
+ uint8_t brightness=255,
+ TBlendType blendType=LINEARBLEND);
+
+CRGB ColorFromPalette( const TProgmemRGBPalette16& pal,
uint8_t index,
uint8_t brightness=255,
- TBlendType blendType=BLEND);
+ TBlendType blendType=LINEARBLEND);
CRGB ColorFromPalette( const CRGBPalette256& pal,
uint8_t index,
@@ -759,7 +1004,7 @@ CRGB ColorFromPalette( const CRGBPalette256& pal,
CHSV ColorFromPalette( const CHSVPalette16& pal,
uint8_t index,
uint8_t brightness=255,
- TBlendType blendType=BLEND);
+ TBlendType blendType=LINEARBLEND);
CHSV ColorFromPalette( const CHSVPalette256& pal,
uint8_t index,
@@ -768,7 +1013,7 @@ CHSV ColorFromPalette( const CHSVPalette256& pal,
// Fill a range of LEDs with a sequece of entryies from a palette
-template <typename PALETTE>
+template <typename PALETTE>
void fill_palette(CRGB* L, uint16_t N, uint8_t startIndex, uint8_t incIndex,
const PALETTE& pal, uint8_t brightness, TBlendType blendType)
{
@@ -780,13 +1025,13 @@ void fill_palette(CRGB* L, uint16_t N, uint8_t startIndex, uint8_t incIndex,
}
template <typename PALETTE>
-void map_data_into_colors_through_palette(
- uint8_t *dataArray, uint16_t dataCount,
- CRGB* targetColorArray,
- const PALETTE& pal,
- uint8_t brightness=255,
- uint8_t opacity=255,
- TBlendType blendType=BLEND)
+void map_data_into_colors_through_palette(
+ uint8_t *dataArray, uint16_t dataCount,
+ CRGB* targetColorArray,
+ const PALETTE& pal,
+ uint8_t brightness=255,
+ uint8_t opacity=255,
+ TBlendType blendType=LINEARBLEND)
{
for( uint16_t i = 0; i < dataCount; i++) {
uint8_t d = dataArray[i];
@@ -801,4 +1046,120 @@ void map_data_into_colors_through_palette(
}
}
+// nblendPaletteTowardPalette:
+// Alter one palette by making it slightly more like
+// a 'target palette', used for palette cross-fades.
+//
+// It does this by comparing each of the R, G, and B channels
+// of each entry in the current palette to the corresponding
+// entry in the target palette and making small adjustments:
+// If the Red channel is too low, it will be increased.
+// If the Red channel is too high, it will be slightly reduced.
+// ... and likewise for Green and Blue channels.
+//
+// Additionally, there are two significant visual improvements
+// to this algorithm implemented here. First is this:
+// When increasing a channel, it is stepped up by ONE.
+// When decreasing a channel, it is stepped down by TWO.
+// Due to the way the eye perceives light, and the way colors
+// are represented in RGB, this produces a more uniform apparent
+// brightness when cross-fading between most palette colors.
+//
+// The second visual tweak is limiting the number of changes
+// that will be made to the palette at once. If all the palette
+// entries are changed at once, it can give a muddled appearance.
+// However, if only a few palette entries are changed at once,
+// you get a visually smoother transition: in the middle of the
+// cross-fade your current palette will actually contain some
+// colors from the old palette, a few blended colors, and some
+// colors from the new palette.
+// The maximum number of possible palette changes per call
+// is 48 (sixteen color entries time three channels each).
+// The default 'maximim number of changes' here is 12, meaning
+// that only approximately a quarter of the palette entries
+// will be changed per call.
+void nblendPaletteTowardPalette( CRGBPalette16& currentPalette,
+ CRGBPalette16& targetPalette,
+ uint8_t maxChanges=24);
+
+
+
+
+// You can also define a static RGB palette very compactly in terms of a series
+// of connected color gradients.
+// For example, if you want the first 3/4ths of the palette to be a slow
+// gradient ramping from black to red, and then the remaining 1/4 of the
+// palette to be a quicker ramp to white, you specify just three points: the
+// starting black point (at index 0), the red midpoint (at index 192),
+// and the final white point (at index 255). It looks like this:
+//
+// index: 0 192 255
+// |----------r-r-r-rrrrrrrrRrRrRrRrRRRR-|-RRWRWWRWWW-|
+// color: (0,0,0) (255,0,0) (255,255,255)
+//
+// Here's how you'd define that gradient palette:
+//
+// DEFINE_GRADIENT_PALETTE( black_to_red_to_white_p ) {
+// 0, 0, 0, 0, /* at index 0, black(0,0,0) */
+// 192, 255, 0, 0, /* at index 192, red(255,0,0) */
+// 255, 255,255,255 /* at index 255, white(255,255,255) */
+// };
+//
+// This format is designed for compact storage. The example palette here
+// takes up just 12 bytes of PROGMEM (flash) storage, and zero bytes
+// of SRAM when not currently in use.
+//
+// To use one of these gradient palettes, simply assign it into a
+// CRGBPalette16 or a CRGBPalette256, like this:
+//
+// CRGBPalette16 pal = black_to_red_to_white_p;
+//
+// When the assignment is made, the gradients are expanded out into
+// either 16 or 256 palette entries, depending on the kind of palette
+// object they're assigned to.
+//
+// IMPORTANT NOTES & CAVEATS:
+//
+// - The last 'index' position MUST BE 255! Failure to end with
+// index 255 will result in program hangs or crashes.
+//
+// - At this point, these gradient palette definitions MUST BE
+// stored in PROGMEM on AVR-based Arduinos. If you use the
+// DEFINE_GRADIENT_PALETTE macro, this is taken care of automatically.
+//
+
+#define DEFINE_GRADIENT_PALETTE(X) \
+ extern const TProgmemRGBGradientPalette_byte X[] FL_PROGMEM =
+
+#define DECLARE_GRADIENT_PALETTE(X) \
+ extern const TProgmemRGBGradientPalette_byte X[] FL_PROGMEM
+
+
+// Functions to apply gamma adjustments, either:
+// - a single gamma adjustment to a single scalar value,
+// - a single gamma adjustment to each channel of a CRGB color, or
+// - different gamma adjustments for each channel of a CRFB color.
+//
+// Note that the gamma is specified as a traditional floating point value
+// e.g., "2.5", and as such these functions should not be called in
+// your innermost pixel loops, or in animations that are extremely
+// low on program storage space. Nevertheless, if you need these
+// functions, here they are.
+//
+// Furthermore, bear in mind that CRGB leds have only eight bits
+// per channel of color resolution, and that very small, subtle shadings
+// may not be visible.
+uint8_t applyGamma_video( uint8_t brightness, float gamma);
+CRGB applyGamma_video( const CRGB& orig, float gamma);
+CRGB applyGamma_video( const CRGB& orig, float gammaR, float gammaG, float gammaB);
+// The "n" versions below modify their arguments in-place.
+CRGB& napplyGamma_video( CRGB& rgb, float gamma);
+CRGB& napplyGamma_video( CRGB& rgb, float gammaR, float gammaG, float gammaB);
+void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gamma);
+void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gammaR, float gammaG, float gammaB);
+
+
+FASTLED_NAMESPACE_END
+
+///@}
#endif