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));
217 constexpr color() noexcept = default;
219 constexpr
color(const
color& other) noexcept = default;
220 constexpr
color& operator=(const
color& other) noexcept = default;
236 constexpr color(
const int gray,
const int alpha) noexcept :
309 NEFORCE_CONSTEXPR20
~color() =
default;
315 constexpr int R() const noexcept {
return r; }
321 constexpr int G() const noexcept {
return g; }
327 constexpr int B() const noexcept {
return b; }
333 constexpr int A() const noexcept {
return a; }
339 constexpr void setR(
const int red)
noexcept { r = clamp(
red); }
357 constexpr void setA(
const int alpha)
noexcept { a = clamp(alpha); }
411 constexpr bool is_opaque() const noexcept {
return a == 255; }
417 constexpr double opacity() const noexcept {
return a / 255.0; }
443 return color(lerp_component(from.r, to.r, t), lerp_component(from.g, to.g, t), lerp_component(from.b, to.b, t),
444 lerp_component(from.a, to.a, t));
453 return color(r + other.r, g + other.g, b + other.b, a + other.a);
462 return color(r - other.r, g - other.g, b - other.b, a - other.a);
471 return color(
static_cast<int>(_NEFORCE
round(r * scalar)),
static_cast<int>(_NEFORCE
round(g * scalar)),
472 static_cast<int>(_NEFORCE
round(b * scalar)),
static_cast<int>(_NEFORCE
round(a * scalar)));
481 return {r * scalar, g * scalar, b * scalar, a * scalar};
490 r = clamp(r + other.r);
491 g = clamp(g + other.g);
492 b = clamp(b + other.b);
493 a = clamp(a + other.a);
503 r = clamp(r - other.r);
504 g = clamp(g - other.g);
505 b = clamp(b - other.b);
506 a = clamp(a - other.a);
516 r = clamp(
static_cast<int>(_NEFORCE
round(r * scalar)));
517 g = clamp(
static_cast<int>(_NEFORCE
round(g * scalar)));
518 b = clamp(
static_cast<int>(_NEFORCE
round(b * scalar)));
519 a = clamp(
static_cast<int>(_NEFORCE
round(a * scalar)));
529 return r == other.r && g == other.g && b == other.b && a == other.a;
566 const decimal_t dst_a = background.a / 255.0;
570 const decimal_t out_a = src_a + dst_a * inv_src_a;
578 const int newR =
static_cast<int>(_NEFORCE
round((r * src_a + background.r * dst_a * inv_src_a) * inv_out_a));
579 const int newG =
static_cast<int>(_NEFORCE
round((g * src_a + background.g * dst_a * inv_src_a) * inv_out_a));
580 const int newB =
static_cast<int>(_NEFORCE
round((b * src_a + background.b * dst_a * inv_src_a) * inv_out_a));
581 const int newA =
static_cast<int>(_NEFORCE
round(out_a * 255.0));
583 return color(newR, newG, newB, newA);
590 NEFORCE_NODISCARD
constexpr double gray_value() const noexcept {
return 0.299 * r + 0.587 * g + 0.114 * b; }
596 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20
string to_string()
const {
597 return _NEFORCE
format(
"{:02X}{:02X}{:02X}{:02X}", r, g, b, a);
608 if (clean_hex[0] ==
'#') {
609 clean_hex = clean_hex.
substr(1);
612 if (clean_hex.
length() == 6) {
617 }
else if (clean_hex.
length() == 8) {
637 if (r == 0 && g == 0 && b == 0) {
640 if (r == 255 && g == 255 && b == 255) {
644 if (r == g && g == b) {
651 const int gray_index = (r - 8) / 10;
652 return 232 + (gray_index > 23 ? 23 : gray_index);
655 constexpr auto find_closest = [](
const int value) ->
int {
656 constexpr int levels[6] = {0, 95, 135, 175, 215, 255};
659 int min_diff = 255 * 255;
660 for (
int i = 0; i < 6; ++i) {
661 const int diff = value - levels[i];
662 const int dist = diff * diff;
663 if (dist < min_diff) {
671 const int r_idx = find_closest(r);
672 const int g_idx = find_closest(g);
673 const int b_idx = find_closest(b);
676 return 16 + 36 * r_idx + 6 * g_idx + b_idx;
684 NEFORCE_NODISCARD
constexpr int to_ansi_basic(
const bool is_background =
false) const noexcept {
685 const int base = is_background ? 40 : 30;
687 if (r > g && r > b) {
688 if (g > 128 && b > 128) {
692 }
else if (g > r && g > b) {
693 if (r > 128 && b > 128) {
697 }
else if (b > r && b > g) {
698 if (r > 128 && g > 128) {
702 }
else if (r == g && g == b) {
710 }
else if (r == g && r > b) {
712 }
else if (r == b && r > g) {
714 }
else if (g == b && g > r) {
752 return color(
static_cast<int>(_NEFORCE
round(r * alpha)),
static_cast<int>(_NEFORCE
round(g * alpha)),
753 static_cast<int>(_NEFORCE
round(b * alpha)), a);
766 return color(
static_cast<int>(_NEFORCE
round(r * inv_alpha)),
static_cast<int>(_NEFORCE
round(g * inv_alpha)),
767 static_cast<int>(_NEFORCE
round(b * inv_alpha)), a);
786 NEFORCE_NODISCARD
constexpr size_t to_hash() const noexcept {
788 return hasher(r) ^ hasher(g) ^ hasher(b) ^ hasher(a);
797 other = _NEFORCE
move(*
this);
798 *
this = _NEFORCE
move(tmp);
850NEFORCE_END_NAMESPACE__
NEFORCE_NODISCARD constexpr size_type length() const noexcept
获取字符串长度
NEFORCE_NODISCARD constexpr basic_string_view substr(const size_type off=0, size_type count=npos) const
获取子视图
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 view_type view() const noexcept
获取字符串视图
constexpr void setG(const int green) noexcept
设置绿色分量
static constexpr color lerp(const color &from, const color &to, double t) noexcept
线性插值两个颜色
constexpr void set_gray(const int gray) noexcept
设置灰度值
constexpr color(color &&other) noexcept
移动构造函数
constexpr color(const int red, const int green, const int blue, const int alpha) noexcept
从RGBA分量构造
constexpr void set_opacity(double opacity) noexcept
设置不透明度
NEFORCE_NODISCARD constexpr color from_premultiplied() const noexcept
从预乘 Alpha 转换回直通 Alpha(Straight Alpha)
constexpr void set_gray(const int gray, const int alpha) noexcept
设置灰度值和透明度
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const
转换为十六进制字符串
constexpr bool operator<(const color &other) const noexcept
小于比较
constexpr color & operator+=(const color &other) noexcept
颜色加等赋值
NEFORCE_NODISCARD constexpr color to_premultiplied() const noexcept
转换为标准预乘 Alpha 表示
constexpr bool operator==(const color &other) const noexcept
相等比较
constexpr color(const int gray, const int alpha) noexcept
从灰度值和透明度构造
NEFORCE_NODISCARD constexpr integer32 to_ansi_foreground(const bool use_256_color=true) const noexcept
转换为ANSI前景色代码
NEFORCE_NODISCARD constexpr int to_ansi_256() const noexcept
转换为256色ANSI颜色索引
constexpr void set_color(const int red, const int green, const int blue) noexcept
设置RGB颜色
constexpr int A() const noexcept
获取透明度
constexpr void setR(const int red) noexcept
设置红色分量
constexpr int G() const noexcept
获取绿色分量
constexpr bool is_opaque() const noexcept
检查是否完全不透明
constexpr color(const int red, const int green, const int blue) noexcept
从RGB分量构造
constexpr color() noexcept=default
默认构造函数,创建黑色(0,0,0,255)
constexpr color operator-(const color &other) const noexcept
颜色减法
static constexpr color blue() noexcept
蓝色
NEFORCE_CONSTEXPR20 color(const string_view str)
从十六进制字符串构造
constexpr void swap(color &other) noexcept
交换两个颜色对象
static constexpr color transparent() noexcept
完全透明
constexpr void setB(const int blue) noexcept
设置蓝色分量
constexpr double opacity() const noexcept
获取不透明度(0.0-1.0)
constexpr int B() const noexcept
获取蓝色分量
constexpr color & operator*=(const double scalar) noexcept
颜色乘等赋值
static constexpr color red() noexcept
红色
constexpr color & operator-=(const color &other) noexcept
颜色减等赋值
NEFORCE_NODISCARD constexpr int to_ansi_basic(const bool is_background=false) const noexcept
转换为基本ANSI颜色代码
static constexpr color black() noexcept
黑色
static constexpr color green() noexcept
绿色
constexpr color operator*(const double scalar) const noexcept
颜色乘以标量
constexpr bool is_transparent() const noexcept
检查是否完全透明
constexpr color operator*(const int scalar) const noexcept
颜色乘以整数标量
NEFORCE_NODISCARD constexpr double gray_value() const noexcept
计算灰度值
static NEFORCE_CONSTEXPR20 color parse(const string_view hex)
从十六进制字符串解析颜色
NEFORCE_NODISCARD constexpr integer32 to_ansi_background(const bool use_256_color=true) const noexcept
转换为ANSI背景色代码
static constexpr color cyan() noexcept
青色
NEFORCE_NODISCARD constexpr color blend(const color &background) const noexcept
将当前颜色与背景色混合
NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept
计算哈希值
static constexpr color white() noexcept
白色
constexpr color operator+(const color &other) const noexcept
颜色加法
constexpr void set_color(const int red, const int green, const int blue, const int alpha) noexcept
设置RGBA颜色
static constexpr color yellow() noexcept
黄色
static constexpr color gray() noexcept
灰色
constexpr color & operator=(color &&other) noexcept
移动赋值运算符
NEFORCE_NODISCARD constexpr integer32 to_integer32(const bool use_256_color=true) const noexcept
转换为整数表示
constexpr int R() const noexcept
获取红色分量
static constexpr color magenta() noexcept
品红
constexpr void setA(const int alpha) noexcept
设置透明度
NEFORCE_CONSTEXPR20 color(const string &str)
从字符串对象构造
NEFORCE_CONSTEXPR20 color(const char *str)
从C风格字符串构造
NEFORCE_NODISCARD constexpr T * addressof(T &x) noexcept
获取对象的地址
constexpr color operator*(const double scalar, const color &color) noexcept
标量乘以颜色
long double decimal_t
扩展精度浮点数类型
NEFORCE_NORETURN NEFORCE_ALWAYS_INLINE_INLINE void unreachable() noexcept
标记不可达代码路径
NEFORCE_CONST_FUNCTION NEFORCE_CONSTEXPR14 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
字符字符串视图
void swap()=delete
删除无参数的swap重载
static NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 hexadecimal parse(const string_view str)
从字符串解析十六进制值
NEFORCE_CONSTEXPR20 bool try_parse(const string_view str) noexcept
NEFORCE_NODISCARD constexpr package_type value() const noexcept
获取数值