svn merge ^/trunk/blender -r42920:42927
[blender.git] / source / blender / blenlib / intern / math_color.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  
21  * The Original Code is: some of this file.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  * */
25
26 /** \file blender/blenlib/intern/math_color.c
27  *  \ingroup bli
28  */
29
30
31 #include <assert.h>
32
33 #include "BLI_math.h"
34
35 void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b)
36 {
37         int i;
38         float f, p, q, t;
39
40         if(s==0.0f) {
41                 *r = v;
42                 *g = v;
43                 *b = v;
44         }
45         else {
46                 h= (h - floorf(h))*6.0f;
47
48                 i = (int)floorf(h);
49                 f = h - i;
50                 p = v*(1.0f-s);
51                 q = v*(1.0f-(s*f));
52                 t = v*(1.0f-(s*(1.0f-f)));
53                 
54                 switch (i) {
55                 case 0 :
56                         *r = v;
57                         *g = t;
58                         *b = p;
59                         break;
60                 case 1 :
61                         *r = q;
62                         *g = v;
63                         *b = p;
64                         break;
65                 case 2 :
66                         *r = p;
67                         *g = v;
68                         *b = t;
69                         break;
70                 case 3 :
71                         *r = p;
72                         *g = q;
73                         *b = v;
74                         break;
75                 case 4 :
76                         *r = t;
77                         *g = p;
78                         *b = v;
79                         break;
80                 case 5 :
81                         *r = v;
82                         *g = p;
83                         *b = q;
84                         break;
85                 }
86         }
87 }
88
89 void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv)
90 {
91         float y, u, v;
92         y= 0.299f*r + 0.587f*g + 0.114f*b;
93         u=-0.147f*r - 0.289f*g + 0.436f*b;
94         v= 0.615f*r - 0.515f*g - 0.100f*b;
95         
96         *ly=y;
97         *lu=u;
98         *lv=v;
99 }
100
101 void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb)
102 {
103         float r, g, b;
104         r=y+1.140f*v;
105         g=y-0.394f*u - 0.581f*v;
106         b=y+2.032f*u;
107         
108         *lr=r;
109         *lg=g;
110         *lb=b;
111 }
112
113 /* The RGB inputs are supposed gamma corrected and in the range 0 - 1.0f */
114 /* Output YCC have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
115 void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr, int colorspace)
116 {
117         float sr,sg, sb;
118         float y = 128.f, cr = 128.f, cb = 128.f;
119         
120         sr=255.0f*r;
121         sg=255.0f*g;
122         sb=255.0f*b;
123         
124         switch (colorspace) {
125         case BLI_YCC_ITU_BT601 :
126                 y=(0.257f*sr)+(0.504f*sg)+(0.098f*sb)+16.0f;
127                 cb=(-0.148f*sr)-(0.291f*sg)+(0.439f*sb)+128.0f;
128                 cr=(0.439f*sr)-(0.368f*sg)-(0.071f*sb)+128.0f;
129                 break;
130         case BLI_YCC_ITU_BT709 :
131                 y=(0.183f*sr)+(0.614f*sg)+(0.062f*sb)+16.0f;
132                 cb=(-0.101f*sr)-(0.338f*sg)+(0.439f*sb)+128.0f;
133                 cr=(0.439f*sr)-(0.399f*sg)-(0.040f*sb)+128.0f;
134                 break;
135         case BLI_YCC_JFIF_0_255 :
136                 y=(0.299f*sr)+(0.587f*sg)+(0.114f*sb);
137                 cb=(-0.16874f*sr)-(0.33126f*sg)+(0.5f*sb)+128.0f;
138                 cr=(0.5f*sr)-(0.41869f*sg)-(0.08131f*sb)+128.0f;
139                 break;
140         default:
141                 assert(!"invalid colorspace");
142         }
143         
144         *ly=y;
145         *lcb=cb;
146         *lcr=cr;
147 }
148
149
150 /* YCC input have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
151 /* RGB outputs are in the range 0 - 1.0f */
152 /* FIXME comment above must be wrong because BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009 */
153 void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb, int colorspace)
154 {
155         float r = 128.f, g = 128.f, b = 128.f;
156         
157         switch (colorspace) {
158         case BLI_YCC_ITU_BT601 :
159                 r=1.164f*(y-16.0f)+1.596f*(cr-128.0f);
160                 g=1.164f*(y-16.0f)-0.813f*(cr-128.0f)-0.392f*(cb-128.0f);
161                 b=1.164f*(y-16.0f)+2.017f*(cb-128.0f);
162                 break;
163         case BLI_YCC_ITU_BT709 :
164                 r=1.164f*(y-16.0f)+1.793f*(cr-128.0f);
165                 g=1.164f*(y-16.0f)-0.534f*(cr-128.0f)-0.213f*(cb-128.0f);
166                 b=1.164f*(y-16.0f)+2.115f*(cb-128.0f);
167                 break;
168         case BLI_YCC_JFIF_0_255 :
169                 r=y+1.402f*cr - 179.456f;
170                 g=y-0.34414f*cb - 0.71414f*cr + 135.45984f;
171                 b=y+1.772f*cb - 226.816f;
172                 break;
173         default:
174                 assert(!"invalid colorspace");
175         }
176         *lr=r/255.0f;
177         *lg=g/255.0f;
178         *lb=b/255.0f;
179 }
180
181 void hex_to_rgb(char *hexcol, float *r, float *g, float *b)
182 {
183         unsigned int ri, gi, bi;
184
185         if (hexcol[0] == '#') hexcol++;
186
187         if (sscanf(hexcol, "%02x%02x%02x", &ri, &gi, &bi)==3) {
188                 *r = ri / 255.0f;
189                 *g = gi / 255.0f;
190                 *b = bi / 255.0f;
191                 CLAMP(*r, 0.0f, 1.0f);
192                 CLAMP(*g, 0.0f, 1.0f);
193                 CLAMP(*b, 0.0f, 1.0f);
194         }
195         else {
196                 /* avoid using un-initialized vars */
197                 *r= *g= *b= 0.0f;
198         }
199 }
200
201 void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv)
202 {
203         float h, s, v;
204         float cmax, cmin, cdelta;
205         float rc, gc, bc;
206
207         cmax = r;
208         cmin = r;
209         cmax = (g>cmax ? g:cmax);
210         cmin = (g<cmin ? g:cmin);
211         cmax = (b>cmax ? b:cmax);
212         cmin = (b<cmin ? b:cmin);
213
214         v = cmax;               /* value */
215         if (cmax != 0.0f)
216                 s = (cmax - cmin)/cmax;
217         else {
218                 s = 0.0f;
219         }
220         if (s == 0.0f)
221                 h = -1.0f;
222         else {
223                 cdelta = cmax-cmin;
224                 rc = (cmax-r)/cdelta;
225                 gc = (cmax-g)/cdelta;
226                 bc = (cmax-b)/cdelta;
227                 if (r==cmax)
228                         h = bc-gc;
229                 else
230                         if (g==cmax)
231                                 h = 2.0f+rc-bc;
232                         else
233                                 h = 4.0f+gc-rc;
234                 h = h*60.0f;
235                 if (h < 0.0f)
236                         h += 360.0f;
237         }
238         
239         *ls = s;
240         *lh = h / 360.0f;
241         if(*lh < 0.0f) *lh= 0.0f;
242         *lv = v;
243 }
244
245 void rgb_to_hsv_compat(float r, float g, float b, float *lh, float *ls, float *lv)
246 {
247         float orig_h= *lh;
248         float orig_s= *ls;
249
250         rgb_to_hsv(r, g, b, lh, ls, lv);
251
252         if(*lv <= 0.0f) {
253                 *lh= orig_h;
254                 *ls= orig_s;
255         }
256         else if (*ls <= 0.0f) {
257                 *lh= orig_h;
258         }
259
260         if(*lh==0.0f && orig_h >= 1.0f) {
261                 *lh= 1.0f;
262         }
263 }
264
265 /*http://brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html */
266
267 void xyz_to_rgb(float xc, float yc, float zc, float *r, float *g, float *b, int colorspace)
268 {
269         switch (colorspace) { 
270         case BLI_XYZ_SMPTE:
271                 *r = (3.50570f   * xc) + (-1.73964f      * yc) + (-0.544011f * zc);
272                 *g = (-1.06906f  * xc) + (1.97781f       * yc) + (0.0351720f * zc);
273                 *b = (0.0563117f * xc) + (-0.196994f * yc) + (1.05005f   * zc);
274                 break;
275         case BLI_XYZ_REC709_SRGB:
276                 *r = (3.240476f  * xc) + (-1.537150f * yc) + (-0.498535f * zc);
277                 *g = (-0.969256f * xc) + (1.875992f  * yc) + (0.041556f  * zc);
278                 *b = (0.055648f  * xc) + (-0.204043f * yc) + (1.057311f  * zc);
279                 break;
280         case BLI_XYZ_CIE:
281                 *r = (2.28783848734076f * xc) + (-0.833367677835217f    * yc) + (-0.454470795871421f    * zc);
282                 *g = (-0.511651380743862f * xc) + (1.42275837632178f * yc) + (0.0888930017552939f * zc);
283                 *b = (0.00572040983140966f      * xc) + (-0.0159068485104036f   * yc) + (1.0101864083734f       * zc);
284                 break;
285         }
286 }
287
288 /* we define a 'cpack' here as a (3 byte color code) number that can be expressed like 0xFFAA66 or so.
289    for that reason it is sensitive for endianness... with this function it works correctly
290 */
291
292 unsigned int hsv_to_cpack(float h, float s, float v)
293 {
294         short r, g, b;
295         float rf, gf, bf;
296         unsigned int col;
297         
298         hsv_to_rgb(h, s, v, &rf, &gf, &bf);
299         
300         r= (short)(rf*255.0f);
301         g= (short)(gf*255.0f);
302         b= (short)(bf*255.0f);
303         
304         col= ( r + (g*256) + (b*256*256) );
305         return col;
306 }
307
308
309 unsigned int rgb_to_cpack(float r, float g, float b)
310 {
311         int ir, ig, ib;
312         
313         ir= (int)floor(255.0f*r);
314         if(ir<0) ir= 0; else if(ir>255) ir= 255;
315         ig= (int)floor(255.0f*g);
316         if(ig<0) ig= 0; else if(ig>255) ig= 255;
317         ib= (int)floor(255.0f*b);
318         if(ib<0) ib= 0; else if(ib>255) ib= 255;
319         
320         return (ir+ (ig*256) + (ib*256*256));
321 }
322
323 void cpack_to_rgb(unsigned int col, float *r, float *g, float *b)
324 {
325         
326         *r= (float)((col)&0xFF);
327         *r /= 255.0f;
328
329         *g= (float)(((col)>>8)&0xFF);
330         *g /= 255.0f;
331
332         *b= (float)(((col)>>16)&0xFF);
333         *b /= 255.0f;
334 }
335
336 void rgb_byte_to_float(const unsigned char *in, float *out)
337 {
338         out[0]= ((float)in[0]) / 255.0f;
339         out[1]= ((float)in[1]) / 255.0f;
340         out[2]= ((float)in[2]) / 255.0f;
341 }
342
343 void rgb_float_to_byte(const float *in, unsigned char *out)
344 {
345         int r, g, b;
346         
347         r= (int)(in[0] * 255.0f);
348         g= (int)(in[1] * 255.0f);
349         b= (int)(in[2] * 255.0f);
350         
351         out[0]= (char)((r <= 0)? 0 : (r >= 255)? 255 : r);
352         out[1]= (char)((g <= 0)? 0 : (g >= 255)? 255 : g);
353         out[2]= (char)((b <= 0)? 0 : (b >= 255)? 255 : b);
354 }
355
356 /* ********************************* color transforms ********************************* */
357
358
359 void gamma_correct(float *c, float gamma)
360 {
361         *c = powf((*c), gamma);
362 }
363
364 float rec709_to_linearrgb(float c)
365 {
366         if (c < 0.081f)
367                 return (c < 0.0f)? 0.0f: c * (1.0f/4.5f);
368         else
369                 return powf((c + 0.099f)*(1.0f/1.099f), (1.0f/0.45f));
370 }
371
372 float linearrgb_to_rec709(float c)
373 {
374         if (c < 0.018f)
375                 return (c < 0.0f)? 0.0f: c * 4.5f;
376         else
377                 return 1.099f * powf(c, 0.45f) - 0.099f;
378 }
379
380 float srgb_to_linearrgb(float c)
381 {
382         if (c < 0.04045f)
383                 return (c < 0.0f)? 0.0f: c * (1.0f/12.92f);
384         else
385                 return powf((c + 0.055f)*(1.0f/1.055f), 2.4f);
386 }
387
388 float linearrgb_to_srgb(float c)
389 {
390         if (c < 0.0031308f)
391                 return (c < 0.0f)? 0.0f: c * 12.92f;
392         else
393                 return  1.055f * powf(c, 1.0f/2.4f) - 0.055f;
394 }
395
396 void srgb_to_linearrgb_v3_v3(float *col_to, float *col_from)
397 {
398         col_to[0] = srgb_to_linearrgb(col_from[0]);
399         col_to[1] = srgb_to_linearrgb(col_from[1]);
400         col_to[2] = srgb_to_linearrgb(col_from[2]);
401 }
402
403 void linearrgb_to_srgb_v3_v3(float *col_to, float *col_from)
404 {
405         col_to[0] = linearrgb_to_srgb(col_from[0]);
406         col_to[1] = linearrgb_to_srgb(col_from[1]);
407         col_to[2] = linearrgb_to_srgb(col_from[2]);
408 }
409
410 /* todo, should these be moved elsewhere?, they dont belong in imbuf */
411 void srgb_to_linearrgb_rgba_buf(float *col, int tot)
412 {
413         while(tot--) {
414                 srgb_to_linearrgb_v3_v3(col, col);
415                 col += 4;
416         }
417 }
418
419 void linearrgb_to_srgb_rgba_buf(float *col, int tot)
420 {
421         while(tot--) {
422                 linearrgb_to_srgb_v3_v3(col, col);
423                 col += 4;
424         }
425 }
426
427 void srgb_to_linearrgb_rgba_rgba_buf(float *col_to, float *col_from, int tot)
428 {
429         while(tot--) {
430                 srgb_to_linearrgb_v3_v3(col_to, col_from);
431                 col_to[3]= col_from[3];
432                 col_to += 4;
433                 col_from += 4;
434         }
435 }
436
437 void linearrgb_to_srgb_rgba_rgba_buf(float *col_to, float *col_from, int tot)
438 {
439         while(tot--) {
440                 linearrgb_to_srgb_v3_v3(col_to, col_from);
441                 col_to[3]= col_from[3];
442                 col_to += 4;
443                 col_from += 4;
444         }
445 }
446
447 void minmax_rgb(short c[])
448 {
449         if(c[0]>255) c[0]=255;
450         else if(c[0]<0) c[0]=0;
451         if(c[1]>255) c[1]=255;
452         else if(c[1]<0) c[1]=0;
453         if(c[2]>255) c[2]=255;
454         else if(c[2]<0) c[2]=0;
455 }
456
457 /*If the requested RGB shade contains a negative weight for
458   one of the primaries, it lies outside the color gamut 
459   accessible from the given triple of primaries.  Desaturate
460   it by adding white, equal quantities of R, G, and B, enough
461   to make RGB all positive.  The function returns 1 if the
462   components were modified, zero otherwise.*/
463 int constrain_rgb(float *r, float *g, float *b)
464 {
465         float w;
466
467         /* Amount of white needed is w = - min(0, *r, *g, *b) */
468
469         w = (0 < *r) ? 0 : *r;
470         w = (w < *g) ? w : *g;
471         w = (w < *b) ? w : *b;
472         w = -w;
473
474         /* Add just enough white to make r, g, b all positive. */
475
476         if (w > 0) {
477                 *r += w;  *g += w; *b += w;
478                 return 1;                     /* Color modified to fit RGB gamut */
479         }
480
481         return 0;                         /* Color within RGB gamut */
482 }
483
484 float rgb_to_grayscale(float rgb[3])
485 {
486         return 0.3f*rgb[0] + 0.58f*rgb[1] + 0.12f*rgb[2];
487 }
488
489 unsigned char rgb_to_grayscale_byte(unsigned char rgb[3])
490 {
491         return (76*(unsigned short)rgb[0] + 148*(unsigned short)rgb[1] + 31*(unsigned short)rgb[2]) / 255;
492 }
493
494 /* ********************************* lift/gamma/gain / ASC-CDL conversion ********************************* */
495
496 void lift_gamma_gain_to_asc_cdl(float *lift, float *gamma, float *gain, float *offset, float *slope, float *power)
497 {
498         int c;
499         for(c=0; c<3; c++) {
500                 offset[c]= lift[c]*gain[c];
501                 slope[c]=  gain[c]*(1.0f-lift[c]);
502                 if(gamma[c] == 0)
503                         power[c]= FLT_MAX;
504                 else
505                         power[c]= 1.0f/gamma[c];
506         }
507 }
508
509 /* ******************************************** other ************************************************* */
510
511 /* Applies an hue offset to a float rgb color */
512 void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset)
513 {
514         float hsv[3];
515         
516         rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
517         
518         hsv[0]+= hue_offset;
519         if(hsv[0] > 1.0f)               hsv[0] -= 1.0f;
520         else if(hsv[0] < 0.0f)  hsv[0] += 1.0f;
521         
522         hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2);
523 }
524
525 /* Applies an hue offset to a byte rgb color */
526 void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset)
527 {
528         float rgb_float[3];
529         
530         rgb_byte_to_float(rgb, rgb_float);
531         rgb_float_set_hue_float_offset(rgb_float, hue_offset);
532         rgb_float_to_byte(rgb_float, rgb);
533 }