nux-1.14.0
Color.cpp
00001 /*
00002  * Copyright 2010 Inalogic® Inc.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License, as
00006  * published by the  Free Software Foundation; either version 2.1 or 3.0
00007  * of the License.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranties of
00011  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00012  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00013  * License for more details.
00014  *
00015  * You should have received a copy of both the GNU Lesser General Public
00016  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00017  *
00018  * Authored by: Jay Taoko <jaytaoko@inalogic.com>
00019  *
00020  */
00021 
00022 #include "Color.h"
00023 
00024 #include <cmath>
00025 #include <cstdlib>
00026 #include <algorithm>
00027 
00028 
00029 #define NUX_RGBA_GET_ALPHA(rgba)      ((rgba) >> 24)
00030 #define NUX_RGBA_GET_RED(rgba)        (((rgba) >> 16) & 0xff)
00031 #define NUX_RGBA_GET_GREEN(rgba)      (((rgba) >> 8) & 0xff)
00032 #define NUX_RGBA_GET_BLUE(rgba)       ((rgba) & 0xff)
00033 
00034 namespace nux
00035 {
00036 namespace color
00037 {
00038 
00039   Color::Color()
00040     : red(0)
00041     , green(0)
00042     , blue(0)
00043     , alpha(1)
00044   {
00045   }
00046 
00047 Color::Color(RedGreenBlue const& rgb, float a)
00048     : red(rgb.red)
00049     , green(rgb.green)
00050     , blue(rgb.blue)
00051     , alpha(a)
00052 {}
00053 
00054   Color::Color (unsigned int c)
00055     : red(NUX_RGBA_GET_RED(c) / 255.f)
00056     , green(NUX_RGBA_GET_GREEN(c) / 255.f)
00057     , blue(NUX_RGBA_GET_BLUE(c) / 255.f)
00058     , alpha(NUX_RGBA_GET_ALPHA(c) / 255.f)
00059   {
00060   }
00061 
00062   Color::Color(int r, int g, int b)
00063     : red(r / 255.f)
00064     , green(g / 255.f)
00065     , blue(b / 255.f)
00066     , alpha(1)
00067   {
00068   }
00069 
00070   Color::Color (float r, float g, float b, float a)
00071     : red(r)
00072     , green(g)
00073     , blue(b)
00074     , alpha(a)
00075   {
00076   }
00077 
00078 bool operator == (const Color &lhs, const Color &rhs)
00079 {
00080   return (lhs.red == rhs.red &&
00081           lhs.green == rhs.green &&
00082           lhs.blue == rhs.blue &&
00083           lhs.alpha == rhs.alpha);
00084 }
00085 
00086 bool operator != (const Color &lhs, const Color &rhs)
00087 {
00088   return !(lhs == rhs);
00089 }
00090 
00091 Color ClampVal(Color const& c)
00092 {
00093   return Color(std::max(0.0f, std::min(1.0f, c.red)),
00094                std::max(0.0f, std::min(1.0f, c.green)),
00095                std::max(0.0f, std::min(1.0f, c.blue)),
00096                std::max(0.0f, std::min(1.0f, c.alpha)));
00097 }
00098 
00099 Color Luminance(Color const& c)
00100 {
00101   float L = 0.30f * c.red + 0.59f * c.green + 0.11f * c.blue;
00102   return Color(L, L, L);
00103 }
00104 
00105 Color OneMinusLuminance(Color const& c)
00106 {
00107   float L = 1.0f - (0.30f * c.red + 0.59f * c.green + 0.11f * c.blue);
00108   return Color(L, L, L);
00109 }
00110 
00111 Color RandomColor()
00112 {
00113   return Color(RandomColorINT());
00114 }
00115 
00116 Color MakeOpaque(Color const& c)
00117 {
00118   return Color(c.red, c.green, c.blue, 1.0f);
00119 }
00120 
00121 unsigned int RandomColorINT()
00122 {
00123   // std::rand isn't defined to be more random than 2^15, so we need
00124   // to generate the full unsigned in chunks.
00125   return (((std::rand() % 255) << 24) |
00126           ((std::rand() % 255) << 16) |
00127           ((std::rand() % 255) << 8) |
00128           (std::rand() % 255));
00129 }
00130 
00131 Color operator + (Color const& lhs, Color const& rhs)
00132 {
00133   return Color(lhs.red + rhs.red,
00134                lhs.green + rhs.green,
00135                lhs.blue + rhs.blue,
00136                lhs.alpha + rhs.alpha);
00137 }
00138 
00139 Color operator - (Color const& lhs, Color const& rhs)
00140 {
00141   return Color(lhs.red - rhs.red,
00142                lhs.green - rhs.green,
00143                lhs.blue - rhs.blue,
00144                lhs.alpha - rhs.alpha);
00145 }
00146 
00147 Color operator + (float scalar, Color const& c)
00148 {
00149   return Color(c.red + scalar,
00150                c.green + scalar,
00151                c.blue + scalar,
00152                c.alpha + scalar);
00153 }
00154 
00155 Color operator + (Color const& c, float scalar)
00156 {
00157   return scalar + c;
00158 }
00159 
00160 Color operator - (float scalar, Color const& c)
00161 {
00162   return Color(scalar - c.red,
00163                scalar - c.green,
00164                scalar - c.blue,
00165                scalar - c.alpha);
00166 }
00167 
00168 
00169 Color operator - (Color const& c, float scalar)
00170 {
00171   return Color(c.red - scalar,
00172                c.green - scalar,
00173                c.blue - scalar,
00174                c.alpha - scalar);
00175 }
00176 
00177 Color operator * (float scalar, Color const& c)
00178 {
00179   return Color(c.red * scalar,
00180                c.green * scalar,
00181                c.blue * scalar,
00182                c.alpha * scalar);
00183 }
00184 
00185 Color operator * (Color const& c, float scalar)
00186 {
00187   return scalar * c;
00188 }
00189 
00190 // The Hue/Saturation/Value model was created by A. R. Smith in 1978. It is
00191 // based on such intuitive color characteristics as tint, shade and tone (or
00192 // family, purety and intensity). The coordinate system is cylindrical, and
00193 // the colors are defined inside a hexcone.  The hue value H runs from 0 to
00194 // 360º. The saturation S is the degree of strength or purity and is from 0 to
00195 // 1. Purity is how much white is added to the color, so S=1 makes the purest
00196 // color (no white). Brightness V also ranges from 0 to 1, where 0 is the
00197 // black.  There is no transformation matrix for RGB/HSV conversion, but the
00198 // algorithm follows:
00199 
00200 // r,g,b values are from 0 to 1
00201 // h = [0,360], s = [0,1], v = [0,1]
00202 //              if s == 0, then h = -1 (undefined)
00203 
00204   void RGBtoHSV ( float r, float g, float b, float &h, float &s, float &v )
00205   {
00206     float min, max, delta;
00207 
00208     min = std::min(std::min(r, g), b);
00209     max = std::max(std::max(r, g), b);
00210     v = max;                            // v
00211 
00212     delta = max - min;
00213 
00214 
00215     if ( max != 0 )
00216     {
00217       s = delta / max;          // s
00218     }
00219     else
00220     {
00221       // MAX = 0 (i.e. if v = 0), then s is undefined.  r = g = b = 0
00222       s = 0;
00223       h = -1;
00224       return;
00225     }
00226 
00227     if (delta == 0) // MAX = MIN (i.e. s = 0), then h is undefined. r = g = b
00228     {
00229       h = 0;
00230       s = 0;
00231       return;
00232     }
00233 
00234     if ( r == max )
00235       h = ( g - b ) / delta;            // between yellow & magenta
00236     else if ( g == max )
00237       h = 2 + ( b - r ) / delta;        // between cyan & yellow
00238     else
00239       h = 4 + ( r - g ) / delta;        // between magenta & cyan
00240 
00241     h *= 60;                            // degrees
00242 
00243     if ( h < 0 )
00244       h += 360;
00245 
00246     // convert h from [0, 360] to [0, 1]
00247     h = (h) / 360.0f;
00248 
00249   }
00250 
00251   void HSVtoRGB ( float &r, float &g, float &b, float h, float s, float v )
00252   {
00253     int i;
00254     float f, p, q, t;
00255 
00256     // convert h from [0, 1] to [0, 360]
00257     h = h * 360.0f;
00258 
00259     if ( s == 0 )
00260     {
00261       // achromatic (grey)
00262       r = g = b = v;
00263       return;
00264     }
00265 
00266     h /= 60;                    // sector 0 to 5
00267     i = (int) std::floor ( h );
00268     f = h - i;                  // factorial part of h
00269     p = v * ( 1 - s );
00270     q = v * ( 1 - s * f );
00271     t = v * ( 1 - s * ( 1 - f ) );
00272 
00273     switch ( i )
00274     {
00275       case 0:
00276         r = v;
00277         g = t;
00278         b = p;
00279         break;
00280       case 1:
00281         r = q;
00282         g = v;
00283         b = p;
00284         break;
00285       case 2:
00286         r = p;
00287         g = v;
00288         b = t;
00289         break;
00290       case 3:
00291         r = p;
00292         g = q;
00293         b = v;
00294         break;
00295       case 4:
00296         r = t;
00297         g = p;
00298         b = v;
00299         break;
00300       default:          // case 5:
00301         r = v;
00302         g = p;
00303         b = q;
00304         break;
00305     }
00306   }
00307 
00309 // HLS-RGB Conversions //
00311 
00312   float HLStoRGB1 (float rn1, float rn2, float huei)
00313   {
00314     // Static method. Auxiliary to HLS2RGB().
00315 
00316     float hue = huei;
00317 
00318     if (hue > 360) hue = hue - 360;
00319 
00320     if (hue < 0)   hue = hue + 360;
00321 
00322     if (hue < 60 ) return rn1 + (rn2 - rn1) * hue / 60;
00323 
00324     if (hue < 180) return rn2;
00325 
00326     if (hue < 240) return rn1 + (rn2 - rn1) * (240 - hue) / 60;
00327 
00328     return rn1;
00329   }
00330 
00331   void HLStoRGB (float &r, float &g, float &b, float hue, float light, float satur)
00332   {
00333     // Static method to compute RGB from HLS. The l and s are between [0,1]
00334     // and h is between [0, 1]. The returned r,g,b triplet is between [0,1].
00335     hue *= 360.0f;
00336 
00337     float rh, rl, rs, rm1, rm2;
00338     rh = rl = rs = 0;
00339 
00340     if (hue   > 0) rh = hue;
00341 
00342     if (rh > 360) rh = 360;
00343 
00344     if (light > 0) rl = light;
00345 
00346     if (rl > 1)   rl = 1;
00347 
00348     if (satur > 0) rs = satur;
00349 
00350     if (rs > 1)   rs = 1;
00351 
00352     if (rl <= 0.5f)
00353       rm2 = rl * (1.0f + rs);
00354     else
00355       rm2 = rl + rs - rl * rs;
00356 
00357     rm1 = 2.0f * rl - rm2;
00358 
00359     if (!rs)
00360     {
00361       r = rl;
00362       g = rl;
00363       b = rl;
00364       return;
00365     }
00366 
00367     r = HLStoRGB1 (rm1, rm2, rh + 120);
00368     g = HLStoRGB1 (rm1, rm2, rh);
00369     b = HLStoRGB1 (rm1, rm2, rh - 120);
00370   }
00371 
00372   void HLStoRGBi (int h, int l, int s, int &r, int &g, int &b)
00373   {
00374     // Static method to compute RGB from HLS. The h,l,s are between [0,255].
00375     // The returned r,g,b triplet is between [0,255].
00376 
00377     float hh, ll, ss;
00378     float rr, gg, bb;
00379     hh = ll = ss = 0;
00380     rr = gg = bb = 0;
00381 
00382     hh = float (h) * 360 / 255;
00383     ll = float (l) / 255;
00384     ss = float (s) / 255;
00385 
00386     HLStoRGB (hh, ll, ss, rr, gg, bb);
00387 
00388     r = (int) (rr * 255);
00389     g = (int) (gg * 255);
00390     b = (int) (bb * 255);
00391   }
00392 
00393   void RGBtoHLS (float rr, float gg, float bb,
00394                  float &hue, float &light, float &satur)
00395   {
00396     // Static method to compute HLS from RGB. The r,g,b triplet is between
00397     // [0,1], hue is between [0,1], light and satur are [0,1].
00398 
00399     float rnorm, gnorm, bnorm, minval, maxval, msum, mdiff, r, g, b;
00400     r = g = b = 0;
00401 
00402     if (rr > 0) r = rr;
00403 
00404     if (r > 1) r = 1;
00405 
00406     if (gg > 0) g = gg;
00407 
00408     if (g > 1) g = 1;
00409 
00410     if (bb > 0) b = bb;
00411 
00412     if (b > 1) b = 1;
00413 
00414     minval = r;
00415 
00416     if (g < minval) minval = g;
00417 
00418     if (b < minval) minval = b;
00419 
00420     maxval = r;
00421 
00422     if (g > maxval) maxval = g;
00423 
00424     if (b > maxval) maxval = b;
00425 
00426     rnorm = gnorm = bnorm = 0;
00427     mdiff = maxval - minval;
00428     msum  = maxval + minval;
00429     light = 0.5f * msum;
00430 
00431     if (maxval != minval)
00432     {
00433       rnorm = (maxval - r) / mdiff;
00434       gnorm = (maxval - g) / mdiff;
00435       bnorm = (maxval - b) / mdiff;
00436     }
00437     else
00438     {
00439       satur = hue = 0;
00440       return;
00441     }
00442 
00443     if (light < 0.5f)
00444       satur = mdiff / msum;
00445     else
00446       satur = mdiff / (2.0f - msum);
00447 
00448     if (r == maxval)
00449       hue = 60.0f * (6.0f + bnorm - gnorm);
00450     else if (g == maxval)
00451       hue = 60.0f * (2.0f + rnorm - bnorm);
00452     else
00453       hue = 60.0f * (4.0f + gnorm - rnorm);
00454 
00455     if (hue > 360)
00456       hue = hue - 360;
00457 
00458     hue = hue / 360.0f;
00459   }
00460 
00461 
00462   void RGBtoHLSi (int r, int g, int b, int &h, int &l, int &s)
00463   {
00464     // Static method to compute HLS from RGB. The r,g,b triplet is between
00465     // [0,255], hue, light and satur are between [0,255].
00466 
00467     float rr, gg, bb, hue, light, satur;
00468 
00469     rr = float (r) / 255;
00470     gg = float (g) / 255;
00471     bb = float (b) / 255;
00472 
00473     RGBtoHLS (rr, gg, bb, hue, light, satur);
00474 
00475     h = (int) (hue / 360 * 255);
00476     l = (int) (light * 255);
00477     s = (int) (satur * 255);
00478   }
00479 
00480 
00481 RedGreenBlue::RedGreenBlue(float r, float g, float b)
00482   : red(r)
00483   , green(g)
00484   , blue(b)
00485 {}
00486 
00487 RedGreenBlue::RedGreenBlue(HueSaturationValue const& hsv)
00488 {
00489   HSVtoRGB(red, green, blue, hsv.hue, hsv.saturation, hsv.value);
00490 }
00491 
00492 RedGreenBlue::RedGreenBlue(HueLightnessSaturation const& hls)
00493 {
00494   HLStoRGB(red, green, blue, hls.hue, hls.lightness, hls.saturation);
00495 }
00496 
00497 HueSaturationValue::HueSaturationValue(float h, float s, float v)
00498   : hue(h)
00499   , saturation(s)
00500   , value(v)
00501 {}
00502 
00503 HueSaturationValue::HueSaturationValue(RedGreenBlue const& rgb)
00504 {
00505   RGBtoHSV(rgb.red, rgb.green, rgb.blue, hue, saturation, value);
00506 }
00507 
00508 HueSaturationValue::HueSaturationValue(Color const& c)
00509 {
00510   RGBtoHSV(c.red, c.green, c.blue, hue, saturation, value);
00511 }
00512 
00513 HueLightnessSaturation::HueLightnessSaturation(float h, float l, float s)
00514   : hue(h)
00515   , lightness(l)
00516   , saturation(s)
00517 {}
00518 
00519 HueLightnessSaturation::HueLightnessSaturation(RedGreenBlue const& rgb)
00520 {
00521   RGBtoHLS(rgb.red, rgb.green, rgb.blue, hue, lightness, saturation);
00522 }
00523 
00524 HueLightnessSaturation::HueLightnessSaturation(Color const& c)
00525 {
00526   RGBtoHLS(c.red, c.green, c.blue, hue, lightness, saturation);
00527 }
00528 
00529 
00530 }
00531 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends