Public Variables
const F32 gGamma
const F32 gOneOver255
const F32 gOneOverGamma
1
2//-----------------------------------------------------------------------------
3// Copyright (c) 2012 GarageGames, LLC
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to
7// deal in the Software without restriction, including without limitation the
8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9// sell copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21// IN THE SOFTWARE.
22//-----------------------------------------------------------------------------
23
24#ifndef _COLOR_H_
25#define _COLOR_H_
26
27#ifndef _MPOINT3_H_
28#include "math/mPoint3.h"
29#endif
30#ifndef _MPOINT4_H_
31#include "math/mPoint4.h"
32#endif
33
34#ifndef _ENGINEAPI_H_
35#include "console/engineAPI.h"
36#endif
37
38const F32 gGamma = 2.2f;
39const F32 gOneOverGamma = 1.f / 2.2f;
40const F32 gOneOver255 = 1.f / 255.f;
41
42class ColorI;
43
44//32bit color in linear space
45class LinearColorF
46{
47public:
48 F32 red;
49 F32 green;
50 F32 blue;
51 F32 alpha;
52
53public:
54 LinearColorF() : red(0), green(0), blue(0), alpha(0) {}
55 LinearColorF(const LinearColorF& in_rCopy);
56 LinearColorF(const F32 in_r, const F32 in_g, const F32 in_b, const F32 in_a = 1.0f);
57 LinearColorF(const ColorI &color);
58 LinearColorF(const char* pStockColorName);
59
60 void set( const F32 in_r, const F32 in_g, const F32 in_b, const F32 in_a = 1.0f );
61 void set( const char* pStockColorName );
62
63 static const LinearColorF& StockColor( const char* pStockColorName );
64 StringTableEntry StockColor( void );
65
66 LinearColorF& operator*=(const LinearColorF& in_mul); // Can be useful for lighting
67 LinearColorF operator*(const LinearColorF& in_mul) const;
68 LinearColorF& operator+=(const LinearColorF& in_rAdd);
69 LinearColorF operator+(const LinearColorF& in_rAdd) const;
70 LinearColorF& operator-=(const LinearColorF& in_rSub);
71 LinearColorF operator-(const LinearColorF& in_rSub) const;
72
73 LinearColorF& operator*=(const F32 in_mul);
74 LinearColorF operator*(const F32 in_mul) const;
75 LinearColorF& operator/=(const F32 in_div);
76 LinearColorF operator/(const F32 in_div) const;
77
78 LinearColorF operator-() const;
79
80 bool operator==(const LinearColorF&) const;
81 bool operator!=(const LinearColorF&) const;
82
83 operator F32*() { return &red; }
84 operator const F32*() const { return &red; }
85
86 operator Point3F() const { return Point3F( red, green, blue ); }
87 operator Point4F() const { return Point4F( red, green, blue, alpha ); }
88
89 U32 getARGBPack() const;
90 U32 getRGBAPack() const;
91 U32 getABGRPack() const;
92
93 void interpolate(const LinearColorF& in_rC1,
94 const LinearColorF& in_rC2,
95 const F32 in_factor);
96
97 bool isClamped() const { return (red >= 0.0f && red <= 1.0f) &&
98 (green >= 0.0f && green <= 1.0f) &&
99 (blue >= 0.0f && blue <= 1.0f) &&
100 (alpha >= 0.0f && alpha <= 1.0f); }
101 void clamp();
102
103 //calculate luminance
104 F32 luminance();
105
106 //convert to ColorI - slow operation, avoid when possible
107 ColorI toColorI(const bool keepAsLinear = false);
108
109 static const LinearColorF ZERO;
110 static const LinearColorF ONE;
111 static const LinearColorF WHITE;
112 static const LinearColorF BLACK;
113 static const LinearColorF RED;
114 static const LinearColorF GREEN;
115 static const LinearColorF BLUE;
116
117 static F32 sSrgbToLinear[256];
118};
119
120
121//8bit color in srgb space
122class ColorI
123{
124public:
125 U8 red;
126 U8 green;
127 U8 blue;
128 U8 alpha;
129
130 struct Hsb
131 {
132 Hsb() :hue(0), sat(0), brightness(0){};
133 Hsb(U32 h, U32 s, U32 b) :hue(h), sat(s), brightness(b){};
134
135 U32 hue; ///Hue
136 U32 sat; ///Saturation
137 U32 brightness; //Brightness/Value/Lightness
138 };
139
140public:
141 ColorI() : red(0), green(0), blue(0), alpha(0) {}
142 ColorI(const ColorI& in_rCopy);
143 ColorI(const Hsb& color);
144 ColorI(const U8 in_r, const U8 in_g, const U8 in_b, const U8 in_a = U8(255));
145 ColorI(const ColorI& in_rCopy, const U8 in_a);
146 ColorI(const char* pStockColorName);
147
148 void set(const Hsb& color);
149
150 void HSLtoRGB_Subfunction(U32& c, const F64& temp1, const F64& temp2, const F64& temp3);
151
152 void set(const String& hex);
153
154 void set(const U8 in_r,
155 const U8 in_g,
156 const U8 in_b,
157 const U8 in_a = U8(255));
158
159 void set(const ColorI& in_rCopy,
160 const U8 in_a);
161
162 void set( const char* pStockColorName );
163
164 static const ColorI& StockColor( const char* pStockColorName );
165 StringTableEntry StockColor( void );
166
167 bool operator==(const ColorI&) const;
168 bool operator!=(const ColorI&) const;
169
170 U32 getARGBPack() const;
171 U32 getRGBAPack() const;
172 U32 getABGRPack() const;
173
174 U32 getBGRPack() const;
175 U32 getRGBPack() const;
176
177 U32 getRGBEndian() const;
178 U32 getARGBEndian() const;
179
180 U16 get565() const;
181 U16 get4444() const;
182
183 Hsb getHSB() const;
184
185 String getHex() const;
186 S32 convertFromHex(const String& hex) const;
187
188 operator const U8*() const { return &red; }
189
190 //convert linear color to srgb - slow operation, avoid when possible
191 ColorI fromLinear();
192
193 static const ColorI ZERO;
194 static const ColorI ONE;
195 static const ColorI WHITE;
196 static const ColorI BLACK;
197 static const ColorI RED;
198 static const ColorI GREEN;
199 static const ColorI BLUE;
200};
201
202//-----------------------------------------------------------------------------
203
204class StockColorItem
205{
206private:
207 StockColorItem():mColorName("") {}
208
209public:
210 StockColorItem( const char* pName, const U8 red, const U8 green, const U8 blue, const U8 alpha = 255 )
211 {
212 // Sanity!
213 AssertFatal( pName != NULL, "Stock color name cannot be NULL." );
214
215 // Set stock color.
216 // NOTE:- We'll use the char pointer here. We can yet use the string-table unfortunately.
217 mColorName = pName;
218 mColorI.set( red, green, blue, alpha );
219 mColorF = mColorI;
220 }
221
222 inline const char* getColorName( void ) const { return mColorName; }
223 inline const LinearColorF& getColorF( void ) const { return mColorF; }
224 inline const ColorI& getColorI( void ) const { return mColorI; }
225
226 const char* mColorName;
227 LinearColorF mColorF;
228 ColorI mColorI;
229};
230
231//-----------------------------------------------------------------------------
232
233class StockColor
234{
235public:
236 static bool isColor( const char* pStockColorName );
237 static const LinearColorF& colorF( const char* pStockColorName );
238 static const ColorI& colorI( const char* pStockColorName );
239 static StringTableEntry name( const LinearColorF& color );
240 static StringTableEntry name( const ColorI& color );
241
242 static S32 getCount( void );
243 static const StockColorItem* getColorItem( const S32 index );
244
245 static void create( void );
246 static void destroy( void );
247};
248
249//------------------------------------------------------------------------------
250//-------------------------------------- INLINES (LinearColorF)
251//
252inline void LinearColorF::set(const F32 in_r, const F32 in_g, const F32 in_b, const F32 in_a)
253{
254 red = in_r;
255 green = in_g;
256 blue = in_b;
257 alpha = in_a;
258}
259
260inline LinearColorF::LinearColorF(const LinearColorF& in_rCopy)
261{
262 red = in_rCopy.red;
263 green = in_rCopy.green;
264 blue = in_rCopy.blue;
265 alpha = in_rCopy.alpha;
266}
267
268inline LinearColorF::LinearColorF(const F32 in_r, const F32 in_g, const F32 in_b, const F32 in_a)
269{
270 set(in_r, in_g, in_b, in_a);
271}
272
273inline LinearColorF& LinearColorF::operator*=(const LinearColorF& in_mul)
274{
275 red *= in_mul.red;
276 green *= in_mul.green;
277 blue *= in_mul.blue;
278 alpha *= in_mul.alpha;
279
280 return *this;
281}
282
283inline LinearColorF LinearColorF::operator*(const LinearColorF& in_mul) const
284{
285 LinearColorF tmp(*this);
286 tmp *= in_mul;
287 return tmp;
288}
289
290inline LinearColorF& LinearColorF::operator+=(const LinearColorF& in_rAdd)
291{
292 red += in_rAdd.red;
293 green += in_rAdd.green;
294 blue += in_rAdd.blue;
295 alpha += in_rAdd.alpha;
296 return *this;
297}
298
299inline LinearColorF LinearColorF::operator+(const LinearColorF& in_rAdd) const
300{
301 LinearColorF temp(*this);
302 temp += in_rAdd;
303 return temp;
304}
305
306inline LinearColorF& LinearColorF::operator-=(const LinearColorF& in_rSub)
307{
308 red -= in_rSub.red;
309 green -= in_rSub.green;
310 blue -= in_rSub.blue;
311 alpha -= in_rSub.alpha;
312 return *this;
313}
314
315inline LinearColorF LinearColorF::operator-(const LinearColorF& in_rSub) const
316{
317 LinearColorF tmp(*this);
318 tmp -= in_rSub;
319 return tmp;
320}
321
322inline LinearColorF& LinearColorF::operator*=(const F32 in_mul)
323{
324 red *= in_mul;
325 green *= in_mul;
326 blue *= in_mul;
327 alpha *= in_mul;
328 return *this;
329}
330
331inline LinearColorF LinearColorF::operator*(const F32 in_mul) const
332{
333 LinearColorF tmp(*this);
334 tmp *= in_mul;
335 return tmp;
336}
337
338inline LinearColorF& LinearColorF::operator/=(const F32 in_div)
339{
340 AssertFatal(in_div != 0.0f, "Error, div by zero...");
341 F32 inv = 1.0f / in_div;
342
343 red *= inv;
344 green *= inv;
345 blue *= inv;
346 alpha *= inv;
347 return *this;
348}
349
350inline LinearColorF LinearColorF::operator/(const F32 in_div) const
351{
352 AssertFatal(in_div != 0.0f, "Error, div by zero...");
353 F32 inv = 1.0f / in_div;
354 LinearColorF tmp(*this);
355 tmp /= inv;
356 return tmp;
357}
358
359inline LinearColorF LinearColorF::operator-() const
360{
361 return LinearColorF(-red, -green, -blue, -alpha);
362}
363
364inline bool LinearColorF::operator==(const LinearColorF& in_Cmp) const
365{
366 return (red == in_Cmp.red && green == in_Cmp.green && blue == in_Cmp.blue && alpha == in_Cmp.alpha);
367}
368
369inline bool LinearColorF::operator!=(const LinearColorF& in_Cmp) const
370{
371 return (red != in_Cmp.red || green != in_Cmp.green || blue != in_Cmp.blue || alpha != in_Cmp.alpha);
372}
373
374inline U32 LinearColorF::getARGBPack() const
375{
376 return (U32(alpha * 255.0f + 0.5) << 24) |
377 (U32(red * 255.0f + 0.5) << 16) |
378 (U32(green * 255.0f + 0.5) << 8) |
379 (U32(blue * 255.0f + 0.5) << 0);
380}
381
382inline U32 LinearColorF::getRGBAPack() const
383{
384 return ( U32( red * 255.0f + 0.5) << 0 ) |
385 ( U32( green * 255.0f + 0.5) << 8 ) |
386 ( U32( blue * 255.0f + 0.5) << 16 ) |
387 ( U32( alpha * 255.0f + 0.5) << 24 );
388}
389
390inline U32 LinearColorF::getABGRPack() const
391{
392 return (U32(alpha * 255.0f + 0.5) << 24) |
393 (U32(blue * 255.0f + 0.5) << 16) |
394 (U32(green * 255.0f + 0.5) << 8) |
395 (U32(red * 255.0f + 0.5) << 0);
396
397}
398
399inline void LinearColorF::interpolate(const LinearColorF& in_rC1,
400 const LinearColorF& in_rC2,
401 const F32 in_factor)
402{
403 if (in_factor <= 0 || in_rC1 == in_rC2)
404 {
405 red = in_rC1.red;
406 green = in_rC1.green;
407 blue =in_rC1.blue;
408 alpha = in_rC1.alpha;
409 return;
410 }
411 else if (in_factor >= 1)
412 {
413 red = in_rC2.red;
414 green = in_rC2.green;
415 blue = in_rC2.blue;
416 alpha = in_rC2.alpha;
417 return;
418 }
419
420 F32 f2 = 1.0f - in_factor;
421 red = (in_rC1.red * f2) + (in_rC2.red * in_factor);
422 green = (in_rC1.green * f2) + (in_rC2.green * in_factor);
423 blue = (in_rC1.blue * f2) + (in_rC2.blue * in_factor);
424 alpha = (in_rC1.alpha * f2) + (in_rC2.alpha * in_factor);
425}
426
427inline void LinearColorF::clamp()
428{
429 red = mClampF(red, 0.0f, 1.0f);
430 green = mClampF(green, 0.0f, 1.0f);
431 blue = mClampF(blue, 0.0f, 1.0f);
432 alpha = mClampF(alpha, 0.0f, 1.0f);
433}
434
435inline F32 LinearColorF::luminance()
436{
437 // ITU BT.709
438 //return red * 0.2126f + green * 0.7152f + blue * 0.0722f;
439 // ITU BT.601
440 return red * 0.3f + green * 0.59f + blue * 0.11f;
441}
442
443//------------------------------------------------------------------------------
444//-------------------------------------- INLINES (ColorI)
445//
446inline void ColorI::set(const U8 in_r,
447 const U8 in_g,
448 const U8 in_b,
449 const U8 in_a)
450{
451 red = in_r;
452 green = in_g;
453 blue = in_b;
454 alpha = in_a;
455}
456
457inline void ColorI::set(const ColorI& in_rCopy,
458 const U8 in_a)
459{
460 red = in_rCopy.red;
461 green = in_rCopy.green;
462 blue = in_rCopy.blue;
463 alpha = in_a;
464}
465
466inline void ColorI::set(const Hsb& color)
467{
468 U32 r = 0;
469 U32 g = 0;
470 U32 b = 0;
471
472 F64 L = ((F64)color.brightness) / 100.0;
473 F64 S = ((F64)color.sat) / 100.0;
474 F64 H = ((F64)color.hue) / 360.0;
475
476 if (color.sat == 0)
477 {
478 r = color.brightness;
479 g = color.brightness;
480 b = color.brightness;
481 }
482 else
483 {
484 F64 temp1 = 0;
485 if (L < 0.50)
486 {
487 temp1 = L*(1 + S);
488 }
489 else
490 {
491 temp1 = L + S - (L*S);
492 }
493
494 F64 temp2 = 2.0*L - temp1;
495
496 F64 temp3 = 0;
497 for (S32 i = 0; i < 3; i++)
498 {
499 switch (i)
500 {
501 case 0: // red
502 {
503 temp3 = H + 0.33333;
504 if (temp3 > 1.0)
505 temp3 -= 1.0;
506 HSLtoRGB_Subfunction(r, temp1, temp2, temp3);
507 break;
508 }
509 case 1: // green
510 {
511 temp3 = H;
512 HSLtoRGB_Subfunction(g, temp1, temp2, temp3);
513 break;
514 }
515 case 2: // blue
516 {
517 temp3 = H - 0.33333;
518 if (temp3 < 0)
519 temp3 += 1;
520 HSLtoRGB_Subfunction(b, temp1, temp2, temp3);
521 break;
522 }
523 default:
524 {
525
526 }
527 }
528 }
529 }
530 red = (U32)((((F64)r) / 100) * 255);
531 green = (U32)((((F64)g) / 100) * 255);
532 blue = (U32)((((F64)b) / 100) * 255);
533 alpha = 255;
534}
535
536// This is a subfunction of HSLtoRGB
537inline void ColorI::HSLtoRGB_Subfunction(U32& c, const F64& temp1, const F64& temp2, const F64& temp3)
538{
539 if ((temp3 * 6.0) < 1.0)
540 c = (U32)((temp2 + (temp1 - temp2)*6.0*temp3)*100.0);
541 else
542 if ((temp3 * 2.0) < 1.0)
543 c = (U32)(temp1*100.0);
544 else
545 if ((temp3 * 3.0) < 2.0)
546 c = (U32)((temp2 + (temp1 - temp2)*(0.66666 - temp3)*6.0)*100.0);
547 else
548 c = (U32)(temp2*100.0);
549 return;
550}
551
552inline void ColorI::set(const String& hex)
553{
554 String redString;
555 String greenString;
556 String blueString;
557
558 //if the prefix # was attached to hex
559 if (hex[0] == '#')
560 {
561 redString = hex.substr(1, 2);
562 greenString = hex.substr(3, 2);
563 blueString = hex.substr(5, 2);
564 }
565 else
566 {
567 // since there is no prefix attached to hex
568 redString = hex.substr(0, 2);
569 greenString = hex.substr(2, 2);
570 blueString = hex.substr(4, 2);
571 }
572
573 red = (U8)(convertFromHex(redString));
574 green = (U8)(convertFromHex(greenString));
575 blue = (U8)(convertFromHex(blueString));
576}
577
578inline S32 ColorI::convertFromHex(const String& hex) const
579{
580 S32 hexValue = 0;
581
582 S32 a = 0;
583 S32 b = hex.length() - 1;
584
585 for (; b >= 0; a++, b--)
586 {
587 if (hex[b] >= '0' && hex[b] <= '9')
588 {
589 hexValue += (hex[b] - '0') * (1 << (a * 4));
590 }
591 else
592 {
593 switch (hex[b])
594 {
595 case 'A':
596 case 'a':
597 hexValue += 10 * (1 << (a * 4));
598 break;
599
600 case 'B':
601 case 'b':
602 hexValue += 11 * (1 << (a * 4));
603 break;
604
605 case 'C':
606 case 'c':
607 hexValue += 12 * (1 << (a * 4));
608 break;
609
610 case 'D':
611 case 'd':
612 hexValue += 13 * (1 << (a * 4));
613 break;
614
615 case 'E':
616 case 'e':
617 hexValue += 14 * (1 << (a * 4));
618 break;
619
620 case 'F':
621 case 'f':
622 hexValue += 15 * (1 << (a * 4));
623 break;
624
625 default:
626 Con::errorf("Error, invalid character '%c' in hex number", hex[a]);
627 break;
628 }
629 }
630 }
631
632 return hexValue;
633}
634
635inline ColorI::ColorI(const ColorI& in_rCopy)
636{
637 red = in_rCopy.red;
638 green = in_rCopy.green;
639 blue = in_rCopy.blue;
640 alpha = in_rCopy.alpha;
641}
642
643inline ColorI::ColorI(const Hsb& color)
644{
645 set(color);
646}
647
648inline ColorI::ColorI(const U8 in_r,
649 const U8 in_g,
650 const U8 in_b,
651 const U8 in_a)
652{
653 set(in_r, in_g, in_b, in_a);
654}
655
656inline ColorI::ColorI(const ColorI& in_rCopy,
657 const U8 in_a)
658{
659 set(in_rCopy, in_a);
660}
661
662inline bool ColorI::operator==(const ColorI& in_Cmp) const
663{
664 return (red == in_Cmp.red && green == in_Cmp.green && blue == in_Cmp.blue && alpha == in_Cmp.alpha);
665}
666
667inline bool ColorI::operator!=(const ColorI& in_Cmp) const
668{
669 return (red != in_Cmp.red || green != in_Cmp.green || blue != in_Cmp.blue || alpha != in_Cmp.alpha);
670}
671
672inline U32 ColorI::getARGBPack() const
673{
674 return (U32(alpha) << 24) |
675 (U32(red) << 16) |
676 (U32(green) << 8) |
677 (U32(blue) << 0);
678}
679
680inline U32 ColorI::getRGBAPack() const
681{
682 return ( U32( red ) << 0 ) |
683 ( U32( green ) << 8 ) |
684 ( U32( blue ) << 16 ) |
685 ( U32( alpha ) << 24 );
686}
687
688inline U32 ColorI::getABGRPack() const
689{
690 return (U32(alpha) << 24) |
691 (U32(blue) << 16) |
692 (U32(green) << 8) |
693 (U32(red) << 0);
694}
695
696
697inline U32 ColorI::getBGRPack() const
698{
699 return (U32(blue) << 16) |
700 (U32(green) << 8) |
701 (U32(red) << 0);
702}
703
704inline U32 ColorI::getRGBPack() const
705{
706 return (U32(red) << 16) |
707 (U32(green) << 8) |
708 (U32(blue) << 0);
709}
710
711inline U32 ColorI::getRGBEndian() const
712{
713#if defined(TORQUE_BIG_ENDIAN)
714 return(getRGBPack());
715#else
716 return(getBGRPack());
717#endif
718}
719
720inline U32 ColorI::getARGBEndian() const
721{
722#if defined(TORQUE_BIG_ENDIAN)
723 return(getABGRPack());
724#else
725 return(getARGBPack());
726#endif
727}
728
729inline U16 ColorI::get565() const
730{
731 return U16((U16(red >> 3) << 11) |
732 (U16(green >> 2) << 5) |
733 (U16(blue >> 3) << 0));
734}
735
736inline U16 ColorI::get4444() const
737{
738 return U16(U16(U16(alpha >> 4) << 12) |
739 U16(U16(red >> 4) << 8) |
740 U16(U16(green >> 4) << 4) |
741 U16(U16(blue >> 4) << 0));
742}
743
744inline ColorI::Hsb ColorI::getHSB() const
745{
746 F64 rPercent = ((F64)red) / 255;
747 F64 gPercent = ((F64)green) / 255;
748 F64 bPercent = ((F64)blue) / 255;
749
750 F64 maxColor = 0.0;
751 if ((rPercent >= gPercent) && (rPercent >= bPercent))
752 maxColor = rPercent;
753 if ((gPercent >= rPercent) && (gPercent >= bPercent))
754 maxColor = gPercent;
755 if ((bPercent >= rPercent) && (bPercent >= gPercent))
756 maxColor = bPercent;
757
758 F64 minColor = 0.0;
759 if ((rPercent <= gPercent) && (rPercent <= bPercent))
760 minColor = rPercent;
761 if ((gPercent <= rPercent) && (gPercent <= bPercent))
762 minColor = gPercent;
763 if ((bPercent <= rPercent) && (bPercent <= gPercent))
764 minColor = bPercent;
765
766 F64 H = 0.0;
767 F64 S = 0.0;
768 F64 B = 0.0;
769
770 B = (maxColor + minColor) / 2.0;
771
772 if (maxColor == minColor)
773 {
774 H = 0.0;
775 S = 0.0;
776 }
777 else
778 {
779 if (B < 0.50)
780 {
781 S = (maxColor - minColor) / (maxColor + minColor);
782 }
783 else
784 {
785 S = (maxColor - minColor) / (2.0 - maxColor - minColor);
786 }
787 if (maxColor == rPercent)
788 {
789 H = (gPercent - bPercent) / (maxColor - minColor);
790 }
791 if (maxColor == gPercent)
792 {
793 H = 2.0 + (bPercent - rPercent) / (maxColor - minColor);
794 }
795 if (maxColor == bPercent)
796 {
797 H = 4.0 + (rPercent - gPercent) / (maxColor - minColor);
798 }
799 }
800
801 ColorI::Hsb val;
802 val.sat = (U32)(S * 100);
803 val.brightness = (U32)(B * 100);
804 H = H*60.0;
805 if (H < 0.0)
806 H += 360.0;
807 val.hue = (U32)H;
808
809 return val;
810}
811
812inline String ColorI::getHex() const
813{
814 char r[255];
815 dSprintf(r, sizeof(r), "%.2X", red);
816 String result(r);
817
818 char g[255];
819 dSprintf(g, sizeof(g), "%.2X", green);
820 result += g;
821
822 char b[255];
823 dSprintf(b, sizeof(b), "%.2X", blue);
824 result += b;
825
826 return result;
827}
828
829inline LinearColorF::LinearColorF( const ColorI &color)
830{
831 red = sSrgbToLinear[color.red],
832 green = sSrgbToLinear[color.green],
833 blue = sSrgbToLinear[color.blue],
834 alpha = F32(color.alpha * gOneOver255);
835}
836
837inline ColorI LinearColorF::toColorI(const bool keepAsLinear)
838{
839 if (isClamped())
840 {
841 if (keepAsLinear)
842 {
843 return ColorI(U8(red * 255.0f + 0.5), U8(green * 255.0f + 0.5), U8(blue * 255.0f + 0.5), U8(alpha * 255.0f + 0.5));
844 }
845 else
846 {
847 #ifdef TORQUE_USE_LEGACY_GAMMA
848 float r = mPow(red, gOneOverGamma);
849 float g = mPow(green, gOneOverGamma);
850 float b = mPow(blue, gOneOverGamma);
851 return ColorI(U8(r * 255.0f + 0.5), U8(g * 255.0f + 0.5), U8(b * 255.0f + 0.5), U8(alpha * 255.0f + 0.5));
852 #else
853 float r = red < 0.0031308f ? 12.92f * red : 1.055 * mPow(red, 1.0f / 2.4f) - 0.055f;
854 float g = green < 0.0031308f ? 12.92f * green : 1.055 * mPow(green, 1.0f / 2.4f) - 0.055f;
855 float b = blue < 0.0031308f ? 12.92f * blue : 1.055 * mPow(blue, 1.0f / 2.4f) - 0.055f;
856 return ColorI(U8(r * 255.0f + 0.5), U8(g * 255.0f + 0.5), U8(b * 255.0f + 0.5), U8(alpha * 255.0f + 0.5));
857 #endif
858 }
859 }
860 else
861 {
862 LinearColorF color = LinearColorF(*this);
863 color.clamp();
864
865 if (keepAsLinear)
866 {
867 return ColorI(U8(color.red * 255.0f + 0.5), U8(color.green * 255.0f + 0.5), U8(color.blue * 255.0f + 0.5), U8(color.alpha * 255.0f + 0.5));
868 }
869 else
870 {
871 #ifdef TORQUE_USE_LEGACY_GAMMA
872 float r = mPow(red, gOneOverGamma);
873 float g = mPow(green, gOneOverGamma);
874 float b = mPow(blue, gOneOverGamma);
875 return ColorI(U8(r * 255.0f + 0.5), U8(g * 255.0f + 0.5), U8(b * 255.0f + 0.5), U8(alpha * 255.0f + 0.5));
876 #else
877 float r = red < 0.0031308f ? 12.92f * red : 1.055 * mPow(red, 1.0f / 2.4f) - 0.055f;
878 float g = green < 0.0031308f ? 12.92f * green : 1.055 * mPow(green, 1.0f / 2.4f) - 0.055f;
879 float b = blue < 0.0031308f ? 12.92f * blue : 1.055 * mPow(blue, 1.0f / 2.4f) - 0.055f;
880 return ColorI(U8(r * 255.0f + 0.5), U8(g * 255.0f + 0.5), U8(b * 255.0f + 0.5), U8(alpha * 255.0f + 0.5));
881 #endif
882 }
883 }
884}
885
886inline ColorI ColorI::fromLinear()
887{
888 //manually create LinearColorF, otherwise it will try and convert to linear first
889 LinearColorF linearColor = LinearColorF(F32(red) * gOneOver255,
890 F32(green) * gOneOver255,
891 F32(blue) * gOneOver255,
892 F32(alpha) * gOneOver255);
893 //convert back to srgb
894 return linearColor.toColorI();
895}
896
897#endif //_COLOR_H_
898