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