qxLib
color.h
Go to the documentation of this file.
1 /**
2 
3  @file color.h
4  @author Khrapov
5  @date 2.11.2020
6  @copyright (c) Nick Khrapov, 2021. All right reserved.
7 
8 **/
9 #pragma once
10 
13 #include <qx/hash.h>
16 #include <qx/patterns/singleton.h>
17 
18 #include <algorithm>
19 #include <unordered_map>
20 
21 QX_PUSH_SUPPRESS_ALL_WARNINGS();
22 #include <glm/vec3.hpp>
23 #include <glm/vec4.hpp>
24 QX_POP_SUPPRESS_WARNINGS();
25 
26 /// @see https://www.cssportal.com/html-colors/x11-colors.php
27 // clang-format off
28 #define _QX_COLORS(macro)\
29  macro(alice_blue , AliceBlue , 240, 248, 255) \
30  macro(antique_white , AntiqueWhite , 250, 235, 215) \
31  macro(aqua , Aqua , 0, 255, 255) \
32  macro(aquamarine , Aquamarine , 127, 255, 212) \
33  macro(azure , Azure , 240, 255, 255) \
34  macro(beige , Beige , 245, 245, 220) \
35  macro(bisque , Bisque , 255, 228, 196) \
36  macro(black , Black , 0, 0, 0) \
37  macro(blanched_almond , BlanchedAlmond , 255, 235, 205) \
38  macro(blue , Blue , 0, 0, 255) \
39  macro(blue_violet , BlueViolet , 138, 43, 226) \
40  macro(brown , Brown , 165, 42, 42) \
41  macro(burly_wood , BurlyWood , 222, 184, 135) \
42  macro(cadet_blue , CadetBlue , 95, 158, 160) \
43  macro(chartreuse , Chartreuse , 127, 255, 0) \
44  macro(chocolate , Chocolate , 210, 105, 30) \
45  macro(coral , Coral , 255, 127, 80) \
46  macro(cornflower_blue , CornflowerBlue , 100, 149, 237) \
47  macro(cornsilk , Cornsilk , 255, 248, 220) \
48  macro(crimson , Crimson , 220, 20, 60) \
49  macro(cyan , Cyan , 0, 255, 255) \
50  macro(dark_blue , DarkBlue , 0, 0, 139) \
51  macro(dark_cyan , DarkCyan , 0, 139, 139) \
52  macro(dark_goldenrod , DarkGoldenrod , 184, 134, 11) \
53  macro(dark_gray , DarkGray , 169, 169, 169) \
54  macro(dark_green , DarkGreen , 0, 100, 0); \
55  macro(dark_khaki , DarkKhaki , 189, 183, 107) \
56  macro(dark_magenta , DarkMagenta , 139, 0, 139) \
57  macro(dark_olive_green , DarkOliveGreen , 85, 107, 47) \
58  macro(dark_orange , DarkOrange , 255, 140, 0) \
59  macro(dark_orchid , DarkOrchid , 153, 50, 204) \
60  macro(dark_red , DarkRed , 139, 0, 0) \
61  macro(dark_salmon , DarkSalmon , 233, 150, 122) \
62  macro(dark_sea_green , DarkSeaGreen , 143, 188, 143) \
63  macro(dark_slate_blue , DarkSlateBlue , 72, 61, 139) \
64  macro(dark_slate_gray , DarkSlateGray , 47, 79, 79) \
65  macro(dark_turquoise , DarkTurquoise , 0, 206, 209) \
66  macro(dark_violet , DarkViolet , 148, 0, 211) \
67  macro(deep_pink , DeepPink , 255, 20, 147) \
68  macro(deep_sky_blue , DeepSkyBlue , 0, 191, 255) \
69  macro(dim_gray , DimGray , 105, 105, 105) \
70  macro(dodger_blue , DodgerBlue , 30, 144, 255) \
71  macro(fire_brick , FireBrick , 178, 34, 34) \
72  macro(floral_white , FloralWhite , 255, 250, 240) \
73  macro(forest_green , ForestGreen , 34, 139, 34) \
74  macro(fuchsia , Fuchsia , 255, 0, 255) \
75  macro(gainsboro , Gainsboro , 220, 220, 220) \
76  macro(ghost_white , GhostWhite , 248, 248, 255) \
77  macro(gold , Gold , 255, 215, 0) \
78  macro(goldenrod , Goldenrod , 218, 165, 32) \
79  macro(gray , Gray , 128, 128, 128) \
80  macro(green , Green , 0, 128, 0) \
81  macro(green_yellow , GreenYellow , 173, 255, 47) \
82  macro(honeydew , Honeydew , 240, 255, 240) \
83  macro(hot_pink , HotPink , 255, 105, 180) \
84  macro(indian_red , IndianRed , 205, 92, 92) \
85  macro(indigo , Indigo , 75, 0, 130) \
86  macro(ivory , Ivory , 255, 255, 240) \
87  macro(khaki , Khaki , 240, 230, 140) \
88  macro(lavender , Lavender , 230, 230, 250) \
89  macro(lavender_blush , LavenderBlush , 255, 240, 245) \
90  macro(lawn_green , LawnGreen , 124, 252, 0) \
91  macro(lemon_chiffon , LemonChiffon , 255, 250, 205) \
92  macro(light_blue , LightBlue , 173, 216, 230) \
93  macro(light_coral , LightCoral , 240, 128, 128) \
94  macro(light_cyan , LightCyan , 224, 255, 255) \
95  macro(light_goldenrod_yellow , LightGoldenrodYellow , 250, 250, 210) \
96  macro(light_green , LightGreen , 144, 238, 144) \
97  macro(light_grey , LightGrey , 211, 211, 211) \
98  macro(light_pink , LightPink , 255, 182, 193) \
99  macro(light_salmon , LightSalmon , 255, 160, 122) \
100  macro(light_sea_green , LightSeaGreen , 32, 178, 170) \
101  macro(light_sky_blue , LightSkyBlue , 135, 206, 250) \
102  macro(light_slate_gray , LightSlateGray , 119, 136, 153) \
103  macro(light_steel_blue , LightSteelBlue , 176, 196, 222) \
104  macro(light_yellow , LightYellow , 255, 255, 224) \
105  macro(lime , Lime , 0, 255, 0) \
106  macro(lime_green , LimeGreen , 50, 205, 50) \
107  macro(linen , Linen , 250, 240, 230) \
108  macro(magenta , Magenta , 255, 0, 255) \
109  macro(maroon , Maroon , 128, 0, 0) \
110  macro(medium_aquamarine , MediumAquamarine , 102, 205, 170) \
111  macro(medium_blue , MediumBlue , 0, 0, 205) \
112  macro(medium_orchid , MediumOrchid , 186, 85, 211) \
113  macro(medium_purple , MediumPurple , 147, 112, 219) \
114  macro(medium_sea_green , MediumSeaGreen , 60, 179, 113) \
115  macro(medium_slate_blue , MediumSlateBlue , 123, 104, 238) \
116  macro(medium_spring_green , MediumSpringGreen , 0, 250, 154) \
117  macro(medium_turquoise , MediumTurquoise , 72, 209, 204) \
118  macro(medium_violet_red , MediumVioletRed , 199, 21, 133) \
119  macro(midnight_blue , MidnightBlue , 25, 25, 112) \
120  macro(mint_cream , MintCream , 245, 255, 250) \
121  macro(misty_rose , MistyRose , 255, 228, 225) \
122  macro(moccasin , Moccasin , 255, 228, 181) \
123  macro(navajo_white , NavajoWhite , 255, 222, 173) \
124  macro(navy , Navy , 0, 0, 128) \
125  macro(old_lace , OldLace , 253, 245, 230) \
126  macro(olive , Olive , 128, 128, 0) \
127  macro(olive_drab , OliveDrab , 107, 142, 35) \
128  macro(orange , Orange , 255, 165, 0) \
129  macro(orange_red , OrangeRed , 255, 69, 0) \
130  macro(orchid , Orchid , 218, 112, 214) \
131  macro(pale_goldenrod , PaleGoldenrod , 238, 232, 170) \
132  macro(pale_green , PaleGreen , 152, 251, 152) \
133  macro(pale_turquoise , PaleTurquoise , 175, 238, 238) \
134  macro(pale_violet_red , PaleVioletRed , 219, 112, 147) \
135  macro(papaya_whip , PapayaWhip , 255, 239, 213) \
136  macro(peach_puff , PeachPuff , 255, 218, 185) \
137  macro(peru , Peru , 205, 133, 63) \
138  macro(pink , Pink , 255, 192, 203) \
139  macro(plum , Plum , 221, 160, 221) \
140  macro(powder_blue , PowderBlue , 176, 224, 230) \
141  macro(purple , Purple , 128, 0, 128) \
142  macro(red , Red , 255, 0, 0) \
143  macro(rosy_brown , RosyBrown , 188, 143, 143) \
144  macro(royal_blue , RoyalBlue , 65, 105, 225) \
145  macro(saddle_brown , SaddleBrown , 139, 69, 19) \
146  macro(salmon , Salmon , 250, 128, 114) \
147  macro(sandy_brown , SandyBrown , 244, 164, 96) \
148  macro(sea_green , SeaGreen , 46, 139, 87) \
149  macro(seashell , Seashell , 255, 245, 238) \
150  macro(sienna , Sienna , 160, 82, 45) \
151  macro(silver , Silver , 192, 192, 192) \
152  macro(sky_blue , SkyBlue , 135, 206, 235) \
153  macro(slate_blue , SlateBlue , 106, 90, 205) \
154  macro(slate_gray , SlateGray , 112, 128, 144) \
155  macro(snow , Snow , 255, 250, 250) \
156  macro(spring_green , SpringGreen , 0, 255, 127) \
157  macro(steel_blue , SteelBlue , 70, 130, 180) \
158  macro(tan , Tan , 210, 180, 140) \
159  macro(teal , Teal , 0, 128, 128) \
160  macro(thistle , Thistle , 216, 191, 216) \
161  macro(tomato , Tomato , 255, 99, 71) \
162  macro(turquoise , Turquoise , 64, 224, 208) \
163  macro(violet , Violet , 238, 130, 238) \
164  macro(wheat , Wheat , 245, 222, 179) \
165  macro(white , White , 255, 255, 255) \
166  macro(white_smoke , WhiteSmoke , 245, 245, 245) \
167  macro(yellow , Yellow , 255, 255, 0) \
168  macro(yellow_green , YellowGreen , 154, 205, 50)
169 // clang-format on
170 
171 
172 namespace qx
173 {
174 
175 enum class color_name_type
176 {
177  // | formatter | output example
178  // -------------|-----------|-------------------
179  css_snake, // | {:s} | alice_blue
180  css_pascal, // | {:p} | AliceBlue
181  hex_lower, // | {:x[a]} | f0f8ff[ff]
182  hex_upper, // | {:X[a]} | F0F8FF[FF]
183  rgb, // | {:r[a]} | 240,248,255[,255]
184 };
185 
186 /**
187 
188  @class color
189  @brief RGBA color
190  @author Khrapov
191  @date 10.04.2021
192 
193 **/
194 class color
195 {
196  QX_COPYMOVABLE(color);
197 
198 public:
199  constexpr color() noexcept = default;
200 
201  /**
202  @brief color object constructor
203  @details out of bound values will be clamped
204  @param fRed - red component [0.f, 1.f]
205  @param fGreen - green component [0.f, 1.f]
206  @param fBlue - blue component [0.f, 1.f]
207  @param fAlpha - alpha component [0.f, 1.f]
208  **/
209  constexpr color(float fRed, float fGreen, float fBlue, float fAlpha = 1.f) noexcept;
210 
211  /**
212  @brief color object constructor
213  @details out of bound values will be clamped
214  @param nRed - red component [0, 255]
215  @param nGreen - green component [0, 255]
216  @param nBlue - blue component [0, 255]
217  @param nAlpha - alpha component [0, 255]
218  **/
219  constexpr color(int nRed, int nGreen, int nBlue, int nAlpha = 255) noexcept;
220 
221  /**
222  @brief color object constructor
223  @param nHexValue - hex color value in 0xRRGGBBAA format
224  **/
225  constexpr explicit color(u64 nHexValue) noexcept;
226 
227  /**
228  @brief color object constructor
229  @param vec3 - int vector
230  **/
231  constexpr explicit color(const glm::ivec3& vec3) noexcept;
232 
233  /**
234  @brief color object constructor
235  @param vec4 - int vector
236  **/
237  constexpr explicit color(const glm::ivec4& vec4) noexcept;
238 
239  /**
240  @brief Get red component
241  @retval - red component
242  **/
243  constexpr float r() const noexcept;
244 
245  /**
246  @brief Get green component
247  @retval - green component
248  **/
249  constexpr float g() const noexcept;
250 
251  /**
252  @brief Get blue component
253  @retval - blue component
254  **/
255  constexpr float b() const noexcept;
256 
257  /**
258  @brief Get alpha component
259  @retval - alpha component
260  **/
261  constexpr float a() const noexcept;
262 
263  /**
264  @brief Get color component
265  @param i - component number [0, 3]
266  @retval - component value
267  **/
268  constexpr float& operator[](size_t i) noexcept;
269 
270  /**
271  @brief Get color component
272  @param i - component number [0, 3]
273  @retval - component value
274  **/
275  constexpr const float& operator[](size_t i) const noexcept;
276 
277  /**
278  @brief Get red component as decimal
279  @retval - red component as decimal
280  **/
281  constexpr int r_dec() const noexcept;
282 
283  /**
284  @brief Get green component as decimal
285  @retval - green component as decimal
286  **/
287  constexpr int g_dec() const noexcept;
288 
289  /**
290  @brief Get blue component as decimal
291  @retval - blue component as decimal
292  **/
293  constexpr int b_dec() const noexcept;
294 
295  /**
296  @brief Get alpha component as decimal
297  @retval - alpha component as decimal
298  **/
299  constexpr int a_dec() const noexcept;
300 
301  /**
302  @brief Get pointer to the first component
303  @retval - pointer to the first component
304  **/
305  constexpr const float* data() const noexcept;
306 
307  /**
308  @brief Get color as hex
309  @retval - hex color value in 0xRRGGBB format
310  **/
311  constexpr unsigned int hex_rgb() const noexcept;
312 
313  /**
314  @brief Get color as hex
315  @retval - hex color value in 0xRRGGBBAA format
316  **/
317  constexpr unsigned int hex_rgba() const noexcept;
318 
319  /**
320  @brief Get color as hex
321  @retval - hex color value in 0xAARRGGBB format
322  **/
323  constexpr unsigned int hex_argb() const noexcept;
324 
325  constexpr bool operator==(const color& other) const noexcept;
326  constexpr operator glm::vec3() const noexcept;
327  constexpr operator glm::vec4() const noexcept;
328 
329  /**
330  @brief Add value to red component
331  @details if the new value goes out of range, it will be clamped
332  @param fDeltaValue - delta value
333  **/
334  constexpr void update_r(float fDeltaValue) noexcept;
335 
336  /**
337  @brief Add value to green component
338  @details if the new value goes out of range, it will be clamped
339  @param fDeltaValue - delta value
340  **/
341  constexpr void update_g(float fDeltaValue) noexcept;
342 
343  /**
344  @brief Add value to blue component
345  @details if the new value goes out of range, it will be clamped
346  @param fDeltaValue - delta value
347  **/
348  constexpr void update_b(float fDeltaValue) noexcept;
349 
350  /**
351  @brief Add value to alpha component
352  @details if the new value goes out of range, it will be clamped
353  @param fDeltaValue - delta value
354  **/
355  constexpr void update_a(float fDeltaValue) noexcept;
356 
357  /**
358  @brief Add value to red component
359  @details if the new value goes out of range, it will be clamped
360  @param nDeltaValue - delta value
361  **/
362  constexpr void update_r_dec(int nDeltaValue) noexcept;
363 
364  /**
365  @brief Add value to green component
366  @details if the new value goes out of range, it will be clamped
367  @param nDeltaValue - delta value
368  **/
369  constexpr void update_g_dec(int nDeltaValue) noexcept;
370 
371  /**
372  @brief Add value to blue component
373  @details if the new value goes out of range, it will be clamped
374  @param nDeltaValue - delta value
375  **/
376  constexpr void update_b_dec(int nDeltaValue) noexcept;
377 
378  /**
379  @brief Add value to alpha component
380  @details if the new value goes out of range, it will be clamped
381  @param nDeltaValue - delta value
382  **/
383  constexpr void update_a_dec(int nDeltaValue) noexcept;
384 
385  /**
386  @brief Set new value of red component
387  @details if the new value goes out of range, it will be clamped
388  @param fValue - new value of component
389  **/
390  constexpr void set_r(float fValue) noexcept;
391 
392  /**
393  @brief Set new value of green component
394  @details if the new value goes out of range, it will be clamped
395  @param fValue - new value of component
396  **/
397  constexpr void set_g(float fValue) noexcept;
398 
399  /**
400  @brief Set new value of blue component
401  @details if the new value goes out of range, it will be clamped
402  @param fValue - new value of component
403  **/
404  constexpr void set_b(float fValue) noexcept;
405 
406  /**
407  @brief Set new value of alpha component
408  @details if the new value goes out of range, it will be clamped
409  @param fValue - new value of component
410  **/
411  constexpr void set_a(float fValue) noexcept;
412 
413  /**
414  @brief Set new value of red component
415  @details if the new value goes out of range, it will be clamped
416  @param nValue - new value of component
417  **/
418  constexpr void set_r_dec(int nValue) noexcept;
419 
420  /**
421  @brief Set new value of green component
422  @details if the new value goes out of range, it will be clamped
423  @param nValue - new value of component
424  **/
425  constexpr void set_g_dec(int nValue) noexcept;
426 
427  /**
428  @brief Set new value of blue component
429  @details if the new value goes out of range, it will be clamped
430  @param nValue - new value of component
431  **/
432  constexpr void set_b_dec(int nValue) noexcept;
433 
434  /**
435  @brief Set new value of alpha component
436  @details if the new value goes out of range, it will be clamped
437  @param nValue - new value of component
438  **/
439  constexpr void set_a_dec(int nValue) noexcept;
440 
441  /**
442  @brief Make color darker
443  @param fPercent - dark factor
444  **/
445  constexpr void darken(float fPercent) noexcept;
446 
447  /**
448  @brief Make color brighter
449  @param fPercent - brighter factor
450  **/
451  constexpr void brighten(float fPercent) noexcept;
452 
453  /**
454  @brief Make darker color
455  @param other - original color
456  @param fPercent - dark factor
457  @retval - darker color
458  **/
459  constexpr static color darken(const color& other, float fPercent) noexcept;
460 
461  /**
462  @brief Make brighter color
463  @param other - original color
464  @param fPercent - brighter factor
465  @retval - brighter color
466  **/
467  constexpr static color brighten(const color& other, float fPercent) noexcept;
468 
469 #define _QX_COLOR_METHOD(snakeCaseName, pascalCaseName, r, g, b) \
470  static constexpr auto snakeCaseName(float fAlpha = 1.f) noexcept \
471  { \
472  return color(r, g, b, float_to_dec(fAlpha)); \
473  }
474 
475  /// Color functions
476  _QX_COLORS(_QX_COLOR_METHOD);
477 
478  /**
479  @brief Try to create color from string
480  @param svColorName - color name: css style (alice_blue, AliceBlue, aliceblue) or #F0F8FF or 0xF0F8FFFF(0xRRGGBBAA) or 0xF0F8FF(0xRRGGBB)
481  @retval - found color or nullopt
482  **/
483  static std::optional<color> from_string(string_view svColorName) noexcept;
484 
485  /**
486  @brief Generate a color unique for a hash value
487  @param nHash - hash value
488  @retval - generated color
489  **/
490  static constexpr color from_hash(size_t nHash) noexcept;
491 
492  /**
493  @brief Get empty color (0, 0, 0, 0)
494  @details - empty color can be useful for out of border values
495  as they won't affect calc result
496  @retval - empty color
497  **/
498  static constexpr color empty() noexcept;
499 
500  /**
501  @brief Get number of float components
502  @retval - number of float components
503  **/
504  static constexpr size_t size() noexcept;
505 
506 private:
507  /**
508  @brief Clamp a value to a valid range
509  @param fValue - input value
510  @retval - clamped value [0.f, 1.f]
511  **/
512  static constexpr float clamp_value(float fValue) noexcept;
513 
514  /**
515  @brief Convert decimal value to float
516  @param nValue - decimal value [0, 255]
517  @retval - float value [0.f, 1.f]
518  **/
519  static constexpr float dec_to_float(int nValue) noexcept;
520 
521  /**
522  @brief Convert float value to decimal
523  @param fValue - float value [0.f, 1.f]
524  @retval - decimal value [0, 255]
525  **/
526  static constexpr int float_to_dec(float fValue) noexcept;
527 
528  /**
529  @brief Clamp all vector components and assign
530  @param other - color vector
531  **/
532  constexpr void assign_checked(const glm::vec4& other) noexcept;
533 
534  /**
535  @brief Clamp component and assign
536  @param pComponent - component field
537  @param fValue - new component value
538  **/
539  static constexpr void assign_component_checked(float& pComponent, float fValue) noexcept;
540 
541 private:
542  glm::vec4 m_Color = glm::vec4(1.f);
543 };
544 
545 } // namespace qx
546 
547 #include <qx/render/color.inl>
RGBA color.
Definition: color.h:195
constexpr float g() const noexcept
Get green component.
Definition: color.inl:147
constexpr void update_r_dec(int nDeltaValue) noexcept
Add value to red component.
Definition: color.inl:261
constexpr void update_a(float fDeltaValue) noexcept
Add value to alpha component.
Definition: color.inl:256
constexpr int r_dec() const noexcept
Get red component as decimal.
Definition: color.inl:172
static std::optional< color > from_string(string_view svColorName) noexcept
Try to create color from string.
Definition: color.inl:347
constexpr void update_g(float fDeltaValue) noexcept
Add value to green component.
Definition: color.inl:246
constexpr void update_b(float fDeltaValue) noexcept
Add value to blue component.
Definition: color.inl:251
constexpr void darken(float fPercent) noexcept
Make color darker.
Definition: color.inl:321
constexpr int g_dec() const noexcept
Get green component as decimal.
Definition: color.inl:177
constexpr float a() const noexcept
Get alpha component.
Definition: color.inl:157
constexpr const float * data() const noexcept
Get pointer to the first component.
Definition: color.inl:192
constexpr float b() const noexcept
Get blue component.
Definition: color.inl:152
constexpr float r() const noexcept
Get red component.
Definition: color.inl:142
constexpr void set_g(float fValue) noexcept
Set new value of green component.
Definition: color.inl:286
constexpr float & operator[](size_t i) noexcept
Get color component.
Definition: color.inl:162
constexpr void set_b(float fValue) noexcept
Set new value of blue component.
Definition: color.inl:291
constexpr int b_dec() const noexcept
Get blue component as decimal.
Definition: color.inl:182
static constexpr color from_hash(size_t nHash) noexcept
Generate a color unique for a hash value.
Definition: color.inl:387
static constexpr color empty() noexcept
Get empty color (0, 0, 0, 0)
Definition: color.inl:395
constexpr void update_g_dec(int nDeltaValue) noexcept
Add value to green component.
Definition: color.inl:266
constexpr void set_r(float fValue) noexcept
Set new value of red component.
Definition: color.inl:281
constexpr unsigned int hex_rgba() const noexcept
Get color as hex.
Definition: color.inl:206
constexpr unsigned int hex_rgb() const noexcept
Get color as hex.
Definition: color.inl:197
constexpr void update_r(float fDeltaValue) noexcept
Add value to red component.
Definition: color.inl:241
constexpr int a_dec() const noexcept
Get alpha component as decimal.
Definition: color.inl:187
constexpr void set_g_dec(int nValue) noexcept
Set new value of green component.
Definition: color.inl:306
static constexpr size_t size() noexcept
Get number of float components.
Definition: color.inl:400
_QX_COLORS(_QX_COLOR_METHOD)
Color functions.
constexpr void brighten(float fPercent) noexcept
Make color brighter.
Definition: color.inl:326
constexpr unsigned int hex_argb() const noexcept
Get color as hex.
Definition: color.inl:216
constexpr void update_b_dec(int nDeltaValue) noexcept
Add value to blue component.
Definition: color.inl:271
constexpr void set_r_dec(int nValue) noexcept
Set new value of red component.
Definition: color.inl:301
constexpr void set_b_dec(int nValue) noexcept
Set new value of blue component.
Definition: color.inl:311
constexpr void update_a_dec(int nDeltaValue) noexcept
Add value to alpha component.
Definition: color.inl:276
constexpr void set_a(float fValue) noexcept
Set new value of alpha component.
Definition: color.inl:296
constexpr void set_a_dec(int nValue) noexcept
Set new value of alpha component.
Definition: color.inl:316
std::uint64_t u64
Definition: typedefs.h:26