Irrlicht 3D Engine
SColor.h
Go to the documentation of this file.
00001 // Copyright (C) 2002-2012 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                     color = 0xffffffff;
00399                 break;
00400             }
00401         }
00402 
00404 
00407         void getData(void *data, ECOLOR_FORMAT format)
00408         {
00409             switch(format)
00410             {
00411                 case ECF_A1R5G5B5:
00412                 {
00413                     u16 * dest = (u16*)data;
00414                     *dest = video::A8R8G8B8toA1R5G5B5( color );
00415                 } 
00416                 break;
00417 
00418                 case ECF_R5G6B5:
00419                 {
00420                     u16 * dest = (u16*)data;
00421                     *dest = video::A8R8G8B8toR5G6B5( color );
00422                 } 
00423                 break;
00424 
00425                 case ECF_R8G8B8:
00426                 {
00427                     u8* dest = (u8*)data;
00428                     dest[0] = (u8)getRed();
00429                     dest[1] = (u8)getGreen();
00430                     dest[2] = (u8)getBlue();
00431                 } 
00432                 break;
00433 
00434                 case ECF_A8R8G8B8:
00435                 {
00436                     u32 * dest = (u32*)data;
00437                     *dest = color;
00438                 } 
00439                 break;
00440 
00441                 default:
00442                 break;
00443             }
00444         }
00445 
00447         u32 color;
00448     };
00449 
00450 
00452 
00458     class SColorf
00459     {
00460     public:
00462 
00463         SColorf() : r(0.0f), g(0.0f), b(0.0f), a(1.0f) {}
00464 
00466 
00476         SColorf(f32 r, f32 g, f32 b, f32 a = 1.0f) : r(r), g(g), b(b), a(a) {}
00477 
00479 
00481         SColorf(SColor c)
00482         {
00483             const f32 inv = 1.0f / 255.0f;
00484             r = c.getRed() * inv;
00485             g = c.getGreen() * inv;
00486             b = c.getBlue() * inv;
00487             a = c.getAlpha() * inv;
00488         }
00489 
00491         SColor toSColor() const
00492         {
00493             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));
00494         }
00495 
00497 
00503         void set(f32 rr, f32 gg, f32 bb) {r = rr; g =gg; b = bb; }
00504 
00506 
00514         void set(f32 aa, f32 rr, f32 gg, f32 bb) {a = aa; r = rr; g =gg; b = bb; }
00515 
00517 
00520         SColorf getInterpolated(const SColorf &other, f32 d) const
00521         {
00522             d = core::clamp(d, 0.f, 1.f);
00523             const f32 inv = 1.0f - d;
00524             return SColorf(other.r*inv + r*d,
00525                 other.g*inv + g*d, other.b*inv + b*d, other.a*inv + a*d);
00526         }
00527 
00529 
00532         inline SColorf getInterpolated_quadratic(const SColorf& c1, const SColorf& c2,
00533                 f32 d) const
00534         {
00535             d = core::clamp(d, 0.f, 1.f);
00536             // this*(1-d)*(1-d) + 2 * c1 * (1-d) + c2 * d * d;
00537             const f32 inv = 1.f - d;
00538             const f32 mul0 = inv * inv;
00539             const f32 mul1 = 2.f * d * inv;
00540             const f32 mul2 = d * d;
00541 
00542             return SColorf (r * mul0 + c1.r * mul1 + c2.r * mul2,
00543                     g * mul0 + c1.g * mul1 + c2.g * mul2,
00544                     b * mul0 + c1.b * mul1 + c2.b * mul2,
00545                     a * mul0 + c1.a * mul1 + c2.a * mul2);
00546         }
00547 
00548 
00550         void setColorComponentValue(s32 index, f32 value)
00551         {
00552             switch(index)
00553             {
00554             case 0: r = value; break;
00555             case 1: g = value; break;
00556             case 2: b = value; break;
00557             case 3: a = value; break;
00558             }
00559         }
00560 
00562         f32 getAlpha() const { return a; }
00563 
00565         f32 getRed() const { return r; }
00566 
00568         f32 getGreen() const { return g; }
00569 
00571         f32 getBlue() const { return b; }
00572 
00574         f32 r;
00575 
00577         f32 g;
00578 
00580         f32 b;
00581 
00583         f32 a;
00584     };
00585 
00586 
00588 
00592     class SColorHSL
00593     {
00594     public:
00595         SColorHSL ( f32 h = 0.f, f32 s = 0.f, f32 l = 0.f )
00596             : Hue ( h ), Saturation ( s ), Luminance ( l ) {}
00597 
00598         void fromRGB(const SColorf &color);
00599         void toRGB(SColorf &color) const;
00600 
00601         f32 Hue;
00602         f32 Saturation;
00603         f32 Luminance;
00604 
00605     private:
00606         inline f32 toRGB1(f32 rm1, f32 rm2, f32 rh) const;
00607 
00608     };
00609 
00610     inline void SColorHSL::fromRGB(const SColorf &color)
00611     {
00612         const f32 maxVal = core::max_(color.getRed(), color.getGreen(), color.getBlue());
00613         const f32 minVal = (f32)core::min_(color.getRed(), color.getGreen(), color.getBlue());
00614         Luminance = (maxVal+minVal)*50;
00615         if (core::equals(maxVal, minVal))
00616         {
00617             Hue=0.f;
00618             Saturation=0.f;
00619             return;
00620         }
00621 
00622         const f32 delta = maxVal-minVal;
00623         if ( Luminance <= 50 )
00624         {
00625             Saturation = (delta)/(maxVal+minVal);
00626         }
00627         else
00628         {
00629             Saturation = (delta)/(2-maxVal-minVal);
00630         }
00631         Saturation *= 100;
00632 
00633         if (core::equals(maxVal, color.getRed()))
00634             Hue = (color.getGreen()-color.getBlue())/delta;
00635         else if (core::equals(maxVal, color.getGreen()))
00636             Hue = 2+((color.getBlue()-color.getRed())/delta);
00637         else // blue is max
00638             Hue = 4+((color.getRed()-color.getGreen())/delta);
00639 
00640         Hue *= 60.0f;
00641         while ( Hue < 0.f )
00642             Hue += 360;
00643     }
00644 
00645 
00646     inline void SColorHSL::toRGB(SColorf &color) const
00647     {
00648         const f32 l = Luminance/100;
00649         if (core::iszero(Saturation)) // grey
00650         {
00651             color.set(l, l, l);
00652             return;
00653         }
00654 
00655         f32 rm2;
00656 
00657         if ( Luminance <= 50 )
00658         {
00659             rm2 = l + l * (Saturation/100);
00660         }
00661         else
00662         {
00663             rm2 = l + (1 - l) * (Saturation/100);
00664         }
00665 
00666         const f32 rm1 = 2.0f * l - rm2;
00667 
00668         const f32 h = Hue / 360.0f;
00669         color.set( toRGB1(rm1, rm2, h + 1.f/3.f),
00670             toRGB1(rm1, rm2, h),
00671             toRGB1(rm1, rm2, h - 1.f/3.f)
00672             );
00673     }
00674 
00675 
00676     // algorithm from Foley/Van-Dam
00677     inline f32 SColorHSL::toRGB1(f32 rm1, f32 rm2, f32 rh) const
00678     {
00679         if (rh<0)
00680             rh += 1;
00681         if (rh>1)
00682             rh -= 1;
00683 
00684         if (rh < 1.f/6.f)
00685             rm1 = rm1 + (rm2 - rm1) * rh*6.f;
00686         else if (rh < 0.5f)
00687             rm1 = rm2;
00688         else if (rh < 2.f/3.f)
00689             rm1 = rm1 + (rm2 - rm1) * ((2.f/3.f)-rh)*6.f;
00690 
00691         return rm1;
00692     }
00693 
00694 } // end namespace video
00695 } // end namespace irr
00696 
00697 #endif