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