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.

1707 lines
58KB

  1. #ifndef __INC_COLORUTILS_H
  2. #define __INC_COLORUTILS_H
  3. ///@file colorutils.h
  4. /// functions for color fill, paletters, blending, and more
  5. #include "FastLED.h"
  6. #include "pixeltypes.h"
  7. #include "fastled_progmem.h"
  8. FASTLED_NAMESPACE_BEGIN
  9. ///@defgroup Colorutils Color utility functions
  10. ///A variety of functions for working with color, palletes, and leds
  11. ///@{
  12. /// fill_solid - fill a range of LEDs with a solid color
  13. /// Example: fill_solid( leds, NUM_LEDS, CRGB(50,0,200));
  14. void fill_solid( struct CRGB * leds, int numToFill,
  15. const struct CRGB& color);
  16. /// fill_solid - fill a range of LEDs with a solid color
  17. /// Example: fill_solid( leds, NUM_LEDS, CRGB(50,0,200));
  18. void fill_solid( struct CHSV* targetArray, int numToFill,
  19. const struct CHSV& hsvColor);
  20. /// fill_rainbow - fill a range of LEDs with a rainbow of colors, at
  21. /// full saturation and full value (brightness)
  22. void fill_rainbow( struct CRGB * pFirstLED, int numToFill,
  23. uint8_t initialhue,
  24. uint8_t deltahue = 5);
  25. /// fill_rainbow - fill a range of LEDs with a rainbow of colors, at
  26. /// full saturation and full value (brightness)
  27. void fill_rainbow( struct CHSV * targetArray, int numToFill,
  28. uint8_t initialhue,
  29. uint8_t deltahue = 5);
  30. // fill_gradient - fill an array of colors with a smooth HSV gradient
  31. // between two specified HSV colors.
  32. // Since 'hue' is a value around a color wheel,
  33. // there are always two ways to sweep from one hue
  34. // to another.
  35. // This function lets you specify which way you want
  36. // the hue gradient to sweep around the color wheel:
  37. // FORWARD_HUES: hue always goes clockwise
  38. // BACKWARD_HUES: hue always goes counter-clockwise
  39. // SHORTEST_HUES: hue goes whichever way is shortest
  40. // LONGEST_HUES: hue goes whichever way is longest
  41. // The default is SHORTEST_HUES, as this is nearly
  42. // always what is wanted.
  43. //
  44. // fill_gradient can write the gradient colors EITHER
  45. // (1) into an array of CRGBs (e.g., into leds[] array, or an RGB Palette)
  46. // OR
  47. // (2) into an array of CHSVs (e.g. an HSV Palette).
  48. //
  49. // In the case of writing into a CRGB array, the gradient is
  50. // computed in HSV space, and then HSV values are converted to RGB
  51. // as they're written into the RGB array.
  52. typedef enum { FORWARD_HUES, BACKWARD_HUES, SHORTEST_HUES, LONGEST_HUES } TGradientDirectionCode;
  53. #define saccum87 int16_t
  54. /// fill_gradient - fill an array of colors with a smooth HSV gradient
  55. /// between two specified HSV colors.
  56. /// Since 'hue' is a value around a color wheel,
  57. /// there are always two ways to sweep from one hue
  58. /// to another.
  59. /// This function lets you specify which way you want
  60. /// the hue gradient to sweep around the color wheel:
  61. ///
  62. /// FORWARD_HUES: hue always goes clockwise
  63. /// BACKWARD_HUES: hue always goes counter-clockwise
  64. /// SHORTEST_HUES: hue goes whichever way is shortest
  65. /// LONGEST_HUES: hue goes whichever way is longest
  66. ///
  67. /// The default is SHORTEST_HUES, as this is nearly
  68. /// always what is wanted.
  69. ///
  70. /// fill_gradient can write the gradient colors EITHER
  71. /// (1) into an array of CRGBs (e.g., into leds[] array, or an RGB Palette)
  72. /// OR
  73. /// (2) into an array of CHSVs (e.g. an HSV Palette).
  74. ///
  75. /// In the case of writing into a CRGB array, the gradient is
  76. /// computed in HSV space, and then HSV values are converted to RGB
  77. /// as they're written into the RGB array.
  78. template <typename T>
  79. void fill_gradient( T* targetArray,
  80. uint16_t startpos, CHSV startcolor,
  81. uint16_t endpos, CHSV endcolor,
  82. TGradientDirectionCode directionCode = SHORTEST_HUES )
  83. {
  84. // if the points are in the wrong order, straighten them
  85. if( endpos < startpos ) {
  86. uint16_t t = endpos;
  87. CHSV tc = endcolor;
  88. endcolor = startcolor;
  89. endpos = startpos;
  90. startpos = t;
  91. startcolor = tc;
  92. }
  93. // If we're fading toward black (val=0) or white (sat=0),
  94. // then set the endhue to the starthue.
  95. // This lets us ramp smoothly to black or white, regardless
  96. // of what 'hue' was set in the endcolor (since it doesn't matter)
  97. if( endcolor.value == 0 || endcolor.saturation == 0) {
  98. endcolor.hue = startcolor.hue;
  99. }
  100. // Similarly, if we're fading in from black (val=0) or white (sat=0)
  101. // then set the starthue to the endhue.
  102. // This lets us ramp smoothly up from black or white, regardless
  103. // of what 'hue' was set in the startcolor (since it doesn't matter)
  104. if( startcolor.value == 0 || startcolor.saturation == 0) {
  105. startcolor.hue = endcolor.hue;
  106. }
  107. saccum87 huedistance87;
  108. saccum87 satdistance87;
  109. saccum87 valdistance87;
  110. satdistance87 = (endcolor.sat - startcolor.sat) << 7;
  111. valdistance87 = (endcolor.val - startcolor.val) << 7;
  112. uint8_t huedelta8 = endcolor.hue - startcolor.hue;
  113. if( directionCode == SHORTEST_HUES ) {
  114. directionCode = FORWARD_HUES;
  115. if( huedelta8 > 127) {
  116. directionCode = BACKWARD_HUES;
  117. }
  118. }
  119. if( directionCode == LONGEST_HUES ) {
  120. directionCode = FORWARD_HUES;
  121. if( huedelta8 < 128) {
  122. directionCode = BACKWARD_HUES;
  123. }
  124. }
  125. if( directionCode == FORWARD_HUES) {
  126. huedistance87 = huedelta8 << 7;
  127. }
  128. else /* directionCode == BACKWARD_HUES */
  129. {
  130. huedistance87 = (uint8_t)(256 - huedelta8) << 7;
  131. huedistance87 = -huedistance87;
  132. }
  133. uint16_t pixeldistance = endpos - startpos;
  134. int16_t divisor = pixeldistance ? pixeldistance : 1;
  135. saccum87 huedelta87 = huedistance87 / divisor;
  136. saccum87 satdelta87 = satdistance87 / divisor;
  137. saccum87 valdelta87 = valdistance87 / divisor;
  138. huedelta87 *= 2;
  139. satdelta87 *= 2;
  140. valdelta87 *= 2;
  141. accum88 hue88 = startcolor.hue << 8;
  142. accum88 sat88 = startcolor.sat << 8;
  143. accum88 val88 = startcolor.val << 8;
  144. for( uint16_t i = startpos; i <= endpos; i++) {
  145. targetArray[i] = CHSV( hue88 >> 8, sat88 >> 8, val88 >> 8);
  146. hue88 += huedelta87;
  147. sat88 += satdelta87;
  148. val88 += valdelta87;
  149. }
  150. }
  151. // Convenience functions to fill an array of colors with a
  152. // two-color, three-color, or four-color gradient
  153. template <typename T>
  154. void fill_gradient( T* targetArray, uint16_t numLeds, const CHSV& c1, const CHSV& c2,
  155. TGradientDirectionCode directionCode = SHORTEST_HUES )
  156. {
  157. uint16_t last = numLeds - 1;
  158. fill_gradient( targetArray, 0, c1, last, c2, directionCode);
  159. }
  160. template <typename T>
  161. void fill_gradient( T* targetArray, uint16_t numLeds,
  162. const CHSV& c1, const CHSV& c2, const CHSV& c3,
  163. TGradientDirectionCode directionCode = SHORTEST_HUES )
  164. {
  165. uint16_t half = (numLeds / 2);
  166. uint16_t last = numLeds - 1;
  167. fill_gradient( targetArray, 0, c1, half, c2, directionCode);
  168. fill_gradient( targetArray, half, c2, last, c3, directionCode);
  169. }
  170. template <typename T>
  171. void fill_gradient( T* targetArray, uint16_t numLeds,
  172. const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4,
  173. TGradientDirectionCode directionCode = SHORTEST_HUES )
  174. {
  175. uint16_t onethird = (numLeds / 3);
  176. uint16_t twothirds = ((numLeds * 2) / 3);
  177. uint16_t last = numLeds - 1;
  178. fill_gradient( targetArray, 0, c1, onethird, c2, directionCode);
  179. fill_gradient( targetArray, onethird, c2, twothirds, c3, directionCode);
  180. fill_gradient( targetArray, twothirds, c3, last, c4, directionCode);
  181. }
  182. // convenience synonym
  183. #define fill_gradient_HSV fill_gradient
  184. // fill_gradient_RGB - fill a range of LEDs with a smooth RGB gradient
  185. // between two specified RGB colors.
  186. // Unlike HSV, there is no 'color wheel' in RGB space,
  187. // and therefore there's only one 'direction' for the
  188. // gradient to go, and no 'direction code' is needed.
  189. void fill_gradient_RGB( CRGB* leds,
  190. uint16_t startpos, CRGB startcolor,
  191. uint16_t endpos, CRGB endcolor );
  192. void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2);
  193. void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2, const CRGB& c3);
  194. void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4);
  195. // fadeLightBy and fade_video - reduce the brightness of an array
  196. // of pixels all at once. Guaranteed
  197. // to never fade all the way to black.
  198. // (The two names are synonyms.)
  199. void fadeLightBy( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
  200. void fade_video( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
  201. // nscale8_video - scale down the brightness of an array of pixels
  202. // all at once. Guaranteed to never scale a pixel
  203. // all the way down to black, unless 'scale' is zero.
  204. void nscale8_video( CRGB* leds, uint16_t num_leds, uint8_t scale);
  205. // fadeToBlackBy and fade_raw - reduce the brightness of an array
  206. // of pixels all at once. These
  207. // functions will eventually fade all
  208. // the way to black.
  209. // (The two names are synonyms.)
  210. void fadeToBlackBy( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
  211. void fade_raw( CRGB* leds, uint16_t num_leds, uint8_t fadeBy);
  212. // nscale8 - scale down the brightness of an array of pixels
  213. // all at once. This function can scale pixels all the
  214. // way down to black even if 'scale' is not zero.
  215. void nscale8( CRGB* leds, uint16_t num_leds, uint8_t scale);
  216. // fadeUsingColor - scale down the brightness of an array of pixels,
  217. // as though it were seen through a transparent
  218. // filter with the specified color.
  219. // For example, if the colormask is
  220. // CRGB( 200, 100, 50)
  221. // then the pixels' red will be faded to 200/256ths,
  222. // their green to 100/256ths, and their blue to 50/256ths.
  223. // This particular example give a 'hot fade' look,
  224. // with white fading to yellow, then red, then black.
  225. // You can also use colormasks like CRGB::Blue to
  226. // zero out the red and green elements, leaving blue
  227. // (largely) the same.
  228. void fadeUsingColor( CRGB* leds, uint16_t numLeds, const CRGB& colormask);
  229. // Pixel blending
  230. //
  231. // blend - computes a new color blended some fraction of the way
  232. // between two other colors.
  233. CRGB blend( const CRGB& p1, const CRGB& p2, fract8 amountOfP2 );
  234. CHSV blend( const CHSV& p1, const CHSV& p2, fract8 amountOfP2,
  235. TGradientDirectionCode directionCode = SHORTEST_HUES );
  236. // blend - computes a new color blended array of colors, each
  237. // a given fraction of the way between corresponding
  238. // elements of two source arrays of colors.
  239. // Useful for blending palettes.
  240. CRGB* blend( const CRGB* src1, const CRGB* src2, CRGB* dest,
  241. uint16_t count, fract8 amountOfsrc2 );
  242. CHSV* blend( const CHSV* src1, const CHSV* src2, CHSV* dest,
  243. uint16_t count, fract8 amountOfsrc2,
  244. TGradientDirectionCode directionCode = SHORTEST_HUES );
  245. // nblend - destructively modifies one color, blending
  246. // in a given fraction of an overlay color
  247. CRGB& nblend( CRGB& existing, const CRGB& overlay, fract8 amountOfOverlay );
  248. CHSV& nblend( CHSV& existing, const CHSV& overlay, fract8 amountOfOverlay,
  249. TGradientDirectionCode directionCode = SHORTEST_HUES );
  250. // nblend - destructively blends a given fraction of
  251. // a new color array into an existing color array
  252. void nblend( CRGB* existing, CRGB* overlay, uint16_t count, fract8 amountOfOverlay);
  253. void nblend( CHSV* existing, CHSV* overlay, uint16_t count, fract8 amountOfOverlay,
  254. TGradientDirectionCode directionCode = SHORTEST_HUES);
  255. // blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors.
  256. // blur2d: two-dimensional blur filter. Spreads light to 8 XY neighbors.
  257. //
  258. // 0 = no spread at all
  259. // 64 = moderate spreading
  260. // 172 = maximum smooth, even spreading
  261. //
  262. // 173..255 = wider spreading, but increasing flicker
  263. //
  264. // Total light is NOT entirely conserved, so many repeated
  265. // calls to 'blur' will also result in the light fading,
  266. // eventually all the way to black; this is by design so that
  267. // it can be used to (slowly) clear the LEDs to black.
  268. void blur1d( CRGB* leds, uint16_t numLeds, fract8 blur_amount);
  269. void blur2d( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
  270. // blurRows: perform a blur1d on every row of a rectangular matrix
  271. void blurRows( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
  272. // blurColumns: perform a blur1d on each column of a rectangular matrix
  273. void blurColumns(CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount);
  274. // CRGB HeatColor( uint8_t temperature)
  275. //
  276. // Approximates a 'black body radiation' spectrum for
  277. // a given 'heat' level. This is useful for animations of 'fire'.
  278. // Heat is specified as an arbitrary scale from 0 (cool) to 255 (hot).
  279. // This is NOT a chromatically correct 'black body radiation'
  280. // spectrum, but it's surprisingly close, and it's fast and small.
  281. CRGB HeatColor( uint8_t temperature);
  282. // Palettes
  283. //
  284. // RGB Palettes map an 8-bit value (0..255) to an RGB color.
  285. //
  286. // You can create any color palette you wish; a couple of starters
  287. // are provided: Forest, Clouds, Lava, Ocean, Rainbow, and Rainbow Stripes.
  288. //
  289. // Palettes come in the traditional 256-entry variety, which take
  290. // up 768 bytes of RAM, and lightweight 16-entry varieties. The 16-entry
  291. // variety automatically interpolates between its entries to produce
  292. // a full 256-element color map, but at a cost of only 48 bytes or RAM.
  293. //
  294. // Basic operation is like this: (example shows the 16-entry variety)
  295. // 1. Declare your palette storage:
  296. // CRGBPalette16 myPalette;
  297. //
  298. // 2. Fill myPalette with your own 16 colors, or with a preset color scheme.
  299. // You can specify your 16 colors a variety of ways:
  300. // CRGBPalette16 myPalette(
  301. // CRGB::Black,
  302. // CRGB::Black,
  303. // CRGB::Red,
  304. // CRGB::Yellow,
  305. // CRGB::Green,
  306. // CRGB::Blue,
  307. // CRGB::Purple,
  308. // CRGB::Black,
  309. //
  310. // 0x100000,
  311. // 0x200000,
  312. // 0x400000,
  313. // 0x800000,
  314. //
  315. // CHSV( 30,255,255),
  316. // CHSV( 50,255,255),
  317. // CHSV( 70,255,255),
  318. // CHSV( 90,255,255)
  319. // );
  320. //
  321. // Or you can initiaize your palette with a preset color scheme:
  322. // myPalette = RainbowStripesColors_p;
  323. //
  324. // 3. Any time you want to set a pixel to a color from your palette, use
  325. // "ColorFromPalette(...)" as shown:
  326. //
  327. // uint8_t index = /* any value 0..255 */;
  328. // leds[i] = ColorFromPalette( myPalette, index);
  329. //
  330. // Even though your palette has only 16 explicily defined entries, you
  331. // can use an 'index' from 0..255. The 16 explicit palette entries will
  332. // be spread evenly across the 0..255 range, and the intermedate values
  333. // will be RGB-interpolated between adjacent explicit entries.
  334. //
  335. // It's easier to use than it sounds.
  336. //
  337. class CRGBPalette16;
  338. class CRGBPalette32;
  339. class CRGBPalette256;
  340. class CHSVPalette16;
  341. class CHSVPalette32;
  342. class CHSVPalette256;
  343. typedef uint32_t TProgmemRGBPalette16[16];
  344. typedef uint32_t TProgmemHSVPalette16[16];
  345. #define TProgmemPalette16 TProgmemRGBPalette16
  346. typedef uint32_t TProgmemRGBPalette32[32];
  347. typedef uint32_t TProgmemHSVPalette32[32];
  348. #define TProgmemPalette32 TProgmemRGBPalette32
  349. typedef const uint8_t TProgmemRGBGradientPalette_byte ;
  350. typedef const TProgmemRGBGradientPalette_byte *TProgmemRGBGradientPalette_bytes;
  351. typedef TProgmemRGBGradientPalette_bytes TProgmemRGBGradientPalettePtr;
  352. typedef union {
  353. struct {
  354. uint8_t index;
  355. uint8_t r;
  356. uint8_t g;
  357. uint8_t b;
  358. };
  359. uint32_t dword;
  360. uint8_t bytes[4];
  361. } TRGBGradientPaletteEntryUnion;
  362. typedef uint8_t TDynamicRGBGradientPalette_byte ;
  363. typedef const TDynamicRGBGradientPalette_byte *TDynamicRGBGradientPalette_bytes;
  364. typedef TDynamicRGBGradientPalette_bytes TDynamicRGBGradientPalettePtr;
  365. // Convert a 16-entry palette to a 256-entry palette
  366. void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette256& destpal256);
  367. void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette256& destpal256);
  368. // Convert a 16-entry palette to a 32-entry palette
  369. void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette32& destpal32);
  370. void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette32& destpal32);
  371. // Convert a 32-entry palette to a 256-entry palette
  372. void UpscalePalette(const struct CRGBPalette32& srcpal32, struct CRGBPalette256& destpal256);
  373. void UpscalePalette(const struct CHSVPalette32& srcpal32, struct CHSVPalette256& destpal256);
  374. class CHSVPalette16 {
  375. public:
  376. CHSV entries[16];
  377. CHSVPalette16() {};
  378. CHSVPalette16( const CHSV& c00,const CHSV& c01,const CHSV& c02,const CHSV& c03,
  379. const CHSV& c04,const CHSV& c05,const CHSV& c06,const CHSV& c07,
  380. const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11,
  381. const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 )
  382. {
  383. entries[0]=c00; entries[1]=c01; entries[2]=c02; entries[3]=c03;
  384. entries[4]=c04; entries[5]=c05; entries[6]=c06; entries[7]=c07;
  385. entries[8]=c08; entries[9]=c09; entries[10]=c10; entries[11]=c11;
  386. entries[12]=c12; entries[13]=c13; entries[14]=c14; entries[15]=c15;
  387. };
  388. CHSVPalette16( const CHSVPalette16& rhs)
  389. {
  390. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  391. }
  392. CHSVPalette16& operator=( const CHSVPalette16& rhs)
  393. {
  394. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  395. return *this;
  396. }
  397. CHSVPalette16( const TProgmemHSVPalette16& rhs)
  398. {
  399. for( uint8_t i = 0; i < 16; i++) {
  400. CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
  401. entries[i].hue = xyz.red;
  402. entries[i].sat = xyz.green;
  403. entries[i].val = xyz.blue;
  404. }
  405. }
  406. CHSVPalette16& operator=( const TProgmemHSVPalette16& rhs)
  407. {
  408. for( uint8_t i = 0; i < 16; i++) {
  409. CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
  410. entries[i].hue = xyz.red;
  411. entries[i].sat = xyz.green;
  412. entries[i].val = xyz.blue;
  413. }
  414. return *this;
  415. }
  416. inline CHSV& operator[] (uint8_t x) __attribute__((always_inline))
  417. {
  418. return entries[x];
  419. }
  420. inline const CHSV& operator[] (uint8_t x) const __attribute__((always_inline))
  421. {
  422. return entries[x];
  423. }
  424. inline CHSV& operator[] (int x) __attribute__((always_inline))
  425. {
  426. return entries[(uint8_t)x];
  427. }
  428. inline const CHSV& operator[] (int x) const __attribute__((always_inline))
  429. {
  430. return entries[(uint8_t)x];
  431. }
  432. operator CHSV*()
  433. {
  434. return &(entries[0]);
  435. }
  436. bool operator==( const CHSVPalette16 rhs)
  437. {
  438. const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
  439. const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
  440. if( p == q) return true;
  441. for( uint8_t i = 0; i < (sizeof( entries)); i++) {
  442. if( *p != *q) return false;
  443. p++;
  444. q++;
  445. }
  446. return true;
  447. }
  448. bool operator!=( const CHSVPalette16 rhs)
  449. {
  450. return !( *this == rhs);
  451. }
  452. CHSVPalette16( const CHSV& c1)
  453. {
  454. fill_solid( &(entries[0]), 16, c1);
  455. }
  456. CHSVPalette16( const CHSV& c1, const CHSV& c2)
  457. {
  458. fill_gradient( &(entries[0]), 16, c1, c2);
  459. }
  460. CHSVPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3)
  461. {
  462. fill_gradient( &(entries[0]), 16, c1, c2, c3);
  463. }
  464. CHSVPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
  465. {
  466. fill_gradient( &(entries[0]), 16, c1, c2, c3, c4);
  467. }
  468. };
  469. class CHSVPalette256 {
  470. public:
  471. CHSV entries[256];
  472. CHSVPalette256() {};
  473. CHSVPalette256( const CHSV& c00,const CHSV& c01,const CHSV& c02,const CHSV& c03,
  474. const CHSV& c04,const CHSV& c05,const CHSV& c06,const CHSV& c07,
  475. const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11,
  476. const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 )
  477. {
  478. CHSVPalette16 p16(c00,c01,c02,c03,c04,c05,c06,c07,
  479. c08,c09,c10,c11,c12,c13,c14,c15);
  480. *this = p16;
  481. };
  482. CHSVPalette256( const CHSVPalette256& rhs)
  483. {
  484. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  485. }
  486. CHSVPalette256& operator=( const CHSVPalette256& rhs)
  487. {
  488. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  489. return *this;
  490. }
  491. CHSVPalette256( const CHSVPalette16& rhs16)
  492. {
  493. UpscalePalette( rhs16, *this);
  494. }
  495. CHSVPalette256& operator=( const CHSVPalette16& rhs16)
  496. {
  497. UpscalePalette( rhs16, *this);
  498. return *this;
  499. }
  500. CHSVPalette256( const TProgmemRGBPalette16& rhs)
  501. {
  502. CHSVPalette16 p16(rhs);
  503. *this = p16;
  504. }
  505. CHSVPalette256& operator=( const TProgmemRGBPalette16& rhs)
  506. {
  507. CHSVPalette16 p16(rhs);
  508. *this = p16;
  509. return *this;
  510. }
  511. inline CHSV& operator[] (uint8_t x) __attribute__((always_inline))
  512. {
  513. return entries[x];
  514. }
  515. inline const CHSV& operator[] (uint8_t x) const __attribute__((always_inline))
  516. {
  517. return entries[x];
  518. }
  519. inline CHSV& operator[] (int x) __attribute__((always_inline))
  520. {
  521. return entries[(uint8_t)x];
  522. }
  523. inline const CHSV& operator[] (int x) const __attribute__((always_inline))
  524. {
  525. return entries[(uint8_t)x];
  526. }
  527. operator CHSV*()
  528. {
  529. return &(entries[0]);
  530. }
  531. bool operator==( const CHSVPalette256 rhs)
  532. {
  533. const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
  534. const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
  535. if( p == q) return true;
  536. for( uint16_t i = 0; i < (sizeof( entries)); i++) {
  537. if( *p != *q) return false;
  538. p++;
  539. q++;
  540. }
  541. return true;
  542. }
  543. bool operator!=( const CHSVPalette256 rhs)
  544. {
  545. return !( *this == rhs);
  546. }
  547. CHSVPalette256( const CHSV& c1)
  548. {
  549. fill_solid( &(entries[0]), 256, c1);
  550. }
  551. CHSVPalette256( const CHSV& c1, const CHSV& c2)
  552. {
  553. fill_gradient( &(entries[0]), 256, c1, c2);
  554. }
  555. CHSVPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3)
  556. {
  557. fill_gradient( &(entries[0]), 256, c1, c2, c3);
  558. }
  559. CHSVPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
  560. {
  561. fill_gradient( &(entries[0]), 256, c1, c2, c3, c4);
  562. }
  563. };
  564. class CRGBPalette16 {
  565. public:
  566. CRGB entries[16];
  567. CRGBPalette16() {};
  568. CRGBPalette16( const CRGB& c00,const CRGB& c01,const CRGB& c02,const CRGB& c03,
  569. const CRGB& c04,const CRGB& c05,const CRGB& c06,const CRGB& c07,
  570. const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11,
  571. const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 )
  572. {
  573. entries[0]=c00; entries[1]=c01; entries[2]=c02; entries[3]=c03;
  574. entries[4]=c04; entries[5]=c05; entries[6]=c06; entries[7]=c07;
  575. entries[8]=c08; entries[9]=c09; entries[10]=c10; entries[11]=c11;
  576. entries[12]=c12; entries[13]=c13; entries[14]=c14; entries[15]=c15;
  577. };
  578. CRGBPalette16( const CRGBPalette16& rhs)
  579. {
  580. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  581. }
  582. CRGBPalette16( const CRGB rhs[16])
  583. {
  584. memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
  585. }
  586. CRGBPalette16& operator=( const CRGBPalette16& rhs)
  587. {
  588. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  589. return *this;
  590. }
  591. CRGBPalette16& operator=( const CRGB rhs[16])
  592. {
  593. memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
  594. return *this;
  595. }
  596. CRGBPalette16( const CHSVPalette16& rhs)
  597. {
  598. for( uint8_t i = 0; i < 16; i++) {
  599. entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
  600. }
  601. }
  602. CRGBPalette16( const CHSV rhs[16])
  603. {
  604. for( uint8_t i = 0; i < 16; i++) {
  605. entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
  606. }
  607. }
  608. CRGBPalette16& operator=( const CHSVPalette16& rhs)
  609. {
  610. for( uint8_t i = 0; i < 16; i++) {
  611. entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
  612. }
  613. return *this;
  614. }
  615. CRGBPalette16& operator=( const CHSV rhs[16])
  616. {
  617. for( uint8_t i = 0; i < 16; i++) {
  618. entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
  619. }
  620. return *this;
  621. }
  622. CRGBPalette16( const TProgmemRGBPalette16& rhs)
  623. {
  624. for( uint8_t i = 0; i < 16; i++) {
  625. entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
  626. }
  627. }
  628. CRGBPalette16& operator=( const TProgmemRGBPalette16& rhs)
  629. {
  630. for( uint8_t i = 0; i < 16; i++) {
  631. entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
  632. }
  633. return *this;
  634. }
  635. bool operator==( const CRGBPalette16 rhs)
  636. {
  637. const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
  638. const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
  639. if( p == q) return true;
  640. for( uint8_t i = 0; i < (sizeof( entries)); i++) {
  641. if( *p != *q) return false;
  642. p++;
  643. q++;
  644. }
  645. return true;
  646. }
  647. bool operator!=( const CRGBPalette16 rhs)
  648. {
  649. return !( *this == rhs);
  650. }
  651. inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
  652. {
  653. return entries[x];
  654. }
  655. inline const CRGB& operator[] (uint8_t x) const __attribute__((always_inline))
  656. {
  657. return entries[x];
  658. }
  659. inline CRGB& operator[] (int x) __attribute__((always_inline))
  660. {
  661. return entries[(uint8_t)x];
  662. }
  663. inline const CRGB& operator[] (int x) const __attribute__((always_inline))
  664. {
  665. return entries[(uint8_t)x];
  666. }
  667. operator CRGB*()
  668. {
  669. return &(entries[0]);
  670. }
  671. CRGBPalette16( const CHSV& c1)
  672. {
  673. fill_solid( &(entries[0]), 16, c1);
  674. }
  675. CRGBPalette16( const CHSV& c1, const CHSV& c2)
  676. {
  677. fill_gradient( &(entries[0]), 16, c1, c2);
  678. }
  679. CRGBPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3)
  680. {
  681. fill_gradient( &(entries[0]), 16, c1, c2, c3);
  682. }
  683. CRGBPalette16( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
  684. {
  685. fill_gradient( &(entries[0]), 16, c1, c2, c3, c4);
  686. }
  687. CRGBPalette16( const CRGB& c1)
  688. {
  689. fill_solid( &(entries[0]), 16, c1);
  690. }
  691. CRGBPalette16( const CRGB& c1, const CRGB& c2)
  692. {
  693. fill_gradient_RGB( &(entries[0]), 16, c1, c2);
  694. }
  695. CRGBPalette16( const CRGB& c1, const CRGB& c2, const CRGB& c3)
  696. {
  697. fill_gradient_RGB( &(entries[0]), 16, c1, c2, c3);
  698. }
  699. CRGBPalette16( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
  700. {
  701. fill_gradient_RGB( &(entries[0]), 16, c1, c2, c3, c4);
  702. }
  703. // Gradient palettes are loaded into CRGB16Palettes in such a way
  704. // that, if possible, every color represented in the gradient palette
  705. // is also represented in the CRGBPalette16.
  706. // For example, consider a gradient palette that is all black except
  707. // for a single, one-element-wide (1/256th!) spike of red in the middle:
  708. // 0, 0,0,0
  709. // 124, 0,0,0
  710. // 125, 255,0,0 // one 1/256th-palette-wide red stripe
  711. // 126, 0,0,0
  712. // 255, 0,0,0
  713. // A naive conversion of this 256-element palette to a 16-element palette
  714. // might accidentally completely eliminate the red spike, rendering the
  715. // palette completely black.
  716. // However, the conversions provided here would attempt to include a
  717. // the red stripe in the output, more-or-less as faithfully as possible.
  718. // So in this case, the resulting CRGBPalette16 palette would have a red
  719. // stripe in the middle which was 1/16th of a palette wide -- the
  720. // narrowest possible in a CRGBPalette16.
  721. // This means that the relative width of stripes in a CRGBPalette16
  722. // will be, by definition, different from the widths in the gradient
  723. // palette. This code attempts to preserve "all the colors", rather than
  724. // the exact stripe widths at the expense of dropping some colors.
  725. CRGBPalette16( TProgmemRGBGradientPalette_bytes progpal )
  726. {
  727. *this = progpal;
  728. }
  729. CRGBPalette16& operator=( TProgmemRGBGradientPalette_bytes progpal )
  730. {
  731. TRGBGradientPaletteEntryUnion* progent = (TRGBGradientPaletteEntryUnion*)(progpal);
  732. TRGBGradientPaletteEntryUnion u;
  733. // Count entries
  734. uint16_t count = 0;
  735. do {
  736. u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
  737. count++;;
  738. } while ( u.index != 255);
  739. int8_t lastSlotUsed = -1;
  740. u.dword = FL_PGM_READ_DWORD_NEAR( progent);
  741. CRGB rgbstart( u.r, u.g, u.b);
  742. int indexstart = 0;
  743. uint8_t istart8 = 0;
  744. uint8_t iend8 = 0;
  745. while( indexstart < 255) {
  746. progent++;
  747. u.dword = FL_PGM_READ_DWORD_NEAR( progent);
  748. int indexend = u.index;
  749. CRGB rgbend( u.r, u.g, u.b);
  750. istart8 = indexstart / 16;
  751. iend8 = indexend / 16;
  752. if( count < 16) {
  753. if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
  754. istart8 = lastSlotUsed + 1;
  755. if( iend8 < istart8) {
  756. iend8 = istart8;
  757. }
  758. }
  759. lastSlotUsed = iend8;
  760. }
  761. fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
  762. indexstart = indexend;
  763. rgbstart = rgbend;
  764. }
  765. return *this;
  766. }
  767. CRGBPalette16& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal )
  768. {
  769. TRGBGradientPaletteEntryUnion* ent = (TRGBGradientPaletteEntryUnion*)(gpal);
  770. TRGBGradientPaletteEntryUnion u;
  771. // Count entries
  772. uint16_t count = 0;
  773. do {
  774. u = *(ent + count);
  775. count++;;
  776. } while ( u.index != 255);
  777. int8_t lastSlotUsed = -1;
  778. u = *ent;
  779. CRGB rgbstart( u.r, u.g, u.b);
  780. int indexstart = 0;
  781. uint8_t istart8 = 0;
  782. uint8_t iend8 = 0;
  783. while( indexstart < 255) {
  784. ent++;
  785. u = *ent;
  786. int indexend = u.index;
  787. CRGB rgbend( u.r, u.g, u.b);
  788. istart8 = indexstart / 16;
  789. iend8 = indexend / 16;
  790. if( count < 16) {
  791. if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 15)) {
  792. istart8 = lastSlotUsed + 1;
  793. if( iend8 < istart8) {
  794. iend8 = istart8;
  795. }
  796. }
  797. lastSlotUsed = iend8;
  798. }
  799. fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
  800. indexstart = indexend;
  801. rgbstart = rgbend;
  802. }
  803. return *this;
  804. }
  805. };
  806. class CHSVPalette32 {
  807. public:
  808. CHSV entries[32];
  809. CHSVPalette32() {};
  810. CHSVPalette32( const CHSV& c00,const CHSV& c01,const CHSV& c02,const CHSV& c03,
  811. const CHSV& c04,const CHSV& c05,const CHSV& c06,const CHSV& c07,
  812. const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11,
  813. const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 )
  814. {
  815. for( uint8_t i = 0; i < 2; i++) {
  816. entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03;
  817. entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07;
  818. entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11;
  819. entries[24+i]=c12; entries[26+i]=c13; entries[28+i]=c14; entries[30+i]=c15;
  820. }
  821. };
  822. CHSVPalette32( const CHSVPalette32& rhs)
  823. {
  824. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  825. }
  826. CHSVPalette32& operator=( const CHSVPalette32& rhs)
  827. {
  828. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  829. return *this;
  830. }
  831. CHSVPalette32( const TProgmemHSVPalette32& rhs)
  832. {
  833. for( uint8_t i = 0; i < 32; i++) {
  834. CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
  835. entries[i].hue = xyz.red;
  836. entries[i].sat = xyz.green;
  837. entries[i].val = xyz.blue;
  838. }
  839. }
  840. CHSVPalette32& operator=( const TProgmemHSVPalette32& rhs)
  841. {
  842. for( uint8_t i = 0; i < 32; i++) {
  843. CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
  844. entries[i].hue = xyz.red;
  845. entries[i].sat = xyz.green;
  846. entries[i].val = xyz.blue;
  847. }
  848. return *this;
  849. }
  850. inline CHSV& operator[] (uint8_t x) __attribute__((always_inline))
  851. {
  852. return entries[x];
  853. }
  854. inline const CHSV& operator[] (uint8_t x) const __attribute__((always_inline))
  855. {
  856. return entries[x];
  857. }
  858. inline CHSV& operator[] (int x) __attribute__((always_inline))
  859. {
  860. return entries[(uint8_t)x];
  861. }
  862. inline const CHSV& operator[] (int x) const __attribute__((always_inline))
  863. {
  864. return entries[(uint8_t)x];
  865. }
  866. operator CHSV*()
  867. {
  868. return &(entries[0]);
  869. }
  870. bool operator==( const CHSVPalette32 rhs)
  871. {
  872. const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
  873. const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
  874. if( p == q) return true;
  875. for( uint8_t i = 0; i < (sizeof( entries)); i++) {
  876. if( *p != *q) return false;
  877. p++;
  878. q++;
  879. }
  880. return true;
  881. }
  882. bool operator!=( const CHSVPalette32 rhs)
  883. {
  884. return !( *this == rhs);
  885. }
  886. CHSVPalette32( const CHSV& c1)
  887. {
  888. fill_solid( &(entries[0]), 32, c1);
  889. }
  890. CHSVPalette32( const CHSV& c1, const CHSV& c2)
  891. {
  892. fill_gradient( &(entries[0]), 32, c1, c2);
  893. }
  894. CHSVPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3)
  895. {
  896. fill_gradient( &(entries[0]), 32, c1, c2, c3);
  897. }
  898. CHSVPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
  899. {
  900. fill_gradient( &(entries[0]), 32, c1, c2, c3, c4);
  901. }
  902. };
  903. class CRGBPalette32 {
  904. public:
  905. CRGB entries[32];
  906. CRGBPalette32() {};
  907. CRGBPalette32( const CRGB& c00,const CRGB& c01,const CRGB& c02,const CRGB& c03,
  908. const CRGB& c04,const CRGB& c05,const CRGB& c06,const CRGB& c07,
  909. const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11,
  910. const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 )
  911. {
  912. for( uint8_t i = 0; i < 2; i++) {
  913. entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03;
  914. entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07;
  915. entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11;
  916. entries[24+i]=c12; entries[26+i]=c13; entries[28+i]=c14; entries[30+i]=c15;
  917. }
  918. };
  919. CRGBPalette32( const CRGBPalette32& rhs)
  920. {
  921. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  922. }
  923. CRGBPalette32( const CRGB rhs[32])
  924. {
  925. memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
  926. }
  927. CRGBPalette32& operator=( const CRGBPalette32& rhs)
  928. {
  929. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  930. return *this;
  931. }
  932. CRGBPalette32& operator=( const CRGB rhs[32])
  933. {
  934. memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
  935. return *this;
  936. }
  937. CRGBPalette32( const CHSVPalette32& rhs)
  938. {
  939. for( uint8_t i = 0; i < 32; i++) {
  940. entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
  941. }
  942. }
  943. CRGBPalette32( const CHSV rhs[32])
  944. {
  945. for( uint8_t i = 0; i < 32; i++) {
  946. entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
  947. }
  948. }
  949. CRGBPalette32& operator=( const CHSVPalette32& rhs)
  950. {
  951. for( uint8_t i = 0; i < 32; i++) {
  952. entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
  953. }
  954. return *this;
  955. }
  956. CRGBPalette32& operator=( const CHSV rhs[32])
  957. {
  958. for( uint8_t i = 0; i < 32; i++) {
  959. entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
  960. }
  961. return *this;
  962. }
  963. CRGBPalette32( const TProgmemRGBPalette32& rhs)
  964. {
  965. for( uint8_t i = 0; i < 32; i++) {
  966. entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
  967. }
  968. }
  969. CRGBPalette32& operator=( const TProgmemRGBPalette32& rhs)
  970. {
  971. for( uint8_t i = 0; i < 32; i++) {
  972. entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
  973. }
  974. return *this;
  975. }
  976. bool operator==( const CRGBPalette32 rhs)
  977. {
  978. const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
  979. const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
  980. if( p == q) return true;
  981. for( uint8_t i = 0; i < (sizeof( entries)); i++) {
  982. if( *p != *q) return false;
  983. p++;
  984. q++;
  985. }
  986. return true;
  987. }
  988. bool operator!=( const CRGBPalette32 rhs)
  989. {
  990. return !( *this == rhs);
  991. }
  992. inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
  993. {
  994. return entries[x];
  995. }
  996. inline const CRGB& operator[] (uint8_t x) const __attribute__((always_inline))
  997. {
  998. return entries[x];
  999. }
  1000. inline CRGB& operator[] (int x) __attribute__((always_inline))
  1001. {
  1002. return entries[(uint8_t)x];
  1003. }
  1004. inline const CRGB& operator[] (int x) const __attribute__((always_inline))
  1005. {
  1006. return entries[(uint8_t)x];
  1007. }
  1008. operator CRGB*()
  1009. {
  1010. return &(entries[0]);
  1011. }
  1012. CRGBPalette32( const CHSV& c1)
  1013. {
  1014. fill_solid( &(entries[0]), 32, c1);
  1015. }
  1016. CRGBPalette32( const CHSV& c1, const CHSV& c2)
  1017. {
  1018. fill_gradient( &(entries[0]), 32, c1, c2);
  1019. }
  1020. CRGBPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3)
  1021. {
  1022. fill_gradient( &(entries[0]), 32, c1, c2, c3);
  1023. }
  1024. CRGBPalette32( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
  1025. {
  1026. fill_gradient( &(entries[0]), 32, c1, c2, c3, c4);
  1027. }
  1028. CRGBPalette32( const CRGB& c1)
  1029. {
  1030. fill_solid( &(entries[0]), 32, c1);
  1031. }
  1032. CRGBPalette32( const CRGB& c1, const CRGB& c2)
  1033. {
  1034. fill_gradient_RGB( &(entries[0]), 32, c1, c2);
  1035. }
  1036. CRGBPalette32( const CRGB& c1, const CRGB& c2, const CRGB& c3)
  1037. {
  1038. fill_gradient_RGB( &(entries[0]), 32, c1, c2, c3);
  1039. }
  1040. CRGBPalette32( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
  1041. {
  1042. fill_gradient_RGB( &(entries[0]), 32, c1, c2, c3, c4);
  1043. }
  1044. CRGBPalette32( const CRGBPalette16& rhs16)
  1045. {
  1046. UpscalePalette( rhs16, *this);
  1047. }
  1048. CRGBPalette32& operator=( const CRGBPalette16& rhs16)
  1049. {
  1050. UpscalePalette( rhs16, *this);
  1051. return *this;
  1052. }
  1053. CRGBPalette32( const TProgmemRGBPalette16& rhs)
  1054. {
  1055. CRGBPalette16 p16(rhs);
  1056. *this = p16;
  1057. }
  1058. CRGBPalette32& operator=( const TProgmemRGBPalette16& rhs)
  1059. {
  1060. CRGBPalette16 p16(rhs);
  1061. *this = p16;
  1062. return *this;
  1063. }
  1064. // Gradient palettes are loaded into CRGB16Palettes in such a way
  1065. // that, if possible, every color represented in the gradient palette
  1066. // is also represented in the CRGBPalette32.
  1067. // For example, consider a gradient palette that is all black except
  1068. // for a single, one-element-wide (1/256th!) spike of red in the middle:
  1069. // 0, 0,0,0
  1070. // 124, 0,0,0
  1071. // 125, 255,0,0 // one 1/256th-palette-wide red stripe
  1072. // 126, 0,0,0
  1073. // 255, 0,0,0
  1074. // A naive conversion of this 256-element palette to a 16-element palette
  1075. // might accidentally completely eliminate the red spike, rendering the
  1076. // palette completely black.
  1077. // However, the conversions provided here would attempt to include a
  1078. // the red stripe in the output, more-or-less as faithfully as possible.
  1079. // So in this case, the resulting CRGBPalette32 palette would have a red
  1080. // stripe in the middle which was 1/16th of a palette wide -- the
  1081. // narrowest possible in a CRGBPalette32.
  1082. // This means that the relative width of stripes in a CRGBPalette32
  1083. // will be, by definition, different from the widths in the gradient
  1084. // palette. This code attempts to preserve "all the colors", rather than
  1085. // the exact stripe widths at the expense of dropping some colors.
  1086. CRGBPalette32( TProgmemRGBGradientPalette_bytes progpal )
  1087. {
  1088. *this = progpal;
  1089. }
  1090. CRGBPalette32& operator=( TProgmemRGBGradientPalette_bytes progpal )
  1091. {
  1092. TRGBGradientPaletteEntryUnion* progent = (TRGBGradientPaletteEntryUnion*)(progpal);
  1093. TRGBGradientPaletteEntryUnion u;
  1094. // Count entries
  1095. uint16_t count = 0;
  1096. do {
  1097. u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
  1098. count++;;
  1099. } while ( u.index != 255);
  1100. int8_t lastSlotUsed = -1;
  1101. u.dword = FL_PGM_READ_DWORD_NEAR( progent);
  1102. CRGB rgbstart( u.r, u.g, u.b);
  1103. int indexstart = 0;
  1104. uint8_t istart8 = 0;
  1105. uint8_t iend8 = 0;
  1106. while( indexstart < 255) {
  1107. progent++;
  1108. u.dword = FL_PGM_READ_DWORD_NEAR( progent);
  1109. int indexend = u.index;
  1110. CRGB rgbend( u.r, u.g, u.b);
  1111. istart8 = indexstart / 8;
  1112. iend8 = indexend / 8;
  1113. if( count < 16) {
  1114. if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
  1115. istart8 = lastSlotUsed + 1;
  1116. if( iend8 < istart8) {
  1117. iend8 = istart8;
  1118. }
  1119. }
  1120. lastSlotUsed = iend8;
  1121. }
  1122. fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
  1123. indexstart = indexend;
  1124. rgbstart = rgbend;
  1125. }
  1126. return *this;
  1127. }
  1128. CRGBPalette32& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal )
  1129. {
  1130. TRGBGradientPaletteEntryUnion* ent = (TRGBGradientPaletteEntryUnion*)(gpal);
  1131. TRGBGradientPaletteEntryUnion u;
  1132. // Count entries
  1133. uint16_t count = 0;
  1134. do {
  1135. u = *(ent + count);
  1136. count++;;
  1137. } while ( u.index != 255);
  1138. int8_t lastSlotUsed = -1;
  1139. u = *ent;
  1140. CRGB rgbstart( u.r, u.g, u.b);
  1141. int indexstart = 0;
  1142. uint8_t istart8 = 0;
  1143. uint8_t iend8 = 0;
  1144. while( indexstart < 255) {
  1145. ent++;
  1146. u = *ent;
  1147. int indexend = u.index;
  1148. CRGB rgbend( u.r, u.g, u.b);
  1149. istart8 = indexstart / 8;
  1150. iend8 = indexend / 8;
  1151. if( count < 16) {
  1152. if( (istart8 <= lastSlotUsed) && (lastSlotUsed < 31)) {
  1153. istart8 = lastSlotUsed + 1;
  1154. if( iend8 < istart8) {
  1155. iend8 = istart8;
  1156. }
  1157. }
  1158. lastSlotUsed = iend8;
  1159. }
  1160. fill_gradient_RGB( &(entries[0]), istart8, rgbstart, iend8, rgbend);
  1161. indexstart = indexend;
  1162. rgbstart = rgbend;
  1163. }
  1164. return *this;
  1165. }
  1166. };
  1167. class CRGBPalette256 {
  1168. public:
  1169. CRGB entries[256];
  1170. CRGBPalette256() {};
  1171. CRGBPalette256( const CRGB& c00,const CRGB& c01,const CRGB& c02,const CRGB& c03,
  1172. const CRGB& c04,const CRGB& c05,const CRGB& c06,const CRGB& c07,
  1173. const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11,
  1174. const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 )
  1175. {
  1176. CRGBPalette16 p16(c00,c01,c02,c03,c04,c05,c06,c07,
  1177. c08,c09,c10,c11,c12,c13,c14,c15);
  1178. *this = p16;
  1179. };
  1180. CRGBPalette256( const CRGBPalette256& rhs)
  1181. {
  1182. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  1183. }
  1184. CRGBPalette256( const CRGB rhs[256])
  1185. {
  1186. memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
  1187. }
  1188. CRGBPalette256& operator=( const CRGBPalette256& rhs)
  1189. {
  1190. memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
  1191. return *this;
  1192. }
  1193. CRGBPalette256& operator=( const CRGB rhs[256])
  1194. {
  1195. memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
  1196. return *this;
  1197. }
  1198. CRGBPalette256( const CHSVPalette256& rhs)
  1199. {
  1200. for( int i = 0; i < 256; i++) {
  1201. entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
  1202. }
  1203. }
  1204. CRGBPalette256( const CHSV rhs[256])
  1205. {
  1206. for( int i = 0; i < 256; i++) {
  1207. entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
  1208. }
  1209. }
  1210. CRGBPalette256& operator=( const CHSVPalette256& rhs)
  1211. {
  1212. for( int i = 0; i < 256; i++) {
  1213. entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
  1214. }
  1215. return *this;
  1216. }
  1217. CRGBPalette256& operator=( const CHSV rhs[256])
  1218. {
  1219. for( int i = 0; i < 256; i++) {
  1220. entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
  1221. }
  1222. return *this;
  1223. }
  1224. CRGBPalette256( const CRGBPalette16& rhs16)
  1225. {
  1226. UpscalePalette( rhs16, *this);
  1227. }
  1228. CRGBPalette256& operator=( const CRGBPalette16& rhs16)
  1229. {
  1230. UpscalePalette( rhs16, *this);
  1231. return *this;
  1232. }
  1233. CRGBPalette256( const TProgmemRGBPalette16& rhs)
  1234. {
  1235. CRGBPalette16 p16(rhs);
  1236. *this = p16;
  1237. }
  1238. CRGBPalette256& operator=( const TProgmemRGBPalette16& rhs)
  1239. {
  1240. CRGBPalette16 p16(rhs);
  1241. *this = p16;
  1242. return *this;
  1243. }
  1244. bool operator==( const CRGBPalette256 rhs)
  1245. {
  1246. const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
  1247. const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
  1248. if( p == q) return true;
  1249. for( uint16_t i = 0; i < (sizeof( entries)); i++) {
  1250. if( *p != *q) return false;
  1251. p++;
  1252. q++;
  1253. }
  1254. return true;
  1255. }
  1256. bool operator!=( const CRGBPalette256 rhs)
  1257. {
  1258. return !( *this == rhs);
  1259. }
  1260. inline CRGB& operator[] (uint8_t x) __attribute__((always_inline))
  1261. {
  1262. return entries[x];
  1263. }
  1264. inline const CRGB& operator[] (uint8_t x) const __attribute__((always_inline))
  1265. {
  1266. return entries[x];
  1267. }
  1268. inline CRGB& operator[] (int x) __attribute__((always_inline))
  1269. {
  1270. return entries[(uint8_t)x];
  1271. }
  1272. inline const CRGB& operator[] (int x) const __attribute__((always_inline))
  1273. {
  1274. return entries[(uint8_t)x];
  1275. }
  1276. operator CRGB*()
  1277. {
  1278. return &(entries[0]);
  1279. }
  1280. CRGBPalette256( const CHSV& c1)
  1281. {
  1282. fill_solid( &(entries[0]), 256, c1);
  1283. }
  1284. CRGBPalette256( const CHSV& c1, const CHSV& c2)
  1285. {
  1286. fill_gradient( &(entries[0]), 256, c1, c2);
  1287. }
  1288. CRGBPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3)
  1289. {
  1290. fill_gradient( &(entries[0]), 256, c1, c2, c3);
  1291. }
  1292. CRGBPalette256( const CHSV& c1, const CHSV& c2, const CHSV& c3, const CHSV& c4)
  1293. {
  1294. fill_gradient( &(entries[0]), 256, c1, c2, c3, c4);
  1295. }
  1296. CRGBPalette256( const CRGB& c1)
  1297. {
  1298. fill_solid( &(entries[0]), 256, c1);
  1299. }
  1300. CRGBPalette256( const CRGB& c1, const CRGB& c2)
  1301. {
  1302. fill_gradient_RGB( &(entries[0]), 256, c1, c2);
  1303. }
  1304. CRGBPalette256( const CRGB& c1, const CRGB& c2, const CRGB& c3)
  1305. {
  1306. fill_gradient_RGB( &(entries[0]), 256, c1, c2, c3);
  1307. }
  1308. CRGBPalette256( const CRGB& c1, const CRGB& c2, const CRGB& c3, const CRGB& c4)
  1309. {
  1310. fill_gradient_RGB( &(entries[0]), 256, c1, c2, c3, c4);
  1311. }
  1312. CRGBPalette256( TProgmemRGBGradientPalette_bytes progpal )
  1313. {
  1314. *this = progpal;
  1315. }
  1316. CRGBPalette256& operator=( TProgmemRGBGradientPalette_bytes progpal )
  1317. {
  1318. TRGBGradientPaletteEntryUnion* progent = (TRGBGradientPaletteEntryUnion*)(progpal);
  1319. TRGBGradientPaletteEntryUnion u;
  1320. u.dword = FL_PGM_READ_DWORD_NEAR( progent);
  1321. CRGB rgbstart( u.r, u.g, u.b);
  1322. int indexstart = 0;
  1323. while( indexstart < 255) {
  1324. progent++;
  1325. u.dword = FL_PGM_READ_DWORD_NEAR( progent);
  1326. int indexend = u.index;
  1327. CRGB rgbend( u.r, u.g, u.b);
  1328. fill_gradient_RGB( &(entries[0]), indexstart, rgbstart, indexend, rgbend);
  1329. indexstart = indexend;
  1330. rgbstart = rgbend;
  1331. }
  1332. return *this;
  1333. }
  1334. CRGBPalette256& loadDynamicGradientPalette( TDynamicRGBGradientPalette_bytes gpal )
  1335. {
  1336. TRGBGradientPaletteEntryUnion* ent = (TRGBGradientPaletteEntryUnion*)(gpal);
  1337. TRGBGradientPaletteEntryUnion u;
  1338. u = *ent;
  1339. CRGB rgbstart( u.r, u.g, u.b);
  1340. int indexstart = 0;
  1341. while( indexstart < 255) {
  1342. ent++;
  1343. u = *ent;
  1344. int indexend = u.index;
  1345. CRGB rgbend( u.r, u.g, u.b);
  1346. fill_gradient_RGB( &(entries[0]), indexstart, rgbstart, indexend, rgbend);
  1347. indexstart = indexend;
  1348. rgbstart = rgbend;
  1349. }
  1350. return *this;
  1351. }
  1352. };
  1353. typedef enum { NOBLEND=0, LINEARBLEND=1 } TBlendType;
  1354. CRGB ColorFromPalette( const CRGBPalette16& pal,
  1355. uint8_t index,
  1356. uint8_t brightness=255,
  1357. TBlendType blendType=LINEARBLEND);
  1358. CRGB ColorFromPalette( const TProgmemRGBPalette16& pal,
  1359. uint8_t index,
  1360. uint8_t brightness=255,
  1361. TBlendType blendType=LINEARBLEND);
  1362. CRGB ColorFromPalette( const CRGBPalette256& pal,
  1363. uint8_t index,
  1364. uint8_t brightness=255,
  1365. TBlendType blendType=NOBLEND );
  1366. CHSV ColorFromPalette( const CHSVPalette16& pal,
  1367. uint8_t index,
  1368. uint8_t brightness=255,
  1369. TBlendType blendType=LINEARBLEND);
  1370. CHSV ColorFromPalette( const CHSVPalette256& pal,
  1371. uint8_t index,
  1372. uint8_t brightness=255,
  1373. TBlendType blendType=NOBLEND );
  1374. CRGB ColorFromPalette( const CRGBPalette32& pal,
  1375. uint8_t index,
  1376. uint8_t brightness=255,
  1377. TBlendType blendType=LINEARBLEND);
  1378. CRGB ColorFromPalette( const TProgmemRGBPalette32& pal,
  1379. uint8_t index,
  1380. uint8_t brightness=255,
  1381. TBlendType blendType=LINEARBLEND);
  1382. CHSV ColorFromPalette( const CHSVPalette32& pal,
  1383. uint8_t index,
  1384. uint8_t brightness=255,
  1385. TBlendType blendType=LINEARBLEND);
  1386. // Fill a range of LEDs with a sequece of entryies from a palette
  1387. template <typename PALETTE>
  1388. void fill_palette(CRGB* L, uint16_t N, uint8_t startIndex, uint8_t incIndex,
  1389. const PALETTE& pal, uint8_t brightness, TBlendType blendType)
  1390. {
  1391. uint8_t colorIndex = startIndex;
  1392. for( uint16_t i = 0; i < N; i++) {
  1393. L[i] = ColorFromPalette( pal, colorIndex, brightness, blendType);
  1394. colorIndex += incIndex;
  1395. }
  1396. }
  1397. template <typename PALETTE>
  1398. void map_data_into_colors_through_palette(
  1399. uint8_t *dataArray, uint16_t dataCount,
  1400. CRGB* targetColorArray,
  1401. const PALETTE& pal,
  1402. uint8_t brightness=255,
  1403. uint8_t opacity=255,
  1404. TBlendType blendType=LINEARBLEND)
  1405. {
  1406. for( uint16_t i = 0; i < dataCount; i++) {
  1407. uint8_t d = dataArray[i];
  1408. CRGB rgb = ColorFromPalette( pal, d, brightness, blendType);
  1409. if( opacity == 255 ) {
  1410. targetColorArray[i] = rgb;
  1411. } else {
  1412. targetColorArray[i].nscale8( 256 - opacity);
  1413. rgb.nscale8_video( opacity);
  1414. targetColorArray[i] += rgb;
  1415. }
  1416. }
  1417. }
  1418. // nblendPaletteTowardPalette:
  1419. // Alter one palette by making it slightly more like
  1420. // a 'target palette', used for palette cross-fades.
  1421. //
  1422. // It does this by comparing each of the R, G, and B channels
  1423. // of each entry in the current palette to the corresponding
  1424. // entry in the target palette and making small adjustments:
  1425. // If the Red channel is too low, it will be increased.
  1426. // If the Red channel is too high, it will be slightly reduced.
  1427. // ... and likewise for Green and Blue channels.
  1428. //
  1429. // Additionally, there are two significant visual improvements
  1430. // to this algorithm implemented here. First is this:
  1431. // When increasing a channel, it is stepped up by ONE.
  1432. // When decreasing a channel, it is stepped down by TWO.
  1433. // Due to the way the eye perceives light, and the way colors
  1434. // are represented in RGB, this produces a more uniform apparent
  1435. // brightness when cross-fading between most palette colors.
  1436. //
  1437. // The second visual tweak is limiting the number of changes
  1438. // that will be made to the palette at once. If all the palette
  1439. // entries are changed at once, it can give a muddled appearance.
  1440. // However, if only a few palette entries are changed at once,
  1441. // you get a visually smoother transition: in the middle of the
  1442. // cross-fade your current palette will actually contain some
  1443. // colors from the old palette, a few blended colors, and some
  1444. // colors from the new palette.
  1445. // The maximum number of possible palette changes per call
  1446. // is 48 (sixteen color entries time three channels each).
  1447. // The default 'maximim number of changes' here is 12, meaning
  1448. // that only approximately a quarter of the palette entries
  1449. // will be changed per call.
  1450. void nblendPaletteTowardPalette( CRGBPalette16& currentPalette,
  1451. CRGBPalette16& targetPalette,
  1452. uint8_t maxChanges=24);
  1453. // You can also define a static RGB palette very compactly in terms of a series
  1454. // of connected color gradients.
  1455. // For example, if you want the first 3/4ths of the palette to be a slow
  1456. // gradient ramping from black to red, and then the remaining 1/4 of the
  1457. // palette to be a quicker ramp to white, you specify just three points: the
  1458. // starting black point (at index 0), the red midpoint (at index 192),
  1459. // and the final white point (at index 255). It looks like this:
  1460. //
  1461. // index: 0 192 255
  1462. // |----------r-r-r-rrrrrrrrRrRrRrRrRRRR-|-RRWRWWRWWW-|
  1463. // color: (0,0,0) (255,0,0) (255,255,255)
  1464. //
  1465. // Here's how you'd define that gradient palette:
  1466. //
  1467. // DEFINE_GRADIENT_PALETTE( black_to_red_to_white_p ) {
  1468. // 0, 0, 0, 0, /* at index 0, black(0,0,0) */
  1469. // 192, 255, 0, 0, /* at index 192, red(255,0,0) */
  1470. // 255, 255,255,255 /* at index 255, white(255,255,255) */
  1471. // };
  1472. //
  1473. // This format is designed for compact storage. The example palette here
  1474. // takes up just 12 bytes of PROGMEM (flash) storage, and zero bytes
  1475. // of SRAM when not currently in use.
  1476. //
  1477. // To use one of these gradient palettes, simply assign it into a
  1478. // CRGBPalette16 or a CRGBPalette256, like this:
  1479. //
  1480. // CRGBPalette16 pal = black_to_red_to_white_p;
  1481. //
  1482. // When the assignment is made, the gradients are expanded out into
  1483. // either 16 or 256 palette entries, depending on the kind of palette
  1484. // object they're assigned to.
  1485. //
  1486. // IMPORTANT NOTES & CAVEATS:
  1487. //
  1488. // - The last 'index' position MUST BE 255! Failure to end with
  1489. // index 255 will result in program hangs or crashes.
  1490. //
  1491. // - At this point, these gradient palette definitions MUST BE
  1492. // stored in PROGMEM on AVR-based Arduinos. If you use the
  1493. // DEFINE_GRADIENT_PALETTE macro, this is taken care of automatically.
  1494. //
  1495. #define DEFINE_GRADIENT_PALETTE(X) \
  1496. FL_ALIGN_PROGMEM \
  1497. extern const TProgmemRGBGradientPalette_byte X[] FL_PROGMEM =
  1498. #define DECLARE_GRADIENT_PALETTE(X) \
  1499. FL_ALIGN_PROGMEM \
  1500. extern const TProgmemRGBGradientPalette_byte X[] FL_PROGMEM
  1501. // Functions to apply gamma adjustments, either:
  1502. // - a single gamma adjustment to a single scalar value,
  1503. // - a single gamma adjustment to each channel of a CRGB color, or
  1504. // - different gamma adjustments for each channel of a CRFB color.
  1505. //
  1506. // Note that the gamma is specified as a traditional floating point value
  1507. // e.g., "2.5", and as such these functions should not be called in
  1508. // your innermost pixel loops, or in animations that are extremely
  1509. // low on program storage space. Nevertheless, if you need these
  1510. // functions, here they are.
  1511. //
  1512. // Furthermore, bear in mind that CRGB leds have only eight bits
  1513. // per channel of color resolution, and that very small, subtle shadings
  1514. // may not be visible.
  1515. uint8_t applyGamma_video( uint8_t brightness, float gamma);
  1516. CRGB applyGamma_video( const CRGB& orig, float gamma);
  1517. CRGB applyGamma_video( const CRGB& orig, float gammaR, float gammaG, float gammaB);
  1518. // The "n" versions below modify their arguments in-place.
  1519. CRGB& napplyGamma_video( CRGB& rgb, float gamma);
  1520. CRGB& napplyGamma_video( CRGB& rgb, float gammaR, float gammaG, float gammaB);
  1521. void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gamma);
  1522. void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gammaR, float gammaG, float gammaB);
  1523. FASTLED_NAMESPACE_END
  1524. ///@}
  1525. #endif