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 © 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  css_snake, // {:s} alice_blue
178  css_pascal, // {:p} AliceBlue
179  hex_lower, // {:x[a]} f0f8ff[ff]
180  hex_upper, // {:X[a]} F0F8FF[FF]
181  rgb, // {:r[a]} 240,248,255[,255]
182 };
183 
184 /**
185 
186  @class color
187  @brief RGBA color
188  @author Khrapov
189  @date 10.04.2021
190 
191 **/
192 class color
193 {
194  QX_COPYMOVABLE(color);
195 
196 public:
197  constexpr color() noexcept = default;
198 
199  /**
200  @brief color object constructor
201  @details out of bound values will be clamped
202  @param fRed - red component [0.f, 1.f]
203  @param fGreen - green component [0.f, 1.f]
204  @param fBlue - blue component [0.f, 1.f]
205  @param fAlpha - alpha component [0.f, 1.f]
206  **/
207  constexpr color(float fRed, float fGreen, float fBlue, float fAlpha = 1.f) noexcept;
208 
209  /**
210  @brief color object constructor
211  @details out of bound values will be clamped
212  @param nRed - red component [0, 255]
213  @param nGreen - green component [0, 255]
214  @param nBlue - blue component [0, 255]
215  @param nAlpha - alpha component [0, 255]
216  **/
217  constexpr color(int nRed, int nGreen, int nBlue, int nAlpha = 255) noexcept;
218 
219  /**
220  @brief color object constructor
221  @param nHexValue - hex color value in 0xRRGGBBAA format
222  **/
223  constexpr explicit color(u64 nHexValue) noexcept;
224 
225  /**
226  @brief color object constructor
227  @param vec3 - int vector
228  **/
229  constexpr explicit color(const glm::ivec3& vec3) noexcept;
230 
231  /**
232  @brief color object constructor
233  @param vec4 - int vector
234  **/
235  constexpr explicit color(const glm::ivec4& vec4) noexcept;
236 
237  /**
238  @brief Get red component
239  @retval - red component
240  **/
241  constexpr float r() const noexcept;
242 
243  /**
244  @brief Get green component
245  @retval - green component
246  **/
247  constexpr float g() const noexcept;
248 
249  /**
250  @brief Get blue component
251  @retval - blue component
252  **/
253  constexpr float b() const noexcept;
254 
255  /**
256  @brief Get alpha component
257  @retval - alpha component
258  **/
259  constexpr float a() const noexcept;
260 
261  /**
262  @brief Get color component
263  @param i - component number [0, 3]
264  @retval - component value
265  **/
266  constexpr float& operator[](size_t i) noexcept;
267 
268  /**
269  @brief Get color component
270  @param i - component number [0, 3]
271  @retval - component value
272  **/
273  constexpr const float& operator[](size_t i) const noexcept;
274 
275  /**
276  @brief Get red component as decimal
277  @retval - red component as decimal
278  **/
279  constexpr int r_dec() const noexcept;
280 
281  /**
282  @brief Get green component as decimal
283  @retval - green component as decimal
284  **/
285  constexpr int g_dec() const noexcept;
286 
287  /**
288  @brief Get blue component as decimal
289  @retval - blue component as decimal
290  **/
291  constexpr int b_dec() const noexcept;
292 
293  /**
294  @brief Get alpha component as decimal
295  @retval - alpha component as decimal
296  **/
297  constexpr int a_dec() const noexcept;
298 
299  /**
300  @brief Get pointer to the first component
301  @retval - pointer to the first component
302  **/
303  constexpr const float* data() const noexcept;
304 
305  /**
306  @brief Get color as hex
307  @retval - hex color value in 0xRRGGBB format
308  **/
309  constexpr unsigned int hex_rgb() const noexcept;
310 
311  /**
312  @brief Get color as hex
313  @retval - hex color value in 0xRRGGBBAA format
314  **/
315  constexpr unsigned int hex_rgba() const noexcept;
316 
317  /**
318  @brief Get color as hex
319  @retval - hex color value in 0xAARRGGBB format
320  **/
321  constexpr unsigned int hex_argb() const noexcept;
322 
323  constexpr bool operator==(const color& other) const noexcept;
324  constexpr operator glm::vec3() const noexcept;
325  constexpr operator glm::vec4() const noexcept;
326 
327  /**
328  @brief Add value to red component
329  @details if the new value goes out of range, it will be clamped
330  @param fDeltaValue - delta value
331  **/
332  constexpr void update_r(float fDeltaValue) noexcept;
333 
334  /**
335  @brief Add value to green component
336  @details if the new value goes out of range, it will be clamped
337  @param fDeltaValue - delta value
338  **/
339  constexpr void update_g(float fDeltaValue) noexcept;
340 
341  /**
342  @brief Add value to blue component
343  @details if the new value goes out of range, it will be clamped
344  @param fDeltaValue - delta value
345  **/
346  constexpr void update_b(float fDeltaValue) noexcept;
347 
348  /**
349  @brief Add value to alpha component
350  @details if the new value goes out of range, it will be clamped
351  @param fDeltaValue - delta value
352  **/
353  constexpr void update_a(float fDeltaValue) noexcept;
354 
355  /**
356  @brief Add value to red component
357  @details if the new value goes out of range, it will be clamped
358  @param nDeltaValue - delta value
359  **/
360  constexpr void update_r_dec(int nDeltaValue) noexcept;
361 
362  /**
363  @brief Add value to green component
364  @details if the new value goes out of range, it will be clamped
365  @param nDeltaValue - delta value
366  **/
367  constexpr void update_g_dec(int nDeltaValue) noexcept;
368 
369  /**
370  @brief Add value to blue component
371  @details if the new value goes out of range, it will be clamped
372  @param nDeltaValue - delta value
373  **/
374  constexpr void update_b_dec(int nDeltaValue) noexcept;
375 
376  /**
377  @brief Add value to alpha component
378  @details if the new value goes out of range, it will be clamped
379  @param nDeltaValue - delta value
380  **/
381  constexpr void update_a_dec(int nDeltaValue) noexcept;
382 
383  /**
384  @brief Set new value of red component
385  @details if the new value goes out of range, it will be clamped
386  @param fValue - new value of component
387  **/
388  constexpr void set_r(float fValue) noexcept;
389 
390  /**
391  @brief Set new value of green component
392  @details if the new value goes out of range, it will be clamped
393  @param fValue - new value of component
394  **/
395  constexpr void set_g(float fValue) noexcept;
396 
397  /**
398  @brief Set new value of blue component
399  @details if the new value goes out of range, it will be clamped
400  @param fValue - new value of component
401  **/
402  constexpr void set_b(float fValue) noexcept;
403 
404  /**
405  @brief Set new value of alpha component
406  @details if the new value goes out of range, it will be clamped
407  @param fValue - new value of component
408  **/
409  constexpr void set_a(float fValue) noexcept;
410 
411  /**
412  @brief Set new value of red component
413  @details if the new value goes out of range, it will be clamped
414  @param nValue - new value of component
415  **/
416  constexpr void set_r_dec(int nValue) noexcept;
417 
418  /**
419  @brief Set new value of green component
420  @details if the new value goes out of range, it will be clamped
421  @param nValue - new value of component
422  **/
423  constexpr void set_g_dec(int nValue) noexcept;
424 
425  /**
426  @brief Set new value of blue component
427  @details if the new value goes out of range, it will be clamped
428  @param nValue - new value of component
429  **/
430  constexpr void set_b_dec(int nValue) noexcept;
431 
432  /**
433  @brief Set new value of alpha component
434  @details if the new value goes out of range, it will be clamped
435  @param nValue - new value of component
436  **/
437  constexpr void set_a_dec(int nValue) noexcept;
438 
439  /**
440  @brief Make color darker
441  @param fPercent - dark factor
442  **/
443  constexpr void darken(float fPercent) noexcept;
444 
445  /**
446  @brief Make color brighter
447  @param fPercent - brighter factor
448  **/
449  constexpr void brighten(float fPercent) noexcept;
450 
451  /**
452  @brief Make darker color
453  @param other - original color
454  @param fPercent - dark factor
455  @retval - darker color
456  **/
457  constexpr static color darken(const color& other, float fPercent) noexcept;
458 
459  /**
460  @brief Make brighter color
461  @param other - original color
462  @param fPercent - brighter factor
463  @retval - brighter color
464  **/
465  constexpr static color brighten(const color& other, float fPercent) noexcept;
466 
467 #define _QX_COLOR_METHOD(snakeCaseName, pascalCaseName, r, g, b) \
468  static constexpr auto snakeCaseName(float fAlpha = 1.f) noexcept \
469  { \
470  return color(r, g, b, float_to_dec(fAlpha)); \
471  }
472 
473  /// Color functions
474  _QX_COLORS(_QX_COLOR_METHOD);
475 
476  /**
477  @brief Try to create color from string
478  @param svColorName - color name: css style (alice_blue, AliceBlue, aliceblue) or #F0F8FF or 0xF0F8FFFF(0xRRGGBBAA) or 0xF0F8FF(0xRRGGBB)
479  @retval - found color or nullopt
480  **/
481  static std::optional<color> from_string(string_view svColorName) noexcept;
482 
483  /**
484  @brief Get empty color (0, 0, 0, 0)
485  @details - empty color can be useful for out of border values
486  as they won't affect calc result
487  @retval - empty color
488  **/
489  static constexpr color empty() noexcept;
490 
491  /**
492  @brief Get number of float components
493  @retval - number of float components
494  **/
495  static constexpr size_t size() noexcept;
496 
497 private:
498  /**
499  @brief Clamp a value to a valid range
500  @param fValue - input value
501  @retval - clamped value [0.f, 1.f]
502  **/
503  static constexpr float clamp_value(float fValue) noexcept;
504 
505  /**
506  @brief Convert decimal value to float
507  @param nValue - decimal value [0, 255]
508  @retval - float value [0.f, 1.f]
509  **/
510  static constexpr float dec_to_float(int nValue) noexcept;
511 
512  /**
513  @brief Convert float value to decimal
514  @param fValue - float value [0.f, 1.f]
515  @retval - decimal value [0, 255]
516  **/
517  static constexpr int float_to_dec(float fValue) noexcept;
518 
519  /**
520  @brief Clamp all vector components and assign
521  @param other - color vector
522  **/
523  constexpr void assign_checked(const glm::vec4& other) noexcept;
524 
525  /**
526  @brief Clamp component and assign
527  @param pComponent - component field
528  @param fValue - new component value
529  **/
530  static constexpr void assign_component_checked(float& pComponent, float fValue) noexcept;
531 
532 private:
533  glm::vec4 m_Color = glm::vec4(1.f);
534 };
535 
536 } // namespace qx
537 
538 #include <qx/render/color.inl>
RGBA color.
Definition: color.h:193
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 empty() noexcept
Get empty color (0, 0, 0, 0)
Definition: color.inl:387
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:392
_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