PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

hsv2rgb.cpp 23KB

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