FastLED 3.9.15
Loading...
Searching...
No Matches
hsv2rgb.cpp
Go to the documentation of this file.
1
3
5#define FASTLED_INTERNAL
6#include "fl/stdint.h"
7
8#include "FastLED.h"
9#include "fl/math_macros.h"
10
11#include "hsv2rgb.h"
12
14
16void hsv2rgb_raw_C (const struct CHSV & hsv, struct CRGB & rgb);
18void hsv2rgb_raw_avr(const struct CHSV & hsv, struct CRGB & rgb);
19
20#if defined(__AVR__) && !defined( LIB8_ATTINY )
21void hsv2rgb_raw(const struct CHSV & hsv, struct CRGB & rgb)
22{
23 hsv2rgb_raw_avr( hsv, rgb);
24}
25#else
26void hsv2rgb_raw(const struct CHSV & hsv, struct CRGB & rgb)
27{
28 hsv2rgb_raw_C( hsv, rgb);
29}
30#endif
31
32
34#define APPLY_DIMMING(X) (X)
35
38#define HSV_SECTION_6 (0x20)
39
42#define HSV_SECTION_3 (0x40)
43
45CRGB hsv2rgb_spectrum( const struct CHSV& hsv) {
46 CRGB rgb;
47 hsv2rgb_spectrum(hsv, rgb);
48 return rgb;
49}
50
51void hsv2rgb_raw_C (const struct CHSV & hsv, struct CRGB & rgb)
52{
53 // Convert hue, saturation and brightness ( HSV/HSB ) to RGB
54 // "Dimming" is used on saturation and brightness to make
55 // the output more visually linear.
56
57 // Apply dimming curves
58 uint8_t value = APPLY_DIMMING( hsv.val); // cppcheck-suppress selfAssignment
59 uint8_t saturation = hsv.sat;
60
61 // The brightness floor is minimum number that all of
62 // R, G, and B will be set to.
63 uint8_t invsat = APPLY_DIMMING( 255 - saturation); // cppcheck-suppress selfAssignment
64 uint8_t brightness_floor = (value * invsat) / 256;
65
66 // The color amplitude is the maximum amount of R, G, and B
67 // that will be added on top of the brightness_floor to
68 // create the specific hue desired.
69 uint8_t color_amplitude = value - brightness_floor;
70
71 // Figure out which section of the hue wheel we're in,
72 // and how far offset we are withing that section
73 uint8_t section = hsv.hue / HSV_SECTION_3; // 0..2
74 uint8_t offset = hsv.hue % HSV_SECTION_3; // 0..63
75
76 uint8_t rampup = offset; // 0..63
77 uint8_t rampdown = (HSV_SECTION_3 - 1) - offset; // 63..0
78
79 // We now scale rampup and rampdown to a 0-255 range -- at least
80 // in theory, but here's where architecture-specific decsions
81 // come in to play:
82 // To scale them up to 0-255, we'd want to multiply by 4.
83 // But in the very next step, we multiply the ramps by other
84 // values and then divide the resulting product by 256.
85 // So which is faster?
86 // ((ramp * 4) * othervalue) / 256
87 // or
88 // ((ramp ) * othervalue) / 64
89 // It depends on your processor architecture.
90 // On 8-bit AVR, the "/ 256" is just a one-cycle register move,
91 // but the "/ 64" might be a multicycle shift process. So on AVR
92 // it's faster do multiply the ramp values by four, and then
93 // divide by 256.
94 // On ARM, the "/ 256" and "/ 64" are one cycle each, so it's
95 // faster to NOT multiply the ramp values by four, and just to
96 // divide the resulting product by 64 (instead of 256).
97 // Moral of the story: trust your profiler, not your insticts.
98
99 // Since there's an AVR assembly version elsewhere, we'll
100 // assume what we're on an architecture where any number of
101 // bit shifts has roughly the same cost, and we'll remove the
102 // redundant math at the source level:
103
104 // // scale up to 255 range
105 // //rampup *= 4; // 0..252
106 // //rampdown *= 4; // 0..252
107
108 // compute color-amplitude-scaled-down versions of rampup and rampdown
109 uint8_t rampup_amp_adj = (rampup * color_amplitude) / (256 / 4);
110 uint8_t rampdown_amp_adj = (rampdown * color_amplitude) / (256 / 4);
111
112 // add brightness_floor offset to everything
113 uint8_t rampup_adj_with_floor = rampup_amp_adj + brightness_floor;
114 uint8_t rampdown_adj_with_floor = rampdown_amp_adj + brightness_floor;
115
116
117 if( section ) {
118 if( section == 1) {
119 // section 1: 0x40..0x7F
120 rgb.r = brightness_floor;
121 rgb.g = rampdown_adj_with_floor;
122 rgb.b = rampup_adj_with_floor;
123 } else {
124 // section 2; 0x80..0xBF
125 rgb.r = rampup_adj_with_floor;
126 rgb.g = brightness_floor;
127 rgb.b = rampdown_adj_with_floor;
128 }
129 } else {
130 // section 0: 0x00..0x3F
131 rgb.r = rampdown_adj_with_floor;
132 rgb.g = rampup_adj_with_floor;
133 rgb.b = brightness_floor;
134 }
135}
136
137
138
139#if defined(__AVR__) && !defined( LIB8_ATTINY )
140void hsv2rgb_raw_avr(const struct CHSV & hsv, struct CRGB & rgb)
141{
142 uint8_t hue, saturation, value;
143
144 hue = hsv.hue;
145 saturation = hsv.sat;
146 value = hsv.val;
147
148 // Saturation more useful the other way around
149 saturation = 255 - saturation;
150 uint8_t invsat = APPLY_DIMMING( saturation ); // cppcheck-suppress selfAssignment
151
152 // Apply dimming curves
153 value = APPLY_DIMMING( value ); // cppcheck-suppress selfAssignment
154
155 // The brightness floor is minimum number that all of
156 // R, G, and B will be set to, which is value * invsat
157 uint8_t brightness_floor;
158
159 asm volatile(
160 "mul %[value], %[invsat] \n"
161 "mov %[brightness_floor], r1 \n"
162 : [brightness_floor] "=r" (brightness_floor)
163 : [value] "r" (value),
164 [invsat] "r" (invsat)
165 : "r0", "r1"
166 );
167
168 // The color amplitude is the maximum amount of R, G, and B
169 // that will be added on top of the brightness_floor to
170 // create the specific hue desired.
171 uint8_t color_amplitude = value - brightness_floor;
172
173 // Figure how far we are offset into the section of the
174 // color wheel that we're in
175 uint8_t offset = hsv.hue & (HSV_SECTION_3 - 1); // 0..63
176 uint8_t rampup = offset * 4; // 0..252
177
178
179 // compute color-amplitude-scaled-down versions of rampup and rampdown
180 uint8_t rampup_amp_adj;
181 uint8_t rampdown_amp_adj;
182
183 asm volatile(
184 "mul %[rampup], %[color_amplitude] \n"
185 "mov %[rampup_amp_adj], r1 \n"
186 "com %[rampup] \n"
187 "mul %[rampup], %[color_amplitude] \n"
188 "mov %[rampdown_amp_adj], r1 \n"
189 : [rampup_amp_adj] "=&r" (rampup_amp_adj),
190 [rampdown_amp_adj] "=&r" (rampdown_amp_adj),
191 [rampup] "+r" (rampup)
192 : [color_amplitude] "r" (color_amplitude)
193 : "r0", "r1"
194 );
195
196
197 // add brightness_floor offset to everything
198 uint8_t rampup_adj_with_floor = rampup_amp_adj + brightness_floor;
199 uint8_t rampdown_adj_with_floor = rampdown_amp_adj + brightness_floor;
200
201
202 // keep gcc from using "X" as the index register for storing
203 // results back in the return structure. AVR's X register can't
204 // do "std X+q, rnn", but the Y and Z registers can.
205 // if the pointer to 'rgb' is in X, gcc will add all kinds of crazy
206 // extra instructions. Simply killing X here seems to help it
207 // try Y or Z first.
208 asm volatile( "" : : : "r26", "r27" );
209
210
211 if( hue & 0x80 ) {
212 // section 2: 0x80..0xBF
213 rgb.r = rampup_adj_with_floor;
214 rgb.g = brightness_floor;
215 rgb.b = rampdown_adj_with_floor;
216 } else {
217 if( hue & 0x40) {
218 // section 1: 0x40..0x7F
219 rgb.r = brightness_floor;
220 rgb.g = rampdown_adj_with_floor;
221 rgb.b = rampup_adj_with_floor;
222 } else {
223 // section 0: 0x00..0x3F
224 rgb.r = rampdown_adj_with_floor;
225 rgb.g = rampup_adj_with_floor;
226 rgb.b = brightness_floor;
227 }
228 }
229
230 cleanup_R1();
231}
232// End of AVR asm implementation
233
234#endif
235
236void hsv2rgb_spectrum( const struct CHSV& hsv, CRGB& rgb)
237{
238 CHSV hsv2(hsv);
239 hsv2.hue = scale8( hsv2.hue, 191);
240 hsv2rgb_raw(hsv2, rgb);
241}
242
243
251#define FORCE_REFERENCE(var) asm volatile( "" : : "r" (var) )
252
253
255#define K255 255
256#define K171 171
257#define K170 170
258#define K85 85
260
261CRGB hsv2rgb_rainbow( const struct CHSV& hsv) {
262 CRGB rgb;
263 hsv2rgb_rainbow(hsv, rgb);
264 return rgb;
265}
266
267void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
268{
269 // Yellow has a higher inherent brightness than
270 // any other color; 'pure' yellow is perceived to
271 // be 93% as bright as white. In order to make
272 // yellow appear the correct relative brightness,
273 // it has to be rendered brighter than all other
274 // colors.
275 // Level Y1 is a moderate boost, the default.
276 // Level Y2 is a strong boost.
277 const uint8_t Y1 = 1;
278 const uint8_t Y2 = 0;
279
280 // G2: Whether to divide all greens by two.
281 // Depends GREATLY on your particular LEDs
282 const uint8_t G2 = 0;
283
284 // Gscale: what to scale green down by.
285 // Depends GREATLY on your particular LEDs
286 const uint8_t Gscale = 0;
287
288
289 uint8_t hue = hsv.hue;
290 uint8_t sat = hsv.sat;
291 uint8_t val = hsv.val;
292
293 uint8_t offset = hue & 0x1F; // 0..31
294
295 // offset8 = offset * 8
296 uint8_t offset8 = offset;
297 {
298#if defined(__AVR__)
299 // Left to its own devices, gcc turns "x <<= 3" into a loop
300 // It's much faster and smaller to just do three single-bit shifts
301 // So this business is to force that.
302 offset8 <<= 1;
303 asm volatile("");
304 offset8 <<= 1;
305 asm volatile("");
306 offset8 <<= 1;
307#else
308 // On ARM and other non-AVR platforms, we just shift 3.
309 offset8 <<= 3;
310#endif
311 }
312
313 uint8_t third = scale8( offset8, (256 / 3)); // max = 85
314
315 uint8_t r, g, b;
316
317 if( ! (hue & 0x80) ) {
318 // 0XX
319 if( ! (hue & 0x40) ) {
320 // 00X
321 //section 0-1
322 if( ! (hue & 0x20) ) {
323 // 000
324 //case 0: // R -> O
325 r = K255 - third;
326 g = third;
327 b = 0;
329 } else {
330 // 001
331 //case 1: // O -> Y
332 if( Y1 ) {
333 r = K171;
334 g = K85 + third ;
335 b = 0;
337 }
338 if( Y2 ) {
339 r = K170 + third;
340 //uint8_t twothirds = (third << 1);
341 uint8_t twothirds = scale8( offset8, ((256 * 2) / 3)); // max=170
342 g = K85 + twothirds;
343 b = 0;
345 }
346 }
347 } else {
348 //01X
349 // section 2-3
350 if( ! (hue & 0x20) ) {
351 // 010
352 //case 2: // Y -> G
353 if( Y1 ) {
354 //uint8_t twothirds = (third << 1);
355 uint8_t twothirds = scale8( offset8, ((256 * 2) / 3)); // max=170
356 r = K171 - twothirds;
357 g = K170 + third;
358 b = 0;
360 }
361 if( Y2 ) {
362 r = K255 - offset8;
363 g = K255;
364 b = 0;
366 }
367 } else {
368 // 011
369 // case 3: // G -> A
370 r = 0;
372 g = K255 - third;
373 b = third;
374 }
375 }
376 } else {
377 // section 4-7
378 // 1XX
379 if( ! (hue & 0x40) ) {
380 // 10X
381 if( ! ( hue & 0x20) ) {
382 // 100
383 //case 4: // A -> B
384 r = 0;
386 //uint8_t twothirds = (third << 1);
387 uint8_t twothirds = scale8( offset8, ((256 * 2) / 3)); // max=170
388 g = K171 - twothirds; //K170?
389 b = K85 + twothirds;
390
391 } else {
392 // 101
393 //case 5: // B -> P
394 r = third;
395 g = 0;
397 b = K255 - third;
398
399 }
400 } else {
401 if( ! (hue & 0x20) ) {
402 // 110
403 //case 6: // P -- K
404 r = K85 + third;
405 g = 0;
407 b = K171 - third;
408
409 } else {
410 // 111
411 //case 7: // K -> R
412 r = K170 + third;
413 g = 0;
415 b = K85 - third;
416
417 }
418 }
419 }
420
421 // This is one of the good places to scale the green down,
422 // although the client can scale green down as well.
423 if( G2 ) g = g >> 1;
424 if( Gscale ) g = scale8_video_LEAVING_R1_DIRTY( g, Gscale);
425
426 // Scale down colors if we're desaturated at all
427 // and add the brightness_floor to r, g, and b.
428 if( sat != 255 ) {
429 if( sat == 0) {
430 r = 255; b = 255; g = 255;
431 } else {
432 uint8_t desat = 255 - sat;
433 desat = scale8_video( desat, desat);
434
435 uint8_t satscale = 255 - desat;
436 //satscale = sat; // uncomment to revert to pre-2021 saturation behavior
437
438 //nscale8x3_video( r, g, b, sat);
439#if (FASTLED_SCALE8_FIXED==1)
440 r = scale8_LEAVING_R1_DIRTY( r, satscale);
441 asm volatile(""); // Fixes jumping red pixel: https://github.com/FastLED/FastLED/pull/943
442 g = scale8_LEAVING_R1_DIRTY( g, satscale);
443 asm volatile("");
444 b = scale8_LEAVING_R1_DIRTY( b, satscale);
445 asm volatile("");
446 cleanup_R1();
447#else
448 if( r ) r = scale8( r, satscale) + 1;
449 if( g ) g = scale8( g, satscale) + 1;
450 if( b ) b = scale8( b, satscale) + 1;
451#endif
452 uint8_t brightness_floor = desat;
453 r += brightness_floor;
454 g += brightness_floor;
455 b += brightness_floor;
456 }
457 }
458
459 // Now scale everything down if we're at value < 255.
460 if( val != 255 ) {
461
462 val = scale8_video_LEAVING_R1_DIRTY( val, val);
463 if( val == 0 ) {
464 r=0; g=0; b=0;
465 } else {
466 // nscale8x3_video( r, g, b, val);
467#if (FASTLED_SCALE8_FIXED==1)
468 r = scale8_LEAVING_R1_DIRTY( r, val);
469 asm volatile(""); // Fixes jumping red pixel: https://github.com/FastLED/FastLED/pull/943
470 g = scale8_LEAVING_R1_DIRTY( g, val);
471 asm volatile("");
472 b = scale8_LEAVING_R1_DIRTY( b, val);
473 asm volatile("");
474 cleanup_R1();
475#else
476 if( r ) r = scale8( r, val) + 1;
477 if( g ) g = scale8( g, val) + 1;
478 if( b ) b = scale8( b, val) + 1;
479#endif
480 }
481 }
482
483 // Here we have the old AVR "missing std X+n" problem again
484 // It turns out that fixing it winds up costing more than
485 // not fixing it.
486 // To paraphrase Dr Bronner, profile! profile! profile!
487 //asm volatile( "" : : : "r26", "r27" );
488 //asm volatile (" movw r30, r26 \n" : : : "r30", "r31");
489 rgb.r = r;
490 rgb.g = g;
491 rgb.b = b;
492}
493
494void hsv2rgb_fullspectrum( const struct CHSV& hsv, CRGB& rgb) {
495 const auto f = [](const int n, const uint8_t h) -> unsigned int {
496 constexpr int kZero = 0 << 8;
497 constexpr int kOne = 1 << 8;
498 constexpr int kFour = 4 << 8;
499 constexpr int kSix = 6 << 8;
500
501 const int k = ((n << 8) + 6*h) % kSix;
502 const int k2 = kFour - k;
503 return fl::fl_max(kZero, fl::fl_min(kOne, fl::fl_min(k, k2)));
504 };
505
506 const unsigned int chroma = hsv.v * hsv.s / 255;
507 rgb.r = hsv.v - ((chroma * f(5, hsv.h)) >> 8);
508 rgb.g = hsv.v - ((chroma * f(3, hsv.h)) >> 8);
509 rgb.b = hsv.v - ((chroma * f(1, hsv.h)) >> 8);
510}
511
513CRGB hsv2rgb_fullspectrum( const struct CHSV& hsv) {
514 CRGB rgb;
515 hsv2rgb_fullspectrum(hsv, rgb);
516 return rgb;
517}
518
519
520void hsv2rgb_raw(const struct CHSV * phsv, struct CRGB * prgb, int numLeds) {
521 for(int i = 0; i < numLeds; ++i) {
522 hsv2rgb_raw(phsv[i], prgb[i]);
523 }
524}
525
526void hsv2rgb_rainbow( const struct CHSV* phsv, struct CRGB * prgb, int numLeds) {
527 for(int i = 0; i < numLeds; ++i) {
528 hsv2rgb_rainbow(phsv[i], prgb[i]);
529 }
530}
531
532void hsv2rgb_spectrum( const struct CHSV* phsv, struct CRGB * prgb, int numLeds) {
533 for(int i = 0; i < numLeds; ++i) {
534 hsv2rgb_spectrum(phsv[i], prgb[i]);
535 }
536}
537
538void hsv2rgb_fullspectrum( const struct CHSV* phsv, struct CRGB * prgb, int numLeds) {
539 for (int i = 0; i < numLeds; ++i) {
540 hsv2rgb_fullspectrum(phsv[i], prgb[i]);
541 }
542}
543
545#define FIXFRAC8(N,D) (((N)*256)/(D))
546
547// This function is only an approximation, and it is not
548// nearly as fast as the normal HSV-to-RGB conversion.
549// See extended notes in the .h file.
551{
552 uint8_t r = rgb.r;
553 uint8_t g = rgb.g;
554 uint8_t b = rgb.b;
555 uint8_t h, s, v;
556
557 // find desaturation
558 uint8_t desat = 255;
559 if( r < desat) desat = r;
560 if( g < desat) desat = g;
561 if( b < desat) desat = b;
562
563 // remove saturation from all channels
564 r -= desat;
565 g -= desat;
566 b -= desat;
567
568 //Serial.print("desat="); Serial.print(desat); Serial.println("");
569
570 //uint8_t orig_desat = sqrt16( desat * 256);
571 //Serial.print("orig_desat="); Serial.print(orig_desat); Serial.println("");
572
573 // saturation is opposite of desaturation
574 s = 255 - desat;
575 //Serial.print("s.1="); Serial.print(s); Serial.println("");
576
577 if( s != 255 ) {
578 // undo 'dimming' of saturation
579 s = 255 - sqrt16( (255-s) * 256);
580 }
581 // without lib8tion: float ... ew ... sqrt... double ew, or rather, ew ^ 0.5
582 // if( s != 255 ) s = (255 - (256.0 * sqrt( (float)(255-s) / 256.0)));
583 //Serial.print("s.2="); Serial.print(s); Serial.println("");
584
585
586 // at least one channel is now zero
587 // if all three channels are zero, we had a
588 // shade of gray.
589 if( (r + g + b) == 0) {
590 // we pick hue zero for no special reason
591 return CHSV( 0, 0, 255 - s);
592 }
593
594 // scale all channels up to compensate for desaturation
595 if( s < 255) {
596 if( s == 0) s = 1;
597 uint32_t scaleup = 65535 / (s);
598 r = ((uint32_t)(r) * scaleup) / 256;
599 g = ((uint32_t)(g) * scaleup) / 256;
600 b = ((uint32_t)(b) * scaleup) / 256;
601 }
602 //Serial.print("r.2="); Serial.print(r); Serial.println("");
603 //Serial.print("g.2="); Serial.print(g); Serial.println("");
604 //Serial.print("b.2="); Serial.print(b); Serial.println("");
605
606 uint16_t total = r + g + b;
607
608 //Serial.print("total="); Serial.print(total); Serial.println("");
609
610 // scale all channels up to compensate for low values
611 if( total < 255) {
612 if( total == 0) total = 1;
613 uint32_t scaleup = 65535 / (total);
614 r = ((uint32_t)(r) * scaleup) / 256;
615 g = ((uint32_t)(g) * scaleup) / 256;
616 b = ((uint32_t)(b) * scaleup) / 256;
617 }
618 //Serial.print("r.3="); Serial.print(r); Serial.println("");
619 //Serial.print("g.3="); Serial.print(g); Serial.println("");
620 //Serial.print("b.3="); Serial.print(b); Serial.println("");
621
622 if( total > 255 ) {
623 v = 255;
624 } else {
625 v = qadd8(desat,total);
626 // undo 'dimming' of brightness
627 if( v != 255) v = sqrt16( v * 256);
628 // without lib8tion: float ... ew ... sqrt... double ew, or rather, ew ^ 0.5
629 // if( v != 255) v = (256.0 * sqrt( (float)(v) / 256.0));
630
631 }
632
633 //Serial.print("v="); Serial.print(v); Serial.println("");
634
635
636#if 0
637
638 //#else
639 if( v != 255) {
640 // this part could probably use refinement/rethinking,
641 // (but it doesn't overflow & wrap anymore)
642 uint16_t s16;
643 s16 = (s * 256);
644 s16 /= v;
645 //Serial.print("s16="); Serial.print(s16); Serial.println("");
646 if( s16 < 256) {
647 s = s16;
648 } else {
649 s = 255; // clamp to prevent overflow
650 }
651 }
652#endif
653
654 //Serial.print("s.3="); Serial.print(s); Serial.println("");
655
656
657 // since this wasn't a pure shade of gray,
658 // the interesting question is what hue is it
659
660
661
662 // start with which channel is highest
663 // (ties don't matter)
664 uint8_t highest = r;
665 if( g > highest) highest = g;
666 if( b > highest) highest = b;
667
668 if( highest == r ) {
669 // Red is highest.
670 // Hue could be Purple/Pink-Red,Red-Orange,Orange-Yellow
671 if( g == 0 ) {
672 // if green is zero, we're in Purple/Pink-Red
673 h = (HUE_PURPLE + HUE_PINK) / 2;
674 h += scale8( qsub8(r, 128), FIXFRAC8(48,128));
675 } else if ( (r - g) > g) {
676 // if R-G > G then we're in Red-Orange
677 h = HUE_RED;
678 h += scale8( g, FIXFRAC8(32,85));
679 } else {
680 // R-G < G, we're in Orange-Yellow
681 h = HUE_ORANGE;
682 h += scale8( qsub8((g - 85) + (171 - r), 4), FIXFRAC8(32,85)); //221
683 }
684
685 } else if ( highest == g) {
686 // Green is highest
687 // Hue could be Yellow-Green, Green-Aqua
688 if( b == 0) {
689 // if Blue is zero, we're in Yellow-Green
690 // G = 171..255
691 // R = 171.. 0
692 h = HUE_YELLOW;
693 uint8_t radj = scale8( qsub8(171,r), 47); //171..0 -> 0..171 -> 0..31
694 uint8_t gadj = scale8( qsub8(g,171), 96); //171..255 -> 0..84 -> 0..31;
695 uint8_t rgadj = radj + gadj;
696 uint8_t hueadv = rgadj / 2;
697 h += hueadv;
698 //h += scale8( qadd8( 4, qadd8((g - 128), (128 - r))),
699 // FIXFRAC8(32,255)); //
700 } else {
701 // if Blue is nonzero we're in Green-Aqua
702 if( (g-b) > b) {
703 h = HUE_GREEN;
704 h += scale8( b, FIXFRAC8(32,85));
705 } else {
706 h = HUE_AQUA;
707 h += scale8( qsub8(b, 85), FIXFRAC8(8,42));
708 }
709 }
710
711 } else /* highest == b */ {
712 // Blue is highest
713 // Hue could be Aqua/Blue-Blue, Blue-Purple, Purple-Pink
714 if( r == 0) {
715 // if red is zero, we're in Aqua/Blue-Blue
716 h = HUE_AQUA + ((HUE_BLUE - HUE_AQUA) / 4);
717 h += scale8( qsub8(b, 128), FIXFRAC8(24,128));
718 } else if ( (b-r) > r) {
719 // B-R > R, we're in Blue-Purple
720 h = HUE_BLUE;
721 h += scale8( r, FIXFRAC8(32,85));
722 } else {
723 // B-R < R, we're in Purple-Pink
724 h = HUE_PURPLE;
725 h += scale8( qsub8(r, 85), FIXFRAC8(32,85));
726 }
727 }
728
729 h += 1;
730 return CHSV( h, s, v);
731}
732
733// Examples that need work:
734// 0,192,192
735// 192,64,64
736// 224,32,32
737// 252,0,126
738// 252,252,0
739// 252,252,126
740
uint8_t hue
central include file for FastLED, defines the CFastLED class/object
@ HUE_BLUE
Blue (225°)
Definition hsv.h:102
@ HUE_RED
Red (0°)
Definition hsv.h:97
@ HUE_AQUA
Aqua (180°)
Definition hsv.h:101
@ HUE_PINK
Pink (315°)
Definition hsv.h:104
@ HUE_GREEN
Green (135°)
Definition hsv.h:100
@ HUE_YELLOW
Yellow (90°)
Definition hsv.h:99
@ HUE_ORANGE
Orange (45°)
Definition hsv.h:98
@ HUE_PURPLE
Purple (270°)
Definition hsv.h:103
UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
CHSV rgb2hsv_approximate(const CRGB &rgb)
Recover approximate HSV values from RGB.
Definition hsv2rgb.cpp:550
LIB8STATIC_ALWAYS_INLINE uint8_t qadd8(uint8_t i, uint8_t j)
Add one byte to another, saturating at 0xFF.
Definition math8.h:40
LIB8STATIC uint8_t sqrt16(uint16_t x)
Square root for 16-bit integers.
Definition math8.h:540
LIB8STATIC_ALWAYS_INLINE uint8_t qsub8(uint8_t i, uint8_t j)
Subtract one byte from another, saturating at 0x00.
Definition math8.h:112
LIB8STATIC_ALWAYS_INLINE void cleanup_R1()
Clean up the r1 register after a series of *LEAVING_R1_DIRTY calls.
Definition scale8.h:343
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:180
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:272
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:127
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:44
#define APPLY_DIMMING(X)
Apply dimming compensation to values.
Definition hsv2rgb.cpp:34
#define FIXFRAC8(N, D)
Convert a fractional input into a constant.
Definition hsv2rgb.cpp:545
CRGB hsv2rgb_rainbow(const struct CHSV &hsv)
Definition hsv2rgb.cpp:261
#define FORCE_REFERENCE(var)
Force a variable reference to avoid compiler over-optimization.
Definition hsv2rgb.cpp:251
void hsv2rgb_raw(const struct CHSV &hsv, struct CRGB &rgb)
Definition hsv2rgb.cpp:26
void hsv2rgb_raw_avr(const struct CHSV &hsv, struct CRGB &rgb)
HSV to RGB implementation in raw C, for the AVR platform only.
CRGB hsv2rgb_spectrum(const struct CHSV &hsv)
Inline version of hsv2rgb_spectrum which returns a CRGB object.
Definition hsv2rgb.cpp:45
FASTLED_NAMESPACE_BEGIN void hsv2rgb_raw_C(const struct CHSV &hsv, struct CRGB &rgb)
HSV to RGB implementation in raw C, platform independent.
Definition hsv2rgb.cpp:51
void hsv2rgb_fullspectrum(const struct CHSV &hsv, CRGB &rgb)
Definition hsv2rgb.cpp:494
#define HSV_SECTION_3
Divide the color wheel into four sections, 64 elements each.
Definition hsv2rgb.cpp:42
Functions to convert from the HSV colorspace to the RGB colorspace.
#define FASTLED_NAMESPACE_END
Definition namespace.h:23
#define FASTLED_NAMESPACE_BEGIN
Definition namespace.h:22
FL_DISABLE_WARNING_PUSH U common_type_t< T, U > fl_min(T a, U b)
Definition math_macros.h:25
common_type_t< T, U > fl_max(T a, U b)
Definition math_macros.h:29
Representation of an RGB pixel (Red, Green, Blue)
Definition crgb.h:86
Representation of an HSV pixel (hue, saturation, value (aka brightness)).
Definition hsv.h:15