Line data Source code
1 : // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 : // This file is part of the "Irrlicht Engine".
3 : // For conditions of distribution and use, see copyright notice in irrlicht.h
4 :
5 : #ifndef __COLOR_H_INCLUDED__
6 : #define __COLOR_H_INCLUDED__
7 :
8 : #include "irrTypes.h"
9 : #include "irrMath.h"
10 :
11 : namespace irr
12 : {
13 : namespace video
14 : {
15 : //! An enum for the color format of textures used by the Irrlicht Engine.
16 : /** A color format specifies how color information is stored. */
17 : enum ECOLOR_FORMAT
18 : {
19 : //! 16 bit color format used by the software driver.
20 : /** It is thus preferred by all other irrlicht engine video drivers.
21 : There are 5 bits for every color component, and a single bit is left
22 : for alpha information. */
23 : ECF_A1R5G5B5 = 0,
24 :
25 : //! Standard 16 bit color format.
26 : ECF_R5G6B5,
27 :
28 : //! 24 bit color, no alpha channel, but 8 bit for red, green and blue.
29 : ECF_R8G8B8,
30 :
31 : //! Default 32 bit color format. 8 bits are used for every component: red, green, blue and alpha.
32 : ECF_A8R8G8B8,
33 :
34 : /** Floating Point formats. The following formats may only be used for render target textures. */
35 :
36 : //! 16 bit floating point format using 16 bits for the red channel.
37 : ECF_R16F,
38 :
39 : //! 32 bit floating point format using 16 bits for the red channel and 16 bits for the green channel.
40 : ECF_G16R16F,
41 :
42 : //! 64 bit floating point format 16 bits are used for the red, green, blue and alpha channels.
43 : ECF_A16B16G16R16F,
44 :
45 : //! 32 bit floating point format using 32 bits for the red channel.
46 : ECF_R32F,
47 :
48 : //! 64 bit floating point format using 32 bits for the red channel and 32 bits for the green channel.
49 : ECF_G32R32F,
50 :
51 : //! 128 bit floating point format. 32 bits are used for the red, green, blue and alpha channels.
52 : ECF_A32B32G32R32F,
53 :
54 : //! Unknown color format:
55 : ECF_UNKNOWN
56 : };
57 :
58 :
59 : //! Creates a 16 bit A1R5G5B5 color
60 : inline u16 RGBA16(u32 r, u32 g, u32 b, u32 a=0xFF)
61 : {
62 : return (u16)((a & 0x80) << 8 |
63 : (r & 0xF8) << 7 |
64 : (g & 0xF8) << 2 |
65 : (b & 0xF8) >> 3);
66 : }
67 :
68 :
69 : //! Creates a 16 bit A1R5G5B5 color
70 : inline u16 RGB16(u32 r, u32 g, u32 b)
71 : {
72 : return RGBA16(r,g,b);
73 : }
74 :
75 :
76 : //! Creates a 16bit A1R5G5B5 color, based on 16bit input values
77 : inline u16 RGB16from16(u16 r, u16 g, u16 b)
78 : {
79 : return (0x8000 |
80 : (r & 0x1F) << 10 |
81 : (g & 0x1F) << 5 |
82 : (b & 0x1F));
83 : }
84 :
85 :
86 : //! Converts a 32bit (X8R8G8B8) color to a 16bit A1R5G5B5 color
87 : inline u16 X8R8G8B8toA1R5G5B5(u32 color)
88 : {
89 : return (u16)(0x8000 |
90 : ( color & 0x00F80000) >> 9 |
91 : ( color & 0x0000F800) >> 6 |
92 : ( color & 0x000000F8) >> 3);
93 : }
94 :
95 :
96 : //! Converts a 32bit (A8R8G8B8) color to a 16bit A1R5G5B5 color
97 : inline u16 A8R8G8B8toA1R5G5B5(u32 color)
98 : {
99 : return (u16)(( color & 0x80000000) >> 16|
100 : ( color & 0x00F80000) >> 9 |
101 : ( color & 0x0000F800) >> 6 |
102 : ( color & 0x000000F8) >> 3);
103 : }
104 :
105 :
106 : //! Converts a 32bit (A8R8G8B8) color to a 16bit R5G6B5 color
107 : inline u16 A8R8G8B8toR5G6B5(u32 color)
108 : {
109 : return (u16)(( color & 0x00F80000) >> 8 |
110 : ( color & 0x0000FC00) >> 5 |
111 : ( color & 0x000000F8) >> 3);
112 : }
113 :
114 :
115 : //! Convert A8R8G8B8 Color from A1R5G5B5 color
116 : /** build a nicer 32bit Color by extending dest lower bits with source high bits. */
117 : inline u32 A1R5G5B5toA8R8G8B8(u16 color)
118 : {
119 : return ( (( -( (s32) color & 0x00008000 ) >> (s32) 31 ) & 0xFF000000 ) |
120 : (( color & 0x00007C00 ) << 9) | (( color & 0x00007000 ) << 4) |
121 : (( color & 0x000003E0 ) << 6) | (( color & 0x00000380 ) << 1) |
122 : (( color & 0x0000001F ) << 3) | (( color & 0x0000001C ) >> 2)
123 : );
124 : }
125 :
126 :
127 : //! Returns A8R8G8B8 Color from R5G6B5 color
128 : inline u32 R5G6B5toA8R8G8B8(u16 color)
129 : {
130 : return 0xFF000000 |
131 : ((color & 0xF800) << 8)|
132 : ((color & 0x07E0) << 5)|
133 : ((color & 0x001F) << 3);
134 : }
135 :
136 :
137 : //! Returns A1R5G5B5 Color from R5G6B5 color
138 : inline u16 R5G6B5toA1R5G5B5(u16 color)
139 : {
140 : return 0x8000 | (((color & 0xFFC0) >> 1) | (color & 0x1F));
141 : }
142 :
143 :
144 : //! Returns R5G6B5 Color from A1R5G5B5 color
145 : inline u16 A1R5G5B5toR5G6B5(u16 color)
146 : {
147 : return (((color & 0x7FE0) << 1) | (color & 0x1F));
148 : }
149 :
150 :
151 :
152 : //! Returns the alpha component from A1R5G5B5 color
153 : /** In Irrlicht, alpha refers to opacity.
154 : \return The alpha value of the color. 0 is transparent, 1 is opaque. */
155 : inline u32 getAlpha(u16 color)
156 : {
157 : return ((color >> 15)&0x1);
158 : }
159 :
160 :
161 : //! Returns the red component from A1R5G5B5 color.
162 : /** Shift left by 3 to get 8 bit value. */
163 : inline u32 getRed(u16 color)
164 : {
165 : return ((color >> 10)&0x1F);
166 : }
167 :
168 :
169 : //! Returns the green component from A1R5G5B5 color
170 : /** Shift left by 3 to get 8 bit value. */
171 : inline u32 getGreen(u16 color)
172 : {
173 : return ((color >> 5)&0x1F);
174 : }
175 :
176 :
177 : //! Returns the blue component from A1R5G5B5 color
178 : /** Shift left by 3 to get 8 bit value. */
179 : inline u32 getBlue(u16 color)
180 : {
181 : return (color & 0x1F);
182 : }
183 :
184 :
185 : //! Returns the average from a 16 bit A1R5G5B5 color
186 : inline s32 getAverage(s16 color)
187 : {
188 : return ((getRed(color)<<3) + (getGreen(color)<<3) + (getBlue(color)<<3)) / 3;
189 : }
190 :
191 :
192 : //! Class representing a 32 bit ARGB color.
193 : /** The color values for alpha, red, green, and blue are
194 : stored in a single u32. So all four values may be between 0 and 255.
195 : Alpha in Irrlicht is opacity, so 0 is fully transparent, 255 is fully opaque (solid).
196 : This class is used by most parts of the Irrlicht Engine
197 : to specify a color. Another way is using the class SColorf, which
198 : stores the color values in 4 floats.
199 : This class must consist of only one u32 and must not use virtual functions.
200 : */
201 : class SColor
202 : {
203 : public:
204 :
205 : //! Constructor of the Color. Does nothing.
206 : /** The color value is not initialized to save time. */
207 7292905 : SColor() {}
208 :
209 : //! Constructs the color from 4 values representing the alpha, red, green and blue component.
210 : /** Must be values between 0 and 255. */
211 23917185 : SColor (u32 a, u32 r, u32 g, u32 b)
212 23917185 : : color(((a & 0xff)<<24) | ((r & 0xff)<<16) | ((g & 0xff)<<8) | (b & 0xff)) {}
213 :
214 : //! Constructs the color from a 32 bit value. Could be another color.
215 123 : SColor(u32 clr)
216 123 : : color(clr) {}
217 :
218 : //! Returns the alpha component of the color.
219 : /** The alpha component defines how opaque a color is.
220 : \return The alpha value of the color. 0 is fully transparent, 255 is fully opaque. */
221 54794374 : u32 getAlpha() const { return color>>24; }
222 :
223 : //! Returns the red component of the color.
224 : /** \return Value between 0 and 255, specifying how red the color is.
225 : 0 means no red, 255 means full red. */
226 44744634 : u32 getRed() const { return (color>>16) & 0xff; }
227 :
228 : //! Returns the green component of the color.
229 : /** \return Value between 0 and 255, specifying how green the color is.
230 : 0 means no green, 255 means full green. */
231 42702561 : u32 getGreen() const { return (color>>8) & 0xff; }
232 :
233 : //! Returns the blue component of the color.
234 : /** \return Value between 0 and 255, specifying how blue the color is.
235 : 0 means no blue, 255 means full blue. */
236 44837249 : u32 getBlue() const { return color & 0xff; }
237 :
238 : //! Get lightness of the color in the range [0,255]
239 : f32 getLightness() const
240 : {
241 : return 0.5f*(core::max_(core::max_(getRed(),getGreen()),getBlue())+core::min_(core::min_(getRed(),getGreen()),getBlue()));
242 : }
243 :
244 : //! Get luminance of the color in the range [0,255].
245 : f32 getLuminance() const
246 : {
247 : return 0.3f*getRed() + 0.59f*getGreen() + 0.11f*getBlue();
248 : }
249 :
250 : //! Get average intensity of the color in the range [0,255].
251 : u32 getAverage() const
252 : {
253 : return ( getRed() + getGreen() + getBlue() ) / 3;
254 : }
255 :
256 : //! Sets the alpha component of the Color.
257 : /** The alpha component defines how transparent a color should be.
258 : \param a The alpha value of the color. 0 is fully transparent, 255 is fully opaque. */
259 366430 : void setAlpha(u32 a) { color = ((a & 0xff)<<24) | (color & 0x00ffffff); }
260 :
261 : //! Sets the red component of the Color.
262 : /** \param r: Has to be a value between 0 and 255.
263 : 0 means no red, 255 means full red. */
264 5148936 : void setRed(u32 r) { color = ((r & 0xff)<<16) | (color & 0xff00ffff); }
265 :
266 : //! Sets the green component of the Color.
267 : /** \param g: Has to be a value between 0 and 255.
268 : 0 means no green, 255 means full green. */
269 5148835 : void setGreen(u32 g) { color = ((g & 0xff)<<8) | (color & 0xffff00ff); }
270 :
271 : //! Sets the blue component of the Color.
272 : /** \param b: Has to be a value between 0 and 255.
273 : 0 means no blue, 255 means full blue. */
274 161271 : void setBlue(u32 b) { color = (b & 0xff) | (color & 0xffffff00); }
275 :
276 : //! Calculates a 16 bit A1R5G5B5 value of this color.
277 : /** \return 16 bit A1R5G5B5 value of this color. */
278 : u16 toA1R5G5B5() const { return A8R8G8B8toA1R5G5B5(color); }
279 :
280 : //! Converts color to OpenGL color format
281 : /** From ARGB to RGBA in 4 byte components for endian aware
282 : passing to OpenGL
283 : \param dest: address where the 4x8 bit OpenGL color is stored. */
284 : void toOpenGLColor(u8* dest) const
285 : {
286 : *dest = (u8)getRed();
287 : *++dest = (u8)getGreen();
288 : *++dest = (u8)getBlue();
289 : *++dest = (u8)getAlpha();
290 : }
291 :
292 : //! Sets all four components of the color at once.
293 : /** Constructs the color from 4 values representing the alpha,
294 : red, green and blue components of the color. Must be values
295 : between 0 and 255.
296 : \param a: Alpha component of the color. The alpha component
297 : defines how transparent a color should be. Has to be a value
298 : between 0 and 255. 255 means not transparent (opaque), 0 means
299 : fully transparent.
300 : \param r: Sets the red component of the Color. Has to be a
301 : value between 0 and 255. 0 means no red, 255 means full red.
302 : \param g: Sets the green component of the Color. Has to be a
303 : value between 0 and 255. 0 means no green, 255 means full
304 : green.
305 : \param b: Sets the blue component of the Color. Has to be a
306 : value between 0 and 255. 0 means no blue, 255 means full blue. */
307 5830 : void set(u32 a, u32 r, u32 g, u32 b)
308 : {
309 5830 : color = (((a & 0xff)<<24) | ((r & 0xff)<<16) | ((g & 0xff)<<8) | (b & 0xff));
310 5830 : }
311 0 : void set(u32 col) { color = col; }
312 :
313 : //! Compares the color to another color.
314 : /** \return True if the colors are the same, and false if not. */
315 0 : bool operator==(const SColor& other) const { return other.color == color; }
316 :
317 : //! Compares the color to another color.
318 : /** \return True if the colors are different, and false if they are the same. */
319 4651720 : bool operator!=(const SColor& other) const { return other.color != color; }
320 :
321 : //! comparison operator
322 : /** \return True if this color is smaller than the other one */
323 0 : bool operator<(const SColor& other) const { return (color < other.color); }
324 :
325 : //! Adds two colors, result is clamped to 0..255 values
326 : /** \param other Color to add to this color
327 : \return Addition of the two colors, clamped to 0..255 values */
328 : SColor operator+(const SColor& other) const
329 : {
330 : return SColor(core::min_(getAlpha() + other.getAlpha(), 255u),
331 : core::min_(getRed() + other.getRed(), 255u),
332 : core::min_(getGreen() + other.getGreen(), 255u),
333 : core::min_(getBlue() + other.getBlue(), 255u));
334 : }
335 :
336 : //! Interpolates the color with a f32 value to another color
337 : /** \param other: Other color
338 : \param d: value between 0.0f and 1.0f
339 : \return Interpolated color. */
340 17302482 : SColor getInterpolated(const SColor &other, f32 d) const
341 : {
342 17302482 : d = core::clamp(d, 0.f, 1.f);
343 17302482 : const f32 inv = 1.0f - d;
344 17302482 : return SColor((u32)core::round32(other.getAlpha()*inv + getAlpha()*d),
345 17302482 : (u32)core::round32(other.getRed()*inv + getRed()*d),
346 17302482 : (u32)core::round32(other.getGreen()*inv + getGreen()*d),
347 69209928 : (u32)core::round32(other.getBlue()*inv + getBlue()*d));
348 : }
349 :
350 : //! Returns interpolated color. ( quadratic )
351 : /** \param c1: first color to interpolate with
352 : \param c2: second color to interpolate with
353 : \param d: value between 0.0f and 1.0f. */
354 0 : SColor getInterpolated_quadratic(const SColor& c1, const SColor& c2, f32 d) const
355 : {
356 : // this*(1-d)*(1-d) + 2 * c1 * (1-d) + c2 * d * d;
357 0 : d = core::clamp(d, 0.f, 1.f);
358 0 : const f32 inv = 1.f - d;
359 0 : const f32 mul0 = inv * inv;
360 0 : const f32 mul1 = 2.f * d * inv;
361 0 : const f32 mul2 = d * d;
362 :
363 : return SColor(
364 0 : core::clamp( core::floor32(
365 0 : getAlpha() * mul0 + c1.getAlpha() * mul1 + c2.getAlpha() * mul2 ), 0, 255 ),
366 0 : core::clamp( core::floor32(
367 0 : getRed() * mul0 + c1.getRed() * mul1 + c2.getRed() * mul2 ), 0, 255 ),
368 0 : core::clamp ( core::floor32(
369 0 : getGreen() * mul0 + c1.getGreen() * mul1 + c2.getGreen() * mul2 ), 0, 255 ),
370 0 : core::clamp ( core::floor32(
371 0 : getBlue() * mul0 + c1.getBlue() * mul1 + c2.getBlue() * mul2 ), 0, 255 ));
372 : }
373 :
374 : //! set the color by expecting data in the given format
375 : /** \param data: must point to valid memory containing color information in the given format
376 : \param format: tells the format in which data is available
377 : */
378 : void setData(const void *data, ECOLOR_FORMAT format)
379 : {
380 : switch (format)
381 : {
382 : case ECF_A1R5G5B5:
383 : color = A1R5G5B5toA8R8G8B8(*(u16*)data);
384 : break;
385 : case ECF_R5G6B5:
386 : color = R5G6B5toA8R8G8B8(*(u16*)data);
387 : break;
388 : case ECF_A8R8G8B8:
389 : color = *(u32*)data;
390 : break;
391 : case ECF_R8G8B8:
392 : {
393 : u8* p = (u8*)data;
394 : set(255, p[0],p[1],p[2]);
395 : }
396 : break;
397 : default:
398 : color = 0xffffffff;
399 : break;
400 : }
401 : }
402 :
403 : //! Write the color to data in the defined format
404 : /** \param data: target to write the color. Must contain sufficiently large memory to receive the number of bytes neede for format
405 : \param format: tells the format used to write the color into data
406 : */
407 : void getData(void *data, ECOLOR_FORMAT format)
408 : {
409 : switch(format)
410 : {
411 : case ECF_A1R5G5B5:
412 : {
413 : u16 * dest = (u16*)data;
414 : *dest = video::A8R8G8B8toA1R5G5B5( color );
415 : }
416 : break;
417 :
418 : case ECF_R5G6B5:
419 : {
420 : u16 * dest = (u16*)data;
421 : *dest = video::A8R8G8B8toR5G6B5( color );
422 : }
423 : break;
424 :
425 : case ECF_R8G8B8:
426 : {
427 : u8* dest = (u8*)data;
428 : dest[0] = (u8)getRed();
429 : dest[1] = (u8)getGreen();
430 : dest[2] = (u8)getBlue();
431 : }
432 : break;
433 :
434 : case ECF_A8R8G8B8:
435 : {
436 : u32 * dest = (u32*)data;
437 : *dest = color;
438 : }
439 : break;
440 :
441 : default:
442 : break;
443 : }
444 : }
445 :
446 : //! color in A8R8G8B8 Format
447 : u32 color;
448 : };
449 :
450 :
451 : //! Class representing a color with four floats.
452 : /** The color values for red, green, blue
453 : and alpha are each stored in a 32 bit floating point variable.
454 : So all four values may be between 0.0f and 1.0f.
455 : Another, faster way to define colors is using the class SColor, which
456 : stores the color values in a single 32 bit integer.
457 : */
458 : class SColorf
459 : {
460 : public:
461 : //! Default constructor for SColorf.
462 : /** Sets red, green and blue to 0.0f and alpha to 1.0f. */
463 6 : SColorf() : r(0.0f), g(0.0f), b(0.0f), a(1.0f) {}
464 :
465 : //! Constructs a color from up to four color values: red, green, blue, and alpha.
466 : /** \param r: Red color component. Should be a value between
467 : 0.0f meaning no red and 1.0f, meaning full red.
468 : \param g: Green color component. Should be a value between 0.0f
469 : meaning no green and 1.0f, meaning full green.
470 : \param b: Blue color component. Should be a value between 0.0f
471 : meaning no blue and 1.0f, meaning full blue.
472 : \param a: Alpha color component of the color. The alpha
473 : component defines how transparent a color should be. Has to be
474 : a value between 0.0f and 1.0f, 1.0f means not transparent
475 : (opaque), 0.0f means fully transparent. */
476 16053 : SColorf(f32 r, f32 g, f32 b, f32 a = 1.0f) : r(r), g(g), b(b), a(a) {}
477 :
478 : //! Constructs a color from 32 bit Color.
479 : /** \param c: 32 bit color from which this SColorf class is
480 : constructed from. */
481 1433472 : SColorf(SColor c)
482 : {
483 1433472 : const f32 inv = 1.0f / 255.0f;
484 1433472 : r = c.getRed() * inv;
485 1433472 : g = c.getGreen() * inv;
486 1433472 : b = c.getBlue() * inv;
487 1433472 : a = c.getAlpha() * inv;
488 1433472 : }
489 :
490 : //! Converts this color to a SColor without floats.
491 12518 : SColor toSColor() const
492 : {
493 12518 : return SColor((u32)core::round32(a*255.0f), (u32)core::round32(r*255.0f), (u32)core::round32(g*255.0f), (u32)core::round32(b*255.0f));
494 : }
495 :
496 : //! Sets three color components to new values at once.
497 : /** \param rr: Red color component. Should be a value between 0.0f meaning
498 : no red (=black) and 1.0f, meaning full red.
499 : \param gg: Green color component. Should be a value between 0.0f meaning
500 : no green (=black) and 1.0f, meaning full green.
501 : \param bb: Blue color component. Should be a value between 0.0f meaning
502 : no blue (=black) and 1.0f, meaning full blue. */
503 : void set(f32 rr, f32 gg, f32 bb) {r = rr; g =gg; b = bb; }
504 :
505 : //! Sets all four color components to new values at once.
506 : /** \param aa: Alpha component. Should be a value between 0.0f meaning
507 : fully transparent and 1.0f, meaning opaque.
508 : \param rr: Red color component. Should be a value between 0.0f meaning
509 : no red and 1.0f, meaning full red.
510 : \param gg: Green color component. Should be a value between 0.0f meaning
511 : no green and 1.0f, meaning full green.
512 : \param bb: Blue color component. Should be a value between 0.0f meaning
513 : no blue and 1.0f, meaning full blue. */
514 2 : void set(f32 aa, f32 rr, f32 gg, f32 bb) {a = aa; r = rr; g =gg; b = bb; }
515 :
516 : //! Interpolates the color with a f32 value to another color
517 : /** \param other: Other color
518 : \param d: value between 0.0f and 1.0f
519 : \return Interpolated color. */
520 3795 : SColorf getInterpolated(const SColorf &other, f32 d) const
521 : {
522 3795 : d = core::clamp(d, 0.f, 1.f);
523 3795 : const f32 inv = 1.0f - d;
524 3795 : return SColorf(other.r*inv + r*d,
525 7590 : other.g*inv + g*d, other.b*inv + b*d, other.a*inv + a*d);
526 : }
527 :
528 : //! Returns interpolated color. ( quadratic )
529 : /** \param c1: first color to interpolate with
530 : \param c2: second color to interpolate with
531 : \param d: value between 0.0f and 1.0f. */
532 : inline SColorf getInterpolated_quadratic(const SColorf& c1, const SColorf& c2,
533 : f32 d) const
534 : {
535 : d = core::clamp(d, 0.f, 1.f);
536 : // this*(1-d)*(1-d) + 2 * c1 * (1-d) + c2 * d * d;
537 : const f32 inv = 1.f - d;
538 : const f32 mul0 = inv * inv;
539 : const f32 mul1 = 2.f * d * inv;
540 : const f32 mul2 = d * d;
541 :
542 : return SColorf (r * mul0 + c1.r * mul1 + c2.r * mul2,
543 : g * mul0 + c1.g * mul1 + c2.g * mul2,
544 : b * mul0 + c1.b * mul1 + c2.b * mul2,
545 : a * mul0 + c1.a * mul1 + c2.a * mul2);
546 : }
547 :
548 :
549 : //! Sets a color component by index. R=0, G=1, B=2, A=3
550 : void setColorComponentValue(s32 index, f32 value)
551 : {
552 : switch(index)
553 : {
554 : case 0: r = value; break;
555 : case 1: g = value; break;
556 : case 2: b = value; break;
557 : case 3: a = value; break;
558 : }
559 : }
560 :
561 : //! Returns the alpha component of the color in the range 0.0 (transparent) to 1.0 (opaque)
562 : f32 getAlpha() const { return a; }
563 :
564 : //! Returns the red component of the color in the range 0.0 to 1.0
565 : f32 getRed() const { return r; }
566 :
567 : //! Returns the green component of the color in the range 0.0 to 1.0
568 : f32 getGreen() const { return g; }
569 :
570 : //! Returns the blue component of the color in the range 0.0 to 1.0
571 : f32 getBlue() const { return b; }
572 :
573 : //! red color component
574 : f32 r;
575 :
576 : //! green color component
577 : f32 g;
578 :
579 : //! blue component
580 : f32 b;
581 :
582 : //! alpha color component
583 : f32 a;
584 : };
585 :
586 :
587 : //! Class representing a color in HSL format
588 : /** The color values for hue, saturation, luminance
589 : are stored in 32bit floating point variables. Hue is in range [0,360],
590 : Luminance and Saturation are in percent [0,100]
591 : */
592 : class SColorHSL
593 : {
594 : public:
595 : SColorHSL ( f32 h = 0.f, f32 s = 0.f, f32 l = 0.f )
596 : : Hue ( h ), Saturation ( s ), Luminance ( l ) {}
597 :
598 : void fromRGB(const SColorf &color);
599 : void toRGB(SColorf &color) const;
600 :
601 : f32 Hue;
602 : f32 Saturation;
603 : f32 Luminance;
604 :
605 : private:
606 : inline f32 toRGB1(f32 rm1, f32 rm2, f32 rh) const;
607 :
608 : };
609 :
610 : inline void SColorHSL::fromRGB(const SColorf &color)
611 : {
612 : const f32 maxVal = core::max_(color.getRed(), color.getGreen(), color.getBlue());
613 : const f32 minVal = (f32)core::min_(color.getRed(), color.getGreen(), color.getBlue());
614 : Luminance = (maxVal+minVal)*50;
615 : if (core::equals(maxVal, minVal))
616 : {
617 : Hue=0.f;
618 : Saturation=0.f;
619 : return;
620 : }
621 :
622 : const f32 delta = maxVal-minVal;
623 : if ( Luminance <= 50 )
624 : {
625 : Saturation = (delta)/(maxVal+minVal);
626 : }
627 : else
628 : {
629 : Saturation = (delta)/(2-maxVal-minVal);
630 : }
631 : Saturation *= 100;
632 :
633 : if (core::equals(maxVal, color.getRed()))
634 : Hue = (color.getGreen()-color.getBlue())/delta;
635 : else if (core::equals(maxVal, color.getGreen()))
636 : Hue = 2+((color.getBlue()-color.getRed())/delta);
637 : else // blue is max
638 : Hue = 4+((color.getRed()-color.getGreen())/delta);
639 :
640 : Hue *= 60.0f;
641 : while ( Hue < 0.f )
642 : Hue += 360;
643 : }
644 :
645 :
646 : inline void SColorHSL::toRGB(SColorf &color) const
647 : {
648 : const f32 l = Luminance/100;
649 : if (core::iszero(Saturation)) // grey
650 : {
651 : color.set(l, l, l);
652 : return;
653 : }
654 :
655 : f32 rm2;
656 :
657 : if ( Luminance <= 50 )
658 : {
659 : rm2 = l + l * (Saturation/100);
660 : }
661 : else
662 : {
663 : rm2 = l + (1 - l) * (Saturation/100);
664 : }
665 :
666 : const f32 rm1 = 2.0f * l - rm2;
667 :
668 : const f32 h = Hue / 360.0f;
669 : color.set( toRGB1(rm1, rm2, h + 1.f/3.f),
670 : toRGB1(rm1, rm2, h),
671 : toRGB1(rm1, rm2, h - 1.f/3.f)
672 : );
673 : }
674 :
675 :
676 : // algorithm from Foley/Van-Dam
677 : inline f32 SColorHSL::toRGB1(f32 rm1, f32 rm2, f32 rh) const
678 : {
679 : if (rh<0)
680 : rh += 1;
681 : if (rh>1)
682 : rh -= 1;
683 :
684 : if (rh < 1.f/6.f)
685 : rm1 = rm1 + (rm2 - rm1) * rh*6.f;
686 : else if (rh < 0.5f)
687 : rm1 = rm2;
688 : else if (rh < 2.f/3.f)
689 : rm1 = rm1 + (rm2 - rm1) * ((2.f/3.f)-rh)*6.f;
690 :
691 : return rm1;
692 : }
693 :
694 : } // end namespace video
695 : } // end namespace irr
696 :
697 : #endif
|