Fix HSV to RGB conversion once and for all
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <Color4.hpp>
|
||||||
|
|
||||||
// Gets set to whatever your terminal emulator is configured for.
|
// Gets set to whatever your terminal emulator is configured for.
|
||||||
// This means black can be shown as purple if configured that way.
|
// This means black can be shown as purple if configured that way.
|
||||||
|
@@ -32,40 +32,40 @@ public:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/// The default constructor does not initialize any members.
|
/// The default constructor does not initialize any members.
|
||||||
constexpr Color4() = default;
|
Color4() = default;
|
||||||
|
|
||||||
/// Constructs a new Color4 from a Color3 and an optional alpha value.
|
/// Constructs a new Color4 from a Color3 and an optional alpha value.
|
||||||
constexpr explicit Color4(const Color3& color3, u8 alpha = 255);
|
explicit Color4(const Color3& color3, u8 alpha = 255);
|
||||||
|
|
||||||
/// Constructs a new Color4 from red, green, blue channel values, and an optional alpha value.
|
/// Constructs a new Color4 from red, green, blue channel values, and an optional alpha value.
|
||||||
constexpr Color4(u8 red, u8 green, u8 blue, u8 alpha = 255);
|
Color4(u8 red, u8 green, u8 blue, u8 alpha = 255);
|
||||||
|
|
||||||
/// Constructs a new Color4 from an RGB structure and an optional alpha value.
|
/// Constructs a new Color4 from an RGB structure and an optional alpha value.
|
||||||
constexpr explicit Color4(const RGB& rgb, u8 alpha = 255);
|
explicit Color4(const RGB& rgb, u8 alpha = 255);
|
||||||
|
|
||||||
/// Constructs a new Color4 from an RGBA structure.
|
/// Constructs a new Color4 from an RGBA structure.
|
||||||
constexpr explicit Color4(const RGBA& rgba);
|
explicit Color4(const RGBA& rgba);
|
||||||
|
|
||||||
/// Constructs a new Color4 from a floating-point RGB structure and an optional alpha value.
|
/// Constructs a new Color4 from a floating-point RGB structure and an optional alpha value.
|
||||||
/// @note: Normalizes the color values from ranges [0, 1] to [0, 255].
|
/// @note: Normalizes the color values from ranges [0, 1] to [0, 255].
|
||||||
constexpr explicit Color4(const RGBf& rgb, float alpha = 1.0f);
|
explicit Color4(const RGBf& rgb, float alpha = 1.0f);
|
||||||
|
|
||||||
/// Constructs a new Color4 from a floating-point RGBA structure.
|
/// Constructs a new Color4 from a floating-point RGBA structure.
|
||||||
/// /// @note: Normalizes the color values from ranges [0, 1] to [0, 255].
|
/// /// @note: Normalizes the color values from ranges [0, 1] to [0, 255].
|
||||||
constexpr explicit Color4(const RGBAf& rgba);
|
explicit Color4(const RGBAf& rgba);
|
||||||
|
|
||||||
/// Constructs a new Color4 from an HSV structure.
|
/// Constructs a new Color4 from an HSV structure.
|
||||||
constexpr explicit Color4(const HSV& hsv, float alpha = 1.f);
|
explicit Color4(const HSV& hsv, float alpha = 1.f);
|
||||||
|
|
||||||
/// Constructs a new Color4 from an HSVA structure.
|
/// Constructs a new Color4 from an HSVA structure.
|
||||||
constexpr explicit Color4(const HSVA& hsva);
|
explicit Color4(const HSVA& hsva);
|
||||||
|
|
||||||
/// TODO: HSL to RGB constructor
|
/// TODO: HSL to RGB constructor
|
||||||
constexpr explicit Color4(const HSL& hsl, float alpha = 1.f);
|
explicit Color4(const HSL& hsl, float alpha = 1.f);
|
||||||
// TODO: LCH to RGB constructor
|
// TODO: LCH to RGB constructor
|
||||||
constexpr explicit Color4(const LCH& lch, float alpha = 1.f);
|
explicit Color4(const LCH& lch, float alpha = 1.f);
|
||||||
// TODO: LCHA to RGB constructor
|
// TODO: LCHA to RGB constructor
|
||||||
constexpr explicit Color4(const LCHA& lcha);
|
explicit Color4(const LCHA& lcha);
|
||||||
|
|
||||||
|
|
||||||
static Color4 FromColor3(const Color3& color3, u8 alpha = 255);
|
static Color4 FromColor3(const Color3& color3, u8 alpha = 255);
|
||||||
@@ -73,10 +73,11 @@ public:
|
|||||||
|
|
||||||
static Color4 FromHexA(const std::string& hexACode);
|
static Color4 FromHexA(const std::string& hexACode);
|
||||||
|
|
||||||
static Color4 FromHSV(float hue, float saturation, float value, float alpha = 1.f) {
|
static Color4 FromHSV(const HSV& hsv, float alpha = 1.f);
|
||||||
// TODO: implement
|
|
||||||
return {};
|
/// @param hue The hue value represented in degrees [0-360]
|
||||||
}
|
|
||||||
|
static Color4 FromHSV(float hue, float saturation, float value, float alpha = 1.f);
|
||||||
static Color4 FromHSL(float hue, float saturation, float lightness, float alpha = 1.f);
|
static Color4 FromHSL(float hue, float saturation, float lightness, float alpha = 1.f);
|
||||||
static Color4 FromNormalized(float red, float green, float blue, float alpha = 1.f);
|
static Color4 FromNormalized(float red, float green, float blue, float alpha = 1.f);
|
||||||
static Color4 FromLCH(float l, float c, float h, float alpha = 1.f);
|
static Color4 FromLCH(float l, float c, float h, float alpha = 1.f);
|
||||||
|
10
main.cpp
10
main.cpp
@@ -21,5 +21,15 @@ int main()
|
|||||||
mcolor::printAnsiColorTable();
|
mcolor::printAnsiColorTable();
|
||||||
mcolor::printRGBConsoleTest();
|
mcolor::printRGBConsoleTest();
|
||||||
|
|
||||||
|
|
||||||
|
for (float i = 0; i < 360; i+=10.f)
|
||||||
|
{
|
||||||
|
HSVA hsva {i, 1.f, 1.f};
|
||||||
|
|
||||||
|
Color4 c = Color4(hsva);
|
||||||
|
|
||||||
|
std::cout << std::format("{}hue:{} rgb: {},{},{}", toEscapeCode(c), i, c.r, c.g, c.b) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
172
src/Color4.cpp
172
src/Color4.cpp
@@ -24,63 +24,84 @@ void print_builtin_color_list() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Color4::Color4(const RGB &rgb, u8 alpha): Color4(rgb.r, rgb.g, rgb.b, alpha) {}
|
Color4::Color4(const RGB &rgb, u8 alpha): Color4(rgb.r, rgb.g, rgb.b, alpha) {}
|
||||||
|
|
||||||
constexpr Color4::Color4(const RGBA &rgba): Color4(rgba.r, rgba.g, rgba.b, rgba.a) {}
|
Color4::Color4(const RGBA &rgba): Color4(rgba.r, rgba.g, rgba.b, rgba.a) {}
|
||||||
|
|
||||||
constexpr Color4::Color4(const RGBf &rgb, float alpha): Color4(rgb.r * 255, rgb.g * 255, rgb.b * 255, alpha * 255) { }
|
Color4::Color4(const RGBf &rgb, float alpha): Color4(rgb.r * 255, rgb.g * 255, rgb.b * 255, alpha * 255) { }
|
||||||
|
|
||||||
constexpr Color4::Color4(const RGBAf &rgba): Color4(rgba.r * 255, rgba.g * 255, rgba.b * 255, rgba.a * 255) { }
|
Color4::Color4(const RGBAf &rgba): Color4(rgba.r * 255, rgba.g * 255, rgba.b * 255, rgba.a * 255) { }
|
||||||
|
|
||||||
constexpr Color4::Color4(const HSV &hsv, float alpha) {
|
Color4::Color4(const HSV &hsv, float alpha) {
|
||||||
float h = hsv.h;
|
|
||||||
float s = hsv.s;
|
|
||||||
float v = hsv.v;
|
|
||||||
float M = 255*hsv.v;
|
|
||||||
float m = M*(1-hsv.s);
|
|
||||||
|
|
||||||
float z = (M-m)*(1 - std::abs( std::fmod(hsv.h/60.f, 2) - 1));
|
float hue = hsv.h;
|
||||||
|
float saturation = hsv.s;
|
||||||
|
float value = hsv.v;
|
||||||
|
|
||||||
if (0 <= h <= 60) {
|
float hh, p, q, t, ff;
|
||||||
r = M;
|
long i;
|
||||||
g = z + m;
|
float rn, gn, bn;
|
||||||
b = m;
|
|
||||||
}
|
if (saturation <= 0.0) { // < is bogus, just shuts up warnings.
|
||||||
if (60 <= h < 120) {
|
r = value*255;
|
||||||
r = z + m;
|
g = value*255;
|
||||||
g = M;
|
b = value*255;
|
||||||
b = m;
|
return;
|
||||||
}
|
//return Color4(RGBAf{rn, bn, gn, alpha});
|
||||||
if (120 <= h < 180) {
|
|
||||||
r = m;
|
|
||||||
g = M;
|
|
||||||
b = z + m;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (180 <= h < 240) {
|
hh = hue;
|
||||||
r = m;
|
if (hh >= 360.f) hh = 0;
|
||||||
g = z + m;
|
hh /= 60.f;
|
||||||
b = M;
|
i = (long)hh;
|
||||||
}
|
ff = hh - i;
|
||||||
|
p = value * (1.f - saturation);
|
||||||
|
q = value * (1.f - (saturation * ff));
|
||||||
|
t = value * (1.f - (saturation * (1.f - ff)));
|
||||||
|
|
||||||
if (240 <= h < 300) {
|
switch(i) {
|
||||||
r = z + m;
|
case 0:
|
||||||
g = m;
|
rn = value;
|
||||||
b = M;
|
gn = t;
|
||||||
|
bn = p;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rn = q;
|
||||||
|
gn = value;
|
||||||
|
bn = p;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rn = p;
|
||||||
|
gn = value;
|
||||||
|
bn = t;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
rn = p;
|
||||||
|
gn = q;
|
||||||
|
bn = value;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
rn = t;
|
||||||
|
gn = p;
|
||||||
|
bn = value;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
default:
|
||||||
|
rn = value;
|
||||||
|
gn = p;
|
||||||
|
bn = q;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
this->r = rn * 255;
|
||||||
if (300 <= h < 360) {
|
this->g = gn * 255;
|
||||||
r = M;
|
this->b = bn * 255;
|
||||||
g = m;
|
this->a = alpha * 255;
|
||||||
b = z + m;
|
//return Color4(RGBAf{rn, gn, bn, alpha});
|
||||||
}
|
|
||||||
|
|
||||||
a = alpha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Color4::Color4(const Color3 &color3, u8 alpha) {r = color3.r; g = color3.g; b = color3.b; a = alpha;}
|
Color4::Color4(const Color3 &color3, u8 alpha) {r = color3.r; g = color3.g; b = color3.b; a = alpha;}
|
||||||
|
|
||||||
constexpr Color4::Color4(u8 red, u8 green, u8 blue, u8 alpha): r(red), g(green), b(blue), a(alpha) {
|
Color4::Color4(u8 red, u8 green, u8 blue, u8 alpha): r(red), g(green), b(blue), a(alpha) {
|
||||||
#if !defined(WIN32)
|
#if !defined(WIN32)
|
||||||
list.push_back(*this);
|
list.push_back(*this);
|
||||||
#endif
|
#endif
|
||||||
@@ -356,3 +377,66 @@ std::string Color4::ToHexAlpha() const {
|
|||||||
std::string as = decimal_to_hex(a);
|
std::string as = decimal_to_hex(a);
|
||||||
return "#" + rs + gs + bs + as;
|
return "#" + rs + gs + bs + as;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color4 Color4::FromHSV(float hue, float saturation, float value, float alpha) {
|
||||||
|
float hh, p, q, t, ff;
|
||||||
|
long i;
|
||||||
|
float rn, gn, bn;
|
||||||
|
|
||||||
|
if (saturation <= 0.0) { // < is bogus, just shuts up warnings.
|
||||||
|
rn = value;
|
||||||
|
bn = value;
|
||||||
|
gn = value;
|
||||||
|
return Color4(RGBAf{rn, bn, gn, alpha});
|
||||||
|
}
|
||||||
|
|
||||||
|
hh = hue;
|
||||||
|
if (hh >= 360.f) hh = 0;
|
||||||
|
hh /= 60.f;
|
||||||
|
i = (long)hh;
|
||||||
|
ff = hh - i;
|
||||||
|
p = value * (1.f - saturation);
|
||||||
|
q = value * (1.f - (saturation * ff));
|
||||||
|
t = value * (1.f - (saturation * (1.f - ff)));
|
||||||
|
|
||||||
|
switch(i) {
|
||||||
|
case 0:
|
||||||
|
rn = value;
|
||||||
|
gn = t;
|
||||||
|
bn = p;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rn = q;
|
||||||
|
gn = value;
|
||||||
|
bn = p;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rn = p;
|
||||||
|
gn = value;
|
||||||
|
bn = t;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
rn = p;
|
||||||
|
gn = q;
|
||||||
|
bn = value;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
rn = t;
|
||||||
|
gn = p;
|
||||||
|
bn = value;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
default:
|
||||||
|
rn = value;
|
||||||
|
gn = p;
|
||||||
|
bn = q;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Color4(RGBAf{rn, gn, bn, alpha});
|
||||||
|
}
|
||||||
|
|
||||||
|
Color4 Color4::FromHSV(const HSV &hsv, float alpha) {
|
||||||
|
return FromHSV(hsv.h, hsv.s, hsv.v, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color4::Color4(const HSVA &hsva) : Color4(HSV{hsva.h,hsva.s,hsva.v}, hsva.a) {}
|
||||||
|
Reference in New Issue
Block a user