nux-1.14.0
|
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 }