IrrlichtEngine
SColor.h
Go to the documentation of this file.
00001 // Copyright (C) 2002-2011 Nikolaus Gebhardt
00002 // This file is part of the "Irrlicht Engine".
00003 // For conditions of distribution and use, see copyright notice in irrlicht.h
00004 
00005 #ifndef __COLOR_H_INCLUDED__
00006 #define __COLOR_H_INCLUDED__
00007 
00008 #include "irrTypes.h"
00009 #include "irrMath.h"
00010 
00011 namespace irr
00012 {
00013 namespace video
00014 {
00016 
00017         enum ECOLOR_FORMAT
00018         {
00020 
00023                 ECF_A1R5G5B5 = 0,
00024 
00026                 ECF_R5G6B5,
00027 
00029                 ECF_R8G8B8,
00030 
00032                 ECF_A8R8G8B8,
00033 
00036 
00037                 ECF_R16F,
00038 
00040                 ECF_G16R16F,
00041 
00043                 ECF_A16B16G16R16F,
00044 
00046                 ECF_R32F,
00047 
00049                 ECF_G32R32F,
00050 
00052                 ECF_A32B32G32R32F,
00053 
00055                 ECF_UNKNOWN
00056         };
00057 
00058 
00060         inline u16 RGBA16(u32 r, u32 g, u32 b, u32 a=0xFF)
00061         {
00062                 return (u16)((a & 0x80) << 8 |
00063                         (r & 0xF8) << 7 |
00064                         (g & 0xF8) << 2 |
00065                         (b & 0xF8) >> 3);
00066         }
00067 
00068 
00070         inline u16 RGB16(u32 r, u32 g, u32 b)
00071         {
00072                 return RGBA16(r,g,b);
00073         }
00074 
00075 
00077         inline u16 RGB16from16(u16 r, u16 g, u16 b)
00078         {
00079                 return (0x8000 |
00080                                 (r & 0x1F) << 10 |
00081                                 (g & 0x1F) << 5  |
00082                                 (b & 0x1F));
00083         }
00084 
00085 
00087         inline u16 X8R8G8B8toA1R5G5B5(u32 color)
00088         {
00089                 return (u16)(0x8000 |
00090                         ( color & 0x00F80000) >> 9 |
00091                         ( color & 0x0000F800) >> 6 |
00092                         ( color & 0x000000F8) >> 3);
00093         }
00094 
00095 
00097         inline u16 A8R8G8B8toA1R5G5B5(u32 color)
00098         {
00099                 return (u16)(( color & 0x80000000) >> 16|
00100                         ( color & 0x00F80000) >> 9 |
00101                         ( color & 0x0000F800) >> 6 |
00102                         ( color & 0x000000F8) >> 3);
00103         }
00104 
00105 
00107         inline u16 A8R8G8B8toR5G6B5(u32 color)
00108         {
00109                 return (u16)(( color & 0x00F80000) >> 8 |
00110                         ( color & 0x0000FC00) >> 5 |
00111                         ( color & 0x000000F8) >> 3);
00112         }
00113 
00114 
00116 
00117         inline u32 A1R5G5B5toA8R8G8B8(u16 color)
00118         {
00119                 return ( (( -( (s32) color & 0x00008000 ) >> (s32) 31 ) & 0xFF000000 ) |
00120                                 (( color & 0x00007C00 ) << 9) | (( color & 0x00007000 ) << 4) |
00121                                 (( color & 0x000003E0 ) << 6) | (( color & 0x00000380 ) << 1) |
00122                                 (( color & 0x0000001F ) << 3) | (( color & 0x0000001C ) >> 2)
00123                                 );
00124         }
00125 
00126 
00128         inline u32 R5G6B5toA8R8G8B8(u16 color)
00129         {
00130                 return 0xFF000000 |
00131                         ((color & 0xF800) << 8)|
00132                         ((color & 0x07E0) << 5)|
00133                         ((color & 0x001F) << 3);
00134         }
00135 
00136 
00138         inline u16 R5G6B5toA1R5G5B5(u16 color)
00139         {
00140                 return 0x8000 | (((color & 0xFFC0) >> 1) | (color & 0x1F));
00141         }
00142 
00143 
00145         inline u16 A1R5G5B5toR5G6B5(u16 color)
00146         {
00147                 return (((color & 0x7FE0) << 1) | (color & 0x1F));
00148         }
00149 
00150 
00151 
00153 
00155         inline u32 getAlpha(u16 color)
00156         {
00157                 return ((color >> 15)&0x1);
00158         }
00159 
00160 
00162 
00163         inline u32 getRed(u16 color)
00164         {
00165                 return ((color >> 10)&0x1F);
00166         }
00167 
00168 
00170 
00171         inline u32 getGreen(u16 color)
00172         {
00173                 return ((color >> 5)&0x1F);
00174         }
00175 
00176 
00178 
00179         inline u32 getBlue(u16 color)
00180         {
00181                 return (color & 0x1F);
00182         }
00183 
00184 
00186         inline s32 getAverage(s16 color)
00187         {
00188                 return ((getRed(color)<<3) + (getGreen(color)<<3) + (getBlue(color)<<3)) / 3;
00189         }
00190 
00191 
00193 
00201         class SColor
00202         {
00203         public:
00204 
00206 
00207                 SColor() {}
00208 
00210 
00211                 SColor (u32 a, u32 r, u32 g, u32 b)
00212                         : color(((a & 0xff)<<24) | ((r & 0xff)<<16) | ((g & 0xff)<<8) | (b & 0xff)) {}
00213 
00215                 SColor(u32 clr)
00216                         : color(clr) {}
00217 
00219 
00221                 u32 getAlpha() const { return color>>24; }
00222 
00224 
00226                 u32 getRed() const { return (color>>16) & 0xff; }
00227 
00229 
00231                 u32 getGreen() const { return (color>>8) & 0xff; }
00232 
00234 
00236                 u32 getBlue() const { return color & 0xff; }
00237 
00239                 f32 getLightness() const
00240                 {
00241                         return 0.5f*(core::max_(core::max_(getRed(),getGreen()),getBlue())+core::min_(core::min_(getRed(),getGreen()),getBlue()));
00242                 }
00243 
00245                 f32 getLuminance() const
00246                 {
00247                         return 0.3f*getRed() + 0.59f*getGreen() + 0.11f*getBlue();
00248                 }
00249 
00251                 u32 getAverage() const
00252                 {
00253                         return ( getRed() + getGreen() + getBlue() ) / 3;
00254                 }
00255 
00257 
00259                 void setAlpha(u32 a) { color = ((a & 0xff)<<24) | (color & 0x00ffffff); }
00260 
00262 
00264                 void setRed(u32 r) { color = ((r & 0xff)<<16) | (color & 0xff00ffff); }
00265 
00267 
00269                 void setGreen(u32 g) { color = ((g & 0xff)<<8) | (color & 0xffff00ff); }
00270 
00272 
00274                 void setBlue(u32 b) { color = (b & 0xff) | (color & 0xffffff00); }
00275 
00277 
00278                 u16 toA1R5G5B5() const { return A8R8G8B8toA1R5G5B5(color); }
00279 
00281 
00284                 void toOpenGLColor(u8* dest) const
00285                 {
00286                         *dest =   (u8)getRed();
00287                         *++dest = (u8)getGreen();
00288                         *++dest = (u8)getBlue();
00289                         *++dest = (u8)getAlpha();
00290                 }
00291 
00293 
00307                 void set(u32 a, u32 r, u32 g, u32 b)
00308                 {
00309                         color = (((a & 0xff)<<24) | ((r & 0xff)<<16) | ((g & 0xff)<<8) | (b & 0xff));
00310                 }
00311                 void set(u32 col) { color = col; }
00312 
00314 
00315                 bool operator==(const SColor& other) const { return other.color == color; }
00316 
00318 
00319                 bool operator!=(const SColor& other) const { return other.color != color; }
00320 
00322 
00323                 bool operator<(const SColor& other) const { return (color < other.color); }
00324 
00326 
00328                 SColor operator+(const SColor& other) const
00329                 {
00330                         return SColor(core::min_(getAlpha() + other.getAlpha(), 255u),
00331                                         core::min_(getRed() + other.getRed(), 255u),
00332                                         core::min_(getGreen() + other.getGreen(), 255u),
00333                                         core::min_(getBlue() + other.getBlue(), 255u));
00334                 }
00335 
00337 
00340                 SColor getInterpolated(const SColor &other, f32 d) const
00341                 {
00342                         d = core::clamp(d, 0.f, 1.f);
00343                         const f32 inv = 1.0f - d;
00344                         return SColor((u32)core::round32(other.getAlpha()*inv + getAlpha()*d),
00345                                 (u32)core::round32(other.getRed()*inv + getRed()*d),
00346                                 (u32)core::round32(other.getGreen()*inv + getGreen()*d),
00347                                 (u32)core::round32(other.getBlue()*inv + getBlue()*d));
00348                 }
00349 
00351 
00354                 SColor getInterpolated_quadratic(const SColor& c1, const SColor& c2, f32 d) const
00355                 {
00356                         // this*(1-d)*(1-d) + 2 * c1 * (1-d) + c2 * d * d;
00357                         d = core::clamp(d, 0.f, 1.f);
00358                         const f32 inv = 1.f - d;
00359                         const f32 mul0 = inv * inv;
00360                         const f32 mul1 = 2.f * d * inv;
00361                         const f32 mul2 = d * d;
00362 
00363                         return SColor(
00364                                         core::clamp( core::floor32(
00365                                                         getAlpha() * mul0 + c1.getAlpha() * mul1 + c2.getAlpha() * mul2 ), 0, 255 ),
00366                                         core::clamp( core::floor32(
00367                                                         getRed()   * mul0 + c1.getRed()   * mul1 + c2.getRed()   * mul2 ), 0, 255 ),
00368                                         core::clamp ( core::floor32(
00369                                                         getGreen() * mul0 + c1.getGreen() * mul1 + c2.getGreen() * mul2 ), 0, 255 ),
00370                                         core::clamp ( core::floor32(
00371                                                         getBlue()  * mul0 + c1.getBlue()  * mul1 + c2.getBlue()  * mul2 ), 0, 255 ));
00372                 }
00373 
00375 
00378                 void setData(const void *data, ECOLOR_FORMAT format)
00379                 {
00380                         switch (format)
00381                         {
00382                                 case ECF_A1R5G5B5:
00383                                         color = A1R5G5B5toA8R8G8B8(*(u16*)data);
00384                                         break;
00385                                 case ECF_R5G6B5:
00386                                         color = R5G6B5toA8R8G8B8(*(u16*)data);
00387                                         break;
00388                                 case ECF_A8R8G8B8:
00389                                         color = *(u32*)data;
00390                                         break;
00391                                 case ECF_R8G8B8:
00392                                         {
00393                                                 u8* p = (u8*)data;
00394                                                 set(255, p[0],p[1],p[2]);
00395                                         }
00396                                         break;
00397                                 default:
00398                                 break;
00399                         }
00400                 }
00401 
00403 
00406                 void getData(void *data, ECOLOR_FORMAT format)
00407                 {
00408                         switch(format)
00409                         {
00410                                 case ECF_A1R5G5B5:
00411                                 {
00412                                         u16 * dest = (u16*)data;
00413                                         *dest = video::A8R8G8B8toA1R5G5B5( color );
00414                                 } 
00415                                 break;
00416 
00417                                 case ECF_R5G6B5:
00418                                 {
00419                                         u16 * dest = (u16*)data;
00420                                         *dest = video::A8R8G8B8toR5G6B5( color );
00421                                 } 
00422                                 break;
00423 
00424                                 case ECF_R8G8B8:
00425                                 {
00426                                         u8* dest = (u8*)data;
00427                                         dest[0] = (u8)getRed();
00428                                         dest[1] = (u8)getGreen();
00429                                         dest[2] = (u8)getBlue();
00430                                 } 
00431                                 break;
00432 
00433                                 case ECF_A8R8G8B8:
00434                                 {
00435                                         u32 * dest = (u32*)data;
00436                                         *dest = color;
00437                                 } 
00438                                 break;
00439 
00440                                 default:
00441                                 break;
00442                         }
00443                 }
00444 
00446                 u32 color;
00447         };
00448 
00449 
00451 
00457         class SColorf
00458         {
00459         public:
00461 
00462                 SColorf() : r(0.0f), g(0.0f), b(0.0f), a(1.0f) {}
00463 
00465 
00475                 SColorf(f32 r, f32 g, f32 b, f32 a = 1.0f) : r(r), g(g), b(b), a(a) {}
00476 
00478 
00480                 SColorf(SColor c)
00481                 {
00482                         const f32 inv = 1.0f / 255.0f;
00483                         r = c.getRed() * inv;
00484                         g = c.getGreen() * inv;
00485                         b = c.getBlue() * inv;
00486                         a = c.getAlpha() * inv;
00487                 }
00488 
00490                 SColor toSColor() const
00491                 {
00492                         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));
00493                 }
00494 
00496 
00502                 void set(f32 rr, f32 gg, f32 bb) {r = rr; g =gg; b = bb; }
00503 
00505 
00513                 void set(f32 aa, f32 rr, f32 gg, f32 bb) {a = aa; r = rr; g =gg; b = bb; }
00514 
00516 
00519                 SColorf getInterpolated(const SColorf &other, f32 d) const
00520                 {
00521                         d = core::clamp(d, 0.f, 1.f);
00522                         const f32 inv = 1.0f - d;
00523                         return SColorf(other.r*inv + r*d,
00524                                 other.g*inv + g*d, other.b*inv + b*d, other.a*inv + a*d);
00525                 }
00526 
00528 
00531                 inline SColorf getInterpolated_quadratic(const SColorf& c1, const SColorf& c2,
00532                                 f32 d) const
00533                 {
00534                         d = core::clamp(d, 0.f, 1.f);
00535                         // this*(1-d)*(1-d) + 2 * c1 * (1-d) + c2 * d * d;
00536                         const f32 inv = 1.f - d;
00537                         const f32 mul0 = inv * inv;
00538                         const f32 mul1 = 2.f * d * inv;
00539                         const f32 mul2 = d * d;
00540 
00541                         return SColorf (r * mul0 + c1.r * mul1 + c2.r * mul2,
00542                                         g * mul0 + c1.g * mul1 + c2.g * mul2,
00543                                         b * mul0 + c1.b * mul1 + c2.b * mul2,
00544                                         a * mul0 + c1.a * mul1 + c2.a * mul2);
00545                 }
00546 
00547 
00549                 void setColorComponentValue(s32 index, f32 value)
00550                 {
00551                         switch(index)
00552                         {
00553                         case 0: r = value; break;
00554                         case 1: g = value; break;
00555                         case 2: b = value; break;
00556                         case 3: a = value; break;
00557                         }
00558                 }
00559 
00561                 f32 getAlpha() const { return a; }
00562 
00564                 f32 getRed() const { return r; }
00565 
00567                 f32 getGreen() const { return g; }
00568 
00570                 f32 getBlue() const { return b; }
00571 
00573                 f32 r;
00574 
00576                 f32 g;
00577 
00579                 f32 b;
00580 
00582                 f32 a;
00583         };
00584 
00585 
00587 
00591         class SColorHSL
00592         {
00593         public:
00594                 SColorHSL ( f32 h = 0.f, f32 s = 0.f, f32 l = 0.f )
00595                         : Hue ( h ), Saturation ( s ), Luminance ( l ) {}
00596 
00597                 void fromRGB(const SColorf &color);
00598                 void toRGB(SColorf &color) const;
00599 
00600                 f32 Hue;
00601                 f32 Saturation;
00602                 f32 Luminance;
00603 
00604         private:
00605                 inline f32 toRGB1(f32 rm1, f32 rm2, f32 rh) const;
00606 
00607         };
00608 
00609         inline void SColorHSL::fromRGB(const SColorf &color)
00610         {
00611                 const f32 maxVal = core::max_(color.getRed(), color.getGreen(), color.getBlue());
00612                 const f32 minVal = (f32)core::min_(color.getRed(), color.getGreen(), color.getBlue());
00613                 Luminance = (maxVal+minVal)*50;
00614                 if (core::equals(maxVal, minVal))
00615                 {
00616                         Hue=0.f;
00617                         Saturation=0.f;
00618                         return;
00619                 }
00620 
00621                 const f32 delta = maxVal-minVal;
00622                 if ( Luminance <= 50 )
00623                 {
00624                         Saturation = (delta)/(maxVal+minVal);
00625                 }
00626                 else
00627                 {
00628                         Saturation = (delta)/(2-maxVal-minVal);
00629                 }
00630                 Saturation *= 100;
00631 
00632                 if (core::equals(maxVal, color.getRed()))
00633                         Hue = (color.getGreen()-color.getBlue())/delta;
00634                 else if (core::equals(maxVal, color.getGreen()))
00635                         Hue = 2+((color.getBlue()-color.getRed())/delta);
00636                 else // blue is max
00637                         Hue = 4+((color.getRed()-color.getGreen())/delta);
00638 
00639                 Hue *= 60.0f;
00640                 while ( Hue < 0.f )
00641                         Hue += 360;
00642         }
00643 
00644 
00645         inline void SColorHSL::toRGB(SColorf &color) const
00646         {
00647                 const f32 l = Luminance/100;
00648                 if (core::iszero(Saturation)) // grey
00649                 {
00650                         color.set(l, l, l);
00651                         return;
00652                 }
00653 
00654                 f32 rm2;
00655 
00656                 if ( Luminance <= 50 )
00657                 {
00658                         rm2 = l + l * (Saturation/100);
00659                 }
00660                 else
00661                 {
00662                         rm2 = l + (1 - l) * (Saturation/100);
00663                 }
00664 
00665                 const f32 rm1 = 2.0f * l - rm2;
00666 
00667                 const f32 h = Hue / 360.0f;
00668                 color.set( toRGB1(rm1, rm2, h + 1.f/3.f),
00669                         toRGB1(rm1, rm2, h),
00670                         toRGB1(rm1, rm2, h - 1.f/3.f)
00671                         );
00672         }
00673 
00674 
00675         // algorithm from Foley/Van-Dam
00676         inline f32 SColorHSL::toRGB1(f32 rm1, f32 rm2, f32 rh) const
00677         {
00678                 if (rh<0)
00679                         rh += 1;
00680                 if (rh>1)
00681                         rh -= 1;
00682 
00683                 if (rh < 1.f/6.f)
00684                         rm1 = rm1 + (rm2 - rm1) * rh*6.f;
00685                 else if (rh < 0.5f)
00686                         rm1 = rm2;
00687                 else if (rh < 2.f/3.f)
00688                         rm1 = rm1 + (rm2 - rm1) * ((2.f/3.f)-rh)*6.f;
00689 
00690                 return rm1;
00691         }
00692 
00693 } // end namespace video
00694 } // end namespace irr
00695 
00696 #endif