ge211
ge211_color.cpp
1 #include "ge211_color.h"
2 
3 #include <algorithm>
4 #include <cmath>
5 #include <tuple>
6 
7 namespace ge211 {
8 
9 template<class T, class U>
10 static T weighted_average(T t, double weight, U u) noexcept
11 {
12  double f1 = static_cast<double>(t);
13  double f2 = static_cast<double>(u);
14  double result = (1 - weight) * f1 + weight * f2;
15  return T(result);
16 }
17 
18 template<class T, class Field>
19 static T adjust_field(T result, Field T::*field,
20  double weight, double goal) noexcept
21 {
22  result.*field = weighted_average(result.*field, weight, goal);
23  return result;
24 }
25 
26 Color Color::from_rgba(double red, double green, double blue, double alpha) noexcept
27 {
28  return Color{uint8_t(255 * red),
29  uint8_t(255 * green),
30  uint8_t(255 * blue),
31  uint8_t(255 * alpha)};
32 }
33 
34 // Creates a color from the HSL/HSV-style hue, the chroma, an adjustment
35 // for brightness, and the alpha.
36 //
37 // From https://en.wikipedia.org/wiki/HSL_and_HSV
38 static Color from_hcma(double hue,
39  double C,
40  double m,
41  double alpha) noexcept
42 {
43  double H6 = std::fmod(hue, 360.0) / 60.0;
44  double X = C * (1 - std::fabs(std::fmod(H6, 2) - 1));
45 
46  double r1 = 0, g1 = 0, b1 = 0;
47 
48  if (H6 <= 1) {
49  r1 = C;
50  g1 = X;
51  } else if (H6 <= 2) {
52  r1 = X;
53  g1 = C;
54  } else if (H6 <= 3) {
55  g1 = C;
56  b1 = X;
57  } else if (H6 <= 4) {
58  g1 = X;
59  b1 = C;
60  } else if (H6 <= 5) {
61  b1 = C;
62  r1 = X;
63  } else {
64  b1 = X;
65  r1 = C;
66  }
67 
68  return Color::from_rgba(r1 + m, g1 + m, b1 + m, alpha);
69 }
70 
71 Color Color::from_hsla(double hue, double saturation, double lightness,
72  double alpha) noexcept
73 {
74  double C = (1 - std::fabs(2 * lightness - 1)) * saturation;
75  double m = lightness - 0.5 * C;
76  return from_hcma(hue, C, m, alpha);
77 }
78 
79 Color Color::from_hsva(double hue, double saturation, double value,
80  double alpha) noexcept
81 {
82  double C = value * saturation;
83  double m = value - C;
84  return from_hcma(hue, C, m, alpha);
85 }
86 
87 Color Color::invert() const noexcept
88 {
89  return Color{uint8_t(~red_), uint8_t(~blue_), uint8_t(~green_), alpha_};
90 }
91 
92 Color Color::rotate_hue(double degrees) const noexcept
93 {
94  return to_hsva().rotate_hue(degrees).to_rgba();
95 }
96 
97 Color Color::lighten(double unit_amount) const noexcept
98 {
99  return to_hsla().lighten(unit_amount).to_rgba();
100 }
101 
102 Color Color::darken(double unit_amount) const noexcept
103 {
104  return to_hsla().darken(unit_amount).to_rgba();
105 }
106 
107 Color Color::saturate(double unit_amount) const noexcept
108 {
109  return to_hsla().saturate(unit_amount).to_rgba();
110 }
111 
112 Color Color::desaturate(double unit_amount) const noexcept
113 {
114  return to_hsla().desaturate(unit_amount).to_rgba();
115 }
116 
117 static std::tuple<double, double, double, double> to_HCMm(Color color) noexcept
118 {
119  double R = color.red() / 255.0;
120  double G = color.green() / 255.0;
121  double B = color.blue() / 255.0;
122 
123  double M = std::max(R, std::max(G, B));
124  double m = std::min(R, std::min(G, B));
125  double C = M - m;
126 
127  double H6 =
128  (M == R)? std::fmod((G - B) / C, 6) :
129  (M == G)? (B - R) / C + 2 :
130  (R - G) / C + 4;
131 
132  double H = 60 * H6;
133 
134  return std::make_tuple(H, C, M, m);
135 }
136 
137 Color::HSLA Color::to_hsla() const noexcept
138 {
139  double H, C, M, m;
140  std::tie(H, C, M, m) = to_HCMm(*this);
141 
142  double L = (M + m) / 2;
143  double S = (L == 1)? 0 : C / (1 - std::fabs(2 * L - 1));
144 
145  return {H, S, L, alpha() / 255.0};
146 }
147 
148 Color::HSVA Color::to_hsva() const noexcept
149 {
150  double H, C, M, m;
151  std::tie(H, C, M, m) = to_HCMm(*this);
152 
153  double V = M;
154  double S = V == 0 ? 0 : C / V;
155 
156  return {H, S, V, alpha() / 255.0};
157 }
158 
159 SDL_Color Color::to_sdl_() const noexcept
160 {
161  SDL_Color result;
162  result.a = alpha_;
163  result.r = red_;
164  result.g = green_;
165  result.b = blue_;
166  return result;
167 }
168 
169 uint32_t Color::to_sdl_(const SDL_PixelFormat* format) const noexcept
170 {
171  return SDL_MapRGBA(format, red_, green_, blue_, alpha_);
172 }
173 
174 Color Color::fade_in(double unit_amount) const noexcept
175 {
176  return adjust_field(*this, &Color::alpha_, unit_amount, 255);
177 }
178 
179 Color Color::fade_out(double unit_amount) const noexcept
180 {
181  return adjust_field(*this, &Color::alpha_, unit_amount, 0);
182 }
183 
184 Color Color::HSLA::to_rgba() const noexcept
185 {
187 }
188 
189 Color::HSLA Color::HSLA::rotate_hue(double degrees) const noexcept
190 {
191  auto result = *this;
192  result.hue = std::fmod(result.hue + degrees, 360);
193  return result;
194 }
195 
196 Color::HSLA Color::HSLA::saturate(double unit_amount) const noexcept
197 {
198  return adjust_field(*this, &HSLA::saturation, unit_amount, 1.0);
199 }
200 
201 Color::HSLA Color::HSLA::desaturate(double unit_amount) const noexcept
202 {
203  return adjust_field(*this, &HSLA::saturation, unit_amount, 0.0);
204 }
205 
206 Color::HSLA Color::HSLA::lighten(double unit_amount) const noexcept
207 {
208  return adjust_field(*this, &HSLA::lightness, unit_amount, 1.0);
209 }
210 
211 Color::HSLA Color::HSLA::darken(double unit_amount) const noexcept
212 {
213  return adjust_field(*this, &HSLA::lightness, unit_amount, 0.0);
214 }
215 
216 Color::HSLA Color::HSLA::fade_in(double unit_amount) const noexcept
217 {
218  return adjust_field(*this, &HSLA::alpha, unit_amount, 1.0);
219 }
220 
221 Color::HSLA Color::HSLA::fade_out(double unit_amount) const noexcept
222 {
223  return adjust_field(*this, &HSLA::alpha, unit_amount, 0.0);
224 }
225 
226 Color Color::HSVA::to_rgba() const noexcept
227 {
228  return Color::from_hsva(hue, saturation, value, alpha);
229 }
230 
231 Color::HSVA Color::HSVA::rotate_hue(double degrees) const noexcept
232 {
233  auto result = *this;
234  result.hue = std::fmod(result.hue + degrees, 360);
235  return result;
236 }
237 
238 Color::HSVA Color::HSVA::saturate(double unit_amount) const noexcept
239 {
240  return adjust_field(*this, &HSVA::saturation, unit_amount, 1.0);
241 }
242 
243 Color::HSVA Color::HSVA::desaturate(double unit_amount) const noexcept
244 {
245  return adjust_field(*this, &HSVA::saturation, unit_amount, 0.0);
246 }
247 
248 Color::HSVA Color::HSVA::revalue(double unit_amount) const noexcept
249 {
250  return adjust_field(*this, &HSVA::value, unit_amount, 1.0);
251 }
252 
253 Color::HSVA Color::HSVA::devalue(double unit_amount) const noexcept
254 {
255  return adjust_field(*this, &HSVA::value, unit_amount, 0.0);
256 }
257 
258 Color::HSVA Color::HSVA::fade_in(double unit_amount) const noexcept
259 {
260  return adjust_field(*this, &HSVA::alpha, unit_amount, 1.0);
261 }
262 
263 Color::HSVA Color::HSVA::fade_out(double unit_amount) const noexcept
264 {
265  return adjust_field(*this, &HSVA::alpha, unit_amount, 0.0);
266 }
267 
268 }
HSLA fade_out(double unit_amount) const noexcept
Decreases opacity of the color.
static Color from_hsva(double hue, double saturation, double value, double alpha=1) noexcept
Constructs a color given the hue, saturation, value, and alpha.
Definition: ge211_color.cpp:79
Color invert() const noexcept
Returns the inverse of a color.
Definition: ge211_color.cpp:87
double saturation
The fullness of the color, from 0,0 (grey) to 1.0 (fully saturated).
Definition: ge211_color.h:222
double hue
The hue in degrees from 0 to 360.
Definition: ge211_color.h:219
uint8_t alpha() const noexcept
Gets the alpha (opacity) component of a color.
Definition: ge211_color.h:99
double value
The brightness of the color, from 0.0 (black) to 1.0 (fully colored).
Definition: ge211_color.h:225
Representation for the hue-saturation-value-alpha color model.
Definition: ge211_color.h:216
HSVA to_hsva() const noexcept
Converts a color to the hue-saturation-value (HSV) color model.
Representation for the hue-saturation-lightness-alpha color model.
Definition: ge211_color.h:151
Color rotate_hue(double degrees) const noexcept
Returns a color by rotating the hue, leaving the other properties constant.
Definition: ge211_color.cpp:92
The game engine namespace.
Definition: ge211.h:17
Color fade_in(double unit_amount) const noexcept
Increases opacity of the color.
HSVA fade_in(double unit_amount) const noexcept
Increases opacity of the color.
HSVA fade_out(double unit_amount) const noexcept
Decreases opacity of the color.
Color saturate(double unit_amount) const noexcept
Produces a fuller tone by saturating the color.
double lightness
The lightness of the color, from 0.0 (black) to 1.0 (white).
Definition: ge211_color.h:159
HSLA lighten(double unit_amount) const noexcept
Produces a tint by lightening the color.
HSLA saturate(double unit_amount) const noexcept
Produces a fuller tone by saturating the color.
HSLA to_hsla() const noexcept
Converts a color to the hue-saturation-lightness (HSL) color model.
HSVA saturate(double unit_amount) const noexcept
Produces a fuller tone by saturating the color.
Color darken(double unit_amount) const noexcept
Produces a shade by darkening the color.
HSLA darken(double unit_amount) const noexcept
Produces a shade by darkening the color.
HSVA revalue(double unit_amount) const noexcept
Produces a brighter color by increasing the value.
HSVA rotate_hue(double degrees) const noexcept
Returns a color by rotating the hue, leaving the other properties constant.
Color fade_out(double unit_amount) const noexcept
Decreases opacity of the color.
Color desaturate(double unit_amount) const noexcept
Produces a weaker tone by desaturating the color.
static Color from_rgba(double red, double green, double blue, double alpha=1.0) noexcept
Constructs a color with the given components.
Definition: ge211_color.cpp:26
double saturation
The fullness of the color, from 0.0 (grey) to 1.0 (fully saturated).
Definition: ge211_color.h:157
HSVA desaturate(double unit_amount) const noexcept
Produces a weaker tone by desaturating the color.
HSLA fade_in(double unit_amount) const noexcept
Increases opacity of the color.
For representing colors.
Definition: ge211_color.h:22
double hue
The hue in degrees from 0 to 360.
Definition: ge211_color.h:154
Color to_rgba() const noexcept
Converts color to the RGBA color model.
double alpha
The opacity of the color, from 0.0 (fully transparent) to 1.0 (fully opaque).
Definition: ge211_color.h:228
static Color from_hsla(double hue, double saturation, double lightness, double alpha=1) noexcept
Constructs a color given the hue, saturation, lightness, and alpha.
Definition: ge211_color.cpp:71
HSLA rotate_hue(double degrees) const noexcept
Returns a color by rotating the hue, leaving the other properties.
HSVA devalue(double unit_amount) const noexcept
Produces a darker color by decreasing the value.
Color lighten(double unit_amount) const noexcept
Produces a tint by lightening the color.
Definition: ge211_color.cpp:97
Color to_rgba() const noexcept
Converts color to the RGBA color model.
double alpha
The opacity of the color, from 0.0 (fully transparent) to 1.0 (fully opaque).
Definition: ge211_color.h:162
HSLA desaturate(double unit_amount) const noexcept
Produces a weaker tone by desaturating the color.