From 2040a4837da0014840c3264d7510fc13fbd9d671 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sun, 10 Oct 2021 17:45:48 -0700 Subject: [PATCH] Ucs890x (#517) --- keywords.txt | 5 + src/NeoPixelBus.h | 2 + src/internal/NeoColorFeatures.h | 299 +++++++++++++++++++++++--- src/internal/NeoTm1814ColorFeatures.h | 4 +- src/internal/NeoTm1914ColorFeatures.h | 6 +- src/internal/Rgb48Color.cpp | 11 - src/internal/Rgb48Color.h | 13 +- src/internal/Rgbw64Color.cpp | 188 ++++++++++++++++ src/internal/Rgbw64Color.h | 248 +++++++++++++++++++++ src/internal/RgbwColor.h | 14 +- 10 files changed, 737 insertions(+), 53 deletions(-) create mode 100644 src/internal/Rgbw64Color.cpp create mode 100644 src/internal/Rgbw64Color.h diff --git a/keywords.txt b/keywords.txt index 03f59e8..e6c54c1 100644 --- a/keywords.txt +++ b/keywords.txt @@ -12,6 +12,7 @@ RgbwColor KEYWORD1 RgbColor KEYWORD1 Rgb16Color KEYWORD1 Rgb48Color KEYWORD1 +Rgbw64Color KEYWORD1 HslColor KEYWORD1 HsbColor KEYWORD1 HtmlColor KEYWORD1 @@ -25,6 +26,10 @@ NeoRgbwFeature KEYWORD1 NeoRgbFeature KEYWORD1 NeoBrgFeature KEYWORD1 NeoRbgFeature KEYWORD1 +NeoRgbw64Feature KEYWORD1 +NeoRgb48Feature KEYWORD1 +NeoRgbUcs8903Feature KEYWORD1 +NeoRgbwUcs8904Feature KEYWORD1 NeoWrgbTm1814Feature KEYWORD1 NeoRgbTm1914Feature KEYWORD1 NeoGrbTm1914Feature KEYWORD1 diff --git a/src/NeoPixelBus.h b/src/NeoPixelBus.h index 1f06ef5..489432e 100644 --- a/src/NeoPixelBus.h +++ b/src/NeoPixelBus.h @@ -59,6 +59,8 @@ License along with NeoPixel. If not, see #include "internal/HtmlColor.h" #include "internal/RgbwColor.h" +#include "internal/Rgbw64Color.h" + #include "internal/SegmentDigit.h" #include "internal/NeoColorFeatures.h" diff --git a/src/internal/NeoColorFeatures.h b/src/internal/NeoColorFeatures.h index d1494a2..bc4f2a3 100644 --- a/src/internal/NeoColorFeatures.h +++ b/src/internal/NeoColorFeatures.h @@ -26,7 +26,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #pragma once -class Neo3Elements +class Neo3ByteElements { public: static const size_t PixelSize = 3; @@ -64,7 +64,7 @@ public: static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) { uint8_t* pEnd = pPixelDest + (count * PixelSize); - const uint8_t* pSrc = (const uint8_t*)pPixelSrc; + const uint8_t* pSrc = reinterpret_cast(pPixelSrc); while (pPixelDest < pEnd) { *pPixelDest++ = pgm_read_byte(pSrc++); @@ -84,7 +84,7 @@ public: typedef RgbColor ColorObject; }; -class Neo4Elements +class Neo4ByteElements { public: static const size_t PixelSize = 4; @@ -100,8 +100,8 @@ public: static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) { - uint32_t* pDest = (uint32_t*)pPixelDest; - const uint32_t* pSrc = (const uint32_t*)pPixelSrc; + uint32_t* pDest = reinterpret_cast(pPixelDest); + const uint32_t* pSrc = reinterpret_cast(pPixelSrc); uint32_t* pEnd = pDest + count; while (pDest < pEnd) @@ -112,8 +112,8 @@ public: static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) { - uint32_t* pDest = (uint32_t*)pPixelDest; - const uint32_t* pSrc = (uint32_t*)pPixelSrc; + uint32_t* pDest = reinterpret_cast(pPixelDest); + const uint32_t* pSrc = reinterpret_cast(pPixelSrc); uint32_t* pEnd = pDest + count; while (pDest < pEnd) { @@ -123,8 +123,8 @@ public: static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) { - uint32_t* pDest = (uint32_t*)pPixelDest; - const uint32_t* pSrc = (const uint32_t*)pPixelSrc; + uint32_t* pDest = reinterpret_cast(pPixelDest); + const uint32_t* pSrc = reinterpret_cast(pPixelSrc); uint32_t* pEnd = pDest + count; while (pDest < pEnd) { @@ -134,8 +134,8 @@ public: static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) { - uint32_t* pDest = (uint32_t*)pPixelDest; - const uint32_t* pSrc = (uint32_t*)pPixelSrc; + uint32_t* pDest = reinterpret_cast(pPixelDest); + const uint32_t* pSrc = reinterpret_cast(pPixelSrc); uint32_t* pDestBack = pDest + count; const uint32_t* pSrcBack = pSrc + count; while (pDestBack > pDest) @@ -147,8 +147,133 @@ public: typedef RgbwColor ColorObject; }; - -class Neo3ElementsNoSettings : public Neo3Elements +class Neo6ByteElements +{ +public: + static const size_t PixelSize = 6; + + static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + + static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint16_t* pDest = reinterpret_cast(pPixelDest); + const uint16_t* pSrc = reinterpret_cast(pPixelSrc); + + uint16_t* pEnd = pDest + (count * PixelSize / 2); + while (pDest < pEnd) + { + *pDest++ = *pSrc; + } + } + + static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint16_t* pDest = reinterpret_cast(pPixelDest); + const uint16_t* pSrc = reinterpret_cast(pPixelSrc); + uint16_t* pEnd = pDest + (count * PixelSize / 2); + while (pDest < pEnd) + { + *pDest++ = *pSrc++; + } + } + + static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) + { + uint16_t* pDest = reinterpret_cast(pPixelDest); + const uint16_t* pSrc = reinterpret_cast(pPixelSrc); + uint16_t* pEnd = pDest + (count * PixelSize / 2); + while (pDest < pEnd) + { + *pDest++ = pgm_read_word(pSrc++); + } + } + + static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint16_t* pDest = reinterpret_cast(pPixelDest); + const uint16_t* pSrc = reinterpret_cast(pPixelSrc); + uint16_t* pDestBack = pDest + (count * PixelSize / 2); + const uint16_t* pSrcBack = pSrc + (count * PixelSize / 2); + while (pDestBack > pDest) + { + *--pDestBack = *--pSrcBack; + } + } + + typedef Rgb48Color ColorObject; +}; + +class Neo8ByteElements +{ +public: + static const size_t PixelSize = 8; + + static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + + static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint32_t* pDest = reinterpret_cast(pPixelDest); + const uint32_t* pSrc = reinterpret_cast(pPixelSrc); + + uint32_t* pEnd = pDest + (count * PixelSize); + while (pDest < pEnd) + { + *pDest++ = *pSrc; + } + } + + static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint32_t* pDest = reinterpret_cast(pPixelDest); + const uint32_t* pSrc = reinterpret_cast(pPixelSrc); + uint32_t* pEnd = pDest + (count * PixelSize); + while (pDest < pEnd) + { + *pDest++ = *pSrc++; + } + } + + static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) + { + uint32_t* pDest = reinterpret_cast(pPixelDest); + const uint32_t* pSrc = reinterpret_cast(pPixelSrc); + uint32_t* pEnd = pDest + (count * PixelSize); + while (pDest < pEnd) + { + *pDest++ = pgm_read_dword(pSrc++); + } + } + + static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint32_t* pDest = reinterpret_cast(pPixelDest); + const uint32_t* pSrc = reinterpret_cast(pPixelSrc); + uint32_t* pDestBack = pDest + (count * PixelSize); + const uint32_t* pSrcBack = pSrc + (count * PixelSize); + while (pDestBack > pDest) + { + *--pDestBack = *--pSrcBack; + } + } + + typedef Rgbw64Color ColorObject; +}; + +class Neo3ByteElementsNoSettings : public Neo3ByteElements { public: typedef NeoNoSettings SettingsObject; @@ -169,7 +294,7 @@ public: } }; -class Neo4ElementsNoSettings : public Neo4Elements +class Neo4ByteElementsNoSettings : public Neo4ByteElements { public: typedef NeoNoSettings SettingsObject; @@ -190,7 +315,49 @@ public: } }; -class NeoGrbFeature : public Neo3ElementsNoSettings +class Neo6ByteElementsNoSettings : public Neo6ByteElements +{ +public: + typedef NeoNoSettings SettingsObject; + static const size_t SettingsSize = 0; + + static void applySettings(uint8_t*, const SettingsObject&) + { + } + + static uint8_t* pixels(uint8_t* pData) + { + return pData; + } + + static const uint8_t* pixels(const uint8_t* pData) + { + return pData; + } +}; + +class Neo8ByteElementsNoSettings : public Neo8ByteElements +{ +public: + typedef NeoNoSettings SettingsObject; + static const size_t SettingsSize = 0; + + static void applySettings(uint8_t*, const SettingsObject&) + { + } + + static uint8_t* pixels(uint8_t* pData) + { + return pData; + } + + static const uint8_t* pixels(const uint8_t* pData) + { + return pData; + } +}; + +class NeoGrbFeature : public Neo3ByteElementsNoSettings { public: static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) @@ -217,7 +384,7 @@ public: static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) { ColorObject color; - const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + const uint8_t* p = getPixelAddress(reinterpret_cast(pPixels), indexPixel); color.G = pgm_read_byte(p++); color.R = pgm_read_byte(p++); @@ -228,7 +395,7 @@ public: }; -class NeoGrbwFeature : public Neo4ElementsNoSettings +class NeoGrbwFeature : public Neo4ByteElementsNoSettings { public: static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) @@ -258,7 +425,7 @@ public: static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) { ColorObject color; - const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + const uint8_t* p = getPixelAddress(reinterpret_cast(pPixels), indexPixel); color.G = pgm_read_byte(p++); color.R = pgm_read_byte(p++); @@ -270,7 +437,7 @@ public: }; -class NeoRgbwFeature : public Neo4ElementsNoSettings +class NeoRgbwFeature : public Neo4ByteElementsNoSettings { public: static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) @@ -299,7 +466,7 @@ public: static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) { ColorObject color; - const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + const uint8_t* p = getPixelAddress(reinterpret_cast(pPixels), indexPixel); color.R = pgm_read_byte(p++); color.G = pgm_read_byte(p++); @@ -311,7 +478,7 @@ public: }; -class NeoRgbFeature : public Neo3ElementsNoSettings +class NeoRgbFeature : public Neo3ByteElementsNoSettings { public: static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) @@ -338,7 +505,7 @@ public: static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) { ColorObject color; - const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + const uint8_t* p = getPixelAddress(reinterpret_cast(pPixels), indexPixel); color.R = pgm_read_byte(p++); color.G = pgm_read_byte(p++); @@ -349,7 +516,7 @@ public: }; -class NeoBrgFeature : public Neo3ElementsNoSettings +class NeoBrgFeature : public Neo3ByteElementsNoSettings { public: static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) @@ -376,7 +543,7 @@ public: static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) { ColorObject color; - const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + const uint8_t* p = getPixelAddress(reinterpret_cast(pPixels), indexPixel); color.B = pgm_read_byte(p++); color.R = pgm_read_byte(p++); @@ -387,7 +554,7 @@ public: }; -class NeoRbgFeature : public Neo3ElementsNoSettings +class NeoRbgFeature : public Neo3ByteElementsNoSettings { public: static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) @@ -415,7 +582,7 @@ public: static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) { ColorObject color; - const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + const uint8_t* p = getPixelAddress(reinterpret_cast(pPixels), indexPixel); color.R = pgm_read_byte(p++); color.B = pgm_read_byte(p++); @@ -425,3 +592,83 @@ public: } }; + +class NeoRgbw64Feature : public Neo8ByteElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint16_t* p = reinterpret_cast(getPixelAddress(pPixels, indexPixel)); + + *p++ = color.R; + *p++ = color.G; + *p++ = color.B; + *p = color.W; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint16_t* p = reinterpret_cast(getPixelAddress(pPixels, indexPixel)); + + color.R = *p++; + color.G = *p++; + color.B = *p++; + color.W = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint16_t* p = reinterpret_cast(getPixelAddress(reinterpret_cast(pPixels), indexPixel)); + + color.R = pgm_read_word(p++); + color.G = pgm_read_word(p++); + color.B = pgm_read_word(p++); + color.W = pgm_read_word(p); + + return color; + } +}; + +class NeoRgb48Feature : public Neo6ByteElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint16_t* p = reinterpret_cast(getPixelAddress(pPixels, indexPixel)); + + *p++ = color.R; + *p++ = color.G; + *p = color.B; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint16_t* p = reinterpret_cast(getPixelAddress(pPixels, indexPixel)); + + color.R = *p++; + color.G = *p++; + color.B = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint16_t* p = reinterpret_cast(getPixelAddress(reinterpret_cast(pPixels), indexPixel)); + + color.R = pgm_read_word(p++); + color.G = pgm_read_word(p++); + color.B = pgm_read_word(p); + + return color; + } +}; + +typedef NeoRgb48Feature NeoRgbUcs8903Feature; +typedef NeoRgbw64Feature NeoRgbwUcs8904Feature; \ No newline at end of file diff --git a/src/internal/NeoTm1814ColorFeatures.h b/src/internal/NeoTm1814ColorFeatures.h index 00d0dfa..d19a51d 100644 --- a/src/internal/NeoTm1814ColorFeatures.h +++ b/src/internal/NeoTm1814ColorFeatures.h @@ -51,7 +51,7 @@ public: } }; -class Neo4ElementsTm1814Settings : public Neo4Elements +class Neo4ByteElementsTm1814Settings : public Neo4ByteElements { public: typedef NeoTm1814Settings SettingsObject; @@ -88,7 +88,7 @@ public: }; -class NeoWrgbTm1814Feature : public Neo4ElementsTm1814Settings +class NeoWrgbTm1814Feature : public Neo4ByteElementsTm1814Settings { public: static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) diff --git a/src/internal/NeoTm1914ColorFeatures.h b/src/internal/NeoTm1914ColorFeatures.h index 52bc03d..d99572e 100644 --- a/src/internal/NeoTm1914ColorFeatures.h +++ b/src/internal/NeoTm1914ColorFeatures.h @@ -44,7 +44,7 @@ public: NeoTm1914_Mode Mode; }; -class Neo3ElementsTm1914Settings : public Neo3Elements +class Neo3ByteElementsTm1914Settings : public Neo3ByteElements { public: typedef NeoTm1914Settings SettingsObject; @@ -96,7 +96,7 @@ public: }; -class NeoRgbTm1914Feature : public Neo3ElementsTm1914Settings +class NeoRgbTm1914Feature : public Neo3ByteElementsTm1914Settings { public: static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) @@ -135,7 +135,7 @@ public: }; -class NeoGrbTm1914Feature : public Neo3ElementsTm1914Settings +class NeoGrbTm1914Feature : public Neo3ByteElementsTm1914Settings { public: static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) diff --git a/src/internal/Rgb48Color.cpp b/src/internal/Rgb48Color.cpp index ea03f92..6b881b9 100644 --- a/src/internal/Rgb48Color.cpp +++ b/src/internal/Rgb48Color.cpp @@ -30,17 +30,6 @@ License along with NeoPixel. If not, see #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; diff --git a/src/internal/Rgb48Color.h b/src/internal/Rgb48Color.h index eb35142..f9776b1 100644 --- a/src/internal/Rgb48Color.h +++ b/src/internal/Rgb48Color.h @@ -61,17 +61,20 @@ struct Rgb48Color : RgbColorBase // ------------------------------------------------------------------------ // Construct a Rgb48Color using RgbColor // ------------------------------------------------------------------------ - Rgb48Color(const RgbColor& color) + 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); + Rgb48Color(const HtmlColor& color) + { + *this = RgbColor(color); + }; // ------------------------------------------------------------------------ // Construct a Rgb48Color using HslColor @@ -189,12 +192,12 @@ struct Rgb48Color : RgbColorBase private: inline static uint16_t _elementDim(uint16_t value, uint16_t ratio) { - return (static_cast(value) * (static_cast(ratio) + 1)) >> 8; + return (static_cast(value) * (static_cast(ratio) + 1)) >> 16; } inline static uint16_t _elementBrighten(uint16_t value, uint16_t ratio) { - uint32_t element = ((static_cast(value) + 1) << 8) / (static_cast(ratio) + 1); + uint32_t element = ((static_cast(value) + 1) << 16) / (static_cast(ratio) + 1); if (element > Max) { diff --git a/src/internal/Rgbw64Color.cpp b/src/internal/Rgbw64Color.cpp new file mode 100644 index 0000000..9a2a849 --- /dev/null +++ b/src/internal/Rgbw64Color.cpp @@ -0,0 +1,188 @@ +/*------------------------------------------------------------------------- +Rgbw64Color 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 "RgbwColor.h" +#include "Rgb48Color.h" +#include "HslColor.h" +#include "HsbColor.h" +#include "Rgbw64Color.h" +#include "HtmlColor.h" + +Rgbw64Color::Rgbw64Color(const RgbwColor& 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); + W = (color.W == 0) ? 0 : (color.W << 8 | 0xff); +}; + +Rgbw64Color::Rgbw64Color(const HslColor& color) +{ + Rgb48Color rgbColor(color); + *this = rgbColor; +} + +Rgbw64Color::Rgbw64Color(const HsbColor& color) +{ + Rgb48Color rgbColor(color); + *this = rgbColor; +} + +uint16_t Rgbw64Color::CalculateBrightness() const +{ + uint16_t colorB = static_cast((static_cast(R) + static_cast(G) + static_cast(B)) / 3); + if (W > colorB) + { + return W; + } + else + { + return colorB; + } +} + +Rgbw64Color Rgbw64Color::Dim(uint16_t ratio) const +{ + // specifically avoids float math + return Rgbw64Color(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio), _elementDim(W, ratio)); +} + +Rgbw64Color Rgbw64Color::Brighten(uint16_t ratio) const +{ + // specifically avoids float math + return Rgbw64Color(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio), _elementBrighten(W, ratio)); +} + +void Rgbw64Color::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; + } + + if (W > delta) + { + W -= delta; + } + else + { + W = 0; + } +} + +void Rgbw64Color::Lighten(uint16_t delta) +{ + if (IsColorLess()) + { + if (W < Max - delta) + { + W += delta; + } + else + { + W = Max; + } + } + else + { + 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; + } + } +} + +Rgbw64Color Rgbw64Color::LinearBlend(const Rgbw64Color& left, const Rgbw64Color& right, float progress) +{ + return Rgbw64Color( 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) ); +} + +Rgbw64Color Rgbw64Color::BilinearBlend(const Rgbw64Color& c00, + const Rgbw64Color& c01, + const Rgbw64Color& c10, + const Rgbw64Color& 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 Rgbw64Color( + 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 ); +} \ No newline at end of file diff --git a/src/internal/Rgbw64Color.h b/src/internal/Rgbw64Color.h new file mode 100644 index 0000000..28a2193 --- /dev/null +++ b/src/internal/Rgbw64Color.h @@ -0,0 +1,248 @@ +/*------------------------------------------------------------------------- +Rgbw64Color 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 +. +-------------------------------------------------------------------------*/ +#pragma once + +#include +#include "NeoSettings.h" + +struct RgbColor; +struct HslColor; +struct HsbColor; + +// ------------------------------------------------------------------------ +// Rgbw64Color represents a color object that is represented by Red, Green, Blue +// component values and an extra White component. It contains helpful color +// routines to manipulate the color. +// ------------------------------------------------------------------------ +struct Rgbw64Color +{ + typedef NeoRgbwCurrentSettings SettingsObject; + + // ------------------------------------------------------------------------ + // Construct a Rgbw64Color using R, G, B, W values (0-65535) + // ------------------------------------------------------------------------ + Rgbw64Color(uint16_t r, uint16_t g, uint16_t b, uint16_t w = 0) : + R(r), G(g), B(b), W(w) + { + }; + + // ------------------------------------------------------------------------ + // Construct a RgbColor using a single brightness value (0-65535) + // This works well for creating gray tone colors + // (0) = black, (65535) = white, (32768) = gray + // ------------------------------------------------------------------------ + Rgbw64Color(uint16_t brightness) : + R(0), G(0), B(0), W(brightness) + { + }; + + // ------------------------------------------------------------------------ + // Construct a Rgbw64Color using RgbColor + // ------------------------------------------------------------------------ + Rgbw64Color(const RgbColor& color) + { + *this = Rgb48Color(color); + }; + + // ------------------------------------------------------------------------ + // Construct a Rgbw64Color using Rgb48Color + // ------------------------------------------------------------------------ + Rgbw64Color(const Rgb48Color& color) : + R(color.R), + G(color.G), + B(color.B), + W(0) + { + }; + + // ------------------------------------------------------------------------ + // Construct a Rgbw64Color using RgbwColor + // ------------------------------------------------------------------------ + Rgbw64Color(const RgbwColor& color); + + // ------------------------------------------------------------------------ + // Construct a Rgbw64Color using HtmlColor + // ------------------------------------------------------------------------ + Rgbw64Color(const HtmlColor& color) + { + *this = RgbwColor(color); + } + + // ------------------------------------------------------------------------ + // Construct a Rgbw64Color using HslColor + // ------------------------------------------------------------------------ + Rgbw64Color(const HslColor& color); + + // ------------------------------------------------------------------------ + // Construct a Rgbw64Color using HsbColor + // ------------------------------------------------------------------------ + Rgbw64Color(const HsbColor& color); + + // ------------------------------------------------------------------------ + // Construct a Rgbw64Color that will have its values set in latter operations + // CAUTION: The R,G,B, W members are not initialized and may not be consistent + // ------------------------------------------------------------------------ + Rgbw64Color() + { + }; + + // ------------------------------------------------------------------------ + // Comparison operators + // ------------------------------------------------------------------------ + bool operator==(const Rgbw64Color& other) const + { + return (R == other.R && G == other.G && B == other.B && W == other.W); + }; + + bool operator!=(const Rgbw64Color& other) const + { + return !(*this == other); + }; + + // ------------------------------------------------------------------------ + // Returns if the color is grey, all values are equal other than white + // ------------------------------------------------------------------------ + bool IsMonotone() const + { + return (R == B && R == G); + }; + + // ------------------------------------------------------------------------ + // Returns if the color components are all zero, the white component maybe + // anything + // ------------------------------------------------------------------------ + bool IsColorLess() const + { + return (R == 0 && B == 0 && G == 0); + }; + + // ------------------------------------------------------------------------ + // 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 + // ------------------------------------------------------------------------ + Rgbw64Color 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 + // ------------------------------------------------------------------------ + Rgbw64Color 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 Rgbw64Color LinearBlend(const Rgbw64Color& left, const Rgbw64Color& 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 Rgbw64Color BilinearBlend(const Rgbw64Color& c00, + const Rgbw64Color& c01, + const Rgbw64Color& c10, + const Rgbw64Color& c11, + float x, + float y); + + uint16_t CalcTotalTenthMilliAmpere(const SettingsObject& settings) + { + auto total = 0; + + total += R * settings.RedTenthMilliAmpere / Max; + total += G * settings.GreenTenthMilliAmpere / Max; + total += B * settings.BlueTenthMilliAmpere / Max; + total += W * settings.WhiteCurrent / Max; + + return total; + } + + // ------------------------------------------------------------------------ + // Red, Green, Blue, White color members (0-65535) where + // (0,0,0,0) is black and (65535,65535,65535, 0) and (0,0,0,65535) is white + // Note (65535,65535,65535,65535) is extreme bright white + // ------------------------------------------------------------------------ + uint16_t R; + uint16_t G; + uint16_t B; + uint16_t W; + + 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)) >> 16; + } + + inline static uint16_t _elementBrighten(uint16_t value, uint16_t ratio) + { + uint16_t element = ((static_cast(value) + 1) << 16) / (static_cast(ratio) + 1); + + if (element > Max) + { + element = Max; + } + else + { + element -= 1; + } + return element; + } +}; + diff --git a/src/internal/RgbwColor.h b/src/internal/RgbwColor.h index 73732b5..6fdc73c 100644 --- a/src/internal/RgbwColor.h +++ b/src/internal/RgbwColor.h @@ -187,10 +187,10 @@ struct RgbwColor { auto total = 0; - total += R * settings.RedTenthMilliAmpere / 255; - total += G * settings.GreenTenthMilliAmpere / 255; - total += B * settings.BlueTenthMilliAmpere / 255; - total += W * settings.WhiteCurrent / 255; + total += R * settings.RedTenthMilliAmpere / Max; + total += G * settings.GreenTenthMilliAmpere / Max; + total += B * settings.BlueTenthMilliAmpere / Max; + total += W * settings.WhiteCurrent / Max; return total; } @@ -205,6 +205,8 @@ struct RgbwColor uint8_t B; uint8_t W; + const static uint8_t Max = 255; + private: inline static uint8_t _elementDim(uint8_t value, uint8_t ratio) { @@ -215,9 +217,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 {