NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
color.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_UTILITY_COLOR_HPP__
2#define NEFORCE_CORE_UTILITY_COLOR_HPP__
3
11
14NEFORCE_BEGIN_NAMESPACE__
15
155
164class color : public iobject<color>, public icommon<color> {
165private:
166 int r = 0;
167 int g = 0;
168 int b = 0;
169 int a = 255;
170
176 static constexpr int clamp(const int value) noexcept {
177 if (value < 0) {
178 return 0;
179 }
180 if (value > 255) {
181 return 255;
182 }
183 return value;
184 }
185
191 static constexpr double clamp_double(const double value) noexcept {
192 if (value < 0.0) {
193 return 0.0;
194 }
195 if (value > 1.0) {
196 return 1.0;
197 }
198 return value;
199 }
200
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));
211 }
212
213 static constexpr int find_closest(const int value) noexcept {
214 constexpr int levels[6] = {0, 95, 135, 175, 215, 255};
215
216 int closest_idx = 0;
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) {
222 min_diff = dist;
223 closest_idx = i;
224 }
225 }
226 return closest_idx;
227 };
228
229public:
233 constexpr color() noexcept = default;
234
235 constexpr color(const color& other) noexcept = default;
236 constexpr color& operator=(const color& other) noexcept = default;
237
242 explicit constexpr color(const int gray) noexcept :
243 r(clamp(gray)),
244 g(clamp(gray)),
245 b(clamp(gray)) {}
246
252 constexpr color(const int gray, const int alpha) noexcept :
253 r(clamp(gray)),
254 g(clamp(gray)),
255 b(clamp(gray)),
256 a(clamp(alpha)) {}
257
264 constexpr color(const int red, const int green, const int blue) noexcept :
265 r(clamp(red)),
266 g(clamp(green)),
267 b(clamp(blue)) {}
268
276 constexpr color(const int red, const int green, const int blue, const int alpha) noexcept :
277 r(clamp(red)),
278 g(clamp(green)),
279 b(clamp(blue)),
280 a(clamp(alpha)) {}
281
287 NEFORCE_CONSTEXPR20 explicit color(const string_view str) { *this = parse(str); }
288
294 NEFORCE_CONSTEXPR20 explicit color(const string& str) { *this = parse(str.view()); }
295
301 NEFORCE_CONSTEXPR20 explicit color(const char* str) { *this = parse(string_view{str}); }
302
306 constexpr color(color&& other) noexcept :
307 r(other.r),
308 g(other.g),
309 b(other.b),
310 a(other.a) {
311 other.r = 0;
312 other.g = 0;
313 other.b = 0;
314 other.a = 255;
315 }
316
320 constexpr color& operator=(color&& other) noexcept {
321 if (_NEFORCE addressof(other) == this) {
322 return *this;
323 }
324 r = other.r;
325 g = other.g;
326 b = other.b;
327 a = other.a;
328 other.r = 0;
329 other.g = 0;
330 other.b = 0;
331 other.a = 255;
332 return *this;
333 }
334
335 NEFORCE_CONSTEXPR20 ~color() = default;
336
341 NEFORCE_NODISCARD constexpr int R() const noexcept { return r; }
342
347 NEFORCE_NODISCARD constexpr int G() const noexcept { return g; }
348
353 NEFORCE_NODISCARD constexpr int B() const noexcept { return b; }
354
359 NEFORCE_NODISCARD constexpr int A() const noexcept { return a; }
360
365 constexpr void setR(const int red) noexcept { r = clamp(red); }
366
371 constexpr void setG(const int green) noexcept { g = clamp(green); }
372
377 constexpr void setB(const int blue) noexcept { b = clamp(blue); }
378
383 constexpr void setA(const int alpha) noexcept { a = clamp(alpha); }
384
391 constexpr void set_color(const int red, const int green, const int blue) noexcept {
392 r = clamp(red);
393 g = clamp(green);
394 b = clamp(blue);
395 }
396
404 constexpr void set_color(const int red, const int green, const int blue, const int alpha) noexcept {
405 r = clamp(red);
406 g = clamp(green);
407 b = clamp(blue);
408 a = clamp(alpha);
409 }
410
415 constexpr void set_gray(const int gray) noexcept { r = g = b = clamp(gray); }
416
422 constexpr void set_gray(const int gray, const int alpha) noexcept {
423 set_gray(gray);
424 a = clamp(alpha);
425 }
426
431 NEFORCE_NODISCARD constexpr bool is_transparent() const noexcept { return a == 0; }
432
437 NEFORCE_NODISCARD constexpr bool is_opaque() const noexcept { return a == 255; }
438
443 NEFORCE_NODISCARD constexpr double opacity() const noexcept { return a / 255.0; }
444
449 constexpr void set_opacity(double opacity) noexcept {
450 opacity = _NEFORCE max(opacity, 0.0);
451 opacity = _NEFORCE min(opacity, 1.0);
452 a = static_cast<int>(_NEFORCE round(opacity * 255));
453 }
454
463 static constexpr color lerp(const color& from, const color& to, double t) noexcept {
464 t = clamp_double(t);
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)};
467 }
468
474 constexpr color operator+(const color& other) const noexcept {
475 return {r + other.r, g + other.g, b + other.b, a + other.a};
476 }
477
483 constexpr color operator-(const color& other) const noexcept {
484 return {r - other.r, g - other.g, b - other.b, a - other.a};
485 }
486
492 constexpr color operator*(const double scalar) const noexcept {
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))};
497 }
498
504 constexpr color operator*(const int scalar) const noexcept {
505 return {r * scalar, g * scalar, b * scalar, a * scalar};
506 }
507
513 constexpr color& operator+=(const color& other) noexcept {
514 r = clamp(r + other.r);
515 g = clamp(g + other.g);
516 b = clamp(b + other.b);
517 a = clamp(a + other.a);
518 return *this;
519 }
520
526 constexpr color& operator-=(const color& other) noexcept {
527 r = clamp(r - other.r);
528 g = clamp(g - other.g);
529 b = clamp(b - other.b);
530 a = clamp(a - other.a);
531 return *this;
532 }
533
539 constexpr color& operator*=(const double scalar) noexcept {
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)));
544 return *this;
545 }
546
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;
554 }
555
561 NEFORCE_NODISCARD constexpr bool less_than(const color& other) const noexcept {
562 if (r != other.r) {
563 return r < other.r;
564 }
565 if (g != other.g) {
566 return g < other.g;
567 }
568 if (b != other.b) {
569 return b < other.b;
570 }
571 return a < other.a;
572 }
573
581 NEFORCE_NODISCARD constexpr color blend(const color& background) const noexcept {
582 if (a == 255) {
583 return *this;
584 }
585 if (a == 0) {
586 return background;
587 }
588
589 const decimal_t src_a = a / 255.0;
590 const decimal_t dst_a = background.a / 255.0;
591 const decimal_t inv_src_a = 1.0 - src_a;
592
593 // Result_A = Src_A + Dst_A * (1 - Src_A)
594 const decimal_t out_a = src_a + dst_a * inv_src_a;
595
596 if (out_a <= 0.0) {
597 return transparent();
598 }
599
600 // Result_RGB = (Src_RGB * Src_A + Dst_RGB * Dst_A * (1 - Src_A)) / Result_A
601 const decimal_t inv_out_a = 1.0 / out_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));
606
607 return {newR, newG, newB, newA};
608 }
609
614 NEFORCE_NODISCARD constexpr double gray_value() const noexcept { return 0.299 * r + 0.587 * g + 0.114 * b; }
615
620 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const {
621 return _NEFORCE format("{:02X}{:02X}{:02X}{:02X}", r, g, b, a);
622 }
623
630 static NEFORCE_CONSTEXPR20 color parse(const string_view hex) {
631 string_view clean_hex = hex;
632 if (clean_hex[0] == '#') {
633 clean_hex = clean_hex.tail(1);
634 }
635
636 if (clean_hex.length() == 6) {
637 const int64_t r = hexadecimal::parse(clean_hex.substr(0, 2)).value();
638 const int64_t g = hexadecimal::parse(clean_hex.substr(2, 2)).value();
639 const int64_t b = hexadecimal::parse(clean_hex.substr(4, 2)).value();
640 return {static_cast<int>(r), static_cast<int>(g), static_cast<int>(b)};
641 } else if (clean_hex.length() == 8) {
642 const int64_t r = hexadecimal::parse(clean_hex.substr(0, 2)).value();
643 const int64_t g = hexadecimal::parse(clean_hex.substr(2, 2)).value();
644 const int64_t b = hexadecimal::parse(clean_hex.substr(4, 2)).value();
645 const int64_t a = hexadecimal::parse(clean_hex.substr(6, 2)).value();
646 return {static_cast<int>(r), static_cast<int>(g), static_cast<int>(b), static_cast<int>(a)};
647 } else {
648 NEFORCE_THROW_EXCEPTION(value_exception("Invalid hex string"));
649 }
650 unreachable();
651 }
652
660 NEFORCE_NODISCARD constexpr int to_ansi_256() const noexcept {
661 if (r == 0 && g == 0 && b == 0) {
662 return 16;
663 }
664 if (r == 255 && g == 255 && b == 255) {
665 return 231;
666 }
667
668 if (r == g && g == b) {
669 if (r < 8) {
670 return 16;
671 }
672 if (r > 248) {
673 return 231;
674 }
675 const int gray_index = (r - 8) / 10;
676 return 232 + (gray_index > 23 ? 23 : gray_index);
677 }
678
679 const int r_idx = find_closest(r);
680 const int g_idx = find_closest(g);
681 const int b_idx = find_closest(b);
682
683 // 16 + 36 * R + 6 * G + B
684 return 16 + 36 * r_idx + 6 * g_idx + b_idx;
685 }
686
692 NEFORCE_NODISCARD constexpr int to_ansi_basic(const bool is_background = false) const noexcept {
693 const int base = is_background ? 40 : 30;
694
695 if (r > g && r > b) {
696 if (g > 128 && b > 128) {
697 return base + 7;
698 }
699 return base + 1;
700 } else if (g > r && g > b) {
701 if (r > 128 && b > 128) {
702 return base + 7;
703 }
704 return base + 2;
705 } else if (b > r && b > g) {
706 if (r > 128 && g > 128) {
707 return base + 7;
708 }
709 return base + 4;
710 } else if (r == g && g == b) {
711 if (r < 64) {
712 return base + 0;
713 }
714 if (r < 192) {
715 return base + 7;
716 }
717 return base + 7;
718 } else if (r == g && r > b) {
719 return base + 3;
720 } else if (r == b && r > g) {
721 return base + 5;
722 } else if (g == b && g > r) {
723 return base + 6;
724 }
725
726 return base + 7;
727 }
728
734 NEFORCE_NODISCARD constexpr integer32 to_ansi_foreground(const bool use_256_color = true) const noexcept {
735 if (use_256_color) {
736 return integer32{38 * 100 + 5 * 10 + to_ansi_256()};
737 }
738 return integer32{to_ansi_basic(false)};
739 }
740
746 NEFORCE_NODISCARD constexpr integer32 to_ansi_background(const bool use_256_color = true) const noexcept {
747 if (use_256_color) {
748 return integer32{48 * 100 + 5 * 10 + to_ansi_256()};
749 }
750 return integer32{to_ansi_basic(true)};
751 }
752
758 NEFORCE_NODISCARD constexpr color to_premultiplied() const noexcept {
759 const decimal_t alpha = a / 255.0;
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};
762 }
763
769 NEFORCE_NODISCARD constexpr color from_premultiplied() const noexcept {
770 if (a == 0) {
771 return transparent();
772 }
773 const decimal_t inv_alpha = 255.0 / 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};
776 }
777
783 NEFORCE_NODISCARD constexpr integer32 to_integer32(const bool use_256_color = true) const noexcept {
784 if (use_256_color) {
785 return integer32{to_ansi_256()};
786 }
787 return integer32{to_ansi_basic(false)};
788 }
789
794 NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept {
795 constexpr hash<int> hasher;
796 return hasher(r) ^ hasher(g) ^ hasher(b) ^ hasher(a);
797 }
798
803 constexpr void swap(color& other) noexcept {
804 color tmp = _NEFORCE move(other);
805 other = _NEFORCE move(*this);
806 *this = _NEFORCE move(tmp);
807 }
808
810 static constexpr color black() noexcept { return {0, 0, 0, 255}; }
811
813 static constexpr color white() noexcept { return {255, 255, 255, 255}; }
814
816 static constexpr color gray() noexcept { return {128, 128, 128, 255}; }
817
819 static constexpr color red() noexcept { return {255, 0, 0, 255}; }
820
822 static constexpr color green() noexcept { return {0, 255, 0, 255}; }
823
825 static constexpr color blue() noexcept { return {0, 0, 255, 255}; }
826
828 static constexpr color yellow() noexcept { return {255, 255, 0, 255}; }
829
831 static constexpr color magenta() noexcept { return {255, 0, 255, 255}; }
832
834 static constexpr color cyan() noexcept { return {0, 255, 255, 255}; }
835
837 static constexpr color purple() noexcept { return {255, 0, 255, 255}; }
838
840 static constexpr color transparent() noexcept { return {0, 0, 0, 0}; }
841};
842
849constexpr color operator*(const double scalar, const color& color) noexcept { return color * scalar; }
850
857constexpr color operator*(const int scalar, const color& color) noexcept { return color * scalar; }
858 // Color
860
861NEFORCE_END_NAMESPACE__
862#endif // NEFORCE_CORE_UTILITY_COLOR_HPP__
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
获取字符串视图
RGB颜色类
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 int64_t
64位有符号整数类型
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 string format(const string_view fmt, Args &&... args)
格式化字符串
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)
从字符串解析十六进制值
通用接口,同时具备可比较和可哈希功能
32位整数包装类
可解析对象接口