svn merge ^/trunk/blender -r42920:42927
[blender.git] / source / blender / blenkernel / intern / colortools.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) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL/BL DUAL LICENSE BLOCK *****
26  */
27
28 /** \file blender/blenkernel/intern/colortools.c
29  *  \ingroup bke
30  */
31
32
33 #include <string.h>
34 #include <math.h>
35 #include <stdlib.h>
36 #include <float.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_color_types.h"
41 #include "DNA_curve_types.h"
42
43 #include "BLI_blenlib.h"
44 #include "BLI_math.h"
45 #include "BLI_utildefines.h"
46
47 #include "BKE_colortools.h"
48 #include "BKE_curve.h"
49 #include "BKE_fcurve.h"
50
51
52 #include "IMB_imbuf.h"
53 #include "IMB_imbuf_types.h"
54
55
56 void floatbuf_to_srgb_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int UNUSED(w))
57 {
58         int x, y;
59         float *rf= rectf;
60         float srgb[3];
61         unsigned char *rc= rectc;
62         
63         for(y=y1; y<y2; y++) {
64                 for(x=x1; x<x2; x++, rf+=4, rc+=4) {
65                         srgb[0]= linearrgb_to_srgb(rf[0]);
66                         srgb[1]= linearrgb_to_srgb(rf[1]);
67                         srgb[2]= linearrgb_to_srgb(rf[2]);
68
69                         rc[0]= FTOCHAR(srgb[0]);
70                         rc[1]= FTOCHAR(srgb[1]);
71                         rc[2]= FTOCHAR(srgb[2]);
72                         rc[3]= FTOCHAR(rf[3]);
73                 }
74         }
75 }
76
77 void floatbuf_to_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int UNUSED(w))
78 {
79         int x, y;
80         float *rf= rectf;
81         unsigned char *rc= rectc;
82         
83         for(y=y1; y<y2; y++) {
84                 for(x=x1; x<x2; x++, rf+=4, rc+=4) {
85                         rc[0]= FTOCHAR(rf[0]);
86                         rc[1]= FTOCHAR(rf[1]);
87                         rc[2]= FTOCHAR(rf[2]);
88                         rc[3]= FTOCHAR(rf[3]);
89                 }
90         }
91 }
92
93
94 /* ********************************* color curve ********************* */
95
96 /* ***************** operations on full struct ************* */
97
98 CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
99 {
100         CurveMapping *cumap;
101         int a;
102         float clipminx, clipminy, clipmaxx, clipmaxy;
103         
104         cumap= MEM_callocN(sizeof(CurveMapping), "new curvemap");
105         cumap->flag= CUMA_DO_CLIP;
106         if(tot==4) cumap->cur= 3;               /* rhms, hack for 'col' curve? */
107         
108         clipminx = MIN2(minx, maxx);
109         clipminy = MIN2(miny, maxy);
110         clipmaxx = MAX2(minx, maxx);
111         clipmaxy = MAX2(miny, maxy);
112         
113         BLI_init_rctf(&cumap->curr, clipminx, clipmaxx, clipminy, clipmaxy);
114         cumap->clipr= cumap->curr;
115         
116         cumap->white[0]= cumap->white[1]= cumap->white[2]= 1.0f;
117         cumap->bwmul[0]= cumap->bwmul[1]= cumap->bwmul[2]= 1.0f;
118         
119         for(a=0; a<tot; a++) {
120                 cumap->cm[a].flag= CUMA_EXTEND_EXTRAPOLATE;
121                 cumap->cm[a].totpoint= 2;
122                 cumap->cm[a].curve= MEM_callocN(2*sizeof(CurveMapPoint), "curve points");
123                 
124                 cumap->cm[a].curve[0].x= minx;
125                 cumap->cm[a].curve[0].y= miny;
126                 cumap->cm[a].curve[1].x= maxx;
127                 cumap->cm[a].curve[1].y= maxy;
128         }       
129
130         cumap->changed_timestamp = 0;
131
132         return cumap;
133 }
134
135 void curvemapping_free(CurveMapping *cumap)
136 {
137         int a;
138         
139         if(cumap) {
140                 for(a=0; a<CM_TOT; a++) {
141                         if(cumap->cm[a].curve) MEM_freeN(cumap->cm[a].curve);
142                         if(cumap->cm[a].table) MEM_freeN(cumap->cm[a].table);
143                         if(cumap->cm[a].premultable) MEM_freeN(cumap->cm[a].premultable);
144                 }
145                 MEM_freeN(cumap);
146         }
147 }
148
149 CurveMapping *curvemapping_copy(CurveMapping *cumap)
150 {
151         int a;
152         
153         if(cumap) {
154                 CurveMapping *cumapn= MEM_dupallocN(cumap);
155                 for(a=0; a<CM_TOT; a++) {
156                         if(cumap->cm[a].curve) 
157                                 cumapn->cm[a].curve= MEM_dupallocN(cumap->cm[a].curve);
158                         if(cumap->cm[a].table) 
159                                 cumapn->cm[a].table= MEM_dupallocN(cumap->cm[a].table);
160                         if(cumap->cm[a].premultable) 
161                                 cumapn->cm[a].premultable= MEM_dupallocN(cumap->cm[a].premultable);
162                 }
163                 return cumapn;
164         }
165         return NULL;
166 }
167
168 void curvemapping_set_black_white(CurveMapping *cumap, const float black[3], const float white[3])
169 {
170         int a;
171         
172         if(white)
173                 copy_v3_v3(cumap->white, white);
174         if(black)
175                 copy_v3_v3(cumap->black, black);
176         
177         for(a=0; a<3; a++) {
178                 if(cumap->white[a]==cumap->black[a])
179                         cumap->bwmul[a]= 0.0f;
180                 else
181                         cumap->bwmul[a]= 1.0f/(cumap->white[a] - cumap->black[a]);
182         }       
183 }
184
185 /* ***************** operations on single curve ************* */
186 /* ********** NOTE: requires curvemapping_changed() call after ******** */
187
188 /* removes with flag set */
189 void curvemap_remove(CurveMap *cuma, int flag)
190 {
191         CurveMapPoint *cmp= MEM_mallocN((cuma->totpoint)*sizeof(CurveMapPoint), "curve points");
192         int a, b, removed=0;
193         
194         /* well, lets keep the two outer points! */
195         cmp[0]= cuma->curve[0];
196         for(a=1, b=1; a<cuma->totpoint-1; a++) {
197                 if(!(cuma->curve[a].flag & flag)) {
198                         cmp[b]= cuma->curve[a];
199                         b++;
200                 }
201                 else removed++;
202         }
203         cmp[b]= cuma->curve[a];
204         
205         MEM_freeN(cuma->curve);
206         cuma->curve= cmp;
207         cuma->totpoint -= removed;
208 }
209
210 void curvemap_insert(CurveMap *cuma, float x, float y)
211 {
212         CurveMapPoint *cmp= MEM_callocN((cuma->totpoint+1)*sizeof(CurveMapPoint), "curve points");
213         int a, b, foundloc= 0;
214                 
215         /* insert fragments of the old one and the new point to the new curve */
216         cuma->totpoint++;
217         for(a=0, b=0; a<cuma->totpoint; a++) {
218                 if((x < cuma->curve[a].x) && !foundloc) {
219                         cmp[a].x= x;
220                         cmp[a].y= y;
221                         cmp[a].flag= CUMA_SELECT;
222                         foundloc= 1;
223                 }
224                 else {
225                         cmp[a].x= cuma->curve[b].x;
226                         cmp[a].y= cuma->curve[b].y;
227                         cmp[a].flag= cuma->curve[b].flag;
228                         cmp[a].flag &= ~CUMA_SELECT; /* make sure old points don't remain selected */
229                         cmp[a].shorty= cuma->curve[b].shorty;
230                         b++;
231                 }
232         }
233
234         /* free old curve and replace it with new one */
235         MEM_freeN(cuma->curve);
236         cuma->curve= cmp;
237 }
238
239 void curvemap_reset(CurveMap *cuma, rctf *clipr, int preset, int slope)
240 {
241         if(cuma->curve)
242                 MEM_freeN(cuma->curve);
243
244         switch(preset) {
245                 case CURVE_PRESET_LINE: cuma->totpoint= 2; break;
246                 case CURVE_PRESET_SHARP: cuma->totpoint= 4; break;
247                 case CURVE_PRESET_SMOOTH: cuma->totpoint= 4; break;
248                 case CURVE_PRESET_MAX: cuma->totpoint= 2; break;
249                 case CURVE_PRESET_MID9: cuma->totpoint= 9; break;
250                 case CURVE_PRESET_ROUND: cuma->totpoint= 4; break;
251                 case CURVE_PRESET_ROOT: cuma->totpoint= 4; break;
252         }
253
254         cuma->curve= MEM_callocN(cuma->totpoint*sizeof(CurveMapPoint), "curve points");
255
256         switch(preset) {
257                 case CURVE_PRESET_LINE:
258                         cuma->curve[0].x= clipr->xmin;
259                         cuma->curve[0].y= clipr->ymax;
260                         cuma->curve[0].flag= 0;
261                         cuma->curve[1].x= clipr->xmax;
262                         cuma->curve[1].y= clipr->ymin;
263                         cuma->curve[1].flag= 0;
264                         break;
265                 case CURVE_PRESET_SHARP:
266                         cuma->curve[0].x= 0;
267                         cuma->curve[0].y= 1;
268                         cuma->curve[1].x= 0.25;
269                         cuma->curve[1].y= 0.50;
270                         cuma->curve[2].x= 0.75;
271                         cuma->curve[2].y= 0.04;
272                         cuma->curve[3].x= 1;
273                         cuma->curve[3].y= 0;
274                         break;
275                 case CURVE_PRESET_SMOOTH:
276                         cuma->curve[0].x= 0;
277                         cuma->curve[0].y= 1;
278                         cuma->curve[1].x= 0.25;
279                         cuma->curve[1].y= 0.94;
280                         cuma->curve[2].x= 0.75;
281                         cuma->curve[2].y= 0.06;
282                         cuma->curve[3].x= 1;
283                         cuma->curve[3].y= 0;
284                         break;
285                 case CURVE_PRESET_MAX:
286                         cuma->curve[0].x= 0;
287                         cuma->curve[0].y= 1;
288                         cuma->curve[1].x= 1;
289                         cuma->curve[1].y= 1;
290                         break;
291                 case CURVE_PRESET_MID9:
292                         {
293                                 int i;
294                                 for (i=0; i < cuma->totpoint; i++)
295                                 {
296                                         cuma->curve[i].x= i / ((float)cuma->totpoint-1);
297                                         cuma->curve[i].y= 0.5;
298                                 }
299                         }
300                         break;
301                 case CURVE_PRESET_ROUND:
302                         cuma->curve[0].x= 0;
303                         cuma->curve[0].y= 1;
304                         cuma->curve[1].x= 0.5;
305                         cuma->curve[1].y= 0.90;
306                         cuma->curve[2].x= 0.86;
307                         cuma->curve[2].y= 0.5;
308                         cuma->curve[3].x= 1;
309                         cuma->curve[3].y= 0;
310                         break;
311                 case CURVE_PRESET_ROOT:
312                         cuma->curve[0].x= 0;
313                         cuma->curve[0].y= 1;
314                         cuma->curve[1].x= 0.25;
315                         cuma->curve[1].y= 0.95;
316                         cuma->curve[2].x= 0.75;
317                         cuma->curve[2].y= 0.44;
318                         cuma->curve[3].x= 1;
319                         cuma->curve[3].y= 0;
320                         break;
321         }
322
323         /* mirror curve in x direction to have positive slope
324          * rather than default negative slope */
325         if (slope == CURVEMAP_SLOPE_POSITIVE) {
326                 int i, last=cuma->totpoint-1;
327                 CurveMapPoint *newpoints= MEM_dupallocN(cuma->curve);
328                 
329                 for (i=0; i<cuma->totpoint; i++) {
330                         newpoints[i].y = cuma->curve[last-i].y;
331                 }
332                 
333                 MEM_freeN(cuma->curve);
334                 cuma->curve = newpoints;
335         }
336         
337         if(cuma->table) {
338                 MEM_freeN(cuma->table);
339                 cuma->table= NULL;
340         }
341 }
342
343 /* if type==1: vector, else auto */
344 void curvemap_sethandle(CurveMap *cuma, int type)
345 {
346         int a;
347         
348         for(a=0; a<cuma->totpoint; a++) {
349                 if(cuma->curve[a].flag & CUMA_SELECT) {
350                         if(type) cuma->curve[a].flag |= CUMA_VECTOR;
351                         else cuma->curve[a].flag &= ~CUMA_VECTOR;
352                 }
353         }
354 }
355
356 /* *********************** Making the tables and display ************** */
357
358 /* reduced copy of garbled calchandleNurb() code in curve.c */
359 static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int UNUSED(mode))
360 {
361         float *p1,*p2,*p3,pt[3];
362         float len,len_a, len_b;
363         float dvec_a[2], dvec_b[2];
364
365         if(bezt->h1==0 && bezt->h2==0) {
366                 return;
367         }
368         
369         p2= bezt->vec[1];
370         
371         if(prev==NULL) {
372                 p3= next->vec[1];
373                 pt[0]= 2.0f*p2[0] - p3[0];
374                 pt[1]= 2.0f*p2[1] - p3[1];
375                 p1= pt;
376         }
377         else {
378                 p1= prev->vec[1];
379         }
380         
381         if(next==NULL) {
382                 p1= prev->vec[1];
383                 pt[0]= 2.0f*p2[0] - p1[0];
384                 pt[1]= 2.0f*p2[1] - p1[1];
385                 p3= pt;
386         }
387         else {
388                 p3= next->vec[1];
389         }
390
391         sub_v2_v2v2(dvec_a, p2, p1);
392         sub_v2_v2v2(dvec_b, p3, p2);
393
394         len_a= len_v2(dvec_a);
395         len_b= len_v2(dvec_b);
396
397         if(len_a==0.0f) len_a=1.0f;
398         if(len_b==0.0f) len_b=1.0f;
399
400         if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */
401                 float tvec[2];
402                 tvec[0]= dvec_b[0]/len_b + dvec_a[0]/len_a;
403                 tvec[1]= dvec_b[1]/len_b + dvec_a[1]/len_a;
404
405                 len= len_v2(tvec) * 2.5614f;
406                 if(len!=0.0f) {
407                         
408                         if(bezt->h1==HD_AUTO) {
409                                 len_a/=len;
410                                 madd_v2_v2v2fl(p2-3, p2, tvec, -len_a);
411                         }
412                         if(bezt->h2==HD_AUTO) {
413                                 len_b/=len;
414                                 madd_v2_v2v2fl(p2+3, p2, tvec,  len_b);
415                         }
416                 }
417         }
418
419         if(bezt->h1==HD_VECT) { /* vector */
420                 madd_v2_v2v2fl(p2-3, p2, dvec_a, -1.0f/3.0f);
421         }
422         if(bezt->h2==HD_VECT) {
423                 madd_v2_v2v2fl(p2+3, p2, dvec_b,  1.0f/3.0f);
424         }
425 }
426
427 /* in X, out Y. 
428    X is presumed to be outside first or last */
429 static float curvemap_calc_extend(CurveMap *cuma, float x, const float first[2], const float last[2])
430 {
431         if(x <= first[0]) {
432                 if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) {
433                         /* no extrapolate */
434                         return first[1];
435                 }
436                 else {
437                         if(cuma->ext_in[0]==0.0f)
438                                 return first[1] + cuma->ext_in[1]*10000.0f;
439                         else
440                                 return first[1] + cuma->ext_in[1]*(x - first[0])/cuma->ext_in[0];
441                 }
442         }
443         else if(x >= last[0]) {
444                 if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) {
445                         /* no extrapolate */
446                         return last[1];
447                 }
448                 else {
449                         if(cuma->ext_out[0]==0.0f)
450                                 return last[1] - cuma->ext_out[1]*10000.0f;
451                         else
452                                 return last[1] + cuma->ext_out[1]*(x - last[0])/cuma->ext_out[0];
453                 }
454         }
455         return 0.0f;
456 }
457
458 /* only creates a table for a single channel in CurveMapping */
459 static void curvemap_make_table(CurveMap *cuma, rctf *clipr)
460 {
461         CurveMapPoint *cmp= cuma->curve;
462         BezTriple *bezt;
463         float *fp, *allpoints, *lastpoint, curf, range;
464         int a, totpoint;
465         
466         if(cuma->curve==NULL) return;
467         
468         /* default rect also is table range */
469         cuma->mintable= clipr->xmin;
470         cuma->maxtable= clipr->xmax;
471         
472         /* hrmf... we now rely on blender ipo beziers, these are more advanced */
473         bezt= MEM_callocN(cuma->totpoint*sizeof(BezTriple), "beztarr");
474         
475         for(a=0; a<cuma->totpoint; a++) {
476                 cuma->mintable= MIN2(cuma->mintable, cmp[a].x);
477                 cuma->maxtable= MAX2(cuma->maxtable, cmp[a].x);
478                 bezt[a].vec[1][0]= cmp[a].x;
479                 bezt[a].vec[1][1]= cmp[a].y;
480                 if(cmp[a].flag & CUMA_VECTOR)
481                         bezt[a].h1= bezt[a].h2= HD_VECT;
482                 else
483                         bezt[a].h1= bezt[a].h2= HD_AUTO;
484         }
485         
486         for(a=0; a<cuma->totpoint; a++) {
487                 if(a==0)
488                         calchandle_curvemap(bezt, NULL, bezt+1, 0);
489                 else if(a==cuma->totpoint-1)
490                         calchandle_curvemap(bezt+a, bezt+a-1, NULL, 0);
491                 else
492                         calchandle_curvemap(bezt+a, bezt+a-1, bezt+a+1, 0);
493         }
494         
495         /* first and last handle need correction, instead of pointing to center of next/prev, 
496                 we let it point to the closest handle */
497         if(cuma->totpoint>2) {
498                 float hlen, nlen, vec[3];
499                 
500                 if(bezt[0].h2==HD_AUTO) {
501                         
502                         hlen= len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */
503                         /* clip handle point */
504                         copy_v3_v3(vec, bezt[1].vec[0]);
505                         if(vec[0] < bezt[0].vec[1][0])
506                                 vec[0]= bezt[0].vec[1][0];
507                         
508                         sub_v3_v3(vec, bezt[0].vec[1]);
509                         nlen= len_v3(vec);
510                         if(nlen>FLT_EPSILON) {
511                                 mul_v3_fl(vec, hlen/nlen);
512                                 add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]);
513                                 sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec);
514                         }
515                 }
516                 a= cuma->totpoint-1;
517                 if(bezt[a].h2==HD_AUTO) {
518                         
519                         hlen= len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */
520                         /* clip handle point */
521                         copy_v3_v3(vec, bezt[a-1].vec[2]);
522                         if(vec[0] > bezt[a].vec[1][0])
523                                 vec[0]= bezt[a].vec[1][0];
524                         
525                         sub_v3_v3(vec, bezt[a].vec[1]);
526                         nlen= len_v3(vec);
527                         if(nlen>FLT_EPSILON) {
528                                 mul_v3_fl(vec, hlen/nlen);
529                                 add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]);
530                                 sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec);
531                         }
532                 }
533         }       
534         /* make the bezier curve */
535         if(cuma->table)
536                 MEM_freeN(cuma->table);
537         totpoint= (cuma->totpoint-1)*CM_RESOL;
538         fp= allpoints= MEM_callocN(totpoint*2*sizeof(float), "table");
539         
540         for(a=0; a<cuma->totpoint-1; a++, fp += 2*CM_RESOL) {
541                 correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a+1].vec[0], bezt[a+1].vec[1]);
542                 forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a+1].vec[0][0], bezt[a+1].vec[1][0], fp, CM_RESOL-1, 2*sizeof(float));   
543                 forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a+1].vec[0][1], bezt[a+1].vec[1][1], fp+1, CM_RESOL-1, 2*sizeof(float));
544         }
545         
546         /* store first and last handle for extrapolation, unit length */
547         cuma->ext_in[0]= bezt[0].vec[0][0] - bezt[0].vec[1][0];
548         cuma->ext_in[1]= bezt[0].vec[0][1] - bezt[0].vec[1][1];
549         range= sqrt(cuma->ext_in[0]*cuma->ext_in[0] + cuma->ext_in[1]*cuma->ext_in[1]);
550         cuma->ext_in[0]/= range;
551         cuma->ext_in[1]/= range;
552         
553         a= cuma->totpoint-1;
554         cuma->ext_out[0]= bezt[a].vec[1][0] - bezt[a].vec[2][0];
555         cuma->ext_out[1]= bezt[a].vec[1][1] - bezt[a].vec[2][1];
556         range= sqrt(cuma->ext_out[0]*cuma->ext_out[0] + cuma->ext_out[1]*cuma->ext_out[1]);
557         cuma->ext_out[0]/= range;
558         cuma->ext_out[1]/= range;
559         
560         /* cleanup */
561         MEM_freeN(bezt);
562
563         range= CM_TABLEDIV*(cuma->maxtable - cuma->mintable);
564         cuma->range= 1.0f/range;
565         
566         /* now make a table with CM_TABLE equal x distances */
567         fp= allpoints;
568         lastpoint= allpoints + 2*(totpoint-1);
569         cmp= MEM_callocN((CM_TABLE+1)*sizeof(CurveMapPoint), "dist table");
570         
571         for(a=0; a<=CM_TABLE; a++) {
572                 curf= cuma->mintable + range*(float)a;
573                 cmp[a].x= curf;
574                 
575                 /* get the first x coordinate larger than curf */
576                 while(curf >= fp[0] && fp!=lastpoint) {
577                         fp+=2;
578                 }
579                 if(fp==allpoints || (curf >= fp[0] && fp==lastpoint))
580                         cmp[a].y= curvemap_calc_extend(cuma, curf, allpoints, lastpoint);
581                 else {
582                         float fac1= fp[0] - fp[-2];
583                         float fac2= fp[0] - curf;
584                         if(fac1 > FLT_EPSILON)
585                                 fac1= fac2/fac1;
586                         else
587                                 fac1= 0.0f;
588                         cmp[a].y= fac1*fp[-1] + (1.0f-fac1)*fp[1];
589                 }
590         }
591         
592         MEM_freeN(allpoints);
593         cuma->table= cmp;
594 }
595
596 /* call when you do images etc, needs restore too. also verifies tables */
597 /* it uses a flag to prevent premul or free to happen twice */
598 void curvemapping_premultiply(CurveMapping *cumap, int restore)
599 {
600         int a;
601         
602         if(restore) {
603                 if(cumap->flag & CUMA_PREMULLED) {
604                         for(a=0; a<3; a++) {
605                                 MEM_freeN(cumap->cm[a].table);
606                                 cumap->cm[a].table= cumap->cm[a].premultable;
607                                 cumap->cm[a].premultable= NULL;
608                         }
609                         
610                         cumap->flag &= ~CUMA_PREMULLED;
611                 }
612         }
613         else {
614                 if((cumap->flag & CUMA_PREMULLED)==0) {
615                         /* verify and copy */
616                         for(a=0; a<3; a++) {
617                                 if(cumap->cm[a].table==NULL)
618                                         curvemap_make_table(cumap->cm+a, &cumap->clipr);
619                                 cumap->cm[a].premultable= cumap->cm[a].table;
620                                 cumap->cm[a].table= MEM_mallocN((CM_TABLE+1)*sizeof(CurveMapPoint), "premul table");
621                                 memcpy(cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE+1)*sizeof(CurveMapPoint));
622                         }
623                         
624                         if(cumap->cm[3].table==NULL)
625                                 curvemap_make_table(cumap->cm+3, &cumap->clipr);
626                 
627                         /* premul */
628                         for(a=0; a<3; a++) {
629                                 int b;
630                                 for(b=0; b<=CM_TABLE; b++) {
631                                         cumap->cm[a].table[b].y= curvemap_evaluateF(cumap->cm+3, cumap->cm[a].table[b].y);
632                                 }
633                         }
634                         
635                         cumap->flag |= CUMA_PREMULLED;
636                 }
637         }
638 }
639
640 static int sort_curvepoints(const void *a1, const void *a2)
641 {
642         const struct CurveMapPoint *x1=a1, *x2=a2;
643         
644         if( x1->x > x2->x ) return 1;
645         else if( x1->x < x2->x) return -1;
646         return 0;
647 }
648
649 /* ************************ more CurveMapping calls *************** */
650
651 /* note; only does current curvemap! */
652 void curvemapping_changed(CurveMapping *cumap, int rem_doubles)
653 {
654         CurveMap *cuma= cumap->cm+cumap->cur;
655         CurveMapPoint *cmp= cuma->curve;
656         rctf *clipr= &cumap->clipr;
657         float thresh= 0.01f*(clipr->xmax - clipr->xmin);
658         float dx= 0.0f, dy= 0.0f;
659         int a;
660
661         cumap->changed_timestamp++;
662
663         /* clamp with clip */
664         if(cumap->flag & CUMA_DO_CLIP) {
665                 for(a=0; a<cuma->totpoint; a++) {
666                         if(cmp[a].flag & CUMA_SELECT) {
667                                 if(cmp[a].x < clipr->xmin)
668                                         dx= MIN2(dx, cmp[a].x - clipr->xmin);
669                                 else if(cmp[a].x > clipr->xmax)
670                                         dx= MAX2(dx, cmp[a].x - clipr->xmax);
671                                 if(cmp[a].y < clipr->ymin)
672                                         dy= MIN2(dy, cmp[a].y - clipr->ymin);
673                                 else if(cmp[a].y > clipr->ymax)
674                                         dy= MAX2(dy, cmp[a].y - clipr->ymax);
675                         }
676                 }
677                 for(a=0; a<cuma->totpoint; a++) {
678                         if(cmp[a].flag & CUMA_SELECT) {
679                                 cmp[a].x -= dx;
680                                 cmp[a].y -= dy;
681                         }
682                 }
683         }
684         
685         
686         qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints);
687         
688         /* remove doubles, threshold set on 1% of default range */
689         if(rem_doubles && cuma->totpoint>2) {
690                 for(a=0; a<cuma->totpoint-1; a++) {
691                         dx= cmp[a].x - cmp[a+1].x;
692                         dy= cmp[a].y - cmp[a+1].y;
693                         if( sqrtf(dx*dx + dy*dy) < thresh ) {
694                                 if(a==0) {
695                                         cmp[a+1].flag|= 2;
696                                         if(cmp[a+1].flag & CUMA_SELECT)
697                                                 cmp[a].flag |= CUMA_SELECT;
698                                 }
699                                 else {
700                                         cmp[a].flag|= 2;
701                                         if(cmp[a].flag & CUMA_SELECT)
702                                                 cmp[a+1].flag |= CUMA_SELECT;
703                                 }
704                                 break;  /* we assume 1 deletion per edit is ok */
705                         }
706                 }
707                 if(a != cuma->totpoint-1)
708                         curvemap_remove(cuma, 2);
709         }       
710         curvemap_make_table(cuma, clipr);
711 }
712
713 /* table should be verified */
714 float curvemap_evaluateF(CurveMap *cuma, float value)
715 {
716         float fi;
717         int i;
718
719         /* index in table */
720         fi= (value-cuma->mintable)*cuma->range;
721         i= (int)fi;
722         
723         /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */
724         if(fi<0.0f || fi>CM_TABLE)
725                 return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x);
726         else {
727                 if(i<0) return cuma->table[0].y;
728                 if(i>=CM_TABLE) return cuma->table[CM_TABLE].y;
729                 
730                 fi= fi-(float)i;
731                 return (1.0f-fi)*cuma->table[i].y + (fi)*cuma->table[i+1].y; 
732         }
733 }
734
735 /* works with curve 'cur' */
736 float curvemapping_evaluateF(CurveMapping *cumap, int cur, float value)
737 {
738         CurveMap *cuma= cumap->cm+cur;
739         
740         /* allocate or bail out */
741         if(cuma->table==NULL) {
742                 curvemap_make_table(cuma, &cumap->clipr);
743                 if(cuma->table==NULL)
744                         return 1.0f-value;
745         }
746         return curvemap_evaluateF(cuma, value);
747 }
748
749 /* vector case */
750 void curvemapping_evaluate3F(CurveMapping *cumap, float vecout[3], const float vecin[3])
751 {
752         vecout[0]= curvemapping_evaluateF(cumap, 0, vecin[0]);
753         vecout[1]= curvemapping_evaluateF(cumap, 1, vecin[1]);
754         vecout[2]= curvemapping_evaluateF(cumap, 2, vecin[2]);
755 }
756
757 /* RGB case, no black/white points, no premult */
758 void curvemapping_evaluateRGBF(CurveMapping *cumap, float vecout[3], const float vecin[3])
759 {
760         vecout[0]= curvemapping_evaluateF(cumap, 0, curvemapping_evaluateF(cumap, 3, vecin[0]));
761         vecout[1]= curvemapping_evaluateF(cumap, 1, curvemapping_evaluateF(cumap, 3, vecin[1]));
762         vecout[2]= curvemapping_evaluateF(cumap, 2, curvemapping_evaluateF(cumap, 3, vecin[2]));
763 }
764
765
766 /* RGB with black/white points and premult. tables are checked */
767 void curvemapping_evaluate_premulRGBF(CurveMapping *cumap, float vecout[3], const float vecin[3])
768 {
769         float fac;
770         
771         fac= (vecin[0] - cumap->black[0])*cumap->bwmul[0];
772         vecout[0]= curvemap_evaluateF(cumap->cm, fac);
773         
774         fac= (vecin[1] - cumap->black[1])*cumap->bwmul[1];
775         vecout[1]= curvemap_evaluateF(cumap->cm+1, fac);
776         
777         fac= (vecin[2] - cumap->black[2])*cumap->bwmul[2];
778         vecout[2]= curvemap_evaluateF(cumap->cm+2, fac);
779 }
780
781
782 /* only used for image editor curves */
783 void curvemapping_do_ibuf(CurveMapping *cumap, ImBuf *ibuf)
784 {
785         ImBuf *tmpbuf;
786         int pixel;
787         float *pix_in;
788         float col[3];
789         int stride= 4;
790         float *pix_out;
791         
792         if(ibuf==NULL)
793                 return;
794         if(ibuf->rect_float==NULL)
795                 IMB_float_from_rect(ibuf);
796         else if(ibuf->rect==NULL)
797                 imb_addrectImBuf(ibuf);
798         
799         if (!ibuf->rect || !ibuf->rect_float)
800                 return;
801         
802         /* work on a temp buffer, so can color manage afterwards.
803          * No worse off memory wise than comp nodes */
804         tmpbuf = IMB_dupImBuf(ibuf);
805         
806         curvemapping_premultiply(cumap, 0);
807         
808         pix_in= ibuf->rect_float;
809         pix_out= tmpbuf->rect_float;
810
811         if(ibuf->channels)
812                 stride= ibuf->channels;
813         
814         for(pixel= ibuf->x*ibuf->y; pixel>0; pixel--, pix_in+=stride, pix_out+=stride) {
815                 if(stride<3) {
816                         col[0]= curvemap_evaluateF(cumap->cm, *pix_in);
817                         
818                         pix_out[1]= pix_out[2]= pix_out[3]= pix_out[0]= col[0];
819                 }
820                 else {
821                         curvemapping_evaluate_premulRGBF(cumap, col, pix_in);
822                         pix_out[0]= col[0];
823                         pix_out[1]= col[1];
824                         pix_out[2]= col[2];
825                         if(stride>3)
826                                 pix_out[3]= pix_in[3];
827                         else
828                                 pix_out[3]= 1.f;
829                 }
830         }
831         
832         IMB_rect_from_float(tmpbuf);
833         SWAP(unsigned int *, tmpbuf->rect, ibuf->rect);
834         IMB_freeImBuf(tmpbuf);
835         
836         curvemapping_premultiply(cumap, 1);
837 }
838
839 int curvemapping_RGBA_does_something(CurveMapping *cumap)
840 {
841         int a;
842         
843         if(cumap->black[0]!=0.0f) return 1;
844         if(cumap->black[1]!=0.0f) return 1;
845         if(cumap->black[2]!=0.0f) return 1;
846         if(cumap->white[0]!=1.0f) return 1;
847         if(cumap->white[1]!=1.0f) return 1;
848         if(cumap->white[2]!=1.0f) return 1;
849         
850         for(a=0; a<CM_TOT; a++) {
851                 if(cumap->cm[a].curve) {
852                         if(cumap->cm[a].totpoint!=2)  return 1;
853                         
854                         if(cumap->cm[a].curve[0].x != 0.0f) return 1;
855                         if(cumap->cm[a].curve[0].y != 0.0f) return 1;
856                         if(cumap->cm[a].curve[1].x != 1.0f) return 1;
857                         if(cumap->cm[a].curve[1].y != 1.0f) return 1;
858                 }
859         }
860         return 0;
861 }
862
863 void curvemapping_initialize(CurveMapping *cumap)
864 {
865         int a;
866         
867         if(cumap==NULL) return;
868         
869         for(a=0; a<CM_TOT; a++) {
870                 if(cumap->cm[a].table==NULL)
871                         curvemap_make_table(cumap->cm+a, &cumap->clipr);
872         }
873 }
874
875 void curvemapping_table_RGBA(CurveMapping *cumap, float **array, int *size)
876 {
877         int a;
878         
879         *size = CM_TABLE+1;
880         *array = MEM_callocN(sizeof(float)*(*size)*4, "CurveMapping");
881         curvemapping_initialize(cumap);
882
883         for(a=0; a<*size; a++) {
884                 if(cumap->cm[0].table)
885                         (*array)[a*4+0]= cumap->cm[0].table[a].y;
886                 if(cumap->cm[1].table)
887                         (*array)[a*4+1]= cumap->cm[1].table[a].y;
888                 if(cumap->cm[2].table)
889                         (*array)[a*4+2]= cumap->cm[2].table[a].y;
890                 if(cumap->cm[3].table)
891                         (*array)[a*4+3]= cumap->cm[3].table[a].y;
892         }
893 }
894
895 /* ***************** Histogram **************** */
896
897 #define INV_255         (1.f/255.f)
898
899 DO_INLINE int get_bin_float(float f)
900 {
901         int bin= (int)((f*255.0f) + 0.5f);      /* 0.5 to prevent quantisation differences */
902
903         /* note: clamp integer instead of float to avoid problems with NaN */
904         CLAMP(bin, 0, 255);
905
906         return bin;
907 }
908
909 DO_INLINE void save_sample_line(Scopes *scopes, const int idx, const float fx, float *rgb, float *ycc)
910 {
911         float yuv[3];
912
913         /* vectorscope*/
914         rgb_to_yuv(rgb[0], rgb[1], rgb[2], &yuv[0], &yuv[1], &yuv[2]);
915         scopes->vecscope[idx + 0] = yuv[1];
916         scopes->vecscope[idx + 1] = yuv[2];
917
918         /* waveform */
919         switch (scopes->wavefrm_mode) {
920                 case SCOPES_WAVEFRM_RGB:
921                         scopes->waveform_1[idx + 0] = fx;
922                         scopes->waveform_1[idx + 1] = rgb[0];
923                         scopes->waveform_2[idx + 0] = fx;
924                         scopes->waveform_2[idx + 1] = rgb[1];
925                         scopes->waveform_3[idx + 0] = fx;
926                         scopes->waveform_3[idx + 1] = rgb[2];
927                         break;
928                 case SCOPES_WAVEFRM_LUMA:
929                         scopes->waveform_1[idx + 0] = fx;
930                         scopes->waveform_1[idx + 1] = ycc[0];
931                         break;
932                 case SCOPES_WAVEFRM_YCC_JPEG:
933                 case SCOPES_WAVEFRM_YCC_709:
934                 case SCOPES_WAVEFRM_YCC_601:
935                         scopes->waveform_1[idx + 0] = fx;
936                         scopes->waveform_1[idx + 1] = ycc[0];
937                         scopes->waveform_2[idx + 0] = fx;
938                         scopes->waveform_2[idx + 1] = ycc[1];
939                         scopes->waveform_3[idx + 0] = fx;
940                         scopes->waveform_3[idx + 1] = ycc[2];
941                         break;
942         }
943 }
944
945 void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management)
946 {
947         int x, y, c;
948         unsigned int n, nl;
949         double div, divl;
950         float *rf=NULL;
951         unsigned char *rc=NULL;
952         unsigned int *bin_r, *bin_g, *bin_b, *bin_lum;
953         int savedlines, saveline;
954         float rgb[3], ycc[3], luma;
955         int ycc_mode=-1;
956         const short is_float = (ibuf->rect_float != NULL);
957
958         if (ibuf->rect==NULL && ibuf->rect_float==NULL) return;
959
960         if (scopes->ok == 1 ) return;
961
962         if (scopes->hist.ymax == 0.f) scopes->hist.ymax = 1.f;
963
964         /* hmmmm */
965         if (!(ELEM(ibuf->channels, 3, 4))) return;
966
967         scopes->hist.channels = 3;
968         scopes->hist.x_resolution = 256;
969
970         switch (scopes->wavefrm_mode) {
971                 case SCOPES_WAVEFRM_RGB:
972                         ycc_mode = -1;
973                         break;
974                 case SCOPES_WAVEFRM_LUMA:
975                 case SCOPES_WAVEFRM_YCC_JPEG:
976                         ycc_mode = BLI_YCC_JFIF_0_255;
977                         break;
978                 case SCOPES_WAVEFRM_YCC_601:
979                         ycc_mode = BLI_YCC_ITU_BT601;
980                         break;
981                 case SCOPES_WAVEFRM_YCC_709:
982                         ycc_mode = BLI_YCC_ITU_BT709;
983                         break;
984         }
985
986         /* temp table to count pix value for histo */
987         bin_r = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
988         bin_g = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
989         bin_b = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
990         bin_lum = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
991
992         /* convert to number of lines with logarithmic scale */
993         scopes->sample_lines = (scopes->accuracy*0.01f) * (scopes->accuracy*0.01f) * ibuf->y;
994         
995         if (scopes->sample_full)
996                 scopes->sample_lines = ibuf->y;
997
998         /* scan the image */
999         savedlines=0;
1000         for (c=0; c<3; c++) {
1001                 scopes->minmax[c][0]=25500.0f;
1002                 scopes->minmax[c][1]=-25500.0f;
1003         }
1004         
1005         scopes->waveform_tot = ibuf->x*scopes->sample_lines;
1006         
1007         if (scopes->waveform_1)
1008                 MEM_freeN(scopes->waveform_1);
1009         if (scopes->waveform_2)
1010                 MEM_freeN(scopes->waveform_2);
1011         if (scopes->waveform_3)
1012                 MEM_freeN(scopes->waveform_3);
1013         if (scopes->vecscope)
1014                 MEM_freeN(scopes->vecscope);
1015         
1016         scopes->waveform_1= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 1");
1017         scopes->waveform_2= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 2");
1018         scopes->waveform_3= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 3");
1019         scopes->vecscope= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "vectorscope point channel");
1020         
1021         if (is_float)
1022                 rf = ibuf->rect_float;
1023         else
1024                 rc = (unsigned char *)ibuf->rect;
1025
1026         for (y = 0; y < ibuf->y; y++) {
1027                 if (savedlines<scopes->sample_lines && y>=((savedlines)*ibuf->y)/(scopes->sample_lines+1)) {
1028                         saveline=1;
1029                 } else saveline=0;
1030                 for (x = 0; x < ibuf->x; x++) {
1031
1032                         if (is_float) {
1033                                 if (use_color_management)
1034                                         linearrgb_to_srgb_v3_v3(rgb, rf);
1035                                 else
1036                                         copy_v3_v3(rgb, rf);
1037                         }
1038                         else {
1039                                 for (c=0; c<3; c++)
1040                                         rgb[c] = rc[c] * INV_255;
1041                         }
1042
1043                         /* we still need luma for histogram */
1044                         luma = 0.299f * rgb[0] + 0.587f * rgb[1] + 0.114f * rgb[2];
1045
1046                         /* check for min max */
1047                         if(ycc_mode == -1 ) {
1048                                 for (c=0; c<3; c++) {
1049                                         if (rgb[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = rgb[c];
1050                                         if (rgb[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = rgb[c];
1051                                 }
1052                         }
1053                         else {
1054                                 rgb_to_ycc(rgb[0],rgb[1],rgb[2],&ycc[0],&ycc[1],&ycc[2], ycc_mode);
1055                                 for (c=0; c<3; c++) {
1056                                         ycc[c] *=INV_255;
1057                                         if (ycc[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = ycc[c];
1058                                         if (ycc[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = ycc[c];
1059                                 }
1060                         }
1061                         /* increment count for histo*/
1062                         bin_r[ get_bin_float(rgb[0]) ] += 1;
1063                         bin_g[ get_bin_float(rgb[1]) ] += 1;
1064                         bin_b[ get_bin_float(rgb[2]) ] += 1;
1065                         bin_lum[ get_bin_float(luma) ] += 1;
1066
1067                         /* save sample if needed */
1068                         if(saveline) {
1069                                 const float fx = (float)x / (float)ibuf->x;
1070                                 const int idx = 2*(ibuf->x*savedlines+x);
1071                                 save_sample_line(scopes, idx, fx, rgb, ycc);
1072                         }
1073
1074                         rf+= ibuf->channels;
1075                         rc+= ibuf->channels;
1076                 }
1077                 if (saveline)
1078                         savedlines +=1;
1079         }
1080
1081         /* convert hist data to float (proportional to max count) */
1082         n=0;
1083         nl=0;
1084         for (x=0; x<256; x++) {
1085                 if (bin_r[x] > n)
1086                         n = bin_r[x];
1087                 if (bin_g[x] > n)
1088                         n = bin_g[x];
1089                 if (bin_b[x] > n)
1090                         n = bin_b[x];
1091                 if (bin_lum[x] > nl)
1092                         nl = bin_lum[x];
1093         }
1094         div = 1.0/(double)n;
1095         divl = 1.0/(double)nl;
1096         for (x=0; x<256; x++) {
1097                 scopes->hist.data_r[x] = bin_r[x] * div;
1098                 scopes->hist.data_g[x] = bin_g[x] * div;
1099                 scopes->hist.data_b[x] = bin_b[x] * div;
1100                 scopes->hist.data_luma[x] = bin_lum[x] * divl;
1101         }
1102         MEM_freeN(bin_r);
1103         MEM_freeN(bin_g);
1104         MEM_freeN(bin_b);
1105         MEM_freeN(bin_lum);
1106
1107         scopes->ok = 1;
1108 }
1109
1110 void scopes_free(Scopes *scopes)
1111 {
1112         if (scopes->waveform_1) {
1113                 MEM_freeN(scopes->waveform_1);
1114                 scopes->waveform_1 = NULL;
1115         }
1116         if (scopes->waveform_2) {
1117                 MEM_freeN(scopes->waveform_2);
1118                 scopes->waveform_2 = NULL;
1119         }
1120         if (scopes->waveform_3) {
1121                 MEM_freeN(scopes->waveform_3);
1122                 scopes->waveform_3 = NULL;
1123         }
1124         if (scopes->vecscope) {
1125                 MEM_freeN(scopes->vecscope);
1126                 scopes->vecscope = NULL;
1127         }
1128 }
1129
1130 void scopes_new(Scopes *scopes)
1131 {
1132         scopes->accuracy=30.0;
1133         scopes->hist.mode=HISTO_MODE_RGB;
1134         scopes->wavefrm_alpha=0.3;
1135         scopes->vecscope_alpha=0.3;
1136         scopes->wavefrm_height= 100;
1137         scopes->vecscope_height= 100;
1138         scopes->hist.height= 100;
1139         scopes->ok= 0;
1140         scopes->waveform_1 = NULL;
1141         scopes->waveform_2 = NULL;
1142         scopes->waveform_3 = NULL;
1143         scopes->vecscope = NULL;
1144 }