1 /*
2 Copyright (C) 2003 - 2018 by the Battle for Wesnoth Project https://www.wesnoth.org/
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY.
10
11 See the COPYING file for more details.
12 */
13
14 #pragma once
15
16 #include "global.hpp"
17
18 #include <algorithm> // for max
19 #include <cstdint>
20 #include <ostream>
21 #include <string>
22 #include <utility>
23
24 struct SDL_Color;
25
26 //
27 // TODO: constexpr
28 //
29
30 const uint32_t SDL_ALPHA_MASK = 0xFF000000;
31 const uint32_t SDL_RED_MASK = 0x00FF0000;
32 const uint32_t SDL_GREEN_MASK = 0x0000FF00;
33 const uint32_t SDL_BLUE_MASK = 0x000000FF;
34
35 const uint32_t SDL_ALPHA_BITSHIFT = 24;
36 const uint32_t SDL_RED_BITSHIFT = 16;
37 const uint32_t SDL_GREEN_BITSHIFT = 8;
38 const uint32_t SDL_BLUE_BITSHIFT = 0;
39
40 const uint32_t RGBA_ALPHA_MASK = 0x000000FF;
41 const uint32_t RGBA_RED_MASK = 0xFF000000;
42 const uint32_t RGBA_GREEN_MASK = 0x00FF0000;
43 const uint32_t RGBA_BLUE_MASK = 0x0000FF00;
44
45 const uint32_t RGBA_ALPHA_BITSHIFT = 0;
46 const uint32_t RGBA_RED_BITSHIFT = 24;
47 const uint32_t RGBA_GREEN_BITSHIFT = 16;
48 const uint32_t RGBA_BLUE_BITSHIFT = 8;
49
50 const uint8_t ALPHA_OPAQUE = 255;
51
52 struct color_t
53 {
color_tcolor_t54 color_t()
55 : r(255)
56 , g(255)
57 , b(255)
58 , a(ALPHA_OPAQUE)
59 {}
60
color_tcolor_t61 color_t(uint8_t r_val, uint8_t g_val, uint8_t b_val, uint8_t a_val = ALPHA_OPAQUE)
62 : r(r_val)
63 , g(g_val)
64 , b(b_val)
65 , a(a_val)
66 {}
67
68 // Implemented in sdl/utils.cpp to avoid dependency nightmares
69 explicit color_t(const 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(const std::string& 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(const std::string& 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(const std::string& 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 color_t from_rgba_bytes(uint32_t c);
111
112 /**
113 * Creates a new color_t object from a uint32_t variable.
114 *
115 * @param c A uint32_t variable, in ARGB format.
116 * @return A new color_t object.
117 */
118 static color_t from_argb_bytes(uint32_t c);
119
120 /**
121 * Returns the stored color in rrggbb hex format.
122 *
123 * @return The string in hex format. The preceding '#' needed for pango markup
124 * is prepended.
125 */
126 std::string to_hex_string() const;
127
128 /**
129 * Returns the stored color as a uint32_t, in RGBA format.
130 *
131 * @return The new uint32_t object.
132 */
to_rgba_bytescolor_t133 uint32_t to_rgba_bytes() const
134 {
135 return
136 (static_cast<uint32_t>(r) << RGBA_RED_BITSHIFT) |
137 (static_cast<uint32_t>(g) << RGBA_GREEN_BITSHIFT) |
138 (static_cast<uint32_t>(b) << RGBA_BLUE_BITSHIFT) |
139 (static_cast<uint32_t>(a) << RGBA_ALPHA_BITSHIFT);
140 }
141
142 /**
143 * Returns the stored color as a uint32_t, an ARGB format.
144 *
145 * @return The new uint32_t object.
146 */
to_argb_bytescolor_t147 uint32_t to_argb_bytes() const
148 {
149 return
150 (static_cast<uint32_t>(r) << SDL_RED_BITSHIFT) |
151 (static_cast<uint32_t>(g) << SDL_GREEN_BITSHIFT) |
152 (static_cast<uint32_t>(b) << SDL_BLUE_BITSHIFT) |
153 (static_cast<uint32_t>(a) << SDL_ALPHA_BITSHIFT);
154 }
155
156 /**
157 * Returns the stored color as an "R,G,B,A" string
158 *
159 * @return The new color string.
160 */
161 std::string to_rgba_string() const;
162
163 /**
164 * Returns the stored color as an "R,G,B" string
165 *
166 * @return The new color string.
167 */
168 std::string to_rgb_string() const;
169
170 /**
171 * Returns the stored color as an color_t object.
172 *
173 * @return The new color_t object.
174 */
175 // Implemented in sdl/utils.cpp to avoid dependency nightmares
176 SDL_Color to_sdl() const;
177
178 /** Red value */
179 uint8_t r;
180
181 /** Green value */
182 uint8_t g;
183
184 /** Blue value */
185 uint8_t b;
186
187 /** Alpha value */
188 uint8_t a;
189
nullcolor_t190 bool null() const
191 {
192 return *this == null_color();
193 }
194
operator ==color_t195 bool operator==(const color_t& c) const
196 {
197 return r == c.r && g == c.g && b == c.b && a == c.a;
198 }
199
operator !=color_t200 bool operator!=(const color_t& c) const
201 {
202 return !(*this == c);
203 }
204
blend_addcolor_t205 color_t blend_add(const color_t& c) const
206 {
207 // Do some magic to detect integer overflow
208 // We want overflows to max out the component instead of wrapping.
209 // The static_cast is to silence narrowing conversion warnings etc
210 return {
211 static_cast<uint8_t>(r > 255 - c.r ? 255 : r + c.r),
212 static_cast<uint8_t>(g > 255 - c.g ? 255 : g + c.g),
213 static_cast<uint8_t>(b > 255 - c.b ? 255 : b + c.b),
214 static_cast<uint8_t>(a > 255 - c.a ? 255 : a + c.a),
215 };
216 }
217
blend_lightencolor_t218 color_t blend_lighten(const color_t& c) const
219 {
220 return {
221 std::max<uint8_t>(r, c.r),
222 std::max<uint8_t>(g, c.g),
223 std::max<uint8_t>(b, c.b),
224 std::max<uint8_t>(a, c.a),
225 };
226 }
227
inversecolor_t228 color_t inverse() const {
229 return {
230 static_cast<uint8_t>(255 - r),
231 static_cast<uint8_t>(255 - g),
232 static_cast<uint8_t>(255 - b),
233 a
234 };
235 }
236
237 /** Definition of a 'null' color - fully transparent black. */
null_colorcolor_t238 static color_t null_color()
239 {
240 return {0,0,0,0};
241 }
242 };
243
operator <<(std::ostream & s,const color_t & c)244 inline std::ostream& operator<<(std::ostream& s, const color_t& c)
245 {
246 s << static_cast<int>(c.r) << " "
247 << static_cast<int>(c.g) << " "
248 << static_cast<int>(c.b) << " "
249 << static_cast<int>(c.a) << std::endl;
250
251 return s;
252 }
253
254 namespace std
255 {
256 template<>
257 struct hash<color_t>
258 {
operator ()std::hash259 size_t operator()(const color_t& c) const NOEXCEPT
260 {
261 return c.to_rgba_bytes();
262 }
263 };
264 }
265