diff --git a/include/AnsiEscapeCodes.hpp b/include/AnsiEscapeCodes.hpp index e50a349..491bb3b 100644 --- a/include/AnsiEscapeCodes.hpp +++ b/include/AnsiEscapeCodes.hpp @@ -3,6 +3,7 @@ #include #include #include +#include // Gets set to whatever your terminal emulator is configured for. // This means black can be shown as purple if configured that way. diff --git a/include/Color4.hpp b/include/Color4.hpp index ea63462..4773ce0 100644 --- a/include/Color4.hpp +++ b/include/Color4.hpp @@ -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); diff --git a/main.cpp b/main.cpp index 0e356a0..3c9a691 100644 --- a/main.cpp +++ b/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; } diff --git a/src/Color4.cpp b/src/Color4.cpp index dfdc6da..8b538e3 100644 --- a/src/Color4.cpp +++ b/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))); - if (240 <= h < 300) { - r = z + m; - g = m; - b = M; + 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; } - - if (300 <= h < 360) { - r = M; - g = m; - b = z + m; - } - - a = alpha; + this->r = rn * 255; + this->g = gn * 255; + this->b = bn * 255; + this->a = alpha * 255; + //return Color4(RGBAf{rn, gn, bn, 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) 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) {}