1#ifndef NEFORCE_CORE_UTILITY_COLOR_HPP__
2#define NEFORCE_CORE_UTILITY_COLOR_HPP__
14NEFORCE_BEGIN_NAMESPACE__
176 static constexpr int clamp(
const int value)
noexcept {
191 static constexpr double clamp_double(
const double value)
noexcept {
208 static constexpr int lerp_component(
const int from,
const int to,
const double t)
noexcept {
209 const double result = from + (to - from) * clamp_double(t);
210 return static_cast<int>(_NEFORCE
round(result));
213 static constexpr int find_closest(
const int value)
noexcept {
214 constexpr int levels[6] = {0, 95, 135, 175, 215, 255};
217 int min_diff = 255 * 255;
218 for (
int i = 0; i < 6; ++i) {
219 const int diff = value - levels[i];
220 const int dist = diff * diff;
221 if (dist < min_diff) {
233 constexpr color() noexcept = default;
235 constexpr
color(const
color& other) noexcept = default;
236 constexpr
color& operator=(const
color& other) noexcept = default;
252 constexpr color(
const int gray,
const int alpha) noexcept :
294 NEFORCE_CONSTEXPR20
explicit color(
const string& str) { *
this =
parse(str.
view()); }
335 NEFORCE_CONSTEXPR20
~color() =
default;
341 NEFORCE_NODISCARD
constexpr int R() const noexcept {
return r; }
347 NEFORCE_NODISCARD
constexpr int G() const noexcept {
return g; }
353 NEFORCE_NODISCARD
constexpr int B() const noexcept {
return b; }
359 NEFORCE_NODISCARD
constexpr int A() const noexcept {
return a; }
365 constexpr void setR(
const int red)
noexcept { r = clamp(
red); }
383 constexpr void setA(
const int alpha)
noexcept { a = clamp(alpha); }
431 NEFORCE_NODISCARD
constexpr bool is_transparent() const noexcept {
return a == 0; }
437 NEFORCE_NODISCARD
constexpr bool is_opaque() const noexcept {
return a == 255; }
443 NEFORCE_NODISCARD
constexpr double opacity() const noexcept {
return a / 255.0; }
465 return {lerp_component(from.r, to.r, t), lerp_component(from.g, to.g, t), lerp_component(from.b, to.b, t),
466 lerp_component(from.a, to.a, t)};
475 return {r + other.r, g + other.g, b + other.b, a + other.a};
484 return {r - other.r, g - other.g, b - other.b, a - other.a};
493 return {
static_cast<int>(_NEFORCE
round(
static_cast<double>(r) * scalar)),
494 static_cast<int>(_NEFORCE
round(
static_cast<double>(g) * scalar)),
495 static_cast<int>(_NEFORCE
round(
static_cast<double>(b) * scalar)),
496 static_cast<int>(_NEFORCE
round(
static_cast<double>(a) * scalar))};
505 return {r * scalar, g * scalar, b * scalar, a * scalar};
514 r = clamp(r + other.r);
515 g = clamp(g + other.g);
516 b = clamp(b + other.b);
517 a = clamp(a + other.a);
527 r = clamp(r - other.r);
528 g = clamp(g - other.g);
529 b = clamp(b - other.b);
530 a = clamp(a - other.a);
540 r = clamp(
static_cast<int>(_NEFORCE
round(r * scalar)));
541 g = clamp(
static_cast<int>(_NEFORCE
round(g * scalar)));
542 b = clamp(
static_cast<int>(_NEFORCE
round(b * scalar)));
543 a = clamp(
static_cast<int>(_NEFORCE
round(a * scalar)));
552 NEFORCE_NODISCARD
constexpr bool equal_to(
const color& other)
const noexcept {
553 return r == other.r && g == other.g && b == other.b && a == other.a;
590 const decimal_t dst_a = background.a / 255.0;
594 const decimal_t out_a = src_a + dst_a * inv_src_a;
602 const int newR =
static_cast<int>(_NEFORCE
round((r * src_a + background.r * dst_a * inv_src_a) * inv_out_a));
603 const int newG =
static_cast<int>(_NEFORCE
round((g * src_a + background.g * dst_a * inv_src_a) * inv_out_a));
604 const int newB =
static_cast<int>(_NEFORCE
round((b * src_a + background.b * dst_a * inv_src_a) * inv_out_a));
605 const int newA =
static_cast<int>(_NEFORCE
round(out_a * 255.0));
607 return {newR, newG, newB, newA};
614 NEFORCE_NODISCARD
constexpr double gray_value() const noexcept {
return 0.299 * r + 0.587 * g + 0.114 * b; }
620 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string()
const {
621 return _NEFORCE
format(
"{:02X}{:02X}{:02X}{:02X}", r, g, b, a);
632 if (clean_hex[0] ==
'#') {
633 clean_hex = clean_hex.
tail(1);
636 if (clean_hex.
length() == 6) {
640 return {
static_cast<int>(r),
static_cast<int>(g),
static_cast<int>(b)};
641 }
else if (clean_hex.
length() == 8) {
646 return {
static_cast<int>(r),
static_cast<int>(g),
static_cast<int>(b),
static_cast<int>(a)};
661 if (r == 0 && g == 0 && b == 0) {
664 if (r == 255 && g == 255 && b == 255) {
668 if (r == g && g == b) {
675 const int gray_index = (r - 8) / 10;
676 return 232 + (gray_index > 23 ? 23 : gray_index);
679 const int r_idx = find_closest(r);
680 const int g_idx = find_closest(g);
681 const int b_idx = find_closest(b);
684 return 16 + 36 * r_idx + 6 * g_idx + b_idx;
692 NEFORCE_NODISCARD
constexpr int to_ansi_basic(
const bool is_background =
false) const noexcept {
693 const int base = is_background ? 40 : 30;
695 if (r > g && r > b) {
696 if (g > 128 && b > 128) {
700 }
else if (g > r && g > b) {
701 if (r > 128 && b > 128) {
705 }
else if (b > r && b > g) {
706 if (r > 128 && g > 128) {
710 }
else if (r == g && g == b) {
718 }
else if (r == g && r > b) {
720 }
else if (r == b && r > g) {
722 }
else if (g == b && g > r) {
760 return {
static_cast<int>(_NEFORCE
round(r * alpha)),
static_cast<int>(_NEFORCE
round(g * alpha)),
761 static_cast<int>(_NEFORCE
round(b * alpha)), a};
774 return {
static_cast<int>(_NEFORCE
round(r * inv_alpha)),
static_cast<int>(_NEFORCE
round(g * inv_alpha)),
775 static_cast<int>(_NEFORCE
round(b * inv_alpha)), a};
794 NEFORCE_NODISCARD
constexpr size_t to_hash() const noexcept {
796 return hasher(r) ^ hasher(g) ^ hasher(b) ^ hasher(a);
805 other = _NEFORCE
move(*
this);
806 *
this = _NEFORCE
move(tmp);
810 static constexpr color black() noexcept {
return {0, 0, 0, 255}; }
813 static constexpr color white() noexcept {
return {255, 255, 255, 255}; }
816 static constexpr color gray() noexcept {
return {128, 128, 128, 255}; }
819 static constexpr color red() noexcept {
return {255, 0, 0, 255}; }
822 static constexpr color green() noexcept {
return {0, 255, 0, 255}; }
825 static constexpr color blue() noexcept {
return {0, 0, 255, 255}; }
828 static constexpr color yellow() noexcept {
return {255, 255, 0, 255}; }
831 static constexpr color magenta() noexcept {
return {255, 0, 255, 255}; }
834 static constexpr color cyan() noexcept {
return {0, 255, 255, 255}; }
837 static constexpr color purple() noexcept {
return {255, 0, 255, 255}; }
861NEFORCE_END_NAMESPACE__
constexpr basic_string_view tail(const size_type off=0) const
获取尾部子串
constexpr size_type length() const noexcept
获取字符串长度
constexpr basic_string_view substr(const size_type off=0, const size_type count=npos) const
获取子视图
constexpr view_type view() const noexcept
获取字符串视图
constexpr color(const int red, const int green, const int blue, const int alpha) noexcept
从RGBA分量构造
constexpr bool is_transparent() const noexcept
检查是否完全透明
constexpr void setR(const int red) noexcept
设置红色分量
constexpr void swap(color &other) noexcept
交换两个颜色对象
constexpr color & operator*=(const double scalar) noexcept
颜色乘等赋值
constexpr string to_string() const
转换为十六进制字符串
constexpr double gray_value() const noexcept
计算灰度值
constexpr color & operator+=(const color &other) noexcept
颜色加等赋值
constexpr void set_opacity(double opacity) noexcept
设置不透明度
constexpr color to_premultiplied() const noexcept
转换为标准预乘 Alpha 表示
constexpr color(const int red, const int green, const int blue) noexcept
从RGB分量构造
constexpr void set_gray(const int gray) noexcept
设置灰度值
static constexpr color gray() noexcept
灰色
constexpr int A() const noexcept
获取透明度
constexpr integer32 to_ansi_foreground(const bool use_256_color=true) const noexcept
转换为ANSI前景色代码
constexpr void setG(const int green) noexcept
设置绿色分量
constexpr void set_color(const int red, const int green, const int blue) noexcept
设置RGB颜色
constexpr color operator+(const color &other) const noexcept
颜色加法
static constexpr color blue() noexcept
蓝色
static constexpr color lerp(const color &from, const color &to, double t) noexcept
线性插值两个颜色
constexpr color operator*(const double scalar) const noexcept
颜色乘以标量
constexpr size_t to_hash() const noexcept
计算哈希值
constexpr void setB(const int blue) noexcept
设置蓝色分量
static constexpr color green() noexcept
绿色
constexpr color blend(const color &background) const noexcept
将当前颜色与背景色混合
static constexpr color magenta() noexcept
品红
constexpr integer32 to_integer32(const bool use_256_color=true) const noexcept
转换为整数表示
constexpr int B() const noexcept
获取蓝色分量
static constexpr color purple() noexcept
紫色
constexpr integer32 to_ansi_background(const bool use_256_color=true) const noexcept
转换为ANSI背景色代码
static constexpr color parse(const string_view hex)
从十六进制字符串解析颜色
constexpr int to_ansi_basic(const bool is_background=false) const noexcept
转换为基本ANSI颜色代码
static constexpr color red() noexcept
红色
constexpr bool is_opaque() const noexcept
检查是否完全不透明
constexpr double opacity() const noexcept
获取不透明度(0.0-1.0)
constexpr void set_color(const int red, const int green, const int blue, const int alpha) noexcept
设置RGBA颜色
static constexpr color black() noexcept
黑色
constexpr color & operator=(color &&other) noexcept
移动赋值运算符
constexpr color() noexcept=default
默认构造函数,创建黑色(0,0,0,255)
constexpr void setA(const int alpha) noexcept
设置透明度
static constexpr color yellow() noexcept
黄色
constexpr color & operator-=(const color &other) noexcept
颜色减等赋值
constexpr color from_premultiplied() const noexcept
从预乘 Alpha 转换回直通 Alpha(Straight Alpha)
constexpr int R() const noexcept
获取红色分量
constexpr color operator*(const int scalar) const noexcept
颜色乘以整数标量
static constexpr color transparent() noexcept
完全透明
constexpr color operator-(const color &other) const noexcept
颜色减法
constexpr int G() const noexcept
获取绿色分量
static constexpr color white() noexcept
白色
constexpr color(const int gray, const int alpha) noexcept
从灰度值和透明度构造
constexpr void set_gray(const int gray, const int alpha) noexcept
设置灰度值和透明度
constexpr bool equal_to(const color &other) const noexcept
相等比较
static constexpr color cyan() noexcept
青色
constexpr color(const string_view str)
从十六进制字符串构造
constexpr bool less_than(const color &other) const noexcept
小于比较
constexpr color(color &&other) noexcept
移动构造函数
constexpr int to_ansi_256() const noexcept
转换为256色ANSI颜色索引
constexpr color(const string &str)
从字符串对象构造
constexpr color(const char *str)
从C风格字符串构造
constexpr T * addressof(T &x) noexcept
获取对象的地址
constexpr const T & min(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(b, a)))
返回两个值中的较小者
constexpr const T & max(const T &a, const T &b, Compare comp) noexcept(noexcept(comp(a, b)))
返回两个值中的较大者
long double decimal_t
扩展精度浮点数类型
void unreachable() noexcept
标记不可达代码路径
constexpr duration< inner::__common_rep_t< Rep1, Rep2 >, Period > operator*(const duration< Rep1, Period > &value, const Rep2 &scalar)
乘法运算符(持续时间 * 标量)
constexpr decimal_t round(const decimal_t x) noexcept
四舍五入
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
basic_string_view< char > string_view
字符字符串视图
static constexpr hexadecimal parse(const string_view str)
从字符串解析十六进制值