From de32dd9cc8109dcbee2cb20cb24e7e17fba9fcdf Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sat, 26 Dec 2020 09:54:21 -0800 Subject: [PATCH] Rgb color enhancements (#391) * Rgb48Color * Rgb16Color * Discord readme --- ReadMe.md | 1 + keywords.txt | 2 + src/NeoPixelBus.h | 4 + src/internal/HsbColor.cpp | 39 +++-- src/internal/HsbColor.h | 8 + src/internal/HslColor.cpp | 35 +++-- src/internal/HslColor.h | 9 ++ src/internal/Rgb16Color.h | 272 ++++++++++++++++++++++++++++++++++ src/internal/Rgb48Color.cpp | 170 +++++++++++++++++++++ src/internal/Rgb48Color.h | 210 ++++++++++++++++++++++++++ src/internal/RgbColor.cpp | 123 +++------------ src/internal/RgbColor.h | 24 +-- src/internal/RgbColorBase.cpp | 134 +++++++++++++++++ src/internal/RgbColorBase.h | 42 ++++++ src/internal/RgbwColor.cpp | 1 + 15 files changed, 940 insertions(+), 134 deletions(-) create mode 100644 src/internal/Rgb16Color.h create mode 100644 src/internal/Rgb48Color.cpp create mode 100644 src/internal/Rgb48Color.h create mode 100644 src/internal/RgbColorBase.cpp create mode 100644 src/internal/RgbColorBase.h diff --git a/ReadMe.md b/ReadMe.md index 51017a9..ab8d6fd 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -12,6 +12,7 @@ Please read this best practices link before connecting your NeoPixels, it will s For quick questions and support: * [Try the new Github Discussions](https://github.com/Makuna/NeoPixelBus/discussions) +* [Discord NeoPixelBus Invitation](https://discord.gg/c6FrysvZyV) or if you are already a member of [Discord Server NeoPixelBus](https://discord.com/channels/789177382221119519/789177382221119521) * Or jump on Gitter [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Makuna/NeoPixelBus?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) diff --git a/keywords.txt b/keywords.txt index ca68e07..0508346 100644 --- a/keywords.txt +++ b/keywords.txt @@ -10,6 +10,8 @@ NeoPixelBus KEYWORD1 NeoPixelSegmentBus KEYWORD1 RgbwColor KEYWORD1 RgbColor KEYWORD1 +Rgb16Color KEYWORD1 +Rgb48Color KEYWORD1 HslColor KEYWORD1 HsbColor KEYWORD1 HtmlColor KEYWORD1 diff --git a/src/NeoPixelBus.h b/src/NeoPixelBus.h index a9ec865..a80a0fd 100644 --- a/src/NeoPixelBus.h +++ b/src/NeoPixelBus.h @@ -51,9 +51,13 @@ License along with NeoPixel. If not, see #include "internal/NeoSettings.h" #include "internal/RgbColor.h" +#include "internal/Rgb16Color.h" +#include "internal/Rgb48Color.h" + #include "internal/HslColor.h" #include "internal/HsbColor.h" #include "internal/HtmlColor.h" + #include "internal/RgbwColor.h" #include "internal/SegmentDigit.h" diff --git a/src/internal/HsbColor.cpp b/src/internal/HsbColor.cpp index e47912f..146ddb8 100644 --- a/src/internal/HsbColor.cpp +++ b/src/internal/HsbColor.cpp @@ -25,22 +25,17 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include "RgbColor.h" +#include "Rgb48Color.h" #include "HsbColor.h" - -HsbColor::HsbColor(const RgbColor& color) +void HsbColor::_RgbToHsb(float r, float g, float b, HsbColor* 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 min = (r < g&& r < b) ? r : (g < b) ? g : b; float d = max - min; - float h = 0.0; + float h = 0.0; float v = max; float s = (v == 0.0f) ? 0 : (d / v); @@ -62,7 +57,27 @@ HsbColor::HsbColor(const RgbColor& color) } - H = h; - S = s; - B = v; + color->H = h; + color->S = s; + color->B = v; +} + +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; + + _RgbToHsb(r, g, b, this); +} + +HsbColor::HsbColor(const Rgb48Color& color) +{ + // convert colors to float between (0.0 - 1.0) + float r = color.R / 65535.0f; + float g = color.G / 65535.0f; + float b = color.B / 65535.0f; + + _RgbToHsb(r, g, b, this); } diff --git a/src/internal/HsbColor.h b/src/internal/HsbColor.h index 4d0bdfa..939d5a1 100644 --- a/src/internal/HsbColor.h +++ b/src/internal/HsbColor.h @@ -48,6 +48,11 @@ struct HsbColor // ------------------------------------------------------------------------ HsbColor(const RgbColor& color); + // ------------------------------------------------------------------------ + // Construct a HsbColor using Rgb48Color + // ------------------------------------------------------------------------ + HsbColor(const Rgb48Color& 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 @@ -109,5 +114,8 @@ struct HsbColor float H; float S; float B; + +private: + static void _RgbToHsb(float r, float g, float b, HsbColor* color); }; diff --git a/src/internal/HslColor.cpp b/src/internal/HslColor.cpp index ce9b238..92ae687 100644 --- a/src/internal/HslColor.cpp +++ b/src/internal/HslColor.cpp @@ -26,16 +26,11 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include "RgbColor.h" +#include "Rgb48Color.h" #include "HslColor.h" - -HslColor::HslColor(const RgbColor& color) +void HslColor::_RgbToHsl(float r, float g, float b, HslColor* 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; @@ -66,7 +61,27 @@ HslColor::HslColor(const RgbColor& color) h /= 6.0f; } - H = h; - S = s; - L = l; + color->H = h; + color->S = s; + color->L = l; +} + +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; + + _RgbToHsl(r, g, b, this); +} + +HslColor::HslColor(const Rgb48Color& color) +{ + // convert colors to float between (0.0 - 1.0) + float r = color.R / 65535.0f; + float g = color.G / 65535.0f; + float b = color.B / 65535.0f; + + _RgbToHsl(r, g, b, this); } diff --git a/src/internal/HslColor.h b/src/internal/HslColor.h index f6988bd..3555a5c 100644 --- a/src/internal/HslColor.h +++ b/src/internal/HslColor.h @@ -49,6 +49,11 @@ struct HslColor // ------------------------------------------------------------------------ HslColor(const RgbColor& color); + // ------------------------------------------------------------------------ + // Construct a HslColor using Rgb48Color + // ------------------------------------------------------------------------ + HslColor(const Rgb48Color& 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 @@ -109,5 +114,9 @@ struct HslColor float H; float S; float L; + +private: + static void _RgbToHsl(float r, float g, float b, HslColor* color); + }; diff --git a/src/internal/Rgb16Color.h b/src/internal/Rgb16Color.h new file mode 100644 index 0000000..c038c4c --- /dev/null +++ b/src/internal/Rgb16Color.h @@ -0,0 +1,272 @@ +/*------------------------------------------------------------------------- +Rgb16Color provides a color object that stores in only 16 bits, aka 565 format + +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 +. +-------------------------------------------------------------------------*/ +#pragma once + +#include +#include "NeoSettings.h" +#include "RgbColorBase.h" + + +// ------------------------------------------------------------------------ +// Rgb16Color represents a color object that is represented by Red, Green, Blue +// component values stored in a single 16 bit value using 565 model. +// It contains helpful color routines to manipulate the color. +// ------------------------------------------------------------------------ +struct Rgb16Color : RgbColorBase +{ + typedef NeoRgbCurrentSettings SettingsObject; + + // ------------------------------------------------------------------------ + // Construct a Rgb16Color using R, G, B values (0-255) + // ------------------------------------------------------------------------ + Rgb16Color(uint8_t r, uint8_t g, uint8_t b) + { + setR(r); + setG(g); + setB(b); + }; + + // ------------------------------------------------------------------------ + // Construct a Rgb16Color using a single brightness value (0-255) + // This works well for creating gray tone colors + // (0) = black, (255) = white, (128) = gray + // ------------------------------------------------------------------------ + Rgb16Color(uint8_t brightness) + { + setR(brightness); + setG(brightness); + setB(brightness); + }; + + // ------------------------------------------------------------------------ + // Construct a Rgb16Color using HtmlColor + // ------------------------------------------------------------------------ + Rgb16Color(const HtmlColor& color) + { + RgbColor converted = color; + + setR(converted.R); + setG(converted.G); + setB(converted.B); + }; + + // ------------------------------------------------------------------------ + // Construct a Rgb16Color using HslColor + // ------------------------------------------------------------------------ + Rgb16Color(const HslColor& color) + { + RgbColor converted = color; + + setR(converted.R); + setG(converted.G); + setB(converted.B); + }; + + // ------------------------------------------------------------------------ + // Construct a Rgb16Color using HsbColor + // ------------------------------------------------------------------------ + Rgb16Color(const HsbColor& color) + { + RgbColor converted = color; + + setR(converted.R); + setG(converted.G); + setB(converted.B); + }; + + // ------------------------------------------------------------------------ + // Construct a Rgb16Color that will have its values set in latter operations + // CAUTION: The _c members are not initialized and may not be consistent + // ------------------------------------------------------------------------ + Rgb16Color() + { + }; + + // ------------------------------------------------------------------------ + // properties + // ------------------------------------------------------------------------ + void setR(uint8_t r) + { + _c &= 0x07ff; + _c |= ((r & 0xf8) << 8); + }; + uint8_t getR() const + { + return (_c & 0xf800) >> 8; + }; + + void setG(uint8_t g) + { + _c &= 0xf81f; + _c |= ((g & 0xfe) << 3); + }; + uint8_t getG() const + { + return (_c & 0x07e0) >> 3; + }; + + void setB(uint8_t b) + { + _c &= 0xffe0; + _c |= ((b & 0xf8) >> 3); + }; + uint8_t getB() const + { + return (_c & 0x001f) << 3; + }; + + + // ------------------------------------------------------------------------ + // Comparison operators + // ------------------------------------------------------------------------ + bool operator==(const Rgb16Color& other) const + { + return (_c == other._c); + }; + + bool operator!=(const Rgb16Color& other) const + { + return !(*this == other); + }; + + // ------------------------------------------------------------------------ + // CalculateBrightness will calculate the overall brightness + // NOTE: This is a simple linear brightness + // ------------------------------------------------------------------------ + uint8_t CalculateBrightness() const + { + RgbColor converted = *this; + return converted.CalculateBrightness(); + }; + + // ------------------------------------------------------------------------ + // 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 + // ------------------------------------------------------------------------ + Rgb16Color Dim(uint8_t ratio) const + { + RgbColor converted = *this; + RgbColor result = converted.Dim(ratio); + + return Rgb16Color(result.R, result.G, result.B); + }; + + // ------------------------------------------------------------------------ + // 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 + // ------------------------------------------------------------------------ + Rgb16Color Brighten(uint8_t ratio) const + { + RgbColor converted = *this; + RgbColor result = converted.Brighten(ratio); + + return Rgb16Color(result.R, result.G, result.B); + }; + + // ------------------------------------------------------------------------ + // 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) + { + RgbColor converted = *this; + + converted.Darken(delta); + setR(converted.R); + setG(converted.G); + setB(converted.B); + }; + + // ------------------------------------------------------------------------ + // 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) + { + RgbColor converted = *this; + + converted.Lighten(delta); + setR(converted.R); + setG(converted.G); + setB(converted.B); + }; + + // ------------------------------------------------------------------------ + // LinearBlend between two colors by the amount defined by progress variable + // left - the color to start the blend at + // right - the color to end the blend at + // 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 Rgb16Color LinearBlend(const Rgb16Color& left, const Rgb16Color& right, float progress) + { + RgbColor result = RgbColor::LinearBlend(left, right, progress); + + return Rgb16Color(result.R, result.G, result.B); + }; + + // ------------------------------------------------------------------------ + // BilinearBlend between four colors by the amount defined by 2d variable + // c00 - upper left quadrant color + // c01 - upper right quadrant color + // c10 - lower left quadrant color + // c11 - lower right quadrant color + // 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 Rgb16Color BilinearBlend(const Rgb16Color& c00, + const Rgb16Color& c01, + const Rgb16Color& c10, + const Rgb16Color& c11, + float x, + float y) + { + RgbColor result = RgbColor::BilinearBlend(c00, c01, c10, c11, x, y); + + return Rgb16Color(result.R, result.G, result.B); + }; + + uint32_t CalcTotalTenthMilliAmpere(const SettingsObject& settings) + { + auto total = 0; + + total += getR() * settings.RedTenthMilliAmpere / 255; + total += getG() * settings.GreenTenthMilliAmpere / 255; + total += getB() * settings.BlueTenthMilliAmpere / 255; + + return total; + }; + +protected: + uint16_t _c; +}; + diff --git a/src/internal/Rgb48Color.cpp b/src/internal/Rgb48Color.cpp new file mode 100644 index 0000000..3743ac5 --- /dev/null +++ b/src/internal/Rgb48Color.cpp @@ -0,0 +1,170 @@ +/*------------------------------------------------------------------------- +Rgb48Color 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 "Rgb48Color.h" +#include "RgbColor.h" +#include "HslColor.h" +#include "HsbColor.h" +#include "HtmlColor.h" + +Rgb48Color::Rgb48Color(const HtmlColor& color) +{ + uint32_t temp = color.Color; + + B = (temp & 0xff); + temp = temp >> 8; + G = (temp & 0xff); + temp = temp >> 8; + R = (temp & 0xff); +}; + +Rgb48Color::Rgb48Color(const HslColor& color) +{ + float r; + float g; + float b; + + _HslToRgb(color, &r, &g, &b); + + R = (uint16_t)(r * Max); + G = (uint16_t)(g * Max); + B = (uint16_t)(b * Max); +} + +Rgb48Color::Rgb48Color(const HsbColor& color) +{ + float r; + float g; + float b; + + _HsbToRgb(color, &r, &g, &b); + + R = (uint16_t)(r * Max); + G = (uint16_t)(g * Max); + B = (uint16_t)(b * Max); +} + +uint16_t Rgb48Color::CalculateBrightness() const +{ + return (uint16_t)(((uint32_t)R + (uint32_t)G + (uint32_t)B) / 3); +} + +Rgb48Color Rgb48Color::Dim(uint16_t ratio) const +{ + // specifically avoids float math + return Rgb48Color(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio)); +} + +Rgb48Color Rgb48Color::Brighten(uint16_t ratio) const +{ + // specifically avoids float math + return Rgb48Color(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio)); +} + +void Rgb48Color::Darken(uint16_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 Rgb48Color::Lighten(uint16_t delta) +{ + if (R < Max - delta) + { + R += delta; + } + else + { + R = Max; + } + + if (G < Max - delta) + { + G += delta; + } + else + { + G = Max; + } + + if (B < Max - delta) + { + B += delta; + } + else + { + B = Max; + } +} + +Rgb48Color Rgb48Color::LinearBlend(const Rgb48Color& left, const Rgb48Color& right, float progress) +{ + return Rgb48Color( left.R + ((right.R - left.R) * progress), + left.G + ((right.G - left.G) * progress), + left.B + ((right.B - left.B) * progress)); +} + +Rgb48Color Rgb48Color::BilinearBlend(const Rgb48Color& c00, + const Rgb48Color& c01, + const Rgb48Color& c10, + const Rgb48Color& 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 Rgb48Color( + 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); +} \ No newline at end of file diff --git a/src/internal/Rgb48Color.h b/src/internal/Rgb48Color.h new file mode 100644 index 0000000..eb35142 --- /dev/null +++ b/src/internal/Rgb48Color.h @@ -0,0 +1,210 @@ +/*------------------------------------------------------------------------- +Rgb48Color provides a color object that contains 16bit color elements + +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 +. +-------------------------------------------------------------------------*/ +#pragma once + +#include +#include "NeoSettings.h" +#include "RgbColorBase.h" +#include "RgbColor.h" + + +// ------------------------------------------------------------------------ +// Rgb48Color represents a color object that is represented by Red, Green, Blue +// component values. It contains helpful color routines to manipulate the +// color. +// ------------------------------------------------------------------------ +struct Rgb48Color : RgbColorBase +{ + typedef NeoRgbCurrentSettings SettingsObject; + + // ------------------------------------------------------------------------ + // Construct a Rgb48Color using R, G, B values (0-65535) + // ------------------------------------------------------------------------ + Rgb48Color(uint16_t r, uint16_t g, uint16_t b) : + R(r), G(g), B(b) + { + }; + + // ------------------------------------------------------------------------ + // Construct a Rgb48Color using a single brightness value (0-65535) + // This works well for creating gray tone colors + // (0) = black, (65535) = white, (32768) = gray + // ------------------------------------------------------------------------ + Rgb48Color(uint16_t brightness) : + R(brightness), G(brightness), B(brightness) + { + }; + + // ------------------------------------------------------------------------ + // Construct a Rgb48Color using RgbColor + // ------------------------------------------------------------------------ + Rgb48Color(const RgbColor& color) + { + R = (color.R == 0) ? 0 : (color.R << 8 | 0xff); + G = (color.G == 0) ? 0 : (color.G << 8 | 0xff); + B = (color.B == 0) ? 0 : (color.B << 8 | 0xff); + } + + // ------------------------------------------------------------------------ + // Construct a Rgb48Color using HtmlColor + // ------------------------------------------------------------------------ + Rgb48Color(const HtmlColor& color); + + // ------------------------------------------------------------------------ + // Construct a Rgb48Color using HslColor + // ------------------------------------------------------------------------ + Rgb48Color(const HslColor& color); + + // ------------------------------------------------------------------------ + // Construct a Rgb48Color using HsbColor + // ------------------------------------------------------------------------ + Rgb48Color(const HsbColor& color); + + // ------------------------------------------------------------------------ + // Construct a Rgb48Color that will have its values set in latter operations + // CAUTION: The R,G,B members are not initialized and may not be consistent + // ------------------------------------------------------------------------ + Rgb48Color() + { + }; + + // ------------------------------------------------------------------------ + // Comparison operators + // ------------------------------------------------------------------------ + bool operator==(const Rgb48Color& other) const + { + return (R == other.R && G == other.G && B == other.B); + }; + + bool operator!=(const Rgb48Color& other) const + { + return !(*this == other); + }; + + // ------------------------------------------------------------------------ + // CalculateBrightness will calculate the overall brightness + // NOTE: This is a simple linear brightness + // ------------------------------------------------------------------------ + uint16_t CalculateBrightness() const; + + // ------------------------------------------------------------------------ + // Dim will return a new color that is blended to black with the given ratio + // ratio - (0-65535) where 65535 will return the original color and 0 will return black + // + // NOTE: This is a simple linear blend + // ------------------------------------------------------------------------ + Rgb48Color Dim(uint16_t ratio) const; + + // ------------------------------------------------------------------------ + // Brighten will return a new color that is blended to white with the given ratio + // ratio - (0-65535) where 65535 will return the original color and 0 will return white + // + // NOTE: This is a simple linear blend + // ------------------------------------------------------------------------ + Rgb48Color Brighten(uint16_t ratio) const; + + // ------------------------------------------------------------------------ + // Darken will adjust the color by the given delta toward black + // NOTE: This is a simple linear change + // delta - (0-65535) the amount to dim the color + // ------------------------------------------------------------------------ + void Darken(uint16_t delta); + + // ------------------------------------------------------------------------ + // Lighten will adjust the color by the given delta toward white + // NOTE: This is a simple linear change + // delta - (0-65535) the amount to lighten the color + // ------------------------------------------------------------------------ + void Lighten(uint16_t delta); + + // ------------------------------------------------------------------------ + // LinearBlend between two colors by the amount defined by progress variable + // left - the color to start the blend at + // right - the color to end the blend at + // 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 Rgb48Color LinearBlend(const Rgb48Color& left, const Rgb48Color& right, float progress); + + // ------------------------------------------------------------------------ + // BilinearBlend between four colors by the amount defined by 2d variable + // c00 - upper left quadrant color + // c01 - upper right quadrant color + // c10 - lower left quadrant color + // c11 - lower right quadrant color + // 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 Rgb48Color BilinearBlend(const Rgb48Color& c00, + const Rgb48Color& c01, + const Rgb48Color& c10, + const Rgb48Color& c11, + float x, + float y); + + uint32_t CalcTotalTenthMilliAmpere(const SettingsObject& settings) + { + auto total = 0; + + total += R * settings.RedTenthMilliAmpere / Max; + total += G * settings.GreenTenthMilliAmpere / Max; + total += B * settings.BlueTenthMilliAmpere / Max; + + return total; + } + + // ------------------------------------------------------------------------ + // Red, Green, Blue color members (0-65535) where + // (0,0,0) is black and (65535,65535,65535) is white + // ------------------------------------------------------------------------ + uint16_t R; + uint16_t G; + uint16_t B; + + const static uint16_t Max = 65535; + +private: + inline static uint16_t _elementDim(uint16_t value, uint16_t ratio) + { + return (static_cast(value) * (static_cast(ratio) + 1)) >> 8; + } + + inline static uint16_t _elementBrighten(uint16_t value, uint16_t ratio) + { + uint32_t element = ((static_cast(value) + 1) << 8) / (static_cast(ratio) + 1); + + if (element > Max) + { + element = Max; + } + else + { + element -= 1; + } + return element; + } +}; + diff --git a/src/internal/RgbColor.cpp b/src/internal/RgbColor.cpp index 30a7811..c2692ed 100644 --- a/src/internal/RgbColor.cpp +++ b/src/internal/RgbColor.cpp @@ -25,27 +25,17 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include "RgbColor.h" +#include "Rgb16Color.h" +#include "Rgb48Color.h" #include "HslColor.h" #include "HsbColor.h" #include "HtmlColor.h" -static float _CalcColor(float p, float q, float t) +RgbColor::RgbColor(const Rgb16Color& color) { - 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; + R = color.getR(); + G = color.getG(); + B = color.getB(); } RgbColor::RgbColor(const HtmlColor& color) @@ -65,27 +55,11 @@ RgbColor::RgbColor(const HslColor& color) float g; float b; - float h = color.H; - float s = color.S; - float l = color.L; + _HslToRgb(color, &r, &g, &b); - - 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); + R = (uint8_t)(r * Max); + G = (uint8_t)(g * Max); + B = (uint8_t)(b * Max); } RgbColor::RgbColor(const HsbColor& color) @@ -94,68 +68,11 @@ RgbColor::RgbColor(const HsbColor& color) float g; float b; - float h = color.H; - float s = color.S; - float v = color.B; + _HsbToRgb(color, &r, &g, &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); + R = (uint8_t)(r * Max); + G = (uint8_t)(g * Max); + B = (uint8_t)(b * Max); } uint8_t RgbColor::CalculateBrightness() const @@ -207,31 +124,31 @@ void RgbColor::Darken(uint8_t delta) void RgbColor::Lighten(uint8_t delta) { - if (R < 255 - delta) + if (R < Max - delta) { R += delta; } else { - R = 255; + R = Max; } - if (G < 255 - delta) + if (G < Max - delta) { G += delta; } else { - G = 255; + G = Max; } - if (B < 255 - delta) + if (B < Max - delta) { B += delta; } else { - B = 255; + B = Max; } } diff --git a/src/internal/RgbColor.h b/src/internal/RgbColor.h index b50857b..cdbcf22 100644 --- a/src/internal/RgbColor.h +++ b/src/internal/RgbColor.h @@ -27,17 +27,15 @@ License along with NeoPixel. If not, see #include #include "NeoSettings.h" +#include "RgbColorBase.h" -struct HslColor; -struct HsbColor; -struct HtmlColor; // ------------------------------------------------------------------------ // RgbColor represents a color object that is represented by Red, Green, Blue // component values. It contains helpful color routines to manipulate the // color. // ------------------------------------------------------------------------ -struct RgbColor +struct RgbColor : RgbColorBase { typedef NeoRgbCurrentSettings SettingsObject; @@ -59,6 +57,11 @@ struct RgbColor { }; + // ------------------------------------------------------------------------ + // Construct a RgbColor using Rgb16Color + // ------------------------------------------------------------------------ + RgbColor(const Rgb16Color& color); + // ------------------------------------------------------------------------ // Construct a RgbColor using HtmlColor // ------------------------------------------------------------------------ @@ -74,6 +77,7 @@ struct RgbColor // ------------------------------------------------------------------------ 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 @@ -160,9 +164,9 @@ struct RgbColor { auto total = 0; - total += R * settings.RedTenthMilliAmpere / 255; - total += G * settings.GreenTenthMilliAmpere / 255; - total += B * settings.BlueTenthMilliAmpere / 255; + total += R * settings.RedTenthMilliAmpere / Max; + total += G * settings.GreenTenthMilliAmpere / Max; + total += B * settings.BlueTenthMilliAmpere / Max; return total; } @@ -175,6 +179,8 @@ struct RgbColor uint8_t G; uint8_t B; + const static uint8_t Max = 255; + private: inline static uint8_t _elementDim(uint8_t value, uint8_t ratio) { @@ -185,9 +191,9 @@ private: { uint16_t element = ((static_cast(value) + 1) << 8) / (static_cast(ratio) + 1); - if (element > 255) + if (element > Max) { - element = 255; + element = Max; } else { diff --git a/src/internal/RgbColorBase.cpp b/src/internal/RgbColorBase.cpp new file mode 100644 index 0000000..ad0eb82 --- /dev/null +++ b/src/internal/RgbColorBase.cpp @@ -0,0 +1,134 @@ +/*------------------------------------------------------------------------- +RgbColorBase provides a RGB color object common support + +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 "RgbColorBase.h" +#include "RgbColor.h" +#include "Rgb48Color.h" +#include "HslColor.h" +#include "HsbColor.h" +#include "HtmlColor.h" + +float RgbColorBase::_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; +} + +void RgbColorBase::_HslToRgb(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); + } +} + +void RgbColorBase::_HsbToRgb(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; + } + } +} \ No newline at end of file diff --git a/src/internal/RgbColorBase.h b/src/internal/RgbColorBase.h new file mode 100644 index 0000000..689fe88 --- /dev/null +++ b/src/internal/RgbColorBase.h @@ -0,0 +1,42 @@ +/*------------------------------------------------------------------------- +RgbColorBase provides a RGB color object common support + +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 +. +-------------------------------------------------------------------------*/ +#pragma once + +struct HslColor; +struct HsbColor; +struct HtmlColor; +struct Rgb16Color; + +struct RgbColorBase +{ + +protected: + static float _CalcColor(float p, float q, float t); + + static void _HslToRgb(const HslColor& color, float* r, float* g, float* b); + + static void _HsbToRgb(const HsbColor& color, float* r, float* g, float* b); +}; \ No newline at end of file diff --git a/src/internal/RgbwColor.cpp b/src/internal/RgbwColor.cpp index cb9681f..d73c7c9 100644 --- a/src/internal/RgbwColor.cpp +++ b/src/internal/RgbwColor.cpp @@ -25,6 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include "RgbColor.h" +#include "Rgb48Color.h" #include "HslColor.h" #include "HsbColor.h" #include "RgbwColor.h"