HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
color.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
9#pragma once
10
11#include "../SIMD/module.hpp"
12#include "../geometry/module.hpp"
13#include "../utility/module.hpp"
14#include "../concurrency/module.hpp"
15#include <string>
16#include <map>
17
18namespace hi { inline namespace v1 {
19
44class color {
45public:
46 constexpr color() noexcept = default;
47 constexpr color(color const&) noexcept = default;
48 constexpr color(color&&) noexcept = default;
49 constexpr color& operator=(color const&) noexcept = default;
50 constexpr color& operator=(color&&) noexcept = default;
51
52 [[nodiscard]] constexpr explicit color(f16x4 const& other) noexcept : _v(other)
53 {
54 hi_axiom(holds_invariant());
55 }
56
57 [[nodiscard]] constexpr explicit color(f32x4 const& other) noexcept : color(static_cast<f16x4>(other)) {}
58
59 [[nodiscard]] constexpr explicit operator f16x4() const noexcept
60 {
61 return _v;
62 }
63
64 [[nodiscard]] constexpr explicit operator f32x4() const noexcept
65 {
66 return static_cast<f32x4>(_v);
67 }
68
69 [[nodiscard]] constexpr color(float r, float g, float b, float a = 1.0f) noexcept : color(f32x4{r, g, b, a}) {}
70
73 [[nodiscard]] static inline std::vector<std::string> list() noexcept;
74
80 [[nodiscard]] static inline color *find(std::string const& name) noexcept;
81
82 [[nodiscard]] static inline color black() noexcept;
83 [[nodiscard]] static inline color silver() noexcept;
84 [[nodiscard]] static inline color gray() noexcept;
85 [[nodiscard]] static inline color white() noexcept;
86 [[nodiscard]] static inline color maroon() noexcept;
87 [[nodiscard]] static inline color red() noexcept;
88 [[nodiscard]] static inline color purple() noexcept;
89 [[nodiscard]] static inline color fuchsia() noexcept;
90 [[nodiscard]] static inline color green() noexcept;
91 [[nodiscard]] static inline color lime() noexcept;
92 [[nodiscard]] static inline color olive() noexcept;
93 [[nodiscard]] static inline color yellow() noexcept;
94 [[nodiscard]] static inline color navy() noexcept;
95 [[nodiscard]] static inline color blue() noexcept;
96 [[nodiscard]] static inline color teal() noexcept;
97 [[nodiscard]] static inline color aqua() noexcept;
98 [[nodiscard]] static inline color indigo() noexcept;
99 [[nodiscard]] static inline color orange() noexcept;
100 [[nodiscard]] static inline color pink() noexcept;
101 [[nodiscard]] static inline color background() noexcept;
102 [[nodiscard]] static inline color gray1() noexcept;
103 [[nodiscard]] static inline color gray2() noexcept;
104 [[nodiscard]] static inline color gray3() noexcept;
105 [[nodiscard]] static inline color gray4() noexcept;
106 [[nodiscard]] static inline color gray5() noexcept;
107 [[nodiscard]] static inline color gray6() noexcept;
108 [[nodiscard]] static inline color gray7() noexcept;
109 [[nodiscard]] static inline color gray8() noexcept;
110 [[nodiscard]] static inline color gray9() noexcept;
111 [[nodiscard]] static inline color foreground() noexcept;
112 [[nodiscard]] static inline color transparent() noexcept;
113 [[nodiscard]] static inline color accent() noexcept;
114
115 [[nodiscard]] size_t hash() const noexcept
116 {
117 return std::hash<uint64_t>{}(std::bit_cast<uint64_t>(_v));
118 }
119
120 [[nodiscard]] constexpr float16& r() noexcept
121 {
122 return _v.x();
123 }
124
125 [[nodiscard]] constexpr float16& g() noexcept
126 {
127 return _v.y();
128 }
129
130 [[nodiscard]] constexpr float16& b() noexcept
131 {
132 return _v.z();
133 }
134
135 [[nodiscard]] constexpr float16& a() noexcept
136 {
137 return _v.w();
138 }
139
140 [[nodiscard]] constexpr float16 r() const noexcept
141 {
142 return _v.x();
143 }
144
145 [[nodiscard]] constexpr float16 g() const noexcept
146 {
147 return _v.y();
148 }
149
150 [[nodiscard]] constexpr float16 b() const noexcept
151 {
152 return _v.z();
153 }
154
155 [[nodiscard]] constexpr float16 a() const noexcept
156 {
157 return _v.w();
158 }
159
160 [[nodiscard]] constexpr bool holds_invariant() const noexcept
161 {
162 return _v.w() >= 0.0 && _v.w() <= 1.0;
163 }
164
165 [[nodiscard]] constexpr friend bool operator==(color const& lhs, color const& rhs) noexcept
166 {
167 return equal(lhs._v, rhs._v);
168 }
169
170 [[nodiscard]] constexpr friend color operator*(color const& lhs, color const& rhs) noexcept
171 {
172 return color{lhs._v * rhs._v};
173 }
174
175 [[nodiscard]] constexpr friend color composit(color const& lhs, color const& rhs) noexcept
176 {
177 return color{composit(lhs._v, rhs._v)};
178 }
179
180 [[nodiscard]] constexpr friend color desaturate(color const& rhs) noexcept
181 {
182 hilet rhs_ = f32x4{rhs};
183
184 hilet Y = 0.2126f * rhs_.r() + 0.7152f * rhs_.g() + 0.0722f * rhs_.b();
185
186 return color{Y, Y, Y, rhs_.a()};
187 }
188
198 [[nodiscard]] constexpr friend color operator*(matrix3 const& lhs, color const& rhs) noexcept
199 {
200 hi_axiom(rhs.holds_invariant());
201 auto r = color{
202 get<0>(lhs) * static_cast<f32x4>(rhs).xxxx() + get<1>(lhs) * static_cast<f32x4>(rhs).yyyy() +
203 get<2>(lhs) * static_cast<f32x4>(rhs).zzzz() + get<3>(lhs)};
204
205 r.a() = rhs.a();
206 return r;
207 }
208
209 [[nodiscard]] constexpr friend color operator*(identity3 const& lhs, color const& rhs) noexcept
210 {
211 return rhs;
212 }
213
214 friend std::ostream &operator<<(std::ostream &lhs, color const &rhs)
215 {
216 return lhs << std::format("rgb({} {} {} {})", rhs.r(), rhs.g(), rhs.b(), rhs.a());
217 }
218
219private:
220 f16x4 _v = {};
221};
222
223namespace detail {
224
226public:
227 named_color_base(std::string name, hi::color color) noexcept : _color(color)
228 {
229 hilet lock = std::scoped_lock(_map_mutex);
230 _map[name] = this;
231 }
232
233 named_color_base(named_color_base const&) = delete;
235 named_color_base& operator=(named_color_base const&) = delete;
236 named_color_base& operator=(named_color_base&&) = delete;
237
238 hi::color const& operator*() const noexcept
239 {
240 return _color;
241 }
242
243 hi::color& operator*() noexcept
244 {
245 return _color;
246 }
247
248 operator hi::color() const noexcept
249 {
250 return _color;
251 }
252
253 [[nodiscard]] static std::vector<std::string> list() noexcept
254 {
255 auto r = std::vector<std::string>{};
256
257 hilet lock = std::scoped_lock(_map_mutex);
258 for (auto &item: _map) {
259 r.push_back(item.first);
260 }
261
262 return r;
263 }
264
265 [[nodiscard]] static named_color_base *find(std::string const& name) noexcept
266 {
267 hilet lock = std::scoped_lock(_map_mutex);
268 hilet it = _map.find(name);
269 if (it != _map.end()) {
270 return it->second;
271 } else {
272 return nullptr;
273 }
274 }
275
276private:
277 // The map is protected with a mutex because global variable initialization
278 // may be deferred and run on a different threads. However we can not
279 // use the deadlock detector as it will use a thread_local variable.
280 // The initialization order of static global variables and thread_local
281 // variables are undetermined.
283 inline static unfair_mutex_without_deadlock_detector _map_mutex;
284
285protected:
286 color _color;
287};
288
289template<fixed_string Tag>
291public:
292 named_color_type() noexcept : named_color_base(Tag, hi::color{}) {}
294
295 named_color_type& operator=(hi::color color) noexcept
296 {
297 _color = color;
298 }
299};
300
301} // namespace detail
302
303template<fixed_string Tag>
304inline auto named_color = detail::named_color_type<Tag>{};
305
306[[nodiscard]] inline std::vector<std::string> color::list() noexcept
307{
308 return detail::named_color_base::list();
309}
310
311[[nodiscard]] inline color *color::find(std::string const& name) noexcept
312{
313 if (auto named_color_ptr = detail::named_color_base::find(name)) {
314 return std::addressof(**named_color_ptr);
315 } else {
316 return nullptr;
317 }
318}
319
320// clang-format off
321
322template<> inline auto named_color<"black"> = detail::named_color_type<"black">{color{0, 0, 0}};
323template<> inline auto named_color<"silver"> = detail::named_color_type<"silver">{color{192, 192, 192}};
324template<> inline auto named_color<"gray"> = detail::named_color_type<"gray">{color{128, 128, 128}};
325template<> inline auto named_color<"white"> = detail::named_color_type<"white">{color{255, 255, 255}};
326template<> inline auto named_color<"maroon"> = detail::named_color_type<"maroon">{color{128, 0, 0}};
327template<> inline auto named_color<"red"> = detail::named_color_type<"red">{color{255, 0, 0}};
328template<> inline auto named_color<"purple"> = detail::named_color_type<"purple">{color{128, 0, 128}};
329template<> inline auto named_color<"fuchsia"> = detail::named_color_type<"fuchsia">{color{255, 0, 255}};
330template<> inline auto named_color<"green"> = detail::named_color_type<"green">{color{0, 128, 0}};
331template<> inline auto named_color<"lime"> = detail::named_color_type<"lime">{color{0, 255, 0}};
332template<> inline auto named_color<"olive"> = detail::named_color_type<"olive">{color{128, 128, 0}};
333template<> inline auto named_color<"yellow"> = detail::named_color_type<"yellow">{color{255, 255, 0}};
334template<> inline auto named_color<"navy"> = detail::named_color_type<"navy">{color{0, 0, 128}};
335template<> inline auto named_color<"blue"> = detail::named_color_type<"blue">{color{0, 0, 255}};
336template<> inline auto named_color<"teal"> = detail::named_color_type<"teal">{color{0, 128, 128}};
337template<> inline auto named_color<"aqua"> = detail::named_color_type<"aqua">{color{0, 255, 255}};
338template<> inline auto named_color<"indigo"> = detail::named_color_type<"indigo">{color{75, 0, 130}};
339template<> inline auto named_color<"orange"> = detail::named_color_type<"orange">{color{255, 165, 0}};
340template<> inline auto named_color<"pink"> = detail::named_color_type<"pink">{color{255, 192, 203}};
341template<> inline auto named_color<"background"> = detail::named_color_type<"background">{color{0, 0, 0}};
342template<> inline auto named_color<"gray1"> = detail::named_color_type<"gray1">{color{26, 26, 26}};
343template<> inline auto named_color<"gray2"> = detail::named_color_type<"gray2">{color{51, 51, 51}};
344template<> inline auto named_color<"gray3"> = detail::named_color_type<"gray3">{color{77, 77, 77}};
345template<> inline auto named_color<"gray4"> = detail::named_color_type<"gray4">{color{102, 102, 102}};
346template<> inline auto named_color<"gray5"> = detail::named_color_type<"gray5">{color{127, 127, 127}};
347template<> inline auto named_color<"gray6"> = detail::named_color_type<"gray6">{color{153, 153, 153}};
348template<> inline auto named_color<"gray7"> = detail::named_color_type<"gray7">{color{179, 179, 179}};
349template<> inline auto named_color<"gray8"> = detail::named_color_type<"gray8">{color{204, 204, 204}};
350template<> inline auto named_color<"gray9"> = detail::named_color_type<"gray9">{color{229, 229, 229}};
351template<> inline auto named_color<"foreground"> = detail::named_color_type<"foreground">{color{255, 255, 255}};
352template<> inline auto named_color<"transparent"> = detail::named_color_type<"transparent">{color{0, 0, 0, 0}};
353template<> inline auto named_color<"accent"> = detail::named_color_type<"accent">{color{0, 0, 255}};
354
355[[nodiscard]] inline color color::black() noexcept { return named_color<"black">; }
356[[nodiscard]] inline color color::silver() noexcept { return named_color<"silver">; }
357[[nodiscard]] inline color color::gray() noexcept { return named_color<"gray">; }
358[[nodiscard]] inline color color::white() noexcept { return named_color<"white">; }
359[[nodiscard]] inline color color::maroon() noexcept { return named_color<"maroon">; }
360[[nodiscard]] inline color color::red() noexcept { return named_color<"red">; }
361[[nodiscard]] inline color color::purple() noexcept { return named_color<"purple">; }
362[[nodiscard]] inline color color::fuchsia() noexcept { return named_color<"fuchsia">; }
363[[nodiscard]] inline color color::green() noexcept { return named_color<"green">; }
364[[nodiscard]] inline color color::lime() noexcept { return named_color<"lime">; }
365[[nodiscard]] inline color color::olive() noexcept { return named_color<"olive">; }
366[[nodiscard]] inline color color::yellow() noexcept { return named_color<"yellow">; }
367[[nodiscard]] inline color color::navy() noexcept { return named_color<"navy">; }
368[[nodiscard]] inline color color::blue() noexcept { return named_color<"blue">; }
369[[nodiscard]] inline color color::teal() noexcept { return named_color<"teal">; }
370[[nodiscard]] inline color color::aqua() noexcept { return named_color<"aqua">; }
371[[nodiscard]] inline color color::indigo() noexcept { return named_color<"indigo">; }
372[[nodiscard]] inline color color::orange() noexcept { return named_color<"orange">; }
373[[nodiscard]] inline color color::pink() noexcept { return named_color<"pink">; }
374[[nodiscard]] inline color color::background() noexcept { return named_color<"background">; }
375[[nodiscard]] inline color color::gray1() noexcept { return named_color<"gray1">; }
376[[nodiscard]] inline color color::gray2() noexcept { return named_color<"gray2">; }
377[[nodiscard]] inline color color::gray3() noexcept { return named_color<"gray3">; }
378[[nodiscard]] inline color color::gray4() noexcept { return named_color<"gray4">; }
379[[nodiscard]] inline color color::gray5() noexcept { return named_color<"gray5">; }
380[[nodiscard]] inline color color::gray6() noexcept { return named_color<"gray6">; }
381[[nodiscard]] inline color color::gray7() noexcept { return named_color<"gray7">; }
382[[nodiscard]] inline color color::gray8() noexcept { return named_color<"gray8">; }
383[[nodiscard]] inline color color::gray9() noexcept { return named_color<"gray9">; }
384[[nodiscard]] inline color color::foreground() noexcept { return named_color<"foreground">; }
385[[nodiscard]] inline color color::transparent() noexcept { return named_color<"transparent">; }
386[[nodiscard]] inline color color::accent() noexcept { return named_color<"accent">; }
387// clang-format on
388
389}} // namespace hi::v1
390
391template<>
392struct std::hash<hi::color> {
393 [[nodiscard]] size_t operator()(hi::color const& rhs) const noexcept
394 {
395 return rhs.hash();
396 }
397};
398
399
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
@ other
The gui_event does not have associated data.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
This is a RGBA floating point color.
Definition color.hpp:44
static color * find(std::string const &name) noexcept
Find a color by name.
Definition color.hpp:311
static std::vector< std::string > list() noexcept
List color names.
Definition color.hpp:306
constexpr friend color operator*(matrix3 const &lhs, color const &rhs) noexcept
Transform a color by a color matrix.
Definition color.hpp:198
Definition color.hpp:225
Definition color.hpp:290
Identity transform.
Definition identity.hpp:20
A 2D or 3D homogenius matrix for transforming homogenious vectors and points.
Definition matrix.hpp:33
T addressof(T... args)
T operator()(T... args)