1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Image/BsColor.h"
4#include "Math/BsMath.h"
5
6namespace bs
7{
8 const Color Color::ZERO = Color(0.0f, 0.0f, 0.0f, 0.0f);
9 const Color Color::Black = Color(0.0f, 0.0f, 0.0f);
10 const Color Color::White = Color(1.0f, 1.0f, 1.0f);
11 const Color Color::Red = Color(1.0f, 0.0f, 0.0f);
12 const Color Color::Green = Color(0.0f, 1.0f, 0.0f);
13 const Color Color::Blue = Color(0.0f, 0.0f, 1.0f);
14 const Color Color::LightGray = Color(200.0f / 255.0f, 200.0f / 255.0f, 200.0f / 255.0f);
15 const Color Color::BansheeOrange = Color(1.0f, (168.0f/255.0f), 0.0f);
16
17 Color Color::fromRGBA(RGBA val)
18 {
19 Color output;
20 const UINT32 val32 = val;
21
22 output.a = ((val32 >> 24) & 0xFF) / 255.0f;
23 output.b = ((val32 >> 16) & 0xFF) / 255.0f;
24 output.g = ((val32 >> 8) & 0xFF) / 255.0f;
25 output.r = (val32 & 0xFF) / 255.0f;
26
27 return output;
28 }
29
30 Color Color::fromABGR(UINT32 val)
31 {
32 Color output;
33 const UINT32 val32 = val;
34
35 output.r = ((val32 >> 24) & 0xFF) / 255.0f;
36 output.g = ((val32 >> 16) & 0xFF) / 255.0f;
37 output.b = ((val32 >> 8) & 0xFF) / 255.0f;
38 output.a = (val32 & 0xFF) / 255.0f;
39
40 return output;
41 }
42
43 Color Color::fromARGB(ARGB val)
44 {
45 Color output;
46 const UINT32 val32 = val;
47
48 output.b = ((val32 >> 24) & 0xFF) / 255.0f;
49 output.g = ((val32 >> 16) & 0xFF) / 255.0f;
50 output.r = ((val32 >> 8) & 0xFF) / 255.0f;
51 output.a = (val32 & 0xFF) / 255.0f;
52
53 return output;
54 }
55
56 Color Color::fromBGRA(BGRA val)
57 {
58 Color output;
59 const UINT32 val32 = val;
60
61 output.a = ((val32 >> 24) & 0xFF) / 255.0f;
62 output.r = ((val32 >> 16) & 0xFF) / 255.0f;
63 output.g = ((val32 >> 8) & 0xFF) / 255.0f;
64 output.b = (val32 & 0xFF) / 255.0f;
65
66 return output;
67 }
68
69 Color Color::fromHSB(float hue, float saturation, float brightness)
70 {
71 Color output;
72
73 // wrap hue
74 if (hue > 1.0f)
75 hue -= (int)hue;
76 else if (hue < 0.0f)
77 hue += (int)hue + 1;
78
79 // clamp saturation / brightness
80 saturation = std::min(saturation, (float)1.0);
81 saturation = std::max(saturation, (float)0.0);
82 brightness = std::min(brightness, (float)1.0);
83 brightness = std::max(brightness, (float)0.0);
84
85 if (brightness == 0.0f)
86 {
87 // early exit, this has to be black
88 output.r = output.g = output.b = 0.0f;
89 return output;
90 }
91
92 if (saturation == 0.0f)
93 {
94 // early exit, this has to be grey
95
96 output.r = output.g = output.b = brightness;
97 return output;
98 }
99
100 float hueDomain = hue * 6.0f;
101 if (hueDomain >= 6.0f)
102 {
103 // wrap around, and allow mathematical errors
104 hueDomain = 0.0f;
105 }
106
107 const auto domain = (unsigned short)hueDomain;
108 const float f1 = brightness * (1 - saturation);
109 const float f2 = brightness * (1 - saturation * (hueDomain - domain));
110 const float f3 = brightness * (1 - saturation * (1 - (hueDomain - domain)));
111
112 switch (domain)
113 {
114 case 0:
115 // red domain; green ascends
116 output.r = brightness;
117 output.g = f3;
118 output.b = f1;
119 break;
120 case 1:
121 // yellow domain; red descends
122 output.r = f2;
123 output.g = brightness;
124 output.b = f1;
125 break;
126 case 2:
127 // green domain; blue ascends
128 output.r = f1;
129 output.g = brightness;
130 output.b = f3;
131 break;
132 case 3:
133 // cyan domain; green descends
134 output.r = f1;
135 output.g = f2;
136 output.b = brightness;
137 break;
138 case 4:
139 // blue domain; red ascends
140 output.r = f3;
141 output.g = f1;
142 output.b = brightness;
143 break;
144 case 5:
145 // magenta domain; blue descends
146 output.r = brightness;
147 output.g = f1;
148 output.b = f2;
149 break;
150 }
151
152 return output;
153 }
154
155 ABGR Color::getAsABGR() const
156 {
157 UINT8 val8;
158 UINT32 val32 = 0;
159
160 // Convert to 32bit pattern
161 // (RGBA = 8888)
162
163 // Red
164 val8 = static_cast<UINT8>(r * 255);
165 val32 = val8 << 24;
166
167 // Green
168 val8 = static_cast<UINT8>(g * 255);
169 val32 += val8 << 16;
170
171 // Blue
172 val8 = static_cast<UINT8>(b * 255);
173 val32 += val8 << 8;
174
175 // Alpha
176 val8 = static_cast<UINT8>(a * 255);
177 val32 += val8;
178
179 return val32;
180 }
181
182 BGRA Color::getAsBGRA() const
183 {
184 UINT8 val8;
185 UINT32 val32 = 0;
186
187 // Convert to 32bit pattern
188 // (ARGB = 8888)
189
190 // Alpha
191 val8 = static_cast<UINT8>(a * 255);
192 val32 = val8 << 24;
193
194 // Red
195 val8 = static_cast<UINT8>(r * 255);
196 val32 += val8 << 16;
197
198 // Green
199 val8 = static_cast<UINT8>(g * 255);
200 val32 += val8 << 8;
201
202 // Blue
203 val8 = static_cast<UINT8>(b * 255);
204 val32 += val8;
205
206 return val32;
207 }
208
209 ARGB Color::getAsARGB() const
210 {
211 UINT8 val8;
212 UINT32 val32 = 0;
213
214 // Convert to 32bit pattern
215 // (ARGB = 8888)
216
217 // Blue
218 val8 = static_cast<UINT8>(b * 255);
219 val32 = val8 << 24;
220
221 // Green
222 val8 = static_cast<UINT8>(g * 255);
223 val32 += val8 << 16;
224
225 // Red
226 val8 = static_cast<UINT8>(r * 255);
227 val32 += val8 << 8;
228
229 // Alpha
230 val8 = static_cast<UINT8>(a * 255);
231 val32 += val8;
232
233
234 return val32;
235 }
236
237 RGBA Color::getAsRGBA() const
238 {
239 UINT8 val8;
240 UINT32 val32 = 0;
241
242 // Convert to 32bit pattern
243 // (ABRG = 8888)
244
245 // Alpha
246 val8 = static_cast<UINT8>(a * 255);
247 val32 = val8 << 24;
248
249 // Blue
250 val8 = static_cast<UINT8>(b * 255);
251 val32 += val8 << 16;
252
253 // Green
254 val8 = static_cast<UINT8>(g * 255);
255 val32 += val8 << 8;
256
257 // Red
258 val8 = static_cast<UINT8>(r * 255);
259 val32 += val8;
260
261
262 return val32;
263 }
264
265 bool Color::operator==(const Color& rhs) const
266 {
267 return (r == rhs.r &&
268 g == rhs.g &&
269 b == rhs.b &&
270 a == rhs.a);
271 }
272
273 bool Color::operator!=(const Color& rhs) const
274 {
275 return !(*this == rhs);
276 }
277
278 void Color::getHSB(float* hue, float* saturation, float* brightness) const
279 {
280 float vMin = std::min(r, std::min(g, b));
281 float vMax = std::max(r, std::max(g, b));
282 float delta = vMax - vMin;
283
284 *brightness = vMax;
285
286 if (Math::approxEquals(delta, 0.0f, 1e-6f))
287 {
288 // grey
289 *hue = 0;
290 *saturation = 0;
291 }
292 else
293 {
294 // a colour
295 *saturation = delta / vMax;
296
297 float deltaR = (((vMax - r) / 6.0f) + (delta / 2.0f)) / delta;
298 float deltaG = (((vMax - g) / 6.0f) + (delta / 2.0f)) / delta;
299 float deltaB = (((vMax - b) / 6.0f) + (delta / 2.0f)) / delta;
300
301 if (Math::approxEquals(r, vMax))
302 *hue = deltaB - deltaG;
303 else if (Math::approxEquals(g, vMax))
304 *hue = 0.3333333f + deltaR - deltaB;
305 else if (Math::approxEquals(b, vMax))
306 *hue = 0.6666667f + deltaG - deltaR;
307
308 if (*hue < 0.0f)
309 *hue += 1.0f;
310 if (*hue > 1.0f)
311 *hue -= 1.0f;
312 }
313 }
314
315 Color Color::lerp(float t, const Color& a, const Color& b)
316 {
317 t = Math::clamp01(t);
318 return Color(a.r + (b.r - a.r) * t,
319 a.g + (b.g - a.g) * t,
320 a.b + (b.b - a.b) * t,
321 a.a + (b.a - a.a) * t);
322 }
323}
324
325