forked from Makuna/NeoPixelBus
RgbColor, RgbwColor, HsbColor and HslColor now support constexpr
This commit is contained in:
@ -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
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#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;
|
||||
}
|
@ -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 <Arduino.h>
|
||||
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 <typename T_NEOHUEBLEND> static HsbColor LinearBlend(const HsbColor& left,
|
||||
template <typename T_NEOHUEBLEND>
|
||||
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 <typename T_NEOHUEBLEND> static HsbColor BilinearBlend(const HsbColor& c00,
|
||||
template <typename T_NEOHUEBLEND>
|
||||
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 <typename T_NEOHUEBLEND>
|
||||
//static constexpr HsbColor HsbColor::LinearBlend<T_NEOHUEBLEND>(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 <typename T_NEOHUEBLEND>
|
||||
//static constexpr HsbColor HsbColor::BilinearBlend<T_NEOHUEBLEND>(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;
|
||||
}
|
||||
|
@ -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
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#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;
|
||||
}
|
@ -25,37 +25,35 @@ License along with NeoPixel. If not, see
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
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 <typename T_NEOHUEBLEND> static HslColor LinearBlend(const HslColor& left,
|
||||
template <typename T_NEOHUEBLEND>
|
||||
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 <typename T_NEOHUEBLEND> static HslColor BilinearBlend(const HslColor& c00,
|
||||
template <typename T_NEOHUEBLEND>
|
||||
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 <typename T_NEOHUEBLEND>
|
||||
//static constexpr HslColor HslColor::LinearBlend<T_NEOHUEBLEND>(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 <typename T_NEOHUEBLEND>
|
||||
//static constexpr HslColor HslColor::BilinearBlend<T_NEOHUEBLEND>(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;
|
||||
}
|
||||
|
@ -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
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#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);
|
||||
}
|
@ -25,7 +25,8 @@ License along with NeoPixel. If not, see
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <cstdint>
|
||||
|
||||
#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<uint16_t>(value) * (static_cast<uint16_t>(ratio) + 1)) >> 8;
|
||||
}
|
||||
|
||||
inline static uint8_t _elementBrighten(uint8_t value, uint8_t ratio)
|
||||
{
|
||||
uint16_t element = ((static_cast<uint16_t>(value) + 1) << 8) / (static_cast<uint16_t>(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<uint16_t>(value) * (static_cast<uint16_t>(ratio) + 1)) >> 8;
|
||||
}
|
||||
|
||||
constexpr uint8_t RgbColor::_elementBrighten(uint8_t value, uint8_t ratio)
|
||||
{
|
||||
uint16_t element = ((static_cast<uint16_t>(value) + 1) << 8) / (static_cast<uint16_t>(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)};
|
||||
}
|
||||
|
@ -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
|
||||
<http://www.gnu.org/licenses/>.
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#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 );
|
||||
}
|
@ -25,7 +25,9 @@ License along with NeoPixel. If not, see
|
||||
-------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <cstdint>
|
||||
|
||||
#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<uint16_t>(value) * (static_cast<uint16_t>(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<uint16_t>(value) + 1) << 8) / (static_cast<uint16_t>(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<uint16_t>(value) * (static_cast<uint16_t>(ratio) + 1)) >> 8;
|
||||
}
|
||||
|
||||
constexpr uint8_t RgbwColor::_elementBrighten(uint8_t value, uint8_t ratio)
|
||||
{
|
||||
uint16_t element = ((static_cast<uint16_t>(value) + 1) << 8) / (static_cast<uint16_t>(ratio) + 1);
|
||||
|
||||
if (element > 255)
|
||||
{
|
||||
element = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
element -= 1;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
Reference in New Issue
Block a user