Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Garcia <danielgarcia@gmail.com>2015-01-05 09:49:26 +0300
committerDaniel Garcia <danielgarcia@gmail.com>2015-01-05 09:49:26 +0300
commite9eb8f627f3fb12190074173bae3750a961e69d3 (patch)
tree826532787a9b927c9f4264b956c3254f4f9dc7cf
parent781f2ba320b09cbc32b3ec19de7f4d7181561e78 (diff)
parented027b5c61cc2de15b7c0f010d279665a3c8c5d4 (diff)
Merge branch 'FastLED3.1' of https://github.com/FastLED/FastLED into FastLED3.1
-rw-r--r--hsv2rgb.cpp132
-rw-r--r--hsv2rgb.h38
-rw-r--r--lib8tion.h52
3 files changed, 222 insertions, 0 deletions
diff --git a/hsv2rgb.cpp b/hsv2rgb.cpp
index 8a6d0575..ab037e82 100644
--- a/hsv2rgb.cpp
+++ b/hsv2rgb.cpp
@@ -474,3 +474,135 @@ void hsv2rgb_spectrum( const struct CHSV* phsv, struct CRGB * prgb, int numLeds)
hsv2rgb_spectrum(phsv[i], prgb[i]);
}
}
+
+
+
+#define FIXFRAC8(N,D) (((N)*256)/(D))
+
+// This function is only an approximation, and it is not
+// nearly as fast as the normal HSV-to-RGB conversion.
+// See extended notes in the .h file.
+CHSV rgb2hsv_approximate( const CRGB& rgb)
+{
+ byte r = rgb.r;
+ byte g = rgb.g;
+ byte b = rgb.b;
+ byte h, s, v;
+
+ // find desaturation
+ byte desat = 255;
+ if( r < desat) desat = r;
+ if( g < desat) desat = g;
+ if( b < desat) desat = b;
+
+ // remove saturation from all channels
+ r -= desat;
+ g -= desat;
+ b -= desat;
+
+ // at least one channel is now zero
+
+ // if all three channels are zero, we had a
+ // shade of gray.
+
+ uint16_t total = r + g + b;
+
+ if( total == 0) {
+ // we pick hue zero for no special reason
+ h = 0;
+ return CHSV( h, s, v);
+ }
+
+ // since this wasn't a pure shade of gray,
+ // the interesting question is what hue is it
+
+ // scale all channels up to a total of 255
+ if( total != 255) {
+ uint32_t scaleup = 65535 / (total);
+ r = ((uint32_t)(r) * scaleup) / 256;
+ g = ((uint32_t)(g) * scaleup) / 256;
+ b = ((uint32_t)(b) * scaleup) / 256;
+ }
+
+ if( total > 255 ) {
+ v = 255;
+ } else {
+ v = qadd8(desat,total);
+ // undo 'dimming' of brightness
+ if( v != 255) v = sqrt16( v * 256);
+ // without lib8tion: float ... ew ... sqrt... double ew, or rather, ew ^ 0.5
+ // if( v != 255) v = (256.0 * sqrt( (float)(v) / 256.0));
+
+ }
+
+ // saturation is opposite of desaturation
+ s = 255 - desat;
+ if( v != 255) s = (s * 256) / v;
+
+ // undo 'dimming' of saturation
+ if( s != 255 ) s = 255 - sqrt16( (255-s) * 256);
+ // without lib8tion: float ... ew ... sqrt... double ew, or rather, ew ^ 0.5
+ // if( s != 255 ) s = (255 - (256.0 * sqrt( (float)(255-s) / 256.0)));
+
+ // start with which channel is highest
+ // (ties don't matter)
+ byte highest = r;
+ if( g > highest) highest = g;
+ if( b > highest) highest = b;
+
+ if( highest == r ) {
+ // Red is highest.
+ // Hue could be Purple/Pink-Red,Red-Orange,Orange-Yellow
+ if( g == 0 ) {
+ // if green is zero, we're in Purple/Pink-Red
+ h = (HUE_PURPLE + HUE_PINK) / 2;
+ h += scale8( r - 128, FIXFRAC8(48,128));
+ } else if ( (r - g) > g) {
+ // if R-G > G then we're in Red-Orange
+ h = HUE_RED;
+ h += scale8( g, FIXFRAC8(32,85));
+ } else {
+ // R-G < G, we're in Orange-Yellow
+ h = HUE_ORANGE;
+ h += scale8( qsub8((g - 85) + (171 - r), 4), FIXFRAC8(32,85)); //221
+ }
+
+ } else if ( highest == g) {
+ // Green is highest
+ // Hue could be Yellow-Green, Green-Aqua
+ if( b == 0) {
+ // if Blue is zero, we're in Yellow-Green
+ h = HUE_YELLOW;
+ h += scale8( qadd8( qadd8((g - 128), (128 - r)), 4), FIXFRAC8(32,255)); //
+ } else {
+ // if Blue is nonzero we're in Green-Aqua
+ if( (g-b) > b) {
+ h = HUE_GREEN;
+ h += scale8( b, FIXFRAC8(32,85));
+ } else {
+ h = HUE_AQUA;
+ h += scale8( b - 85, FIXFRAC8(8,42));
+ }
+ }
+
+ } else /* highest == b */ {
+ // Blue is highest
+ // Hue could be Aqua/Blue-Blue, Blue-Purple, Purple-Pink
+ if( r == 0) {
+ // if red is zero, we're in Aqua/Blue-Blue
+ h = HUE_AQUA + ((HUE_BLUE - HUE_AQUA) / 4);
+ h += scale8( b - 128, FIXFRAC8(24,128));
+ } else if ( (b-r) > r) {
+ // B-R > R, we're in Blue-Purple
+ h = HUE_BLUE;
+ h += scale8( r, FIXFRAC8(32,85));
+ } else {
+ // B-R < R, we're in Purple-Pink
+ h = HUE_PURPLE;
+ h += scale8( r - 85, FIXFRAC8(32,85));
+ }
+ }
+
+ h += 1;
+ return CHSV( h, s, v);
+}
diff --git a/hsv2rgb.h b/hsv2rgb.h
index 959c754a..06857285 100644
--- a/hsv2rgb.h
+++ b/hsv2rgb.h
@@ -45,4 +45,42 @@ void hsv2rgb_raw(const struct CHSV& hsv, struct CRGB & rgb);
void hsv2rgb_raw(const struct CHSV* phsv, struct CRGB * prgb, int numLeds);
#define HUE_MAX 191
+
+// rgb2hsv_approximate - recover _approximate_ HSV values from RGB.
+//
+// NOTE 1: This function is a long-term work in process; expect
+// results to change slightly over time as this function is
+// refined and improved.
+//
+// NOTE 2: This function is most accurate when the input is an
+// RGB color that came from a fully-saturated HSV color to start
+// with. E.g. CHSV( hue, 255, 255) -> CRGB -> CHSV will give
+// best results.
+//
+// NOTE 3: This function is not nearly as fast as HSV-to-RGB.
+// It is provided for those situations when the need for this
+// function cannot be avoided, or when extremely high performance
+// is not needed.
+//
+// NOTE 4: Why is this 'only' an "approximation"?
+// Not all RGB colors have HSV equivalents! For example, there
+// is no HSV value that will ever convert to RGB(255,255,0) using
+// the code provided in this library. So if you try to
+// convert RGB(255,255,0) 'back' to HSV, you'll necessarily get
+// only an approximation. Emphasis has been placed on getting
+// the 'hue' as close as usefully possible, but even that's a bit
+// of a challenge. The 8-bit HSV and 8-bit RGB color spaces
+// are not a "bijection".
+//
+// Nevertheless, this function does a pretty good job, particularly
+// at recovering the 'hue' from fully saturated RGB colors that
+// originally came from HSV rainbow colors. So if you start
+// with CHSV(hue_in,255,255), and convert that to RGB, and then
+// convert it back to HSV using this function, the resulting output
+// hue will either exactly the same, or very close (+/-1).
+// The more desaturated the original RGB color is, the rougher the
+// approximation, and the less accurate the results.
+//
+CHSV rgb2hsv_approximate( const CRGB& rgb);
+
#endif
diff --git a/lib8tion.h b/lib8tion.h
index b6e03ed6..a32e6b49 100644
--- a/lib8tion.h
+++ b/lib8tion.h
@@ -524,6 +524,58 @@ LIB8STATIC int8_t avg7( int8_t i, int8_t j)
#endif
}
+// mod8: Calculate the remainder of one unsigned 8-bit
+// value divided by anoter, aka A % M.
+// Implemented by repeated subtraction, which is
+// very compact, and very fast if A is 'probably'
+// less than M. If A is a large multiple of M,
+// the loop has to execute multiple times. However,
+// even in that case, the loop is only two
+// instructions long on AVR, i.e., quick.
+LIB8STATIC uint8_t mod8( uint8_t a, uint8_t m)
+{
+#if defined(__AVR__)
+ asm volatile (
+ "L_%=: sub %[a],%[m] \n\t"
+ " brcc L_%= \n\t"
+ " add %[a],%[m] \n\t"
+ : [a] "+r" (a)
+ : [m] "r" (m)
+ );
+#else
+ while( a >= m) a -= m;
+#endif
+ return a;
+}
+
+// addmod8: Add two numbers, and calculate the modulo
+// of the sum and a third number, M.
+// In other words, it returns (A+B) % M.
+// It is designed as a compact mechanism for
+// incrementing a 'mode' switch and wrapping
+// around back to 'mode 0' when the switch
+// goes past the end of the available range.
+// e.g. if you have seven modes, this switches
+// to the next one and wraps around if needed:
+// mode = addmod8( mode, 1, 7);
+// See 'mod8' for notes on performance.
+LIB8STATIC uint8_t addmod8( uint8_t a, uint8_t b, uint8_t m)
+{
+#if defined(__AVR__)
+ asm volatile (
+ " add %[a],%[b] \n\t"
+ "L_%=: sub %[a],%[m] \n\t"
+ " brcc L_%= \n\t"
+ " add %[a],%[m] \n\t"
+ : [a] "+r" (a)
+ : [b] "r" (b), [m] "r" (m)
+ );
+#else
+ a += b;
+ while( a >= m) a -= m;
+#endif
+ return a;
+}
// scale8: scale one byte by a second one, which is treated as