FastLED 3.6.0
Loading...
Searching...
No Matches
colorutils.cpp
Go to the documentation of this file.
1#define FASTLED_INTERNAL
2#define __PROG_TYPES_COMPAT__
3
6
7#include <stdint.h>
8#include <math.h>
9
10#include "FastLED.h"
11
12FASTLED_NAMESPACE_BEGIN
13
14
15
16void fill_solid( struct CRGB * targetArray, int numToFill,
17 const struct CRGB& color)
18{
19 for( int i = 0; i < numToFill; ++i) {
20 targetArray[i] = color;
21 }
22}
23
24void fill_solid( struct CHSV * targetArray, int numToFill,
25 const struct CHSV& color)
26{
27 for( int i = 0; i < numToFill; ++i) {
28 targetArray[i] = color;
29 }
30}
31
32
33// void fill_solid( struct CRGB* targetArray, int numToFill,
34// const struct CHSV& hsvColor)
35// {
36// fill_solid<CRGB>( targetArray, numToFill, (CRGB) hsvColor);
37// }
38
39void fill_rainbow( struct CRGB * targetArray, int numToFill,
40 uint8_t initialhue,
41 uint8_t deltahue )
42{
43 CHSV hsv;
44 hsv.hue = initialhue;
45 hsv.val = 255;
46 hsv.sat = 240;
47 for( int i = 0; i < numToFill; ++i) {
48 targetArray[i] = hsv;
49 hsv.hue += deltahue;
50 }
51}
52
53void fill_rainbow( struct CHSV * targetArray, int numToFill,
54 uint8_t initialhue,
55 uint8_t deltahue )
56{
57 CHSV hsv;
58 hsv.hue = initialhue;
59 hsv.val = 255;
60 hsv.sat = 240;
61 for( int i = 0; i < numToFill; ++i) {
62 targetArray[i] = hsv;
63 hsv.hue += deltahue;
64 }
65}
66
67
68void fill_rainbow_circular(struct CRGB* targetArray, int numToFill, uint8_t initialhue, bool reversed)
69{
70 if (numToFill == 0) return; // avoiding div/0
71
72 CHSV hsv;
73 hsv.hue = initialhue;
74 hsv.val = 255;
75 hsv.sat = 240;
76
77 const uint16_t hueChange = 65535 / (uint16_t)numToFill; // hue change for each LED, * 256 for precision (256 * 256 - 1)
78 uint16_t hueOffset = 0; // offset for hue value, with precision (*256)
79
80 for (int i = 0; i < numToFill; ++i) {
81 targetArray[i] = hsv;
82 if (reversed) hueOffset -= hueChange;
83 else hueOffset += hueChange;
84 hsv.hue = initialhue + (uint8_t)(hueOffset >> 8); // assign new hue with precise offset (as 8-bit)
85 }
86}
87
88void fill_rainbow_circular(struct CHSV* targetArray, int numToFill, uint8_t initialhue, bool reversed)
89{
90 if (numToFill == 0) return; // avoiding div/0
91
92 CHSV hsv;
93 hsv.hue = initialhue;
94 hsv.val = 255;
95 hsv.sat = 240;
96
97 const uint16_t hueChange = 65535 / (uint16_t) numToFill; // hue change for each LED, * 256 for precision (256 * 256 - 1)
98 uint16_t hueOffset = 0; // offset for hue value, with precision (*256)
99
100 for (int i = 0; i < numToFill; ++i) {
101 targetArray[i] = hsv;
102 if (reversed) hueOffset -= hueChange;
103 else hueOffset += hueChange;
104 hsv.hue = initialhue + (uint8_t)(hueOffset >> 8); // assign new hue with precise offset (as 8-bit)
105 }
106}
107
108
110 uint16_t startpos, CRGB startcolor,
111 uint16_t endpos, CRGB endcolor )
112{
113 // if the points are in the wrong order, straighten them
114 if( endpos < startpos ) {
115 uint16_t t = endpos;
116 CRGB tc = endcolor;
117 endcolor = startcolor;
118 endpos = startpos;
119 startpos = t;
120 startcolor = tc;
121 }
122
123 saccum87 rdistance87;
124 saccum87 gdistance87;
125 saccum87 bdistance87;
126
127 rdistance87 = (endcolor.r - startcolor.r) << 7;
128 gdistance87 = (endcolor.g - startcolor.g) << 7;
129 bdistance87 = (endcolor.b - startcolor.b) << 7;
130
131 uint16_t pixeldistance = endpos - startpos;
132 int16_t divisor = pixeldistance ? pixeldistance : 1;
133
134 saccum87 rdelta87 = rdistance87 / divisor;
135 saccum87 gdelta87 = gdistance87 / divisor;
136 saccum87 bdelta87 = bdistance87 / divisor;
137
138 rdelta87 *= 2;
139 gdelta87 *= 2;
140 bdelta87 *= 2;
141
142 accum88 r88 = startcolor.r << 8;
143 accum88 g88 = startcolor.g << 8;
144 accum88 b88 = startcolor.b << 8;
145 for( uint16_t i = startpos; i <= endpos; ++i) {
146 leds[i] = CRGB( r88 >> 8, g88 >> 8, b88 >> 8);
147 r88 += rdelta87;
148 g88 += gdelta87;
149 b88 += bdelta87;
150 }
151}
152
153#if 0
154void fill_gradient( const CHSV& c1, const CHSV& c2)
155{
156 fill_gradient( FastLED[0].leds(), FastLED[0].size(), c1, c2);
157}
158
159void fill_gradient( const CHSV& c1, const CHSV& c2, const CHSV& c3)
160{
161 fill_gradient( FastLED[0].leds(), FastLED[0].size(), c1, c2, c3);
162}
163
164void fill_gradient( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
165{
166 fill_gradient( FastLED[0].leds(), FastLED[0].size(), c1, c2, c3, c4);
167}
168
169void fill_gradient_RGB( const CRGB& c1, const CRGB& c2)
170{
171 fill_gradient_RGB( FastLED[0].leds(), FastLED[0].size(), c1, c2);
172}
173
174void fill_gradient_RGB( const CRGB& c1, const CRGB& c2, const CRGB& c3)
175{
176 fill_gradient_RGB( FastLED[0].leds(), FastLED[0].size(), c1, c2, c3);
177}
178
179void fill_gradient_RGB( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
180{
181 fill_gradient_RGB( FastLED[0].leds(), FastLED[0].size(), c1, c2, c3, c4);
182}
183#endif
184
185
186
187
188void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2)
189{
190 uint16_t last = numLeds - 1;
191 fill_gradient_RGB( leds, 0, c1, last, c2);
192}
193
194
195void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2, const CRGB& c3)
196{
197 uint16_t half = (numLeds / 2);
198 uint16_t last = numLeds - 1;
199 fill_gradient_RGB( leds, 0, c1, half, c2);
200 fill_gradient_RGB( leds, half, c2, last, c3);
201}
202
203void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
204{
205 uint16_t onethird = (numLeds / 3);
206 uint16_t twothirds = ((numLeds * 2) / 3);
207 uint16_t last = numLeds - 1;
208 fill_gradient_RGB( leds, 0, c1, onethird, c2);
209 fill_gradient_RGB( leds, onethird, c2, twothirds, c3);
210 fill_gradient_RGB( leds, twothirds, c3, last, c4);
211}
212
213
214
215
216void nscale8_video( CRGB* leds, uint16_t num_leds, uint8_t scale)
217{
218 for( uint16_t i = 0; i < num_leds; ++i) {
219 leds[i].nscale8_video( scale);
220 }
221}
222
223void fade_video(CRGB* leds, uint16_t num_leds, uint8_t fadeBy)
224{
225 nscale8_video( leds, num_leds, 255 - fadeBy);
226}
227
228void fadeLightBy(CRGB* leds, uint16_t num_leds, uint8_t fadeBy)
229{
230 nscale8_video( leds, num_leds, 255 - fadeBy);
231}
232
233
234void fadeToBlackBy( CRGB* leds, uint16_t num_leds, uint8_t fadeBy)
235{
236 nscale8( leds, num_leds, 255 - fadeBy);
237}
238
239void fade_raw( CRGB* leds, uint16_t num_leds, uint8_t fadeBy)
240{
241 nscale8( leds, num_leds, 255 - fadeBy);
242}
243
246void nscale8_raw( CRGB* leds, uint16_t num_leds, uint8_t scale)
247{
248 nscale8( leds, num_leds, scale);
249}
250
251void nscale8( CRGB* leds, uint16_t num_leds, uint8_t scale)
252{
253 for( uint16_t i = 0; i < num_leds; ++i) {
254 leds[i].nscale8( scale);
255 }
256}
257
258void fadeUsingColor( CRGB* leds, uint16_t numLeds, const CRGB& colormask)
259{
260 uint8_t fr, fg, fb;
261 fr = colormask.r;
262 fg = colormask.g;
263 fb = colormask.b;
264
265 for( uint16_t i = 0; i < numLeds; ++i) {
266 leds[i].r = scale8_LEAVING_R1_DIRTY( leds[i].r, fr);
267 leds[i].g = scale8_LEAVING_R1_DIRTY( leds[i].g, fg);
268 leds[i].b = scale8 ( leds[i].b, fb);
269 }
270}
271
272
273CRGB& nblend( CRGB& existing, const CRGB& overlay, fract8 amountOfOverlay )
274{
275 if( amountOfOverlay == 0) {
276 return existing;
277 }
278
279 if( amountOfOverlay == 255) {
280 existing = overlay;
281 return existing;
282 }
283
284#if 0
285 // Old blend method which unfortunately had some rounding errors
286 fract8 amountOfKeep = 255 - amountOfOverlay;
287
288 existing.red = scale8_LEAVING_R1_DIRTY( existing.red, amountOfKeep)
289 + scale8_LEAVING_R1_DIRTY( overlay.red, amountOfOverlay);
290 existing.green = scale8_LEAVING_R1_DIRTY( existing.green, amountOfKeep)
291 + scale8_LEAVING_R1_DIRTY( overlay.green, amountOfOverlay);
292 existing.blue = scale8_LEAVING_R1_DIRTY( existing.blue, amountOfKeep)
293 + scale8_LEAVING_R1_DIRTY( overlay.blue, amountOfOverlay);
294
295 cleanup_R1();
296#else
297 // Corrected blend method, with no loss-of-precision rounding errors
298 existing.red = blend8( existing.red, overlay.red, amountOfOverlay);
299 existing.green = blend8( existing.green, overlay.green, amountOfOverlay);
300 existing.blue = blend8( existing.blue, overlay.blue, amountOfOverlay);
301#endif
302
303 return existing;
304}
305
306
307
308void nblend( CRGB* existing, CRGB* overlay, uint16_t count, fract8 amountOfOverlay)
309{
310 for( uint16_t i = count; i; --i) {
311 nblend( *existing, *overlay, amountOfOverlay);
312 ++existing;
313 ++overlay;
314 }
315}
316
317CRGB blend( const CRGB& p1, const CRGB& p2, fract8 amountOfP2 )
318{
319 CRGB nu(p1);
320 nblend( nu, p2, amountOfP2);
321 return nu;
322}
323
324CRGB* blend( const CRGB* src1, const CRGB* src2, CRGB* dest, uint16_t count, fract8 amountOfsrc2 )
325{
326 for( uint16_t i = 0; i < count; ++i) {
327 dest[i] = blend(src1[i], src2[i], amountOfsrc2);
328 }
329 return dest;
330}
331
332
333
334CHSV& nblend( CHSV& existing, const CHSV& overlay, fract8 amountOfOverlay, TGradientDirectionCode directionCode)
335{
336 if( amountOfOverlay == 0) {
337 return existing;
338 }
339
340 if( amountOfOverlay == 255) {
341 existing = overlay;
342 return existing;
343 }
344
345 fract8 amountOfKeep = 255 - amountOfOverlay;
346
347 uint8_t huedelta8 = overlay.hue - existing.hue;
348
349 if( directionCode == SHORTEST_HUES ) {
350 directionCode = FORWARD_HUES;
351 if( huedelta8 > 127) {
352 directionCode = BACKWARD_HUES;
353 }
354 }
355
356 if( directionCode == LONGEST_HUES ) {
357 directionCode = FORWARD_HUES;
358 if( huedelta8 < 128) {
359 directionCode = BACKWARD_HUES;
360 }
361 }
362
363 if( directionCode == FORWARD_HUES) {
364 existing.hue = existing.hue + scale8( huedelta8, amountOfOverlay);
365 }
366 else /* directionCode == BACKWARD_HUES */
367 {
368 huedelta8 = -huedelta8;
369 existing.hue = existing.hue - scale8( huedelta8, amountOfOverlay);
370 }
371
372 existing.sat = scale8_LEAVING_R1_DIRTY( existing.sat, amountOfKeep)
373 + scale8_LEAVING_R1_DIRTY( overlay.sat, amountOfOverlay);
374 existing.val = scale8_LEAVING_R1_DIRTY( existing.val, amountOfKeep)
375 + scale8_LEAVING_R1_DIRTY( overlay.val, amountOfOverlay);
376
377 cleanup_R1();
378
379 return existing;
380}
381
382
383
384void nblend( CHSV* existing, CHSV* overlay, uint16_t count, fract8 amountOfOverlay, TGradientDirectionCode directionCode )
385{
386 if(existing == overlay) return;
387 for( uint16_t i = count; i; --i) {
388 nblend( *existing, *overlay, amountOfOverlay, directionCode);
389 ++existing;
390 ++overlay;
391 }
392}
393
394CHSV blend( const CHSV& p1, const CHSV& p2, fract8 amountOfP2, TGradientDirectionCode directionCode )
395{
396 CHSV nu(p1);
397 nblend( nu, p2, amountOfP2, directionCode);
398 return nu;
399}
400
401CHSV* blend( const CHSV* src1, const CHSV* src2, CHSV* dest, uint16_t count, fract8 amountOfsrc2, TGradientDirectionCode directionCode )
402{
403 for( uint16_t i = 0; i < count; ++i) {
404 dest[i] = blend(src1[i], src2[i], amountOfsrc2, directionCode);
405 }
406 return dest;
407}
408
409
410
413uint16_t XY( uint8_t, uint8_t);// __attribute__ ((weak));
414
415
416// blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors.
417// blur2d: two-dimensional blur filter. Spreads light to 8 XY neighbors.
418//
419// 0 = no spread at all
420// 64 = moderate spreading
421// 172 = maximum smooth, even spreading
422//
423// 173..255 = wider spreading, but increasing flicker
424//
425// Total light is NOT entirely conserved, so many repeated
426// calls to 'blur' will also result in the light fading,
427// eventually all the way to black; this is by design so that
428// it can be used to (slowly) clear the LEDs to black.
429void blur1d( CRGB* leds, uint16_t numLeds, fract8 blur_amount)
430{
431 uint8_t keep = 255 - blur_amount;
432 uint8_t seep = blur_amount >> 1;
433 CRGB carryover = CRGB::Black;
434 for( uint16_t i = 0; i < numLeds; ++i) {
435 CRGB cur = leds[i];
436 CRGB part = cur;
437 part.nscale8( seep);
438 cur.nscale8( keep);
439 cur += carryover;
440 if( i) leds[i-1] += part;
441 leds[i] = cur;
442 carryover = part;
443 }
444}
445
446void blur2d( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount)
447{
448 blurRows(leds, width, height, blur_amount);
449 blurColumns(leds, width, height, blur_amount);
450}
451
452void blurRows( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount)
453{
454/* for( uint8_t row = 0; row < height; row++) {
455 CRGB* rowbase = leds + (row * width);
456 blur1d( rowbase, width, blur_amount);
457 }
458*/
459 // blur rows same as columns, for irregular matrix
460 uint8_t keep = 255 - blur_amount;
461 uint8_t seep = blur_amount >> 1;
462 for( uint8_t row = 0; row < height; row++) {
463 CRGB carryover = CRGB::Black;
464 for( uint8_t i = 0; i < width; i++) {
465 CRGB cur = leds[XY(i,row)];
466 CRGB part = cur;
467 part.nscale8( seep);
468 cur.nscale8( keep);
469 cur += carryover;
470 if( i) leds[XY(i-1,row)] += part;
471 leds[XY(i,row)] = cur;
472 carryover = part;
473 }
474 }
475}
476
477// blurColumns: perform a blur1d on each column of a rectangular matrix
478void blurColumns(CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount)
479{
480 // blur columns
481 uint8_t keep = 255 - blur_amount;
482 uint8_t seep = blur_amount >> 1;
483 for( uint8_t col = 0; col < width; ++col) {
484 CRGB carryover = CRGB::Black;
485 for( uint8_t i = 0; i < height; ++i) {
486 CRGB cur = leds[XY(col,i)];
487 CRGB part = cur;
488 part.nscale8( seep);
489 cur.nscale8( keep);
490 cur += carryover;
491 if( i) leds[XY(col,i-1)] += part;
492 leds[XY(col,i)] = cur;
493 carryover = part;
494 }
495 }
496}
497
498
499
500// CRGB HeatColor( uint8_t temperature)
501//
502// Approximates a 'black body radiation' spectrum for
503// a given 'heat' level. This is useful for animations of 'fire'.
504// Heat is specified as an arbitrary scale from 0 (cool) to 255 (hot).
505// This is NOT a chromatically correct 'black body radiation'
506// spectrum, but it's surprisingly close, and it's fast and small.
507//
508// On AVR/Arduino, this typically takes around 70 bytes of program memory,
509// versus 768 bytes for a full 256-entry RGB lookup table.
510
511CRGB HeatColor( uint8_t temperature)
512{
513 CRGB heatcolor;
514
515 // Scale 'heat' down from 0-255 to 0-191,
516 // which can then be easily divided into three
517 // equal 'thirds' of 64 units each.
518 uint8_t t192 = scale8_video( temperature, 191);
519
520 // calculate a value that ramps up from
521 // zero to 255 in each 'third' of the scale.
522 uint8_t heatramp = t192 & 0x3F; // 0..63
523 heatramp <<= 2; // scale up to 0..252
524
525 // now figure out which third of the spectrum we're in:
526 if( t192 & 0x80) {
527 // we're in the hottest third
528 heatcolor.r = 255; // full red
529 heatcolor.g = 255; // full green
530 heatcolor.b = heatramp; // ramp up blue
531
532 } else if( t192 & 0x40 ) {
533 // we're in the middle third
534 heatcolor.r = 255; // full red
535 heatcolor.g = heatramp; // ramp up green
536 heatcolor.b = 0; // no blue
537
538 } else {
539 // we're in the coolest third
540 heatcolor.r = heatramp; // ramp up red
541 heatcolor.g = 0; // no green
542 heatcolor.b = 0; // no blue
543 }
544
545 return heatcolor;
546}
547
548
553inline uint8_t lsrX4( uint8_t dividend) __attribute__((always_inline));
554inline uint8_t lsrX4( uint8_t dividend)
555{
556#if defined(__AVR__)
557 dividend /= 2;
558 dividend /= 2;
559 dividend /= 2;
560 dividend /= 2;
561#else
562 dividend >>= 4;
563#endif
564 return dividend;
565}
566
567
568CRGB ColorFromPalette( const CRGBPalette16& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
569{
570 if ( blendType == LINEARBLEND_NOWRAP) {
571 index = map8(index, 0, 239); // Blend range is affected by lo4 blend of values, remap to avoid wrapping
572 }
573
574 // hi4 = index >> 4;
575 uint8_t hi4 = lsrX4(index);
576 uint8_t lo4 = index & 0x0F;
577
578 // const CRGB* entry = &(pal[0]) + hi4;
579 // since hi4 is always 0..15, hi4 * sizeof(CRGB) can be a single-byte value,
580 // instead of the two byte 'int' that avr-gcc defaults to.
581 // So, we multiply hi4 X sizeof(CRGB), giving hi4XsizeofCRGB;
582 uint8_t hi4XsizeofCRGB = hi4 * sizeof(CRGB);
583 // We then add that to a base array pointer.
584 const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + hi4XsizeofCRGB);
585
586 uint8_t blend = lo4 && (blendType != NOBLEND);
587
588 uint8_t red1 = entry->red;
589 uint8_t green1 = entry->green;
590 uint8_t blue1 = entry->blue;
591
592
593 if( blend ) {
594
595 if( hi4 == 15 ) {
596 entry = &(pal[0]);
597 } else {
598 ++entry;
599 }
600
601 uint8_t f2 = lo4 << 4;
602 uint8_t f1 = 255 - f2;
603
604 // rgb1.nscale8(f1);
605 uint8_t red2 = entry->red;
606 red1 = scale8_LEAVING_R1_DIRTY( red1, f1);
607 red2 = scale8_LEAVING_R1_DIRTY( red2, f2);
608 red1 += red2;
609
610 uint8_t green2 = entry->green;
611 green1 = scale8_LEAVING_R1_DIRTY( green1, f1);
612 green2 = scale8_LEAVING_R1_DIRTY( green2, f2);
613 green1 += green2;
614
615 uint8_t blue2 = entry->blue;
616 blue1 = scale8_LEAVING_R1_DIRTY( blue1, f1);
617 blue2 = scale8_LEAVING_R1_DIRTY( blue2, f2);
618 blue1 += blue2;
619
620 cleanup_R1();
621 }
622
623 if( brightness != 255) {
624 if( brightness ) {
625 ++brightness; // adjust for rounding
626 // Now, since brightness is nonzero, we don't need the full scale8_video logic;
627 // we can just to scale8 and then add one (unless scale8 fixed) to all nonzero inputs.
628 if( red1 ) {
629 red1 = scale8_LEAVING_R1_DIRTY( red1, brightness);
630#if !(FASTLED_SCALE8_FIXED==1)
631 ++red1;
632#endif
633 }
634 if( green1 ) {
635 green1 = scale8_LEAVING_R1_DIRTY( green1, brightness);
636#if !(FASTLED_SCALE8_FIXED==1)
637 ++green1;
638#endif
639 }
640 if( blue1 ) {
641 blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness);
642#if !(FASTLED_SCALE8_FIXED==1)
643 ++blue1;
644#endif
645 }
646 cleanup_R1();
647 } else {
648 red1 = 0;
649 green1 = 0;
650 blue1 = 0;
651 }
652 }
653
654 return CRGB( red1, green1, blue1);
655}
656
657CRGB ColorFromPalette( const TProgmemRGBPalette16& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
658{
659 if ( blendType == LINEARBLEND_NOWRAP) {
660 index = map8(index, 0, 239); // Blend range is affected by lo4 blend of values, remap to avoid wrapping
661 }
662
663 // hi4 = index >> 4;
664 uint8_t hi4 = lsrX4(index);
665 uint8_t lo4 = index & 0x0F;
666
667 CRGB entry = FL_PGM_READ_DWORD_NEAR( &(pal[0]) + hi4 );
668
669
670 uint8_t red1 = entry.red;
671 uint8_t green1 = entry.green;
672 uint8_t blue1 = entry.blue;
673
674 uint8_t blend = lo4 && (blendType != NOBLEND);
675
676 if( blend ) {
677
678 if( hi4 == 15 ) {
679 entry = FL_PGM_READ_DWORD_NEAR( &(pal[0]) );
680 } else {
681 entry = FL_PGM_READ_DWORD_NEAR( &(pal[1]) + hi4 );
682 }
683
684 uint8_t f2 = lo4 << 4;
685 uint8_t f1 = 255 - f2;
686
687 uint8_t red2 = entry.red;
688 red1 = scale8_LEAVING_R1_DIRTY( red1, f1);
689 red2 = scale8_LEAVING_R1_DIRTY( red2, f2);
690 red1 += red2;
691
692 uint8_t green2 = entry.green;
693 green1 = scale8_LEAVING_R1_DIRTY( green1, f1);
694 green2 = scale8_LEAVING_R1_DIRTY( green2, f2);
695 green1 += green2;
696
697 uint8_t blue2 = entry.blue;
698 blue1 = scale8_LEAVING_R1_DIRTY( blue1, f1);
699 blue2 = scale8_LEAVING_R1_DIRTY( blue2, f2);
700 blue1 += blue2;
701
702 cleanup_R1();
703 }
704
705 if( brightness != 255) {
706 if( brightness ) {
707 ++brightness; // adjust for rounding
708 // Now, since brightness is nonzero, we don't need the full scale8_video logic;
709 // we can just to scale8 and then add one (unless scale8 fixed) to all nonzero inputs.
710 if( red1 ) {
711 red1 = scale8_LEAVING_R1_DIRTY( red1, brightness);
712#if !(FASTLED_SCALE8_FIXED==1)
713 ++red1;
714#endif
715 }
716 if( green1 ) {
717 green1 = scale8_LEAVING_R1_DIRTY( green1, brightness);
718#if !(FASTLED_SCALE8_FIXED==1)
719 ++green1;
720#endif
721 }
722 if( blue1 ) {
723 blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness);
724#if !(FASTLED_SCALE8_FIXED==1)
725 ++blue1;
726#endif
727 }
728 cleanup_R1();
729 } else {
730 red1 = 0;
731 green1 = 0;
732 blue1 = 0;
733 }
734 }
735
736 return CRGB( red1, green1, blue1);
737}
738
739
740CRGB ColorFromPalette( const CRGBPalette32& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
741{
742 if ( blendType == LINEARBLEND_NOWRAP) {
743 index = map8(index, 0, 247); // Blend range is affected by lo3 blend of values, remap to avoid wrapping
744 }
745
746 uint8_t hi5 = index;
747#if defined(__AVR__)
748 hi5 /= 2;
749 hi5 /= 2;
750 hi5 /= 2;
751#else
752 hi5 >>= 3;
753#endif
754 uint8_t lo3 = index & 0x07;
755
756 // const CRGB* entry = &(pal[0]) + hi5;
757 // since hi5 is always 0..31, hi4 * sizeof(CRGB) can be a single-byte value,
758 // instead of the two byte 'int' that avr-gcc defaults to.
759 // So, we multiply hi5 X sizeof(CRGB), giving hi5XsizeofCRGB;
760 uint8_t hi5XsizeofCRGB = hi5 * sizeof(CRGB);
761 // We then add that to a base array pointer.
762 const CRGB* entry = (CRGB*)( (uint8_t*)(&(pal[0])) + hi5XsizeofCRGB);
763
764 uint8_t red1 = entry->red;
765 uint8_t green1 = entry->green;
766 uint8_t blue1 = entry->blue;
767
768 uint8_t blend = lo3 && (blendType != NOBLEND);
769
770 if( blend ) {
771
772 if( hi5 == 31 ) {
773 entry = &(pal[0]);
774 } else {
775 ++entry;
776 }
777
778 uint8_t f2 = lo3 << 5;
779 uint8_t f1 = 255 - f2;
780
781 uint8_t red2 = entry->red;
782 red1 = scale8_LEAVING_R1_DIRTY( red1, f1);
783 red2 = scale8_LEAVING_R1_DIRTY( red2, f2);
784 red1 += red2;
785
786 uint8_t green2 = entry->green;
787 green1 = scale8_LEAVING_R1_DIRTY( green1, f1);
788 green2 = scale8_LEAVING_R1_DIRTY( green2, f2);
789 green1 += green2;
790
791 uint8_t blue2 = entry->blue;
792 blue1 = scale8_LEAVING_R1_DIRTY( blue1, f1);
793 blue2 = scale8_LEAVING_R1_DIRTY( blue2, f2);
794 blue1 += blue2;
795
796 cleanup_R1();
797
798 }
799
800 if( brightness != 255) {
801 if( brightness ) {
802 ++brightness; // adjust for rounding
803 // Now, since brightness is nonzero, we don't need the full scale8_video logic;
804 // we can just to scale8 and then add one (unless scale8 fixed) to all nonzero inputs.
805 if( red1 ) {
806 red1 = scale8_LEAVING_R1_DIRTY( red1, brightness);
807#if !(FASTLED_SCALE8_FIXED==1)
808 ++red1;
809#endif
810 }
811 if( green1 ) {
812 green1 = scale8_LEAVING_R1_DIRTY( green1, brightness);
813#if !(FASTLED_SCALE8_FIXED==1)
814 ++green1;
815#endif
816 }
817 if( blue1 ) {
818 blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness);
819#if !(FASTLED_SCALE8_FIXED==1)
820 ++blue1;
821#endif
822 }
823 cleanup_R1();
824 } else {
825 red1 = 0;
826 green1 = 0;
827 blue1 = 0;
828 }
829 }
830
831 return CRGB( red1, green1, blue1);
832}
833
834
835CRGB ColorFromPalette( const TProgmemRGBPalette32& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
836{
837 if ( blendType == LINEARBLEND_NOWRAP) {
838 index = map8(index, 0, 247); // Blend range is affected by lo3 blend of values, remap to avoid wrapping
839 }
840
841 uint8_t hi5 = index;
842#if defined(__AVR__)
843 hi5 /= 2;
844 hi5 /= 2;
845 hi5 /= 2;
846#else
847 hi5 >>= 3;
848#endif
849 uint8_t lo3 = index & 0x07;
850
851 CRGB entry = FL_PGM_READ_DWORD_NEAR( &(pal[0]) + hi5);
852
853 uint8_t red1 = entry.red;
854 uint8_t green1 = entry.green;
855 uint8_t blue1 = entry.blue;
856
857 uint8_t blend = lo3 && (blendType != NOBLEND);
858
859 if( blend ) {
860
861 if( hi5 == 31 ) {
862 entry = FL_PGM_READ_DWORD_NEAR( &(pal[0]) );
863 } else {
864 entry = FL_PGM_READ_DWORD_NEAR( &(pal[1]) + hi5 );
865 }
866
867 uint8_t f2 = lo3 << 5;
868 uint8_t f1 = 255 - f2;
869
870 uint8_t red2 = entry.red;
871 red1 = scale8_LEAVING_R1_DIRTY( red1, f1);
872 red2 = scale8_LEAVING_R1_DIRTY( red2, f2);
873 red1 += red2;
874
875 uint8_t green2 = entry.green;
876 green1 = scale8_LEAVING_R1_DIRTY( green1, f1);
877 green2 = scale8_LEAVING_R1_DIRTY( green2, f2);
878 green1 += green2;
879
880 uint8_t blue2 = entry.blue;
881 blue1 = scale8_LEAVING_R1_DIRTY( blue1, f1);
882 blue2 = scale8_LEAVING_R1_DIRTY( blue2, f2);
883 blue1 += blue2;
884
885 cleanup_R1();
886 }
887
888 if( brightness != 255) {
889 if( brightness ) {
890 ++brightness; // adjust for rounding
891 // Now, since brightness is nonzero, we don't need the full scale8_video logic;
892 // we can just to scale8 and then add one (unless scale8 fixed) to all nonzero inputs.
893 if( red1 ) {
894 red1 = scale8_LEAVING_R1_DIRTY( red1, brightness);
895#if !(FASTLED_SCALE8_FIXED==1)
896 ++red1;
897#endif
898 }
899 if( green1 ) {
900 green1 = scale8_LEAVING_R1_DIRTY( green1, brightness);
901#if !(FASTLED_SCALE8_FIXED==1)
902 ++green1;
903#endif
904 }
905 if( blue1 ) {
906 blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness);
907#if !(FASTLED_SCALE8_FIXED==1)
908 ++blue1;
909#endif
910 }
911 cleanup_R1();
912 } else {
913 red1 = 0;
914 green1 = 0;
915 blue1 = 0;
916 }
917 }
918
919 return CRGB( red1, green1, blue1);
920}
921
922
923
924CRGB ColorFromPalette( const CRGBPalette256& pal, uint8_t index, uint8_t brightness, TBlendType)
925{
926 const CRGB* entry = &(pal[0]) + index;
927
928 uint8_t red = entry->red;
929 uint8_t green = entry->green;
930 uint8_t blue = entry->blue;
931
932 if( brightness != 255) {
933 ++brightness; // adjust for rounding
934 red = scale8_video_LEAVING_R1_DIRTY( red, brightness);
935 green = scale8_video_LEAVING_R1_DIRTY( green, brightness);
936 blue = scale8_video_LEAVING_R1_DIRTY( blue, brightness);
937 cleanup_R1();
938 }
939
940 return CRGB( red, green, blue);
941}
942
943
944CHSV ColorFromPalette( const CHSVPalette16& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
945{
946 if ( blendType == LINEARBLEND_NOWRAP) {
947 index = map8(index, 0, 239); // Blend range is affected by lo4 blend of values, remap to avoid wrapping
948 }
949
950 // hi4 = index >> 4;
951 uint8_t hi4 = lsrX4(index);
952 uint8_t lo4 = index & 0x0F;
953
954 // CRGB rgb1 = pal[ hi4];
955 const CHSV* entry = &(pal[0]) + hi4;
956
957 uint8_t hue1 = entry->hue;
958 uint8_t sat1 = entry->sat;
959 uint8_t val1 = entry->val;
960
961 uint8_t blend = lo4 && (blendType != NOBLEND);
962
963 if( blend ) {
964
965 if( hi4 == 15 ) {
966 entry = &(pal[0]);
967 } else {
968 ++entry;
969 }
970
971 uint8_t f2 = lo4 << 4;
972 uint8_t f1 = 255 - f2;
973
974 uint8_t hue2 = entry->hue;
975 uint8_t sat2 = entry->sat;
976 uint8_t val2 = entry->val;
977
978 // Now some special casing for blending to or from
979 // either black or white. Black and white don't have
980 // proper 'hue' of their own, so when ramping from
981 // something else to/from black/white, we set the 'hue'
982 // of the black/white color to be the same as the hue
983 // of the other color, so that you get the expected
984 // brightness or saturation ramp, with hue staying
985 // constant:
986
987 // If we are starting from white (sat=0)
988 // or black (val=0), adopt the target hue.
989 if( sat1 == 0 || val1 == 0) {
990 hue1 = hue2;
991 }
992
993 // If we are ending at white (sat=0)
994 // or black (val=0), adopt the starting hue.
995 if( sat2 == 0 || val2 == 0) {
996 hue2 = hue1;
997 }
998
999
1000 sat1 = scale8_LEAVING_R1_DIRTY( sat1, f1);
1001 val1 = scale8_LEAVING_R1_DIRTY( val1, f1);
1002
1003 sat2 = scale8_LEAVING_R1_DIRTY( sat2, f2);
1004 val2 = scale8_LEAVING_R1_DIRTY( val2, f2);
1005
1006 // cleanup_R1();
1007
1008 // These sums can't overflow, so no qadd8 needed.
1009 sat1 += sat2;
1010 val1 += val2;
1011
1012 uint8_t deltaHue = (uint8_t)(hue2 - hue1);
1013 if( deltaHue & 0x80 ) {
1014 // go backwards
1015 hue1 -= scale8( 256 - deltaHue, f2);
1016 } else {
1017 // go forwards
1018 hue1 += scale8( deltaHue, f2);
1019 }
1020
1021 cleanup_R1();
1022 }
1023
1024 if( brightness != 255) {
1025 val1 = scale8_video( val1, brightness);
1026 }
1027
1028 return CHSV( hue1, sat1, val1);
1029}
1030
1031
1032CHSV ColorFromPalette( const CHSVPalette32& pal, uint8_t index, uint8_t brightness, TBlendType blendType)
1033{
1034 if ( blendType == LINEARBLEND_NOWRAP) {
1035 index = map8(index, 0, 247); // Blend range is affected by lo3 blend of values, remap to avoid wrapping
1036 }
1037
1038 uint8_t hi5 = index;
1039#if defined(__AVR__)
1040 hi5 /= 2;
1041 hi5 /= 2;
1042 hi5 /= 2;
1043#else
1044 hi5 >>= 3;
1045#endif
1046 uint8_t lo3 = index & 0x07;
1047
1048 uint8_t hi5XsizeofCHSV = hi5 * sizeof(CHSV);
1049 const CHSV* entry = (CHSV*)( (uint8_t*)(&(pal[0])) + hi5XsizeofCHSV);
1050
1051 uint8_t hue1 = entry->hue;
1052 uint8_t sat1 = entry->sat;
1053 uint8_t val1 = entry->val;
1054
1055 uint8_t blend = lo3 && (blendType != NOBLEND);
1056
1057 if( blend ) {
1058
1059 if( hi5 == 31 ) {
1060 entry = &(pal[0]);
1061 } else {
1062 ++entry;
1063 }
1064
1065 uint8_t f2 = lo3 << 5;
1066 uint8_t f1 = 255 - f2;
1067
1068 uint8_t hue2 = entry->hue;
1069 uint8_t sat2 = entry->sat;
1070 uint8_t val2 = entry->val;
1071
1072 // Now some special casing for blending to or from
1073 // either black or white. Black and white don't have
1074 // proper 'hue' of their own, so when ramping from
1075 // something else to/from black/white, we set the 'hue'
1076 // of the black/white color to be the same as the hue
1077 // of the other color, so that you get the expected
1078 // brightness or saturation ramp, with hue staying
1079 // constant:
1080
1081 // If we are starting from white (sat=0)
1082 // or black (val=0), adopt the target hue.
1083 if( sat1 == 0 || val1 == 0) {
1084 hue1 = hue2;
1085 }
1086
1087 // If we are ending at white (sat=0)
1088 // or black (val=0), adopt the starting hue.
1089 if( sat2 == 0 || val2 == 0) {
1090 hue2 = hue1;
1091 }
1092
1093
1094 sat1 = scale8_LEAVING_R1_DIRTY( sat1, f1);
1095 val1 = scale8_LEAVING_R1_DIRTY( val1, f1);
1096
1097 sat2 = scale8_LEAVING_R1_DIRTY( sat2, f2);
1098 val2 = scale8_LEAVING_R1_DIRTY( val2, f2);
1099
1100 // cleanup_R1();
1101
1102 // These sums can't overflow, so no qadd8 needed.
1103 sat1 += sat2;
1104 val1 += val2;
1105
1106 uint8_t deltaHue = (uint8_t)(hue2 - hue1);
1107 if( deltaHue & 0x80 ) {
1108 // go backwards
1109 hue1 -= scale8( 256 - deltaHue, f2);
1110 } else {
1111 // go forwards
1112 hue1 += scale8( deltaHue, f2);
1113 }
1114
1115 cleanup_R1();
1116 }
1117
1118 if( brightness != 255) {
1119 val1 = scale8_video( val1, brightness);
1120 }
1121
1122 return CHSV( hue1, sat1, val1);
1123}
1124
1125CHSV ColorFromPalette( const CHSVPalette256& pal, uint8_t index, uint8_t brightness, TBlendType)
1126{
1127 CHSV hsv = *( &(pal[0]) + index );
1128
1129 if( brightness != 255) {
1130 hsv.value = scale8_video( hsv.value, brightness);
1131 }
1132
1133 return hsv;
1134}
1135
1136
1137void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette256& destpal256)
1138{
1139 for( int i = 0; i < 256; ++i) {
1140 destpal256[(uint8_t)(i)] = ColorFromPalette( srcpal16, i);
1141 }
1142}
1143
1144void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette256& destpal256)
1145{
1146 for( int i = 0; i < 256; ++i) {
1147 destpal256[(uint8_t)(i)] = ColorFromPalette( srcpal16, i);
1148 }
1149}
1150
1151
1152void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette32& destpal32)
1153{
1154 for( uint8_t i = 0; i < 16; ++i) {
1155 uint8_t j = i * 2;
1156 destpal32[j+0] = srcpal16[i];
1157 destpal32[j+1] = srcpal16[i];
1158 }
1159}
1160
1161void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette32& destpal32)
1162{
1163 for( uint8_t i = 0; i < 16; ++i) {
1164 uint8_t j = i * 2;
1165 destpal32[j+0] = srcpal16[i];
1166 destpal32[j+1] = srcpal16[i];
1167 }
1168}
1169
1170void UpscalePalette(const struct CRGBPalette32& srcpal32, struct CRGBPalette256& destpal256)
1171{
1172 for( int i = 0; i < 256; ++i) {
1173 destpal256[(uint8_t)(i)] = ColorFromPalette( srcpal32, i);
1174 }
1175}
1176
1177void UpscalePalette(const struct CHSVPalette32& srcpal32, struct CHSVPalette256& destpal256)
1178{
1179 for( int i = 0; i < 256; ++i) {
1180 destpal256[(uint8_t)(i)] = ColorFromPalette( srcpal32, i);
1181 }
1182}
1183
1184
1185
1186#if 0
1187// replaced by PartyColors_p
1188void SetupPartyColors(CRGBPalette16& pal)
1189{
1190 fill_gradient( pal, 0, CHSV( HUE_PURPLE,255,255), 7, CHSV(HUE_YELLOW - 18,255,255), FORWARD_HUES);
1191 fill_gradient( pal, 8, CHSV( HUE_ORANGE,255,255), 15, CHSV(HUE_BLUE + 18,255,255), BACKWARD_HUES);
1192}
1193#endif
1194
1195
1196void nblendPaletteTowardPalette( CRGBPalette16& current, CRGBPalette16& target, uint8_t maxChanges)
1197{
1198 uint8_t* p1;
1199 uint8_t* p2;
1200 uint8_t changes = 0;
1201
1202 p1 = (uint8_t*)current.entries;
1203 p2 = (uint8_t*)target.entries;
1204
1205 const uint8_t totalChannels = sizeof(CRGBPalette16);
1206 for( uint8_t i = 0; i < totalChannels; ++i) {
1207 // if the values are equal, no changes are needed
1208 if( p1[i] == p2[i] ) { continue; }
1209
1210 // if the current value is less than the target, increase it by one
1211 if( p1[i] < p2[i] ) { ++p1[i]; ++changes; }
1212
1213 // if the current value is greater than the target,
1214 // increase it by one (or two if it's still greater).
1215 if( p1[i] > p2[i] ) {
1216 --p1[i]; ++changes;
1217 if( p1[i] > p2[i] ) { --p1[i]; }
1218 }
1219
1220 // if we've hit the maximum number of changes, exit
1221 if( changes >= maxChanges) { break; }
1222 }
1223}
1224
1225
1226uint8_t applyGamma_video( uint8_t brightness, float gamma)
1227{
1228 float orig;
1229 float adj;
1230 orig = (float)(brightness) / (255.0);
1231 adj = pow( orig, gamma) * (255.0);
1232 uint8_t result = (uint8_t)(adj);
1233 if( (brightness > 0) && (result == 0)) {
1234 result = 1; // never gamma-adjust a positive number down to zero
1235 }
1236 return result;
1237}
1238
1239CRGB applyGamma_video( const CRGB& orig, float gamma)
1240{
1241 CRGB adj;
1242 adj.r = applyGamma_video( orig.r, gamma);
1243 adj.g = applyGamma_video( orig.g, gamma);
1244 adj.b = applyGamma_video( orig.b, gamma);
1245 return adj;
1246}
1247
1248CRGB applyGamma_video( const CRGB& orig, float gammaR, float gammaG, float gammaB)
1249{
1250 CRGB adj;
1251 adj.r = applyGamma_video( orig.r, gammaR);
1252 adj.g = applyGamma_video( orig.g, gammaG);
1253 adj.b = applyGamma_video( orig.b, gammaB);
1254 return adj;
1255}
1256
1257CRGB& napplyGamma_video( CRGB& rgb, float gamma)
1258{
1259 rgb = applyGamma_video( rgb, gamma);
1260 return rgb;
1261}
1262
1263CRGB& napplyGamma_video( CRGB& rgb, float gammaR, float gammaG, float gammaB)
1264{
1265 rgb = applyGamma_video( rgb, gammaR, gammaG, gammaB);
1266 return rgb;
1267}
1268
1269void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gamma)
1270{
1271 for( uint16_t i = 0; i < count; ++i) {
1272 rgbarray[i] = applyGamma_video( rgbarray[i], gamma);
1273 }
1274}
1275
1276void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gammaR, float gammaG, float gammaB)
1277{
1278 for( uint16_t i = 0; i < count; ++i) {
1279 rgbarray[i] = applyGamma_video( rgbarray[i], gammaR, gammaG, gammaB);
1280 }
1281}
1282
1283
1284FASTLED_NAMESPACE_END
CFastLED FastLED
Global LED strip management instance.
Definition FastLED.cpp:17
central include file for FastLED, defines the CFastLED class/object
HSV color palette with 16 discrete values.
Definition colorutils.h:627
HSV color palette with 256 discrete values.
Definition colorutils.h:774
HSV color palette with 32 discrete values.
RGB color palette with 16 discrete values.
Definition colorutils.h:904
CRGB entries[16]
the color entries that make up the palette
Definition colorutils.h:906
RGB color palette with 256 discrete values.
RGB color palette with 32 discrete values.
uint16_t XY(uint8_t, uint8_t)
Forward declaration of the function "XY" which must be provided by the application for use in two-dim...
Definition Noise.ino:22
void nscale8_raw(CRGB *leds, uint16_t num_leds, uint8_t scale)
Unused alias of nscale8(CRGB*, uint16_t, uint8_t)
uint8_t lsrX4(uint8_t dividend)
Helper function to divide a number by 16, aka four logical shift right (LSR)'s.
CRGB & nblend(CRGB &existing, const CRGB &overlay, fract8 amountOfOverlay)
Destructively modifies one color, blending in a given fraction of an overlay color.
CRGB blend(const CRGB &p1, const CRGB &p2, fract8 amountOfP2)
Computes a new color blended some fraction of the way between two other colors.
void blurRows(CRGB *leds, uint8_t width, uint8_t height, fract8 blur_amount)
Perform a blur1d() on every row of a rectangular matrix.
void blur1d(CRGB *leds, uint16_t numLeds, fract8 blur_amount)
One-dimensional blur filter.
void blurColumns(CRGB *leds, uint8_t width, uint8_t height, fract8 blur_amount)
Perform a blur1d() on every column of a rectangular matrix.
void blur2d(CRGB *leds, uint8_t width, uint8_t height, fract8 blur_amount)
Two-dimensional blur filter.
void fadeToBlackBy(CRGB *leds, uint16_t num_leds, uint8_t fadeBy)
Reduce the brightness of an array of pixels all at once.
void nscale8_video(CRGB *leds, uint16_t num_leds, uint8_t scale)
Scale the brightness of an array of pixels all at once.
void fade_raw(CRGB *leds, uint16_t num_leds, uint8_t fadeBy)
Reduce the brightness of an array of pixels all at once.
void fadeLightBy(CRGB *leds, uint16_t num_leds, uint8_t fadeBy)
Reduce the brightness of an array of pixels all at once.
void nscale8(CRGB *leds, uint16_t num_leds, uint8_t scale)
Scale the brightness of an array of pixels all at once.
void fadeUsingColor(CRGB *leds, uint16_t numLeds, const CRGB &colormask)
Reduce the brightness of an array of pixels as thought it were seen through a transparent filter with...
void fade_video(CRGB *leds, uint16_t num_leds, uint8_t fadeBy)
Reduce the brightness of an array of pixels all at once.
TGradientDirectionCode
Hue direction for calculating fill gradients.
Definition colorutils.h:69
void fill_rainbow(struct CRGB *targetArray, int numToFill, uint8_t initialhue, uint8_t deltahue)
Fill a range of LEDs with a rainbow of colors.
void fill_gradient(T *targetArray, uint16_t startpos, CHSV startcolor, uint16_t endpos, CHSV endcolor, TGradientDirectionCode directionCode=SHORTEST_HUES)
Fill a range of LEDs with a smooth HSV gradient between two HSV colors.
Definition colorutils.h:98
#define saccum87
ANSI: signed short _Accum.
Definition colorutils.h:79
void fill_gradient_RGB(CRGB *leds, uint16_t startpos, CRGB startcolor, uint16_t endpos, CRGB endcolor)
Fill a range of LEDs with a smooth RGB gradient between two RGB colors.
void fill_rainbow_circular(struct CRGB *targetArray, int numToFill, uint8_t initialhue, bool reversed)
Fill a range of LEDs with a rainbow of colors, so that the hues are continuous between the end of the...
void fill_solid(struct CRGB *targetArray, int numToFill, const struct CRGB &color)
Fill a range of LEDs with a solid color.
CRGB HeatColor(uint8_t temperature)
Approximates a "black body radiation" spectrum for a given "heat" level.
@ LONGEST_HUES
Hue goes whichever way is longest.
Definition colorutils.h:73
@ FORWARD_HUES
Hue always goes clockwise around the color wheel.
Definition colorutils.h:70
@ SHORTEST_HUES
Hue goes whichever way is shortest.
Definition colorutils.h:72
@ BACKWARD_HUES
Hue always goes counter-clockwise around the color wheel.
Definition colorutils.h:71
uint16_t accum88
ANSI: unsigned short _Accum. 8 bits int, 8 bits fraction.
Definition lib8tion.h:420
uint8_t fract8
ANSI: unsigned short _Fract.
Definition lib8tion.h:402
CRGB & napplyGamma_video(CRGB &rgb, float gamma)
Destructively applies a gamma adjustment to a color.
uint8_t applyGamma_video(uint8_t brightness, float gamma)
Applies a gamma adjustment to a color channel.
LIB8STATIC uint8_t map8(uint8_t in, uint8_t rangeStart, uint8_t rangeEnd)
Map from one full-range 8-bit value into a narrower range of 8-bit values, possibly a range of hues.
Definition lib8tion.h:636
LIB8STATIC uint8_t blend8(uint8_t a, uint8_t b, uint8_t amountOfB)
Blend a variable proportion (0-255) of one byte to another.
Definition math8.h:692
uint32_t TProgmemRGBPalette32[32]
CRGBPalette32 entries stored in PROGMEM memory.
Definition colorutils.h:559
uint32_t TProgmemRGBPalette16[16]
CRGBPalette16 entries stored in PROGMEM memory.
Definition colorutils.h:555
void nblendPaletteTowardPalette(CRGBPalette16 &current, CRGBPalette16 &target, uint8_t maxChanges)
Alter one palette by making it slightly more like a "target palette".
TBlendType
Color interpolation options for palette.
CRGB ColorFromPalette(const CRGBPalette16 &pal, uint8_t index, uint8_t brightness, TBlendType blendType)
Get a color from a palette.
@ NOBLEND
No interpolation between palette entries.
@ LINEARBLEND_NOWRAP
Linear interpolation between palette entries, but no wrap-around.
void UpscalePalette(const struct CRGBPalette16 &srcpal16, struct CRGBPalette256 &destpal256)
Convert a 16-entry palette to a 256-entry palette.
@ HUE_ORANGE
Orange (45°)
Definition pixeltypes.h:110
@ HUE_BLUE
Blue (225°)
Definition pixeltypes.h:114
@ HUE_YELLOW
Yellow (90°)
Definition pixeltypes.h:111
@ HUE_PURPLE
Purple (270°)
Definition pixeltypes.h:115
LIB8STATIC_ALWAYS_INLINE void cleanup_R1()
Clean up the r1 register after a series of *LEAVING_R1_DIRTY calls.
Definition scale8.h:336
LIB8STATIC_ALWAYS_INLINE uint8_t scale8_LEAVING_R1_DIRTY(uint8_t i, fract8 scale)
This version of scale8() does not clean up the R1 register on AVR.
Definition scale8.h:169
LIB8STATIC_ALWAYS_INLINE uint8_t scale8_video_LEAVING_R1_DIRTY(uint8_t i, fract8 scale)
This version of scale8_video() does not clean up the R1 register on AVR.
Definition scale8.h:262
LIB8STATIC_ALWAYS_INLINE uint8_t scale8_video(uint8_t i, fract8 scale)
The "video" version of scale8() guarantees that the output will be only be zero if one or both of the...
Definition scale8.h:112
LIB8STATIC_ALWAYS_INLINE uint8_t scale8(uint8_t i, fract8 scale)
Scale one byte by a second one, which is treated as the numerator of a fraction whose denominator is ...
Definition scale8.h:30
Representation of an HSV pixel (hue, saturation, value (aka brightness)).
Definition pixeltypes.h:27
uint8_t hue
Color hue.
Definition pixeltypes.h:34
uint8_t sat
Color saturation.
Definition pixeltypes.h:41
uint8_t value
Color value (brightness).
Definition pixeltypes.h:47
uint8_t val
Color value (brightness).
Definition pixeltypes.h:48
Representation of an RGB pixel (Red, Green, Blue)
Definition pixeltypes.h:120
CRGB & nscale8_video(uint8_t scaledown)
Scale down a RGB to N/256ths of it's current brightness using "video" dimming rules.
Definition pixeltypes.h:373
uint8_t r
Red channel value.
Definition pixeltypes.h:124
CRGB & nscale8(uint8_t scaledown)
Scale down a RGB to N/256ths of its current brightness, using "plain math" dimming rules.
Definition pixeltypes.h:399
uint8_t g
Green channel value.
Definition pixeltypes.h:128
uint8_t red
Red channel value.
Definition pixeltypes.h:125
uint8_t blue
Blue channel value.
Definition pixeltypes.h:133
uint8_t b
Blue channel value.
Definition pixeltypes.h:132
uint8_t green
Green channel value.
Definition pixeltypes.h:129
@ Black
Definition pixeltypes.h:672