diff --git a/Adafruit_NeoMatrix.cpp b/Adafruit_NeoMatrix.cpp index 82fcd1a..b9b1f9b 100644 --- a/Adafruit_NeoMatrix.cpp +++ b/Adafruit_NeoMatrix.cpp @@ -74,6 +74,64 @@ uint16_t Adafruit_NeoMatrix::Color(uint8_t r, uint8_t g, uint8_t b) { (b >> 3); } +uint16_t Adafruit_NeoMatrix::ColorHSV(uint16_t hue, uint8_t sat, uint8_t val) { + + uint8_t r, g, b, r2, g2, b2; + + // Remap 0-65535 to 0-1529. Pure red is CENTERED on the 64K rollover; + // 0 is not the start of pure red, but the midpoint...a few values above + // zero and a few below 65536 all yield pure red (similarly, 32768 is the + // midpoint, not start, of pure cyan). The 8-bit RGB hexcone (256 values + // each for red, green, blue) really only allows for 1530 distinct hues + // (not 1536, more on that below), but the full unsigned 16-bit type was + // chosen for hue so that one's code can easily handle a contiguous color + // wheel by allowing hue to roll over in either direction. + hue = (hue * 1530L + 32768) / 65536; + + // Convert hue to R,G,B (nested ifs faster than divide+mod+switch): + if(hue < 510) { // Red to Green-1 + b = 0; + if(hue < 255) { // Red to Yellow-1 + r = 255; + g = hue; // g = 0 to 254 + } else { // Yellow to Green-1 + r = 510 - hue; // r = 255 to 1 + g = 255; + } + } else if(hue < 1020) { // Green to Blue-1 + r = 0; + if(hue < 765) { // Green to Cyan-1 + g = 255; + b = hue - 510; // b = 0 to 254 + } else { // Cyan to Blue-1 + g = 1020 - hue; // g = 255 to 1 + b = 255; + } + } else if(hue < 1530) { // Blue to Red-1 + g = 0; + if(hue < 1275) { // Blue to Magenta-1 + r = hue - 1020; // r = 0 to 254 + b = 255; + } else { // Magenta to Red-1 + r = 255; + b = 1530 - hue; // b = 255 to 1 + } + } else { // Last 0.5 Red (quicker than % operator) + r = 255; + g = b = 0; + } + + // Apply saturation and value to R,G,B + uint32_t v1 = 1 + val; // 1 to 256; allows >>8 instead of /255 + uint16_t s1 = 1 + sat; // 1 to 256; same reason + uint8_t s2 = 255 - sat; // 255 to 0 + + r2 = ((((r * s1) >> 8) + s2) * v1) >> 8; + g2 = ((((g * s1) >> 8) + s2) * v1) >> 8; + b2 = ((((b * s1) >> 8) + s2) * v1) >> 8; + return Color(r2, g2, b2); +} + // Pass-through is a kludge that lets you override the current drawing // color with a 'raw' RGB (or RGBW) value that's issued directly to // pixel(s), side-stepping the 16-bit color limitation of Adafruit_GFX. diff --git a/Adafruit_NeoMatrix.h b/Adafruit_NeoMatrix.h index 8d413dc..21d82b6 100644 --- a/Adafruit_NeoMatrix.h +++ b/Adafruit_NeoMatrix.h @@ -87,6 +87,8 @@ class Adafruit_NeoMatrix : public Adafruit_GFX, public Adafruit_NeoPixel { static uint16_t Color(uint8_t r, uint8_t g, uint8_t b); + static uint16_t + ColorHSV(uint16_t hue, uint8_t sat=255, uint8_t val=255); private: