lxgui
Loading...
Searching...
No Matches
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
11namespace lxgui::gui {
12
13const color color::empty(0.0f, 0.0f, 0.0f, 0.0f);
14const color color::white(1.0f, 1.0f, 1.0f);
15const color color::black(0.0f, 0.0f, 0.0f);
16const color color::red(1.0f, 0.0f, 0.0f);
17const color color::green(0.0f, 1.0f, 0.0f);
18const color color::blue(0.0f, 0.0f, 1.0f);
19const color color::grey(0.5f, 0.5f, 0.5f);
20
21color::color(const std::string& s) {
22 std::istringstream ss(s);
23 ss >> *this;
24}
25
26color::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
62color::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
92float 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
108color 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
133color 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
156bool color::operator==(const color& c) const noexcept {
157 return (r == c.r && g == c.g && b == c.b && a == c.a);
158}
159
160bool color::operator!=(const color& c) const noexcept {
161 return (r != c.r || g != c.g || b != c.b || a != c.a);
162}
163
164void color::operator+=(const color& c) noexcept {
165 r += c.r;
166 g += c.g;
167 b += c.b;
168 a += c.a;
169}
170
171void color::operator-=(const color& c) noexcept {
172 r -= c.r;
173 g -= c.g;
174 b -= c.b;
175 a -= c.a;
176}
177
178void color::operator*=(const color& c) noexcept {
179 r *= c.r;
180 g *= c.g;
181 b *= c.b;
182 a *= c.a;
183}
184
185void color::operator*=(float f) noexcept {
186 r *= f;
187 g *= f;
188 b *= f;
189 a *= f;
190}
191
192color 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
196color 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
200color 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
204color operator*(const color& c1, float f) noexcept {
205 return color(c1.r * f, c1.g * f, c1.b * f, c1.a);
206}
207
208color operator*(float f, const color& c2) noexcept {
209 return color(f * c2.r, f * c2.g, f * c2.b, c2.a);
210}
211
212std::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
219std::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:13
static const color green
Definition gui_color.hpp:47
static const color red
Definition gui_color.hpp:46
void operator*=(const color &c) noexcept
static const color blue
Definition gui_color.hpp:48
bool operator==(const color &c) const noexcept
hsv to_hsv() const noexcept
Definition gui_color.cpp:62
static color from_hls(const hls &hls) noexcept
static color from_hsv(const hsv &hsv) noexcept
constexpr color()=default
bool operator!=(const color &c) const noexcept
void operator-=(const color &c) noexcept
static const color white
Definition gui_color.hpp:44
static const color grey
Definition gui_color.hpp:49
static const color black
Definition gui_color.hpp:45
hls to_hls() const noexcept
Definition gui_color.cpp:26
void operator+=(const color &c) noexcept
static const color empty
Definition gui_color.hpp:43
std::ostream & operator<<(std::ostream &stream, const color &c)
std::istream & operator>>(std::istream &stream, color &c)
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
color operator*(const color &c1, const color &c2) noexcept
color operator-(const color &c1, const color &c2) noexcept