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