Potential bugfix #4141
[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 #include "MEM_guardedalloc.h"
36
37 #include "DNA_color_types.h"
38 #include "DNA_curve_types.h"
39 #include "DNA_image_types.h"
40 #include "DNA_texture_types.h"
41
42 #include "BKE_colortools.h"
43 #include "BKE_curve.h"
44 #include "BKE_global.h"
45 #include "BKE_ipo.h"
46 #include "BKE_main.h"
47 #include "BKE_utildefines.h"
48
49 #include "BLI_blenlib.h"
50 #include "BLI_arithb.h"
51 #include "BLI_threads.h"
52
53 #include "IMB_imbuf.h"
54 #include "IMB_imbuf_types.h"
55
56 /* NOTE: uses threadsafe malloc/calloc/free, for use in compositor */
57
58 /* ********************************* color curve ********************* */
59
60 /* ***************** operations on full struct ************* */
61
62 CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
63 {
64         CurveMapping *cumap;
65         int a;
66         
67         cumap= MEM_callocN(sizeof(CurveMapping), "new curvemap");
68         cumap->flag= CUMA_DO_CLIP;
69         if(tot==4) cumap->cur= 3;               /* rhms, hack for 'col' curve? */
70         
71         BLI_init_rctf(&cumap->curr, minx, maxx, miny, maxy);
72         cumap->clipr= cumap->curr;
73         
74         cumap->white[0]= cumap->white[1]= cumap->white[2]= 1.0f;
75         cumap->bwmul[0]= cumap->bwmul[1]= cumap->bwmul[2]= 1.0f;
76         
77         for(a=0; a<tot; a++) {
78                 cumap->cm[a].totpoint= 2;
79                 cumap->cm[a].curve= MEM_callocN(2*sizeof(CurveMapPoint), "curve points");
80                 
81                 cumap->cm[a].curve[0].x= minx;
82                 cumap->cm[a].curve[0].y= miny;
83                 cumap->cm[a].curve[1].x= maxx;
84                 cumap->cm[a].curve[1].y= maxy;
85         }       
86         return cumap;
87 }
88
89 void curvemapping_free(CurveMapping *cumap)
90 {
91         int a;
92         
93         if(cumap) {
94                 for(a=0; a<CM_TOT; a++) {
95                         if(cumap->cm[a].curve) MEM_freeN(cumap->cm[a].curve);
96                         if(cumap->cm[a].table) MEM_freeN(cumap->cm[a].table);
97                 }
98                 MEM_freeN(cumap);
99         }
100 }
101
102 CurveMapping *curvemapping_copy(CurveMapping *cumap)
103 {
104         int a;
105         
106         if(cumap) {
107                 CurveMapping *cumapn= MEM_dupallocN(cumap);
108                 for(a=0; a<CM_TOT; a++) {
109                         if(cumap->cm[a].curve) 
110                                 cumapn->cm[a].curve= MEM_dupallocN(cumap->cm[a].curve);
111                         if(cumap->cm[a].table) 
112                                 cumapn->cm[a].table= MEM_dupallocN(cumap->cm[a].table);
113                 }
114                 return cumapn;
115         }
116         return NULL;
117 }
118
119 void curvemapping_set_black_white(CurveMapping *cumap, float *black, float *white)
120 {
121         int a;
122         
123         if(white)
124                 VECCOPY(cumap->white, white);
125         if(black)
126                 VECCOPY(cumap->black, black);
127         
128         for(a=0; a<3; a++) {
129                 if(cumap->white[a]==cumap->black[a])
130                         cumap->bwmul[a]= 0.0f;
131                 else
132                         cumap->bwmul[a]= 1.0f/(cumap->white[a] - cumap->black[a]);
133         }       
134 }
135
136 /* ***************** operations on single curve ************* */
137 /* ********** NOTE: requires curvemapping_changed() call after ******** */
138
139 /* removes with flag set */
140 void curvemap_remove(CurveMap *cuma, int flag)
141 {
142         CurveMapPoint *cmp= MEM_mallocN((cuma->totpoint)*sizeof(CurveMapPoint), "curve points");
143         int a, b, removed=0;
144         
145         /* well, lets keep the two outer points! */
146         cmp[0]= cuma->curve[0];
147         for(a=1, b=1; a<cuma->totpoint-1; a++) {
148                 if(!(cuma->curve[a].flag & flag)) {
149                         cmp[b]= cuma->curve[a];
150                         b++;
151                 }
152                 else removed++;
153         }
154         cmp[b]= cuma->curve[a];
155         
156         MEM_freeN(cuma->curve);
157         cuma->curve= cmp;
158         cuma->totpoint -= removed;
159 }
160
161 void curvemap_insert(CurveMap *cuma, float x, float y)
162 {
163         CurveMapPoint *cmp= MEM_callocN((cuma->totpoint+1)*sizeof(CurveMapPoint), "curve points");
164         int a;
165         
166         memcpy(cmp, cuma->curve, (cuma->totpoint)*sizeof(CurveMapPoint));
167         MEM_freeN(cuma->curve);
168         cuma->curve= cmp;
169         
170         cuma->curve[cuma->totpoint].x= x;
171         cuma->curve[cuma->totpoint].y= y;
172         cuma->curve[cuma->totpoint].flag = CUMA_SELECT;
173         for(a=0; a<cuma->totpoint; a++, cmp++)
174                 cmp->flag= 0;
175         cuma->totpoint++;
176 }
177
178 void curvemap_reset(CurveMap *cuma, rctf *clipr)
179 {
180         cuma->totpoint= 2;
181         
182         cuma->curve[0].x= clipr->xmin;
183         cuma->curve[0].y= clipr->ymin;
184         cuma->curve[0].flag= 0;
185         cuma->curve[1].x= clipr->xmax;
186         cuma->curve[1].y= clipr->ymax;
187         cuma->curve[1].flag= 0;
188         
189         if(cuma->table) {
190                 MEM_freeN(cuma->table);
191                 cuma->table= NULL;
192         }
193 }
194
195 /* if type==1: vector, else auto */
196 void curvemap_sethandle(CurveMap *cuma, int type)
197 {
198         int a;
199         
200         for(a=0; a<cuma->totpoint; a++) {
201                 if(cuma->curve[a].flag & CUMA_SELECT) {
202                         if(type) cuma->curve[a].flag |= CUMA_VECTOR;
203                         else cuma->curve[a].flag &= ~CUMA_VECTOR;
204                 }
205         }
206 }
207
208 /* *********************** Making the tables and display ************** */
209
210 /* reduced copy of garbled calchandleNurb() code in curve.c */
211 static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
212 {
213         float *p1,*p2,*p3,pt[3];
214         float dx1,dy1, dx,dy, vx,vy, len,len1,len2;
215         
216         if(bezt->h1==0 && bezt->h2==0) return;
217         
218         p2= bezt->vec[1];
219         
220         if(prev==NULL) {
221                 p3= next->vec[1];
222                 pt[0]= 2*p2[0]- p3[0];
223                 pt[1]= 2*p2[1]- p3[1];
224                 p1= pt;
225         }
226         else p1= prev->vec[1];
227         
228         if(next==NULL) {
229                 p1= prev->vec[1];
230                 pt[0]= 2*p2[0]- p1[0];
231                 pt[1]= 2*p2[1]- p1[1];
232                 p3= pt;
233         }
234         else p3= next->vec[1];
235         
236         dx= p2[0]- p1[0];
237         dy= p2[1]- p1[1];
238
239         len1= (float)sqrt(dx*dx+dy*dy);
240         
241         dx1= p3[0]- p2[0];
242         dy1= p3[1]- p2[1];
243
244         len2= (float)sqrt(dx1*dx1+dy1*dy1);
245         
246         if(len1==0.0f) len1=1.0f;
247         if(len2==0.0f) len2=1.0f;
248         
249         if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) {    /* auto */
250                 vx= dx1/len2 + dx/len1;
251                 vy= dy1/len2 + dy/len1;
252                 
253                 len= 2.5614f*(float)sqrt(vx*vx + vy*vy);
254                 if(len!=0.0f) {
255                         
256                         if(bezt->h1==HD_AUTO) {
257                                 len1/=len;
258                                 *(p2-3)= *p2-vx*len1;
259                                 *(p2-2)= *(p2+1)-vy*len1;
260                         }
261                         if(bezt->h2==HD_AUTO) {
262                                 len2/=len;
263                                 *(p2+3)= *p2+vx*len2;
264                                 *(p2+4)= *(p2+1)+vy*len2;
265                         }
266                 }
267         }
268
269         if(bezt->h1==HD_VECT) { /* vector */
270                 dx/=3.0; 
271                 dy/=3.0; 
272                 *(p2-3)= *p2-dx;
273                 *(p2-2)= *(p2+1)-dy;
274         }
275         if(bezt->h2==HD_VECT) {
276                 dx1/=3.0; 
277                 dy1/=3.0; 
278                 *(p2+3)= *p2+dx1;
279                 *(p2+4)= *(p2+1)+dy1;
280         }
281 }
282
283 /* only creates a table for a single channel in CurveMapping */
284 static void curvemap_make_table(CurveMap *cuma, rctf *clipr)
285 {
286         CurveMapPoint *cmp= cuma->curve;
287         BezTriple *bezt;
288         float *fp, *allpoints, *lastpoint, curf, range;
289         int a, totpoint;
290         
291         if(cuma->curve==NULL) return;
292         
293         /* default rect also is table range */
294         cuma->mintable= clipr->xmin;
295         cuma->maxtable= clipr->xmax;
296         
297         /* hrmf... we now rely on blender ipo beziers, these are more advanced */
298         bezt= MEM_callocT(cuma->totpoint*sizeof(BezTriple), "beztarr");
299         
300         for(a=0; a<cuma->totpoint; a++) {
301                 cuma->mintable= MIN2(cuma->mintable, cmp[a].x);
302                 cuma->maxtable= MAX2(cuma->maxtable, cmp[a].x);
303                 bezt[a].vec[1][0]= cmp[a].x;
304                 bezt[a].vec[1][1]= cmp[a].y;
305                 if(cmp[a].flag & CUMA_VECTOR)
306                         bezt[a].h1= bezt[a].h2= HD_VECT;
307                 else
308                         bezt[a].h1= bezt[a].h2= HD_AUTO;
309         }
310         
311         for(a=0; a<cuma->totpoint; a++) {
312                 if(a==0)
313                         calchandle_curvemap(bezt, NULL, bezt+1, 0);
314                 else if(a==cuma->totpoint-1)
315                         calchandle_curvemap(bezt+a, bezt+a-1, NULL, 0);
316                 else
317                         calchandle_curvemap(bezt+a, bezt+a-1, bezt+a+1, 0);
318         }
319         
320         /* first and last handle need correction, instead of pointing to center of next/prev, 
321                 we let it point to the closest handle */
322         if(cuma->totpoint>2) {
323                 float hlen, nlen, vec[3];
324                 
325                 if(bezt[0].h2==HD_AUTO) {
326                         
327                         hlen= VecLenf(bezt[0].vec[1], bezt[0].vec[2]);  /* original handle length */
328                         /* clip handle point */
329                         VECCOPY(vec, bezt[1].vec[0]);
330                         if(vec[0] < bezt[0].vec[1][0])
331                                 vec[0]= bezt[0].vec[1][0];
332                         
333                         VecSubf(vec, vec, bezt[0].vec[1]);
334                         nlen= VecLength(vec);
335                         if(nlen>FLT_EPSILON) {
336                                 VecMulf(vec, hlen/nlen);
337                                 VecAddf(bezt[0].vec[2], vec, bezt[0].vec[1]);
338                         }
339                 }
340                 a= cuma->totpoint-1;
341                 if(bezt[a].h2==HD_AUTO) {
342                         
343                         hlen= VecLenf(bezt[a].vec[1], bezt[a].vec[0]);  /* original handle length */
344                         /* clip handle point */
345                         VECCOPY(vec, bezt[a-1].vec[2]);
346                         if(vec[0] > bezt[a].vec[1][0])
347                                 vec[0]= bezt[a].vec[1][0];
348                         
349                         VecSubf(vec, vec, bezt[a].vec[1]);
350                         nlen= VecLength(vec);
351                         if(nlen>FLT_EPSILON) {
352                                 VecMulf(vec, hlen/nlen);
353                                 VecAddf(bezt[a].vec[0], vec, bezt[a].vec[1]);
354                         }
355                 }
356         }       
357         /* make the bezier curve */
358         if(cuma->table)
359                 MEM_freeT(cuma->table);
360         totpoint= (cuma->totpoint-1)*CM_RESOL;
361         fp= allpoints= MEM_callocT(totpoint*2*sizeof(float), "table");
362         
363         for(a=0; a<cuma->totpoint-1; a++, fp += 2*CM_RESOL) {
364                 correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a+1].vec[0], bezt[a+1].vec[1]);
365                 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); 
366                 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);
367         }
368         
369         MEM_freeT(bezt);
370         
371         range= CM_TABLEDIV*(cuma->maxtable - cuma->mintable);
372         cuma->range= 1.0f/range;
373         
374         /* now make a table with CM_TABLE equal x distances */
375         fp= allpoints;
376         lastpoint= allpoints + 2*(totpoint-1);
377         cmp= MEM_callocT((CM_TABLE+1)*sizeof(CurveMapPoint), "dist table");
378         cmp[0].x= cuma->mintable;
379         cmp[0].y= allpoints[1];
380         
381         for(a=1; a<CM_TABLE; a++) {
382                 curf= cuma->mintable + range*(float)a;
383                 cmp[a].x= curf;
384                 
385                 /* get the first x coordinate larger than curf */
386                 while(curf >= fp[0] && fp!=lastpoint) {
387                         fp+=2;
388                 }
389                 if(fp==lastpoint)
390                         cmp[a].y= fp[1];
391                 else {
392                         float fac1= fp[0] - fp[-2];
393                         float fac2= fp[0] - curf;
394                         if(fac1 > FLT_EPSILON)
395                                 fac1= fac2/fac1;
396                         else
397                                 fac1= 0.0f;
398                         cmp[a].y= fac1*fp[-1] + (1.0f-fac1)*fp[1];
399                 }
400         }
401         cmp[CM_TABLE].x= cuma->maxtable;
402         cmp[CM_TABLE].y= allpoints[2*totpoint-1];
403         
404         MEM_freeT(allpoints);
405         cuma->table= cmp;
406 }
407
408 /* call when you do images etc, needs restore too. also verifies tables */
409 /* it uses a flag to prevent premul or free to happen twice */
410 void curvemapping_premultiply(CurveMapping *cumap, int restore)
411 {
412         int a;
413         
414         if(restore) {
415                 if(cumap->flag & CUMA_PREMULLED) {
416                         for(a=0; a<3; a++) {
417                                 MEM_freeT(cumap->cm[a].table);
418                                 cumap->cm[a].table= cumap->cm[a].premultable;
419                                 cumap->cm[a].premultable= NULL;
420                         }
421                         
422                         cumap->flag &= ~CUMA_PREMULLED;
423                 }
424         }
425         else {
426                 if((cumap->flag & CUMA_PREMULLED)==0) {
427                         /* verify and copy */
428                         for(a=0; a<3; a++) {
429                                 if(cumap->cm[a].table==NULL)
430                                         curvemap_make_table(cumap->cm+a, &cumap->clipr);
431                                 cumap->cm[a].premultable= cumap->cm[a].table;
432                                 cumap->cm[a].table= MEM_mallocT((CM_TABLE+1)*sizeof(CurveMapPoint), "premul table");
433                                 memcpy(cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE+1)*sizeof(CurveMapPoint));
434                         }
435                         
436                         if(cumap->cm[3].table==NULL)
437                                 curvemap_make_table(cumap->cm+3, &cumap->clipr);
438                 
439                         /* premul */
440                         for(a=0; a<3; a++) {
441                                 int b;
442                                 for(b=0; b<=CM_TABLE; b++) {
443                                         cumap->cm[a].table[b].y= curvemap_evaluateF(cumap->cm+3, cumap->cm[a].table[b].y);
444                                 }
445                         }
446                         
447                         cumap->flag |= CUMA_PREMULLED;
448                 }
449         }
450 }
451
452 static int sort_curvepoints(const void *a1, const void *a2)
453 {
454         const struct CurveMapPoint *x1=a1, *x2=a2;
455         
456         if( x1->x > x2->x ) return 1;
457         else if( x1->x < x2->x) return -1;
458         return 0;
459 }
460
461 /* ************************ more CurveMapping calls *************** */
462
463 /* note; only does current curvemap! */
464 void curvemapping_changed(CurveMapping *cumap, int rem_doubles)
465 {
466         CurveMap *cuma= cumap->cm+cumap->cur;
467         CurveMapPoint *cmp= cuma->curve;
468         rctf *clipr= &cumap->clipr;
469         float thresh= 0.01f*(clipr->xmax - clipr->xmin);
470         float dx, dy;
471         int a;
472         
473         /* clamp with clip */
474         if(cumap->flag & CUMA_DO_CLIP) {
475                 for(a=0; a<cuma->totpoint; a++) {
476                         if(cmp[a].x < clipr->xmin)
477                                 cmp[a].x= clipr->xmin;
478                         else if(cmp[a].x > clipr->xmax)
479                                 cmp[a].x= clipr->xmax;
480                         if(cmp[a].y < clipr->ymin)
481                                 cmp[a].y= clipr->ymin;
482                         else if(cmp[a].y > clipr->ymax)
483                                 cmp[a].y= clipr->ymax;
484                 }
485         }
486         
487         qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints);
488         
489         /* remove doubles, threshold set on 1% of default range */
490         if(rem_doubles && cuma->totpoint>2) {
491                 for(a=0; a<cuma->totpoint-1; a++) {
492                         dx= cmp[a].x - cmp[a+1].x;
493                         dy= cmp[a].y - cmp[a+1].y;
494                         if( sqrt(dx*dx + dy*dy) < thresh ) {
495                                 if(a==0) {
496                                         cmp[a+1].flag|= 2;
497                                         if(cmp[a+1].flag & CUMA_SELECT)
498                                                 cmp[a].flag |= CUMA_SELECT;
499                                 }
500                                 else {
501                                         cmp[a].flag|= 2;
502                                         if(cmp[a].flag & CUMA_SELECT)
503                                                 cmp[a+1].flag |= CUMA_SELECT;
504                                 }
505                                 break;  /* we assume 1 deletion per edit is ok */
506                         }
507                 }
508                 if(a != cuma->totpoint-1)
509                         curvemap_remove(cuma, 2);
510         }       
511         curvemap_make_table(cuma, clipr);
512 }
513
514 /* table should be verified */
515 float curvemap_evaluateF(CurveMap *cuma, float value)
516 {
517         float fi;
518         int i;
519
520         /* index in table */
521         fi= (value-cuma->mintable)*cuma->range;
522         i= (int)fi;
523         if(i<0) return cuma->table[0].y;
524         if(i>=CM_TABLE) return cuma->table[CM_TABLE].y;
525         
526         fi= fi-(float)i;
527         return (1.0f-fi)*cuma->table[i].y + (fi)*cuma->table[i+1].y; 
528 }
529
530 /* works with curve 'cur' */
531 float curvemapping_evaluateF(CurveMapping *cumap, int cur, float value)
532 {
533         CurveMap *cuma= cumap->cm+cur;
534         
535         /* allocate or bail out */
536         if(cuma->table==NULL) {
537                 curvemap_make_table(cuma, &cumap->clipr);
538                 if(cuma->table==NULL)
539                         return value;
540         }
541         return curvemap_evaluateF(cuma, value);
542 }
543
544 /* vector case */
545 void curvemapping_evaluate3F(CurveMapping *cumap, float *vecout, const float *vecin)
546 {
547         vecout[0]= curvemapping_evaluateF(cumap, 0, vecin[0]);
548         vecout[1]= curvemapping_evaluateF(cumap, 1, vecin[1]);
549         vecout[2]= curvemapping_evaluateF(cumap, 2, vecin[2]);
550 }
551
552 /* RGB case, no black/white points, no premult */
553 void curvemapping_evaluateRGBF(CurveMapping *cumap, float *vecout, const float *vecin)
554 {
555         vecout[0]= curvemapping_evaluateF(cumap, 0, curvemapping_evaluateF(cumap, 3, vecin[0]));
556         vecout[1]= curvemapping_evaluateF(cumap, 1, curvemapping_evaluateF(cumap, 3, vecin[1]));
557         vecout[2]= curvemapping_evaluateF(cumap, 2, curvemapping_evaluateF(cumap, 3, vecin[2]));
558 }
559
560
561 /* RGB with black/white points and premult. tables are checked */
562 void curvemapping_evaluate_premulRGBF(CurveMapping *cumap, float *vecout, const float *vecin)
563 {
564         float fac;
565         
566         fac= (vecin[0] - cumap->black[0])*cumap->bwmul[0];
567         vecout[0]= curvemap_evaluateF(cumap->cm, fac);
568         
569         fac= (vecin[1] - cumap->black[1])*cumap->bwmul[1];
570         vecout[1]= curvemap_evaluateF(cumap->cm+1, fac);
571         
572         fac= (vecin[2] - cumap->black[2])*cumap->bwmul[2];
573         vecout[2]= curvemap_evaluateF(cumap->cm+2, fac);
574 }
575
576 #define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
577
578 void curvemapping_do_image(CurveMapping *cumap, Image *ima)
579 {
580         int pixel;
581         
582         if(ima==NULL || ima->ibuf==NULL)
583                 return;
584         if(ima->ibuf->rect_float==NULL)
585                 IMB_float_from_rect(ima->ibuf);
586         else if(ima->ibuf->rect==NULL)
587                 imb_addrectImBuf(ima->ibuf);
588         
589         curvemapping_premultiply(cumap, 0);
590         
591         if(ima->ibuf->rect_float && ima->ibuf->rect) {
592                 float *pixf= ima->ibuf->rect_float;
593                 float col[3];
594                 char *pixc= (char *)ima->ibuf->rect;
595                 
596                 for(pixel= ima->ibuf->x*ima->ibuf->y; pixel>0; pixel--, pixf+=4, pixc+=4) {
597                         curvemapping_evaluate_premulRGBF(cumap, col, pixf);
598                         pixc[0]= FTOCHAR(col[0]);
599                         pixc[1]= FTOCHAR(col[1]);
600                         pixc[2]= FTOCHAR(col[2]);
601                         pixc[3]= FTOCHAR(pixf[3]);
602                 }
603         }
604         
605         curvemapping_premultiply(cumap, 1);
606 }
607
608 int curvemapping_RGBA_does_something(CurveMapping *cumap)
609 {
610         int a;
611         
612         if(cumap->black[0]!=0.0f) return 1;
613         if(cumap->black[1]!=0.0f) return 1;
614         if(cumap->black[2]!=0.0f) return 1;
615         if(cumap->white[0]!=1.0f) return 1;
616         if(cumap->white[1]!=1.0f) return 1;
617         if(cumap->white[2]!=1.0f) return 1;
618         
619         for(a=0; a<CM_TOT; a++) {
620                 if(cumap->cm[a].curve) {
621                         if(cumap->cm[a].totpoint!=2)  return 1;
622                         
623                         if(cumap->cm[a].curve[0].x != 0.0f) return 1;
624                         if(cumap->cm[a].curve[0].y != 0.0f) return 1;
625                         if(cumap->cm[a].curve[1].x != 1.0f) return 1;
626                         if(cumap->cm[a].curve[1].y != 1.0f) return 1;
627                 }
628         }
629         return 0;
630 }
631
632 void curvemapping_initialize(CurveMapping *cumap)
633 {
634         int a;
635         
636         if(cumap==NULL) return;
637         
638         for(a=0; a<CM_TOT; a++) {
639                 if(cumap->cm[a].table==NULL)
640                         curvemap_make_table(cumap->cm+a, &cumap->clipr);
641         }
642 }