Fix HSV to RGB conversion once and for all
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <format>
|
||||
#include <Color4.hpp>
|
||||
|
||||
// Gets set to whatever your terminal emulator is configured for.
|
||||
// This means black can be shown as purple if configured that way.
|
||||
|
@@ -32,40 +32,40 @@ public:
|
||||
public:
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
/// @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.
|
||||
/// /// @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.
|
||||
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.
|
||||
constexpr explicit Color4(const HSVA& hsva);
|
||||
explicit Color4(const HSVA& hsva);
|
||||
|
||||
/// 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
|
||||
constexpr explicit Color4(const LCH& lch, float alpha = 1.f);
|
||||
explicit Color4(const LCH& lch, float alpha = 1.f);
|
||||
// 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);
|
||||
@@ -73,10 +73,11 @@ public:
|
||||
|
||||
static Color4 FromHexA(const std::string& hexACode);
|
||||
|
||||
static Color4 FromHSV(float hue, float saturation, float value, float alpha = 1.f) {
|
||||
// TODO: implement
|
||||
return {};
|
||||
}
|
||||
static Color4 FromHSV(const HSV& hsv, float alpha = 1.f);
|
||||
|
||||
/// @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 FromNormalized(float red, float green, float blue, 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::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;
|
||||
}
|
||||
|
176
src/Color4.cpp
176
src/Color4.cpp
@@ -24,63 +24,84 @@ void print_builtin_color_list() {
|
||||
#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) {
|
||||
float h = hsv.h;
|
||||
float s = hsv.s;
|
||||
float v = hsv.v;
|
||||
float M = 255*hsv.v;
|
||||
float m = M*(1-hsv.s);
|
||||
Color4::Color4(const HSV &hsv, float alpha) {
|
||||
|
||||
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) {
|
||||
r = M;
|
||||
g = z + m;
|
||||
b = m;
|
||||
}
|
||||
if (60 <= h < 120) {
|
||||
r = z + m;
|
||||
g = M;
|
||||
b = m;
|
||||
}
|
||||
if (120 <= h < 180) {
|
||||
r = m;
|
||||
g = M;
|
||||
b = z + m;
|
||||
float hh, p, q, t, ff;
|
||||
long i;
|
||||
float rn, gn, bn;
|
||||
|
||||
if (saturation <= 0.0) { // < is bogus, just shuts up warnings.
|
||||
r = value*255;
|
||||
g = value*255;
|
||||
b = value*255;
|
||||
return;
|
||||
//return Color4(RGBAf{rn, bn, gn, alpha});
|
||||
}
|
||||
|
||||
if (180 <= h < 240) {
|
||||
r = m;
|
||||
g = z + m;
|
||||
b = M;
|
||||
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;
|
||||
}
|
||||
this->r = rn * 255;
|
||||
this->g = gn * 255;
|
||||
this->b = bn * 255;
|
||||
this->a = alpha * 255;
|
||||
//return Color4(RGBAf{rn, gn, bn, alpha});
|
||||
}
|
||||
|
||||
if (240 <= h < 300) {
|
||||
r = z + m;
|
||||
g = m;
|
||||
b = M;
|
||||
}
|
||||
Color4::Color4(const Color3 &color3, u8 alpha) {r = color3.r; g = color3.g; b = color3.b; a = alpha;}
|
||||
|
||||
if (300 <= h < 360) {
|
||||
r = M;
|
||||
g = m;
|
||||
b = z + m;
|
||||
}
|
||||
|
||||
a = alpha;
|
||||
}
|
||||
|
||||
constexpr 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)
|
||||
list.push_back(*this);
|
||||
#endif
|
||||
@@ -356,3 +377,66 @@ std::string Color4::ToHexAlpha() const {
|
||||
std::string as = decimal_to_hex(a);
|
||||
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