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