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