GCC Code Coverage Report


Directory: ./
File: overlays/wled/colorutils.h
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 117 143 81.8%
Functions: 14 14 100.0%
Branches: 36 54 66.7%

Line Branch Exec Source
1 #ifndef __INC_COLORUTILS_H
2 #define __INC_COLORUTILS_H
3
4 /// @file colorutils.h
5 /// Utility functions for color fill, palettes, blending, and more
6
7 #include "FastLED.h"
8 #include "pixeltypes.h"
9
10 FASTLED_NAMESPACE_BEGIN
11
12 /// @defgroup ColorUtils Color Utility Functions
13 /// A variety of functions for working with color, palettes, and leds
14 /// @{
15
16 /// @defgroup ColorFills Color Fill Functions
17 /// Functions for filling LED arrays with colors and gradients
18 /// @{
19
20 /// Fill a range of LEDs with a solid color.
21 /// @param targetArray a pointer to the LED array to fill
22 /// @param numToFill the number of LEDs to fill in the array
23 /// @param color the color to fill with
24 void fill_solid( struct CRGB * targetArray, int numToFill,
25 const struct CRGB& color);
26
27 /// @copydoc fill_solid()
28 void fill_solid( struct CHSV* targetArray, int numToFill,
29 const struct CHSV& color);
30
31
32 /// Fill a range of LEDs with a rainbow of colors.
33 /// The colors making up the rainbow are at full saturation and full
34 /// value (brightness).
35 /// @param targetArray a pointer to the LED array to fill
36 /// @param numToFill the number of LEDs to fill in the array
37 /// @param initialhue the starting hue for the rainbow
38 /// @param deltahue how many hue values to advance for each LED
39 void fill_rainbow( struct CRGB * targetArray, int numToFill,
40 uint8_t initialhue,
41 uint8_t deltahue = 5);
42
43 /// @copydoc fill_rainbow()
44 void fill_rainbow( struct CHSV * targetArray, int numToFill,
45 uint8_t initialhue,
46 uint8_t deltahue = 5);
47
48
49 /// Fill a range of LEDs with a rainbow of colors, so that the hues
50 /// are continuous between the end of the strip and the beginning.
51 /// The colors making up the rainbow are at full saturation and full
52 /// value (brightness).
53 /// @param targetArray a pointer to the LED array to fill
54 /// @param numToFill the number of LEDs to fill in the array
55 /// @param initialhue the starting hue for the rainbow
56 /// @param reversed whether to progress through the rainbow hues backwards
57 void fill_rainbow_circular(struct CRGB* targetArray, int numToFill,
58 uint8_t initialhue, bool reversed=false);
59
60 /// @copydoc fill_rainbow_circular()
61 void fill_rainbow_circular(struct CHSV* targetArray, int numToFill,
62 uint8_t initialhue, bool reversed=false);
63
64
65 /// Hue direction for calculating fill gradients.
66 /// Since "hue" is a value around a color wheel, there are always two directions
67 /// to sweep from one hue to another.
68 typedef enum {
69 FORWARD_HUES, ///< Hue always goes clockwise around the color wheel
70 BACKWARD_HUES, ///< Hue always goes counter-clockwise around the color wheel
71 SHORTEST_HUES, ///< Hue goes whichever way is shortest
72 LONGEST_HUES ///< Hue goes whichever way is longest
73 } TGradientDirectionCode;
74
75
76 /// ANSI: signed short _Accum. 8 bits int, 7 bits fraction
77 /// @see accum88
78 #define saccum87 int16_t
79
80
81 /// Fill a range of LEDs with a smooth HSV gradient between two HSV colors.
82 /// This function can write the gradient colors either:
83 ///
84 /// 1. Into an array of CRGBs (e.g., an leds[] array, or a CRGB palette)
85 /// 2. Into an array of CHSVs (e.g. a CHSV palette).
86 ///
87 /// In the case of writing into a CRGB array, the gradient is
88 /// computed in HSV space, and then HSV values are converted to RGB
89 /// as they're written into the CRGB array.
90 /// @param targetArray a pointer to the color array to fill
91 /// @param startpos the starting position in the array
92 /// @param startcolor the starting color for the gradient
93 /// @param endpos the ending position in the array
94 /// @param endcolor the end color for the gradient
95 /// @param directionCode the direction to travel around the color wheel
96 template <typename T>
97 14091 void fill_gradient( T* targetArray,
98 uint16_t startpos, CHSV startcolor,
99 uint16_t endpos, CHSV endcolor,
100 TGradientDirectionCode directionCode = SHORTEST_HUES )
101 {
102 // if the points are in the wrong order, straighten them
103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14091 times.
14091 if( endpos < startpos ) {
104 ✗ uint16_t t = endpos;
105 ✗ CHSV tc = endcolor;
106 ✗ endcolor = startcolor;
107 ✗ endpos = startpos;
108 ✗ startpos = t;
109 ✗ startcolor = tc;
110 }
111
112 // If we're fading toward black (val=0) or white (sat=0),
113 // then set the endhue to the starthue.
114 // This lets us ramp smoothly to black or white, regardless
115 // of what 'hue' was set in the endcolor (since it doesn't matter)
116
2/4
✓ Branch 0 taken 14091 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14091 times.
14091 if( endcolor.value == 0 || endcolor.saturation == 0) {
117 ✗ endcolor.hue = startcolor.hue;
118 }
119
120 // Similarly, if we're fading in from black (val=0) or white (sat=0)
121 // then set the starthue to the endhue.
122 // This lets us ramp smoothly up from black or white, regardless
123 // of what 'hue' was set in the startcolor (since it doesn't matter)
124
2/4
✓ Branch 0 taken 14091 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14091 times.
14091 if( startcolor.value == 0 || startcolor.saturation == 0) {
125 ✗ startcolor.hue = endcolor.hue;
126 }
127
128 saccum87 huedistance87;
129 saccum87 satdistance87;
130 saccum87 valdistance87;
131
132 14091 satdistance87 = (endcolor.sat - startcolor.sat) << 7;
133 14091 valdistance87 = (endcolor.val - startcolor.val) << 7;
134
135 14091 uint8_t huedelta8 = endcolor.hue - startcolor.hue;
136
137
1/2
✓ Branch 0 taken 14091 times.
✗ Branch 1 not taken.
14091 if( directionCode == SHORTEST_HUES ) {
138 14091 directionCode = FORWARD_HUES;
139
2/2
✓ Branch 0 taken 4896 times.
✓ Branch 1 taken 9195 times.
14091 if( huedelta8 > 127) {
140 4896 directionCode = BACKWARD_HUES;
141 }
142 }
143
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14091 times.
14091 if( directionCode == LONGEST_HUES ) {
145 ✗ directionCode = FORWARD_HUES;
146 ✗ if( huedelta8 < 128) {
147 ✗ directionCode = BACKWARD_HUES;
148 }
149 }
150
151
2/2
✓ Branch 0 taken 9195 times.
✓ Branch 1 taken 4896 times.
14091 if( directionCode == FORWARD_HUES) {
152 9195 huedistance87 = huedelta8 << 7;
153 }
154 else /* directionCode == BACKWARD_HUES */
155 {
156 4896 huedistance87 = (uint8_t)(256 - huedelta8) << 7;
157 4896 huedistance87 = -huedistance87;
158 }
159
160 14091 uint16_t pixeldistance = endpos - startpos;
161
1/2
✓ Branch 0 taken 14091 times.
✗ Branch 1 not taken.
14091 int16_t divisor = pixeldistance ? pixeldistance : 1;
162
163 14091 saccum87 huedelta87 = huedistance87 / divisor;
164 14091 saccum87 satdelta87 = satdistance87 / divisor;
165 14091 saccum87 valdelta87 = valdistance87 / divisor;
166
167 14091 huedelta87 *= 2;
168 14091 satdelta87 *= 2;
169 14091 valdelta87 *= 2;
170
171 14091 accum88 hue88 = startcolor.hue << 8;
172 14091 accum88 sat88 = startcolor.sat << 8;
173 14091 accum88 val88 = startcolor.val << 8;
174
2/2
✓ Branch 0 taken 84546 times.
✓ Branch 1 taken 14091 times.
98637 for( uint16_t i = startpos; i <= endpos; ++i) {
175
1/2
✓ Branch 0 taken 84546 times.
✗ Branch 1 not taken.
85698 targetArray[i] = CHSV( hue88 >> 8, sat88 >> 8, val88 >> 8);
176 84546 hue88 += huedelta87;
177 84546 sat88 += satdelta87;
178 84546 val88 += valdelta87;
179 }
180 14091 }
181
182
183 /// Fill a range of LEDs with a smooth HSV gradient between two HSV colors.
184 /// @see fill_gradient()
185 /// @param targetArray a pointer to the color array to fill
186 /// @param numLeds the number of LEDs to fill
187 /// @param c1 the starting color in the gradient
188 /// @param c2 the end color for the gradient
189 /// @param directionCode the direction to travel around the color wheel
190 template <typename T>
191 void fill_gradient( T* targetArray, uint16_t numLeds, const CHSV& c1, const CHSV& c2,
192 TGradientDirectionCode directionCode = SHORTEST_HUES )
193 {
194 uint16_t last = numLeds - 1;
195 fill_gradient( targetArray, 0, c1, last, c2, directionCode);
196 }
197
198 /// Fill a range of LEDs with a smooth HSV gradient between three HSV colors.
199 /// @see fill_gradient()
200 /// @param targetArray a pointer to the color array to fill
201 /// @param numLeds the number of LEDs to fill
202 /// @param c1 the starting color in the gradient
203 /// @param c2 the middle color for the gradient
204 /// @param c3 the end color for the gradient
205 /// @param directionCode the direction to travel around the color wheel
206 template <typename T>
207 void fill_gradient( T* targetArray, uint16_t numLeds,
208 const CHSV& c1, const CHSV& c2, const CHSV& c3,
209 TGradientDirectionCode directionCode = SHORTEST_HUES )
210 {
211 uint16_t half = (numLeds / 2);
212 uint16_t last = numLeds - 1;
213 fill_gradient( targetArray, 0, c1, half, c2, directionCode);
214 fill_gradient( targetArray, half, c2, last, c3, directionCode);
215 }
216
217 /// Fill a range of LEDs with a smooth HSV gradient between four HSV colors.
218 /// @see fill_gradient()
219 /// @param targetArray a pointer to the color array to fill
220 /// @param numLeds the number of LEDs to fill
221 /// @param c1 the starting color in the gradient
222 /// @param c2 the first middle color for the gradient
223 /// @param c3 the second middle color for the gradient
224 /// @param c4 the end color for the gradient
225 /// @param directionCode the direction to travel around the color wheel
226 template <typename T>
227 4697 void fill_gradient( T* targetArray, uint16_t numLeds,
228 const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4,
229 TGradientDirectionCode directionCode = SHORTEST_HUES )
230 {
231 4697 uint16_t onethird = (numLeds / 3);
232 4697 uint16_t twothirds = ((numLeds * 2) / 3);
233 4697 uint16_t last = numLeds - 1;
234
1/2
✓ Branch 0 taken 4697 times.
✗ Branch 1 not taken.
4697 fill_gradient( targetArray, 0, c1, onethird, c2, directionCode);
235
1/2
✓ Branch 0 taken 4697 times.
✗ Branch 1 not taken.
4697 fill_gradient( targetArray, onethird, c2, twothirds, c3, directionCode);
236
1/2
✓ Branch 0 taken 4697 times.
✗ Branch 1 not taken.
4697 fill_gradient( targetArray, twothirds, c3, last, c4, directionCode);
237 4697 }
238
239 /// Convenience synonym
240 #define fill_gradient_HSV fill_gradient
241
242
243 /// Fill a range of LEDs with a smooth RGB gradient between two RGB colors.
244 /// Unlike HSV, there is no "color wheel" in RGB space, and therefore there's only one
245 /// "direction" for the gradient to go. This means there's no TGradientDirectionCode
246 /// parameter for direction.
247 /// @param leds a pointer to the LED array to fill
248 /// @param startpos the starting position in the array
249 /// @param startcolor the starting color for the gradient
250 /// @param endpos the ending position in the array
251 /// @param endcolor the end color for the gradient
252 void fill_gradient_RGB( CRGB* leds,
253 uint16_t startpos, CRGB startcolor,
254 uint16_t endpos, CRGB endcolor );
255
256 /// Fill a range of LEDs with a smooth RGB gradient between two RGB colors.
257 /// @see fill_gradient_RGB()
258 /// @param leds a pointer to the LED array to fill
259 /// @param numLeds the number of LEDs to fill
260 /// @param c1 the starting color in the gradient
261 /// @param c2 the end color for the gradient
262 void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2);
263
264 /// Fill a range of LEDs with a smooth RGB gradient between three RGB colors.
265 /// @see fill_gradient_RGB()
266 /// @param leds a pointer to the LED array to fill
267 /// @param numLeds the number of LEDs to fill
268 /// @param c1 the starting color in the gradient
269 /// @param c2 the middle color for the gradient
270 /// @param c3 the end color for the gradient
271 void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2, const CRGB& c3);
272
273 /// Fill a range of LEDs with a smooth RGB gradient between four RGB colors.
274 /// @see fill_gradient_RGB()
275 /// @param leds a pointer to the LED array to fill
276 /// @param numLeds the number of LEDs to fill
277 /// @param c1 the starting color in the gradient
278 /// @param c2 the first middle color for the gradient
279 /// @param c3 the second middle color for the gradient
280 /// @param c4 the end color for the gradient
281 void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4);
282
283 /// @} ColorFills
284
285
286 /// @defgroup ColorFades Color Fade Functions
287 /// Functions for fading LED arrays
288 /// @{
289
290 /// Reduce the brightness of an array of pixels all at once.
291 /// Guaranteed to never fade all the way to black.
292 /// @param leds a pointer to the LED array to fade
293 /// @param num_leds the number of LEDs to fade
294 /// @param fadeBy how much to fade each LED
295 void fadeLightBy( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
296
297 /// @copydoc fadeLightBy()
298 void fade_video( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
299
300 /// Scale the brightness of an array of pixels all at once.
301 /// Guaranteed to never fade all the way to black.
302 /// @param leds a pointer to the LED array to scale
303 /// @param num_leds the number of LEDs to scale
304 /// @param scale how much to scale each LED
305 void nscale8_video( CRGB* leds, uint16_t num_leds, uint8_t scale);
306
307
308 /// Reduce the brightness of an array of pixels all at once.
309 /// This function will eventually fade all the way to black.
310 /// @param leds a pointer to the LED array to fade
311 /// @param num_leds the number of LEDs to fade
312 /// @param fadeBy how much to fade each LED
313 void fadeToBlackBy( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
314
315 /// @copydoc fadeToBlackBy()
316 void fade_raw( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
317
318
319 /// Scale the brightness of an array of pixels all at once.
320 /// This function will eventually fade all the way to black, even
321 /// if "scale" is not zero.
322 /// @param leds a pointer to the LED array to scale
323 /// @param num_leds the number of LEDs to scale
324 /// @param scale how much to scale each LED
325 void nscale8( CRGB* leds, uint16_t num_leds, uint8_t scale);
326
327
328 /// Reduce the brightness of an array of pixels as thought it were seen through
329 /// a transparent filter with the specified color.
330 /// For example, if the colormask if CRGB(200, 100, 50), then the pixels' red will
331 /// be faded to 200/256ths, their green to 100/256ths, and their blue to 50/256ths.
332 /// This particular example will give a "hot fade" look, with white fading to yellow,
333 /// then red, then black. You can also use colormasks like CRGB::Blue to zero out the
334 /// red and green elements, leaving blue (largely) the same.
335 /// @param leds a pointer to the LED array to fade
336 /// @param numLeds the number of LEDs to fade
337 /// @param colormask the color mask to fade with
338 void fadeUsingColor( CRGB* leds, uint16_t numLeds, const CRGB& colormask);
339
340 /// @} ColorFades
341
342
343 /// @defgroup ColorBlends Color Blending Functions
344 /// Functions for blending colors together
345 /// @{
346
347 /// Computes a new color blended some fraction of the way between two other colors.
348 /// @param p1 the first color to blend
349 /// @param p2 the second color to blend
350 /// @param amountOfP2 the fraction of p2 to blend into p1
351 CRGB blend( const CRGB& p1, const CRGB& p2, fract8 amountOfP2 );
352
353 /// @copydoc blend(const CRGB&, const CRGB&, fract8)
354 /// @param directionCode the direction to travel around the color wheel
355 CHSV blend( const CHSV& p1, const CHSV& p2, fract8 amountOfP2,
356 TGradientDirectionCode directionCode = SHORTEST_HUES );
357
358
359 /// Computes a new blended array of colors, each some fraction of the way between
360 /// corresponding elements of two source arrays of colors.
361 /// Useful for blending palettes.
362 /// @param src1 the first array of colors to blend
363 /// @param src2 the second array of colors to blend
364 /// @param dest the destination array for the colors
365 /// @param count the number of LEDs to blend
366 /// @param amountOfsrc2 the fraction of src2 to blend into src1
367 CRGB* blend( const CRGB* src1, const CRGB* src2, CRGB* dest,
368 uint16_t count, fract8 amountOfsrc2 );
369
370 /// @copydoc blend(const CRGB*, const CRGB*, CRGB*, uint16_t, fract8)
371 /// @param directionCode the direction to travel around the color wheel
372 CHSV* blend( const CHSV* src1, const CHSV* src2, CHSV* dest,
373 uint16_t count, fract8 amountOfsrc2,
374 TGradientDirectionCode directionCode = SHORTEST_HUES );
375
376
377 /// Destructively modifies one color, blending in a given fraction of an overlay color
378 /// @param existing the color to modify
379 /// @param overlay the color to blend into existing
380 /// @param amountOfOverlay the fraction of overlay to blend into existing
381 CRGB& nblend( CRGB& existing, const CRGB& overlay, fract8 amountOfOverlay );
382
383 /// @copydoc nblend(CRGB&, const CRGB&, fract8)
384 /// @param directionCode the direction to travel around the color wheel
385 CHSV& nblend( CHSV& existing, const CHSV& overlay, fract8 amountOfOverlay,
386 TGradientDirectionCode directionCode = SHORTEST_HUES );
387
388
389 /// Destructively blends a given fraction of a color array into an existing color array
390 /// @param existing the color array to modify
391 /// @param overlay the color array to blend into existing
392 /// @param count the number of colors to process
393 /// @param amountOfOverlay the fraction of overlay to blend into existing
394 void nblend( CRGB* existing, CRGB* overlay, uint16_t count, fract8 amountOfOverlay);
395
396 /// @copydoc nblend(CRGB*, CRGB*, uint16_t, fract8)
397 /// @param directionCode the direction to travel around the color wheel
398 void nblend( CHSV* existing, CHSV* overlay, uint16_t count, fract8 amountOfOverlay,
399 TGradientDirectionCode directionCode = SHORTEST_HUES);
400
401 /// @} ColorBlends
402
403
404 /// @defgroup ColorBlurs Color Blurring Functions
405 /// Functions for blurring colors
406 /// @{
407
408 /// One-dimensional blur filter.
409 /// Spreads light to 2 line neighbors.
410 /// * 0 = no spread at all
411 /// * 64 = moderate spreading
412 /// * 172 = maximum smooth, even spreading
413 /// * 173..255 = wider spreading, but increasing flicker
414 ///
415 /// Total light is NOT entirely conserved, so many repeated
416 /// calls to 'blur' will also result in the light fading,
417 /// eventually all the way to black; this is by design so that
418 /// it can be used to (slowly) clear the LEDs to black.
419 /// @param leds a pointer to the LED array to blur
420 /// @param numLeds the number of LEDs to blur
421 /// @param blur_amount the amount of blur to apply
422 void blur1d( CRGB* leds, uint16_t numLeds, fract8 blur_amount);
423
424 /// Two-dimensional blur filter.
425 /// Spreads light to 8 XY neighbors.
426 /// * 0 = no spread at all
427 /// * 64 = moderate spreading
428 /// * 172 = maximum smooth, even spreading
429 /// * 173..255 = wider spreading, but increasing flicker
430 ///
431 /// Total light is NOT entirely conserved, so many repeated
432 /// calls to 'blur' will also result in the light fading,
433 /// eventually all the way to black; this is by design so that
434 /// it can be used to (slowly) clear the LEDs to black.
435 /// @param leds a pointer to the LED array to blur
436 /// @param width the width of the matrix
437 /// @param height the height of the matrix
438 /// @param blur_amount the amount of blur to apply
439 void blur2d( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
440
441
442 /// Perform a blur1d() on every row of a rectangular matrix
443 /// @see blur1d()
444 /// @param leds a pointer to the LED array to blur
445 /// @param width the width of the matrix
446 /// @param height the height of the matrix
447 /// @param blur_amount the amount of blur to apply
448 void blurRows( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
449
450 /// Perform a blur1d() on every column of a rectangular matrix
451 /// @copydetails blurRows()
452 void blurColumns(CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
453
454 /// @} ColorBlurs
455
456
457 /// @addtogroup ColorFills
458 /// @{
459
460 /// Approximates a "black body radiation" spectrum for
461 /// a given "heat" level. This is useful for animations of "fire".
462 /// Heat is specified as an arbitrary scale from 0 (cool) to 255 (hot).
463 /// This is NOT a chromatically correct "black body radiation"
464 /// spectrum, but it's surprisingly close, and it's fast and small.
465 CRGB HeatColor( uint8_t temperature);
466
467 /// @} ColorFills
468 /// @} ColorUtils
469
470
471 /// @defgroup ColorPalettes Color Palettes
472 /// Functions and class definitions for color palettes.
473 ///
474 /// RGB palettes map an 8-bit value (0-255) to an RGB color.
475 ///
476 /// You can create any color palette you wish; a couple of starters
477 /// are provided: ForestColors_p, CloudColors_p, LavaColors_p, OceanColors_p,
478 /// RainbowColors_p, and RainbowStripeColors_p.
479 ///
480 /// Palettes come in the traditional 256-entry variety, which take
481 /// up 768 bytes of RAM, and lightweight 16-entry varieties. The 16-entry
482 /// variety automatically interpolates between its entries to produce
483 /// a full 256-element color map, but at a cost of only 48 bytes of RAM.
484 ///
485 /// Basic operation is like this (using the 16-entry variety):
486 ///
487 /// 1. Declare your palette storage:
488 /// @code{.cpp}
489 /// CRGBPalette16 myPalette;
490 /// @endcode
491 ///
492 /// 2. Fill `myPalette` with your own 16 colors, or with a preset color scheme.
493 /// You can specify your 16 colors a variety of ways:
494 /// @code{.cpp}
495 /// CRGBPalette16 myPalette(
496 /// CRGB::Black,
497 /// CRGB::Black,
498 /// CRGB::Red,
499 /// CRGB::Yellow,
500 /// CRGB::Green,
501 /// CRGB::Blue,
502 /// CRGB::Purple,
503 /// CRGB::Black,
504 ///
505 /// 0x100000,
506 /// 0x200000,
507 /// 0x400000,
508 /// 0x800000,
509 ///
510 /// CHSV( 30,255,255),
511 /// CHSV( 50,255,255),
512 /// CHSV( 70,255,255),
513 /// CHSV( 90,255,255)
514 /// );
515 /// @endcode
516 ///
517 /// Or you can initiaize your palette with a preset color scheme:
518 /// @code{.cpp}
519 /// myPalette = RainbowStripesColors_p;
520 /// @endcode
521 ///
522 /// 3. Any time you want to set a pixel to a color from your palette, use
523 /// `ColorFromPalette()` as shown:
524 ///
525 /// @code{.cpp}
526 /// uint8_t index = /* any value 0-255 */;
527 /// leds[i] = ColorFromPalette(myPalette, index);
528 /// @endcode
529 ///
530 /// Even though your palette has only 16 explicily defined entries, you
531 /// can use an "index" from 0-255. The 16 explicit palette entries will
532 /// be spread evenly across the 0-255 range, and the intermedate values
533 /// will be RGB-interpolated between adjacent explicit entries.
534 ///
535 /// It's easier to use than it sounds.
536 ///
537 /// @{
538
539
540 /// @defgroup PaletteClasses Palette Classes
541 /// Class definitions for color palettes.
542 /// @todo For documentation purposes it would be nice to reorder these
543 /// definitions by type and in ascending number of entries.
544 ///
545 /// @{
546
547 class CRGBPalette16;
548 class CRGBPalette32;
549 class CRGBPalette256;
550 class CHSVPalette16;
551 class CHSVPalette32;
552 class CHSVPalette256;
553
554 typedef uint32_t TProgmemRGBPalette16[16]; ///< CRGBPalette16 entries stored in PROGMEM memory
555 typedef uint32_t TProgmemHSVPalette16[16]; ///< CHSVPalette16 entries stored in PROGMEM memory
556 /// Alias for TProgmemRGBPalette16
557 #define TProgmemPalette16 TProgmemRGBPalette16
558 typedef uint32_t TProgmemRGBPalette32[32]; ///< CRGBPalette32 entries stored in PROGMEM memory
559 typedef uint32_t TProgmemHSVPalette32[32]; ///< CHSVPalette32 entries stored in PROGMEM memory
560 /// Alias for TProgmemRGBPalette32
561 #define TProgmemPalette32 TProgmemRGBPalette32
562
563 /// Byte of an RGB gradient, stored in PROGMEM memory
564 typedef const uint8_t TProgmemRGBGradientPalette_byte;
565 /// Pointer to bytes of an RGB gradient, stored in PROGMEM memory
566 /// @see DEFINE_GRADIENT_PALETTE
567 /// @see DECLARE_GRADIENT_PALETTE
568 typedef const TProgmemRGBGradientPalette_byte *TProgmemRGBGradientPalette_bytes;
569 /// Alias of ::TProgmemRGBGradientPalette_bytes
570 typedef TProgmemRGBGradientPalette_bytes TProgmemRGBGradientPalettePtr;
571
572 /// Struct for digesting gradient pointer data into its components.
573 /// This is used when loading a gradient stored in PROGMEM or on
574 /// the heap into a palette. The pointer is dereferenced and interpreted as
575 /// this struct, so the component parts can be addressed and copied by name.
576 typedef union {
577 struct {
578 uint8_t index; ///< index of the color entry in the gradient
579 uint8_t r; ///< CRGB::red channel value of the color entry
580 uint8_t g; ///< CRGB::green channel value of the color entry
581 uint8_t b; ///< CRGB::blue channel value of the color entry
582 };
583 uint32_t dword; ///< values as a packed 32-bit double word
584 uint8_t bytes[4]; ///< values as an array
585 } TRGBGradientPaletteEntryUnion;
586
587 typedef uint8_t TDynamicRGBGradientPalette_byte; ///< Byte of an RGB gradient entry, stored in dynamic (heap) memory
588 typedef const TDynamicRGBGradientPalette_byte *TDynamicRGBGradientPalette_bytes; ///< Pointer to bytes of an RGB gradient, stored in dynamic (heap) memory
589 typedef TDynamicRGBGradientPalette_bytes TDynamicRGBGradientPalettePtr; ///< Alias of ::TDynamicRGBGradientPalette_bytes
590
591 /// @}
592
593
594 /// @defgroup PaletteUpscale Palette Upscaling Functions
595 /// Functions to upscale palettes from one type to another.
596 /// @{
597
598 /// Convert a 16-entry palette to a 256-entry palette
599 /// @param srcpal16 the source palette to upscale
600 /// @param destpal256 the destination palette for the upscaled data
601 void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette256& destpal256);
602 /// @copydoc UpscalePalette(const struct CRGBPalette16&, struct CRGBPalette256&)
603 void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette256& destpal256);
604
605 /// Convert a 16-entry palette to a 32-entry palette
606 /// @param srcpal16 the source palette to upscale
607 /// @param destpal32 the destination palette for the upscaled data
608 void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette32& destpal32);
609 /// @copydoc UpscalePalette(const struct CRGBPalette16&, struct CRGBPalette32&)
610 void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette32& destpal32);
611
612 /// Convert a 32-entry palette to a 256-entry palette
613 /// @param srcpal32 the source palette to upscale
614 /// @param destpal256 the destination palette for the upscaled data
615 void UpscalePalette(const struct CRGBPalette32& srcpal32, struct CRGBPalette256& destpal256);
616 /// @copydoc UpscalePalette(const struct CRGBPalette32&, struct CRGBPalette256&)
617 void UpscalePalette(const struct CHSVPalette32& srcpal32, struct CHSVPalette256& destpal256);
618
619 /// @} PaletteUpscale
620
621
622 /// @addtogroup PaletteClasses
623 /// @{
624
625 /// HSV color palette with 16 discrete values
626 class CHSVPalette16 {
627 public:
628 CHSV entries[16]; ///< the color entries that make up the palette
629
630 /// @copydoc CHSV::CHSV()
631 CHSVPalette16() {};
632
633 /// Create palette from 16 CHSV values
634 CHSVPalette16( const CHSV& c00,const CHSV& c01,const CHSV& c02,const CHSV& c03,
635 const CHSV& c04,const CHSV& c05,const CHSV& c06,const CHSV& c07,
636 const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11,
637 const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 )
638 {
639 entries[0]=c00; entries[1]=c01; entries[2]=c02; entries[3]=c03;
640 entries[4]=c04; entries[5]=c05; entries[6]=c06; entries[7]=c07;
641 entries[8]=c08; entries[9]=c09; entries[10]=c10; entries[11]=c11;
642 entries[12]=c12; entries[13]=c13; entries[14]=c14; entries[15]=c15;
643 };
644
645 /// Copy constructor
646 CHSVPalette16( const CHSVPalette16& rhs)
647 {
648 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
649 }
650
651 /// @copydoc CHSVPalette16(const CHSVPalette16& rhs)
652 CHSVPalette16& operator=( const CHSVPalette16& rhs)
653 {
654 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
655 return *this;
656 }
657
658 /// Create palette from palette stored in PROGMEM
659 CHSVPalette16( const TProgmemHSVPalette16& rhs)
660 {
661 for( uint8_t i = 0; i < 16; ++i) {
662 CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
663 entries[i].hue = xyz.red;
664 entries[i].sat = xyz.green;
665 entries[i].val = xyz.blue;
666 }
667 }
668
669 /// @copydoc CHSVPalette16(const TProgmemHSVPalette16&)
670 CHSVPalette16& operator=( const TProgmemHSVPalette16& rhs)
671 {
672 for( uint8_t i = 0; i < 16; ++i) {
673 CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
674 entries[i].hue = xyz.red;
675 entries[i].sat = xyz.green;
676 entries[i].val = xyz.blue;
677 }
678 return *this;
679 }
680
681 /// Array access operator to index into the gradient entries
682 /// @param x the index to retrieve
683 /// @returns reference to an entry in the palette's color array
684 /// @note This does not perform any interpolation like ColorFromPalette(),
685 /// it accesses the underlying entries that make up the gradient. Beware
686 /// of bounds issues!
687 inline CHSV& operator[] (uint8_t x) __attribute__((always_inline))
688 {
689 return entries[x];
690 }
691
692 /// @copydoc operator[]
693 inline const CHSV& operator[] (uint8_t x) const __attribute__((always_inline))
694 {
695 ✗ return entries[x];
696 }
697
698 /// @copydoc operator[]
699 inline CHSV& operator[] (int x) __attribute__((always_inline))
700 {
701 return entries[(uint8_t)x];
702 }
703
704 /// @copydoc operator[]
705 inline const CHSV& operator[] (int x) const __attribute__((always_inline))
706 {
707 ✗ return entries[(uint8_t)x];
708 }
709
710 /// Get the underlying pointer to the CHSV entries making up the palette
711 operator CHSV*()
712 {
713 return &(entries[0]);
714 }
715
716 /// Check if two palettes have the same color entries
717 bool operator==( const CHSVPalette16 &rhs) const
718 {
719 const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
720 const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
721 if( p == q) return true;
722 for( uint8_t i = 0; i < (sizeof( entries)); ++i) {
723 if( *p != *q) return false;
724 ++p;
725 ++q;
726 }
727 return true;
728 }
729
730 /// Check if two palettes do not have the same color entries
731 bool operator!=( const CHSVPalette16 &rhs) const
732 {
733 return !( *this == rhs);
734 }
735
736 /// Create palette filled with one color
737 /// @param c1 the color to fill the palette with
738 CHSVPalette16( const CHSV& c1)
739 {
740 fill_solid( &(entries[0]), 16, c1);
741 }
742
743 /// Create palette with a gradient from one color to another
744 /// @param c1 the starting color for the gradient
745 /// @param c2 the end color for the gradient
746 CHSVPalette16( const CHSV& c1, const CHSV& c2)
747 {
748 fill_gradient( &(entries[0]), 16, c1, c2);
749 }
750
751 /// Create palette with three-color gradient
752 /// @param c1 the starting color for the gradient
753 /// @param c2 the middle color for the gradient
754 /// @param c3 the end color for the gradient
755 CHSVPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3)
756 {
757 fill_gradient( &(entries[0]), 16, c1, c2, c3);
758 }
759
760 /// Create palette with four-color gradient
761 /// @param c1 the starting color for the gradient
762 /// @param c2 the first middle color for the gradient
763 /// @param c3 the second middle color for the gradient
764 /// @param c4 the end color for the gradient
765 CHSVPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
766 {
767 fill_gradient( &(entries[0]), 16, c1, c2, c3, c4);
768 }
769
770 };
771
772 /// HSV color palette with 256 discrete values
773 class CHSVPalette256 {
774 public:
775 CHSV entries[256]; ///< @copydoc CHSVPalette16::entries
776
777 /// @copydoc CHSVPalette16::CHSVPalette16()
778 CHSVPalette256() {};
779
780 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&, const CHSV&, const CHSV&,
781 /// const CHSV&, const CHSV&, const CHSV&, const CHSV&,
782 /// const CHSV&, const CHSV&, const CHSV&, const CHSV&,
783 /// const CHSV&, const CHSV&, const CHSV&, const CHSV&)
784 CHSVPalette256( const CHSV& c00,const CHSV& c01,const CHSV& c02,const CHSV& c03,
785 const CHSV& c04,const CHSV& c05,const CHSV& c06,const CHSV& c07,
786 const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11,
787 const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 )
788 {
789 CHSVPalette16 p16(c00,c01,c02,c03,c04,c05,c06,c07,
790 c08,c09,c10,c11,c12,c13,c14,c15);
791 *this = p16;
792 };
793
794 /// Copy constructor
795 CHSVPalette256( const CHSVPalette256& rhs)
796 {
797 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
798 }
799 /// @copydoc CHSVPalette256( const CHSVPalette256&)
800 CHSVPalette256& operator=( const CHSVPalette256& rhs)
801 {
802 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
803 return *this;
804 }
805
806 /// Create upscaled palette from 16-entry palette
807 CHSVPalette256( const CHSVPalette16& rhs16)
808 {
809 UpscalePalette( rhs16, *this);
810 }
811 /// @copydoc CHSVPalette256( const CHSVPalette16&)
812 CHSVPalette256& operator=( const CHSVPalette16& rhs16)
813 {
814 UpscalePalette( rhs16, *this);
815 return *this;
816 }
817
818 /// @copydoc CHSVPalette16::CHSVPalette16(const TProgmemHSVPalette16&)
819 CHSVPalette256( const TProgmemRGBPalette16& rhs)
820 {
821 CHSVPalette16 p16(rhs);
822 *this = p16;
823 }
824 /// @copydoc CHSVPalette16::CHSVPalette16(const TProgmemHSVPalette16&)
825 CHSVPalette256& operator=( const TProgmemRGBPalette16& rhs)
826 {
827 CHSVPalette16 p16(rhs);
828 *this = p16;
829 return *this;
830 }
831
832 /// @copydoc CHSVPalette16::operator[]
833 inline CHSV& operator[] (uint8_t x) __attribute__((always_inline))
834 {
835 ✗ return entries[x];
836 }
837 /// @copydoc operator[]
838 inline const CHSV& operator[] (uint8_t x) const __attribute__((always_inline))
839 {
840 return entries[x];
841 }
842
843 /// @copydoc operator[]
844 inline CHSV& operator[] (int x) __attribute__((always_inline))
845 {
846 return entries[(uint8_t)x];
847 }
848 /// @copydoc operator[]
849 inline const CHSV& operator[] (int x) const __attribute__((always_inline))
850 {
851 ✗ return entries[(uint8_t)x];
852 }
853
854 /// Get the underlying pointer to the CHSV entries making up the palette
855 operator CHSV*()
856 {
857 return &(entries[0]);
858 }
859
860 /// @copydoc CHSVPalette16::operator==
861 bool operator==( const CHSVPalette256 &rhs) const
862 {
863 const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
864 const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
865 if( p == q) return true;
866 for( uint16_t i = 0; i < (sizeof( entries)); ++i) {
867 if( *p != *q) return false;
868 ++p;
869 ++q;
870 }
871 return true;
872 }
873
874 /// @copydoc CHSVPalette16::operator!=
875 bool operator!=( const CHSVPalette256 &rhs) const
876 {
877 return !( *this == rhs);
878 }
879
880 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&)
881 CHSVPalette256( const CHSV& c1)
882 {
883 fill_solid( &(entries[0]), 256, c1);
884 }
885 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&)
886 CHSVPalette256( const CHSV& c1, const CHSV& c2)
887 {
888 fill_gradient( &(entries[0]), 256, c1, c2);
889 }
890 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&, const CHSV&)
891 CHSVPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3)
892 {
893 fill_gradient( &(entries[0]), 256, c1, c2, c3);
894 }
895 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&, const CHSV&, const CHSV&)
896 CHSVPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
897 {
898 fill_gradient( &(entries[0]), 256, c1, c2, c3, c4);
899 }
900 };
901
902 /// RGB color palette with 16 discrete values
903 class CRGBPalette16 {
904 public:
905 CRGB entries[16]; ///< @copydoc CHSVPalette16::entries
906
907 /// @copydoc CRGB::CRGB()
908 CRGBPalette16() {};
909
910 /// Create palette from 16 CRGB values
911 95 CRGBPalette16( const CRGB& c00,const CRGB& c01,const CRGB& c02,const CRGB& c03,
912 const CRGB& c04,const CRGB& c05,const CRGB& c06,const CRGB& c07,
913 const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11,
914 const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 )
915 95 {
916 95 entries[0]=c00; entries[1]=c01; entries[2]=c02; entries[3]=c03;
917 95 entries[4]=c04; entries[5]=c05; entries[6]=c06; entries[7]=c07;
918 95 entries[8]=c08; entries[9]=c09; entries[10]=c10; entries[11]=c11;
919 95 entries[12]=c12; entries[13]=c13; entries[14]=c14; entries[15]=c15;
920 95 };
921
922 /// Copy constructor
923 18 CRGBPalette16( const CRGBPalette16& rhs)
924 18 {
925 18 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
926 18 }
927 /// Create palette from array of CRGB colors
928 CRGBPalette16( const CRGB rhs[16])
929 {
930 memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
931 }
932 /// @copydoc CRGBPalette16(const CRGBPalette16&)
933 7962 CRGBPalette16& operator=( const CRGBPalette16& rhs)
934 {
935 7962 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
936 7962 return *this;
937 }
938 /// Create palette from array of CRGB colors
939 CRGBPalette16& operator=( const CRGB rhs[16])
940 {
941 memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
942 return *this;
943 }
944
945 /// Create palette from CHSV palette
946 CRGBPalette16( const CHSVPalette16& rhs)
947 {
948 for( uint8_t i = 0; i < 16; ++i) {
949 entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
950 }
951 }
952 /// Create palette from array of CHSV colors
953 CRGBPalette16( const CHSV rhs[16])
954 {
955 for( uint8_t i = 0; i < 16; ++i) {
956 entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
957 }
958 }
959 /// @copydoc CRGBPalette16(const CHSVPalette16&)
960 CRGBPalette16& operator=( const CHSVPalette16& rhs)
961 {
962 for( uint8_t i = 0; i < 16; ++i) {
963 entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
964 }
965 return *this;
966 }
967 /// Create palette from array of CHSV colors
968 CRGBPalette16& operator=( const CHSV rhs[16])
969 {
970 for( uint8_t i = 0; i < 16; ++i) {
971 entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
972 }
973 return *this;
974 }
975
976 /// Create palette from palette stored in PROGMEM
977 CRGBPalette16( const TProgmemRGBPalette16& rhs)
978 {
979 for( uint8_t i = 0; i < 16; ++i) {
980 entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
981 }
982 }
983 /// @copydoc CRGBPalette16(const TProgmemRGBPalette16&)
984 7498 CRGBPalette16& operator=( const TProgmemRGBPalette16& rhs)
985 {
986
2/2
✓ Branch 0 taken 119968 times.
✓ Branch 1 taken 7498 times.
127466 for( uint8_t i = 0; i < 16; ++i) {
987 119968 entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
988 }
989 7498 return *this;
990 }
991
992 /// @copydoc CHSVPalette16::operator==
993 34 bool operator==( const CRGBPalette16 &rhs) const
994 {
995 34 const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
996 34 const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if( p == q) return true;
998
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 for( uint8_t i = 0; i < (sizeof( entries)); ++i) {
999
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 if( *p != *q) return false;
1000 ✗ ++p;
1001 ✗ ++q;
1002 }
1003 ✗ return true;
1004 }
1005 /// @copydoc CHSVPalette16::operator!=
1006 34 bool operator!=( const CRGBPalette16 &rhs) const
1007 {
1008 34 return !( *this == rhs);
1009 }
1010 /// @copydoc CHSVPalette16::operator[]
1011 inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
1012 {
1013 ✗ return entries[x];
1014 }
1015 /// @copydoc CHSVPalette16::operator[]
1016 inline const CRGB& operator[] (uint8_t x) const __attribute__((always_inline))
1017 {
1018 ✗ return entries[x];
1019 }
1020
1021 /// @copydoc CHSVPalette16::operator[]
1022 inline CRGB& operator[] (int x) __attribute__((always_inline))
1023 {
1024 return entries[(uint8_t)x];
1025 }
1026 /// @copydoc CHSVPalette16::operator[]
1027 inline const CRGB& operator[] (int x) const __attribute__((always_inline))
1028 {
1029 534788 return entries[(uint8_t)x];
1030 }
1031
1032 /// Get the underlying pointer to the CHSV entries making up the palette
1033 operator CRGB*()
1034 {
1035 return &(entries[0]);
1036 }
1037
1038 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&)
1039 CRGBPalette16( const CHSV& c1)
1040 {
1041 fill_solid( &(entries[0]), 16, c1);
1042 }
1043 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&)
1044 CRGBPalette16( const CHSV& c1, const CHSV& c2)
1045 {
1046 fill_gradient( &(entries[0]), 16, c1, c2);
1047 }
1048 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&, const CHSV&)
1049 CRGBPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3)
1050 {
1051 fill_gradient( &(entries[0]), 16, c1, c2, c3);
1052 }
1053 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&, const CHSV&, const CHSV&)
1054 4697 CRGBPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
1055 4697 {
1056 4697 fill_gradient( &(entries[0]), 16, c1, c2, c3, c4);
1057 4697 }
1058
1059 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&)
1060 4939 CRGBPalette16( const CRGB& c1)
1061 4939 {
1062 4939 fill_solid( &(entries[0]), 16, c1);
1063 4939 }
1064 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&)
1065 15426 CRGBPalette16( const CRGB& c1, const CRGB& c2)
1066 15426 {
1067 15426 fill_gradient_RGB( &(entries[0]), 16, c1, c2);
1068 15426 }
1069 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&, const CHSV&)
1070 3 CRGBPalette16( const CRGB& c1, const CRGB& c2, const CRGB& c3)
1071 3 {
1072 3 fill_gradient_RGB( &(entries[0]), 16, c1, c2, c3);
1073 3 }
1074 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&, const CHSV&, const CHSV&)
1075 483 CRGBPalette16( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
1076 483 {
1077 483 fill_gradient_RGB( &(entries[0]), 16, c1, c2, c3, c4);
1078 483 }
1079
1080 /// Creates a palette from a gradient palette in PROGMEM.
1081 ///
1082 /// Gradient palettes are loaded into CRGBPalettes in such a way
1083 /// that, if possible, every color represented in the gradient palette
1084 /// is also represented in the CRGBPalette.
1085 ///
1086 /// For example, consider a gradient palette that is all black except
1087 /// for a single, one-element-wide (1/256th!) spike of red in the middle:
1088 /// @code
1089 /// 0, 0,0,0
1090 /// 124, 0,0,0
1091 /// 125, 255,0,0 // one 1/256th-palette-wide red stripe
1092 /// 126, 0,0,0
1093 /// 255, 0,0,0
1094 /// @endcode
1095 /// A naive conversion of this 256-element palette to a 16-element palette
1096 /// might accidentally completely eliminate the red spike, rendering the
1097 /// palette completely black.
1098 ///
1099 /// However, the conversions provided here would attempt to include a
1100 /// the red stripe in the output, more-or-less as faithfully as possible.
1101 /// So in this case, the resulting CRGBPalette16 palette would have a red
1102 /// stripe in the middle which was 1/16th of a palette wide -- the
1103 /// narrowest possible in a CRGBPalette16.
1104 ///
1105 /// This means that the relative width of stripes in a CRGBPalette16
1106 /// will be, by definition, different from the widths in the gradient
1107 /// palette. This code attempts to preserve "all the colors", rather than
1108 /// the exact stripe widths at the expense of dropping some colors.
1109 CRGBPalette16( TProgmemRGBGradientPalette_bytes progpal )
1110 {
1111 *this = progpal;
1112 }
1113 /// @copydoc CRGBPalette16(TProgmemRGBGradientPalette_bytes)
1114 CRGBPalette16& operator=( TProgmemRGBGradientPalette_bytes progpal )
1115 {
1116 TRGBGradientPaletteEntryUnion* progent = (TRGBGradientPaletteEntryUnion*)(progpal);
1117 TRGBGradientPaletteEntryUnion u;
1118
1119 // Count entries
1120 uint16_t count = 0;
1121 do {
1122 u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
1123 ++count;
1124 } while ( u.index != 255);
1125
1126 int8_t lastSlotUsed = -1;
1127
1128 u.dword = FL_PGM_READ_DWORD_NEAR( progent);
1129 CRGB rgbstart( u.r, u.g, u.b);
1130
1131 int indexstart = 0;
1132 uint8_t istart8 = 0;
1133 uint8_t iend8 = 0;
1134 while( indexstart < 255) {
1135 ++progent;
1136 u.dword = FL_PGM_READ_DWORD_NEAR( progent);
1137 int indexend = u.index;
1138 CRGB rgbend( u.r, u.g, u.b);
1139 istart8 = indexstart / 16;
1140 iend8 = indexend / 16;
1141 if( count < 16) {
1142 if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
1143 istart8 = lastSlotUsed + 1;
1144 if( iend8 < istart8) {
1145 iend8 = istart8;
1146 }
1147 }
1148 lastSlotUsed = iend8;
1149 }
1150 fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
1151 indexstart = indexend;
1152 rgbstart = rgbend;
1153 }
1154 return *this;
1155 }
1156 /// Creates a palette from a gradient palette in dynamic (heap) memory.
1157 /// @copydetails CRGBPalette16::CRGBPalette16(TProgmemRGBGradientPalette_bytes)
1158 791 CRGBPalette16& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal )
1159 {
1160 791 TRGBGradientPaletteEntryUnion* ent = (TRGBGradientPaletteEntryUnion*)(gpal);
1161 TRGBGradientPaletteEntryUnion u;
1162
1163 // Count entries
1164 791 uint16_t count = 0;
1165 do {
1166 6706 u = *(ent + count);
1167 6706 ++count;
1168
2/2
✓ Branch 0 taken 5915 times.
✓ Branch 1 taken 791 times.
6706 } while ( u.index != 255);
1169
1170 791 int8_t lastSlotUsed = -1;
1171
1172
1173 791 u = *ent;
1174 791 CRGB rgbstart( u.r, u.g, u.b);
1175
1176 791 int indexstart = 0;
1177 791 uint8_t istart8 = 0;
1178 791 uint8_t iend8 = 0;
1179
2/2
✓ Branch 0 taken 5915 times.
✓ Branch 1 taken 791 times.
6706 while( indexstart < 255) {
1180 5915 ++ent;
1181 5915 u = *ent;
1182 5915 int indexend = u.index;
1183 5915 CRGB rgbend( u.r, u.g, u.b);
1184 5915 istart8 = indexstart / 16;
1185 5915 iend8 = indexend / 16;
1186
2/2
✓ Branch 0 taken 5034 times.
✓ Branch 1 taken 881 times.
5915 if( count < 16) {
1187
4/4
✓ Branch 0 taken 4295 times.
✓ Branch 1 taken 739 times.
✓ Branch 2 taken 4127 times.
✓ Branch 3 taken 168 times.
5034 if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
1188 4127 istart8 = lastSlotUsed + 1;
1189
2/2
✓ Branch 0 taken 697 times.
✓ Branch 1 taken 3430 times.
4127 if( iend8 < istart8) {
1190 697 iend8 = istart8;
1191 }
1192 }
1193 5034 lastSlotUsed = iend8;
1194 }
1195
1/2
✓ Branch 0 taken 5915 times.
✗ Branch 1 not taken.
5915 fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
1196 5915 indexstart = indexend;
1197 5915 rgbstart = rgbend;
1198 }
1199 791 return *this;
1200 }
1201
1202 };
1203
1204
1205 /// HSV color palette with 32 discrete values
1206 class CHSVPalette32 {
1207 public:
1208 CHSV entries[32]; ///< @copydoc CHSVPalette16::entries
1209
1210 /// @copydoc CHSVPalette16::CHSVPalette16()
1211 CHSVPalette32() {};
1212
1213 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&, const CHSV&, const CHSV&,
1214 /// const CHSV&, const CHSV&, const CHSV&, const CHSV&,
1215 /// const CHSV&, const CHSV&, const CHSV&, const CHSV&,
1216 /// const CHSV&, const CHSV&, const CHSV&, const CHSV&)
1217 CHSVPalette32( const CHSV& c00,const CHSV& c01,const CHSV& c02,const CHSV& c03,
1218 const CHSV& c04,const CHSV& c05,const CHSV& c06,const CHSV& c07,
1219 const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11,
1220 const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 )
1221 {
1222 for( uint8_t i = 0; i < 2; ++i) {
1223 entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03;
1224 entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07;
1225 entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11;
1226 entries[24+i]=c12; entries[26+i]=c13; entries[28+i]=c14; entries[30+i]=c15;
1227 }
1228 };
1229
1230 /// Copy constructor
1231 CHSVPalette32( const CHSVPalette32& rhs)
1232 {
1233 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
1234 }
1235 /// @copydoc CHSVPalette32( const CHSVPalette32&)
1236 CHSVPalette32& operator=( const CHSVPalette32& rhs)
1237 {
1238 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
1239 return *this;
1240 }
1241
1242 /// @copydoc CHSVPalette16::CHSVPalette16(const TProgmemHSVPalette16&)
1243 CHSVPalette32( const TProgmemHSVPalette32& rhs)
1244 {
1245 for( uint8_t i = 0; i < 32; ++i) {
1246 CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
1247 entries[i].hue = xyz.red;
1248 entries[i].sat = xyz.green;
1249 entries[i].val = xyz.blue;
1250 }
1251 }
1252 /// @copydoc CHSVPalette16::CHSVPalette16(const TProgmemHSVPalette16&)
1253 CHSVPalette32& operator=( const TProgmemHSVPalette32& rhs)
1254 {
1255 for( uint8_t i = 0; i < 32; ++i) {
1256 CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
1257 entries[i].hue = xyz.red;
1258 entries[i].sat = xyz.green;
1259 entries[i].val = xyz.blue;
1260 }
1261 return *this;
1262 }
1263
1264 /// @copydoc CHSVPalette16::CHSVPalette16(const TProgmemHSVPalette16&)
1265 inline CHSV& operator[] (uint8_t x) __attribute__((always_inline))
1266 {
1267 return entries[x];
1268 }
1269 /// @copydoc CHSVPalette16::CHSVPalette16(const TProgmemHSVPalette16&)
1270 inline const CHSV& operator[] (uint8_t x) const __attribute__((always_inline))
1271 {
1272 return entries[x];
1273 }
1274
1275 /// @copydoc CHSVPalette16::CHSVPalette16(const TProgmemHSVPalette16&)
1276 inline CHSV& operator[] (int x) __attribute__((always_inline))
1277 {
1278 ✗ return entries[(uint8_t)x];
1279 }
1280 /// @copydoc CHSVPalette16::CHSVPalette16(const TProgmemHSVPalette16&)
1281 inline const CHSV& operator[] (int x) const __attribute__((always_inline))
1282 {
1283 ✗ return entries[(uint8_t)x];
1284 }
1285
1286 /// Get the underlying pointer to the CHSV entries making up the palette
1287 operator CHSV*()
1288 {
1289 return &(entries[0]);
1290 }
1291
1292 /// @copydoc CHSVPalette16::operator==
1293 bool operator==( const CHSVPalette32 &rhs) const
1294 {
1295 const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
1296 const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
1297 if( p == q) return true;
1298 for( uint8_t i = 0; i < (sizeof( entries)); ++i) {
1299 if( *p != *q) return false;
1300 ++p;
1301 ++q;
1302 }
1303 return true;
1304 }
1305 /// @copydoc CHSVPalette16::operator!=
1306 bool operator!=( const CHSVPalette32 &rhs) const
1307 {
1308 return !( *this == rhs);
1309 }
1310
1311 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&)
1312 CHSVPalette32( const CHSV& c1)
1313 {
1314 fill_solid( &(entries[0]), 32, c1);
1315 }
1316 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&)
1317 CHSVPalette32( const CHSV& c1, const CHSV& c2)
1318 {
1319 fill_gradient( &(entries[0]), 32, c1, c2);
1320 }
1321 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&, const CHSV&)
1322 CHSVPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3)
1323 {
1324 fill_gradient( &(entries[0]), 32, c1, c2, c3);
1325 }
1326 /// @copydoc CHSVPalette16::CHSVPalette16(const CHSV&, const CHSV&, const CHSV&, const CHSV&)
1327 CHSVPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
1328 {
1329 fill_gradient( &(entries[0]), 32, c1, c2, c3, c4);
1330 }
1331
1332 };
1333
1334 /// RGB color palette with 32 discrete values
1335 class CRGBPalette32 {
1336 public:
1337 CRGB entries[32]; ///< @copydoc CHSVPalette16::entries
1338
1339 /// @copydoc CRGB::CRGB()
1340 CRGBPalette32() {};
1341
1342 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGB&,
1343 /// const CRGB&, const CRGB&, const CRGB&,
1344 /// const CRGB&, const CRGB&, const CRGB&, const CRGB&,
1345 /// const CRGB&, const CRGB&, const CRGB&, const CRGB&,
1346 /// const CRGB&, const CRGB&, const CRGB&, const CRGB&)
1347 CRGBPalette32( const CRGB& c00,const CRGB& c01,const CRGB& c02,const CRGB& c03,
1348 const CRGB& c04,const CRGB& c05,const CRGB& c06,const CRGB& c07,
1349 const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11,
1350 const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 )
1351 {
1352 for( uint8_t i = 0; i < 2; ++i) {
1353 entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03;
1354 entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07;
1355 entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11;
1356 entries[24+i]=c12; entries[26+i]=c13; entries[28+i]=c14; entries[30+i]=c15;
1357 }
1358 };
1359
1360 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGBPalette16&)
1361 CRGBPalette32( const CRGBPalette32& rhs)
1362 {
1363 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
1364 }
1365 /// Create palette from array of CRGB colors
1366 CRGBPalette32( const CRGB rhs[32])
1367 {
1368 memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
1369 }
1370 /// @copydoc CRGBPalette32(const CRGBPalette32&)
1371 CRGBPalette32& operator=( const CRGBPalette32& rhs)
1372 {
1373 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
1374 return *this;
1375 }
1376 /// Create palette from array of CRGB colors
1377 CRGBPalette32& operator=( const CRGB rhs[32])
1378 {
1379 memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
1380 return *this;
1381 }
1382
1383 /// @copydoc CRGBPalette16::CRGBPalette16(const CHSVPalette16&)
1384 CRGBPalette32( const CHSVPalette32& rhs)
1385 {
1386 for( uint8_t i = 0; i < 32; ++i) {
1387 entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
1388 }
1389 }
1390 /// Create palette from array of CHSV colors
1391 CRGBPalette32( const CHSV rhs[32])
1392 {
1393 for( uint8_t i = 0; i < 32; ++i) {
1394 entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
1395 }
1396 }
1397 /// @copydoc CRGBPalette32(const CHSVPalette32&)
1398 CRGBPalette32& operator=( const CHSVPalette32& rhs)
1399 {
1400 for( uint8_t i = 0; i < 32; ++i) {
1401 entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
1402 }
1403 return *this;
1404 }
1405 /// Create palette from array of CHSV colors
1406 CRGBPalette32& operator=( const CHSV rhs[32])
1407 {
1408 for( uint8_t i = 0; i < 32; ++i) {
1409 entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
1410 }
1411 return *this;
1412 }
1413
1414 /// @copydoc CRGBPalette16::CRGBPalette16(const TProgmemRGBPalette16&)
1415 CRGBPalette32( const TProgmemRGBPalette32& rhs)
1416 {
1417 for( uint8_t i = 0; i < 32; ++i) {
1418 entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
1419 }
1420 }
1421 /// @copydoc CRGBPalette32(const TProgmemRGBPalette32&)
1422 CRGBPalette32& operator=( const TProgmemRGBPalette32& rhs)
1423 {
1424 for( uint8_t i = 0; i < 32; ++i) {
1425 entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
1426 }
1427 return *this;
1428 }
1429
1430 /// @copydoc CRGBPalette16::operator==
1431 bool operator==( const CRGBPalette32 &rhs) const
1432 {
1433 const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
1434 const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
1435 if( p == q) return true;
1436 for( uint8_t i = 0; i < (sizeof( entries)); ++i) {
1437 if( *p != *q) return false;
1438 ++p;
1439 ++q;
1440 }
1441 return true;
1442 }
1443 /// @copydoc CRGBPalette16::operator!=
1444 bool operator!=( const CRGBPalette32 &rhs) const
1445 {
1446 return !( *this == rhs);
1447 }
1448
1449 /// @copydoc CRGBPalette16::operator[]
1450 inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
1451 {
1452 return entries[x];
1453 }
1454 /// @copydoc CRGBPalette16::operator[]
1455 inline const CRGB& operator[] (uint8_t x) const __attribute__((always_inline))
1456 {
1457 return entries[x];
1458 }
1459
1460 /// @copydoc CRGBPalette16::operator[]
1461 inline CRGB& operator[] (int x) __attribute__((always_inline))
1462 {
1463 ✗ return entries[(uint8_t)x];
1464 }
1465 /// @copydoc CRGBPalette16::operator[]
1466 inline const CRGB& operator[] (int x) const __attribute__((always_inline))
1467 {
1468 ✗ return entries[(uint8_t)x];
1469 }
1470
1471 /// Get the underlying pointer to the CRGB entries making up the palette
1472 operator CRGB*()
1473 {
1474 return &(entries[0]);
1475 }
1476
1477 /// @copydoc CRGBPalette16::CRGBPalette16(const CHSV&)
1478 CRGBPalette32( const CHSV& c1)
1479 {
1480 fill_solid( &(entries[0]), 32, c1);
1481 }
1482 /// @copydoc CRGBPalette16::CRGBPalette16(const CHSV&, const CHSV&)
1483 CRGBPalette32( const CHSV& c1, const CHSV& c2)
1484 {
1485 fill_gradient( &(entries[0]), 32, c1, c2);
1486 }
1487 /// @copydoc CRGBPalette16::CRGBPalette16(const CHSV&, const CHSV&, const CHSV&)
1488 CRGBPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3)
1489 {
1490 fill_gradient( &(entries[0]), 32, c1, c2, c3);
1491 }
1492 /// @copydoc CRGBPalette16::CRGBPalette16(const CHSV&, const CHSV&, const CHSV&, const CHSV&)
1493 CRGBPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
1494 {
1495 fill_gradient( &(entries[0]), 32, c1, c2, c3, c4);
1496 }
1497
1498 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGB&)
1499 CRGBPalette32( const CRGB& c1)
1500 {
1501 fill_solid( &(entries[0]), 32, c1);
1502 }
1503 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGB&, const CRGB&)
1504 CRGBPalette32( const CRGB& c1, const CRGB& c2)
1505 {
1506 fill_gradient_RGB( &(entries[0]), 32, c1, c2);
1507 }
1508 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGB&, const CRGB&, const CRGB&)
1509 CRGBPalette32( const CRGB& c1, const CRGB& c2, const CRGB& c3)
1510 {
1511 fill_gradient_RGB( &(entries[0]), 32, c1, c2, c3);
1512 }
1513 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGB&, const CRGB&, const CRGB&, const CRGB&)
1514 CRGBPalette32( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
1515 {
1516 fill_gradient_RGB( &(entries[0]), 32, c1, c2, c3, c4);
1517 }
1518
1519
1520 /// Create upscaled palette from 16-entry palette
1521 CRGBPalette32( const CRGBPalette16& rhs16)
1522 {
1523 UpscalePalette( rhs16, *this);
1524 }
1525 /// @copydoc CRGBPalette32(const CRGBPalette16&)
1526 CRGBPalette32& operator=( const CRGBPalette16& rhs16)
1527 {
1528 UpscalePalette( rhs16, *this);
1529 return *this;
1530 }
1531
1532 /// @copydoc CRGBPalette16::CRGBPalette16(const TProgmemRGBPalette16&)
1533 CRGBPalette32( const TProgmemRGBPalette16& rhs)
1534 {
1535 CRGBPalette16 p16(rhs);
1536 *this = p16;
1537 }
1538 /// @copydoc CRGBPalette32(const TProgmemRGBPalette16&)
1539 CRGBPalette32& operator=( const TProgmemRGBPalette16& rhs)
1540 {
1541 CRGBPalette16 p16(rhs);
1542 *this = p16;
1543 return *this;
1544 }
1545
1546
1547 /// @copydoc CRGBPalette16::CRGBPalette16(TProgmemRGBGradientPalette_bytes)
1548 CRGBPalette32( TProgmemRGBGradientPalette_bytes progpal )
1549 {
1550 *this = progpal;
1551 }
1552 /// @copydoc CRGBPalette32(TProgmemRGBGradientPalette_bytes)
1553 CRGBPalette32& operator=( TProgmemRGBGradientPalette_bytes progpal )
1554 {
1555 TRGBGradientPaletteEntryUnion* progent = (TRGBGradientPaletteEntryUnion*)(progpal);
1556 TRGBGradientPaletteEntryUnion u;
1557
1558 // Count entries
1559 uint16_t count = 0;
1560 do {
1561 u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
1562 ++count;
1563 } while ( u.index != 255);
1564
1565 int8_t lastSlotUsed = -1;
1566
1567 u.dword = FL_PGM_READ_DWORD_NEAR( progent);
1568 CRGB rgbstart( u.r, u.g, u.b);
1569
1570 int indexstart = 0;
1571 uint8_t istart8 = 0;
1572 uint8_t iend8 = 0;
1573 while( indexstart < 255) {
1574 ++progent;
1575 u.dword = FL_PGM_READ_DWORD_NEAR( progent);
1576 int indexend = u.index;
1577 CRGB rgbend( u.r, u.g, u.b);
1578 istart8 = indexstart / 8;
1579 iend8 = indexend / 8;
1580 if( count < 16) {
1581 if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1582 istart8 = lastSlotUsed + 1;
1583 if( iend8 < istart8) {
1584 iend8 = istart8;
1585 }
1586 }
1587 lastSlotUsed = iend8;
1588 }
1589 fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
1590 indexstart = indexend;
1591 rgbstart = rgbend;
1592 }
1593 return *this;
1594 }
1595 /// @copydoc CRGBPalette16::loadDynamicGradientPalette(TDynamicRGBGradientPalette_bytes)
1596 CRGBPalette32& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal )
1597 {
1598 TRGBGradientPaletteEntryUnion* ent = (TRGBGradientPaletteEntryUnion*)(gpal);
1599 TRGBGradientPaletteEntryUnion u;
1600
1601 // Count entries
1602 uint16_t count = 0;
1603 do {
1604 u = *(ent + count);
1605 ++count;
1606 } while ( u.index != 255);
1607
1608 int8_t lastSlotUsed = -1;
1609
1610
1611 u = *ent;
1612 CRGB rgbstart( u.r, u.g, u.b);
1613
1614 int indexstart = 0;
1615 uint8_t istart8 = 0;
1616 uint8_t iend8 = 0;
1617 while( indexstart < 255) {
1618 ++ent;
1619 u = *ent;
1620 int indexend = u.index;
1621 CRGB rgbend( u.r, u.g, u.b);
1622 istart8 = indexstart / 8;
1623 iend8 = indexend / 8;
1624 if( count < 16) {
1625 if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
1626 istart8 = lastSlotUsed + 1;
1627 if( iend8 < istart8) {
1628 iend8 = istart8;
1629 }
1630 }
1631 lastSlotUsed = iend8;
1632 }
1633 fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
1634 indexstart = indexend;
1635 rgbstart = rgbend;
1636 }
1637 return *this;
1638 }
1639
1640 };
1641
1642
1643 /// RGB color palette with 256 discrete values
1644 class CRGBPalette256 {
1645 public:
1646 CRGB entries[256]; ///< @copydoc CHSVPalette16::entries
1647
1648 /// @copydoc CRGB::CRGB()
1649 CRGBPalette256() {};
1650
1651 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGB&,
1652 /// const CRGB&, const CRGB&, const CRGB&,
1653 /// const CRGB&, const CRGB&, const CRGB&, const CRGB&,
1654 /// const CRGB&, const CRGB&, const CRGB&, const CRGB&,
1655 /// const CRGB&, const CRGB&, const CRGB&, const CRGB&)
1656 CRGBPalette256( const CRGB& c00,const CRGB& c01,const CRGB& c02,const CRGB& c03,
1657 const CRGB& c04,const CRGB& c05,const CRGB& c06,const CRGB& c07,
1658 const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11,
1659 const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 )
1660 {
1661 CRGBPalette16 p16(c00,c01,c02,c03,c04,c05,c06,c07,
1662 c08,c09,c10,c11,c12,c13,c14,c15);
1663 *this = p16;
1664 };
1665
1666 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGBPalette16&)
1667 CRGBPalette256( const CRGBPalette256& rhs)
1668 {
1669 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
1670 }
1671 /// Create palette from array of CRGB colors
1672 CRGBPalette256( const CRGB rhs[256])
1673 {
1674 memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
1675 }
1676 /// @copydoc CRGBPalette256(const CRGBPalette256&)
1677 CRGBPalette256& operator=( const CRGBPalette256& rhs)
1678 {
1679 memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
1680 return *this;
1681 }
1682 /// Create palette from array of CRGB colors
1683 CRGBPalette256& operator=( const CRGB rhs[256])
1684 {
1685 memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
1686 return *this;
1687 }
1688
1689 /// @copydoc CRGBPalette16::CRGBPalette16(const CHSVPalette16&)
1690 CRGBPalette256( const CHSVPalette256& rhs)
1691 {
1692 for( int i = 0; i < 256; ++i) {
1693 entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
1694 }
1695 }
1696 /// Create palette from array of CHSV colors
1697 CRGBPalette256( const CHSV rhs[256])
1698 {
1699 for( int i = 0; i < 256; ++i) {
1700 entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
1701 }
1702 }
1703 /// @copydoc CRGBPalette256(const CRGBPalette256&)
1704 CRGBPalette256& operator=( const CHSVPalette256& rhs)
1705 {
1706 for( int i = 0; i < 256; ++i) {
1707 entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
1708 }
1709 return *this;
1710 }
1711 /// Create palette from array of CHSV colors
1712 CRGBPalette256& operator=( const CHSV rhs[256])
1713 {
1714 for( int i = 0; i < 256; ++i) {
1715 entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
1716 }
1717 return *this;
1718 }
1719
1720 /// @copydoc CRGBPalette32::CRGBPalette32(const CRGBPalette16&)
1721 CRGBPalette256( const CRGBPalette16& rhs16)
1722 {
1723 UpscalePalette( rhs16, *this);
1724 }
1725 /// @copydoc CRGBPalette256(const CRGBPalette16&)
1726 CRGBPalette256& operator=( const CRGBPalette16& rhs16)
1727 {
1728 UpscalePalette( rhs16, *this);
1729 return *this;
1730 }
1731
1732 /// @copydoc CRGBPalette16::CRGBPalette16(const TProgmemRGBPalette16&)
1733 CRGBPalette256( const TProgmemRGBPalette16& rhs)
1734 {
1735 CRGBPalette16 p16(rhs);
1736 *this = p16;
1737 }
1738 /// @copydoc CRGBPalette256(const TProgmemRGBPalette16&)
1739 CRGBPalette256& operator=( const TProgmemRGBPalette16& rhs)
1740 {
1741 CRGBPalette16 p16(rhs);
1742 *this = p16;
1743 return *this;
1744 }
1745
1746 /// @copydoc CRGBPalette16::operator==
1747 bool operator==( const CRGBPalette256 &rhs) const
1748 {
1749 const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
1750 const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
1751 if( p == q) return true;
1752 for( uint16_t i = 0; i < (sizeof( entries)); ++i) {
1753 if( *p != *q) return false;
1754 ++p;
1755 ++q;
1756 }
1757 return true;
1758 }
1759 /// @copydoc CRGBPalette16::operator!=
1760 bool operator!=( const CRGBPalette256 &rhs) const
1761 {
1762 return !( *this == rhs);
1763 }
1764
1765 /// @copydoc CRGBPalette16::operator[]
1766 inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
1767 {
1768 ✗ return entries[x];
1769 }
1770 /// @copydoc CRGBPalette16::operator[]
1771 inline const CRGB& operator[] (uint8_t x) const __attribute__((always_inline))
1772 {
1773 return entries[x];
1774 }
1775
1776 /// @copydoc CRGBPalette16::operator[]
1777 inline CRGB& operator[] (int x) __attribute__((always_inline))
1778 {
1779 return entries[(uint8_t)x];
1780 }
1781 /// @copydoc CRGBPalette16::operator[]
1782 inline const CRGB& operator[] (int x) const __attribute__((always_inline))
1783 {
1784 ✗ return entries[(uint8_t)x];
1785 }
1786
1787 /// Get the underlying pointer to the CHSV entries making up the palette
1788 operator CRGB*()
1789 {
1790 return &(entries[0]);
1791 }
1792
1793 /// @copydoc CRGBPalette16::CRGBPalette16(const CHSV&)
1794 CRGBPalette256( const CHSV& c1)
1795 {
1796 fill_solid( &(entries[0]), 256, c1);
1797 }
1798 /// @copydoc CRGBPalette16::CRGBPalette16(const CHSV&, const CHSV&)
1799 CRGBPalette256( const CHSV& c1, const CHSV& c2)
1800 {
1801 fill_gradient( &(entries[0]), 256, c1, c2);
1802 }
1803 /// @copydoc CRGBPalette16::CRGBPalette16(const CHSV&, const CHSV&, const CHSV&)
1804 CRGBPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3)
1805 {
1806 fill_gradient( &(entries[0]), 256, c1, c2, c3);
1807 }
1808 /// @copydoc CRGBPalette16::CRGBPalette16(const CHSV&, const CHSV&, const CHSV&, const CHSV&)
1809 CRGBPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
1810 {
1811 fill_gradient( &(entries[0]), 256, c1, c2, c3, c4);
1812 }
1813
1814 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGB&)
1815 CRGBPalette256( const CRGB& c1)
1816 {
1817 fill_solid( &(entries[0]), 256, c1);
1818 }
1819 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGB&, const CRGB&)
1820 CRGBPalette256( const CRGB& c1, const CRGB& c2)
1821 {
1822 fill_gradient_RGB( &(entries[0]), 256, c1, c2);
1823 }
1824 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGB&, const CRGB&, const CRGB&)
1825 CRGBPalette256( const CRGB& c1, const CRGB& c2, const CRGB& c3)
1826 {
1827 fill_gradient_RGB( &(entries[0]), 256, c1, c2, c3);
1828 }
1829 /// @copydoc CRGBPalette16::CRGBPalette16(const CRGB&, const CRGB&, const CRGB&, const CRGB&)
1830 CRGBPalette256( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
1831 {
1832 fill_gradient_RGB( &(entries[0]), 256, c1, c2, c3, c4);
1833 }
1834
1835 /// @copydoc CRGBPalette16::CRGBPalette16(TProgmemRGBGradientPalette_bytes)
1836 CRGBPalette256( TProgmemRGBGradientPalette_bytes progpal )
1837 {
1838 *this = progpal;
1839 }
1840 /// @copydoc CRGBPalette256(TProgmemRGBGradientPalette_bytes)
1841 CRGBPalette256& operator=( TProgmemRGBGradientPalette_bytes progpal )
1842 {
1843 TRGBGradientPaletteEntryUnion* progent = (TRGBGradientPaletteEntryUnion*)(progpal);
1844 TRGBGradientPaletteEntryUnion u;
1845 u.dword = FL_PGM_READ_DWORD_NEAR( progent);
1846 CRGB rgbstart( u.r, u.g, u.b);
1847
1848 int indexstart = 0;
1849 while( indexstart < 255) {
1850 ++progent;
1851 u.dword = FL_PGM_READ_DWORD_NEAR( progent);
1852 int indexend = u.index;
1853 CRGB rgbend( u.r, u.g, u.b);
1854 fill_gradient_RGB( &(entries[0]), indexstart, rgbstart, indexend, rgbend);
1855 indexstart = indexend;
1856 rgbstart = rgbend;
1857 }
1858 return *this;
1859 }
1860 /// @copydoc CRGBPalette16::loadDynamicGradientPalette(TDynamicRGBGradientPalette_bytes)
1861 CRGBPalette256& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal )
1862 {
1863 TRGBGradientPaletteEntryUnion* ent = (TRGBGradientPaletteEntryUnion*)(gpal);
1864 TRGBGradientPaletteEntryUnion u;
1865 u = *ent;
1866 CRGB rgbstart( u.r, u.g, u.b);
1867
1868 int indexstart = 0;
1869 while( indexstart < 255) {
1870 ++ent;
1871 u = *ent;
1872 int indexend = u.index;
1873 CRGB rgbend( u.r, u.g, u.b);
1874 fill_gradient_RGB( &(entries[0]), indexstart, rgbstart, indexend, rgbend);
1875 indexstart = indexend;
1876 rgbstart = rgbend;
1877 }
1878 return *this;
1879 }
1880 };
1881
1882 /// @} PaletteClasses
1883
1884
1885 /// @defgroup PaletteColors Palette Color Functions
1886 /// Functions to retrieve smooth color data from palettes
1887 /// @{
1888
1889 /// Color interpolation options for palette
1890 typedef enum {
1891 NOBLEND=0, ///< No interpolation between palette entries
1892 LINEARBLEND=1, ///< Linear interpolation between palette entries, with wrap-around from end to the beginning again
1893 LINEARBLEND_NOWRAP=2 ///< Linear interpolation between palette entries, but no wrap-around
1894 } TBlendType;
1895
1896 /// Get a color from a palette.
1897 /// These are the main functions for getting and using palette colors. Regardless
1898 /// of the number of entries in the base palette, this function will interpolate
1899 /// between entries to turn the discrete colors into a smooth gradient.
1900 /// @param pal the palette to retrieve the color from
1901 /// @param index the position in the palette to retrieve the color for (0-255)
1902 /// @param brightness optional brightness value to scale the resulting color
1903 /// @param blendType whether to take the palette entries directly (NOBLEND)
1904 /// or blend linearly between palette entries (LINEARBLEND)
1905 CRGB ColorFromPalette( const CRGBPalette16& pal,
1906 uint8_t index,
1907 uint8_t brightness=255,
1908 TBlendType blendType=LINEARBLEND);
1909
1910 /// @copydoc ColorFromPalette(const CRGBPalette16&, uint8_t, uint8_t, TBlendType)
1911 CRGB ColorFromPalette( const TProgmemRGBPalette16& pal,
1912 uint8_t index,
1913 uint8_t brightness=255,
1914 TBlendType blendType=LINEARBLEND);
1915
1916 /// @copydoc ColorFromPalette(const CRGBPalette16&, uint8_t, uint8_t, TBlendType)
1917 CRGB ColorFromPalette( const CRGBPalette256& pal,
1918 uint8_t index,
1919 uint8_t brightness=255,
1920 TBlendType blendType=NOBLEND );
1921
1922 /// @copydoc ColorFromPalette(const CRGBPalette16&, uint8_t, uint8_t, TBlendType)
1923 CHSV ColorFromPalette( const CHSVPalette16& pal,
1924 uint8_t index,
1925 uint8_t brightness=255,
1926 TBlendType blendType=LINEARBLEND);
1927
1928 /// @copydoc ColorFromPalette(const CRGBPalette16&, uint8_t, uint8_t, TBlendType)
1929 CHSV ColorFromPalette( const CHSVPalette256& pal,
1930 uint8_t index,
1931 uint8_t brightness=255,
1932 TBlendType blendType=NOBLEND );
1933
1934 /// @copydoc ColorFromPalette(const CRGBPalette16&, uint8_t, uint8_t, TBlendType)
1935 CRGB ColorFromPalette( const CRGBPalette32& pal,
1936 uint8_t index,
1937 uint8_t brightness=255,
1938 TBlendType blendType=LINEARBLEND);
1939
1940 /// @copydoc ColorFromPalette(const CRGBPalette16&, uint8_t, uint8_t, TBlendType)
1941 CRGB ColorFromPalette( const TProgmemRGBPalette32& pal,
1942 uint8_t index,
1943 uint8_t brightness=255,
1944 TBlendType blendType=LINEARBLEND);
1945
1946 /// @copydoc ColorFromPalette(const CRGBPalette16&, uint8_t, uint8_t, TBlendType)
1947 CHSV ColorFromPalette( const CHSVPalette32& pal,
1948 uint8_t index,
1949 uint8_t brightness=255,
1950 TBlendType blendType=LINEARBLEND);
1951
1952
1953 /// Fill a range of LEDs with a sequence of entries from a palette
1954 /// @tparam PALETTE the type of the palette used (auto-deduced)
1955 /// @param L pointer to the LED array to fill
1956 /// @param N number of LEDs to fill in the array
1957 /// @param startIndex the starting color index in the palette
1958 /// @param incIndex how much to increment the palette color index per LED
1959 /// @param pal the color palette to pull colors from
1960 /// @param brightness brightness value used to scale the resulting color
1961 /// @param blendType whether to take the palette entries directly (NOBLEND)
1962 /// or blend linearly between palette entries (LINEARBLEND)
1963 template <typename PALETTE>
1964 void fill_palette(CRGB* L, uint16_t N, uint8_t startIndex, uint8_t incIndex,
1965 const PALETTE& pal, uint8_t brightness=255, TBlendType blendType=LINEARBLEND)
1966 {
1967 uint8_t colorIndex = startIndex;
1968 for( uint16_t i = 0; i < N; ++i) {
1969 L[i] = ColorFromPalette( pal, colorIndex, brightness, blendType);
1970 colorIndex += incIndex;
1971 }
1972 }
1973
1974
1975 /// Fill a range of LEDs with a sequence of entries from a palette, so that
1976 /// the entire palette smoothly covers the range of LEDs.
1977 /// @tparam PALETTE the type of the palette used (auto-deduced)
1978 /// @param L pointer to the LED array to fill
1979 /// @param N number of LEDs to fill in the array
1980 /// @param startIndex the starting color index in the palette
1981 /// @param pal the color palette to pull colors from
1982 /// @param brightness brightness value used to scale the resulting color
1983 /// @param blendType whether to take the palette entries directly (NOBLEND)
1984 /// or blend linearly between palette entries (LINEARBLEND)
1985 /// @param reversed whether to progress through the palette backwards
1986 template <typename PALETTE>
1987 void fill_palette_circular(CRGB* L, uint16_t N, uint8_t startIndex,
1988 const PALETTE& pal, uint8_t brightness=255, TBlendType blendType=LINEARBLEND,
1989 bool reversed=false)
1990 {
1991 if (N == 0) return; // avoiding div/0
1992
1993 const uint16_t colorChange = 65535 / N; // color change for each LED, * 256 for precision
1994 uint16_t colorIndex = ((uint16_t) startIndex) << 8; // offset for color index, with precision (*256)
1995
1996 for (uint16_t i = 0; i < N; ++i) {
1997 L[i] = ColorFromPalette(pal, (colorIndex >> 8), brightness, blendType);
1998 if (reversed) colorIndex -= colorChange;
1999 else colorIndex += colorChange;
2000 }
2001 }
2002
2003
2004 /// Maps an array of palette color indexes into an array of LED colors.
2005 ///
2006 /// This function provides an easy way to create lightweight color patterns that
2007 /// can be deployed using any palette.
2008 ///
2009 /// @param dataArray the source array, containing color indexes for the palette
2010 /// @param dataCount the number of data elements in the array
2011 /// @param targetColorArray the LED array to store the resulting colors into. Must be
2012 /// at least as long as `dataCount`.
2013 /// @param pal the color palette to pull colors from
2014 /// @param brightness optional brightness value used to scale the resulting color
2015 /// @param opacity optional opacity value for the new color. If this is 255 (default),
2016 /// the new colors will be written to the array directly. Otherwise the existing LED
2017 /// data will be scaled down using `CRGB::nscale8_video()` and then new colors will
2018 /// be added on top. A higher value means that the new colors will be more visible.
2019 /// @param blendType whether to take the palette entries directly (NOBLEND)
2020 /// or blend linearly between palette entries (LINEARBLEND)
2021 template <typename PALETTE>
2022 void map_data_into_colors_through_palette(
2023 uint8_t *dataArray, uint16_t dataCount,
2024 CRGB* targetColorArray,
2025 const PALETTE& pal,
2026 uint8_t brightness=255,
2027 uint8_t opacity=255,
2028 TBlendType blendType=LINEARBLEND)
2029 {
2030 for( uint16_t i = 0; i < dataCount; ++i) {
2031 uint8_t d = dataArray[i];
2032 CRGB rgb = ColorFromPalette( pal, d, brightness, blendType);
2033 if( opacity == 255 ) {
2034 targetColorArray[i] = rgb;
2035 } else {
2036 targetColorArray[i].nscale8( 256 - opacity);
2037 rgb.nscale8_video( opacity);
2038 targetColorArray[i] += rgb;
2039 }
2040 }
2041 }
2042
2043
2044 /// Alter one palette by making it slightly more like a "target palette".
2045 /// Used for palette cross-fades.
2046 ///
2047 /// It does this by comparing each of the R, G, and B channels
2048 /// of each entry in the current palette to the corresponding
2049 /// entry in the target palette and making small adjustments:
2050 /// * If the CRGB::red channel is too low, it will be increased.
2051 /// * If the CRGB::red channel is too high, it will be slightly reduced.
2052 ///
2053 /// ...and so on and so forth for the CRGB::green and CRGB::blue channels.
2054 ///
2055 /// Additionally, there are two significant visual improvements
2056 /// to this algorithm implemented here. First is this:
2057 /// * When increasing a channel, it is stepped up by ONE.
2058 /// * When decreasing a channel, it is stepped down by TWO.
2059 ///
2060 /// Due to the way the eye perceives light, and the way colors
2061 /// are represented in RGB, this produces a more uniform apparent
2062 /// brightness when cross-fading between most palette colors.
2063 ///
2064 /// The second visual tweak is limiting the number of changes
2065 /// that will be made to the palette at once. If all the palette
2066 /// entries are changed at once, it can give a muddled appearance.
2067 /// However, if only a *few* palette entries are changed at once,
2068 /// you get a visually smoother transition: in the middle of the
2069 /// cross-fade your current palette will actually contain some
2070 /// colors from the old palette, a few blended colors, and some
2071 /// colors from the new palette.
2072 ///
2073 /// @param currentPalette the palette to modify
2074 /// @param targetPalette the palette to move towards
2075 /// @param maxChanges the maximum number of possible palette changes
2076 /// to make to the color channels per call. The limit is 48 (16 color
2077 /// entries times 3 channels each). The default is 24, meaning that
2078 /// only half of the palette entries can be changed per call.
2079 /// @warning The palette passed as `currentPalette` will be modified! Be sure
2080 /// to make a copy beforehand if needed.
2081 /// @todo Shouldn't the `targetPalette` be `const`?
2082 void nblendPaletteTowardPalette( CRGBPalette16& currentPalette,
2083 CRGBPalette16& targetPalette,
2084 uint8_t maxChanges=24);
2085
2086 /// @} PaletteColors
2087
2088
2089 /// Defines a static RGB palette very compactly using a series
2090 /// of connected color gradients.
2091 ///
2092 /// For example, if you want the first 3/4ths of the palette to be a slow
2093 /// gradient ramping from black to red, and then the remaining 1/4 of the
2094 /// palette to be a quicker ramp to white, you specify just three points: the
2095 /// starting black point (at index 0), the red midpoint (at index 192),
2096 /// and the final white point (at index 255). It looks like this:
2097 /// @code
2098 /// index: 0 192 255
2099 /// |----------r-r-r-rrrrrrrrRrRrRrRrRRRR-|-RRWRWWRWWW-|
2100 /// color: (0,0,0) (255,0,0) (255,255,255)
2101 /// @endcode
2102 ///
2103 /// Here's how you'd define that gradient palette using this macro:
2104 /// @code{.cpp}
2105 /// DEFINE_GRADIENT_PALETTE( black_to_red_to_white_p ) {
2106 /// 0, 0, 0, 0, /* at index 0, black(0,0,0) */
2107 /// 192, 255, 0, 0, /* at index 192, red(255,0,0) */
2108 /// 255, 255, 255, 255 /* at index 255, white(255,255,255) */
2109 /// };
2110 /// @endcode
2111 ///
2112 /// This format is designed for compact storage. The example palette here
2113 /// takes up just 12 bytes of PROGMEM (flash) storage, and zero bytes
2114 /// of SRAM when not currently in use.
2115 ///
2116 /// To use one of these gradient palettes, simply assign it into a
2117 /// CRGBPalette16 or a CRGBPalette256, like this:
2118 /// @code{.cpp}
2119 /// CRGBPalette16 pal = black_to_red_to_white_p;
2120 /// @endcode
2121 ///
2122 /// When the assignment is made, the gradients are expanded out into
2123 /// either 16 or 256 palette entries, depending on the kind of palette
2124 /// object they're assigned to.
2125 ///
2126 /// @warning The last "index" position **MUST** be 255! Failure to end
2127 /// with index 255 will result in program hangs or crashes.
2128 /// @par
2129 /// @warning At this point, these gradient palette definitions **MUST**
2130 /// be stored in PROGMEM on AVR-based Arduinos. If you use the
2131 /// `DEFINE_GRADIENT_PALETTE` macro, this is taken of automatically.
2132 ///
2133 #define DEFINE_GRADIENT_PALETTE(X) \
2134 FL_ALIGN_PROGMEM \
2135 extern const TProgmemRGBGradientPalette_byte X[] FL_PROGMEM =
2136
2137 /// Forward-declaration macro for DEFINE_GRADIENT_PALETTE(X)
2138 #define DECLARE_GRADIENT_PALETTE(X) \
2139 FL_ALIGN_PROGMEM \
2140 extern const TProgmemRGBGradientPalette_byte X[] FL_PROGMEM
2141
2142 /// @} ColorPalettes
2143
2144
2145 /// @defgroup GammaFuncs Gamma Adjustment Functions
2146 /// Functions for applying gamma adjustments to LED data.
2147 ///
2148 /// Gamma correction tries to compensate for the non-linear
2149 /// manner in which humans perceive light and color. Gamma
2150 /// correction is applied using the following expression:
2151 /// @code{.cpp}
2152 /// output = pow(input / 255.0, gamma) * 255.0;
2153 /// @endcode
2154 ///
2155 /// Larger gamma values result in darker images that have more contrast.
2156 /// Lower gamma values result in lighter images with less contrast.
2157 ///
2158 /// These functions apply either:
2159 /// * a single gamma adjustment to a single scalar value
2160 /// * a single gamma adjustment to each channel of a CRGB color, or
2161 /// * different gamma adjustments for each channel of a CRGB color
2162 ///
2163 /// Note that the gamma is specified as a traditional floating point value,
2164 /// e.g., "2.5", and as such these functions should not be called in
2165 /// your innermost pixel loops, or in animations that are extremely
2166 /// low on program storage space. Nevertheless, if you need these
2167 /// functions, here they are.
2168 ///
2169 /// Furthermore, bear in mind that CRGB LEDs have only eight bits
2170 /// per channel of color resolution, and that very small, subtle shadings
2171 /// may not be visible.
2172 ///
2173 /// @see @ref Dimming
2174 /// @see https://en.wikipedia.org/wiki/Gamma_correction
2175 /// @{
2176
2177 /// Applies a gamma adjustment to a color channel
2178 /// @param brightness the value of the color data
2179 /// @param gamma the gamma value to apply
2180 /// @returns the color data, adjusted for gamma
2181 uint8_t applyGamma_video( uint8_t brightness, float gamma);
2182
2183 /// Applies a gamma adjustment to a color
2184 /// @param orig the color to apply an adjustment to
2185 /// @param gamma the gamma value to apply
2186 /// @returns copy of the CRGB object with gamma adjustment applied
2187 CRGB applyGamma_video( const CRGB& orig, float gamma);
2188
2189 /// Applies a gamma adjustment to a color
2190 /// @param orig the color to apply an adjustment to
2191 /// @param gammaR the gamma value to apply to the CRGB::red channel
2192 /// @param gammaG the gamma value to apply to the CRGB::green channel
2193 /// @param gammaB the gamma value to apply to the CRGB::blue channel
2194 /// @returns copy of the CRGB object with gamma adjustment applied
2195 CRGB applyGamma_video( const CRGB& orig, float gammaR, float gammaG, float gammaB);
2196
2197
2198 /// Destructively applies a gamma adjustment to a color
2199 /// @param rgb the color to apply an adjustment to (modified in place)
2200 /// @param gamma the gamma value to apply
2201 CRGB& napplyGamma_video( CRGB& rgb, float gamma);
2202
2203 /// Destructively applies a gamma adjustment to a color
2204 /// @param rgb the color to apply an adjustment to (modified in place)
2205 /// @param gammaR the gamma value to apply to the CRGB::red channel
2206 /// @param gammaG the gamma value to apply to the CRGB::green channel
2207 /// @param gammaB the gamma value to apply to the CRGB::blue channel
2208 CRGB& napplyGamma_video( CRGB& rgb, float gammaR, float gammaG, float gammaB);
2209
2210 /// Destructively applies a gamma adjustment to a color array
2211 /// @param rgbarray pointer to an LED array to apply an adjustment to (modified in place)
2212 /// @param count the number of LEDs to modify
2213 /// @param gamma the gamma value to apply
2214 void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gamma);
2215
2216 /// Destructively applies a gamma adjustment to a color array
2217 /// @param rgbarray pointer to an LED array to apply an adjustment to (modified in place)
2218 /// @param count the number of LEDs to modify
2219 /// @param gammaR the gamma value to apply to the CRGB::red channel
2220 /// @param gammaG the gamma value to apply to the CRGB::green channel
2221 /// @param gammaB the gamma value to apply to the CRGB::blue channel
2222 void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gammaR, float gammaG, float gammaB);
2223
2224 /// @} GammaFuncs
2225
2226 FASTLED_NAMESPACE_END
2227
2228 #endif
2229