diff --git a/src/internal/HsbColor.cpp b/src/internal/HsbColor.cpp deleted file mode 100644 index e47912f..0000000 --- a/src/internal/HsbColor.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/*------------------------------------------------------------------------- -HsbColor provides a color object that can be directly consumed by NeoPixelBus - -Written by Michael C. Miller. - -I invest time and resources providing this open source code, -please support me by dontating (see https://github.com/Makuna/NeoPixelBus) - -------------------------------------------------------------------------- -This file is part of the Makuna/NeoPixelBus library. - -NeoPixelBus is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation, either version 3 of -the License, or (at your option) any later version. - -NeoPixelBus is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with NeoPixel. If not, see -. --------------------------------------------------------------------------*/ - -#include "RgbColor.h" -#include "HsbColor.h" - - -HsbColor::HsbColor(const RgbColor& color) -{ - // convert colors to float between (0.0 - 1.0) - float r = color.R / 255.0f; - float g = color.G / 255.0f; - float b = color.B / 255.0f; - - float max = (r > g && r > b) ? r : (g > b) ? g : b; - float min = (r < g && r < b) ? r : (g < b) ? g : b; - - float d = max - min; - - float h = 0.0; - float v = max; - float s = (v == 0.0f) ? 0 : (d / v); - - if (d != 0.0f) - { - if (r == max) - { - h = (g - b) / d + (g < b ? 6.0f : 0.0f); - } - else if (g == max) - { - h = (b - r) / d + 2.0f; - } - else - { - h = (r - g) / d + 4.0f; - } - h /= 6.0f; - } - - - H = h; - S = s; - B = v; -} diff --git a/src/internal/HsbColor.h b/src/internal/HsbColor.h index 4d0bdfa..c8869d2 100644 --- a/src/internal/HsbColor.h +++ b/src/internal/HsbColor.h @@ -1,4 +1,3 @@ - /*------------------------------------------------------------------------- HsbColor provides a color object that can be directly consumed by NeoPixelBus @@ -26,35 +25,34 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #pragma once -#include +struct RgbColor; // ------------------------------------------------------------------------ // HsbColor represents a color object that is represented by Hue, Saturation, Brightness -// component values. It contains helpful color routines to manipulate the +// component values. It contains helpful color routines to manipulate the // color. // ------------------------------------------------------------------------ struct HsbColor { + // ------------------------------------------------------------------------ + // Construct a HsbColor that will have its values set in latter operations + // ------------------------------------------------------------------------ + constexpr HsbColor(); + // ------------------------------------------------------------------------ // Construct a HsbColor using H, S, B values (0.0 - 1.0) // ------------------------------------------------------------------------ - HsbColor(float h, float s, float b) : - H(h), S(s), B(b) - { - }; + constexpr HsbColor(float h, float s, float b); + + // ------------------------------------------------------------------------ + // Construct a HsbColor using HsbColor + // ------------------------------------------------------------------------ + constexpr HsbColor(const HsbColor& color); // ------------------------------------------------------------------------ // Construct a HsbColor using RgbColor // ------------------------------------------------------------------------ - HsbColor(const RgbColor& color); - - // ------------------------------------------------------------------------ - // Construct a HsbColor that will have its values set in latter operations - // CAUTION: The H,S,B members are not initialized and may not be consistent - // ------------------------------------------------------------------------ - HsbColor() - { - }; + constexpr HsbColor(const RgbColor& color); // ------------------------------------------------------------------------ // LinearBlend between two colors by the amount defined by progress variable @@ -63,14 +61,10 @@ struct HsbColor // progress - (0.0 - 1.0) value where 0.0 will return left and 1.0 will return right // and a value between will blend the color weighted linearly between them // ------------------------------------------------------------------------ - template static HsbColor LinearBlend(const HsbColor& left, + template + static constexpr HsbColor LinearBlend(const HsbColor& left, const HsbColor& right, - float progress) - { - return HsbColor(T_NEOHUEBLEND::HueBlend(left.H, right.H, progress), - left.S + ((right.S - left.S) * progress), - left.B + ((right.B - left.B) * progress)); - } + float progress); // ------------------------------------------------------------------------ // BilinearBlend between four colors by the amount defined by 2d variable @@ -81,33 +75,107 @@ struct HsbColor // x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space // y - unit value (0.0 - 1.0) that defines the blend progress in vertical space // ------------------------------------------------------------------------ - template static HsbColor BilinearBlend(const HsbColor& c00, + template + static constexpr HsbColor BilinearBlend(const HsbColor& c00, const HsbColor& c01, const HsbColor& c10, const HsbColor& c11, float x, - float y) - { - float v00 = (1.0f - x) * (1.0f - y); - float v10 = x * (1.0f - y); - float v01 = (1.0f - x) * y; - float v11 = x * y; - - return HsbColor( - T_NEOHUEBLEND::HueBlend( - T_NEOHUEBLEND::HueBlend(c00.H, c10.H, x), - T_NEOHUEBLEND::HueBlend(c01.H, c11.H, x), - y), - c00.S * v00 + c10.S * v10 + c01.S * v01 + c11.S * v11, - c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11); - }; + float y); // ------------------------------------------------------------------------ - // Hue, Saturation, Brightness color members + // Hue, Saturation, Brightness color members // ------------------------------------------------------------------------ - float H; - float S; - float B; + float H{}; + float S{}; + float B{}; + +private: + static constexpr HsbColor convertToHsbColor(const RgbColor& color); }; +#include "RgbColor.h" + +constexpr HsbColor::HsbColor() = default; + +constexpr HsbColor::HsbColor(float h, float s, float b) : + H{h}, S{s}, B{b} +{ +} + +constexpr HsbColor::HsbColor(const HsbColor& color) = default; + +constexpr HsbColor::HsbColor(const RgbColor& color) : + HsbColor{convertToHsbColor(color)} +{ +} + +//template +//static constexpr HsbColor HsbColor::LinearBlend(const HsbColor& left, +// const HsbColor& right, +// float progress) +//{ +// return HsbColor(T_NEOHUEBLEND::HueBlend(left.H, right.H, progress), +// left.S + ((right.S - left.S) * progress), +// left.B + ((right.B - left.B) * progress)); +//} + +//template +//static constexpr HsbColor HsbColor::BilinearBlend(const HsbColor& c00, +// const HsbColor& c01, +// const HsbColor& c10, +// const HsbColor& c11, +// float x, +// float y) +//{ +// float v00 = (1.0f - x) * (1.0f - y); +// float v10 = x * (1.0f - y); +// float v01 = (1.0f - x) * y; +// float v11 = x * y; + +// return HsbColor( +// T_NEOHUEBLEND::HueBlend( +// T_NEOHUEBLEND::HueBlend(c00.H, c10.H, x), +// T_NEOHUEBLEND::HueBlend(c01.H, c11.H, x), +// y), +// c00.S * v00 + c10.S * v10 + c01.S * v01 + c11.S * v11, +// c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11); +//} + +constexpr HsbColor HsbColor::convertToHsbColor(const RgbColor& color) +{ + // convert colors to float between (0.0 - 1.0) + float r = color.R / 255.0f; + float g = color.G / 255.0f; + float b = color.B / 255.0f; + + float max = (r > g && r > b) ? r : (g > b) ? g : b; + float min = (r < g && r < b) ? r : (g < b) ? g : b; + + float d = max - min; + + HsbColor hsb{}; + hsb.H = 0.f; + hsb.B = max; + hsb.S = (hsb.B == 0.0f) ? 0 : (d / hsb.B); + + if (d != 0.0f) + { + if (r == max) + { + hsb.H = (g - b) / d + (g < b ? 6.0f : 0.0f); + } + else if (g == max) + { + hsb.H = (b - r) / d + 2.0f; + } + else + { + hsb.H = (r - g) / d + 4.0f; + } + hsb.H /= 6.0f; + } + + return hsb; +} diff --git a/src/internal/HslColor.cpp b/src/internal/HslColor.cpp deleted file mode 100644 index ce9b238..0000000 --- a/src/internal/HslColor.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/*------------------------------------------------------------------------- -HslColor provides a color object that can be directly consumed by NeoPixelBus - - -Written by Michael C. Miller. - -I invest time and resources providing this open source code, -please support me by dontating (see https://github.com/Makuna/NeoPixelBus) - -------------------------------------------------------------------------- -This file is part of the Makuna/NeoPixelBus library. - -NeoPixelBus is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation, either version 3 of -the License, or (at your option) any later version. - -NeoPixelBus is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with NeoPixel. If not, see -. --------------------------------------------------------------------------*/ - -#include "RgbColor.h" -#include "HslColor.h" - - -HslColor::HslColor(const RgbColor& color) -{ - // convert colors to float between (0.0 - 1.0) - float r = color.R / 255.0f; - float g = color.G / 255.0f; - float b = color.B / 255.0f; - - float max = (r > g && r > b) ? r : (g > b) ? g : b; - float min = (r < g && r < b) ? r : (g < b) ? g : b; - - float h, s, l; - l = (max + min) / 2.0f; - - if (max == min) - { - h = s = 0.0f; - } - else - { - float d = max - min; - s = (l > 0.5f) ? d / (2.0f - (max + min)) : d / (max + min); - - if (r > g && r > b) - { - h = (g - b) / d + (g < b ? 6.0f : 0.0f); - } - else if (g > b) - { - h = (b - r) / d + 2.0f; - } - else - { - h = (r - g) / d + 4.0f; - } - h /= 6.0f; - } - - H = h; - S = s; - L = l; -} diff --git a/src/internal/HslColor.h b/src/internal/HslColor.h index f6988bd..05272e1 100644 --- a/src/internal/HslColor.h +++ b/src/internal/HslColor.h @@ -25,37 +25,35 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #pragma once -#include +struct RgbColor; // ------------------------------------------------------------------------ // HslColor represents a color object that is represented by Hue, Saturation, Lightness -// component values. It contains helpful color routines to manipulate the +// component values. It contains helpful color routines to manipulate the // color. // ------------------------------------------------------------------------ struct HslColor { + // ------------------------------------------------------------------------ + // Construct a HslColor that will have its values set in latter operations + // ------------------------------------------------------------------------ + constexpr HslColor(); // ------------------------------------------------------------------------ // Construct a HslColor using H, S, L values (0.0 - 1.0) // L should be limited to between (0.0 - 0.5) // ------------------------------------------------------------------------ - HslColor(float h, float s, float l) : - H(h), S(s), L(l) - { - }; + constexpr HslColor(float h, float s, float l); + + // ------------------------------------------------------------------------ + // Construct a HslColor using HslColor + // ------------------------------------------------------------------------ + constexpr HslColor(const HslColor& color); // ------------------------------------------------------------------------ // Construct a HslColor using RgbColor // ------------------------------------------------------------------------ - HslColor(const RgbColor& color); - - // ------------------------------------------------------------------------ - // Construct a HslColor that will have its values set in latter operations - // CAUTION: The H,S,L members are not initialized and may not be consistent - // ------------------------------------------------------------------------ - HslColor() - { - }; + constexpr HslColor(const RgbColor& color); // ------------------------------------------------------------------------ // LinearBlend between two colors by the amount defined by progress variable @@ -64,14 +62,10 @@ struct HslColor // progress - (0.0 - 1.0) value where 0.0 will return left and 1.0 will return right // and a value between will blend the color weighted linearly between them // ------------------------------------------------------------------------ - template static HslColor LinearBlend(const HslColor& left, + template + static constexpr HslColor LinearBlend(const HslColor& left, const HslColor& right, - float progress) - { - return HslColor(T_NEOHUEBLEND::HueBlend(left.H, right.H, progress), - left.S + ((right.S - left.S) * progress), - left.L + ((right.L - left.L) * progress)); - }; + float progress); // ------------------------------------------------------------------------ // BilinearBlend between four colors by the amount defined by 2d variable @@ -82,32 +76,110 @@ struct HslColor // x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space // y - unit value (0.0 - 1.0) that defines the blend progress in vertical space // ------------------------------------------------------------------------ - template static HslColor BilinearBlend(const HslColor& c00, + template + static constexpr HslColor BilinearBlend(const HslColor& c00, const HslColor& c01, const HslColor& c10, const HslColor& c11, float x, - float y) - { - float v00 = (1.0f - x) * (1.0f - y); - float v10 = x * (1.0f - y); - float v01 = (1.0f - x) * y; - float v11 = x * y; - - return HslColor( - T_NEOHUEBLEND::HueBlend( - T_NEOHUEBLEND::HueBlend(c00.H, c10.H, x), - T_NEOHUEBLEND::HueBlend(c01.H, c11.H, x), - y), - c00.S * v00 + c10.S * v10 + c01.S * v01 + c11.S * v11, - c00.L * v00 + c10.L * v10 + c01.L * v01 + c11.L * v11); - }; + float y); // ------------------------------------------------------------------------ - // Hue, Saturation, Lightness color members + // Hue, Saturation, Lightness color members // ------------------------------------------------------------------------ - float H; - float S; - float L; + float H{}; + float S{}; + float L{}; + +private: + static constexpr HslColor convertToHslColor(const RgbColor& color); }; +#include "RgbColor.h" + +constexpr HslColor::HslColor() = default; + +constexpr HslColor::HslColor(float h, float s, float l) : + H{h}, S{s}, L{l} +{ +} + +constexpr HslColor::HslColor(const HslColor& color) = default; + +constexpr HslColor::HslColor(const RgbColor& color) : + HslColor{convertToHslColor(color)} +{ +} + +//template +//static constexpr HslColor HslColor::LinearBlend(const HslColor& left, +// const HslColor& right, +// float progress) +//{ +// return HslColor(T_NEOHUEBLEND::HueBlend(left.H, right.H, progress), +// left.S + ((right.S - left.S) * progress), +// left.L + ((right.L - left.L) * progress)); +//}; + +//template +//static constexpr HslColor HslColor::BilinearBlend(const HslColor& c00, +// const HslColor& c01, +// const HslColor& c10, +// const HslColor& c11, +// float x, +// float y) +//{ +// float v00 = (1.0f - x) * (1.0f - y); +// float v10 = x * (1.0f - y); +// float v01 = (1.0f - x) * y; +// float v11 = x * y; + +// return HslColor( +// T_NEOHUEBLEND::HueBlend( +// T_NEOHUEBLEND::HueBlend(c00.H, c10.H, x), +// T_NEOHUEBLEND::HueBlend(c01.H, c11.H, x), +// y), +// c00.S * v00 + c10.S * v10 + c01.S * v01 + c11.S * v11, +// c00.L * v00 + c10.L * v10 + c01.L * v01 + c11.L * v11); +//} + +constexpr HslColor HslColor::convertToHslColor(const RgbColor& color) +{ + // convert colors to float between (0.0 - 1.0) + float r = color.R / 255.0f; + float g = color.G / 255.0f; + float b = color.B / 255.0f; + + float max = (r > g && r > b) ? r : (g > b) ? g : b; + float min = (r < g && r < b) ? r : (g < b) ? g : b; + + HslColor hsl; + + hsl.L = (max + min) / 2.0f; + + if (max == min) + { + hsl.H = hsl.S = 0.0f; + } + else + { + float d = max - min; + hsl.S = (hsl.L > 0.5f) ? d / (2.0f - (max + min)) : d / (max + min); + + if (r > g && r > b) + { + hsl.H = (g - b) / d + (g < b ? 6.0f : 0.0f); + } + else if (g > b) + { + hsl.H = (b - r) / d + 2.0f; + } + else + { + hsl.H = (r - g) / d + 4.0f; + } + hsl.H /= 6.0f; + } + + return hsl; +} diff --git a/src/internal/RgbColor.cpp b/src/internal/RgbColor.cpp deleted file mode 100644 index 39371db..0000000 --- a/src/internal/RgbColor.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/*------------------------------------------------------------------------- -RgbColor provides a color object that can be directly consumed by NeoPixelBus - -Written by Michael C. Miller. - -I invest time and resources providing this open source code, -please support me by dontating (see https://github.com/Makuna/NeoPixelBus) - -------------------------------------------------------------------------- -This file is part of the Makuna/NeoPixelBus library. - -NeoPixelBus is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation, either version 3 of -the License, or (at your option) any later version. - -NeoPixelBus is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with NeoPixel. If not, see -. --------------------------------------------------------------------------*/ - -#include "RgbColor.h" -#include "HslColor.h" -#include "HsbColor.h" - -static float _CalcColor(float p, float q, float t) -{ - if (t < 0.0f) - t += 1.0f; - if (t > 1.0f) - t -= 1.0f; - - if (t < 1.0f / 6.0f) - return p + (q - p) * 6.0f * t; - - if (t < 0.5f) - return q; - - if (t < 2.0f / 3.0f) - return p + ((q - p) * (2.0f / 3.0f - t) * 6.0f); - - return p; -} - -RgbColor::RgbColor(const HslColor& color) -{ - float r; - float g; - float b; - - float h = color.H; - float s = color.S; - float l = color.L; - - - if (color.S == 0.0f || color.L == 0.0f) - { - r = g = b = l; // achromatic or black - } - else - { - float q = l < 0.5f ? l * (1.0f + s) : l + s - (l * s); - float p = 2.0f * l - q; - r = _CalcColor(p, q, h + 1.0f / 3.0f); - g = _CalcColor(p, q, h); - b = _CalcColor(p, q, h - 1.0f / 3.0f); - } - - R = (uint8_t)(r * 255.0f); - G = (uint8_t)(g * 255.0f); - B = (uint8_t)(b * 255.0f); -} - -RgbColor::RgbColor(const HsbColor& color) -{ - float r; - float g; - float b; - - float h = color.H; - float s = color.S; - float v = color.B; - - if (color.S == 0.0f) - { - r = g = b = v; // achromatic or black - } - else - { - if (h < 0.0f) - { - h += 1.0f; - } - else if (h >= 1.0f) - { - h -= 1.0f; - } - h *= 6.0f; - int i = (int)h; - float f = h - i; - float q = v * (1.0f - s * f); - float p = v * (1.0f - s); - float t = v * (1.0f - s * (1.0f - f)); - switch (i) - { - case 0: - r = v; - g = t; - b = p; - break; - case 1: - r = q; - g = v; - b = p; - break; - case 2: - r = p; - g = v; - b = t; - break; - case 3: - r = p; - g = q; - b = v; - break; - case 4: - r = t; - g = p; - b = v; - break; - default: - r = v; - g = p; - b = q; - break; - } - } - - R = (uint8_t)(r * 255.0f); - G = (uint8_t)(g * 255.0f); - B = (uint8_t)(b * 255.0f); -} - -uint8_t RgbColor::CalculateBrightness() const -{ - return (uint8_t)(((uint16_t)R + (uint16_t)G + (uint16_t)B) / 3); -} - -RgbColor RgbColor::Dim(uint8_t ratio) const -{ - // specifically avoids float math - return RgbColor(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio)); -} - -RgbColor RgbColor::Brighten(uint8_t ratio) const -{ - // specifically avoids float math - return RgbColor(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio)); -} - -void RgbColor::Darken(uint8_t delta) -{ - if (R > delta) - { - R -= delta; - } - else - { - R = 0; - } - - if (G > delta) - { - G -= delta; - } - else - { - G = 0; - } - - if (B > delta) - { - B -= delta; - } - else - { - B = 0; - } -} - -void RgbColor::Lighten(uint8_t delta) -{ - if (R < 255 - delta) - { - R += delta; - } - else - { - R = 255; - } - - if (G < 255 - delta) - { - G += delta; - } - else - { - G = 255; - } - - if (B < 255 - delta) - { - B += delta; - } - else - { - B = 255; - } -} - -RgbColor RgbColor::LinearBlend(const RgbColor& left, const RgbColor& right, float progress) -{ - return RgbColor( left.R + ((right.R - left.R) * progress), - left.G + ((right.G - left.G) * progress), - left.B + ((right.B - left.B) * progress)); -} - -RgbColor RgbColor::BilinearBlend(const RgbColor& c00, - const RgbColor& c01, - const RgbColor& c10, - const RgbColor& c11, - float x, - float y) -{ - float v00 = (1.0f - x) * (1.0f - y); - float v10 = x * (1.0f - y); - float v01 = (1.0f - x) * y; - float v11 = x * y; - - return RgbColor( - c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11, - c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11, - c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11); -} diff --git a/src/internal/RgbColor.h b/src/internal/RgbColor.h index 55b5618..c6eba0c 100644 --- a/src/internal/RgbColor.h +++ b/src/internal/RgbColor.h @@ -25,7 +25,8 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #pragma once -#include +#include + #include "NeoSettings.h" struct HslColor; @@ -33,97 +34,87 @@ struct HsbColor; // ------------------------------------------------------------------------ // RgbColor represents a color object that is represented by Red, Green, Blue -// component values. It contains helpful color routines to manipulate the +// component values. It contains helpful color routines to manipulate the // color. // ------------------------------------------------------------------------ struct RgbColor { - typedef NeoRgbCurrentSettings SettingsObject; + using SettingsObject = NeoRgbCurrentSettings; + + // ------------------------------------------------------------------------ + // Construct a RgbColor that will have its values set in latter operations + // ------------------------------------------------------------------------ + constexpr RgbColor(); // ------------------------------------------------------------------------ // Construct a RgbColor using R, G, B values (0-255) // ------------------------------------------------------------------------ - RgbColor(uint8_t r, uint8_t g, uint8_t b) : - R(r), G(g), B(b) - { - }; + constexpr RgbColor(uint8_t r, uint8_t g, uint8_t b); // ------------------------------------------------------------------------ // Construct a RgbColor using a single brightness value (0-255) // This works well for creating gray tone colors // (0) = black, (255) = white, (128) = gray // ------------------------------------------------------------------------ - RgbColor(uint8_t brightness) : - R(brightness), G(brightness), B(brightness) - { - }; + constexpr RgbColor(uint8_t brightness); // ------------------------------------------------------------------------ // Construct a RgbColor using HslColor // ------------------------------------------------------------------------ - RgbColor(const HslColor& color); + constexpr RgbColor(const RgbColor& color); + + // ------------------------------------------------------------------------ + // Construct a RgbColor using HslColor + // ------------------------------------------------------------------------ + constexpr RgbColor(const HslColor& color); // ------------------------------------------------------------------------ // Construct a RgbColor using HsbColor // ------------------------------------------------------------------------ - RgbColor(const HsbColor& color); - - // ------------------------------------------------------------------------ - // Construct a RgbColor that will have its values set in latter operations - // CAUTION: The R,G,B members are not initialized and may not be consistent - // ------------------------------------------------------------------------ - RgbColor() - { - }; + constexpr RgbColor(const HsbColor& color); // ------------------------------------------------------------------------ // Comparison operators // ------------------------------------------------------------------------ - bool operator==(const RgbColor& other) const - { - return (R == other.R && G == other.G && B == other.B); - }; + constexpr bool operator==(const RgbColor& other) const; - bool operator!=(const RgbColor& other) const - { - return !(*this == other); - }; + constexpr bool operator!=(const RgbColor& other) const; // ------------------------------------------------------------------------ // CalculateBrightness will calculate the overall brightness // NOTE: This is a simple linear brightness // ------------------------------------------------------------------------ - uint8_t CalculateBrightness() const; + constexpr uint8_t CalculateBrightness() const; // ------------------------------------------------------------------------ // Dim will return a new color that is blended to black with the given ratio // ratio - (0-255) where 255 will return the original color and 0 will return black - // + // // NOTE: This is a simple linear blend // ------------------------------------------------------------------------ - RgbColor Dim(uint8_t ratio) const; + constexpr RgbColor Dim(uint8_t ratio) const; // ------------------------------------------------------------------------ // Brighten will return a new color that is blended to white with the given ratio // ratio - (0-255) where 255 will return the original color and 0 will return white - // + // // NOTE: This is a simple linear blend // ------------------------------------------------------------------------ - RgbColor Brighten(uint8_t ratio) const; + constexpr RgbColor Brighten(uint8_t ratio) const; // ------------------------------------------------------------------------ // Darken will adjust the color by the given delta toward black // NOTE: This is a simple linear change // delta - (0-255) the amount to dim the color // ------------------------------------------------------------------------ - void Darken(uint8_t delta); + constexpr void Darken(uint8_t delta); // ------------------------------------------------------------------------ // Lighten will adjust the color by the given delta toward white // NOTE: This is a simple linear change // delta - (0-255) the amount to lighten the color // ------------------------------------------------------------------------ - void Lighten(uint8_t delta); + constexpr void Lighten(uint8_t delta); // ------------------------------------------------------------------------ // LinearBlend between two colors by the amount defined by progress variable @@ -132,8 +123,8 @@ struct RgbColor // progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right // and a value between will blend the color weighted linearly between them // ------------------------------------------------------------------------ - static RgbColor LinearBlend(const RgbColor& left, const RgbColor& right, float progress); - + static constexpr RgbColor LinearBlend(const RgbColor& left, const RgbColor& right, float progress); + // ------------------------------------------------------------------------ // BilinearBlend between four colors by the amount defined by 2d variable // c00 - upper left quadrant color @@ -143,51 +134,310 @@ struct RgbColor // x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space // y - unit value (0.0 - 1.0) that defines the blend progress in vertical space // ------------------------------------------------------------------------ - static RgbColor BilinearBlend(const RgbColor& c00, - const RgbColor& c01, - const RgbColor& c10, - const RgbColor& c11, - float x, + static constexpr RgbColor BilinearBlend(const RgbColor& c00, + const RgbColor& c01, + const RgbColor& c10, + const RgbColor& c11, + float x, float y); - uint32_t CalcTotalTenthMilliAmpere(const SettingsObject& settings) - { - auto total = 0; - - total += R * settings.RedTenthMilliAmpere / 255; - total += G * settings.GreenTenthMilliAmpere / 255; - total += B * settings.BlueTenthMilliAmpere / 255; - - return total; - } + constexpr uint32_t CalcTotalTenthMilliAmpere(const SettingsObject& settings) const; // ------------------------------------------------------------------------ - // Red, Green, Blue color members (0-255) where + // Red, Green, Blue color members (0-255) where // (0,0,0) is black and (255,255,255) is white // ------------------------------------------------------------------------ - uint8_t R; - uint8_t G; - uint8_t B; + uint8_t R{}; + uint8_t G{}; + uint8_t B{}; private: - inline static uint8_t _elementDim(uint8_t value, uint8_t ratio) - { - return (static_cast(value) * (static_cast(ratio) + 1)) >> 8; - } - - inline static uint8_t _elementBrighten(uint8_t value, uint8_t ratio) - { - uint16_t element = ((static_cast(value) + 1) << 8) / (static_cast(ratio) + 1); - - if (element > 255) - { - element = 255; - } - else - { - element -= 1; - } - return element; - } + inline static constexpr uint8_t _elementDim(uint8_t value, uint8_t ratio); + inline static constexpr uint8_t _elementBrighten(uint8_t value, uint8_t ratio); + inline static constexpr float _CalcColor(float p, float q, float t); + inline static constexpr RgbColor convertToRgbColor(const HslColor& color); + inline static constexpr RgbColor convertToRgbColor(const HsbColor& color); }; +#include "HslColor.h" +#include "HsbColor.h" + +constexpr RgbColor::RgbColor() = default; + +constexpr RgbColor::RgbColor(uint8_t r, uint8_t g, uint8_t b) : + R{r}, G{g}, B{b} +{ +} + +constexpr RgbColor::RgbColor(uint8_t brightness) : + R{brightness}, G{brightness}, B{brightness} +{ +} + +constexpr RgbColor::RgbColor(const RgbColor& color) = default; + +constexpr RgbColor::RgbColor(const HslColor& color) : + RgbColor{convertToRgbColor(color)} +{ +} + +constexpr RgbColor::RgbColor(const HsbColor& color) : + RgbColor{convertToRgbColor(color)} +{ +} + +constexpr bool RgbColor::operator==(const RgbColor& other) const +{ + return (R == other.R && G == other.G && B == other.B); +}; + +constexpr bool RgbColor::operator!=(const RgbColor& other) const +{ + return !(*this == other); +}; + +constexpr uint8_t RgbColor::CalculateBrightness() const +{ + return (uint8_t)(((uint16_t)R + (uint16_t)G + (uint16_t)B) / 3); +} + +constexpr RgbColor RgbColor::Dim(uint8_t ratio) const +{ + // specifically avoids float math + return RgbColor(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio)); +} + +constexpr RgbColor RgbColor::Brighten(uint8_t ratio) const +{ + // specifically avoids float math + return RgbColor(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio)); +} + +constexpr void RgbColor::Darken(uint8_t delta) +{ + if (R > delta) + { + R -= delta; + } + else + { + R = 0; + } + + if (G > delta) + { + G -= delta; + } + else + { + G = 0; + } + + if (B > delta) + { + B -= delta; + } + else + { + B = 0; + } +} + +constexpr void RgbColor::Lighten(uint8_t delta) +{ + if (R < 255 - delta) + { + R += delta; + } + else + { + R = 255; + } + + if (G < 255 - delta) + { + G += delta; + } + else + { + G = 255; + } + + if (B < 255 - delta) + { + B += delta; + } + else + { + B = 255; + } +} + +constexpr RgbColor RgbColor::LinearBlend(const RgbColor& left, const RgbColor& right, float progress) +{ + return RgbColor( left.R + ((right.R - left.R) * progress), + left.G + ((right.G - left.G) * progress), + left.B + ((right.B - left.B) * progress)); +} + +constexpr RgbColor RgbColor::BilinearBlend(const RgbColor& c00, + const RgbColor& c01, + const RgbColor& c10, + const RgbColor& c11, + float x, + float y) +{ + float v00 = (1.0f - x) * (1.0f - y); + float v10 = x * (1.0f - y); + float v01 = (1.0f - x) * y; + float v11 = x * y; + + return RgbColor( + c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11, + c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11, + c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11); +} + +constexpr uint32_t RgbColor::CalcTotalTenthMilliAmpere(const SettingsObject& settings) const +{ + auto total = 0; + + total += R * settings.RedTenthMilliAmpere / 255; + total += G * settings.GreenTenthMilliAmpere / 255; + total += B * settings.BlueTenthMilliAmpere / 255; + + return total; +} + +constexpr uint8_t RgbColor::_elementDim(uint8_t value, uint8_t ratio) +{ + return (static_cast(value) * (static_cast(ratio) + 1)) >> 8; +} + +constexpr uint8_t RgbColor::_elementBrighten(uint8_t value, uint8_t ratio) +{ + uint16_t element = ((static_cast(value) + 1) << 8) / (static_cast(ratio) + 1); + + if (element > 255) + { + element = 255; + } + else + { + element -= 1; + } + return element; +} + +constexpr float RgbColor::_CalcColor(float p, float q, float t) +{ + if (t < 0.0f) + t += 1.0f; + if (t > 1.0f) + t -= 1.0f; + + if (t < 1.0f / 6.0f) + return p + (q - p) * 6.0f * t; + + if (t < 0.5f) + return q; + + if (t < 2.0f / 3.0f) + return p + ((q - p) * (2.0f / 3.0f - t) * 6.0f); + + return p; +} + +constexpr RgbColor RgbColor::convertToRgbColor(const HslColor& color) +{ + float r{}; + float g{}; + float b{}; + + float h = color.H; + float s = color.S; + float l = color.L; + + if (color.S == 0.0f || color.L == 0.0f) + { + r = g = b = l; // achromatic or black + } + else + { + float q = l < 0.5f ? l * (1.0f + s) : l + s - (l * s); + float p = 2.0f * l - q; + r = _CalcColor(p, q, h + 1.0f / 3.0f); + g = _CalcColor(p, q, h); + b = _CalcColor(p, q, h - 1.0f / 3.0f); + } + + return RgbColor{(uint8_t)(r * 255.0f), (uint8_t)(g * 255.0f), (uint8_t)(b * 255.0f)}; +} + +constexpr RgbColor RgbColor::convertToRgbColor(const HsbColor& color) +{ + float r{}; + float g{}; + float b{}; + + float h = color.H; + float s = color.S; + float v = color.B; + + if (color.S == 0.0f) + { + r = g = b = v; // achromatic or black + } + else + { + if (h < 0.0f) + { + h += 1.0f; + } + else if (h >= 1.0f) + { + h -= 1.0f; + } + h *= 6.0f; + int i = (int)h; + float f = h - i; + float q = v * (1.0f - s * f); + float p = v * (1.0f - s); + float t = v * (1.0f - s * (1.0f - f)); + switch (i) + { + case 0: + r = v; + g = t; + b = p; + break; + case 1: + r = q; + g = v; + b = p; + break; + case 2: + r = p; + g = v; + b = t; + break; + case 3: + r = p; + g = q; + b = v; + break; + case 4: + r = t; + g = p; + b = v; + break; + default: + r = v; + g = p; + b = q; + break; + } + } + + return RgbColor{(uint8_t)(r * 255.0f), (uint8_t)(g * 255.0f), (uint8_t)(b * 255.0f)}; +} diff --git a/src/internal/RgbwColor.cpp b/src/internal/RgbwColor.cpp deleted file mode 100644 index 81d89ed..0000000 --- a/src/internal/RgbwColor.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/*------------------------------------------------------------------------- -RgbwColor provides a color object that can be directly consumed by NeoPixelBus - -Written by Michael C. Miller. - -I invest time and resources providing this open source code, -please support me by dontating (see https://github.com/Makuna/NeoPixelBus) - -------------------------------------------------------------------------- -This file is part of the Makuna/NeoPixelBus library. - -NeoPixelBus is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation, either version 3 of -the License, or (at your option) any later version. - -NeoPixelBus is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with NeoPixel. If not, see -. --------------------------------------------------------------------------*/ - -#include "RgbColor.h" -#include "HslColor.h" -#include "HsbColor.h" -#include "RgbwColor.h" - -RgbwColor::RgbwColor(const HslColor& color) -{ - RgbColor rgbColor(color); - *this = rgbColor; -} - -RgbwColor::RgbwColor(const HsbColor& color) -{ - RgbColor rgbColor(color); - *this = rgbColor; -} - -uint8_t RgbwColor::CalculateBrightness() const -{ - uint8_t colorB = (uint8_t)(((uint16_t)R + (uint16_t)G + (uint16_t)B) / 3); - if (W > colorB) - { - return W; - } - else - { - return colorB; - } -} - -RgbwColor RgbwColor::Dim(uint8_t ratio) const -{ - // specifically avoids float math - return RgbwColor(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio), _elementDim(W, ratio)); -} - -RgbwColor RgbwColor::Brighten(uint8_t ratio) const -{ - // specifically avoids float math - return RgbwColor(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio), _elementBrighten(W, ratio)); -} - -void RgbwColor::Darken(uint8_t delta) -{ - if (R > delta) - { - R -= delta; - } - else - { - R = 0; - } - - if (G > delta) - { - G -= delta; - } - else - { - G = 0; - } - - if (B > delta) - { - B -= delta; - } - else - { - B = 0; - } - - if (W > delta) - { - W -= delta; - } - else - { - W = 0; - } -} - -void RgbwColor::Lighten(uint8_t delta) -{ - if (IsColorLess()) - { - if (W < 255 - delta) - { - W += delta; - } - else - { - W = 255; - } - } - else - { - if (R < 255 - delta) - { - R += delta; - } - else - { - R = 255; - } - - if (G < 255 - delta) - { - G += delta; - } - else - { - G = 255; - } - - if (B < 255 - delta) - { - B += delta; - } - else - { - B = 255; - } - } -} - -RgbwColor RgbwColor::LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress) -{ - return RgbwColor( left.R + ((right.R - left.R) * progress), - left.G + ((right.G - left.G) * progress), - left.B + ((right.B - left.B) * progress), - left.W + ((right.W - left.W) * progress) ); -} - -RgbwColor RgbwColor::BilinearBlend(const RgbwColor& c00, - const RgbwColor& c01, - const RgbwColor& c10, - const RgbwColor& c11, - float x, - float y) -{ - float v00 = (1.0f - x) * (1.0f - y); - float v10 = x * (1.0f - y); - float v01 = (1.0f - x) * y; - float v11 = x * y; - - return RgbwColor( - c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11, - c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11, - c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11, - c00.W * v00 + c10.W * v10 + c01.W * v01 + c11.W * v11 ); -} diff --git a/src/internal/RgbwColor.h b/src/internal/RgbwColor.h index e282223..478b316 100644 --- a/src/internal/RgbwColor.h +++ b/src/internal/RgbwColor.h @@ -25,7 +25,9 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #pragma once -#include +#include + +#include "NeoSettings.h" struct RgbColor; struct HslColor; @@ -38,90 +40,68 @@ struct HsbColor; // ------------------------------------------------------------------------ struct RgbwColor { - typedef NeoRgbwCurrentSettings SettingsObject; + using SettingsObject = NeoRgbwCurrentSettings; + + // ------------------------------------------------------------------------ + // Construct a RgbwColor that will have its values set in latter operations + // ------------------------------------------------------------------------ + constexpr RgbwColor(); // ------------------------------------------------------------------------ // Construct a RgbwColor using R, G, B, W values (0-255) // ------------------------------------------------------------------------ - RgbwColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) : - R(r), G(g), B(b), W(w) - { - }; + constexpr RgbwColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0); // ------------------------------------------------------------------------ // Construct a RgbColor using a single brightness value (0-255) // This works well for creating gray tone colors // (0) = black, (255) = white, (128) = gray // ------------------------------------------------------------------------ - RgbwColor(uint8_t brightness) : - R(0), G(0), B(0), W(brightness) - { - }; + constexpr RgbwColor(uint8_t brightness); + + // ------------------------------------------------------------------------ + // Construct a RgbwColor using RgbwColor + // ------------------------------------------------------------------------ + constexpr RgbwColor(const RgbwColor& color); // ------------------------------------------------------------------------ // Construct a RgbwColor using RgbColor // ------------------------------------------------------------------------ - RgbwColor(const RgbColor& color) : - R(color.R), - G(color.G), - B(color.B), - W(0) - { - }; + constexpr RgbwColor(const RgbColor& color); // ------------------------------------------------------------------------ // Construct a RgbwColor using HslColor // ------------------------------------------------------------------------ - RgbwColor(const HslColor& color); + constexpr RgbwColor(const HslColor& color); // ------------------------------------------------------------------------ // Construct a RgbwColor using HsbColor // ------------------------------------------------------------------------ - RgbwColor(const HsbColor& color); - - // ------------------------------------------------------------------------ - // Construct a RgbwColor that will have its values set in latter operations - // CAUTION: The R,G,B, W members are not initialized and may not be consistent - // ------------------------------------------------------------------------ - RgbwColor() - { - }; + constexpr RgbwColor(const HsbColor& color); // ------------------------------------------------------------------------ // Comparison operators // ------------------------------------------------------------------------ - bool operator==(const RgbwColor& other) const - { - return (R == other.R && G == other.G && B == other.B && W == other.W); - }; + constexpr bool operator==(const RgbwColor& other) const; - bool operator!=(const RgbwColor& other) const - { - return !(*this == other); - }; + constexpr bool operator!=(const RgbwColor& other) const; // ------------------------------------------------------------------------ // Returns if the color is grey, all values are equal other than white // ------------------------------------------------------------------------ - bool IsMonotone() const - { - return (R == B && R == G); - }; + constexpr bool IsMonotone() const; // ------------------------------------------------------------------------ // Returns if the color components are all zero, the white component maybe // anything // ------------------------------------------------------------------------ - bool IsColorLess() const - { - return (R == 0 && B == 0 && G == 0); - }; + constexpr bool IsColorLess() const; // ------------------------------------------------------------------------ // CalculateBrightness will calculate the overall brightness // NOTE: This is a simple linear brightness // ------------------------------------------------------------------------ - uint8_t CalculateBrightness() const; + constexpr uint8_t CalculateBrightness() const; // ------------------------------------------------------------------------ // Dim will return a new color that is blended to black with the given ratio @@ -129,7 +109,7 @@ struct RgbwColor // // NOTE: This is a simple linear blend // ------------------------------------------------------------------------ - RgbwColor Dim(uint8_t ratio) const; + constexpr RgbwColor Dim(uint8_t ratio) const; // ------------------------------------------------------------------------ // Brighten will return a new color that is blended to white with the given ratio @@ -137,21 +117,21 @@ struct RgbwColor // // NOTE: This is a simple linear blend // ------------------------------------------------------------------------ - RgbwColor Brighten(uint8_t ratio) const; + constexpr RgbwColor Brighten(uint8_t ratio) const; // ------------------------------------------------------------------------ // Darken will adjust the color by the given delta toward black // NOTE: This is a simple linear change // delta - (0-255) the amount to dim the color // ------------------------------------------------------------------------ - void Darken(uint8_t delta); + constexpr void Darken(uint8_t delta); // ------------------------------------------------------------------------ // Lighten will adjust the color by the given delta toward white // NOTE: This is a simple linear change // delta - (0-255) the amount to lighten the color // ------------------------------------------------------------------------ - void Lighten(uint8_t delta); + constexpr void Lighten(uint8_t delta); // ------------------------------------------------------------------------ // LinearBlend between two colors by the amount defined by progress variable @@ -160,8 +140,8 @@ struct RgbwColor // progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right // and a value between will blend the color weighted linearly between them // ------------------------------------------------------------------------ - static RgbwColor LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress); - + static constexpr RgbwColor LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress); + // ------------------------------------------------------------------------ // BilinearBlend between four colors by the amount defined by 2d variable // c00 - upper left quadrant color @@ -171,54 +151,249 @@ struct RgbwColor // x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space // y - unit value (0.0 - 1.0) that defines the blend progress in vertical space // ------------------------------------------------------------------------ - static RgbwColor BilinearBlend(const RgbwColor& c00, + static constexpr RgbwColor BilinearBlend(const RgbwColor& c00, const RgbwColor& c01, const RgbwColor& c10, const RgbwColor& c11, float x, float y); - uint16_t CalcTotalTenthMilliAmpere(const SettingsObject& settings) - { - auto total = 0; - - total += R * settings.RedTenthMilliAmpere / 255; - total += G * settings.GreenTenthMilliAmpere / 255; - total += B * settings.BlueTenthMilliAmpere / 255; - total += W * settings.WhiteCurrent / 255; - - return total; - } + constexpr uint16_t CalcTotalTenthMilliAmpere(const SettingsObject& settings) const; // ------------------------------------------------------------------------ // Red, Green, Blue, White color members (0-255) where // (0,0,0,0) is black and (255,255,255, 0) and (0,0,0,255) is white // Note (255,255,255,255) is extreme bright white // ------------------------------------------------------------------------ - uint8_t R; - uint8_t G; - uint8_t B; - uint8_t W; + uint8_t R{}; + uint8_t G{}; + uint8_t B{}; + uint8_t W{}; private: - inline static uint8_t _elementDim(uint8_t value, uint8_t ratio) + inline static constexpr uint8_t _elementDim(uint8_t value, uint8_t ratio); + inline static constexpr uint8_t _elementBrighten(uint8_t value, uint8_t ratio); +}; + +#include "RgbColor.h" +#include "HslColor.h" +#include "HsbColor.h" + +constexpr RgbwColor::RgbwColor() = default; + +constexpr RgbwColor::RgbwColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w) : + R{r}, G{g}, B{b}, W{w} +{ +} + +constexpr RgbwColor::RgbwColor(uint8_t brightness) : + R{}, G{}, B{}, W{brightness} +{ +} + +constexpr RgbwColor::RgbwColor(const RgbwColor& color) = default; + +constexpr RgbwColor::RgbwColor(const RgbColor& color) : + R{color.R}, + G{color.G}, + B{color.B}, + W{} +{ +} + +constexpr RgbwColor::RgbwColor(const HslColor& color) : + RgbwColor{RgbColor{color}} +{ +} + +constexpr RgbwColor::RgbwColor(const HsbColor& color) : + RgbwColor{RgbColor{color}} +{ +} + +constexpr bool RgbwColor::operator==(const RgbwColor& other) const +{ + return (R == other.R && G == other.G && B == other.B && W == other.W); +} + +constexpr bool RgbwColor::operator!=(const RgbwColor& other) const +{ + return !(*this == other); +} + +constexpr bool RgbwColor::IsMonotone() const +{ + return (R == B && R == G); +} + +constexpr bool RgbwColor::IsColorLess() const +{ + return (R == 0 && B == 0 && G == 0); +} + +constexpr uint8_t RgbwColor::CalculateBrightness() const +{ + uint8_t colorB = (uint8_t)(((uint16_t)R + (uint16_t)G + (uint16_t)B) / 3); + if (W > colorB) { - return (static_cast(value) * (static_cast(ratio) + 1)) >> 8; + return W; + } + else + { + return colorB; + } +} + +constexpr RgbwColor RgbwColor::Dim(uint8_t ratio) const +{ + // specifically avoids float math + return RgbwColor{_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio), _elementDim(W, ratio)}; +} + +constexpr RgbwColor RgbwColor::Brighten(uint8_t ratio) const +{ + // specifically avoids float math + return RgbwColor{_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio), _elementBrighten(W, ratio)}; +} + +constexpr void RgbwColor::Darken(uint8_t delta) +{ + if (R > delta) + { + R -= delta; + } + else + { + R = 0; } - inline static uint8_t _elementBrighten(uint8_t value, uint8_t ratio) + if (G > delta) { - uint16_t element = ((static_cast(value) + 1) << 8) / (static_cast(ratio) + 1); + G -= delta; + } + else + { + G = 0; + } - if (element > 255) + if (B > delta) + { + B -= delta; + } + else + { + B = 0; + } + + if (W > delta) + { + W -= delta; + } + else + { + W = 0; + } +} + +constexpr void RgbwColor::Lighten(uint8_t delta) +{ + if (IsColorLess()) + { + if (W < 255 - delta) { - element = 255; + W += delta; } else { - element -= 1; + W = 255; } - return element; } -}; + else + { + if (R < 255 - delta) + { + R += delta; + } + else + { + R = 255; + } + if (G < 255 - delta) + { + G += delta; + } + else + { + G = 255; + } + + if (B < 255 - delta) + { + B += delta; + } + else + { + B = 255; + } + } +} + +constexpr RgbwColor RgbwColor::LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress) +{ + return RgbwColor( left.R + ((right.R - left.R) * progress), + left.G + ((right.G - left.G) * progress), + left.B + ((right.B - left.B) * progress), + left.W + ((right.W - left.W) * progress) ); +} + +constexpr RgbwColor RgbwColor::BilinearBlend(const RgbwColor& c00, + const RgbwColor& c01, + const RgbwColor& c10, + const RgbwColor& c11, + float x, + float y) +{ + float v00 = (1.0f - x) * (1.0f - y); + float v10 = x * (1.0f - y); + float v01 = (1.0f - x) * y; + float v11 = x * y; + + return RgbwColor( + c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11, + c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11, + c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11, + c00.W * v00 + c10.W * v10 + c01.W * v01 + c11.W * v11 ); +} + +constexpr uint16_t RgbwColor::CalcTotalTenthMilliAmpere(const SettingsObject& settings) const +{ + auto total = 0; + + total += R * settings.RedTenthMilliAmpere / 255; + total += G * settings.GreenTenthMilliAmpere / 255; + total += B * settings.BlueTenthMilliAmpere / 255; + total += W * settings.WhiteCurrent / 255; + + return total; +} + +constexpr uint8_t RgbwColor::_elementDim(uint8_t value, uint8_t ratio) +{ + return (static_cast(value) * (static_cast(ratio) + 1)) >> 8; +} + +constexpr uint8_t RgbwColor::_elementBrighten(uint8_t value, uint8_t ratio) +{ + uint16_t element = ((static_cast(value) + 1) << 8) / (static_cast(ratio) + 1); + + if (element > 255) + { + element = 255; + } + else + { + element -= 1; + } + return element; +}