svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r20855:20928
[blender.git] / source / blender / blenkernel / intern / colortools.c
1 /* 
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2005 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL/BL DUAL LICENSE BLOCK *****
28  */
29
30 #include <string.h>
31 #include <math.h>
32 #include <stdlib.h>
33 #include <float.h>
34
35 #ifdef WITH_LCMS
36 #include <lcms.h>
37 #endif
38
39 #include "MEM_guardedalloc.h"
40
41 #include "DNA_color_types.h"
42 #include "DNA_curve_types.h"
43 #include "DNA_image_types.h"
44 #include "DNA_texture_types.h"
45
46 #include "BKE_colortools.h"
47 #include "BKE_curve.h"
48 #include "BKE_global.h"
49 #include "BKE_ipo.h"
50 #include "BKE_image.h"
51 #include "BKE_main.h"
52 #include "BKE_utildefines.h"
53
54 #include "BLI_blenlib.h"
55 #include "BLI_arithb.h"
56 #include "BLI_threads.h"
57
58 #include "IMB_imbuf.h"
59 #include "IMB_imbuf_types.h"
60
61 /* ********************************* color curve ********************* */
62
63 /* ***************** operations on full struct ************* */
64
65 CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
66 {
67         CurveMapping *cumap;
68         int a;
69         float clipminx, clipminy, clipmaxx, clipmaxy;
70         
71         cumap= MEM_callocN(sizeof(CurveMapping), "new curvemap");
72         cumap->flag= CUMA_DO_CLIP;
73         if(tot==4) cumap->cur= 3;               /* rhms, hack for 'col' curve? */
74         
75         clipminx = MIN2(minx, maxx);
76         clipminy = MIN2(miny, maxy);
77         clipmaxx = MAX2(minx, maxx);
78         clipmaxy = MAX2(miny, maxy);
79         
80         BLI_init_rctf(&cumap->curr, clipminx, clipmaxx, clipminy, clipmaxy);
81         cumap->clipr= cumap->curr;
82         
83         cumap->white[0]= cumap->white[1]= cumap->white[2]= 1.0f;
84         cumap->bwmul[0]= cumap->bwmul[1]= cumap->bwmul[2]= 1.0f;
85         
86         for(a=0; a<tot; a++) {
87                 cumap->cm[a].flag= CUMA_EXTEND_EXTRAPOLATE;
88                 cumap->cm[a].totpoint= 2;
89                 cumap->cm[a].curve= MEM_callocN(2*sizeof(CurveMapPoint), "curve points");
90                 
91                 cumap->cm[a].curve[0].x= minx;
92                 cumap->cm[a].curve[0].y= miny;
93                 cumap->cm[a].curve[1].x= maxx;
94                 cumap->cm[a].curve[1].y= maxy;
95         }       
96         return cumap;
97 }
98
99 void curvemapping_free(CurveMapping *cumap)
100 {
101         int a;
102         
103         if(cumap) {
104                 for(a=0; a<CM_TOT; a++) {
105                         if(cumap->cm[a].curve) MEM_freeN(cumap->cm[a].curve);
106                         if(cumap->cm[a].table) MEM_freeN(cumap->cm[a].table);
107                 }
108                 MEM_freeN(cumap);
109         }
110 }
111
112 CurveMapping *curvemapping_copy(CurveMapping *cumap)
113 {
114         int a;
115         
116         if(cumap) {
117                 CurveMapping *cumapn= MEM_dupallocN(cumap);
118                 for(a=0; a<CM_TOT; a++) {
119                         if(cumap->cm[a].curve) 
120                                 cumapn->cm[a].curve= MEM_dupallocN(cumap->cm[a].curve);
121                         if(cumap->cm[a].table) 
122                                 cumapn->cm[a].table= MEM_dupallocN(cumap->cm[a].table);
123                 }
124                 return cumapn;
125         }
126         return NULL;
127 }
128
129 void curvemapping_set_black_white(CurveMapping *cumap, float *black, float *white)
130 {
131         int a;
132         
133         if(white)
134                 VECCOPY(cumap->white, white);
135         if(black)
136                 VECCOPY(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)
201 {
202         cuma->totpoint= 2;
203         
204         cuma->curve[0].x= clipr->xmin;
205         cuma->curve[0].y= clipr->ymin;
206         cuma->curve[0].flag= 0;
207         cuma->curve[1].x= clipr->xmax;
208         cuma->curve[1].y= clipr->ymax;
209         cuma->curve[1].flag= 0;
210         
211         if(cuma->table) {
212                 MEM_freeN(cuma->table);
213                 cuma->table= NULL;
214         }
215 }
216
217 /* if type==1: vector, else auto */
218 void curvemap_sethandle(CurveMap *cuma, int type)
219 {
220         int a;
221         
222         for(a=0; a<cuma->totpoint; a++) {
223                 if(cuma->curve[a].flag & CUMA_SELECT) {
224                         if(type) cuma->curve[a].flag |= CUMA_VECTOR;
225                         else cuma->curve[a].flag &= ~CUMA_VECTOR;
226                 }
227         }
228 }
229
230 /* *********************** Making the tables and display ************** */
231
232 /* reduced copy of garbled calchandleNurb() code in curve.c */
233 static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
234 {
235         float *p1,*p2,*p3,pt[3];
236         float dx1,dy1, dx,dy, vx,vy, len,len1,len2;
237         
238         if(bezt->h1==0 && bezt->h2==0) return;
239         
240         p2= bezt->vec[1];
241         
242         if(prev==NULL) {
243                 p3= next->vec[1];
244                 pt[0]= 2*p2[0]- p3[0];
245                 pt[1]= 2*p2[1]- p3[1];
246                 p1= pt;
247         }
248         else p1= prev->vec[1];
249         
250         if(next==NULL) {
251                 p1= prev->vec[1];
252                 pt[0]= 2*p2[0]- p1[0];
253                 pt[1]= 2*p2[1]- p1[1];
254                 p3= pt;
255         }
256         else p3= next->vec[1];
257         
258         dx= p2[0]- p1[0];
259         dy= p2[1]- p1[1];
260
261         len1= (float)sqrt(dx*dx+dy*dy);
262         
263         dx1= p3[0]- p2[0];
264         dy1= p3[1]- p2[1];
265
266         len2= (float)sqrt(dx1*dx1+dy1*dy1);
267         
268         if(len1==0.0f) len1=1.0f;
269         if(len2==0.0f) len2=1.0f;
270         
271         if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) {    /* auto */
272                 vx= dx1/len2 + dx/len1;
273                 vy= dy1/len2 + dy/len1;
274                 
275                 len= 2.5614f*(float)sqrt(vx*vx + vy*vy);
276                 if(len!=0.0f) {
277                         
278                         if(bezt->h1==HD_AUTO) {
279                                 len1/=len;
280                                 *(p2-3)= *p2-vx*len1;
281                                 *(p2-2)= *(p2+1)-vy*len1;
282                         }
283                         if(bezt->h2==HD_AUTO) {
284                                 len2/=len;
285                                 *(p2+3)= *p2+vx*len2;
286                                 *(p2+4)= *(p2+1)+vy*len2;
287                         }
288                 }
289         }
290
291         if(bezt->h1==HD_VECT) { /* vector */
292                 dx/=3.0; 
293                 dy/=3.0; 
294                 *(p2-3)= *p2-dx;
295                 *(p2-2)= *(p2+1)-dy;
296         }
297         if(bezt->h2==HD_VECT) {
298                 dx1/=3.0; 
299                 dy1/=3.0; 
300                 *(p2+3)= *p2+dx1;
301                 *(p2+4)= *(p2+1)+dy1;
302         }
303 }
304
305 /* in X, out Y. 
306    X is presumed to be outside first or last */
307 static float curvemap_calc_extend(CurveMap *cuma, float x, float *first, float *last)
308 {
309         if(x <= first[0]) {
310                 if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) {
311                         /* no extrapolate */
312                         return first[1];
313                 }
314                 else {
315                         if(cuma->ext_in[0]==0.0f)
316                                 return first[1] + cuma->ext_in[1]*10000.0f;
317                         else
318                                 return first[1] + cuma->ext_in[1]*(x - first[0])/cuma->ext_in[0];
319                 }
320         }
321         else if(x >= last[0]) {
322                 if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) {
323                         /* no extrapolate */
324                         return last[1];
325                 }
326                 else {
327                         if(cuma->ext_out[0]==0.0f)
328                                 return last[1] - cuma->ext_out[1]*10000.0f;
329                         else
330                                 return last[1] + cuma->ext_out[1]*(x - last[0])/cuma->ext_out[0];
331                 }
332         }
333         return 0.0f;
334 }
335
336 /* only creates a table for a single channel in CurveMapping */
337 static void curvemap_make_table(CurveMap *cuma, rctf *clipr)
338 {
339         CurveMapPoint *cmp= cuma->curve;
340         BezTriple *bezt;
341         float *fp, *allpoints, *lastpoint, curf, range;
342         int a, totpoint;
343         
344         if(cuma->curve==NULL) return;
345         
346         /* default rect also is table range */
347         cuma->mintable= clipr->xmin;
348         cuma->maxtable= clipr->xmax;
349         
350         /* hrmf... we now rely on blender ipo beziers, these are more advanced */
351         bezt= MEM_callocN(cuma->totpoint*sizeof(BezTriple), "beztarr");
352         
353         for(a=0; a<cuma->totpoint; a++) {
354                 cuma->mintable= MIN2(cuma->mintable, cmp[a].x);
355                 cuma->maxtable= MAX2(cuma->maxtable, cmp[a].x);
356                 bezt[a].vec[1][0]= cmp[a].x;
357                 bezt[a].vec[1][1]= cmp[a].y;
358                 if(cmp[a].flag & CUMA_VECTOR)
359                         bezt[a].h1= bezt[a].h2= HD_VECT;
360                 else
361                         bezt[a].h1= bezt[a].h2= HD_AUTO;
362         }
363         
364         for(a=0; a<cuma->totpoint; a++) {
365                 if(a==0)
366                         calchandle_curvemap(bezt, NULL, bezt+1, 0);
367                 else if(a==cuma->totpoint-1)
368                         calchandle_curvemap(bezt+a, bezt+a-1, NULL, 0);
369                 else
370                         calchandle_curvemap(bezt+a, bezt+a-1, bezt+a+1, 0);
371         }
372         
373         /* first and last handle need correction, instead of pointing to center of next/prev, 
374                 we let it point to the closest handle */
375         if(cuma->totpoint>2) {
376                 float hlen, nlen, vec[3];
377                 
378                 if(bezt[0].h2==HD_AUTO) {
379                         
380                         hlen= VecLenf(bezt[0].vec[1], bezt[0].vec[2]);  /* original handle length */
381                         /* clip handle point */
382                         VECCOPY(vec, bezt[1].vec[0]);
383                         if(vec[0] < bezt[0].vec[1][0])
384                                 vec[0]= bezt[0].vec[1][0];
385                         
386                         VecSubf(vec, vec, bezt[0].vec[1]);
387                         nlen= VecLength(vec);
388                         if(nlen>FLT_EPSILON) {
389                                 VecMulf(vec, hlen/nlen);
390                                 VecAddf(bezt[0].vec[2], vec, bezt[0].vec[1]);
391                                 VecSubf(bezt[0].vec[0], bezt[0].vec[1], vec);
392                         }
393                 }
394                 a= cuma->totpoint-1;
395                 if(bezt[a].h2==HD_AUTO) {
396                         
397                         hlen= VecLenf(bezt[a].vec[1], bezt[a].vec[0]);  /* original handle length */
398                         /* clip handle point */
399                         VECCOPY(vec, bezt[a-1].vec[2]);
400                         if(vec[0] > bezt[a].vec[1][0])
401                                 vec[0]= bezt[a].vec[1][0];
402                         
403                         VecSubf(vec, vec, bezt[a].vec[1]);
404                         nlen= VecLength(vec);
405                         if(nlen>FLT_EPSILON) {
406                                 VecMulf(vec, hlen/nlen);
407                                 VecAddf(bezt[a].vec[0], vec, bezt[a].vec[1]);
408                                 VecSubf(bezt[a].vec[2], bezt[a].vec[1], vec);
409                         }
410                 }
411         }       
412         /* make the bezier curve */
413         if(cuma->table)
414                 MEM_freeN(cuma->table);
415         totpoint= (cuma->totpoint-1)*CM_RESOL;
416         fp= allpoints= MEM_callocN(totpoint*2*sizeof(float), "table");
417         
418         for(a=0; a<cuma->totpoint-1; a++, fp += 2*CM_RESOL) {
419                 correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a+1].vec[0], bezt[a+1].vec[1]);
420                 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); 
421                 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);
422         }
423         
424         /* store first and last handle for extrapolation, unit length */
425         cuma->ext_in[0]= bezt[0].vec[0][0] - bezt[0].vec[1][0];
426         cuma->ext_in[1]= bezt[0].vec[0][1] - bezt[0].vec[1][1];
427         range= sqrt(cuma->ext_in[0]*cuma->ext_in[0] + cuma->ext_in[1]*cuma->ext_in[1]);
428         cuma->ext_in[0]/= range;
429         cuma->ext_in[1]/= range;
430         
431         a= cuma->totpoint-1;
432         cuma->ext_out[0]= bezt[a].vec[1][0] - bezt[a].vec[2][0];
433         cuma->ext_out[1]= bezt[a].vec[1][1] - bezt[a].vec[2][1];
434         range= sqrt(cuma->ext_out[0]*cuma->ext_out[0] + cuma->ext_out[1]*cuma->ext_out[1]);
435         cuma->ext_out[0]/= range;
436         cuma->ext_out[1]/= range;
437         
438         /* cleanup */
439         MEM_freeN(bezt);
440
441         range= CM_TABLEDIV*(cuma->maxtable - cuma->mintable);
442         cuma->range= 1.0f/range;
443         
444         /* now make a table with CM_TABLE equal x distances */
445         fp= allpoints;
446         lastpoint= allpoints + 2*(totpoint-1);
447         cmp= MEM_callocN((CM_TABLE+1)*sizeof(CurveMapPoint), "dist table");
448         
449         for(a=0; a<=CM_TABLE; a++) {
450                 curf= cuma->mintable + range*(float)a;
451                 cmp[a].x= curf;
452                 
453                 /* get the first x coordinate larger than curf */
454                 while(curf >= fp[0] && fp!=lastpoint) {
455                         fp+=2;
456                 }
457                 if(fp==allpoints || (curf >= fp[0] && fp==lastpoint))
458                         cmp[a].y= curvemap_calc_extend(cuma, curf, allpoints, lastpoint);
459                 else {
460                         float fac1= fp[0] - fp[-2];
461                         float fac2= fp[0] - curf;
462                         if(fac1 > FLT_EPSILON)
463                                 fac1= fac2/fac1;
464                         else
465                                 fac1= 0.0f;
466                         cmp[a].y= fac1*fp[-1] + (1.0f-fac1)*fp[1];
467                 }
468         }
469         
470         MEM_freeN(allpoints);
471         cuma->table= cmp;
472 }
473
474 /* call when you do images etc, needs restore too. also verifies tables */
475 /* it uses a flag to prevent premul or free to happen twice */
476 void curvemapping_premultiply(CurveMapping *cumap, int restore)
477 {
478         int a;
479         
480         if(restore) {
481                 if(cumap->flag & CUMA_PREMULLED) {
482                         for(a=0; a<3; a++) {
483                                 MEM_freeN(cumap->cm[a].table);
484                                 cumap->cm[a].table= cumap->cm[a].premultable;
485                                 cumap->cm[a].premultable= NULL;
486                         }
487                         
488                         cumap->flag &= ~CUMA_PREMULLED;
489                 }
490         }
491         else {
492                 if((cumap->flag & CUMA_PREMULLED)==0) {
493                         /* verify and copy */
494                         for(a=0; a<3; a++) {
495                                 if(cumap->cm[a].table==NULL)
496                                         curvemap_make_table(cumap->cm+a, &cumap->clipr);
497                                 cumap->cm[a].premultable= cumap->cm[a].table;
498                                 cumap->cm[a].table= MEM_mallocN((CM_TABLE+1)*sizeof(CurveMapPoint), "premul table");
499                                 memcpy(cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE+1)*sizeof(CurveMapPoint));
500                         }
501                         
502                         if(cumap->cm[3].table==NULL)
503                                 curvemap_make_table(cumap->cm+3, &cumap->clipr);
504                 
505                         /* premul */
506                         for(a=0; a<3; a++) {
507                                 int b;
508                                 for(b=0; b<=CM_TABLE; b++) {
509                                         cumap->cm[a].table[b].y= curvemap_evaluateF(cumap->cm+3, cumap->cm[a].table[b].y);
510                                 }
511                         }
512                         
513                         cumap->flag |= CUMA_PREMULLED;
514                 }
515         }
516 }
517
518 static int sort_curvepoints(const void *a1, const void *a2)
519 {
520         const struct CurveMapPoint *x1=a1, *x2=a2;
521         
522         if( x1->x > x2->x ) return 1;
523         else if( x1->x < x2->x) return -1;
524         return 0;
525 }
526
527 /* ************************ more CurveMapping calls *************** */
528
529 /* note; only does current curvemap! */
530 void curvemapping_changed(CurveMapping *cumap, int rem_doubles)
531 {
532         CurveMap *cuma= cumap->cm+cumap->cur;
533         CurveMapPoint *cmp= cuma->curve;
534         rctf *clipr= &cumap->clipr;
535         float thresh= 0.01f*(clipr->xmax - clipr->xmin);
536         float dx= 0.0f, dy= 0.0f;
537         int a;
538         
539         /* clamp with clip */
540         if(cumap->flag & CUMA_DO_CLIP) {
541                 for(a=0; a<cuma->totpoint; a++) {
542                         if(cmp[a].flag & CUMA_SELECT) {
543                                 if(cmp[a].x < clipr->xmin)
544                                         dx= MIN2(dx, cmp[a].x - clipr->xmin);
545                                 else if(cmp[a].x > clipr->xmax)
546                                         dx= MAX2(dx, cmp[a].x - clipr->xmax);
547                                 if(cmp[a].y < clipr->ymin)
548                                         dy= MIN2(dy, cmp[a].y - clipr->ymin);
549                                 else if(cmp[a].y > clipr->ymax)
550                                         dy= MAX2(dy, cmp[a].y - clipr->ymax);
551                         }
552                 }
553                 for(a=0; a<cuma->totpoint; a++) {
554                         if(cmp[a].flag & CUMA_SELECT) {
555                                 cmp[a].x -= dx;
556                                 cmp[a].y -= dy;
557                         }
558                 }
559         }
560         
561         
562         qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints);
563         
564         /* remove doubles, threshold set on 1% of default range */
565         if(rem_doubles && cuma->totpoint>2) {
566                 for(a=0; a<cuma->totpoint-1; a++) {
567                         dx= cmp[a].x - cmp[a+1].x;
568                         dy= cmp[a].y - cmp[a+1].y;
569                         if( sqrt(dx*dx + dy*dy) < thresh ) {
570                                 if(a==0) {
571                                         cmp[a+1].flag|= 2;
572                                         if(cmp[a+1].flag & CUMA_SELECT)
573                                                 cmp[a].flag |= CUMA_SELECT;
574                                 }
575                                 else {
576                                         cmp[a].flag|= 2;
577                                         if(cmp[a].flag & CUMA_SELECT)
578                                                 cmp[a+1].flag |= CUMA_SELECT;
579                                 }
580                                 break;  /* we assume 1 deletion per edit is ok */
581                         }
582                 }
583                 if(a != cuma->totpoint-1)
584                         curvemap_remove(cuma, 2);
585         }       
586         curvemap_make_table(cuma, clipr);
587 }
588
589 /* table should be verified */
590 float curvemap_evaluateF(CurveMap *cuma, float value)
591 {
592         float fi;
593         int i;
594
595         /* index in table */
596         fi= (value-cuma->mintable)*cuma->range;
597         i= (int)fi;
598         
599         /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */
600         if(fi<0.0f || fi>CM_TABLE)
601                 return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x);
602         else {
603                 if(i<0) return cuma->table[0].y;
604                 if(i>=CM_TABLE) return cuma->table[CM_TABLE].y;
605                 
606                 fi= fi-(float)i;
607                 return (1.0f-fi)*cuma->table[i].y + (fi)*cuma->table[i+1].y; 
608         }
609 }
610
611 /* works with curve 'cur' */
612 float curvemapping_evaluateF(CurveMapping *cumap, int cur, float value)
613 {
614         CurveMap *cuma= cumap->cm+cur;
615         
616         /* allocate or bail out */
617         if(cuma->table==NULL) {
618                 curvemap_make_table(cuma, &cumap->clipr);
619                 if(cuma->table==NULL)
620                         return value;
621         }
622         return curvemap_evaluateF(cuma, value);
623 }
624
625 /* vector case */
626 void curvemapping_evaluate3F(CurveMapping *cumap, float *vecout, const float *vecin)
627 {
628         vecout[0]= curvemapping_evaluateF(cumap, 0, vecin[0]);
629         vecout[1]= curvemapping_evaluateF(cumap, 1, vecin[1]);
630         vecout[2]= curvemapping_evaluateF(cumap, 2, vecin[2]);
631 }
632
633 /* RGB case, no black/white points, no premult */
634 void curvemapping_evaluateRGBF(CurveMapping *cumap, float *vecout, const float *vecin)
635 {
636         vecout[0]= curvemapping_evaluateF(cumap, 0, curvemapping_evaluateF(cumap, 3, vecin[0]));
637         vecout[1]= curvemapping_evaluateF(cumap, 1, curvemapping_evaluateF(cumap, 3, vecin[1]));
638         vecout[2]= curvemapping_evaluateF(cumap, 2, curvemapping_evaluateF(cumap, 3, vecin[2]));
639 }
640
641
642 /* RGB with black/white points and premult. tables are checked */
643 void curvemapping_evaluate_premulRGBF(CurveMapping *cumap, float *vecout, const float *vecin)
644 {
645         float fac;
646         
647         fac= (vecin[0] - cumap->black[0])*cumap->bwmul[0];
648         vecout[0]= curvemap_evaluateF(cumap->cm, fac);
649         
650         fac= (vecin[1] - cumap->black[1])*cumap->bwmul[1];
651         vecout[1]= curvemap_evaluateF(cumap->cm+1, fac);
652         
653         fac= (vecin[2] - cumap->black[2])*cumap->bwmul[2];
654         vecout[2]= curvemap_evaluateF(cumap->cm+2, fac);
655 }
656
657 void colorcorrection_do_ibuf(ImBuf *ibuf, const char *profile)
658 {
659         if (ibuf->crect == NULL)
660         {
661 #ifdef WITH_LCMS
662                 cmsHPROFILE imageProfile, proofingProfile;
663                 cmsHTRANSFORM hTransform;
664                 
665                 ibuf->crect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(int), "imbuf crect");
666
667                 imageProfile  = cmsCreate_sRGBProfile();
668                 proofingProfile = cmsOpenProfileFromFile(profile, "r");
669                 
670                 cmsErrorAction(LCMS_ERROR_SHOW);
671         
672                 hTransform = cmsCreateProofingTransform(imageProfile, TYPE_RGBA_8, imageProfile, TYPE_RGBA_8, 
673                                                   proofingProfile,
674                                                   INTENT_ABSOLUTE_COLORIMETRIC,
675                                                   INTENT_ABSOLUTE_COLORIMETRIC,
676                                                   cmsFLAGS_SOFTPROOFING);
677         
678                 cmsDoTransform(hTransform, ibuf->rect, ibuf->crect, ibuf->x * ibuf->y);
679         
680                 cmsDeleteTransform(hTransform);
681                 cmsCloseProfile(imageProfile);
682                 cmsCloseProfile(proofingProfile);
683 #else
684                 ibuf->crect = ibuf->rect;
685 #endif
686         }
687 }
688
689
690 void curvemapping_do_ibuf(CurveMapping *cumap, ImBuf *ibuf)
691 {
692         int pixel;
693         
694         if(ibuf==NULL)
695                 return;
696         if(ibuf->rect_float==NULL)
697                 IMB_float_from_rect(ibuf);
698         else if(ibuf->rect==NULL)
699                 imb_addrectImBuf(ibuf);
700         
701         curvemapping_premultiply(cumap, 0);
702         
703         if(ibuf->rect_float && ibuf->rect) {
704                 float *pixf= ibuf->rect_float;
705                 float col[3];
706                 int stride= 4;
707                 char *pixc= (char *)ibuf->rect;
708                 
709                 if(ibuf->channels)
710                         stride= ibuf->channels;
711                 
712                 for(pixel= ibuf->x*ibuf->y; pixel>0; pixel--, pixf+=stride, pixc+=4) {
713                         if(stride<3) {
714                                 col[0]= curvemap_evaluateF(cumap->cm, *pixf);
715                                 pixc[1]= pixc[2]= pixc[3]= pixc[0]= FTOCHAR(col[0]);
716                         }
717                         else {
718                                 curvemapping_evaluate_premulRGBF(cumap, col, pixf);
719                                 pixc[0]= FTOCHAR(col[0]);
720                                 pixc[1]= FTOCHAR(col[1]);
721                                 pixc[2]= FTOCHAR(col[2]);
722                                 if(stride>3)
723                                         pixc[3]= FTOCHAR(pixf[3]);
724                                 else
725                                         pixc[3]= 255;
726                         }
727                 }
728         }
729         
730         curvemapping_premultiply(cumap, 1);
731 }
732
733 int curvemapping_RGBA_does_something(CurveMapping *cumap)
734 {
735         int a;
736         
737         if(cumap->black[0]!=0.0f) return 1;
738         if(cumap->black[1]!=0.0f) return 1;
739         if(cumap->black[2]!=0.0f) return 1;
740         if(cumap->white[0]!=1.0f) return 1;
741         if(cumap->white[1]!=1.0f) return 1;
742         if(cumap->white[2]!=1.0f) return 1;
743         
744         for(a=0; a<CM_TOT; a++) {
745                 if(cumap->cm[a].curve) {
746                         if(cumap->cm[a].totpoint!=2)  return 1;
747                         
748                         if(cumap->cm[a].curve[0].x != 0.0f) return 1;
749                         if(cumap->cm[a].curve[0].y != 0.0f) return 1;
750                         if(cumap->cm[a].curve[1].x != 1.0f) return 1;
751                         if(cumap->cm[a].curve[1].y != 1.0f) return 1;
752                 }
753         }
754         return 0;
755 }
756
757 void curvemapping_initialize(CurveMapping *cumap)
758 {
759         int a;
760         
761         if(cumap==NULL) return;
762         
763         for(a=0; a<CM_TOT; a++) {
764                 if(cumap->cm[a].table==NULL)
765                         curvemap_make_table(cumap->cm+a, &cumap->clipr);
766         }
767 }
768
769 void curvemapping_table_RGBA(CurveMapping *cumap, float **array, int *size)
770 {
771         int a;
772         
773         *size = CM_TABLE+1;
774         *array = MEM_callocN(sizeof(float)*(*size)*4, "CurveMapping");
775         curvemapping_initialize(cumap);
776
777         for(a=0; a<*size; a++) {
778                 if(cumap->cm[0].table)
779                         (*array)[a*4+0]= cumap->cm[0].table[a].y;
780                 if(cumap->cm[1].table)
781                         (*array)[a*4+1]= cumap->cm[1].table[a].y;
782                 if(cumap->cm[2].table)
783                         (*array)[a*4+2]= cumap->cm[2].table[a].y;
784                 if(cumap->cm[3].table)
785                         (*array)[a*4+3]= cumap->cm[3].table[a].y;
786         }
787 }
788