diff --git a/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.cpp b/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.cpp index 43ac2bf1bc..0555f0fe75 100644 --- a/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.cpp +++ b/usermods/usermod_rotary_brightness_color/usermod_rotary_brightness_color.cpp @@ -93,9 +93,7 @@ class RotaryEncoderBrightnessColor : public Usermod } else { - fastled_col.red = colPri[0]; - fastled_col.green = colPri[1]; - fastled_col.blue = colPri[2]; + fastled_col = colPri; prim_hsv = rgb2hsv(fastled_col); new_val = (int16_t)prim_hsv.h + fadeAmount; if (new_val > 255) @@ -104,9 +102,7 @@ class RotaryEncoderBrightnessColor : public Usermod new_val += 255; // roll-over if smaller than 0 prim_hsv.h = (byte)new_val; fastled_col = prim_hsv ; - colPri[0] = fastled_col.red; - colPri[1] = fastled_col.green; - colPri[2] = fastled_col.blue; + colPri = fastled_col; } } else if (Enc_B == LOW) @@ -118,9 +114,7 @@ class RotaryEncoderBrightnessColor : public Usermod } else { - fastled_col.red = colPri[0]; - fastled_col.green = colPri[1]; - fastled_col.blue = colPri[2]; + fastled_col = colPri; prim_hsv = rgb2hsv(fastled_col); new_val = (int16_t)prim_hsv.h - fadeAmount; if (new_val > 255) @@ -129,9 +123,7 @@ class RotaryEncoderBrightnessColor : public Usermod new_val += 255; // roll-over if smaller than 0 prim_hsv.h = (byte)new_val; fastled_col = prim_hsv; - colPri[0] = fastled_col.red; - colPri[1] = fastled_col.green; - colPri[2] = fastled_col.blue; + colPri = fastled_col; } } //call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification) diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.cpp b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.cpp index f7e908651b..17f6b5579a 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.cpp +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.cpp @@ -520,7 +520,7 @@ void RotaryEncoderUIUsermod::setup() loopTime = millis(); - currentCCT = (approximateKelvinFromRGB(RGBW32(colPri[0], colPri[1], colPri[2], colPri[3])) - 1900) >> 5; + currentCCT = (approximateKelvinFromRGB(colPri.color32) - 1900) >> 5; if (!initDone) sortModesAndPalettes(); @@ -928,11 +928,11 @@ void RotaryEncoderUIUsermod::changeHue(bool increase){ for (unsigned i=0; igetColorMode() == EspalexaColorMode::ct) //shade of white { - byte rgbw[4]; + CRGBW rgbw = 0; uint16_t ct = dev->getCt(); if (!ct) return; uint16_t k = 1000000 / ct; //mireds to kelvin @@ -109,24 +109,24 @@ void onAlexaChange(EspalexaDevice* dev) strip.setCCT(k); if (hasManualWhite) { - rgbw[0] = 0; rgbw[1] = 0; rgbw[2] = 0; rgbw[3] = 255; + rgbw.color32 = 0xFF000000; // color channels off } else { - rgbw[0] = 255; rgbw[1] = 255; rgbw[2] = 255; rgbw[3] = 0; + rgbw.color32 = 0x00FFFFFF; // white channel off dev->setValue(255); } } else if (strip.hasWhiteChannel()) { switch (ct) { //these values empirically look good on RGBW - case 199: rgbw[0]=255; rgbw[1]=255; rgbw[2]=255; rgbw[3]=255; break; - case 234: rgbw[0]=127; rgbw[1]=127; rgbw[2]=127; rgbw[3]=255; break; - case 284: rgbw[0]= 0; rgbw[1]= 0; rgbw[2]= 0; rgbw[3]=255; break; - case 350: rgbw[0]=130; rgbw[1]= 90; rgbw[2]= 0; rgbw[3]=255; break; - case 383: rgbw[0]=255; rgbw[1]=153; rgbw[2]= 0; rgbw[3]=255; break; + case 199: rgbw.color32 = 0xFFFFFFFF; break; // w=255 r=255 g=255 b=255 + case 234: rgbw.color32 = 0xFF7F7F7F; break; // w=255 r=127 g=127 b=127 + case 284: rgbw.color32 = 0xFF000000; break; // w=255 r=0 g=0 b=0 + case 350: rgbw.color32 = 0xFF825A00; break; // w=255 r=130 g=90 b=0 + case 383: rgbw.color32 = 0xFFFF9900; break; // w=255 r=255 g=153 b=0 default : colorKtoRGB(k, rgbw); } } else { colorKtoRGB(k, rgbw); } - strip.getMainSegment().setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); + strip.getMainSegment().setColor(0, rgbw.color32); } else { uint32_t color = dev->getRGB(); strip.getMainSegment().setColor(0, color); diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 6ddc4ec892..4b808ce3ae 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -15,7 +15,7 @@ /* * color blend function - * the calculation for each color is: result = (C1*(256-blend)+C2+C2*blend) / 256 + * the calculation for each color is: result = (C1*(256-blend)+C2*blend) / 256 */ uint32_t WLED_O2_ATTR IRAM_ATTR color_blend(uint32_t color1, uint32_t color2, uint8_t blend) { // min / max blend checking is omitted: calls with 0 or 255 are rare, checking lowers overall performance @@ -144,7 +144,7 @@ uint32_t ColorFromPalette(const CRGBPalette16& pal, unsigned index, uint8_t brig return RGBW32(red1,green1,blue1,0); } -void setRandomColor(byte* rgb) +void setRandomColor(CRGBW &rgb) { lastRandomIndex = get_random_wheel_index(lastRandomIndex); colorHStoRGB(lastRandomIndex*256,255,rgb); @@ -283,10 +283,10 @@ void loadCustomPalettes() { size_t palSize = MIN(pal.size(), 36); palSize -= palSize % 2; // make sure size is multiple of 2 for (size_t i=0, j=0; i()<256; i+=2) { - uint8_t rgbw[] = {0,0,0,0}; + CRGBW rgbw = 0; if (colorFromHexString(rgbw, pal[i+1].as())) { // will catch non-string entires tcp[ j ] = (uint8_t) pal[ i ].as(); // index - for (size_t c=0; c<3; c++) tcp[j+1+c] = rgbw[c]; // only use RGB component + for (size_t c=0; c<3; c++) tcp[j+1+c] = rgbw.raw[2-c]; // only use RGB component (raw is B,G,R,W i.e. [0] = blue DEBUGFX_PRINTF_P(PSTR("%2u -> %3d [%3d,%3d,%3d]\n"), i, int(tcp[j]), int(tcp[j+1]), int(tcp[j+2]), int(tcp[j+3])); j += 4; } @@ -321,7 +321,7 @@ size_t removeUsermodPalettes(const char *name) { return before - usermodPalettes.size(); } -// convert HSV (16bit hue) to RGB (32bit with white = 0), optimized for speed +// convert HSV (16bit hue) to RGB (32bit, white stays unmodified), optimized for speed WLED_O2_ATTR void hsv2rgb_spectrum(const CHSV32& hsv, CRGBW& rgb) { unsigned p, q, t; unsigned region = ((unsigned)hsv.h * 6) >> 16; // h / (65536 / 6) @@ -412,17 +412,15 @@ CHSV rgb2hsv(const CRGB c) { // CRGB to CHSV return CHSV(hsv); } -void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) { //hue, sat to rgb - CRGBW crgb; - hsv2rgb_spectrum(CHSV32(hue, sat, 255), crgb); - rgb[0] = crgb.r; - rgb[1] = crgb.g; - rgb[2] = crgb.b; +void colorHStoRGB(uint16_t hue, byte sat, CRGBW &rgb) { //hue, sat to rgb + rgb = 0; // init to black, white is unused so make sure it does not contain garbage + hsv2rgb_spectrum(CHSV32(hue, sat, 255), rgb); } //get RGB values from color temperature in K (https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html) -void colorKtoRGB(uint16_t kelvin, byte* rgb) //white spectrum to rgb, calc +void colorKtoRGB(uint16_t kelvin, CRGBW &rgb) //white spectrum to rgb, calc { + rgb = 0; // init to black, white is unused so make sure it does not contain garbage int r = 0, g = 0, b = 0; float temp = kelvin / 100.0f; if (temp <= 66.0f) { @@ -439,36 +437,36 @@ void colorKtoRGB(uint16_t kelvin, byte* rgb) //white spectrum to rgb, calc b = 255; } //g += 12; //mod by Aircoookie, a bit less accurate but visibly less pinkish - 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; + rgb.r = (uint8_t) constrain(r, 0, 255); + rgb.g = (uint8_t) constrain(g, 0, 255); + rgb.b = (uint8_t) constrain(b, 0, 255); } -void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb, bins +void colorCTtoRGB(uint16_t mired, CRGBW &rgb) //white spectrum to rgb, bins { + rgb = 0; // init to black, white is unused so make sure it does not contain garbage //this is only an approximation using WS2812B with gamma correction enabled if (mired > 475) { - rgb[0]=255;rgb[1]=199;rgb[2]=92;//500 + rgb.r=255;rgb.g=199;rgb.b=92;//500 } else if (mired > 425) { - rgb[0]=255;rgb[1]=213;rgb[2]=118;//450 + rgb.r=255;rgb.g=213;rgb.b=118;//450 } else if (mired > 375) { - rgb[0]=255;rgb[1]=216;rgb[2]=118;//400 + rgb.r=255;rgb.g=216;rgb.b=118;//400 } else if (mired > 325) { - rgb[0]=255;rgb[1]=234;rgb[2]=140;//350 + rgb.r=255;rgb.g=234;rgb.b=140;//350 } else if (mired > 275) { - rgb[0]=255;rgb[1]=243;rgb[2]=160;//300 + rgb.r=255;rgb.g=243;rgb.b=160;//300 } else if (mired > 225) { - rgb[0]=250;rgb[1]=255;rgb[2]=188;//250 + rgb.r=250;rgb.g=255;rgb.b=188;//250 } else if (mired > 175) { - rgb[0]=247;rgb[1]=255;rgb[2]=215;//200 + rgb.r=247;rgb.g=255;rgb.b=215;//200 } else { - rgb[0]=237;rgb[1]=255;rgb[2]=239;//150 + rgb.r=237;rgb.g=255;rgb.b=239;//150 } } #ifndef WLED_DISABLE_HUESYNC -void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy) +void colorXYtoRGB(float x, float y, CRGBW &rgb) //coordinates to rgb (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy) { float z = 1.0f - x - y; float X = (1.0f / y) * x; @@ -519,9 +517,10 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www b = 1.0f; } } - rgb[0] = byte(255.0f*r); - rgb[1] = byte(255.0f*g); - rgb[2] = byte(255.0f*b); + rgb = 0; // init to black, white is unused so make sure it does not contain garbage + rgb.r = byte(255.0f*r); + rgb.g = byte(255.0f*g); + rgb.b = byte(255.0f*b); } void colorRGBtoXY(const byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy) @@ -535,7 +534,7 @@ void colorRGBtoXY(const byte* rgb, float* xy) //rgb to coordinates (https://www. #endif // WLED_DISABLE_HUESYNC //RRGGBB / WWRRGGBB order for hex -void colorFromDecOrHexString(byte* rgb, const char* in) +void colorFromDecOrHexString(CRGBW &rgb, const char* in) { if (in[0] == 0) return; char first = in[0]; @@ -548,30 +547,27 @@ void colorFromDecOrHexString(byte* rgb, const char* in) { c = strtoul(in, NULL, 10); } - - rgb[0] = R(c); - rgb[1] = G(c); - rgb[2] = B(c); - rgb[3] = W(c); + rgb = c; } //contrary to the colorFromDecOrHexString() function, this uses the more standard RRGGBB / RRGGBBWW order -bool colorFromHexString(byte* rgb, const char* in) { +bool colorFromHexString(CRGBW &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); + rgb = 0; // init to black in case white is unused if (inputSize == 6) { - rgb[0] = (c >> 16); - rgb[1] = (c >> 8); - rgb[2] = c ; + rgb.r = (c >> 16); + rgb.g = (c >> 8); + rgb.b = c ; } else { - rgb[0] = (c >> 24); - rgb[1] = (c >> 16); - rgb[2] = (c >> 8); - rgb[3] = c ; + rgb.r = (c >> 24); + rgb.g = (c >> 16); + rgb.b = (c >> 8); + rgb.w = c ; } return true; } @@ -593,16 +589,15 @@ static inline float maxf(float v, float w) uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb) { //remember so that slow colorKtoRGB() doesn't have to run for every setPixelColor() - static byte correctionRGB[4] = {0,0,0,0}; + static CRGBW correctionRGB = 0; static uint16_t lastKelvin = 0; 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 - rgbw[3] = W(rgb); - return RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]); + CRGBW rgbw = rgb; // initializes white channel + rgbw.r = ((uint16_t) correctionRGB.r * R(rgb)) /255; // correct R + rgbw.g = ((uint16_t) correctionRGB.g * G(rgb)) /255; // correct G + rgbw.b = ((uint16_t) correctionRGB.b * B(rgb)) /255; // correct B + return rgbw.color32; } //approximates a Kelvin color temperature from an RGB color. diff --git a/wled00/colors.h b/wled00/colors.h index 00fe4fb498..a57938e3a8 100644 --- a/wled00/colors.h +++ b/wled00/colors.h @@ -80,16 +80,16 @@ void hsv2rgb_spectrum(const CHSV32& hsv, CRGBW& rgb); void hsv2rgb_spectrum(const CHSV& hsv, CRGB& rgb); void rgb2hsv(const CRGBW& rgb, CHSV32& hsv); CHSV rgb2hsv(const CRGB c); -void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); -void colorKtoRGB(uint16_t kelvin, byte* rgb); -void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb -void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO +void colorHStoRGB(uint16_t hue, byte sat, CRGBW &rgb); +void colorKtoRGB(uint16_t kelvin, CRGBW &rgb); +void colorCTtoRGB(uint16_t mired, CRGBW &rgb); //white spectrum to rgb +void colorXYtoRGB(float x, float y, CRGBW &rgb); // only defined if huesync disabled TODO void colorRGBtoXY(const byte* rgb, float* xy); // only defined if huesync disabled TODO -void colorFromDecOrHexString(byte* rgb, const char* in); -bool colorFromHexString(byte* rgb, const char* in); +void colorFromDecOrHexString(CRGBW &rgb, const char* in); +bool colorFromHexString(CRGBW &rgb, const char* in); uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); uint16_t approximateKelvinFromRGB(uint32_t rgb); -void setRandomColor(byte* rgb); +void setRandomColor(CRGBW &rgb); // fast scaling function for colors, performs color*scale/256 for all four channels, speed over accuracy // note: inlining uses less code than actual function calls @@ -177,9 +177,9 @@ struct CRGBW { inline CRGBW& operator=(CHSV32 hsv) __attribute__((always_inline)) { hsv2rgb_rainbow(hsv.h, hsv.s, hsv.v, raw, true); return *this; } // Assignment from CHSV - inline CRGBW& operator=(CHSV hsv) __attribute__((always_inline)) { hsv2rgb_rainbow(hsv.h<<8, hsv.s, hsv.v, raw, true); return *this; } + inline CRGBW& operator=(CHSV hsv) __attribute__((always_inline)) { hsv2rgb_rainbow(hsv.h<<8, hsv.s, hsv.v, raw, true); return *this; } - // Assignment from r, g, b, w + // Assignment from CRGB inline CRGBW& operator=(const CRGB& rgb) __attribute__((always_inline)) { b = rgb.b; g = rgb.g; r = rgb.r; w = 0; return *this; } // Conversion operator to uint32_t diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 6201a19192..cdf6cdf41f 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -199,7 +199,7 @@ byte scaledBri(byte in); #ifdef WLED_ENABLE_LOXONE //lx_parser.cpp -bool parseLx(int lxValue, byte* rgbw); +bool parseLx(int lxValue, CRGBW &rgbw); void parseLxJson(int lxValue, byte segId, bool secondary); #endif diff --git a/wled00/json.cpp b/wled00/json.cpp index a4f46bb5e7..a1abf8538a 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -214,20 +214,20 @@ static bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0) // string = hex representation of [WW]RRGGBB or "r" for random color // object = individual channel control {"r":0,"g":127,"b":255,"w":255}, each being optional (valid to send {}) // array = direct channel values [r,g,b,w] (w element being optional) - int rgbw[] = {0,0,0,0}; + CRGBW rgbw = 0; bool colValid = false; JsonArray colX = colarr[i]; if (colX.isNull()) { JsonObject oCol = colarr[i]; if (!oCol.isNull()) { // we have a JSON object for color {"w":123,"r":123,...}; allows individual channel control - rgbw[0] = oCol["r"] | R(seg.colors[i]); - rgbw[1] = oCol["g"] | G(seg.colors[i]); - rgbw[2] = oCol["b"] | B(seg.colors[i]); - rgbw[3] = oCol["w"] | W(seg.colors[i]); + rgbw.r = oCol["r"] | R(seg.colors[i]); + rgbw.g = oCol["g"] | G(seg.colors[i]); + rgbw.b = oCol["b"] | B(seg.colors[i]); + rgbw.w = oCol["w"] | W(seg.colors[i]); colValid = true; } else { - byte brgbw[] = {0,0,0,0}; + CRGBW brgbw = 0; const char* hexCol = colarr[i]; if (hexCol == nullptr) { //Kelvin color temperature (or invalid), e.g 2400 int kelvin = colarr[i] | -1; @@ -241,18 +241,21 @@ static bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0) } else { //HEX string, e.g. "FFAA00" colValid = colorFromHexString(brgbw, hexCol); } - for (size_t c = 0; c < 4; c++) rgbw[c] = brgbw[c]; + rgbw = brgbw; } } else { //Array of ints (RGB or RGBW color), e.g. [255,160,0] byte sz = colX.size(); if (sz == 0) continue; //do nothing on empty array - copyArray(colX, rgbw, 4); + rgbw.r = colX[0] | 0; + rgbw.g = colX[1] | 0; + rgbw.b = colX[2] | 0; + rgbw.w = colX[3] | 0; colValid = true; } if (!colValid) continue; - seg.setColor(i, RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3])); // use transition + seg.setColor(i, rgbw.color32); // use transition if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh } } else { @@ -338,22 +341,26 @@ static bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0) iSet++; } } else { //color - uint8_t rgbw[] = {0,0,0,0}; + CRGBW rgbw = 0; JsonArray icol = iarr[i]; if (!icol.isNull()) { //array, e.g. [255,0,0] byte sz = icol.size(); - if (sz > 0 && sz < 5) copyArray(icol, rgbw); + if (sz > 0 && sz < 5) { + rgbw.r = icol[0] | 0; + rgbw.g = icol[1] | 0; + rgbw.b = icol[2] | 0; + rgbw.w = icol[3] | 0; + } } else { //hex string, e.g. "FF0000" - byte brgbw[] = {0,0,0,0}; + CRGBW brgbw = 0; const char* hexCol = iarr[i]; if (colorFromHexString(brgbw, hexCol)) { - for (size_t c = 0; c < 4; c++) rgbw[c] = brgbw[c]; + rgbw = brgbw; } } if (iSet < 2 || iStop <= iStart) iStop = iStart + 1; - uint32_t c = RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]); - while (iStart < iStop) seg.setRawPixelColor(iStart++, c); // sets pixel color without 1D->2D expansion, grouping or spacing + while (iStart < iStop) seg.setRawPixelColor(iStart++, rgbw.color32); // sets pixel color without 1D->2D expansion, grouping or spacing iSet = 0; } } diff --git a/wled00/led.cpp b/wled00/led.cpp index 131ff95bab..c644c4e31d 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -7,14 +7,8 @@ // applies chosen setment properties to legacy values void setValuesFromSegment(uint8_t s) { const Segment& seg = strip.getSegment(s); - colPri[0] = R(seg.colors[0]); - colPri[1] = G(seg.colors[0]); - colPri[2] = B(seg.colors[0]); - colPri[3] = W(seg.colors[0]); - colSec[0] = R(seg.colors[1]); - colSec[1] = G(seg.colors[1]); - colSec[2] = B(seg.colors[1]); - colSec[3] = W(seg.colors[1]); + colPri = seg.colors[0]; + colSec = seg.colors[1]; effectCurrent = seg.mode; effectSpeed = seg.speed; effectIntensity = seg.intensity; @@ -31,8 +25,8 @@ void applyValuesToSelectedSegs() { if (effectIntensity != seg.intensity) {seg.intensity = effectIntensity; stateChanged = true;} if (effectPalette != seg.palette) {seg.setPalette(effectPalette);} if (effectCurrent != seg.mode) {seg.setMode(effectCurrent);} - uint32_t col0 = RGBW32(colPri[0], colPri[1], colPri[2], colPri[3]); - uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]); + uint32_t col0 = colPri; + uint32_t col1 = colSec; if (col0 != seg.colors[0]) {seg.setColor(0, col0);} if (col1 != seg.colors[1]) {seg.setColor(1, col1);} } @@ -150,7 +144,7 @@ void updateInterfaces(uint8_t callMode) { #ifndef WLED_DISABLE_ALEXA if (espalexaDevice != nullptr && callMode != CALL_MODE_ALEXA) { espalexaDevice->setValue(bri); - espalexaDevice->setColor(colPri[0], colPri[1], colPri[2]); + espalexaDevice->setColor(colPri.r, colPri.g, colPri.b); } #endif #ifndef WLED_DISABLE_MQTT @@ -204,13 +198,13 @@ void handleNightlight() { nightlightDelayMs = (unsigned)(nightlightDelayMins*60000); nightlightActiveOld = true; briNlT = bri; - for (unsigned i=0; i<4; i++) colNlT[i] = colPri[i]; // remember starting color + colNlT = colPri; // remember starting color if (nightlightMode == NL_MODE_SUN) { - //save current - colNlT[0] = effectCurrent; - colNlT[1] = effectSpeed; - colNlT[2] = effectPalette; + // save current globals in unused color channels + colNlT.r = effectCurrent; + colNlT.g = effectSpeed; + colNlT.b = effectPalette; strip.getFirstSelectedSeg().setMode(FX_MODE_STATIC); // make sure seg runtime is reset if it was in sunrise mode effectCurrent = FX_MODE_SUNRISE; // colorUpdated() will take care of assigning that to all selected segments @@ -229,7 +223,11 @@ void handleNightlight() { bri = briNlT + ((nightlightTargetBri - briNlT)*nper); if (nightlightMode == NL_MODE_COLORFADE) // color fading only is enabled with "NF=2" { - for (unsigned i=0; i<4; i++) colPri[i] = colNlT[i]+ ((colSec[i] - colNlT[i])*nper); // fading from actual color to secondary color + uint32_t blendamount = nper * 255; + if (blendamount > 255) + colPri = colSec; + else + colPri = color_blend(colNlT, colSec, blendamount); // fading from actual color to secondary color } uint16_t transitionduration = strip.getTransition(); strip.setTransition(0); // temporary disable transition and set color & brightness directly, (hacky fix for #5620) @@ -247,10 +245,10 @@ void handleNightlight() { if (bri == 0) briLast = briNlT; if (nightlightMode == NL_MODE_SUN) { - if (!briNlT) { //turn off if sunset - effectCurrent = colNlT[0]; - effectSpeed = colNlT[1]; - effectPalette = colNlT[2]; + if (!briNlT) { // turn off if sunset, restore values from color channels (see above) + effectCurrent = colNlT.r; + effectSpeed = colNlT.g; + effectPalette = colNlT.b; toggleOnOff(); applyFinalBri(); } @@ -262,10 +260,10 @@ void handleNightlight() { } } else if (nightlightActiveOld) //early de-init { - if (nightlightMode == NL_MODE_SUN) { //restore previous effect - effectCurrent = colNlT[0]; - effectSpeed = colNlT[1]; - effectPalette = colNlT[2]; + if (nightlightMode == NL_MODE_SUN) { // restore previous effect from color channels (see above) + effectCurrent = colNlT.r; + effectSpeed = colNlT.g; + effectPalette = colNlT.b; colorUpdated(CALL_MODE_NO_NOTIFY); } nightlightActiveOld = false; diff --git a/wled00/lx_parser.cpp b/wled00/lx_parser.cpp index 1318686ceb..08dd724dfc 100644 --- a/wled00/lx_parser.cpp +++ b/wled00/lx_parser.cpp @@ -5,7 +5,7 @@ /* * Parser for Loxone formats */ -bool parseLx(int lxValue, byte* rgbw) +bool parseLx(int lxValue, CRGBW &rgbw) { DEBUG_PRINT(F("LX: Lox = ")); DEBUG_PRINTLN(lxValue); @@ -29,7 +29,7 @@ bool parseLx(int lxValue, byte* rgbw) tmpBri = constrain(tmpBri, 0, 255); colorKtoRGB(ct, rgbw); - lxRed = rgbw[0]; lxGreen = rgbw[1]; lxBlue = rgbw[2]; + lxRed = rgbw.r; lxGreen = rgbw.g; lxBlue = rgbw.b; lxRed *= (tmpBri/255); lxGreen *= (tmpBri/255); @@ -37,10 +37,10 @@ bool parseLx(int lxValue, byte* rgbw) } if (ok) { - rgbw[0] = (uint8_t) constrain(lxRed, 0, 255); - rgbw[1] = (uint8_t) constrain(lxGreen, 0, 255); - rgbw[2] = (uint8_t) constrain(lxBlue, 0, 255); - rgbw[3] = 0; + rgbw = 0; // white is unused, make sure it does not contain garbage value + rgbw.r = (uint8_t) constrain(lxRed, 0, 255); + rgbw.g = (uint8_t) constrain(lxGreen, 0, 255); + rgbw.b = (uint8_t) constrain(lxBlue, 0, 255); return true; } return false; @@ -54,7 +54,7 @@ void parseLxJson(int lxValue, byte segId, bool secondary) DEBUG_PRINT(F("LX: Lox primary = ")); } DEBUG_PRINTLN(lxValue); - byte rgbw[] = {0,0,0,0}; + CRGBW rgbw = 0; if (parseLx(lxValue, rgbw)) { if (bri == 0) { DEBUG_PRINTLN(F("LX: turn on")); @@ -64,7 +64,7 @@ void parseLxJson(int lxValue, byte segId, bool secondary) nightlightActive = false; //always disable nightlight when toggling DEBUG_PRINT(F("LX: segment ")); DEBUG_PRINTLN(segId); - strip.getSegment(segId).setColor(secondary, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3])); // legacy values handled as well in json.cpp by stateUpdated() + strip.getSegment(segId).setColor(secondary, rgbw); // legacy values handled as well in json.cpp by stateUpdated() } } diff --git a/wled00/mqtt.cpp b/wled00/mqtt.cpp index d64dc29d9b..94d7c9abdb 100644 --- a/wled00/mqtt.cpp +++ b/wled00/mqtt.cpp @@ -175,7 +175,7 @@ void publishMqtt() snprintf_P(subuf, sizeof(subuf)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "g"); mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) - sprintf_P(s, PSTR("#%06X"), (colPri[3] << 24) | (colPri[0] << 16) | (colPri[1] << 8) | (colPri[2])); + sprintf_P(s, PSTR("#%06X"), colPri.color32); // 0xWWRRGGBB snprintf_P(subuf, sizeof(subuf)-1, sTopicFormat, MQTT_MAX_TOPIC_LEN, mqttDeviceTopic, "c"); mqtt->publish(subuf, 0, retainMqttMsg, s); // optionally retain message (#2263) diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp index f5366f3b71..eed600f536 100644 --- a/wled00/overlay.cpp +++ b/wled00/overlay.cpp @@ -81,11 +81,11 @@ static void _overlayAnalogCountdown() byte pixelCnt = perc*overlaySize; if (analogClock12pixel + pixelCnt > overlayMax) { - strip.setRange(analogClock12pixel, overlayMax, ((uint32_t)colSec[3] << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]); - strip.setRange(overlayMin, overlayMin +pixelCnt -(1+ overlayMax -analogClock12pixel), ((uint32_t)colSec[3] << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]); + strip.setRange(analogClock12pixel, overlayMax, colSec.color32); + strip.setRange(overlayMin, overlayMin +pixelCnt -(1+ overlayMax -analogClock12pixel), colSec.color32); } else { - strip.setRange(analogClock12pixel, analogClock12pixel + pixelCnt, ((uint32_t)colSec[3] << 24)| ((uint32_t)colSec[0] << 16) | ((uint32_t)colSec[1] << 8) | colSec[2]); + strip.setRange(analogClock12pixel, analogClock12pixel + pixelCnt, colSec.color32); } } } diff --git a/wled00/set.cpp b/wled00/set.cpp index fb516ac7d6..794c1ae02e 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -926,8 +926,8 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) uint32_t col0 = selseg.colors[0]; uint32_t col1 = selseg.colors[1]; uint32_t col2 = selseg.colors[2]; - byte colIn[4] = {R(col0), G(col0), B(col0), W(col0)}; - byte colInSec[4] = {R(col1), G(col1), B(col1), W(col1)}; + CRGBW colIn = col0; + CRGBW colInSec = col1; byte effectIn = selseg.mode; byte speedIn = selseg.speed; byte intensityIn = selseg.intensity; @@ -1010,15 +1010,15 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) bool col0Changed = false, col1Changed = false, col2Changed = false; //set colors - col0Changed |= updateVal(req.c_str(), "&R=", colIn[0]); - col0Changed |= updateVal(req.c_str(), "&G=", colIn[1]); - col0Changed |= updateVal(req.c_str(), "&B=", colIn[2]); - col0Changed |= updateVal(req.c_str(), "&W=", colIn[3]); + col0Changed |= updateVal(req.c_str(), "&R=", colIn.r); + col0Changed |= updateVal(req.c_str(), "&G=", colIn.g); + col0Changed |= updateVal(req.c_str(), "&B=", colIn.b); + col0Changed |= updateVal(req.c_str(), "&W=", colIn.w); - col1Changed |= updateVal(req.c_str(), "R2=", colInSec[0]); - col1Changed |= updateVal(req.c_str(), "G2=", colInSec[1]); - col1Changed |= updateVal(req.c_str(), "B2=", colInSec[2]); - col1Changed |= updateVal(req.c_str(), "W2=", colInSec[3]); + col1Changed |= updateVal(req.c_str(), "R2=", colInSec.r); + col1Changed |= updateVal(req.c_str(), "G2=", colInSec.g); + col1Changed |= updateVal(req.c_str(), "B2=", colInSec.b); + col1Changed |= updateVal(req.c_str(), "W2=", colInSec.w); #ifdef WLED_ENABLE_LOXONE //lox parser @@ -1077,9 +1077,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } pos = req.indexOf(F("C3=")); if (pos > 0) { - byte tmpCol[4]; + CRGBW tmpCol; colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str()); - col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]); + col2 = tmpCol.color32; selseg.setColor(2, col2); // defined above (SS= or main) col2Changed = true; } @@ -1094,12 +1094,12 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) // apply colors to selected segment, and all selected segments if applicable if (col0Changed) { - col0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]); + col0 = colIn.color32; selseg.setColor(0, col0); } if (col1Changed) { - col1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]); + col1 = colInSec.color32; selseg.setColor(1, col1); } @@ -1268,7 +1268,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) } // you can add more if you need - // global colPri[], effectCurrent, ... are updated in stateChanged() + // global colPri, effectCurrent, ... are updated in stateChanged() if (!apply) return true; // when called by JSON API, do not call colorUpdated() here pos = req.indexOf(F("&NN")); //do not send UDP notifications this time diff --git a/wled00/src/dependencies/fastled_slim/fastled_slim.cpp b/wled00/src/dependencies/fastled_slim/fastled_slim.cpp index 55708bbdf5..790bc3ac94 100644 --- a/wled00/src/dependencies/fastled_slim/fastled_slim.cpp +++ b/wled00/src/dependencies/fastled_slim/fastled_slim.cpp @@ -99,15 +99,17 @@ __attribute__((optimize("O2"))) void hsv2rgb_rainbow(uint16_t h, uint8_t s, uint } } if(isRGBW) { - rgbdata[0] = b; + rgbdata[0] = b; // CRGBW has color order [b,g,r,w] rgbdata[1] = g; rgbdata[2] = r; - //rgbdata[3] = 0; // white + rgbdata[3] = 0; // HSV does not contain white, so set it to black to not leave garbage data } else { - rgbdata[0] = r; + rgbdata[0] = r; // CRGB has color order [r,g,b] rgbdata[1] = g; rgbdata[2] = b; } + + } diff --git a/wled00/src/dependencies/fastled_slim/fastled_slim.h b/wled00/src/dependencies/fastled_slim/fastled_slim.h index 1e2fce5f11..723c67d083 100644 --- a/wled00/src/dependencies/fastled_slim/fastled_slim.h +++ b/wled00/src/dependencies/fastled_slim/fastled_slim.h @@ -49,7 +49,7 @@ typedef union { } TRGBGradientPaletteEntryUnion; // function prototypes -void hsv2rgb_rainbow(uint16_t h, uint8_t s, uint8_t v, uint8_t* rgbdata, bool isRGBW); +void hsv2rgb_rainbow(uint16_t h, uint8_t s, uint8_t v, uint8_t* rgbdata, bool isRGBW = false); CRGB HeatColor(uint8_t temperature); // black body radiation void fill_solid_RGB(CRGB* colors, uint32_t num, const CRGB& c1) ; void fill_gradient_RGB(CRGB* colors, uint32_t startpos, CRGB startcolor, uint32_t endpos, CRGB endcolor); @@ -160,22 +160,22 @@ struct CRGB { // allow construction from a CHSV color inline CRGB(const CHSV& rhs) __attribute__((always_inline)) { - hsv2rgb_rainbow(rhs.h<<8, rhs.s, rhs.v, raw, false); + hsv2rgb_rainbow(rhs.h<<8, rhs.s, rhs.v, raw); } // allow assignment from hue, saturation, and value inline CRGB& setHSV (uint8_t hue, uint8_t sat, uint8_t val) __attribute__((always_inline)) { - hsv2rgb_rainbow(hue<<8, sat, val, raw, false); return *this; + hsv2rgb_rainbow(hue<<8, sat, val, raw); return *this; } // allow assignment from just a hue, sat and val are set to max inline CRGB& setHue (uint8_t hue) __attribute__((always_inline)) { - hsv2rgb_rainbow(hue<<8, 255, 255, raw, false); return *this; + hsv2rgb_rainbow(hue<<8, 255, 255, raw); return *this; } // allow assignment from HSV color inline CRGB& operator= (const CHSV& rhs) __attribute__((always_inline)) { - hsv2rgb_rainbow(rhs.h<<8, rhs.s, rhs.v, raw, false); return *this; + hsv2rgb_rainbow(rhs.h<<8, rhs.s, rhs.v, raw); return *this; } // allow assignment from one RGB struct to another inline CRGB& operator= (const CRGB& rhs) __attribute__((always_inline)) = default; diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 55033d5986..b04b629336 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -637,10 +637,7 @@ void WLED::beginStrip() } else { // set color to warm welcoming orange (aka DEFAULT_COLOR) if no preset loaded (will fade to this color once turned on) - colPri[0] = R(DEFAULT_COLOR); - colPri[1] = G(DEFAULT_COLOR); - colPri[2] = B(DEFAULT_COLOR); - colPri[3] = W(DEFAULT_COLOR); + colPri = DEFAULT_COLOR; } strip.setTransition(transitionDelayDefault); // restore default transition time diff --git a/wled00/wled.h b/wled00/wled.h index 23c1995edf..e302efa57e 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -413,8 +413,8 @@ WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on col WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness WLED_GLOBAL float gammaCorrectVal _INIT(2.2f); // gamma correction value -WLED_GLOBAL byte colPri[] _INIT_N(({ 0, 0, 0, 0 })); // current RGB(W) primary color. colPri[] should be updated if you want to change the color. -WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 })); // current RGB(W) secondary color +WLED_GLOBAL CRGBW colPri _INIT(0); // current RGB(W) primary color. colPri should be updated if you want to change the color. +WLED_GLOBAL CRGBW colSec _INIT(0); // current RGB(W) secondary color WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over WLED_GLOBAL byte nightlightDelayMins _INIT(60); @@ -621,7 +621,7 @@ WLED_GLOBAL byte nightlightDelayMinsDefault _INIT(nightlightDelayMins); WLED_GLOBAL unsigned long nightlightStartTime; WLED_GLOBAL unsigned long lastNlUpdate; WLED_GLOBAL byte briNlT _INIT(0); // current nightlight brightness -WLED_GLOBAL byte colNlT[] _INIT_N(({ 0, 0, 0, 0 })); // current nightlight color +WLED_GLOBAL CRGBW colNlT _INIT(0); // current nightlight color // brightness WLED_GLOBAL unsigned long lastOnTime _INIT(0); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 03d4cd1101..c60ec8e59f 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -12,18 +12,18 @@ static void appendGPIOinfo(Print& settingsScript); void XML_response(Print& dest) { dest.printf_P(PSTR("%d"), (nightlightActive && nightlightMode > NL_MODE_SET) ? briT : bri); - for (int i = 0; i < 3; i++) + for (int i = 2; i >= 0; i--) { - dest.printf_P(PSTR("%d"), colPri[i]); + dest.printf_P(PSTR("%d"), colPri.raw[i]); // raw array is in the order B,G,R,W i.e. raw[0] = blue, does not use white } - for (int i = 0; i < 3; i++) + for (int i = 2; i >= 0; i--) { - dest.printf_P(PSTR("%d"), colSec[i]); + dest.printf_P(PSTR("%d"), colSec.raw[i]); // raw array is in the order BGRW, does not use white } dest.printf_P(PSTR("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%s%s%d"), notifyDirect, receiveGroups!=0, nightlightActive, nightlightMode > NL_MODE_SET, nightlightDelayMins, nightlightTargetBri, effectCurrent, effectSpeed, effectIntensity, effectPalette, - strip.hasWhiteChannel() ? colPri[3] : -1, colSec[3], currentPreset, currentPlaylist >= 0, + strip.hasWhiteChannel() ? colPri.w : -1, colSec.w, currentPreset, currentPlaylist >= 0, serverDescription, realtimeMode ? PSTR(" (live)") : "", strip.getFirstSelectedSegId() );