lxgui
gui_color.cpp
1 #include "lxgui/gui_color.hpp"
2 
3 #include "lxgui/utils.hpp"
4 #include "lxgui/utils_string.hpp"
5 
6 #include <algorithm>
7 #include <cmath>
8 #include <iostream>
9 #include <sstream>
10 
11 namespace lxgui::gui {
12 
13 const color color::empty(0.0f, 0.0f, 0.0f, 0.0f);
14 const color color::white(1.0f, 1.0f, 1.0f);
15 const color color::black(0.0f, 0.0f, 0.0f);
16 const color color::red(1.0f, 0.0f, 0.0f);
17 const color color::green(0.0f, 1.0f, 0.0f);
18 const color color::blue(0.0f, 0.0f, 1.0f);
19 const color color::grey(0.5f, 0.5f, 0.5f);
20 
21 color::color(const std::string& s) {
22  std::istringstream ss(s);
23  ss >> *this;
24 }
25 
26 color::hls color::to_hls() const noexcept {
27  float ma = std::max(std::max(r, g), b);
28  float mi = std::min(std::min(r, g), b);
29 
30  color::hls output{};
31  output.a = a;
32 
33  if (ma == mi) {
34  output.l = ma;
35  output.s = 0.0f;
36  } else {
37  float delta = ma - mi;
38  float sum = ma + mi;
39 
40  output.l = 0.5f * sum;
41  if (output.l < 0.5f)
42  output.s = delta / sum;
43  else
44  output.s = delta / (2.0f - sum);
45 
46  if (ma == r)
47  output.h = 60.0f * (g - b) / delta + 0.0f;
48  else if (ma == g)
49  output.h = 60.0f * (b - r) / delta + 120.0f;
50  else
51  output.h = 60.0f * (r - g) / delta + 240.0f;
52 
53  if (output.h < 0.0f)
54  output.h = output.h + 360.0f;
55  else if (output.h > 360.0f)
56  output.h = output.h - 360.0f;
57  }
58 
59  return output;
60 }
61 
62 color::hsv color::to_hsv() const noexcept {
63  color::hsv output{};
64 
65  float cmax;
66  float cmin;
67  if (r > g && r > b) {
68  cmax = r;
69  cmin = g > b ? g : b;
70  output.h = 60.0f * std::fmod((g - b) / (cmax - cmin), 6.0f);
71  } else if (g > r && g > b) {
72  cmax = g;
73  cmin = r > b ? r : b;
74  output.h = 60.0f * ((b - r) / (cmax - cmin) + 2.0f);
75  } else if (b > r && b > g) {
76  cmax = b;
77  cmin = r > g ? r : g;
78  output.h = 60.0f * ((r - g) / (cmax - cmin) + 4.0f);
79  } else {
80  output.h = 0.0f;
81  output.s = 0.0f;
82  output.v = r;
83  return output;
84  }
85 
86  output.s = (cmax - cmin) / cmax;
87  output.v = cmax;
88 
89  return output;
90 }
91 
92 float h2_to_rgb(float v1, float v2, float h) noexcept {
93  if (h < 0.0f)
94  h = h + 360.0f;
95  else if (h > 360.0f)
96  h = h - 360.0f;
97 
98  if (h < 60.0f)
99  return v1 + (v2 - v1) * h / 60.0f;
100  else if (h < 180.0f)
101  return v2;
102  else if (h < 240.0f)
103  return v1 + (v2 - v1) * (4.0f - h / 60.0f);
104  else
105  return v1;
106 }
107 
108 color color::from_hls(const hls& hls) noexcept {
109  color c;
110  c.a = hls.a;
111 
112  if (hls.s == 0.0f) {
113  c.r = hls.l;
114  c.g = hls.l;
115  c.b = hls.l;
116  } else {
117  float v2;
118  if (hls.l < 0.5f)
119  v2 = hls.l * (1.0f + hls.s);
120  else
121  v2 = hls.l + hls.s - hls.l * hls.s;
122 
123  float v1 = 2.0f * hls.l - v2;
124 
125  c.r = h2_to_rgb(v1, v2, hls.h + 120.0f);
126  c.g = h2_to_rgb(v1, v2, hls.h);
127  c.b = h2_to_rgb(v1, v2, hls.h - 120.0f);
128  }
129 
130  return c;
131 }
132 
133 color color::from_hsv(const hsv& hsv) noexcept {
134  const channel t = hsv.s * hsv.v;
135  const channel x = t * (1.0f - std::abs(std::fmod(hsv.h / 60.0f, 2.0f) - 1.0f));
136  const channel m = hsv.v - t;
137 
138  const channel low = std::clamp(m, 0.0f, 1.0f);
139  const channel mid = std::clamp(x + m, 0.0f, 1.0f);
140  const channel hig = std::clamp(t + m, 0.0f, 1.0f);
141 
142  if (hsv.h < 60.0f)
143  return color(hig, mid, low, hsv.a);
144  else if (hsv.h < 120.0f)
145  return color(mid, hig, low, hsv.a);
146  else if (hsv.h < 180.0f)
147  return color(low, hig, mid, hsv.a);
148  else if (hsv.h < 240.0f)
149  return color(low, mid, hig, hsv.a);
150  else if (hsv.h < 300.0f)
151  return color(mid, low, hig, hsv.a);
152  else
153  return color(hig, low, mid, hsv.a);
154 }
155 
156 bool color::operator==(const color& c) const noexcept {
157  return (r == c.r && g == c.g && b == c.b && a == c.a);
158 }
159 
160 bool color::operator!=(const color& c) const noexcept {
161  return (r != c.r || g != c.g || b != c.b || a != c.a);
162 }
163 
164 void color::operator+=(const color& c) noexcept {
165  r += c.r;
166  g += c.g;
167  b += c.b;
168  a += c.a;
169 }
170 
171 void color::operator-=(const color& c) noexcept {
172  r -= c.r;
173  g -= c.g;
174  b -= c.b;
175  a -= c.a;
176 }
177 
178 void color::operator*=(const color& c) noexcept {
179  r *= c.r;
180  g *= c.g;
181  b *= c.b;
182  a *= c.a;
183 }
184 
185 void color::operator*=(float f) noexcept {
186  r *= f;
187  g *= f;
188  b *= f;
189  a *= f;
190 }
191 
192 color operator+(const color& c1, const color& c2) noexcept {
193  return color(c1.r + c2.r, c1.g + c2.g, c1.b + c2.b, c1.a + c2.a);
194 }
195 
196 color operator-(const color& c1, const color& c2) noexcept {
197  return color(c1.r - c2.r, c1.g - c2.g, c1.b - c2.b, c1.a - c2.a);
198 }
199 
200 color operator*(const color& c1, const color& c2) noexcept {
201  return color(c1.r * c2.r, c1.g * c2.g, c1.b * c2.b, c1.a * c2.a);
202 }
203 
204 color operator*(const color& c1, float f) noexcept {
205  return color(c1.r * f, c1.g * f, c1.b * f, c1.a);
206 }
207 
208 color operator*(float f, const color& c2) noexcept {
209  return color(f * c2.r, f * c2.g, f * c2.b, c2.a);
210 }
211 
212 std::ostream& operator<<(std::ostream& stream, const color& c) {
213  return stream << static_cast<std::size_t>(std::round(255.0f * c.r)) << ", "
214  << static_cast<std::size_t>(std::round(255.0f * c.g)) << ", "
215  << static_cast<std::size_t>(std::round(255.0f * c.b)) << ", "
216  << static_cast<std::size_t>(std::round(255.0f * c.a));
217 }
218 
219 std::istream& operator>>(std::istream& stream, color& c) {
220  auto pos = stream.tellg();
221  char start_char;
222  stream >> start_char;
223  if (start_char == '#') {
224  char h[3];
225  h[2] = '\0';
226  stream >> h[0] >> h[1];
227  c.r = utils::hex_to_uint(h) / 255.0f;
228  stream >> h[0] >> h[1];
229  c.g = utils::hex_to_uint(h) / 255.0f;
230  stream >> h[0] >> h[1];
231  c.b = utils::hex_to_uint(h) / 255.0f;
232 
233  pos = stream.tellg();
234  if (!stream.eof()) {
235  stream >> h[0];
236  if (std::isalnum(h[0]) != 0 && !stream.eof()) {
237  stream >> h[1];
238  if (std::isalnum(h[1]) != 0) {
239  c.a = utils::hex_to_uint(h) / 255.0f;
240  return stream;
241  }
242  }
243  }
244 
245  stream.seekg(pos);
246  c.a = 1.0f;
247  } else {
248  stream.seekg(pos);
249  char delim;
250  stream >> c.r >> delim >> c.g >> delim >> c.b >> delim >> c.a;
251  c *= 1.0f / 255.0f;
252  }
253 
254  return stream;
255 }
256 
257 } // namespace lxgui::gui
Holds a single color (float RGBA, 128 bits)
Definition: gui_color.hpp:12
static const color green
Definition: gui_color.hpp:46
static const color red
Definition: gui_color.hpp:45
void operator*=(const color &c) noexcept
Definition: gui_color.cpp:178
static const color blue
Definition: gui_color.hpp:47
bool operator==(const color &c) const noexcept
Definition: gui_color.cpp:156
hsv to_hsv() const noexcept
Definition: gui_color.cpp:62
static color from_hls(const hls &hls) noexcept
Definition: gui_color.cpp:108
static color from_hsv(const hsv &hsv) noexcept
Definition: gui_color.cpp:133
constexpr color()=default
bool operator!=(const color &c) const noexcept
Definition: gui_color.cpp:160
void operator-=(const color &c) noexcept
Definition: gui_color.cpp:171
static const color white
Definition: gui_color.hpp:43
static const color grey
Definition: gui_color.hpp:48
static const color black
Definition: gui_color.hpp:44
hls to_hls() const noexcept
Definition: gui_color.cpp:26
void operator+=(const color &c) noexcept
Definition: gui_color.cpp:164
static const color empty
Definition: gui_color.hpp:42
std::ostream & operator<<(std::ostream &stream, const color &c)
Definition: gui_color.cpp:212
std::istream & operator>>(std::istream &stream, color &c)
Definition: gui_color.cpp:219
float h2_to_rgb(float v1, float v2, float h) noexcept
Definition: gui_color.cpp:92
color operator+(const color &c1, const color &c2) noexcept
Definition: gui_color.cpp:192
color operator*(const color &c1, const color &c2) noexcept
Definition: gui_color.cpp:200
color operator-(const color &c1, const color &c2) noexcept
Definition: gui_color.cpp:196