diff options
author | Mark Kriegsman <kriegsman@tr.org> | 2014-06-18 09:37:18 +0400 |
---|---|---|
committer | Mark Kriegsman <kriegsman@tr.org> | 2014-06-18 09:37:18 +0400 |
commit | a71c5c5d341c25023ce462d52bd7fa62166e1483 (patch) | |
tree | 9064580a889e7c0390c7fee7f85a0d32298e2c22 | |
parent | 36bc6b94e6e09cd5fdb653e1b0b9a12d22f6e92a (diff) |
Initial Palette support.
-rw-r--r-- | colorutils.cpp | 243 | ||||
-rw-r--r-- | colorutils.h | 100 | ||||
-rw-r--r-- | preview_changes.txt | 1 |
3 files changed, 344 insertions, 0 deletions
diff --git a/colorutils.cpp b/colorutils.cpp index 12e9b0ad..399b2372 100644 --- a/colorutils.cpp +++ b/colorutils.cpp @@ -1,5 +1,7 @@ #include <stdint.h> +#include <avr/pgmspace.h> + #include "hsv2rgb.h" #include "colorutils.h" @@ -185,3 +187,244 @@ CRGB HeatColor( uint8_t temperature) return heatcolor; } + + + +CRGB ColorFromPalette( const CRGBPalette16& pal, uint8_t index, uint8_t brightness, TInterpolationType interpolationType) +{ + uint8_t hi4 = index >> 4; + uint8_t lo4 = index & 0x0F; + + // CRGB rgb1 = pal[ hi4]; + const CRGB* entry = pal + hi4; + uint8_t red1 = entry->red; + uint8_t green1 = entry->green; + uint8_t blue1 = entry->blue; + + uint8_t interpolate = lo4 && (interpolationType != INTERPOLATION_NONE); + + if( interpolate ) { + + if( hi4 == 15 ) { + entry = pal; + } else { + entry++; + } + + uint8_t f2 = lo4 << 4; + uint8_t f1 = 256 - f2; + + // rgb1.nscale8(f1); + red1 = scale8_LEAVING_R1_DIRTY( red1, f1); + green1 = scale8_LEAVING_R1_DIRTY( green1, f1); + blue1 = scale8_LEAVING_R1_DIRTY( blue1, f1); + + // cleanup_R1(); + + // CRGB rgb2 = pal[ hi4]; + // rgb2.nscale8(f2); + uint8_t red2 = entry->red; + uint8_t green2 = entry->green; + uint8_t blue2 = entry->blue; + red2 = scale8_LEAVING_R1_DIRTY( red2, f2); + green2 = scale8_LEAVING_R1_DIRTY( green2, f2); + blue2 = scale8_LEAVING_R1_DIRTY( blue2, f2); + + cleanup_R1(); + + // These sums can't overflow, so no qadd8 needed. + red1 += red2; + green1 += green2; + blue1 += blue2; + + } + + if( brightness != 255) { + nscale8x3_video( red1, green1, blue1, brightness); + } + + return CRGB( red1, green1, blue1); +} + + +CRGB ColorFromPalette( const CRGBPalette256& pal, uint8_t index, uint8_t brightness, TInterpolationType) +{ + const CRGB* entry = pal + index; + + uint8_t red = entry->red; + uint8_t green = entry->green; + uint8_t blue = entry->blue; + + if( brightness != 255) { + nscale8x3_video( red, green, blue, brightness); + } + + return CRGB( red, green, blue); +} + +typedef prog_uint32_t TProgmemPalette16[16]; + +const TProgmemPalette16 CloudPalette_p PROGMEM = +{ + CRGB::Blue, + CRGB::DarkBlue, + CRGB::DarkBlue, + CRGB::DarkBlue, + + CRGB::DarkBlue, + CRGB::DarkBlue, + CRGB::DarkBlue, + CRGB::DarkBlue, + + CRGB::Blue, + CRGB::DarkBlue, + CRGB::SkyBlue, + CRGB::SkyBlue, + + CRGB::LightBlue, + CRGB::White, + CRGB::LightBlue, + CRGB::SkyBlue +}; + +const TProgmemPalette16 LavaPalette_p PROGMEM = +{ + CRGB::Black, + CRGB::Maroon, + CRGB::Black, + CRGB::Maroon, + + CRGB::DarkRed, + CRGB::Maroon, + CRGB::DarkRed, + + CRGB::DarkRed, + CRGB::DarkRed, + CRGB::Red, + CRGB::Orange, + + CRGB::White, + CRGB::Orange, + CRGB::Red, + CRGB::DarkRed +}; + + +const TProgmemPalette16 OceanPalette_p PROGMEM = +{ + CRGB::MidnightBlue, + CRGB::DarkBlue, + CRGB::MidnightBlue, + CRGB::Navy, + + CRGB::DarkBlue, + CRGB::MediumBlue, + CRGB::SeaGreen, + CRGB::Teal, + + CRGB::CadetBlue, + CRGB::Blue, + CRGB::DarkCyan, + CRGB::CornflowerBlue, + + CRGB::Aquamarine, + CRGB::SeaGreen, + CRGB::Aqua, + CRGB::LightSkyBlue +}; + +const TProgmemPalette16 ForestPalette_p PROGMEM = +{ + CRGB::DarkGreen, + CRGB::DarkGreen, + CRGB::DarkOliveGreen, + CRGB::DarkGreen, + + CRGB::Green, + CRGB::ForestGreen, + CRGB::OliveDrab, + CRGB::Green, + + CRGB::SeaGreen, + CRGB::MediumAquamarine, + CRGB::LimeGreen, + CRGB::YellowGreen, + + CRGB::LightGreen, + CRGB::LawnGreen, + CRGB::MediumAquamarine, + CRGB::ForestGreen +}; + + +void InitPalette(CRGBPalette16& pal, const TProgmemPalette16 ppp) +{ + for( uint8_t i = 0; i < 16; i++) { + pal[i] = pgm_read_dword_near( ppp + i); + } +} + +void UpscalePalette(const CRGBPalette16& srcpal16, CRGBPalette256& destpal256) +{ + for( int i = 0; i < 256; i++) { + destpal256[i] = ColorFromPalette( srcpal16, i); + } +} + +void SetCloudPalette(CRGBPalette16& pal) +{ + InitPalette( pal, CloudPalette_p); +} + +void SetLavaPalette(CRGBPalette16& pal) +{ + InitPalette( pal, LavaPalette_p); +} + +void SetOceanPalette(CRGBPalette16& pal) +{ + InitPalette( pal, OceanPalette_p); +} + +void SetForestPalette(CRGBPalette16& pal) +{ + InitPalette( pal, ForestPalette_p); +} + +void SetRainbowPalette(CRGBPalette16& pal) +{ + for( uint8_t c = 0; c < 16; c += 1) { + uint8_t hue = c << 4; + pal[c] = CHSV( hue, 255, 255); + } +} + +void SetRainbowStripesPalette(CRGBPalette16& pal) +{ + for( uint8_t c = 0; c < 16; c += 2) { + uint8_t hue = c << 4; + pal[c] = CHSV( hue, 255, 255); + pal[c+1] = CRGB::Black; + } +} + +void fill_palette(CRGB* L, uint16_t N, uint8_t startIndex, uint8_t incIndex, + const CRGBPalette16& pal, uint8_t brightness, TInterpolationType interpType) +{ + uint8_t colorIndex = startIndex; + for( uint16_t i = 0; i < N; i++) { + L[i] = ColorFromPalette( pal, colorIndex, brightness, interpType); + colorIndex += incIndex; + } +} + + +void fill_palette(CRGB* L, uint16_t N, uint8_t startIndex, uint8_t incIndex, + const CRGBPalette256& pal, uint8_t brightness, TInterpolationType interpType) +{ + uint8_t colorIndex = startIndex; + for( uint16_t i = 0; i < N; i++) { + L[i] = ColorFromPalette( pal, colorIndex, brightness, interpType); + colorIndex += incIndex; + } +} diff --git a/colorutils.h b/colorutils.h index 44b2855b..001b8d36 100644 --- a/colorutils.h +++ b/colorutils.h @@ -74,4 +74,104 @@ void nscale8( CRGB* leds, uint16_t num_leds, uint8_t scale); // spectrum, but it's surprisingly close, and it's fast and small. CRGB HeatColor( uint8_t temperature); + +// Palettes +// +// Palettes map an 8-bit value (0..255) to an RGB color. +// +// You can create any color palette you wish; a couple of starters +// are provided: Forest, Clouds, Lava, Ocean, Rainbow, and Rainbow Stripes. +// +// Palettes come in the traditional 256-entry variety, which take +// up 768 bytes of RAM, and lightweight 16-entry varieties. The 16-entry +// variety automatically interpolates between its entries to produce +// a full 256-element color map, but at a cost of only 48 bytes or RAM. +// +// Basic operation is like this: (example shows the 16-entry variety) +// 1. Declare your palette storage: +// CRGBPalette16 myPalette; +// +// 2. Fill myPalette with your own 16 colors, or with a preset color scheme. +// You can specify your 16 colors a variety of ways: +// CRGBPalette16 myPalette = +// { +// CRGB::Black, +// CRGB::Black, +// CRGB::Red, +// CRGB::Yellow, +// CRGB::Green, +// CRGB::Blue, +// CRGB::Purple, +// CRGB::Black, +// +// 0x100000, +// 0x200000, +// 0x400000, +// 0x800000, +// +// CHSV( 30,255,255), +// CHSV( 50,255,255), +// CHSV( 70,255,255), +// CHSV( 90,255,255) +// }; +// +// Or you can initiaize your palette with a preset color scheme: +// SetRainbowStripesPalette( myPalette); +// +// 3. Any time you want to set a pixel to a color from your palette, use +// "ColorFromPalette(...)" as shown: +// +// uint8_t index = /* any value 0..255 */; +// leds[i] = ColorFromPalette( myPalette, index); +// +// Even though your palette has only 16 explicily defined entries, you +// can use an 'index' from 0..255. The 16 explicit palette entries will +// be spread evenly across the 0..255 range, and the intermedate values +// will be RGB-interpolated between adjacent explicit entries. +// +// It's easier to use than it sounds. +// + +typedef CRGB CRGBPalette16[16]; +typedef CRGB CRGBPalette256[256]; + +typedef enum { INTERPOLATION_NONE=0, INTERPOLATION_BLEND=1 } TInterpolationType; + +CRGB ColorFromPalette( const CRGBPalette16& pal, + uint8_t index, + uint8_t brightness=255, + TInterpolationType interpolationType=INTERPOLATION_BLEND); + +CRGB ColorFromPalette( const CRGBPalette256& pal, + uint8_t index, + uint8_t brightness=255, + TInterpolationType interpolationType=INTERPOLATION_NONE ); + +// Preset color schemes, such as they are. +// Try Rainbow Stripes or Lava first. +void SetForestPalette(CRGBPalette16& pal); +void SetCloudPalette(CRGBPalette16& pal); +void SetLavaPalette(CRGBPalette16& pal); +void SetOceanPalette(CRGBPalette16& pal); +void SetRainbowPalette(CRGBPalette16& pal); +void SetRainbowStripesPalette(CRGBPalette16& pal); + + +// Convert a 16-entry palette to a 256-entry palette +void UpscalePalette(const CRGBPalette16& srcpal16, CRGBPalette256& destpal256); + +// Fill a range of LEDs with a sequece of entryies from a palette +void fill_palette(CRGB* L, uint16_t N, + uint8_t startIndex, uint8_t incIndex, + const CRGBPalette16& pal, + uint8_t brightness=255, + TInterpolationType interpType=INTERPOLATION_BLEND); + +void fill_palette(CRGB* L, uint16_t N, + uint8_t startIndex, uint8_t incIndex, + const CRGBPalette256& pal, + uint8_t brightness=255, + TInterpolationType interpType=INTERPOLATION_NONE); + + #endif diff --git a/preview_changes.txt b/preview_changes.txt index da565b0e..88a9f9bc 100644 --- a/preview_changes.txt +++ b/preview_changes.txt @@ -19,3 +19,4 @@ * Added fill_gradient * Added inoise8/inoise16 and example program * Added LEDS.countFPS() for debugging framerate counts. Bit rough at the moment, thought +* Added Palettes and associated functions and presets |