| 
									
										
										
										
											2020-03-25 08:00:55 +00:00
										 |  |  | #include "wled.h"
 | 
					
						
							| 
									
										
										
										
											2018-11-01 14:36:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-31 00:38:08 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2022-07-06 11:13:54 +00:00
										 |  |  |  * Color conversion & utility methods | 
					
						
							| 
									
										
										
										
											2020-03-31 00:38:08 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-06 11:13:54 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * color blend function | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2022-08-03 19:36:47 +00:00
										 |  |  | uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) { | 
					
						
							| 
									
										
										
										
											2022-07-06 11:13:54 +00:00
										 |  |  |   if(blend == 0)   return color1; | 
					
						
							|  |  |  |   uint16_t blendmax = b16 ? 0xFFFF : 0xFF; | 
					
						
							|  |  |  |   if(blend == blendmax) return color2; | 
					
						
							|  |  |  |   uint8_t shift = b16 ? 16 : 8; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint32_t w1 = W(color1); | 
					
						
							|  |  |  |   uint32_t r1 = R(color1); | 
					
						
							|  |  |  |   uint32_t g1 = G(color1); | 
					
						
							|  |  |  |   uint32_t b1 = B(color1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint32_t w2 = W(color2); | 
					
						
							|  |  |  |   uint32_t r2 = R(color2); | 
					
						
							|  |  |  |   uint32_t g2 = G(color2); | 
					
						
							|  |  |  |   uint32_t b2 = B(color2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift; | 
					
						
							|  |  |  |   uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift; | 
					
						
							|  |  |  |   uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift; | 
					
						
							|  |  |  |   uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return RGBW32(r3, g3, b3, w3); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * color add function that preserves ratio | 
					
						
							|  |  |  |  * idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | uint32_t color_add(uint32_t c1, uint32_t c2) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   uint32_t r = R(c1) + R(c2); | 
					
						
							|  |  |  |   uint32_t g = G(c1) + G(c2); | 
					
						
							|  |  |  |   uint32_t b = B(c1) + B(c2); | 
					
						
							|  |  |  |   uint32_t w = W(c1) + W(c2); | 
					
						
							|  |  |  |   uint16_t max = r; | 
					
						
							|  |  |  |   if (g > max) max = g; | 
					
						
							|  |  |  |   if (b > max) max = b; | 
					
						
							|  |  |  |   if (w > max) max = w; | 
					
						
							|  |  |  |   if (max < 256) return RGBW32(r, g, b, w); | 
					
						
							|  |  |  |   else           return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-20 21:24:11 +00:00
										 |  |  | void setRandomColor(byte* rgb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-07-10 20:23:25 +00:00
										 |  |  |   lastRandomIndex = strip.getMainSegment().get_random_wheel_index(lastRandomIndex); | 
					
						
							| 
									
										
										
										
											2022-02-20 21:24:11 +00:00
										 |  |  |   colorHStoRGB(lastRandomIndex*256,255,rgb); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-01 14:36:13 +00:00
										 |  |  | void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   float h = ((float)hue)/65535.0; | 
					
						
							|  |  |  |   float s = ((float)sat)/255.0; | 
					
						
							|  |  |  |   byte i = floor(h*6); | 
					
						
							|  |  |  |   float f = h * 6-i; | 
					
						
							|  |  |  |   float p = 255 * (1-s); | 
					
						
							|  |  |  |   float q = 255 * (1-f*s); | 
					
						
							|  |  |  |   float t = 255 * (1-(1-f)*s); | 
					
						
							|  |  |  |   switch (i%6) { | 
					
						
							|  |  |  |     case 0: rgb[0]=255,rgb[1]=t,rgb[2]=p;break; | 
					
						
							|  |  |  |     case 1: rgb[0]=q,rgb[1]=255,rgb[2]=p;break; | 
					
						
							|  |  |  |     case 2: rgb[0]=p,rgb[1]=255,rgb[2]=t;break; | 
					
						
							|  |  |  |     case 3: rgb[0]=p,rgb[1]=q,rgb[2]=255;break; | 
					
						
							|  |  |  |     case 4: rgb[0]=t,rgb[1]=p,rgb[2]=255;break; | 
					
						
							|  |  |  |     case 5: rgb[0]=255,rgb[1]=p,rgb[2]=q; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-16 13:13:30 +00:00
										 |  |  | //get RGB values from color temperature in K (https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html)
 | 
					
						
							| 
									
										
										
										
											2020-09-27 09:43:28 +00:00
										 |  |  | void colorKtoRGB(uint16_t kelvin, byte* rgb) //white spectrum to rgb, calc
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   float r = 0, g = 0, b = 0; | 
					
						
							|  |  |  |   float temp = kelvin / 100; | 
					
						
							|  |  |  |   if (temp <= 66) { | 
					
						
							|  |  |  |     r = 255; | 
					
						
							|  |  |  |     g = round(99.4708025861 * log(temp) - 161.1195681661); | 
					
						
							|  |  |  |     if (temp <= 19) { | 
					
						
							|  |  |  |       b = 0; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       b = round(138.5177312231 * log((temp - 10)) - 305.0447927307); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     r = round(329.698727446 * pow((temp - 60), -0.1332047592)); | 
					
						
							|  |  |  |     g = round(288.1221695283 * pow((temp - 60), -0.0755148492)); | 
					
						
							|  |  |  |     b = 255; | 
					
						
							|  |  |  |   }  | 
					
						
							| 
									
										
										
										
											2021-11-21 22:46:44 +00:00
										 |  |  |   //g += 12; //mod by Aircoookie, a bit less accurate but visibly less pinkish
 | 
					
						
							| 
									
										
										
										
											2020-09-27 09:43:28 +00:00
										 |  |  |   rgb[0] = (uint8_t) constrain(r, 0, 255); | 
					
						
							|  |  |  |   rgb[1] = (uint8_t) constrain(g, 0, 255); | 
					
						
							|  |  |  |   rgb[2] = (uint8_t) constrain(b, 0, 255); | 
					
						
							|  |  |  |   rgb[3] = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb, bins
 | 
					
						
							| 
									
										
										
										
											2018-01-14 23:20:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |   //this is only an approximation using WS2812B with gamma correction enabled
 | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |   if (mired > 475) { | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |     rgb[0]=255;rgb[1]=199;rgb[2]=92;//500
 | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |   } else if (mired > 425) { | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |     rgb[0]=255;rgb[1]=213;rgb[2]=118;//450
 | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |   } else if (mired > 375) { | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |     rgb[0]=255;rgb[1]=216;rgb[2]=118;//400
 | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |   } else if (mired > 325) { | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |     rgb[0]=255;rgb[1]=234;rgb[2]=140;//350
 | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |   } else if (mired > 275) { | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |     rgb[0]=255;rgb[1]=243;rgb[2]=160;//300
 | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |   } else if (mired > 225) { | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |     rgb[0]=250;rgb[1]=255;rgb[2]=188;//250
 | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |   } else if (mired > 175) { | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |     rgb[0]=247;rgb[1]=255;rgb[2]=215;//200
 | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |     rgb[0]=237;rgb[1]=255;rgb[2]=239;//150
 | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-01-14 23:20:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-24 23:59:48 +00:00
										 |  |  | #ifndef WLED_DISABLE_HUESYNC
 | 
					
						
							| 
									
										
										
										
											2018-03-14 12:16:28 +00:00
										 |  |  | void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
 | 
					
						
							| 
									
										
										
										
											2018-01-14 23:20:23 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   float z = 1.0f - x - y; | 
					
						
							|  |  |  |   float X = (1.0f / y) * x; | 
					
						
							|  |  |  |   float Z = (1.0f / y) * z; | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |   float r = (int)255*(X * 1.656492f - 0.354851f - Z * 0.255038f); | 
					
						
							|  |  |  |   float g = (int)255*(-X * 0.707196f + 1.655397f + Z * 0.036152f); | 
					
						
							|  |  |  |   float b = (int)255*(X * 0.051713f - 0.121364f + Z * 1.011530f); | 
					
						
							|  |  |  |   if (r > b && r > g && r > 1.0f) { | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |     // red is too big
 | 
					
						
							|  |  |  |     g = g / r; | 
					
						
							|  |  |  |     b = b / r; | 
					
						
							|  |  |  |     r = 1.0f; | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |   } else if (g > b && g > r && g > 1.0f) { | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |     // green is too big
 | 
					
						
							|  |  |  |     r = r / g; | 
					
						
							|  |  |  |     b = b / g; | 
					
						
							|  |  |  |     g = 1.0f; | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |   } else if (b > r && b > g && b > 1.0f) { | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |     // blue is too big
 | 
					
						
							|  |  |  |     r = r / b; | 
					
						
							|  |  |  |     g = g / b; | 
					
						
							|  |  |  |     b = 1.0f; | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |   } | 
					
						
							|  |  |  |   // Apply gamma correction
 | 
					
						
							|  |  |  |   r = r <= 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * pow(r, (1.0f / 2.4f)) - 0.055f; | 
					
						
							|  |  |  |   g = g <= 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * pow(g, (1.0f / 2.4f)) - 0.055f; | 
					
						
							|  |  |  |   b = b <= 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * pow(b, (1.0f / 2.4f)) - 0.055f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (r > b && r > g) { | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |     // red is biggest
 | 
					
						
							|  |  |  |     if (r > 1.0f) { | 
					
						
							|  |  |  |       g = g / r; | 
					
						
							|  |  |  |       b = b / r; | 
					
						
							|  |  |  |       r = 1.0f; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-03-06 22:47:08 +00:00
										 |  |  |   } else if (g > b && g > r) { | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |     // green is biggest
 | 
					
						
							|  |  |  |     if (g > 1.0f) { | 
					
						
							|  |  |  |       r = r / g; | 
					
						
							|  |  |  |       b = b / g; | 
					
						
							|  |  |  |       g = 1.0f; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-03-06 22:47:08 +00:00
										 |  |  |   } else if (b > r && b > g) { | 
					
						
							| 
									
										
										
										
											2018-11-09 16:00:36 +00:00
										 |  |  |     // blue is biggest
 | 
					
						
							|  |  |  |     if (b > 1.0f) { | 
					
						
							|  |  |  |       r = r / b; | 
					
						
							|  |  |  |       g = g / b; | 
					
						
							|  |  |  |       b = 1.0f; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-02-27 23:27:10 +00:00
										 |  |  |   } | 
					
						
							|  |  |  |   rgb[0] = 255.0*r; | 
					
						
							|  |  |  |   rgb[1] = 255.0*g; | 
					
						
							|  |  |  |   rgb[2] = 255.0*b; | 
					
						
							| 
									
										
										
										
											2018-01-14 23:20:23 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-01 14:36:13 +00:00
										 |  |  | void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   float X = rgb[0] * 0.664511f + rgb[1] * 0.154324f + rgb[2] * 0.162028f; | 
					
						
							|  |  |  |   float Y = rgb[0] * 0.283881f + rgb[1] * 0.668433f + rgb[2] * 0.047685f; | 
					
						
							|  |  |  |   float Z = rgb[0] * 0.000088f + rgb[1] * 0.072310f + rgb[2] * 0.986039f; | 
					
						
							|  |  |  |   xy[0] = X / (X + Y + Z); | 
					
						
							|  |  |  |   xy[1] = Y / (X + Y + Z); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-25 08:00:55 +00:00
										 |  |  | #endif // WLED_DISABLE_HUESYNC
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 23:33:17 +00:00
										 |  |  | //RRGGBB / WWRRGGBB order for hex
 | 
					
						
							| 
									
										
										
										
											2019-02-05 20:53:39 +00:00
										 |  |  | void colorFromDecOrHexString(byte* rgb, char* in) | 
					
						
							| 
									
										
										
										
											2018-09-28 21:53:51 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   if (in[0] == 0) return; | 
					
						
							|  |  |  |   char first = in[0]; | 
					
						
							|  |  |  |   uint32_t c = 0; | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   if (first == '#' || first == 'h' || first == 'H') //is HEX encoded
 | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     c = strtoul(in +1, NULL, 16); | 
					
						
							|  |  |  |   } else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     c = strtoul(in, NULL, 10); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-26 18:35:45 +00:00
										 |  |  |   rgb[0] = R(c); | 
					
						
							|  |  |  |   rgb[1] = G(c); | 
					
						
							|  |  |  |   rgb[2] = B(c); | 
					
						
							|  |  |  |   rgb[3] = W(c); | 
					
						
							| 
									
										
										
										
											2018-09-28 21:53:51 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 23:33:17 +00:00
										 |  |  | //contrary to the colorFromDecOrHexString() function, this uses the more standard RRGGBB / RRGGBBWW order
 | 
					
						
							|  |  |  | bool colorFromHexString(byte* rgb, const char* in) { | 
					
						
							|  |  |  |   if (in == nullptr) return false; | 
					
						
							|  |  |  |   size_t inputSize = strnlen(in, 9); | 
					
						
							|  |  |  |   if (inputSize != 6 && inputSize != 8) return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uint32_t c = strtoul(in, NULL, 16); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (inputSize == 6) { | 
					
						
							| 
									
										
										
										
											2021-10-26 18:35:45 +00:00
										 |  |  |     rgb[0] = (c >> 16); | 
					
						
							|  |  |  |     rgb[1] = (c >>  8); | 
					
						
							|  |  |  |     rgb[2] =  c       ; | 
					
						
							| 
									
										
										
										
											2020-11-19 23:33:17 +00:00
										 |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2021-10-26 18:35:45 +00:00
										 |  |  |     rgb[0] = (c >> 24); | 
					
						
							|  |  |  |     rgb[1] = (c >> 16); | 
					
						
							|  |  |  |     rgb[2] = (c >>  8); | 
					
						
							|  |  |  |     rgb[3] =  c       ; | 
					
						
							| 
									
										
										
										
											2020-11-19 23:33:17 +00:00
										 |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-06 22:47:08 +00:00
										 |  |  | float minf (float v, float w) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (w > v) return v; | 
					
						
							|  |  |  |   return w; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float maxf (float v, float w) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (w > v) return w; | 
					
						
							|  |  |  |   return v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-26 18:35:45 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2021-10-24 19:07:05 +00:00
										 |  |  | uint32_t colorRGBtoRGBW(uint32_t c) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   byte rgb[4]; | 
					
						
							| 
									
										
										
										
											2021-10-26 18:35:45 +00:00
										 |  |  |   rgb[0] = R(c); | 
					
						
							|  |  |  |   rgb[1] = G(c); | 
					
						
							|  |  |  |   rgb[2] = B(c); | 
					
						
							|  |  |  |   rgb[3] = W(c); | 
					
						
							| 
									
										
										
										
											2021-10-24 19:07:05 +00:00
										 |  |  |   colorRGBtoRGBW(rgb); | 
					
						
							| 
									
										
										
										
											2021-10-26 18:35:45 +00:00
										 |  |  |   return RGBW32(rgb[0], rgb[1], rgb[2], rgb[3]); | 
					
						
							| 
									
										
										
										
											2021-10-24 19:07:05 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-19 23:45:09 +00:00
										 |  |  | void colorRGBtoRGBW(byte* rgb) //rgb to rgbw (http://codewelt.com/rgbw). (RGBW_MODE_LEGACY)
 | 
					
						
							| 
									
										
										
										
											2018-03-06 22:47:08 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-05-31 17:26:16 +00:00
										 |  |  |   float low = minf(rgb[0],minf(rgb[1],rgb[2])); | 
					
						
							|  |  |  |   float high = maxf(rgb[0],maxf(rgb[1],rgb[2])); | 
					
						
							|  |  |  |   if (high < 0.1f) return; | 
					
						
							| 
									
										
										
										
											2021-12-04 00:05:01 +00:00
										 |  |  |   float sat = 100.0f * ((high - low) / high);   // maximum saturation is 100  (corrected from 255)
 | 
					
						
							| 
									
										
										
										
											2019-02-05 20:53:39 +00:00
										 |  |  |   rgb[3] = (byte)((255.0f - sat) / 255.0f * (rgb[0] + rgb[1] + rgb[2]) / 3); | 
					
						
							| 
									
										
										
										
											2018-05-31 17:26:16 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-10-26 18:35:45 +00:00
										 |  |  | */ | 
					
						
							| 
									
										
										
										
											2021-10-16 13:13:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-21 22:46:44 +00:00
										 |  |  | byte correctionRGB[4] = {0,0,0,0}; | 
					
						
							|  |  |  | uint16_t lastKelvin = 0; | 
					
						
							| 
									
										
										
										
											2021-10-16 13:13:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-24 10:02:25 +00:00
										 |  |  | // adjust RGB values based on color temperature in K (range [2800-10200]) (https://en.wikipedia.org/wiki/Color_balance)
 | 
					
						
							| 
									
										
										
										
											2021-10-16 13:13:30 +00:00
										 |  |  | uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-11-21 22:46:44 +00:00
										 |  |  |   //remember so that slow colorKtoRGB() doesn't have to run for every setPixelColor()
 | 
					
						
							|  |  |  |   if (lastKelvin != kelvin) colorKtoRGB(kelvin, correctionRGB);  // convert Kelvin to RGB
 | 
					
						
							|  |  |  |   lastKelvin = kelvin; | 
					
						
							|  |  |  |   byte rgbw[4]; | 
					
						
							|  |  |  |   rgbw[0] = ((uint16_t) correctionRGB[0] * R(rgb)) /255; // correct R
 | 
					
						
							|  |  |  |   rgbw[1] = ((uint16_t) correctionRGB[1] * G(rgb)) /255; // correct G
 | 
					
						
							|  |  |  |   rgbw[2] = ((uint16_t) correctionRGB[2] * B(rgb)) /255; // correct B
 | 
					
						
							| 
									
										
										
										
											2021-11-24 10:02:25 +00:00
										 |  |  |   rgbw[3] =                                W(rgb); | 
					
						
							| 
									
										
										
										
											2022-01-14 13:27:11 +00:00
										 |  |  |   return RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]); | 
					
						
							| 
									
										
										
										
											2021-10-16 13:13:30 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-11-24 10:02:25 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | //approximates a Kelvin color temperature from an RGB color.
 | 
					
						
							|  |  |  | //this does no check for the "whiteness" of the color,
 | 
					
						
							|  |  |  | //so should be used combined with a saturation check (as done by auto-white)
 | 
					
						
							|  |  |  | //values from http://www.vendian.org/mncharity/dir3/blackbody/UnstableURLs/bbr_color.html (10deg)
 | 
					
						
							|  |  |  | //equation spreadsheet at https://bit.ly/30RkHaN
 | 
					
						
							|  |  |  | //accuracy +-50K from 1900K up to 8000K
 | 
					
						
							|  |  |  | //minimum returned: 1900K, maximum returned: 10091K (range of 8192)
 | 
					
						
							|  |  |  | uint16_t approximateKelvinFromRGB(uint32_t rgb) { | 
					
						
							|  |  |  |   //if not either red or blue is 255, color is dimmed. Scale up
 | 
					
						
							|  |  |  |   uint8_t r = R(rgb), b = B(rgb); | 
					
						
							|  |  |  |   if (r == b) return 6550; //red == blue at about 6600K (also can't go further if both R and B are 0)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (r > b) { | 
					
						
							|  |  |  |     //scale blue up as if red was at 255
 | 
					
						
							|  |  |  |     uint16_t scale = 0xFFFF / r; //get scale factor (range 257-65535)
 | 
					
						
							|  |  |  |     b = ((uint16_t)b * scale) >> 8; | 
					
						
							|  |  |  |     //For all temps K<6600 R is bigger than B (for full bri colors R=255)
 | 
					
						
							|  |  |  |     //-> Use 9 linear approximations for blackbody radiation blue values from 2000-6600K (blue is always 0 below 2000K)
 | 
					
						
							|  |  |  |     if (b < 33)  return 1900 + b       *6; | 
					
						
							|  |  |  |     if (b < 72)  return 2100 + (b-33)  *10; | 
					
						
							|  |  |  |     if (b < 101) return 2492 + (b-72)  *14; | 
					
						
							|  |  |  |     if (b < 132) return 2900 + (b-101) *16; | 
					
						
							|  |  |  |     if (b < 159) return 3398 + (b-132) *19; | 
					
						
							|  |  |  |     if (b < 186) return 3906 + (b-159) *22; | 
					
						
							|  |  |  |     if (b < 210) return 4500 + (b-186) *25; | 
					
						
							|  |  |  |     if (b < 230) return 5100 + (b-210) *30; | 
					
						
							|  |  |  |                  return 5700 + (b-230) *34; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     //scale red up as if blue was at 255
 | 
					
						
							|  |  |  |     uint16_t scale = 0xFFFF / b; //get scale factor (range 257-65535)
 | 
					
						
							|  |  |  |     r = ((uint16_t)r * scale) >> 8; | 
					
						
							|  |  |  |     //For all temps K>6600 B is bigger than R (for full bri colors B=255)
 | 
					
						
							|  |  |  |     //-> Use 2 linear approximations for blackbody radiation red values from 6600-10091K (blue is always 0 below 2000K)
 | 
					
						
							|  |  |  |     if (r > 225) return 6600 + (254-r) *50; | 
					
						
							|  |  |  |     uint16_t k = 8080 + (225-r) *86; | 
					
						
							|  |  |  |     return (k > 10091) ? 10091 : k; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-12-01 13:51:45 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-30 21:58:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | //gamma 2.8 lookup table used for color correction
 | 
					
						
							|  |  |  | static byte gammaT[] = { | 
					
						
							|  |  |  |     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, | 
					
						
							|  |  |  |     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1, | 
					
						
							|  |  |  |     1,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2, | 
					
						
							|  |  |  |     2,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  5,  5,  5, | 
					
						
							|  |  |  |     5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9,  9,  9, 10, | 
					
						
							|  |  |  |    10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, | 
					
						
							|  |  |  |    17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, | 
					
						
							|  |  |  |    25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36, | 
					
						
							|  |  |  |    37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50, | 
					
						
							|  |  |  |    51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68, | 
					
						
							|  |  |  |    69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89, | 
					
						
							|  |  |  |    90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114, | 
					
						
							|  |  |  |   115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142, | 
					
						
							|  |  |  |   144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175, | 
					
						
							|  |  |  |   177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213, | 
					
						
							|  |  |  |   215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint8_t gamma8_cal(uint8_t b, float gamma) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return (int)(powf((float)b / 255.0f, gamma) * 255.0f + 0.5f); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void calcGammaTable(float gamma) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   for (uint16_t i = 0; i < 256; i++) { | 
					
						
							|  |  |  |     gammaT[i] = gamma8_cal(i, gamma); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint8_t gamma8(uint8_t b) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return gammaT[b]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint32_t gamma32(uint32_t color) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-07-31 17:52:07 +00:00
										 |  |  |   //if (!strip.gammaCorrectCol) return color;
 | 
					
						
							| 
									
										
										
										
											2022-07-30 21:58:29 +00:00
										 |  |  |   uint8_t w = W(color); | 
					
						
							|  |  |  |   uint8_t r = R(color); | 
					
						
							|  |  |  |   uint8_t g = G(color); | 
					
						
							|  |  |  |   uint8_t b = B(color); | 
					
						
							|  |  |  |   w = gammaT[w]; | 
					
						
							|  |  |  |   r = gammaT[r]; | 
					
						
							|  |  |  |   g = gammaT[g]; | 
					
						
							|  |  |  |   b = gammaT[b]; | 
					
						
							|  |  |  |   return RGBW32(r, g, b, w); | 
					
						
							|  |  |  | } |