FastLED  3.1
colorutils.h
Go to the documentation of this file.
1 #ifndef __INC_COLORUTILS_H
2 #define __INC_COLORUTILS_H
3 
6 
7 #include "FastLED.h"
8 #include "pixeltypes.h"
9 #include "fastled_progmem.h"
10 
11 FASTLED_NAMESPACE_BEGIN
15 
18 void fill_solid( struct CRGB * leds, int numToFill,
19  const struct CRGB& color);
20 
23 void fill_solid( struct CHSV* targetArray, int numToFill,
24  const struct CHSV& hsvColor);
25 
26 
29 void fill_rainbow( struct CRGB * pFirstLED, int numToFill,
30  uint8_t initialhue,
31  uint8_t deltahue = 5);
32 
35 void fill_rainbow( struct CHSV * targetArray, int numToFill,
36  uint8_t initialhue,
37  uint8_t deltahue = 5);
38 
39 
40 // fill_gradient - fill an array of colors with a smooth HSV gradient
41 // between two specified HSV colors.
42 // Since 'hue' is a value around a color wheel,
43 // there are always two ways to sweep from one hue
44 // to another.
45 // This function lets you specify which way you want
46 // the hue gradient to sweep around the color wheel:
47 // FORWARD_HUES: hue always goes clockwise
48 // BACKWARD_HUES: hue always goes counter-clockwise
49 // SHORTEST_HUES: hue goes whichever way is shortest
50 // LONGEST_HUES: hue goes whichever way is longest
51 // The default is SHORTEST_HUES, as this is nearly
52 // always what is wanted.
53 //
54 // fill_gradient can write the gradient colors EITHER
55 // (1) into an array of CRGBs (e.g., into leds[] array, or an RGB Palette)
56 // OR
57 // (2) into an array of CHSVs (e.g. an HSV Palette).
58 //
59 // In the case of writing into a CRGB array, the gradient is
60 // computed in HSV space, and then HSV values are converted to RGB
61 // as they're written into the RGB array.
62 
63 typedef enum { FORWARD_HUES, BACKWARD_HUES, SHORTEST_HUES, LONGEST_HUES } TGradientDirectionCode;
64 
65 
66 
67 #define saccum87 int16_t
68 
93 template <typename T>
94 void fill_gradient( T* targetArray,
95  uint16_t startpos, CHSV startcolor,
96  uint16_t endpos, CHSV endcolor,
97  TGradientDirectionCode directionCode = SHORTEST_HUES )
98 {
99  // if the points are in the wrong order, straighten them
100  if( endpos < startpos ) {
101  uint16_t t = endpos;
102  CHSV tc = endcolor;
103  endcolor = startcolor;
104  endpos = startpos;
105  startpos = t;
106  startcolor = tc;
107  }
108 
109  // If we're fading toward black (val=0) or white (sat=0),
110  // then set the endhue to the starthue.
111  // This lets us ramp smoothly to black or white, regardless
112  // of what 'hue' was set in the endcolor (since it doesn't matter)
113  if( endcolor.value == 0 || endcolor.saturation == 0) {
114  endcolor.hue = startcolor.hue;
115  }
116 
117  // Similarly, if we're fading in from black (val=0) or white (sat=0)
118  // then set the starthue to the endhue.
119  // This lets us ramp smoothly up from black or white, regardless
120  // of what 'hue' was set in the startcolor (since it doesn't matter)
121  if( startcolor.value == 0 || startcolor.saturation == 0) {
122  startcolor.hue = endcolor.hue;
123  }
124 
125  saccum87 huedistance87;
126  saccum87 satdistance87;
127  saccum87 valdistance87;
128 
129  satdistance87 = (endcolor.sat - startcolor.sat) << 7;
130  valdistance87 = (endcolor.val - startcolor.val) << 7;
131 
132  uint8_t huedelta8 = endcolor.hue - startcolor.hue;
133 
134  if( directionCode == SHORTEST_HUES ) {
135  directionCode = FORWARD_HUES;
136  if( huedelta8 > 127) {
137  directionCode = BACKWARD_HUES;
138  }
139  }
140 
141  if( directionCode == LONGEST_HUES ) {
142  directionCode = FORWARD_HUES;
143  if( huedelta8 < 128) {
144  directionCode = BACKWARD_HUES;
145  }
146  }
147 
148  if( directionCode == FORWARD_HUES) {
149  huedistance87 = huedelta8 << 7;
150  }
151  else /* directionCode == BACKWARD_HUES */
152  {
153  huedistance87 = (uint8_t)(256 - huedelta8) << 7;
154  huedistance87 = -huedistance87;
155  }
156 
157  uint16_t pixeldistance = endpos - startpos;
158  int16_t divisor = pixeldistance ? pixeldistance : 1;
159 
160  saccum87 huedelta87 = huedistance87 / divisor;
161  saccum87 satdelta87 = satdistance87 / divisor;
162  saccum87 valdelta87 = valdistance87 / divisor;
163 
164  huedelta87 *= 2;
165  satdelta87 *= 2;
166  valdelta87 *= 2;
167 
168  accum88 hue88 = startcolor.hue << 8;
169  accum88 sat88 = startcolor.sat << 8;
170  accum88 val88 = startcolor.val << 8;
171  for( uint16_t i = startpos; i <= endpos; i++) {
172  targetArray[i] = CHSV( hue88 >> 8, sat88 >> 8, val88 >> 8);
173  hue88 += huedelta87;
174  sat88 += satdelta87;
175  val88 += valdelta87;
176  }
177 }
178 
179 
180 // Convenience functions to fill an array of colors with a
181 // two-color, three-color, or four-color gradient
182 template <typename T>
183 void fill_gradient( T* targetArray, uint16_t numLeds, const CHSV& c1, const CHSV& c2,
184  TGradientDirectionCode directionCode = SHORTEST_HUES )
185 {
186  uint16_t last = numLeds - 1;
187  fill_gradient( targetArray, 0, c1, last, c2, directionCode);
188 }
189 
190 template <typename T>
191 void fill_gradient( T* targetArray, uint16_t numLeds,
192  const CHSV& c1, const CHSV& c2, const CHSV& c3,
193  TGradientDirectionCode directionCode = SHORTEST_HUES )
194 {
195  uint16_t half = (numLeds / 2);
196  uint16_t last = numLeds - 1;
197  fill_gradient( targetArray, 0, c1, half, c2, directionCode);
198  fill_gradient( targetArray, half, c2, last, c3, directionCode);
199 }
200 
201 template <typename T>
202 void fill_gradient( T* targetArray, uint16_t numLeds,
203  const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4,
204  TGradientDirectionCode directionCode = SHORTEST_HUES )
205 {
206  uint16_t onethird = (numLeds / 3);
207  uint16_t twothirds = ((numLeds * 2) / 3);
208  uint16_t last = numLeds - 1;
209  fill_gradient( targetArray, 0, c1, onethird, c2, directionCode);
210  fill_gradient( targetArray, onethird, c2, twothirds, c3, directionCode);
211  fill_gradient( targetArray, twothirds, c3, last, c4, directionCode);
212 }
213 
214 // convenience synonym
215 #define fill_gradient_HSV fill_gradient
216 
217 
218 // fill_gradient_RGB - fill a range of LEDs with a smooth RGB gradient
219 // between two specified RGB colors.
220 // Unlike HSV, there is no 'color wheel' in RGB space,
221 // and therefore there's only one 'direction' for the
222 // gradient to go, and no 'direction code' is needed.
223 void fill_gradient_RGB( CRGB* leds,
224  uint16_t startpos, CRGB startcolor,
225  uint16_t endpos, CRGB endcolor );
226 void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2);
227 void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2, const CRGB& c3);
228 void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4);
229 
230 
231 // fadeLightBy and fade_video - reduce the brightness of an array
232 // of pixels all at once. Guaranteed
233 // to never fade all the way to black.
234 // (The two names are synonyms.)
235 void fadeLightBy( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
236 void fade_video( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
237 
238 // nscale8_video - scale down the brightness of an array of pixels
239 // all at once. Guaranteed to never scale a pixel
240 // all the way down to black, unless 'scale' is zero.
241 void nscale8_video( CRGB* leds, uint16_t num_leds, uint8_t scale);
242 
243 // fadeToBlackBy and fade_raw - reduce the brightness of an array
244 // of pixels all at once. These
245 // functions will eventually fade all
246 // the way to black.
247 // (The two names are synonyms.)
248 void fadeToBlackBy( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
249 void fade_raw( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
250 
251 // nscale8 - scale down the brightness of an array of pixels
252 // all at once. This function can scale pixels all the
253 // way down to black even if 'scale' is not zero.
254 void nscale8( CRGB* leds, uint16_t num_leds, uint8_t scale);
255 
256 // fadeUsingColor - scale down the brightness of an array of pixels,
257 // as though it were seen through a transparent
258 // filter with the specified color.
259 // For example, if the colormask is
260 // CRGB( 200, 100, 50)
261 // then the pixels' red will be faded to 200/256ths,
262 // their green to 100/256ths, and their blue to 50/256ths.
263 // This particular example give a 'hot fade' look,
264 // with white fading to yellow, then red, then black.
265 // You can also use colormasks like CRGB::Blue to
266 // zero out the red and green elements, leaving blue
267 // (largely) the same.
268 void fadeUsingColor( CRGB* leds, uint16_t numLeds, const CRGB& colormask);
269 
270 
271 // Pixel blending
272 //
273 // blend - computes a new color blended some fraction of the way
274 // between two other colors.
275 CRGB blend( const CRGB& p1, const CRGB& p2, fract8 amountOfP2 );
276 
277 CHSV blend( const CHSV& p1, const CHSV& p2, fract8 amountOfP2,
278  TGradientDirectionCode directionCode = SHORTEST_HUES );
279 
280 // blend - computes a new color blended array of colors, each
281 // a given fraction of the way between corresponding
282 // elements of two source arrays of colors.
283 // Useful for blending palettes.
284 CRGB* blend( const CRGB* src1, const CRGB* src2, CRGB* dest,
285  uint16_t count, fract8 amountOfsrc2 );
286 
287 CHSV* blend( const CHSV* src1, const CHSV* src2, CHSV* dest,
288  uint16_t count, fract8 amountOfsrc2,
289  TGradientDirectionCode directionCode = SHORTEST_HUES );
290 
291 // nblend - destructively modifies one color, blending
292 // in a given fraction of an overlay color
293 CRGB& nblend( CRGB& existing, const CRGB& overlay, fract8 amountOfOverlay );
294 
295 CHSV& nblend( CHSV& existing, const CHSV& overlay, fract8 amountOfOverlay,
296  TGradientDirectionCode directionCode = SHORTEST_HUES );
297 
298 // nblend - destructively blends a given fraction of
299 // a new color array into an existing color array
300 void nblend( CRGB* existing, CRGB* overlay, uint16_t count, fract8 amountOfOverlay);
301 
302 void nblend( CHSV* existing, CHSV* overlay, uint16_t count, fract8 amountOfOverlay,
303  TGradientDirectionCode directionCode = SHORTEST_HUES);
304 
305 
306 // blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors.
307 // blur2d: two-dimensional blur filter. Spreads light to 8 XY neighbors.
308 //
309 // 0 = no spread at all
310 // 64 = moderate spreading
311 // 172 = maximum smooth, even spreading
312 //
313 // 173..255 = wider spreading, but increasing flicker
314 //
315 // Total light is NOT entirely conserved, so many repeated
316 // calls to 'blur' will also result in the light fading,
317 // eventually all the way to black; this is by design so that
318 // it can be used to (slowly) clear the LEDs to black.
319 void blur1d( CRGB* leds, uint16_t numLeds, fract8 blur_amount);
320 void blur2d( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
321 
322 // blurRows: perform a blur1d on every row of a rectangular matrix
323 void blurRows( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
324 // blurColumns: perform a blur1d on each column of a rectangular matrix
325 void blurColumns(CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
326 
327 
328 // CRGB HeatColor( uint8_t temperature)
329 //
330 // Approximates a 'black body radiation' spectrum for
331 // a given 'heat' level. This is useful for animations of 'fire'.
332 // Heat is specified as an arbitrary scale from 0 (cool) to 255 (hot).
333 // This is NOT a chromatically correct 'black body radiation'
334 // spectrum, but it's surprisingly close, and it's fast and small.
335 CRGB HeatColor( uint8_t temperature);
336 
337 
338 // Palettes
339 //
340 // RGB Palettes map an 8-bit value (0..255) to an RGB color.
341 //
342 // You can create any color palette you wish; a couple of starters
343 // are provided: Forest, Clouds, Lava, Ocean, Rainbow, and Rainbow Stripes.
344 //
345 // Palettes come in the traditional 256-entry variety, which take
346 // up 768 bytes of RAM, and lightweight 16-entry varieties. The 16-entry
347 // variety automatically interpolates between its entries to produce
348 // a full 256-element color map, but at a cost of only 48 bytes or RAM.
349 //
350 // Basic operation is like this: (example shows the 16-entry variety)
351 // 1. Declare your palette storage:
352 // CRGBPalette16 myPalette;
353 //
354 // 2. Fill myPalette with your own 16 colors, or with a preset color scheme.
355 // You can specify your 16 colors a variety of ways:
356 // CRGBPalette16 myPalette(
357 // CRGB::Black,
358 // CRGB::Black,
359 // CRGB::Red,
360 // CRGB::Yellow,
361 // CRGB::Green,
362 // CRGB::Blue,
363 // CRGB::Purple,
364 // CRGB::Black,
365 //
366 // 0x100000,
367 // 0x200000,
368 // 0x400000,
369 // 0x800000,
370 //
371 // CHSV( 30,255,255),
372 // CHSV( 50,255,255),
373 // CHSV( 70,255,255),
374 // CHSV( 90,255,255)
375 // );
376 //
377 // Or you can initiaize your palette with a preset color scheme:
378 // myPalette = RainbowStripesColors_p;
379 //
380 // 3. Any time you want to set a pixel to a color from your palette, use
381 // "ColorFromPalette(...)" as shown:
382 //
383 // uint8_t index = /* any value 0..255 */;
384 // leds[i] = ColorFromPalette( myPalette, index);
385 //
386 // Even though your palette has only 16 explicily defined entries, you
387 // can use an 'index' from 0..255. The 16 explicit palette entries will
388 // be spread evenly across the 0..255 range, and the intermedate values
389 // will be RGB-interpolated between adjacent explicit entries.
390 //
391 // It's easier to use than it sounds.
392 //
393 
394 class CRGBPalette16;
395 class CRGBPalette32;
396 class CRGBPalette256;
397 class CHSVPalette16;
398 class CHSVPalette32;
399 class CHSVPalette256;
400 typedef uint32_t TProgmemRGBPalette16[16];
401 typedef uint32_t TProgmemHSVPalette16[16];
402 #define TProgmemPalette16 TProgmemRGBPalette16
403 typedef uint32_t TProgmemRGBPalette32[32];
404 typedef uint32_t TProgmemHSVPalette32[32];
405 #define TProgmemPalette32 TProgmemRGBPalette32
406 
407 typedef const uint8_t TProgmemRGBGradientPalette_byte ;
408 typedef const TProgmemRGBGradientPalette_byte *TProgmemRGBGradientPalette_bytes;
409 typedef TProgmemRGBGradientPalette_bytes TProgmemRGBGradientPalettePtr;
410 typedef union {
411  struct {
412  uint8_t index;
413  uint8_t r;
414  uint8_t g;
415  uint8_t b;
416  };
417  uint32_t dword;
418  uint8_t bytes[4];
420 
421 typedef uint8_t TDynamicRGBGradientPalette_byte ;
422 typedef const TDynamicRGBGradientPalette_byte *TDynamicRGBGradientPalette_bytes;
423 typedef TDynamicRGBGradientPalette_bytes TDynamicRGBGradientPalettePtr;
424 
425 // Convert a 16-entry palette to a 256-entry palette
426 void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette256& destpal256);
427 void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette256& destpal256);
428 
429 // Convert a 16-entry palette to a 32-entry palette
430 void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette32& destpal32);
431 void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette32& destpal32);
432 
433 // Convert a 32-entry palette to a 256-entry palette
434 void UpscalePalette(const struct CRGBPalette32& srcpal32, struct CRGBPalette256& destpal256);
435 void UpscalePalette(const struct CHSVPalette32& srcpal32, struct CHSVPalette256& destpal256);
436 
437 
439 public:
440  CHSV entries[16];
441  CHSVPalette16() {};
442  CHSVPalette16( const CHSV& c00,const CHSV& c01,const CHSV& c02,const CHSV& c03,
443  const CHSV& c04,const CHSV& c05,const CHSV& c06,const CHSV& c07,
444  const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11,
445  const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 )
446  {
447  entries[0]=c00; entries[1]=c01; entries[2]=c02; entries[3]=c03;
448  entries[4]=c04; entries[5]=c05; entries[6]=c06; entries[7]=c07;
449  entries[8]=c08; entries[9]=c09; entries[10]=c10; entries[11]=c11;
450  entries[12]=c12; entries[13]=c13; entries[14]=c14; entries[15]=c15;
451  };
452 
453  CHSVPalette16( const CHSVPalette16& rhs)
454  {
455  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
456  }
457  CHSVPalette16& operator=( const CHSVPalette16& rhs)
458  {
459  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
460  return *this;
461  }
462 
463  CHSVPalette16( const TProgmemHSVPalette16& rhs)
464  {
465  for( uint8_t i = 0; i < 16; i++) {
466  CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
467  entries[i].hue = xyz.red;
468  entries[i].sat = xyz.green;
469  entries[i].val = xyz.blue;
470  }
471  }
472  CHSVPalette16& operator=( const TProgmemHSVPalette16& rhs)
473  {
474  for( uint8_t i = 0; i < 16; i++) {
475  CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
476  entries[i].hue = xyz.red;
477  entries[i].sat = xyz.green;
478  entries[i].val = xyz.blue;
479  }
480  return *this;
481  }
482 
483  inline CHSV& operator[] (uint8_t x) __attribute__((always_inline))
484  {
485  return entries[x];
486  }
487  inline const CHSV& operator[] (uint8_t x) const __attribute__((always_inline))
488  {
489  return entries[x];
490  }
491 
492  inline CHSV& operator[] (int x) __attribute__((always_inline))
493  {
494  return entries[(uint8_t)x];
495  }
496  inline const CHSV& operator[] (int x) const __attribute__((always_inline))
497  {
498  return entries[(uint8_t)x];
499  }
500 
501  operator CHSV*()
502  {
503  return &(entries[0]);
504  }
505 
506  bool operator==( const CHSVPalette16 rhs)
507  {
508  const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
509  const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
510  if( p == q) return true;
511  for( uint8_t i = 0; i < (sizeof( entries)); i++) {
512  if( *p != *q) return false;
513  p++;
514  q++;
515  }
516  return true;
517  }
518  bool operator!=( const CHSVPalette16 rhs)
519  {
520  return !( *this == rhs);
521  }
522 
523  CHSVPalette16( const CHSV& c1)
524  {
525  fill_solid( &(entries[0]), 16, c1);
526  }
527  CHSVPalette16( const CHSV& c1, const CHSV& c2)
528  {
529  fill_gradient( &(entries[0]), 16, c1, c2);
530  }
531  CHSVPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3)
532  {
533  fill_gradient( &(entries[0]), 16, c1, c2, c3);
534  }
535  CHSVPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
536  {
537  fill_gradient( &(entries[0]), 16, c1, c2, c3, c4);
538  }
539 
540 };
541 
543 public:
544  CHSV entries[256];
545  CHSVPalette256() {};
546  CHSVPalette256( const CHSV& c00,const CHSV& c01,const CHSV& c02,const CHSV& c03,
547  const CHSV& c04,const CHSV& c05,const CHSV& c06,const CHSV& c07,
548  const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11,
549  const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 )
550  {
551  CHSVPalette16 p16(c00,c01,c02,c03,c04,c05,c06,c07,
552  c08,c09,c10,c11,c12,c13,c14,c15);
553  *this = p16;
554  };
555 
556  CHSVPalette256( const CHSVPalette256& rhs)
557  {
558  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
559  }
560  CHSVPalette256& operator=( const CHSVPalette256& rhs)
561  {
562  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
563  return *this;
564  }
565 
566  CHSVPalette256( const CHSVPalette16& rhs16)
567  {
568  UpscalePalette( rhs16, *this);
569  }
570  CHSVPalette256& operator=( const CHSVPalette16& rhs16)
571  {
572  UpscalePalette( rhs16, *this);
573  return *this;
574  }
575 
576  CHSVPalette256( const TProgmemRGBPalette16& rhs)
577  {
578  CHSVPalette16 p16(rhs);
579  *this = p16;
580  }
581  CHSVPalette256& operator=( const TProgmemRGBPalette16& rhs)
582  {
583  CHSVPalette16 p16(rhs);
584  *this = p16;
585  return *this;
586  }
587 
588  inline CHSV& operator[] (uint8_t x) __attribute__((always_inline))
589  {
590  return entries[x];
591  }
592  inline const CHSV& operator[] (uint8_t x) const __attribute__((always_inline))
593  {
594  return entries[x];
595  }
596 
597  inline CHSV& operator[] (int x) __attribute__((always_inline))
598  {
599  return entries[(uint8_t)x];
600  }
601  inline const CHSV& operator[] (int x) const __attribute__((always_inline))
602  {
603  return entries[(uint8_t)x];
604  }
605 
606  operator CHSV*()
607  {
608  return &(entries[0]);
609  }
610 
611  bool operator==( const CHSVPalette256 rhs)
612  {
613  const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
614  const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
615  if( p == q) return true;
616  for( uint16_t i = 0; i < (sizeof( entries)); i++) {
617  if( *p != *q) return false;
618  p++;
619  q++;
620  }
621  return true;
622  }
623  bool operator!=( const CHSVPalette256 rhs)
624  {
625  return !( *this == rhs);
626  }
627 
628  CHSVPalette256( const CHSV& c1)
629  {
630  fill_solid( &(entries[0]), 256, c1);
631  }
632  CHSVPalette256( const CHSV& c1, const CHSV& c2)
633  {
634  fill_gradient( &(entries[0]), 256, c1, c2);
635  }
636  CHSVPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3)
637  {
638  fill_gradient( &(entries[0]), 256, c1, c2, c3);
639  }
640  CHSVPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
641  {
642  fill_gradient( &(entries[0]), 256, c1, c2, c3, c4);
643  }
644 };
645 
647 public:
648  CRGB entries[16];
649  CRGBPalette16() {};
650  CRGBPalette16( const CRGB& c00,const CRGB& c01,const CRGB& c02,const CRGB& c03,
651  const CRGB& c04,const CRGB& c05,const CRGB& c06,const CRGB& c07,
652  const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11,
653  const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 )
654  {
655  entries[0]=c00; entries[1]=c01; entries[2]=c02; entries[3]=c03;
656  entries[4]=c04; entries[5]=c05; entries[6]=c06; entries[7]=c07;
657  entries[8]=c08; entries[9]=c09; entries[10]=c10; entries[11]=c11;
658  entries[12]=c12; entries[13]=c13; entries[14]=c14; entries[15]=c15;
659  };
660 
661  CRGBPalette16( const CRGBPalette16& rhs)
662  {
663  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
664  }
665  CRGBPalette16( const CRGB rhs[16])
666  {
667  memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
668  }
669  CRGBPalette16& operator=( const CRGBPalette16& rhs)
670  {
671  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
672  return *this;
673  }
674  CRGBPalette16& operator=( const CRGB rhs[16])
675  {
676  memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
677  return *this;
678  }
679 
680  CRGBPalette16( const CHSVPalette16& rhs)
681  {
682  for( uint8_t i = 0; i < 16; i++) {
683  entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
684  }
685  }
686  CRGBPalette16( const CHSV rhs[16])
687  {
688  for( uint8_t i = 0; i < 16; i++) {
689  entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
690  }
691  }
692  CRGBPalette16& operator=( const CHSVPalette16& rhs)
693  {
694  for( uint8_t i = 0; i < 16; i++) {
695  entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
696  }
697  return *this;
698  }
699  CRGBPalette16& operator=( const CHSV rhs[16])
700  {
701  for( uint8_t i = 0; i < 16; i++) {
702  entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
703  }
704  return *this;
705  }
706 
707  CRGBPalette16( const TProgmemRGBPalette16& rhs)
708  {
709  for( uint8_t i = 0; i < 16; i++) {
710  entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
711  }
712  }
713  CRGBPalette16& operator=( const TProgmemRGBPalette16& rhs)
714  {
715  for( uint8_t i = 0; i < 16; i++) {
716  entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
717  }
718  return *this;
719  }
720 
721  bool operator==( const CRGBPalette16 rhs)
722  {
723  const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
724  const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
725  if( p == q) return true;
726  for( uint8_t i = 0; i < (sizeof( entries)); i++) {
727  if( *p != *q) return false;
728  p++;
729  q++;
730  }
731  return true;
732  }
733  bool operator!=( const CRGBPalette16 rhs)
734  {
735  return !( *this == rhs);
736  }
737 
738  inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
739  {
740  return entries[x];
741  }
742  inline const CRGB& operator[] (uint8_t x) const __attribute__((always_inline))
743  {
744  return entries[x];
745  }
746 
747  inline CRGB& operator[] (int x) __attribute__((always_inline))
748  {
749  return entries[(uint8_t)x];
750  }
751  inline const CRGB& operator[] (int x) const __attribute__((always_inline))
752  {
753  return entries[(uint8_t)x];
754  }
755 
756  operator CRGB*()
757  {
758  return &(entries[0]);
759  }
760 
761  CRGBPalette16( const CHSV& c1)
762  {
763  fill_solid( &(entries[0]), 16, c1);
764  }
765  CRGBPalette16( const CHSV& c1, const CHSV& c2)
766  {
767  fill_gradient( &(entries[0]), 16, c1, c2);
768  }
769  CRGBPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3)
770  {
771  fill_gradient( &(entries[0]), 16, c1, c2, c3);
772  }
773  CRGBPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
774  {
775  fill_gradient( &(entries[0]), 16, c1, c2, c3, c4);
776  }
777 
778  CRGBPalette16( const CRGB& c1)
779  {
780  fill_solid( &(entries[0]), 16, c1);
781  }
782  CRGBPalette16( const CRGB& c1, const CRGB& c2)
783  {
784  fill_gradient_RGB( &(entries[0]), 16, c1, c2);
785  }
786  CRGBPalette16( const CRGB& c1, const CRGB& c2, const CRGB& c3)
787  {
788  fill_gradient_RGB( &(entries[0]), 16, c1, c2, c3);
789  }
790  CRGBPalette16( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
791  {
792  fill_gradient_RGB( &(entries[0]), 16, c1, c2, c3, c4);
793  }
794 
795 
796  // Gradient palettes are loaded into CRGB16Palettes in such a way
797  // that, if possible, every color represented in the gradient palette
798  // is also represented in the CRGBPalette16.
799  // For example, consider a gradient palette that is all black except
800  // for a single, one-element-wide (1/256th!) spike of red in the middle:
801  // 0, 0,0,0
802  // 124, 0,0,0
803  // 125, 255,0,0 // one 1/256th-palette-wide red stripe
804  // 126, 0,0,0
805  // 255, 0,0,0
806  // A naive conversion of this 256-element palette to a 16-element palette
807  // might accidentally completely eliminate the red spike, rendering the
808  // palette completely black.
809  // However, the conversions provided here would attempt to include a
810  // the red stripe in the output, more-or-less as faithfully as possible.
811  // So in this case, the resulting CRGBPalette16 palette would have a red
812  // stripe in the middle which was 1/16th of a palette wide -- the
813  // narrowest possible in a CRGBPalette16.
814  // This means that the relative width of stripes in a CRGBPalette16
815  // will be, by definition, different from the widths in the gradient
816  // palette. This code attempts to preserve "all the colors", rather than
817  // the exact stripe widths at the expense of dropping some colors.
818  CRGBPalette16( TProgmemRGBGradientPalette_bytes progpal )
819  {
820  *this = progpal;
821  }
822  CRGBPalette16& operator=( TProgmemRGBGradientPalette_bytes progpal )
823  {
826 
827  // Count entries
828  uint8_t count = 0;
829  do {
830  u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
831  count++;;
832  } while ( u.index != 255);
833 
834  int8_t lastSlotUsed = -1;
835 
836  u.dword = FL_PGM_READ_DWORD_NEAR( progent);
837  CRGB rgbstart( u.r, u.g, u.b);
838 
839  int indexstart = 0;
840  uint8_t istart8 = 0;
841  uint8_t iend8 = 0;
842  while( indexstart < 255) {
843  progent++;
844  u.dword = FL_PGM_READ_DWORD_NEAR( progent);
845  int indexend = u.index;
846  CRGB rgbend( u.r, u.g, u.b);
847  istart8 = indexstart / 16;
848  iend8 = indexend / 16;
849  if( count < 16) {
850  if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
851  istart8 = lastSlotUsed + 1;
852  if( iend8 < istart8) {
853  iend8 = istart8;
854  }
855  }
856  lastSlotUsed = iend8;
857  }
858  fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
859  indexstart = indexend;
860  rgbstart = rgbend;
861  }
862  return *this;
863  }
864  CRGBPalette16& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal )
865  {
868 
869  // Count entries
870  uint8_t count = 0;
871  do {
872  u = *(ent + count);
873  count++;;
874  } while ( u.index != 255);
875 
876  int8_t lastSlotUsed = -1;
877 
878 
879  u = *ent;
880  CRGB rgbstart( u.r, u.g, u.b);
881 
882  int indexstart = 0;
883  uint8_t istart8 = 0;
884  uint8_t iend8 = 0;
885  while( indexstart < 255) {
886  ent++;
887  u = *ent;
888  int indexend = u.index;
889  CRGB rgbend( u.r, u.g, u.b);
890  istart8 = indexstart / 16;
891  iend8 = indexend / 16;
892  if( count < 16) {
893  if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
894  istart8 = lastSlotUsed + 1;
895  if( iend8 < istart8) {
896  iend8 = istart8;
897  }
898  }
899  lastSlotUsed = iend8;
900  }
901  fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
902  indexstart = indexend;
903  rgbstart = rgbend;
904  }
905  return *this;
906  }
907 
908 };
909 
910 
911 
913 public:
914  CHSV entries[32];
915  CHSVPalette32() {};
916  CHSVPalette32( const CHSV& c00,const CHSV& c01,const CHSV& c02,const CHSV& c03,
917  const CHSV& c04,const CHSV& c05,const CHSV& c06,const CHSV& c07,
918  const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11,
919  const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 )
920  {
921  for( uint8_t i = 0; i < 2; i++) {
922  entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03;
923  entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07;
924  entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11;
925  entries[24+i]=c12; entries[26+i]=c13; entries[28+i]=c14; entries[30+i]=c15;
926  }
927  };
928 
929  CHSVPalette32( const CHSVPalette32& rhs)
930  {
931  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
932  }
933  CHSVPalette32& operator=( const CHSVPalette32& rhs)
934  {
935  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
936  return *this;
937  }
938 
939  CHSVPalette32( const TProgmemHSVPalette32& rhs)
940  {
941  for( uint8_t i = 0; i < 32; i++) {
942  CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
943  entries[i].hue = xyz.red;
944  entries[i].sat = xyz.green;
945  entries[i].val = xyz.blue;
946  }
947  }
948  CHSVPalette32& operator=( const TProgmemHSVPalette32& rhs)
949  {
950  for( uint8_t i = 0; i < 32; i++) {
951  CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
952  entries[i].hue = xyz.red;
953  entries[i].sat = xyz.green;
954  entries[i].val = xyz.blue;
955  }
956  return *this;
957  }
958 
959  inline CHSV& operator[] (uint8_t x) __attribute__((always_inline))
960  {
961  return entries[x];
962  }
963  inline const CHSV& operator[] (uint8_t x) const __attribute__((always_inline))
964  {
965  return entries[x];
966  }
967 
968  inline CHSV& operator[] (int x) __attribute__((always_inline))
969  {
970  return entries[(uint8_t)x];
971  }
972  inline const CHSV& operator[] (int x) const __attribute__((always_inline))
973  {
974  return entries[(uint8_t)x];
975  }
976 
977  operator CHSV*()
978  {
979  return &(entries[0]);
980  }
981 
982  bool operator==( const CHSVPalette32 rhs)
983  {
984  const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
985  const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
986  if( p == q) return true;
987  for( uint8_t i = 0; i < (sizeof( entries)); i++) {
988  if( *p != *q) return false;
989  p++;
990  q++;
991  }
992  return true;
993  }
994  bool operator!=( const CHSVPalette32 rhs)
995  {
996  return !( *this == rhs);
997  }
998 
999  CHSVPalette32( const CHSV& c1)
1000  {
1001  fill_solid( &(entries[0]), 32, c1);
1002  }
1003  CHSVPalette32( const CHSV& c1, const CHSV& c2)
1004  {
1005  fill_gradient( &(entries[0]), 32, c1, c2);
1006  }
1007  CHSVPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3)
1008  {
1009  fill_gradient( &(entries[0]), 32, c1, c2, c3);
1010  }
1011  CHSVPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
1012  {
1013  fill_gradient( &(entries[0]), 32, c1, c2, c3, c4);
1014  }
1015 
1016 };
1017 
1019 public:
1020  CRGB entries[32];
1021  CRGBPalette32() {};
1022  CRGBPalette32( const CRGB& c00,const CRGB& c01,const CRGB& c02,const CRGB& c03,
1023  const CRGB& c04,const CRGB& c05,const CRGB& c06,const CRGB& c07,
1024  const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11,
1025  const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 )
1026  {
1027  for( uint8_t i = 0; i < 2; i++) {
1028  entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03;
1029  entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07;
1030  entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11;
1031  entries[24+i]=c12; entries[26+i]=c13; entries[28+i]=c14; entries[30+i]=c15;
1032  }
1033  };
1034 
1035  CRGBPalette32( const CRGBPalette32& rhs)
1036  {
1037  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
1038  }
1039  CRGBPalette32( const CRGB rhs[32])
1040  {
1041  memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
1042  }
1043  CRGBPalette32& operator=( const CRGBPalette32& rhs)
1044  {
1045  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
1046  return *this;
1047  }
1048  CRGBPalette32& operator=( const CRGB rhs[32])
1049  {
1050  memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
1051  return *this;
1052  }
1053 
1054  CRGBPalette32( const CHSVPalette32& rhs)
1055  {
1056  for( uint8_t i = 0; i < 32; i++) {
1057  entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
1058  }
1059  }
1060  CRGBPalette32( const CHSV rhs[32])
1061  {
1062  for( uint8_t i = 0; i < 32; i++) {
1063  entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
1064  }
1065  }
1066  CRGBPalette32& operator=( const CHSVPalette32& rhs)
1067  {
1068  for( uint8_t i = 0; i < 32; i++) {
1069  entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
1070  }
1071  return *this;
1072  }
1073  CRGBPalette32& operator=( const CHSV rhs[32])
1074  {
1075  for( uint8_t i = 0; i < 32; i++) {
1076  entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
1077  }
1078  return *this;
1079  }
1080 
1081  CRGBPalette32( const TProgmemRGBPalette32& rhs)
1082  {
1083  for( uint8_t i = 0; i < 32; i++) {
1084  entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
1085  }
1086  }
1087  CRGBPalette32& operator=( const TProgmemRGBPalette32& rhs)
1088  {
1089  for( uint8_t i = 0; i < 32; i++) {
1090  entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
1091  }
1092  return *this;
1093  }
1094 
1095  bool operator==( const CRGBPalette32 rhs)
1096  {
1097  const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
1098  const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
1099  if( p == q) return true;
1100  for( uint8_t i = 0; i < (sizeof( entries)); i++) {
1101  if( *p != *q) return false;
1102  p++;
1103  q++;
1104  }
1105  return true;
1106  }
1107  bool operator!=( const CRGBPalette32 rhs)
1108  {
1109  return !( *this == rhs);
1110  }
1111 
1112  inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
1113  {
1114  return entries[x];
1115  }
1116  inline const CRGB& operator[] (uint8_t x) const __attribute__((always_inline))
1117  {
1118  return entries[x];
1119  }
1120 
1121  inline CRGB& operator[] (int x) __attribute__((always_inline))
1122  {
1123  return entries[(uint8_t)x];
1124  }
1125  inline const CRGB& operator[] (int x) const __attribute__((always_inline))
1126  {
1127  return entries[(uint8_t)x];
1128  }
1129 
1130  operator CRGB*()
1131  {
1132  return &(entries[0]);
1133  }
1134 
1135  CRGBPalette32( const CHSV& c1)
1136  {
1137  fill_solid( &(entries[0]), 32, c1);
1138  }
1139  CRGBPalette32( const CHSV& c1, const CHSV& c2)
1140  {
1141  fill_gradient( &(entries[0]), 32, c1, c2);
1142  }
1143  CRGBPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3)
1144  {
1145  fill_gradient( &(entries[0]), 32, c1, c2, c3);
1146  }
1147  CRGBPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
1148  {
1149  fill_gradient( &(entries[0]), 32, c1, c2, c3, c4);
1150  }
1151 
1152  CRGBPalette32( const CRGB& c1)
1153  {
1154  fill_solid( &(entries[0]), 32, c1);
1155  }
1156  CRGBPalette32( const CRGB& c1, const CRGB& c2)
1157  {
1158  fill_gradient_RGB( &(entries[0]), 32, c1, c2);
1159  }
1160  CRGBPalette32( const CRGB& c1, const CRGB& c2, const CRGB& c3)
1161  {
1162  fill_gradient_RGB( &(entries[0]), 32, c1, c2, c3);
1163  }
1164  CRGBPalette32( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
1165  {
1166  fill_gradient_RGB( &(entries[0]), 32, c1, c2, c3, c4);
1167  }
1168 
1169 
1170  CRGBPalette32( const CRGBPalette16& rhs16)
1171  {
1172  UpscalePalette( rhs16, *this);
1173  }
1174  CRGBPalette32& operator=( const CRGBPalette16& rhs16)
1175  {
1176  UpscalePalette( rhs16, *this);
1177  return *this;
1178  }
1179 
1180  CRGBPalette32( const TProgmemRGBPalette16& rhs)
1181  {
1182  CRGBPalette16 p16(rhs);
1183  *this = p16;
1184  }
1185  CRGBPalette32& operator=( const TProgmemRGBPalette16& rhs)
1186  {
1187  CRGBPalette16 p16(rhs);
1188  *this = p16;
1189  return *this;
1190  }
1191 
1192 
1193  // Gradient palettes are loaded into CRGB16Palettes in such a way
1194  // that, if possible, every color represented in the gradient palette
1195  // is also represented in the CRGBPalette32.
1196  // For example, consider a gradient palette that is all black except
1197  // for a single, one-element-wide (1/256th!) spike of red in the middle:
1198  // 0, 0,0,0
1199  // 124, 0,0,0
1200  // 125, 255,0,0 // one 1/256th-palette-wide red stripe
1201  // 126, 0,0,0
1202  // 255, 0,0,0
1203  // A naive conversion of this 256-element palette to a 16-element palette
1204  // might accidentally completely eliminate the red spike, rendering the
1205  // palette completely black.
1206  // However, the conversions provided here would attempt to include a
1207  // the red stripe in the output, more-or-less as faithfully as possible.
1208  // So in this case, the resulting CRGBPalette32 palette would have a red
1209  // stripe in the middle which was 1/16th of a palette wide -- the
1210  // narrowest possible in a CRGBPalette32.
1211  // This means that the relative width of stripes in a CRGBPalette32
1212  // will be, by definition, different from the widths in the gradient
1213  // palette. This code attempts to preserve "all the colors", rather than
1214  // the exact stripe widths at the expense of dropping some colors.
1215  CRGBPalette32( TProgmemRGBGradientPalette_bytes progpal )
1216  {
1217  *this = progpal;
1218  }
1219  CRGBPalette32& operator=( TProgmemRGBGradientPalette_bytes progpal )
1220  {
1223 
1224  // Count entries
1225  uint8_t count = 0;
1226  do {
1227  u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
1228  count++;;
1229  } while ( u.index != 255);
1230 
1231  int8_t lastSlotUsed = -1;
1232 
1233  u.dword = FL_PGM_READ_DWORD_NEAR( progent);
1234  CRGB rgbstart( u.r, u.g, u.b);
1235 
1236  int indexstart = 0;
1237  uint8_t istart8 = 0;
1238  uint8_t iend8 = 0;
1239  while( indexstart < 255) {
1240  progent++;
1241  u.dword = FL_PGM_READ_DWORD_NEAR( progent);
1242  int indexend = u.index;
1243  CRGB rgbend( u.r, u.g, u.b);
1244  istart8 = indexstart / 8;
1245  iend8 = indexend / 8;
1246  if( count < 16) {
1247  if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1248  istart8 = lastSlotUsed + 1;
1249  if( iend8 < istart8) {
1250  iend8 = istart8;
1251  }
1252  }
1253  lastSlotUsed = iend8;
1254  }
1255  fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
1256  indexstart = indexend;
1257  rgbstart = rgbend;
1258  }
1259  return *this;
1260  }
1261  CRGBPalette32& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal )
1262  {
1265 
1266  // Count entries
1267  uint8_t count = 0;
1268  do {
1269  u = *(ent + count);
1270  count++;;
1271  } while ( u.index != 255);
1272 
1273  int8_t lastSlotUsed = -1;
1274 
1275 
1276  u = *ent;
1277  CRGB rgbstart( u.r, u.g, u.b);
1278 
1279  int indexstart = 0;
1280  uint8_t istart8 = 0;
1281  uint8_t iend8 = 0;
1282  while( indexstart < 255) {
1283  ent++;
1284  u = *ent;
1285  int indexend = u.index;
1286  CRGB rgbend( u.r, u.g, u.b);
1287  istart8 = indexstart / 8;
1288  iend8 = indexend / 8;
1289  if( count < 16) {
1290  if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1291  istart8 = lastSlotUsed + 1;
1292  if( iend8 < istart8) {
1293  iend8 = istart8;
1294  }
1295  }
1296  lastSlotUsed = iend8;
1297  }
1298  fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
1299  indexstart = indexend;
1300  rgbstart = rgbend;
1301  }
1302  return *this;
1303  }
1304 
1305 };
1306 
1307 
1308 
1310 public:
1311  CRGB entries[256];
1312  CRGBPalette256() {};
1313  CRGBPalette256( const CRGB& c00,const CRGB& c01,const CRGB& c02,const CRGB& c03,
1314  const CRGB& c04,const CRGB& c05,const CRGB& c06,const CRGB& c07,
1315  const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11,
1316  const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 )
1317  {
1318  CRGBPalette16 p16(c00,c01,c02,c03,c04,c05,c06,c07,
1319  c08,c09,c10,c11,c12,c13,c14,c15);
1320  *this = p16;
1321  };
1322 
1323  CRGBPalette256( const CRGBPalette256& rhs)
1324  {
1325  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
1326  }
1327  CRGBPalette256( const CRGB rhs[256])
1328  {
1329  memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
1330  }
1331  CRGBPalette256& operator=( const CRGBPalette256& rhs)
1332  {
1333  memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
1334  return *this;
1335  }
1336  CRGBPalette256& operator=( const CRGB rhs[256])
1337  {
1338  memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
1339  return *this;
1340  }
1341 
1342  CRGBPalette256( const CHSVPalette256& rhs)
1343  {
1344  for( int i = 0; i < 256; i++) {
1345  entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
1346  }
1347  }
1348  CRGBPalette256( const CHSV rhs[256])
1349  {
1350  for( int i = 0; i < 256; i++) {
1351  entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
1352  }
1353  }
1354  CRGBPalette256& operator=( const CHSVPalette256& rhs)
1355  {
1356  for( int i = 0; i < 256; i++) {
1357  entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
1358  }
1359  return *this;
1360  }
1361  CRGBPalette256& operator=( const CHSV rhs[256])
1362  {
1363  for( int i = 0; i < 256; i++) {
1364  entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
1365  }
1366  return *this;
1367  }
1368 
1369  CRGBPalette256( const CRGBPalette16& rhs16)
1370  {
1371  UpscalePalette( rhs16, *this);
1372  }
1373  CRGBPalette256& operator=( const CRGBPalette16& rhs16)
1374  {
1375  UpscalePalette( rhs16, *this);
1376  return *this;
1377  }
1378 
1379  CRGBPalette256( const TProgmemRGBPalette16& rhs)
1380  {
1381  CRGBPalette16 p16(rhs);
1382  *this = p16;
1383  }
1384  CRGBPalette256& operator=( const TProgmemRGBPalette16& rhs)
1385  {
1386  CRGBPalette16 p16(rhs);
1387  *this = p16;
1388  return *this;
1389  }
1390 
1391  bool operator==( const CRGBPalette256 rhs)
1392  {
1393  const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
1394  const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
1395  if( p == q) return true;
1396  for( uint16_t i = 0; i < (sizeof( entries)); i++) {
1397  if( *p != *q) return false;
1398  p++;
1399  q++;
1400  }
1401  return true;
1402  }
1403  bool operator!=( const CRGBPalette256 rhs)
1404  {
1405  return !( *this == rhs);
1406  }
1407 
1408  inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
1409  {
1410  return entries[x];
1411  }
1412  inline const CRGB& operator[] (uint8_t x) const __attribute__((always_inline))
1413  {
1414  return entries[x];
1415  }
1416 
1417  inline CRGB& operator[] (int x) __attribute__((always_inline))
1418  {
1419  return entries[(uint8_t)x];
1420  }
1421  inline const CRGB& operator[] (int x) const __attribute__((always_inline))
1422  {
1423  return entries[(uint8_t)x];
1424  }
1425 
1426  operator CRGB*()
1427  {
1428  return &(entries[0]);
1429  }
1430 
1431  CRGBPalette256( const CHSV& c1)
1432  {
1433  fill_solid( &(entries[0]), 256, c1);
1434  }
1435  CRGBPalette256( const CHSV& c1, const CHSV& c2)
1436  {
1437  fill_gradient( &(entries[0]), 256, c1, c2);
1438  }
1439  CRGBPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3)
1440  {
1441  fill_gradient( &(entries[0]), 256, c1, c2, c3);
1442  }
1443  CRGBPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
1444  {
1445  fill_gradient( &(entries[0]), 256, c1, c2, c3, c4);
1446  }
1447 
1448  CRGBPalette256( const CRGB& c1)
1449  {
1450  fill_solid( &(entries[0]), 256, c1);
1451  }
1452  CRGBPalette256( const CRGB& c1, const CRGB& c2)
1453  {
1454  fill_gradient_RGB( &(entries[0]), 256, c1, c2);
1455  }
1456  CRGBPalette256( const CRGB& c1, const CRGB& c2, const CRGB& c3)
1457  {
1458  fill_gradient_RGB( &(entries[0]), 256, c1, c2, c3);
1459  }
1460  CRGBPalette256( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
1461  {
1462  fill_gradient_RGB( &(entries[0]), 256, c1, c2, c3, c4);
1463  }
1464 
1465  CRGBPalette256( TProgmemRGBGradientPalette_bytes progpal )
1466  {
1467  *this = progpal;
1468  }
1469  CRGBPalette256& operator=( TProgmemRGBGradientPalette_bytes progpal )
1470  {
1473  u.dword = FL_PGM_READ_DWORD_NEAR( progent);
1474  CRGB rgbstart( u.r, u.g, u.b);
1475 
1476  int indexstart = 0;
1477  while( indexstart < 255) {
1478  progent++;
1479  u.dword = FL_PGM_READ_DWORD_NEAR( progent);
1480  int indexend = u.index;
1481  CRGB rgbend( u.r, u.g, u.b);
1482  fill_gradient_RGB( &(entries[0]), indexstart, rgbstart, indexend, rgbend);
1483  indexstart = indexend;
1484  rgbstart = rgbend;
1485  }
1486  return *this;
1487  }
1488  CRGBPalette256& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal )
1489  {
1492  u = *ent;
1493  CRGB rgbstart( u.r, u.g, u.b);
1494 
1495  int indexstart = 0;
1496  while( indexstart < 255) {
1497  ent++;
1498  u = *ent;
1499  int indexend = u.index;
1500  CRGB rgbend( u.r, u.g, u.b);
1501  fill_gradient_RGB( &(entries[0]), indexstart, rgbstart, indexend, rgbend);
1502  indexstart = indexend;
1503  rgbstart = rgbend;
1504  }
1505  return *this;
1506  }
1507 };
1508 
1509 
1510 
1511 typedef enum { NOBLEND=0, LINEARBLEND=1 } TBlendType;
1512 
1513 CRGB ColorFromPalette( const CRGBPalette16& pal,
1514  uint8_t index,
1515  uint8_t brightness=255,
1516  TBlendType blendType=LINEARBLEND);
1517 
1518 CRGB ColorFromPalette( const TProgmemRGBPalette16& pal,
1519  uint8_t index,
1520  uint8_t brightness=255,
1521  TBlendType blendType=LINEARBLEND);
1522 
1523 CRGB ColorFromPalette( const CRGBPalette256& pal,
1524  uint8_t index,
1525  uint8_t brightness=255,
1526  TBlendType blendType=NOBLEND );
1527 
1528 CHSV ColorFromPalette( const CHSVPalette16& pal,
1529  uint8_t index,
1530  uint8_t brightness=255,
1531  TBlendType blendType=LINEARBLEND);
1532 
1533 CHSV ColorFromPalette( const CHSVPalette256& pal,
1534  uint8_t index,
1535  uint8_t brightness=255,
1536  TBlendType blendType=NOBLEND );
1537 
1538 CRGB ColorFromPalette( const CRGBPalette32& pal,
1539  uint8_t index,
1540  uint8_t brightness=255,
1541  TBlendType blendType=LINEARBLEND);
1542 
1543 CRGB ColorFromPalette( const TProgmemRGBPalette32& pal,
1544  uint8_t index,
1545  uint8_t brightness=255,
1546  TBlendType blendType=LINEARBLEND);
1547 
1548 CHSV ColorFromPalette( const CHSVPalette32& pal,
1549  uint8_t index,
1550  uint8_t brightness=255,
1551  TBlendType blendType=LINEARBLEND);
1552 
1553 
1554 // Fill a range of LEDs with a sequece of entryies from a palette
1555 template <typename PALETTE>
1556 void fill_palette(CRGB* L, uint16_t N, uint8_t startIndex, uint8_t incIndex,
1557  const PALETTE& pal, uint8_t brightness, TBlendType blendType)
1558 {
1559  uint8_t colorIndex = startIndex;
1560  for( uint16_t i = 0; i < N; i++) {
1561  L[i] = ColorFromPalette( pal, colorIndex, brightness, blendType);
1562  colorIndex += incIndex;
1563  }
1564 }
1565 
1566 template <typename PALETTE>
1567 void map_data_into_colors_through_palette(
1568  uint8_t *dataArray, uint16_t dataCount,
1569  CRGB* targetColorArray,
1570  const PALETTE& pal,
1571  uint8_t brightness=255,
1572  uint8_t opacity=255,
1573  TBlendType blendType=LINEARBLEND)
1574 {
1575  for( uint16_t i = 0; i < dataCount; i++) {
1576  uint8_t d = dataArray[i];
1577  CRGB rgb = ColorFromPalette( pal, d, brightness, blendType);
1578  if( opacity == 255 ) {
1579  targetColorArray[i] = rgb;
1580  } else {
1581  targetColorArray[i].nscale8( 256 - opacity);
1582  rgb.nscale8_video( opacity);
1583  targetColorArray[i] += rgb;
1584  }
1585  }
1586 }
1587 
1588 // nblendPaletteTowardPalette:
1589 // Alter one palette by making it slightly more like
1590 // a 'target palette', used for palette cross-fades.
1591 //
1592 // It does this by comparing each of the R, G, and B channels
1593 // of each entry in the current palette to the corresponding
1594 // entry in the target palette and making small adjustments:
1595 // If the Red channel is too low, it will be increased.
1596 // If the Red channel is too high, it will be slightly reduced.
1597 // ... and likewise for Green and Blue channels.
1598 //
1599 // Additionally, there are two significant visual improvements
1600 // to this algorithm implemented here. First is this:
1601 // When increasing a channel, it is stepped up by ONE.
1602 // When decreasing a channel, it is stepped down by TWO.
1603 // Due to the way the eye perceives light, and the way colors
1604 // are represented in RGB, this produces a more uniform apparent
1605 // brightness when cross-fading between most palette colors.
1606 //
1607 // The second visual tweak is limiting the number of changes
1608 // that will be made to the palette at once. If all the palette
1609 // entries are changed at once, it can give a muddled appearance.
1610 // However, if only a few palette entries are changed at once,
1611 // you get a visually smoother transition: in the middle of the
1612 // cross-fade your current palette will actually contain some
1613 // colors from the old palette, a few blended colors, and some
1614 // colors from the new palette.
1615 // The maximum number of possible palette changes per call
1616 // is 48 (sixteen color entries time three channels each).
1617 // The default 'maximim number of changes' here is 12, meaning
1618 // that only approximately a quarter of the palette entries
1619 // will be changed per call.
1620 void nblendPaletteTowardPalette( CRGBPalette16& currentPalette,
1621  CRGBPalette16& targetPalette,
1622  uint8_t maxChanges=24);
1623 
1624 
1625 
1626 
1627 // You can also define a static RGB palette very compactly in terms of a series
1628 // of connected color gradients.
1629 // For example, if you want the first 3/4ths of the palette to be a slow
1630 // gradient ramping from black to red, and then the remaining 1/4 of the
1631 // palette to be a quicker ramp to white, you specify just three points: the
1632 // starting black point (at index 0), the red midpoint (at index 192),
1633 // and the final white point (at index 255). It looks like this:
1634 //
1635 // index: 0 192 255
1636 // |----------r-r-r-rrrrrrrrRrRrRrRrRRRR-|-RRWRWWRWWW-|
1637 // color: (0,0,0) (255,0,0) (255,255,255)
1638 //
1639 // Here's how you'd define that gradient palette:
1640 //
1641 // DEFINE_GRADIENT_PALETTE( black_to_red_to_white_p ) {
1642 // 0, 0, 0, 0, /* at index 0, black(0,0,0) */
1643 // 192, 255, 0, 0, /* at index 192, red(255,0,0) */
1644 // 255, 255,255,255 /* at index 255, white(255,255,255) */
1645 // };
1646 //
1647 // This format is designed for compact storage. The example palette here
1648 // takes up just 12 bytes of PROGMEM (flash) storage, and zero bytes
1649 // of SRAM when not currently in use.
1650 //
1651 // To use one of these gradient palettes, simply assign it into a
1652 // CRGBPalette16 or a CRGBPalette256, like this:
1653 //
1654 // CRGBPalette16 pal = black_to_red_to_white_p;
1655 //
1656 // When the assignment is made, the gradients are expanded out into
1657 // either 16 or 256 palette entries, depending on the kind of palette
1658 // object they're assigned to.
1659 //
1660 // IMPORTANT NOTES & CAVEATS:
1661 //
1662 // - The last 'index' position MUST BE 255! Failure to end with
1663 // index 255 will result in program hangs or crashes.
1664 //
1665 // - At this point, these gradient palette definitions MUST BE
1666 // stored in PROGMEM on AVR-based Arduinos. If you use the
1667 // DEFINE_GRADIENT_PALETTE macro, this is taken care of automatically.
1668 //
1669 
1670 #define DEFINE_GRADIENT_PALETTE(X) \
1671  extern const TProgmemRGBGradientPalette_byte X[] FL_PROGMEM =
1672 
1673 #define DECLARE_GRADIENT_PALETTE(X) \
1674  extern const TProgmemRGBGradientPalette_byte X[] FL_PROGMEM
1675 
1676 
1677 // Functions to apply gamma adjustments, either:
1678 // - a single gamma adjustment to a single scalar value,
1679 // - a single gamma adjustment to each channel of a CRGB color, or
1680 // - different gamma adjustments for each channel of a CRFB color.
1681 //
1682 // Note that the gamma is specified as a traditional floating point value
1683 // e.g., "2.5", and as such these functions should not be called in
1684 // your innermost pixel loops, or in animations that are extremely
1685 // low on program storage space. Nevertheless, if you need these
1686 // functions, here they are.
1687 //
1688 // Furthermore, bear in mind that CRGB leds have only eight bits
1689 // per channel of color resolution, and that very small, subtle shadings
1690 // may not be visible.
1691 uint8_t applyGamma_video( uint8_t brightness, float gamma);
1692 CRGB applyGamma_video( const CRGB& orig, float gamma);
1693 CRGB applyGamma_video( const CRGB& orig, float gammaR, float gammaG, float gammaB);
1694 // The "n" versions below modify their arguments in-place.
1695 CRGB& napplyGamma_video( CRGB& rgb, float gamma);
1696 CRGB& napplyGamma_video( CRGB& rgb, float gammaR, float gammaG, float gammaB);
1697 void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gamma);
1698 void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gammaR, float gammaG, float gammaB);
1699 
1700 
1701 FASTLED_NAMESPACE_END
1702 
1704 #endif
Representation of an RGB pixel (Red, Green, Blue)
Definition: pixeltypes.h:90
uint16_t accum88
ANSI: unsigned short _Accum. 8 bits int, 8 bits fraction.
Definition: lib8tion.h:354
uint8_t fract8
ANSI unsigned short _Fract.
Definition: lib8tion.h:335
CRGB & nscale8_video(uint8_t scaledown)
scale down a RGB to N 256ths of it's current brightness, using 'video' dimming rules, which means that unless the scale factor is ZERO each channel is guaranteed NOT to dim down to zero.
Definition: pixeltypes.h:329
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 (brig...
Definition: colorutils.cpp:35
CRGB & nscale8(uint8_t scaledown)
scale down a RGB to N 256ths of it's current brightness, using 'plain math' dimming rules...
Definition: pixeltypes.h:353
void fill_gradient(T *targetArray, uint16_t startpos, CHSV startcolor, uint16_t endpos, CHSV endcolor, TGradientDirectionCode directionCode=SHORTEST_HUES)
fill_gradient - fill an array of colors with a smooth HSV gradient between two specified HSV colors...
Definition: colorutils.h:94
central include file for FastLED, defines the CFastLED class/object
__attribute__((always_inline)) inline void swapbits8(bitswap_type in
Do an 8byte by 8bit rotation.
Definition: fastled_delay.h:92
Representation of an HSV pixel (hue, saturation, value (aka brightness)).
Definition: pixeltypes.h:23
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));
Definition: colorutils.cpp:12
Template class for represneting fractional ints.
Definition: lib8tion.h:754
wrapper definitions to allow seamless use of PROGMEM in environmens that have it
Definition: colorutils.h:410