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