The Battle for Wesnoth  1.19.5+dev
color.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2024
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
17 #include <SDL2/SDL_pixels.h>
18 
19 #include <algorithm> // for max
20 #include <cstdint>
21 #include <ostream>
22 #include <string>
23 #include <utility>
24 
25 constexpr uint32_t SDL_ALPHA_MASK = 0xFF000000;
26 constexpr uint32_t SDL_RED_MASK = 0x00FF0000;
27 constexpr uint32_t SDL_GREEN_MASK = 0x0000FF00;
28 constexpr uint32_t SDL_BLUE_MASK = 0x000000FF;
29 
30 constexpr uint32_t SDL_ALPHA_BITSHIFT = 24;
31 constexpr uint32_t SDL_RED_BITSHIFT = 16;
32 constexpr uint32_t SDL_GREEN_BITSHIFT = 8;
33 constexpr uint32_t SDL_BLUE_BITSHIFT = 0;
34 
35 constexpr uint32_t RGBA_ALPHA_MASK = 0x000000FF;
36 constexpr uint32_t RGBA_RED_MASK = 0xFF000000;
37 constexpr uint32_t RGBA_GREEN_MASK = 0x00FF0000;
38 constexpr uint32_t RGBA_BLUE_MASK = 0x0000FF00;
39 
40 constexpr uint32_t RGBA_ALPHA_BITSHIFT = 0;
41 constexpr uint32_t RGBA_RED_BITSHIFT = 24;
42 constexpr uint32_t RGBA_GREEN_BITSHIFT = 16;
43 constexpr uint32_t RGBA_BLUE_BITSHIFT = 8;
44 
45 constexpr uint8_t ALPHA_OPAQUE = SDL_ALPHA_OPAQUE; // This is always 255 in SDL2
46 
47 // Functions for manipulating RGB values.
48 constexpr uint8_t float_to_color(double n);
49 constexpr uint8_t float_to_color(float n);
50 constexpr uint8_t color_multiply(uint8_t n1, uint8_t n2);
51 constexpr uint8_t color_blend(uint8_t n1, uint8_t n2, uint8_t p);
52 
53 /**
54  * The basic class for representing 8-bit RGB or RGBA colour values.
55  *
56  * This is a thin wrapper over SDL_Color, and can be used interchangeably.
57  */
58 struct color_t : SDL_Color
59 {
60  /** color_t initializes to fully opaque white by default. */
61  constexpr color_t() : SDL_Color{255, 255, 255, ALPHA_OPAQUE} {}
62 
63  /** Basic RGB or RGBA constructor. */
64  constexpr color_t(uint8_t r_val, uint8_t g_val, uint8_t b_val, uint8_t a_val = ALPHA_OPAQUE)
65  : SDL_Color{r_val, g_val, b_val, a_val}
66  {}
67 
68  /** This is a thin wrapper. There is nothing extra to do here. */
69  constexpr color_t(const SDL_Color& c) : SDL_Color{c} {}
70 
71  /**
72  * Creates a new color_t object from a string variable in "R,G,B,A" format.
73  * An empty string results in white. Otherwise, omitting components other than
74  * alpha is an error.
75  *
76  * @param c A string variable, in "R,G,B,A" format.
77  * @return A new color_t object.
78  *
79  * @throw std::invalid_argument if the string is not correctly formatted
80  */
81  static color_t from_rgba_string(std::string_view c);
82 
83  /**
84  * Creates a new opaque color_t object from a string variable in "R,G,B" format.
85  * An empty string results in white. Otherwise, omitting components is an error.
86  *
87  * @param c A string variable, in "R,G,B" format.
88  * @return A new color_t object.
89  *
90  * @throw std::invalid_argument if the string is not correctly formatted
91  */
92  static color_t from_rgb_string(std::string_view c);
93 
94  /**
95  * Creates a new color_t object from a string variable in hex format.
96  *
97  * @param c A string variable, in rrggbb hex format.
98  * @return A new color_t object.
99  *
100  * @throw std::invalid_argument if the string is not correctly formatted
101  */
102  static color_t from_hex_string(std::string_view c);
103 
104  /**
105  * Creates a new color_t object from a uint32_t variable.
106  *
107  * @param c A uint32_t variable, in RGBA format.
108  * @return A new color_t object.
109  */
110  static constexpr color_t from_rgba_bytes(uint32_t c)
111  {
112  return {
113  static_cast<uint8_t>((RGBA_RED_MASK & c) >> RGBA_RED_BITSHIFT),
114  static_cast<uint8_t>((RGBA_GREEN_MASK & c) >> RGBA_GREEN_BITSHIFT),
115  static_cast<uint8_t>((RGBA_BLUE_MASK & c) >> RGBA_BLUE_BITSHIFT),
116  static_cast<uint8_t>((RGBA_ALPHA_MASK & c) >> RGBA_ALPHA_BITSHIFT),
117  };
118  }
119 
120  /**
121  * Creates a new color_t object from a uint32_t variable.
122  *
123  * @param c A uint32_t variable, in ARGB format.
124  * @return A new color_t object.
125  */
126  static constexpr color_t from_argb_bytes(uint32_t c)
127  {
128  return {
129  static_cast<uint8_t>((SDL_RED_MASK & c) >> SDL_RED_BITSHIFT),
130  static_cast<uint8_t>((SDL_GREEN_MASK & c) >> SDL_GREEN_BITSHIFT),
131  static_cast<uint8_t>((SDL_BLUE_MASK & c) >> SDL_BLUE_BITSHIFT),
132  static_cast<uint8_t>((SDL_ALPHA_MASK & c) >> SDL_ALPHA_BITSHIFT),
133  };
134  }
135 
136  /**
137  * Returns the stored color in rrggbb hex format.
138  *
139  * @return The string in hex format. The preceding '#' needed for pango markup
140  * is prepended.
141  */
142  std::string to_hex_string() const;
143 
144  /**
145  * Returns the stored color as a uint32_t, in RGBA format.
146  *
147  * @return The new uint32_t object.
148  */
149  constexpr uint32_t to_rgba_bytes() const
150  {
151  return
152  (static_cast<uint32_t>(r) << RGBA_RED_BITSHIFT) |
153  (static_cast<uint32_t>(g) << RGBA_GREEN_BITSHIFT) |
154  (static_cast<uint32_t>(b) << RGBA_BLUE_BITSHIFT) |
155  (static_cast<uint32_t>(a) << RGBA_ALPHA_BITSHIFT);
156  }
157 
158  /**
159  * Returns the stored color as a uint32_t, an ARGB format.
160  *
161  * @return The new uint32_t object.
162  */
163  constexpr uint32_t to_argb_bytes() const
164  {
165  return
166  (static_cast<uint32_t>(r) << SDL_RED_BITSHIFT) |
167  (static_cast<uint32_t>(g) << SDL_GREEN_BITSHIFT) |
168  (static_cast<uint32_t>(b) << SDL_BLUE_BITSHIFT) |
169  (static_cast<uint32_t>(a) << SDL_ALPHA_BITSHIFT);
170  }
171 
172  /**
173  * Returns the stored color as an "R,G,B,A" string
174  *
175  * @return The new color string.
176  */
177  std::string to_rgba_string() const;
178 
179  /**
180  * Returns the stored color as an "R,G,B" string
181  *
182  * @return The new color string.
183  */
184  std::string to_rgb_string() const;
185 
186  constexpr bool null() const
187  {
188  return *this == null_color();
189  }
190 
191  constexpr bool operator==(const color_t& c) const
192  {
193  return r == c.r && g == c.g && b == c.b && a == c.a;
194  }
195 
196  constexpr bool operator!=(const color_t& c) const
197  {
198  return !(*this == c);
199  }
200 
201  constexpr color_t blend_add(const color_t& c) const
202  {
203  // Do some magic to detect integer overflow
204  // We want overflows to max out the component instead of wrapping.
205  // The static_cast is to silence narrowing conversion warnings etc
206  return {
207  static_cast<uint8_t>(r > 255 - c.r ? 255 : r + c.r),
208  static_cast<uint8_t>(g > 255 - c.g ? 255 : g + c.g),
209  static_cast<uint8_t>(b > 255 - c.b ? 255 : b + c.b),
210  static_cast<uint8_t>(a > 255 - c.a ? 255 : a + c.a),
211  };
212  }
213 
214  constexpr color_t blend_lighten(const color_t& c) const
215  {
216  return {
217  std::max<uint8_t>(r, c.r),
218  std::max<uint8_t>(g, c.g),
219  std::max<uint8_t>(b, c.b),
220  std::max<uint8_t>(a, c.a),
221  };
222  }
223 
224  constexpr color_t inverse() const {
225  return {
226  static_cast<uint8_t>(255 - r),
227  static_cast<uint8_t>(255 - g),
228  static_cast<uint8_t>(255 - b),
229  a
230  };
231  }
232 
233  /**
234  * Blend smoothly with another color_t.
235  *
236  * @param c The color to blend with.
237  * @param p The proportion of the other color to blend. 0 will
238  * return the original color, 255 the blending color.
239  */
240  constexpr color_t smooth_blend(const color_t& c, uint8_t p) const
241  {
242  return {
243  color_blend(r, c.r, p),
244  color_blend(g, c.g, p),
245  color_blend(b, c.b, p),
246  color_blend(a, c.a, p)
247  };
248  }
249 
250  /** Definition of a 'null' color - fully transparent black. */
251  static constexpr color_t null_color()
252  {
253  return {0,0,0,0};
254  }
255 };
256 
257 inline std::ostream& operator<<(std::ostream& s, const color_t& c)
258 {
259  s << c.to_hex_string();
260  return s;
261 }
262 
263 namespace std
264 {
265  template<>
266  struct hash<color_t>
267  {
268  std::size_t operator()(const color_t& c) const noexcept
269  {
270  return c.to_rgba_bytes();
271  }
272  };
273 }
274 
275 /********************************************/
276 /* Functions for manipulating colour values */
277 /********************************************/
278 
279 /** Convert a double in the range [0.0,1.0] to an 8-bit colour value. */
280 constexpr uint8_t float_to_color(double n)
281 {
282  if(n <= 0.0) return 0;
283  else if(n >= 1.0) return 255;
284  else return uint8_t(n * 256.0);
285 }
286 
287 /** Convert a float in the range [0.0,1.0] to an 8-bit colour value. */
288 constexpr uint8_t float_to_color(float n)
289 {
290  if(n <= 0.0f) return 0;
291  else if(n >= 1.0f) return 255;
292  else return uint8_t(n * 256.0f);
293 }
294 
295 /** Multiply two 8-bit colour values as if in the range [0.0,1.0]. */
296 constexpr uint8_t color_multiply(uint8_t n1, uint8_t n2)
297 {
298  return uint8_t((uint16_t(n1) * uint16_t(n2))/255);
299 }
300 
301 /**
302  * Blend 8-bit colour value with another in the given proportion.
303  *
304  * A proportion of 0 returns the first value, 255 the second.
305  */
306 constexpr uint8_t color_blend(uint8_t n1, uint8_t n2, uint8_t p)
307 {
308  return color_multiply(n1, ~p) + color_multiply(n2, p);
309 }
double g
Definition: astarsearch.cpp:63
constexpr uint8_t ALPHA_OPAQUE
Definition: color.hpp:45
constexpr uint32_t RGBA_RED_MASK
Definition: color.hpp:36
constexpr uint32_t SDL_RED_BITSHIFT
Definition: color.hpp:31
constexpr uint32_t RGBA_BLUE_BITSHIFT
Definition: color.hpp:43
constexpr uint32_t SDL_GREEN_BITSHIFT
Definition: color.hpp:32
constexpr uint32_t SDL_GREEN_MASK
Definition: color.hpp:27
constexpr uint32_t RGBA_GREEN_MASK
Definition: color.hpp:37
constexpr uint32_t SDL_ALPHA_MASK
Definition: color.hpp:25
constexpr uint8_t color_multiply(uint8_t n1, uint8_t n2)
Multiply two 8-bit colour values as if in the range [0.0,1.0].
Definition: color.hpp:296
constexpr uint32_t SDL_BLUE_BITSHIFT
Definition: color.hpp:33
std::ostream & operator<<(std::ostream &s, const color_t &c)
Definition: color.hpp:257
constexpr uint8_t float_to_color(double n)
Convert a double in the range [0.0,1.0] to an 8-bit colour value.
Definition: color.hpp:280
constexpr uint32_t SDL_ALPHA_BITSHIFT
Definition: color.hpp:30
constexpr uint32_t RGBA_ALPHA_BITSHIFT
Definition: color.hpp:40
constexpr uint8_t color_blend(uint8_t n1, uint8_t n2, uint8_t p)
Blend 8-bit colour value with another in the given proportion.
Definition: color.hpp:306
constexpr uint32_t RGBA_GREEN_BITSHIFT
Definition: color.hpp:42
constexpr uint32_t SDL_RED_MASK
Definition: color.hpp:26
constexpr uint32_t RGBA_BLUE_MASK
Definition: color.hpp:38
constexpr uint32_t RGBA_ALPHA_MASK
Definition: color.hpp:35
constexpr uint32_t RGBA_RED_BITSHIFT
Definition: color.hpp:41
constexpr uint32_t SDL_BLUE_MASK
Definition: color.hpp:28
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
static constexpr color_t from_rgba_bytes(uint32_t c)
Creates a new color_t object from a uint32_t variable.
Definition: color.hpp:110
constexpr uint32_t to_rgba_bytes() const
Returns the stored color as a uint32_t, in RGBA format.
Definition: color.hpp:149
static color_t from_hex_string(std::string_view c)
Creates a new color_t object from a string variable in hex format.
Definition: color.cpp:64
constexpr color_t smooth_blend(const color_t &c, uint8_t p) const
Blend smoothly with another color_t.
Definition: color.hpp:240
constexpr uint32_t to_argb_bytes() const
Returns the stored color as a uint32_t, an ARGB format.
Definition: color.hpp:163
constexpr bool operator!=(const color_t &c) const
Definition: color.hpp:196
std::string to_hex_string() const
Returns the stored color in rrggbb hex format.
Definition: color.cpp:88
static color_t from_rgb_string(std::string_view c)
Creates a new opaque color_t object from a string variable in "R,G,B" format.
Definition: color.cpp:44
static constexpr color_t null_color()
Definition of a 'null' color - fully transparent black.
Definition: color.hpp:251
std::string to_rgb_string() const
Returns the stored color as an "R,G,B" string.
Definition: color.cpp:117
constexpr color_t blend_lighten(const color_t &c) const
Definition: color.hpp:214
constexpr color_t(const SDL_Color &c)
This is a thin wrapper.
Definition: color.hpp:69
constexpr color_t blend_add(const color_t &c) const
Definition: color.hpp:201
constexpr color_t inverse() const
Definition: color.hpp:224
constexpr bool operator==(const color_t &c) const
Definition: color.hpp:191
static color_t from_rgba_string(std::string_view c)
Creates a new color_t object from a string variable in "R,G,B,A" format.
Definition: color.cpp:23
static constexpr color_t from_argb_bytes(uint32_t c)
Creates a new color_t object from a uint32_t variable.
Definition: color.hpp:126
std::string to_rgba_string() const
Returns the stored color as an "R,G,B,A" string.
Definition: color.cpp:105
constexpr color_t()
color_t initializes to fully opaque white by default.
Definition: color.hpp:61
constexpr color_t(uint8_t r_val, uint8_t g_val, uint8_t b_val, uint8_t a_val=ALPHA_OPAQUE)
Basic RGB or RGBA constructor.
Definition: color.hpp:64
std::size_t operator()(const color_t &c) const noexcept
Definition: color.hpp:268
mock_char c
mock_party p
static map_location::direction n
static map_location::direction s
#define b