Blender V2.61 - r43446

math_color.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  
00021  * The Original Code is: some of this file.
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  * */
00025 
00031 #include <assert.h>
00032 
00033 #include "MEM_guardedalloc.h"
00034 
00035 #include "BLI_math.h"
00036 #include "BLI_rand.h"
00037 #include "BLI_utildefines.h"
00038 
00039 void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b)
00040 {
00041     int i;
00042     float f, p, q, t;
00043 
00044     if(s==0.0f) {
00045         *r = v;
00046         *g = v;
00047         *b = v;
00048     }
00049     else {
00050         h= (h - floorf(h))*6.0f;
00051 
00052         i = (int)floorf(h);
00053         f = h - i;
00054         p = v*(1.0f-s);
00055         q = v*(1.0f-(s*f));
00056         t = v*(1.0f-(s*(1.0f-f)));
00057         
00058         switch (i) {
00059         case 0 :
00060             *r = v;
00061             *g = t;
00062             *b = p;
00063             break;
00064         case 1 :
00065             *r = q;
00066             *g = v;
00067             *b = p;
00068             break;
00069         case 2 :
00070             *r = p;
00071             *g = v;
00072             *b = t;
00073             break;
00074         case 3 :
00075             *r = p;
00076             *g = q;
00077             *b = v;
00078             break;
00079         case 4 :
00080             *r = t;
00081             *g = p;
00082             *b = v;
00083             break;
00084         case 5 :
00085             *r = v;
00086             *g = p;
00087             *b = q;
00088             break;
00089         }
00090     }
00091 }
00092 
00093 void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv)
00094 {
00095     float y, u, v;
00096     y= 0.299f*r + 0.587f*g + 0.114f*b;
00097     u=-0.147f*r - 0.289f*g + 0.436f*b;
00098     v= 0.615f*r - 0.515f*g - 0.100f*b;
00099     
00100     *ly=y;
00101     *lu=u;
00102     *lv=v;
00103 }
00104 
00105 void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb)
00106 {
00107     float r, g, b;
00108     r=y+1.140f*v;
00109     g=y-0.394f*u - 0.581f*v;
00110     b=y+2.032f*u;
00111     
00112     *lr=r;
00113     *lg=g;
00114     *lb=b;
00115 }
00116 
00117 /* The RGB inputs are supposed gamma corrected and in the range 0 - 1.0f */
00118 /* Output YCC have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
00119 void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr, int colorspace)
00120 {
00121     float sr,sg, sb;
00122     float y = 128.f, cr = 128.f, cb = 128.f;
00123     
00124     sr=255.0f*r;
00125     sg=255.0f*g;
00126     sb=255.0f*b;
00127     
00128     switch (colorspace) {
00129     case BLI_YCC_ITU_BT601 :
00130         y=(0.257f*sr)+(0.504f*sg)+(0.098f*sb)+16.0f;
00131         cb=(-0.148f*sr)-(0.291f*sg)+(0.439f*sb)+128.0f;
00132         cr=(0.439f*sr)-(0.368f*sg)-(0.071f*sb)+128.0f;
00133         break;
00134     case BLI_YCC_ITU_BT709 :
00135         y=(0.183f*sr)+(0.614f*sg)+(0.062f*sb)+16.0f;
00136         cb=(-0.101f*sr)-(0.338f*sg)+(0.439f*sb)+128.0f;
00137         cr=(0.439f*sr)-(0.399f*sg)-(0.040f*sb)+128.0f;
00138         break;
00139     case BLI_YCC_JFIF_0_255 :
00140         y=(0.299f*sr)+(0.587f*sg)+(0.114f*sb);
00141         cb=(-0.16874f*sr)-(0.33126f*sg)+(0.5f*sb)+128.0f;
00142         cr=(0.5f*sr)-(0.41869f*sg)-(0.08131f*sb)+128.0f;
00143         break;
00144     default:
00145         assert(!"invalid colorspace");
00146     }
00147     
00148     *ly=y;
00149     *lcb=cb;
00150     *lcr=cr;
00151 }
00152 
00153 
00154 /* YCC input have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
00155 /* RGB outputs are in the range 0 - 1.0f */
00156 /* FIXME comment above must be wrong because BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009 */
00157 void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb, int colorspace)
00158 {
00159     float r = 128.f, g = 128.f, b = 128.f;
00160     
00161     switch (colorspace) {
00162     case BLI_YCC_ITU_BT601 :
00163         r=1.164f*(y-16.0f)+1.596f*(cr-128.0f);
00164         g=1.164f*(y-16.0f)-0.813f*(cr-128.0f)-0.392f*(cb-128.0f);
00165         b=1.164f*(y-16.0f)+2.017f*(cb-128.0f);
00166         break;
00167     case BLI_YCC_ITU_BT709 :
00168         r=1.164f*(y-16.0f)+1.793f*(cr-128.0f);
00169         g=1.164f*(y-16.0f)-0.534f*(cr-128.0f)-0.213f*(cb-128.0f);
00170         b=1.164f*(y-16.0f)+2.115f*(cb-128.0f);
00171         break;
00172     case BLI_YCC_JFIF_0_255 :
00173         r=y+1.402f*cr - 179.456f;
00174         g=y-0.34414f*cb - 0.71414f*cr + 135.45984f;
00175         b=y+1.772f*cb - 226.816f;
00176         break;
00177     default:
00178         assert(!"invalid colorspace");
00179     }
00180     *lr=r/255.0f;
00181     *lg=g/255.0f;
00182     *lb=b/255.0f;
00183 }
00184 
00185 void hex_to_rgb(char *hexcol, float *r, float *g, float *b)
00186 {
00187     unsigned int ri, gi, bi;
00188 
00189     if (hexcol[0] == '#') hexcol++;
00190 
00191     if (sscanf(hexcol, "%02x%02x%02x", &ri, &gi, &bi)==3) {
00192         *r = ri / 255.0f;
00193         *g = gi / 255.0f;
00194         *b = bi / 255.0f;
00195         CLAMP(*r, 0.0f, 1.0f);
00196         CLAMP(*g, 0.0f, 1.0f);
00197         CLAMP(*b, 0.0f, 1.0f);
00198     }
00199     else {
00200         /* avoid using un-initialized vars */
00201         *r= *g= *b= 0.0f;
00202     }
00203 }
00204 
00205 void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv)
00206 {
00207     float h, s, v;
00208     float cmax, cmin, cdelta;
00209     float rc, gc, bc;
00210 
00211     cmax = r;
00212     cmin = r;
00213     cmax = (g>cmax ? g:cmax);
00214     cmin = (g<cmin ? g:cmin);
00215     cmax = (b>cmax ? b:cmax);
00216     cmin = (b<cmin ? b:cmin);
00217 
00218     v = cmax;       /* value */
00219     if (cmax != 0.0f)
00220         s = (cmax - cmin)/cmax;
00221     else {
00222         s = 0.0f;
00223     }
00224     if (s == 0.0f)
00225         h = -1.0f;
00226     else {
00227         cdelta = cmax-cmin;
00228         rc = (cmax-r)/cdelta;
00229         gc = (cmax-g)/cdelta;
00230         bc = (cmax-b)/cdelta;
00231         if (r==cmax)
00232             h = bc-gc;
00233         else
00234             if (g==cmax)
00235                 h = 2.0f+rc-bc;
00236             else
00237                 h = 4.0f+gc-rc;
00238         h = h*60.0f;
00239         if (h < 0.0f)
00240             h += 360.0f;
00241     }
00242     
00243     *ls = s;
00244     *lh = h / 360.0f;
00245     if(*lh < 0.0f) *lh= 0.0f;
00246     *lv = v;
00247 }
00248 
00249 void rgb_to_hsv_compat(float r, float g, float b, float *lh, float *ls, float *lv)
00250 {
00251     float orig_h= *lh;
00252     float orig_s= *ls;
00253 
00254     rgb_to_hsv(r, g, b, lh, ls, lv);
00255 
00256     if(*lv <= 0.0f) {
00257         *lh= orig_h;
00258         *ls= orig_s;
00259     }
00260     else if (*ls <= 0.0f) {
00261         *lh= orig_h;
00262     }
00263 
00264     if(*lh==0.0f && orig_h >= 1.0f) {
00265         *lh= 1.0f;
00266     }
00267 }
00268 
00269 /*http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html */
00270 
00271 void xyz_to_rgb(float xc, float yc, float zc, float *r, float *g, float *b, int colorspace)
00272 {
00273     switch (colorspace) { 
00274     case BLI_XYZ_SMPTE:
00275         *r = (3.50570f   * xc) + (-1.73964f  * yc) + (-0.544011f * zc);
00276         *g = (-1.06906f  * xc) + (1.97781f   * yc) + (0.0351720f * zc);
00277         *b = (0.0563117f * xc) + (-0.196994f * yc) + (1.05005f   * zc);
00278         break;
00279     case BLI_XYZ_REC709_SRGB:
00280         *r = (3.240476f  * xc) + (-1.537150f * yc) + (-0.498535f * zc);
00281         *g = (-0.969256f * xc) + (1.875992f  * yc) + (0.041556f  * zc);
00282         *b = (0.055648f  * xc) + (-0.204043f * yc) + (1.057311f  * zc);
00283         break;
00284     case BLI_XYZ_CIE:
00285         *r = (2.28783848734076f * xc) + (-0.833367677835217f    * yc) + (-0.454470795871421f    * zc);
00286         *g = (-0.511651380743862f * xc) + (1.42275837632178f * yc) + (0.0888930017552939f * zc);
00287         *b = (0.00572040983140966f  * xc) + (-0.0159068485104036f   * yc) + (1.0101864083734f   * zc);
00288         break;
00289     }
00290 }
00291 
00292 /* we define a 'cpack' here as a (3 byte color code) number that can be expressed like 0xFFAA66 or so.
00293    for that reason it is sensitive for endianness... with this function it works correctly
00294 */
00295 
00296 unsigned int hsv_to_cpack(float h, float s, float v)
00297 {
00298     short r, g, b;
00299     float rf, gf, bf;
00300     unsigned int col;
00301     
00302     hsv_to_rgb(h, s, v, &rf, &gf, &bf);
00303     
00304     r= (short)(rf*255.0f);
00305     g= (short)(gf*255.0f);
00306     b= (short)(bf*255.0f);
00307     
00308     col= ( r + (g*256) + (b*256*256) );
00309     return col;
00310 }
00311 
00312 
00313 unsigned int rgb_to_cpack(float r, float g, float b)
00314 {
00315     int ir, ig, ib;
00316     
00317     ir= (int)floor(255.0f*r);
00318     if(ir<0) ir= 0; else if(ir>255) ir= 255;
00319     ig= (int)floor(255.0f*g);
00320     if(ig<0) ig= 0; else if(ig>255) ig= 255;
00321     ib= (int)floor(255.0f*b);
00322     if(ib<0) ib= 0; else if(ib>255) ib= 255;
00323     
00324     return (ir+ (ig*256) + (ib*256*256));
00325 }
00326 
00327 void cpack_to_rgb(unsigned int col, float *r, float *g, float *b)
00328 {
00329     
00330     *r= (float)((col)&0xFF);
00331     *r /= 255.0f;
00332 
00333     *g= (float)(((col)>>8)&0xFF);
00334     *g /= 255.0f;
00335 
00336     *b= (float)(((col)>>16)&0xFF);
00337     *b /= 255.0f;
00338 }
00339 
00340 void rgb_byte_to_float(const unsigned char in[3], float out[3])
00341 {
00342     out[0]= ((float)in[0]) / 255.0f;
00343     out[1]= ((float)in[1]) / 255.0f;
00344     out[2]= ((float)in[2]) / 255.0f;
00345 }
00346 
00347 void rgb_float_to_byte(const float in[3], unsigned char out[3])
00348 {
00349     int r, g, b;
00350     
00351     r= (int)(in[0] * 255.0f);
00352     g= (int)(in[1] * 255.0f);
00353     b= (int)(in[2] * 255.0f);
00354     
00355     out[0]= (char)((r <= 0)? 0 : (r >= 255)? 255 : r);
00356     out[1]= (char)((g <= 0)? 0 : (g >= 255)? 255 : g);
00357     out[2]= (char)((b <= 0)? 0 : (b >= 255)? 255 : b);
00358 }
00359 
00360 /* ********************************* color transforms ********************************* */
00361 
00362 
00363 void gamma_correct(float *c, float gamma)
00364 {
00365     *c = powf((*c), gamma);
00366 }
00367 
00368 float rec709_to_linearrgb(float c)
00369 {
00370     if (c < 0.081f)
00371         return (c < 0.0f)? 0.0f: c * (1.0f/4.5f);
00372     else
00373         return powf((c + 0.099f)*(1.0f/1.099f), (1.0f/0.45f));
00374 }
00375 
00376 float linearrgb_to_rec709(float c)
00377 {
00378     if (c < 0.018f)
00379         return (c < 0.0f)? 0.0f: c * 4.5f;
00380     else
00381         return 1.099f * powf(c, 0.45f) - 0.099f;
00382 }
00383 
00384 float srgb_to_linearrgb(float c)
00385 {
00386     if (c < 0.04045f)
00387         return (c < 0.0f)? 0.0f: c * (1.0f/12.92f);
00388     else
00389         return powf((c + 0.055f)*(1.0f/1.055f), 2.4f);
00390 }
00391 
00392 float linearrgb_to_srgb(float c)
00393 {
00394     if (c < 0.0031308f)
00395         return (c < 0.0f)? 0.0f: c * 12.92f;
00396     else
00397         return  1.055f * powf(c, 1.0f/2.4f) - 0.055f;
00398 }
00399 
00400 void minmax_rgb(short c[])
00401 {
00402     if(c[0]>255) c[0]=255;
00403     else if(c[0]<0) c[0]=0;
00404     if(c[1]>255) c[1]=255;
00405     else if(c[1]<0) c[1]=0;
00406     if(c[2]>255) c[2]=255;
00407     else if(c[2]<0) c[2]=0;
00408 }
00409 
00410 /*If the requested RGB shade contains a negative weight for
00411   one of the primaries, it lies outside the color gamut 
00412   accessible from the given triple of primaries.  Desaturate
00413   it by adding white, equal quantities of R, G, and B, enough
00414   to make RGB all positive.  The function returns 1 if the
00415   components were modified, zero otherwise.*/
00416 int constrain_rgb(float *r, float *g, float *b)
00417 {
00418     float w;
00419 
00420     /* Amount of white needed is w = - min(0, *r, *g, *b) */
00421 
00422     w = (0 < *r) ? 0 : *r;
00423     w = (w < *g) ? w : *g;
00424     w = (w < *b) ? w : *b;
00425     w = -w;
00426 
00427     /* Add just enough white to make r, g, b all positive. */
00428 
00429     if (w > 0) {
00430         *r += w;  *g += w; *b += w;
00431         return 1;                     /* Color modified to fit RGB gamut */
00432     }
00433 
00434     return 0;                         /* Color within RGB gamut */
00435 }
00436 
00437 float rgb_to_grayscale(const float rgb[3])
00438 {
00439     return 0.3f*rgb[0] + 0.58f*rgb[1] + 0.12f*rgb[2];
00440 }
00441 
00442 unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3])
00443 {
00444     return (76*(unsigned short)rgb[0] + 148*(unsigned short)rgb[1] + 31*(unsigned short)rgb[2]) / 255;
00445 }
00446 
00447 float rgb_to_luma(const float rgb[3])
00448 {
00449     return 0.299f*rgb[0] + 0.587f*rgb[1] + 0.114f*rgb[2];
00450 }
00451 
00452 unsigned char rgb_to_luma_byte(const unsigned char rgb[3])
00453 {
00454     return (76*(unsigned short)rgb[0] + 150*(unsigned short)rgb[1] + 29*(unsigned short)rgb[2]) / 255;
00455 }
00456 
00457 /* ********************************* lift/gamma/gain / ASC-CDL conversion ********************************* */
00458 
00459 void lift_gamma_gain_to_asc_cdl(float *lift, float *gamma, float *gain, float *offset, float *slope, float *power)
00460 {
00461     int c;
00462     for(c=0; c<3; c++) {
00463         offset[c]= lift[c]*gain[c];
00464         slope[c]=  gain[c]*(1.0f-lift[c]);
00465         if(gamma[c] == 0)
00466             power[c]= FLT_MAX;
00467         else
00468             power[c]= 1.0f/gamma[c];
00469     }
00470 }
00471 
00472 /* ******************************************** other ************************************************* */
00473 
00474 /* Applies an hue offset to a float rgb color */
00475 void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset)
00476 {
00477     float hsv[3];
00478     
00479     rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
00480     
00481     hsv[0]+= hue_offset;
00482     if(hsv[0] > 1.0f)       hsv[0] -= 1.0f;
00483     else if(hsv[0] < 0.0f)  hsv[0] += 1.0f;
00484     
00485     hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2);
00486 }
00487 
00488 /* Applies an hue offset to a byte rgb color */
00489 void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset)
00490 {
00491     float rgb_float[3];
00492     
00493     rgb_byte_to_float(rgb, rgb_float);
00494     rgb_float_set_hue_float_offset(rgb_float, hue_offset);
00495     rgb_float_to_byte(rgb_float, rgb);
00496 }
00497 
00498 
00499 /* fast sRGB conversion
00500  * LUT from linear float to 16-bit short
00501  * based on http://mysite.verizon.net/spitzak/conversion/
00502  */
00503 
00504 float BLI_color_from_srgb_table[256];
00505 unsigned short BLI_color_to_srgb_table[0x10000];
00506 
00507 static unsigned short hipart(const float f)
00508 {
00509     union {
00510         float f;
00511         unsigned short us[2];
00512     } tmp;
00513 
00514     tmp.f = f;
00515 
00516 #ifdef __BIG_ENDIAN__
00517     return tmp.us[0];
00518 #else
00519     return tmp.us[1];
00520 #endif
00521 }
00522 
00523 static float index_to_float(const unsigned short i)
00524 {
00525     union {
00526         float f;
00527         unsigned short us[2];
00528     } tmp;
00529 
00530     /* positive and negative zeros, and all gradual underflow, turn into zero: */
00531     if (i<0x80 || (i >= 0x8000 && i < 0x8080)) return 0;
00532     /* All NaN's and infinity turn into the largest possible legal float: */
00533     if (i>=0x7f80 && i<0x8000) return FLT_MAX;
00534     if (i>=0xff80) return -FLT_MAX;
00535 
00536 #ifdef __BIG_ENDIAN__
00537     tmp.us[0] = i;
00538     tmp.us[1] = 0x8000;
00539 #else
00540     tmp.us[0] = 0x8000;
00541     tmp.us[1] = i;
00542 #endif
00543 
00544     return tmp.f;
00545 }
00546 
00547 void BLI_init_srgb_conversion(void)
00548 {
00549     static int initialized= 0;
00550     int i, b;
00551 
00552     if (initialized) return;
00553     initialized = 1;
00554 
00555     /* Fill in the lookup table to convert floats to bytes: */
00556     for (i = 0; i < 0x10000; i++) {
00557         float f = linearrgb_to_srgb(index_to_float(i))*255.0f;
00558         if (f <= 0) BLI_color_to_srgb_table[i] = 0;
00559         else if (f < 255) BLI_color_to_srgb_table[i] = (unsigned short)(f*0x100+.5);
00560         else BLI_color_to_srgb_table[i] = 0xff00;
00561     }
00562 
00563     /* Fill in the lookup table to convert bytes to float: */
00564     for (b = 0; b <= 255; b++) {
00565         float f = srgb_to_linearrgb(((float)b)*(1.0f/255.0f));
00566         BLI_color_from_srgb_table[b] = f;
00567         i = hipart(f);
00568         /* replace entries so byte->float->byte does not change the data: */
00569         BLI_color_to_srgb_table[i] = b*0x100;
00570     }
00571 }
00572