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 | #pragma once |
4 | |
5 | #include "Prerequisites/BsPrerequisitesUtil.h" |
6 | |
7 | namespace bs |
8 | { |
9 | /** @addtogroup Image |
10 | * @{ |
11 | */ |
12 | |
13 | typedef UINT32 RGBA; |
14 | typedef UINT32 ARGB; |
15 | typedef UINT32 ABGR; |
16 | typedef UINT32 BGRA; |
17 | |
18 | /** |
19 | * Color represented as 4 components, each being a floating point value ranging from 0 to 1. Color components are |
20 | * red, green, blue and alpha. |
21 | */ |
22 | class BS_UTILITY_EXPORT Color |
23 | { |
24 | public: |
25 | static const Color ZERO; |
26 | static const Color Black; |
27 | static const Color White; |
28 | static const Color Red; |
29 | static const Color Green; |
30 | static const Color Blue; |
31 | static const Color LightGray; |
32 | static const Color BansheeOrange; |
33 | |
34 | constexpr explicit Color(float red = 1.0f, float green = 1.0f, float blue = 1.0f, float alpha = 1.0f ) |
35 | :r(red), g(green), b(blue), a(alpha) |
36 | { } |
37 | |
38 | bool operator==(const Color& rhs) const; |
39 | bool operator!=(const Color& rhs) const; |
40 | |
41 | /** Returns the color as a 32-bit value in RGBA order. */ |
42 | RGBA getAsRGBA() const; |
43 | |
44 | /** Returns the color as a 32-bit value in ARGB order. */ |
45 | ARGB getAsARGB() const; |
46 | |
47 | /** Returns the color as a 32-bit value in BGRA order. */ |
48 | BGRA getAsBGRA() const; |
49 | |
50 | /** Returns the color as a 32-bit value in ABGR order. */ |
51 | ABGR getAsABGR() const; |
52 | |
53 | /** |
54 | * Convert the current color to hue, saturation and brightness values. |
55 | * |
56 | * @param[in] hue Output hue value, scaled to the [0,1] range. |
57 | * @param[in] saturation Output saturation level, [0,1]. |
58 | * @param[in] brightness Output brightness level, [0,1]. |
59 | */ |
60 | void getHSB(float* hue, float* saturation, float* brightness) const; |
61 | |
62 | /** Clamps color value to the range [0, 1]. */ |
63 | void saturate() |
64 | { |
65 | if (r < 0) |
66 | r = 0; |
67 | else if (r > 1) |
68 | r = 1; |
69 | |
70 | if (g < 0) |
71 | g = 0; |
72 | else if (g > 1) |
73 | g = 1; |
74 | |
75 | if (b < 0) |
76 | b = 0; |
77 | else if (b > 1) |
78 | b = 1; |
79 | |
80 | if (a < 0) |
81 | a = 0; |
82 | else if (a > 1) |
83 | a = 1; |
84 | } |
85 | |
86 | /** Clamps colour value to the range [0, 1]. Returned saturated color as a copy. */ |
87 | Color saturateCopy() const |
88 | { |
89 | Color ret = *this; |
90 | ret.saturate(); |
91 | return ret; |
92 | } |
93 | |
94 | float operator[] (const UINT32 i) const |
95 | { |
96 | assert(i < 4); |
97 | |
98 | return *(&r+i); |
99 | } |
100 | |
101 | float& operator[] (const UINT32 i) |
102 | { |
103 | assert(i < 4); |
104 | |
105 | return *(&r+i); |
106 | } |
107 | |
108 | /** Pointer accessor for direct copying. */ |
109 | float* ptr() |
110 | { |
111 | return &r; |
112 | } |
113 | |
114 | /** Pointer accessor for direct copying. */ |
115 | const float* ptr() const |
116 | { |
117 | return &r; |
118 | } |
119 | |
120 | Color operator+ (const Color& rhs) const |
121 | { |
122 | return Color(r + rhs.r, g + rhs.g, b + rhs.b, a + rhs.a); |
123 | } |
124 | |
125 | Color operator- (const Color& rhs) const |
126 | { |
127 | return Color(r - rhs.r, g - rhs.g, b - rhs.b, a - rhs.a); |
128 | } |
129 | |
130 | Color operator* (float rhs) const |
131 | { |
132 | return Color(rhs * r, rhs * g, rhs * b, rhs * a); |
133 | } |
134 | |
135 | Color operator* (const Color& rhs) const |
136 | { |
137 | return Color(rhs.r * r, rhs.g * g, rhs.b * b, rhs.a * a); |
138 | } |
139 | |
140 | Color operator/ (const Color& rhs) const |
141 | { |
142 | return Color(r / rhs.r, g / rhs.g, b / rhs.b, a / rhs.a); |
143 | } |
144 | |
145 | Color operator/ (float rhs) const |
146 | { |
147 | assert(rhs != 0.0f); |
148 | float invRhs = 1.0f / rhs; |
149 | |
150 | return Color(r * invRhs, g * invRhs, b * invRhs, a * invRhs); |
151 | } |
152 | |
153 | friend Color operator* (float lhs, const Color& rhs) |
154 | { |
155 | return Color(lhs * rhs.r, lhs * rhs.g, lhs * rhs.b, lhs * rhs.a); |
156 | } |
157 | |
158 | Color& operator+= (const Color& rhs) |
159 | { |
160 | r += rhs.r; |
161 | g += rhs.g; |
162 | b += rhs.b; |
163 | a += rhs.a; |
164 | |
165 | return *this; |
166 | } |
167 | |
168 | Color& operator-= (const Color& rhs) |
169 | { |
170 | r -= rhs.r; |
171 | g -= rhs.g; |
172 | b -= rhs.b; |
173 | a -= rhs.a; |
174 | |
175 | return *this; |
176 | } |
177 | |
178 | Color& operator*= (float rhs) |
179 | { |
180 | r *= rhs; |
181 | g *= rhs; |
182 | b *= rhs; |
183 | a *= rhs; |
184 | |
185 | return *this; |
186 | } |
187 | |
188 | Color& operator/= (float rhs) |
189 | { |
190 | assert(rhs != 0.0f); |
191 | |
192 | float invRhs = 1.0f / rhs; |
193 | |
194 | r *= invRhs; |
195 | g *= invRhs; |
196 | b *= invRhs; |
197 | a *= invRhs; |
198 | |
199 | return *this; |
200 | } |
201 | |
202 | /** Creates a color value from a 32-bit value that encodes a RGBA color. */ |
203 | static Color fromRGBA(RGBA val); |
204 | |
205 | /** Creates a color value from a 32-bit value that encodes a ARGB color. */ |
206 | static Color fromARGB(ARGB val); |
207 | |
208 | /** Creates a color value from a 32-bit value that encodes a BGRA color. */ |
209 | static Color fromBGRA(BGRA val); |
210 | |
211 | /** Creates a color value from a 32-bit value that encodes a ABGR color. */ |
212 | static Color fromABGR(ABGR val); |
213 | |
214 | /** |
215 | * Creates a color value from hue, saturation and brightness. |
216 | * |
217 | * @param[in] hue Hue value, scaled to the [0,1] range. |
218 | * @param[in] saturation Saturation level, [0,1]. |
219 | * @param[in] brightness Brightness level, [0,1]. |
220 | */ |
221 | static Color fromHSB(float hue, float saturation, float brightness); |
222 | |
223 | /** |
224 | * Linearly interpolates between the two colors using @p t. t should be in [0, 1] range, where t = 0 corresponds |
225 | * to the left color, while t = 1 corresponds to the right color. |
226 | */ |
227 | static Color lerp(float t, const Color& a, const Color& b); |
228 | |
229 | /** |
230 | * Linearly interpolates between the two colors using @p t. t should be in [0, 255] range, where t = 0 corresponds |
231 | * to the left color, while t = 1 corresponds to the right color. Operates directly on 8-bit per channel |
232 | * encoded color instead of on floating point values. |
233 | */ |
234 | static constexpr RGBA lerp(UINT8 t, RGBA from, RGBA to) |
235 | { |
236 | constexpr UINT32 RB_MASK = 0x00FF00FF; |
237 | constexpr UINT32 GA_MASK = 0xFF00FF00; |
238 | |
239 | // Lerp two channels at a time (this leaves 8 extra bits for each channel for results) |
240 | //// Red-blue first |
241 | const UINT32 rbFrom = from & RB_MASK; |
242 | const UINT32 rbTo = to & RB_MASK; |
243 | const UINT32 rb = (rbFrom + (((rbTo - rbFrom) * t) >> 8)) & RB_MASK; |
244 | |
245 | //// Then green-alpha |
246 | const UINT32 gaFrom = from & GA_MASK; |
247 | const UINT32 gaTo = to & GA_MASK; |
248 | const UINT32 ga = (((gaFrom >> 8) + ((((gaTo >> 8) - (gaFrom >> 8)) * t) >> 8)) << 8) & GA_MASK; |
249 | |
250 | return rb | ga; |
251 | } |
252 | |
253 | float r, g, b, a; |
254 | }; |
255 | |
256 | /** @cond SPECIALIZATIONS */ |
257 | BS_ALLOW_MEMCPY_SERIALIZATION(Color); |
258 | /** @endcond */ |
259 | |
260 | /** @} */ |
261 | } |
262 | |
263 | /** @cond SPECIALIZATIONS */ |
264 | |
265 | namespace std |
266 | { |
267 | /** Hash value generator for Color. */ |
268 | template<> |
269 | struct hash<bs::Color> |
270 | { |
271 | size_t operator()(const bs::Color& color) const |
272 | { |
273 | size_t hash = 0; |
274 | bs::bs_hash_combine(hash, color.r); |
275 | bs::bs_hash_combine(hash, color.g); |
276 | bs::bs_hash_combine(hash, color.b); |
277 | bs::bs_hash_combine(hash, color.a); |
278 | |
279 | return hash; |
280 | } |
281 | }; |
282 | } |
283 | |
284 | /** @endcond */ |
285 | |