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