|
IrrlichtEngine
|
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