Blender V2.61 - r43446

colortools.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2005 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL/BL DUAL LICENSE BLOCK *****
00026  */
00027 
00033 #include <string.h>
00034 #include <math.h>
00035 #include <stdlib.h>
00036 #include <float.h>
00037 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "DNA_color_types.h"
00041 #include "DNA_curve_types.h"
00042 
00043 #include "BLI_blenlib.h"
00044 #include "BLI_math.h"
00045 #include "BLI_utildefines.h"
00046 
00047 #include "BKE_colortools.h"
00048 #include "BKE_curve.h"
00049 #include "BKE_fcurve.h"
00050 
00051 
00052 #include "IMB_imbuf.h"
00053 #include "IMB_imbuf_types.h"
00054 
00055 /* ********************************* color curve ********************* */
00056 
00057 /* ***************** operations on full struct ************* */
00058 
00059 CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
00060 {
00061     CurveMapping *cumap;
00062     int a;
00063     float clipminx, clipminy, clipmaxx, clipmaxy;
00064     
00065     cumap= MEM_callocN(sizeof(CurveMapping), "new curvemap");
00066     cumap->flag= CUMA_DO_CLIP;
00067     if(tot==4) cumap->cur= 3;       /* rhms, hack for 'col' curve? */
00068     
00069     clipminx = MIN2(minx, maxx);
00070     clipminy = MIN2(miny, maxy);
00071     clipmaxx = MAX2(minx, maxx);
00072     clipmaxy = MAX2(miny, maxy);
00073     
00074     BLI_init_rctf(&cumap->curr, clipminx, clipmaxx, clipminy, clipmaxy);
00075     cumap->clipr= cumap->curr;
00076     
00077     cumap->white[0]= cumap->white[1]= cumap->white[2]= 1.0f;
00078     cumap->bwmul[0]= cumap->bwmul[1]= cumap->bwmul[2]= 1.0f;
00079     
00080     for(a=0; a<tot; a++) {
00081         cumap->cm[a].flag= CUMA_EXTEND_EXTRAPOLATE;
00082         cumap->cm[a].totpoint= 2;
00083         cumap->cm[a].curve= MEM_callocN(2*sizeof(CurveMapPoint), "curve points");
00084         
00085         cumap->cm[a].curve[0].x= minx;
00086         cumap->cm[a].curve[0].y= miny;
00087         cumap->cm[a].curve[1].x= maxx;
00088         cumap->cm[a].curve[1].y= maxy;
00089     }   
00090 
00091     cumap->changed_timestamp = 0;
00092 
00093     return cumap;
00094 }
00095 
00096 void curvemapping_free(CurveMapping *cumap)
00097 {
00098     int a;
00099     
00100     if(cumap) {
00101         for(a=0; a<CM_TOT; a++) {
00102             if(cumap->cm[a].curve) MEM_freeN(cumap->cm[a].curve);
00103             if(cumap->cm[a].table) MEM_freeN(cumap->cm[a].table);
00104             if(cumap->cm[a].premultable) MEM_freeN(cumap->cm[a].premultable);
00105         }
00106         MEM_freeN(cumap);
00107     }
00108 }
00109 
00110 CurveMapping *curvemapping_copy(CurveMapping *cumap)
00111 {
00112     int a;
00113     
00114     if(cumap) {
00115         CurveMapping *cumapn= MEM_dupallocN(cumap);
00116         for(a=0; a<CM_TOT; a++) {
00117             if(cumap->cm[a].curve) 
00118                 cumapn->cm[a].curve= MEM_dupallocN(cumap->cm[a].curve);
00119             if(cumap->cm[a].table) 
00120                 cumapn->cm[a].table= MEM_dupallocN(cumap->cm[a].table);
00121             if(cumap->cm[a].premultable) 
00122                 cumapn->cm[a].premultable= MEM_dupallocN(cumap->cm[a].premultable);
00123         }
00124         return cumapn;
00125     }
00126     return NULL;
00127 }
00128 
00129 void curvemapping_set_black_white(CurveMapping *cumap, const float black[3], const float white[3])
00130 {
00131     int a;
00132     
00133     if(white)
00134         copy_v3_v3(cumap->white, white);
00135     if(black)
00136         copy_v3_v3(cumap->black, black);
00137     
00138     for(a=0; a<3; a++) {
00139         if(cumap->white[a]==cumap->black[a])
00140             cumap->bwmul[a]= 0.0f;
00141         else
00142             cumap->bwmul[a]= 1.0f/(cumap->white[a] - cumap->black[a]);
00143     }   
00144 }
00145 
00146 /* ***************** operations on single curve ************* */
00147 /* ********** NOTE: requires curvemapping_changed() call after ******** */
00148 
00149 /* removes with flag set */
00150 void curvemap_remove(CurveMap *cuma, int flag)
00151 {
00152     CurveMapPoint *cmp= MEM_mallocN((cuma->totpoint)*sizeof(CurveMapPoint), "curve points");
00153     int a, b, removed=0;
00154     
00155     /* well, lets keep the two outer points! */
00156     cmp[0]= cuma->curve[0];
00157     for(a=1, b=1; a<cuma->totpoint-1; a++) {
00158         if(!(cuma->curve[a].flag & flag)) {
00159             cmp[b]= cuma->curve[a];
00160             b++;
00161         }
00162         else removed++;
00163     }
00164     cmp[b]= cuma->curve[a];
00165     
00166     MEM_freeN(cuma->curve);
00167     cuma->curve= cmp;
00168     cuma->totpoint -= removed;
00169 }
00170 
00171 void curvemap_insert(CurveMap *cuma, float x, float y)
00172 {
00173     CurveMapPoint *cmp= MEM_callocN((cuma->totpoint+1)*sizeof(CurveMapPoint), "curve points");
00174     int a, b, foundloc= 0;
00175         
00176     /* insert fragments of the old one and the new point to the new curve */
00177     cuma->totpoint++;
00178     for(a=0, b=0; a<cuma->totpoint; a++) {
00179         if((x < cuma->curve[a].x) && !foundloc) {
00180             cmp[a].x= x;
00181             cmp[a].y= y;
00182             cmp[a].flag= CUMA_SELECT;
00183             foundloc= 1;
00184         }
00185         else {
00186             cmp[a].x= cuma->curve[b].x;
00187             cmp[a].y= cuma->curve[b].y;
00188             cmp[a].flag= cuma->curve[b].flag;
00189             cmp[a].flag &= ~CUMA_SELECT; /* make sure old points don't remain selected */
00190             cmp[a].shorty= cuma->curve[b].shorty;
00191             b++;
00192         }
00193     }
00194 
00195     /* free old curve and replace it with new one */
00196     MEM_freeN(cuma->curve);
00197     cuma->curve= cmp;
00198 }
00199 
00200 void curvemap_reset(CurveMap *cuma, rctf *clipr, int preset, int slope)
00201 {
00202     if(cuma->curve)
00203         MEM_freeN(cuma->curve);
00204 
00205     switch(preset) {
00206         case CURVE_PRESET_LINE: cuma->totpoint= 2; break;
00207         case CURVE_PRESET_SHARP: cuma->totpoint= 4; break;
00208         case CURVE_PRESET_SMOOTH: cuma->totpoint= 4; break;
00209         case CURVE_PRESET_MAX: cuma->totpoint= 2; break;
00210         case CURVE_PRESET_MID9: cuma->totpoint= 9; break;
00211         case CURVE_PRESET_ROUND: cuma->totpoint= 4; break;
00212         case CURVE_PRESET_ROOT: cuma->totpoint= 4; break;
00213     }
00214 
00215     cuma->curve= MEM_callocN(cuma->totpoint*sizeof(CurveMapPoint), "curve points");
00216 
00217     switch(preset) {
00218         case CURVE_PRESET_LINE:
00219             cuma->curve[0].x= clipr->xmin;
00220             cuma->curve[0].y= clipr->ymax;
00221             cuma->curve[0].flag= 0;
00222             cuma->curve[1].x= clipr->xmax;
00223             cuma->curve[1].y= clipr->ymin;
00224             cuma->curve[1].flag= 0;
00225             break;
00226         case CURVE_PRESET_SHARP:
00227             cuma->curve[0].x= 0;
00228             cuma->curve[0].y= 1;
00229             cuma->curve[1].x= 0.25;
00230             cuma->curve[1].y= 0.50;
00231             cuma->curve[2].x= 0.75;
00232             cuma->curve[2].y= 0.04;
00233             cuma->curve[3].x= 1;
00234             cuma->curve[3].y= 0;
00235             break;
00236         case CURVE_PRESET_SMOOTH:
00237             cuma->curve[0].x= 0;
00238             cuma->curve[0].y= 1;
00239             cuma->curve[1].x= 0.25;
00240             cuma->curve[1].y= 0.94;
00241             cuma->curve[2].x= 0.75;
00242             cuma->curve[2].y= 0.06;
00243             cuma->curve[3].x= 1;
00244             cuma->curve[3].y= 0;
00245             break;
00246         case CURVE_PRESET_MAX:
00247             cuma->curve[0].x= 0;
00248             cuma->curve[0].y= 1;
00249             cuma->curve[1].x= 1;
00250             cuma->curve[1].y= 1;
00251             break;
00252         case CURVE_PRESET_MID9:
00253             {
00254                 int i;
00255                 for (i=0; i < cuma->totpoint; i++)
00256                 {
00257                     cuma->curve[i].x= i / ((float)cuma->totpoint-1);
00258                     cuma->curve[i].y= 0.5;
00259                 }
00260             }
00261             break;
00262         case CURVE_PRESET_ROUND:
00263             cuma->curve[0].x= 0;
00264             cuma->curve[0].y= 1;
00265             cuma->curve[1].x= 0.5;
00266             cuma->curve[1].y= 0.90;
00267             cuma->curve[2].x= 0.86;
00268             cuma->curve[2].y= 0.5;
00269             cuma->curve[3].x= 1;
00270             cuma->curve[3].y= 0;
00271             break;
00272         case CURVE_PRESET_ROOT:
00273             cuma->curve[0].x= 0;
00274             cuma->curve[0].y= 1;
00275             cuma->curve[1].x= 0.25;
00276             cuma->curve[1].y= 0.95;
00277             cuma->curve[2].x= 0.75;
00278             cuma->curve[2].y= 0.44;
00279             cuma->curve[3].x= 1;
00280             cuma->curve[3].y= 0;
00281             break;
00282     }
00283 
00284     /* mirror curve in x direction to have positive slope
00285      * rather than default negative slope */
00286     if (slope == CURVEMAP_SLOPE_POSITIVE) {
00287         int i, last=cuma->totpoint-1;
00288         CurveMapPoint *newpoints= MEM_dupallocN(cuma->curve);
00289         
00290         for (i=0; i<cuma->totpoint; i++) {
00291             newpoints[i].y = cuma->curve[last-i].y;
00292         }
00293         
00294         MEM_freeN(cuma->curve);
00295         cuma->curve = newpoints;
00296     }
00297     
00298     if(cuma->table) {
00299         MEM_freeN(cuma->table);
00300         cuma->table= NULL;
00301     }
00302 }
00303 
00304 /* if type==1: vector, else auto */
00305 void curvemap_sethandle(CurveMap *cuma, int type)
00306 {
00307     int a;
00308     
00309     for(a=0; a<cuma->totpoint; a++) {
00310         if(cuma->curve[a].flag & CUMA_SELECT) {
00311             if(type) cuma->curve[a].flag |= CUMA_VECTOR;
00312             else cuma->curve[a].flag &= ~CUMA_VECTOR;
00313         }
00314     }
00315 }
00316 
00317 /* *********************** Making the tables and display ************** */
00318 
00319 /* reduced copy of garbled calchandleNurb() code in curve.c */
00320 static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int UNUSED(mode))
00321 {
00322     float *p1,*p2,*p3,pt[3];
00323     float len,len_a, len_b;
00324     float dvec_a[2], dvec_b[2];
00325 
00326     if(bezt->h1==0 && bezt->h2==0) {
00327         return;
00328     }
00329     
00330     p2= bezt->vec[1];
00331     
00332     if(prev==NULL) {
00333         p3= next->vec[1];
00334         pt[0]= 2.0f*p2[0] - p3[0];
00335         pt[1]= 2.0f*p2[1] - p3[1];
00336         p1= pt;
00337     }
00338     else {
00339         p1= prev->vec[1];
00340     }
00341     
00342     if(next==NULL) {
00343         p1= prev->vec[1];
00344         pt[0]= 2.0f*p2[0] - p1[0];
00345         pt[1]= 2.0f*p2[1] - p1[1];
00346         p3= pt;
00347     }
00348     else {
00349         p3= next->vec[1];
00350     }
00351 
00352     sub_v2_v2v2(dvec_a, p2, p1);
00353     sub_v2_v2v2(dvec_b, p3, p2);
00354 
00355     len_a= len_v2(dvec_a);
00356     len_b= len_v2(dvec_b);
00357 
00358     if(len_a==0.0f) len_a=1.0f;
00359     if(len_b==0.0f) len_b=1.0f;
00360 
00361     if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */
00362         float tvec[2];
00363         tvec[0]= dvec_b[0]/len_b + dvec_a[0]/len_a;
00364         tvec[1]= dvec_b[1]/len_b + dvec_a[1]/len_a;
00365 
00366         len= len_v2(tvec) * 2.5614f;
00367         if(len!=0.0f) {
00368             
00369             if(bezt->h1==HD_AUTO) {
00370                 len_a/=len;
00371                 madd_v2_v2v2fl(p2-3, p2, tvec, -len_a);
00372             }
00373             if(bezt->h2==HD_AUTO) {
00374                 len_b/=len;
00375                 madd_v2_v2v2fl(p2+3, p2, tvec,  len_b);
00376             }
00377         }
00378     }
00379 
00380     if(bezt->h1==HD_VECT) { /* vector */
00381         madd_v2_v2v2fl(p2-3, p2, dvec_a, -1.0f/3.0f);
00382     }
00383     if(bezt->h2==HD_VECT) {
00384         madd_v2_v2v2fl(p2+3, p2, dvec_b,  1.0f/3.0f);
00385     }
00386 }
00387 
00388 /* in X, out Y. 
00389    X is presumed to be outside first or last */
00390 static float curvemap_calc_extend(CurveMap *cuma, float x, const float first[2], const float last[2])
00391 {
00392     if(x <= first[0]) {
00393         if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) {
00394             /* no extrapolate */
00395             return first[1];
00396         }
00397         else {
00398             if(cuma->ext_in[0]==0.0f)
00399                 return first[1] + cuma->ext_in[1]*10000.0f;
00400             else
00401                 return first[1] + cuma->ext_in[1]*(x - first[0])/cuma->ext_in[0];
00402         }
00403     }
00404     else if(x >= last[0]) {
00405         if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) {
00406             /* no extrapolate */
00407             return last[1];
00408         }
00409         else {
00410             if(cuma->ext_out[0]==0.0f)
00411                 return last[1] - cuma->ext_out[1]*10000.0f;
00412             else
00413                 return last[1] + cuma->ext_out[1]*(x - last[0])/cuma->ext_out[0];
00414         }
00415     }
00416     return 0.0f;
00417 }
00418 
00419 /* only creates a table for a single channel in CurveMapping */
00420 static void curvemap_make_table(CurveMap *cuma, rctf *clipr)
00421 {
00422     CurveMapPoint *cmp= cuma->curve;
00423     BezTriple *bezt;
00424     float *fp, *allpoints, *lastpoint, curf, range;
00425     int a, totpoint;
00426     
00427     if(cuma->curve==NULL) return;
00428     
00429     /* default rect also is table range */
00430     cuma->mintable= clipr->xmin;
00431     cuma->maxtable= clipr->xmax;
00432     
00433     /* hrmf... we now rely on blender ipo beziers, these are more advanced */
00434     bezt= MEM_callocN(cuma->totpoint*sizeof(BezTriple), "beztarr");
00435     
00436     for(a=0; a<cuma->totpoint; a++) {
00437         cuma->mintable= MIN2(cuma->mintable, cmp[a].x);
00438         cuma->maxtable= MAX2(cuma->maxtable, cmp[a].x);
00439         bezt[a].vec[1][0]= cmp[a].x;
00440         bezt[a].vec[1][1]= cmp[a].y;
00441         if(cmp[a].flag & CUMA_VECTOR)
00442             bezt[a].h1= bezt[a].h2= HD_VECT;
00443         else
00444             bezt[a].h1= bezt[a].h2= HD_AUTO;
00445     }
00446     
00447     for(a=0; a<cuma->totpoint; a++) {
00448         if(a==0)
00449             calchandle_curvemap(bezt, NULL, bezt+1, 0);
00450         else if(a==cuma->totpoint-1)
00451             calchandle_curvemap(bezt+a, bezt+a-1, NULL, 0);
00452         else
00453             calchandle_curvemap(bezt+a, bezt+a-1, bezt+a+1, 0);
00454     }
00455     
00456     /* first and last handle need correction, instead of pointing to center of next/prev, 
00457         we let it point to the closest handle */
00458     if(cuma->totpoint>2) {
00459         float hlen, nlen, vec[3];
00460         
00461         if(bezt[0].h2==HD_AUTO) {
00462             
00463             hlen= len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */
00464             /* clip handle point */
00465             copy_v3_v3(vec, bezt[1].vec[0]);
00466             if(vec[0] < bezt[0].vec[1][0])
00467                 vec[0]= bezt[0].vec[1][0];
00468             
00469             sub_v3_v3(vec, bezt[0].vec[1]);
00470             nlen= len_v3(vec);
00471             if(nlen>FLT_EPSILON) {
00472                 mul_v3_fl(vec, hlen/nlen);
00473                 add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]);
00474                 sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec);
00475             }
00476         }
00477         a= cuma->totpoint-1;
00478         if(bezt[a].h2==HD_AUTO) {
00479             
00480             hlen= len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */
00481             /* clip handle point */
00482             copy_v3_v3(vec, bezt[a-1].vec[2]);
00483             if(vec[0] > bezt[a].vec[1][0])
00484                 vec[0]= bezt[a].vec[1][0];
00485             
00486             sub_v3_v3(vec, bezt[a].vec[1]);
00487             nlen= len_v3(vec);
00488             if(nlen>FLT_EPSILON) {
00489                 mul_v3_fl(vec, hlen/nlen);
00490                 add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]);
00491                 sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec);
00492             }
00493         }
00494     }   
00495     /* make the bezier curve */
00496     if(cuma->table)
00497         MEM_freeN(cuma->table);
00498     totpoint= (cuma->totpoint-1)*CM_RESOL;
00499     fp= allpoints= MEM_callocN(totpoint*2*sizeof(float), "table");
00500     
00501     for(a=0; a<cuma->totpoint-1; a++, fp += 2*CM_RESOL) {
00502         correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a+1].vec[0], bezt[a+1].vec[1]);
00503         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));   
00504         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));
00505     }
00506     
00507     /* store first and last handle for extrapolation, unit length */
00508     cuma->ext_in[0]= bezt[0].vec[0][0] - bezt[0].vec[1][0];
00509     cuma->ext_in[1]= bezt[0].vec[0][1] - bezt[0].vec[1][1];
00510     range= sqrt(cuma->ext_in[0]*cuma->ext_in[0] + cuma->ext_in[1]*cuma->ext_in[1]);
00511     cuma->ext_in[0]/= range;
00512     cuma->ext_in[1]/= range;
00513     
00514     a= cuma->totpoint-1;
00515     cuma->ext_out[0]= bezt[a].vec[1][0] - bezt[a].vec[2][0];
00516     cuma->ext_out[1]= bezt[a].vec[1][1] - bezt[a].vec[2][1];
00517     range= sqrt(cuma->ext_out[0]*cuma->ext_out[0] + cuma->ext_out[1]*cuma->ext_out[1]);
00518     cuma->ext_out[0]/= range;
00519     cuma->ext_out[1]/= range;
00520     
00521     /* cleanup */
00522     MEM_freeN(bezt);
00523 
00524     range= CM_TABLEDIV*(cuma->maxtable - cuma->mintable);
00525     cuma->range= 1.0f/range;
00526     
00527     /* now make a table with CM_TABLE equal x distances */
00528     fp= allpoints;
00529     lastpoint= allpoints + 2*(totpoint-1);
00530     cmp= MEM_callocN((CM_TABLE+1)*sizeof(CurveMapPoint), "dist table");
00531     
00532     for(a=0; a<=CM_TABLE; a++) {
00533         curf= cuma->mintable + range*(float)a;
00534         cmp[a].x= curf;
00535         
00536         /* get the first x coordinate larger than curf */
00537         while(curf >= fp[0] && fp!=lastpoint) {
00538             fp+=2;
00539         }
00540         if(fp==allpoints || (curf >= fp[0] && fp==lastpoint))
00541             cmp[a].y= curvemap_calc_extend(cuma, curf, allpoints, lastpoint);
00542         else {
00543             float fac1= fp[0] - fp[-2];
00544             float fac2= fp[0] - curf;
00545             if(fac1 > FLT_EPSILON)
00546                 fac1= fac2/fac1;
00547             else
00548                 fac1= 0.0f;
00549             cmp[a].y= fac1*fp[-1] + (1.0f-fac1)*fp[1];
00550         }
00551     }
00552     
00553     MEM_freeN(allpoints);
00554     cuma->table= cmp;
00555 }
00556 
00557 /* call when you do images etc, needs restore too. also verifies tables */
00558 /* it uses a flag to prevent premul or free to happen twice */
00559 void curvemapping_premultiply(CurveMapping *cumap, int restore)
00560 {
00561     int a;
00562     
00563     if(restore) {
00564         if(cumap->flag & CUMA_PREMULLED) {
00565             for(a=0; a<3; a++) {
00566                 MEM_freeN(cumap->cm[a].table);
00567                 cumap->cm[a].table= cumap->cm[a].premultable;
00568                 cumap->cm[a].premultable= NULL;
00569             }
00570             
00571             cumap->flag &= ~CUMA_PREMULLED;
00572         }
00573     }
00574     else {
00575         if((cumap->flag & CUMA_PREMULLED)==0) {
00576             /* verify and copy */
00577             for(a=0; a<3; a++) {
00578                 if(cumap->cm[a].table==NULL)
00579                     curvemap_make_table(cumap->cm+a, &cumap->clipr);
00580                 cumap->cm[a].premultable= cumap->cm[a].table;
00581                 cumap->cm[a].table= MEM_mallocN((CM_TABLE+1)*sizeof(CurveMapPoint), "premul table");
00582                 memcpy(cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE+1)*sizeof(CurveMapPoint));
00583             }
00584             
00585             if(cumap->cm[3].table==NULL)
00586                 curvemap_make_table(cumap->cm+3, &cumap->clipr);
00587         
00588             /* premul */
00589             for(a=0; a<3; a++) {
00590                 int b;
00591                 for(b=0; b<=CM_TABLE; b++) {
00592                     cumap->cm[a].table[b].y= curvemap_evaluateF(cumap->cm+3, cumap->cm[a].table[b].y);
00593                 }
00594             }
00595             
00596             cumap->flag |= CUMA_PREMULLED;
00597         }
00598     }
00599 }
00600 
00601 static int sort_curvepoints(const void *a1, const void *a2)
00602 {
00603     const struct CurveMapPoint *x1=a1, *x2=a2;
00604     
00605     if( x1->x > x2->x ) return 1;
00606     else if( x1->x < x2->x) return -1;
00607     return 0;
00608 }
00609 
00610 /* ************************ more CurveMapping calls *************** */
00611 
00612 /* note; only does current curvemap! */
00613 void curvemapping_changed(CurveMapping *cumap, int rem_doubles)
00614 {
00615     CurveMap *cuma= cumap->cm+cumap->cur;
00616     CurveMapPoint *cmp= cuma->curve;
00617     rctf *clipr= &cumap->clipr;
00618     float thresh= 0.01f*(clipr->xmax - clipr->xmin);
00619     float dx= 0.0f, dy= 0.0f;
00620     int a;
00621 
00622     cumap->changed_timestamp++;
00623 
00624     /* clamp with clip */
00625     if(cumap->flag & CUMA_DO_CLIP) {
00626         for(a=0; a<cuma->totpoint; a++) {
00627             if(cmp[a].flag & CUMA_SELECT) {
00628                 if(cmp[a].x < clipr->xmin)
00629                     dx= MIN2(dx, cmp[a].x - clipr->xmin);
00630                 else if(cmp[a].x > clipr->xmax)
00631                     dx= MAX2(dx, cmp[a].x - clipr->xmax);
00632                 if(cmp[a].y < clipr->ymin)
00633                     dy= MIN2(dy, cmp[a].y - clipr->ymin);
00634                 else if(cmp[a].y > clipr->ymax)
00635                     dy= MAX2(dy, cmp[a].y - clipr->ymax);
00636             }
00637         }
00638         for(a=0; a<cuma->totpoint; a++) {
00639             if(cmp[a].flag & CUMA_SELECT) {
00640                 cmp[a].x -= dx;
00641                 cmp[a].y -= dy;
00642             }
00643         }
00644     }
00645     
00646     
00647     qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints);
00648     
00649     /* remove doubles, threshold set on 1% of default range */
00650     if(rem_doubles && cuma->totpoint>2) {
00651         for(a=0; a<cuma->totpoint-1; a++) {
00652             dx= cmp[a].x - cmp[a+1].x;
00653             dy= cmp[a].y - cmp[a+1].y;
00654             if( sqrtf(dx*dx + dy*dy) < thresh ) {
00655                 if(a==0) {
00656                     cmp[a+1].flag|= 2;
00657                     if(cmp[a+1].flag & CUMA_SELECT)
00658                         cmp[a].flag |= CUMA_SELECT;
00659                 }
00660                 else {
00661                     cmp[a].flag|= 2;
00662                     if(cmp[a].flag & CUMA_SELECT)
00663                         cmp[a+1].flag |= CUMA_SELECT;
00664                 }
00665                 break;  /* we assume 1 deletion per edit is ok */
00666             }
00667         }
00668         if(a != cuma->totpoint-1)
00669             curvemap_remove(cuma, 2);
00670     }   
00671     curvemap_make_table(cuma, clipr);
00672 }
00673 
00674 /* table should be verified */
00675 float curvemap_evaluateF(CurveMap *cuma, float value)
00676 {
00677     float fi;
00678     int i;
00679 
00680     /* index in table */
00681     fi= (value-cuma->mintable)*cuma->range;
00682     i= (int)fi;
00683     
00684     /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */
00685     if(fi<0.0f || fi>CM_TABLE)
00686         return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x);
00687     else {
00688         if(i<0) return cuma->table[0].y;
00689         if(i>=CM_TABLE) return cuma->table[CM_TABLE].y;
00690         
00691         fi= fi-(float)i;
00692         return (1.0f-fi)*cuma->table[i].y + (fi)*cuma->table[i+1].y; 
00693     }
00694 }
00695 
00696 /* works with curve 'cur' */
00697 float curvemapping_evaluateF(CurveMapping *cumap, int cur, float value)
00698 {
00699     CurveMap *cuma= cumap->cm+cur;
00700     
00701     /* allocate or bail out */
00702     if(cuma->table==NULL) {
00703         curvemap_make_table(cuma, &cumap->clipr);
00704         if(cuma->table==NULL)
00705             return 1.0f-value;
00706     }
00707     return curvemap_evaluateF(cuma, value);
00708 }
00709 
00710 /* vector case */
00711 void curvemapping_evaluate3F(CurveMapping *cumap, float vecout[3], const float vecin[3])
00712 {
00713     vecout[0]= curvemapping_evaluateF(cumap, 0, vecin[0]);
00714     vecout[1]= curvemapping_evaluateF(cumap, 1, vecin[1]);
00715     vecout[2]= curvemapping_evaluateF(cumap, 2, vecin[2]);
00716 }
00717 
00718 /* RGB case, no black/white points, no premult */
00719 void curvemapping_evaluateRGBF(CurveMapping *cumap, float vecout[3], const float vecin[3])
00720 {
00721     vecout[0]= curvemapping_evaluateF(cumap, 0, curvemapping_evaluateF(cumap, 3, vecin[0]));
00722     vecout[1]= curvemapping_evaluateF(cumap, 1, curvemapping_evaluateF(cumap, 3, vecin[1]));
00723     vecout[2]= curvemapping_evaluateF(cumap, 2, curvemapping_evaluateF(cumap, 3, vecin[2]));
00724 }
00725 
00726 
00727 /* RGB with black/white points and premult. tables are checked */
00728 void curvemapping_evaluate_premulRGBF(CurveMapping *cumap, float vecout[3], const float vecin[3])
00729 {
00730     float fac;
00731     
00732     fac= (vecin[0] - cumap->black[0])*cumap->bwmul[0];
00733     vecout[0]= curvemap_evaluateF(cumap->cm, fac);
00734     
00735     fac= (vecin[1] - cumap->black[1])*cumap->bwmul[1];
00736     vecout[1]= curvemap_evaluateF(cumap->cm+1, fac);
00737     
00738     fac= (vecin[2] - cumap->black[2])*cumap->bwmul[2];
00739     vecout[2]= curvemap_evaluateF(cumap->cm+2, fac);
00740 }
00741 
00742 
00743 /* only used for image editor curves */
00744 void curvemapping_do_ibuf(CurveMapping *cumap, ImBuf *ibuf)
00745 {
00746     ImBuf *tmpbuf;
00747     int pixel;
00748     float *pix_in;
00749     float col[3];
00750     int stride= 4;
00751     float *pix_out;
00752     
00753     if(ibuf==NULL)
00754         return;
00755     if(ibuf->rect_float==NULL)
00756         IMB_float_from_rect(ibuf);
00757     else if(ibuf->rect==NULL)
00758         imb_addrectImBuf(ibuf);
00759     
00760     if (!ibuf->rect || !ibuf->rect_float)
00761         return;
00762     
00763     /* work on a temp buffer, so can color manage afterwards.
00764      * No worse off memory wise than comp nodes */
00765     tmpbuf = IMB_dupImBuf(ibuf);
00766     
00767     curvemapping_premultiply(cumap, 0);
00768     
00769     pix_in= ibuf->rect_float;
00770     pix_out= tmpbuf->rect_float;
00771 
00772     if(ibuf->channels)
00773         stride= ibuf->channels;
00774     
00775     for(pixel= ibuf->x*ibuf->y; pixel>0; pixel--, pix_in+=stride, pix_out+=stride) {
00776         if(stride<3) {
00777             col[0]= curvemap_evaluateF(cumap->cm, *pix_in);
00778             
00779             pix_out[1]= pix_out[2]= pix_out[3]= pix_out[0]= col[0];
00780         }
00781         else {
00782             curvemapping_evaluate_premulRGBF(cumap, col, pix_in);
00783             pix_out[0]= col[0];
00784             pix_out[1]= col[1];
00785             pix_out[2]= col[2];
00786             if(stride>3)
00787                 pix_out[3]= pix_in[3];
00788             else
00789                 pix_out[3]= 1.f;
00790         }
00791     }
00792     
00793     IMB_rect_from_float(tmpbuf);
00794     SWAP(unsigned int *, tmpbuf->rect, ibuf->rect);
00795     IMB_freeImBuf(tmpbuf);
00796     
00797     curvemapping_premultiply(cumap, 1);
00798 }
00799 
00800 int curvemapping_RGBA_does_something(CurveMapping *cumap)
00801 {
00802     int a;
00803     
00804     if(cumap->black[0]!=0.0f) return 1;
00805     if(cumap->black[1]!=0.0f) return 1;
00806     if(cumap->black[2]!=0.0f) return 1;
00807     if(cumap->white[0]!=1.0f) return 1;
00808     if(cumap->white[1]!=1.0f) return 1;
00809     if(cumap->white[2]!=1.0f) return 1;
00810     
00811     for(a=0; a<CM_TOT; a++) {
00812         if(cumap->cm[a].curve) {
00813             if(cumap->cm[a].totpoint!=2)  return 1;
00814             
00815             if(cumap->cm[a].curve[0].x != 0.0f) return 1;
00816             if(cumap->cm[a].curve[0].y != 0.0f) return 1;
00817             if(cumap->cm[a].curve[1].x != 1.0f) return 1;
00818             if(cumap->cm[a].curve[1].y != 1.0f) return 1;
00819         }
00820     }
00821     return 0;
00822 }
00823 
00824 void curvemapping_initialize(CurveMapping *cumap)
00825 {
00826     int a;
00827     
00828     if(cumap==NULL) return;
00829     
00830     for(a=0; a<CM_TOT; a++) {
00831         if(cumap->cm[a].table==NULL)
00832             curvemap_make_table(cumap->cm+a, &cumap->clipr);
00833     }
00834 }
00835 
00836 void curvemapping_table_RGBA(CurveMapping *cumap, float **array, int *size)
00837 {
00838     int a;
00839     
00840     *size = CM_TABLE+1;
00841     *array = MEM_callocN(sizeof(float)*(*size)*4, "CurveMapping");
00842     curvemapping_initialize(cumap);
00843 
00844     for(a=0; a<*size; a++) {
00845         if(cumap->cm[0].table)
00846             (*array)[a*4+0]= cumap->cm[0].table[a].y;
00847         if(cumap->cm[1].table)
00848             (*array)[a*4+1]= cumap->cm[1].table[a].y;
00849         if(cumap->cm[2].table)
00850             (*array)[a*4+2]= cumap->cm[2].table[a].y;
00851         if(cumap->cm[3].table)
00852             (*array)[a*4+3]= cumap->cm[3].table[a].y;
00853     }
00854 }
00855 
00856 /* ***************** Histogram **************** */
00857 
00858 #define INV_255     (1.f/255.f)
00859 
00860 DO_INLINE int get_bin_float(float f)
00861 {
00862     int bin= (int)((f*255.0f) + 0.5f);  /* 0.5 to prevent quantisation differences */
00863 
00864     /* note: clamp integer instead of float to avoid problems with NaN */
00865     CLAMP(bin, 0, 255);
00866 
00867     return bin;
00868 }
00869 
00870 DO_INLINE void save_sample_line(Scopes *scopes, const int idx, const float fx, float *rgb, float *ycc)
00871 {
00872     float yuv[3];
00873 
00874     /* vectorscope*/
00875     rgb_to_yuv(rgb[0], rgb[1], rgb[2], &yuv[0], &yuv[1], &yuv[2]);
00876     scopes->vecscope[idx + 0] = yuv[1];
00877     scopes->vecscope[idx + 1] = yuv[2];
00878 
00879     /* waveform */
00880     switch (scopes->wavefrm_mode) {
00881         case SCOPES_WAVEFRM_RGB:
00882             scopes->waveform_1[idx + 0] = fx;
00883             scopes->waveform_1[idx + 1] = rgb[0];
00884             scopes->waveform_2[idx + 0] = fx;
00885             scopes->waveform_2[idx + 1] = rgb[1];
00886             scopes->waveform_3[idx + 0] = fx;
00887             scopes->waveform_3[idx + 1] = rgb[2];
00888             break;
00889         case SCOPES_WAVEFRM_LUMA:
00890             scopes->waveform_1[idx + 0] = fx;
00891             scopes->waveform_1[idx + 1] = ycc[0];
00892             break;
00893         case SCOPES_WAVEFRM_YCC_JPEG:
00894         case SCOPES_WAVEFRM_YCC_709:
00895         case SCOPES_WAVEFRM_YCC_601:
00896             scopes->waveform_1[idx + 0] = fx;
00897             scopes->waveform_1[idx + 1] = ycc[0];
00898             scopes->waveform_2[idx + 0] = fx;
00899             scopes->waveform_2[idx + 1] = ycc[1];
00900             scopes->waveform_3[idx + 0] = fx;
00901             scopes->waveform_3[idx + 1] = ycc[2];
00902             break;
00903     }
00904 }
00905 
00906 void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management)
00907 {
00908     int x, y, c;
00909     unsigned int n, nl;
00910     double div, divl;
00911     float *rf=NULL;
00912     unsigned char *rc=NULL;
00913     unsigned int *bin_r, *bin_g, *bin_b, *bin_lum;
00914     int savedlines, saveline;
00915     float rgb[3], ycc[3], luma;
00916     int ycc_mode=-1;
00917     const short is_float = (ibuf->rect_float != NULL);
00918 
00919     if (ibuf->rect==NULL && ibuf->rect_float==NULL) return;
00920 
00921     if (scopes->ok == 1 ) return;
00922 
00923     if (scopes->hist.ymax == 0.f) scopes->hist.ymax = 1.f;
00924 
00925     /* hmmmm */
00926     if (!(ELEM(ibuf->channels, 3, 4))) return;
00927 
00928     scopes->hist.channels = 3;
00929     scopes->hist.x_resolution = 256;
00930 
00931     switch (scopes->wavefrm_mode) {
00932         case SCOPES_WAVEFRM_RGB:
00933             ycc_mode = -1;
00934             break;
00935         case SCOPES_WAVEFRM_LUMA:
00936         case SCOPES_WAVEFRM_YCC_JPEG:
00937             ycc_mode = BLI_YCC_JFIF_0_255;
00938             break;
00939         case SCOPES_WAVEFRM_YCC_601:
00940             ycc_mode = BLI_YCC_ITU_BT601;
00941             break;
00942         case SCOPES_WAVEFRM_YCC_709:
00943             ycc_mode = BLI_YCC_ITU_BT709;
00944             break;
00945     }
00946 
00947     /* temp table to count pix value for histo */
00948     bin_r = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
00949     bin_g = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
00950     bin_b = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
00951     bin_lum = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins");
00952 
00953     /* convert to number of lines with logarithmic scale */
00954     scopes->sample_lines = (scopes->accuracy*0.01f) * (scopes->accuracy*0.01f) * ibuf->y;
00955     
00956     if (scopes->sample_full)
00957         scopes->sample_lines = ibuf->y;
00958 
00959     /* scan the image */
00960     savedlines=0;
00961     for (c=0; c<3; c++) {
00962         scopes->minmax[c][0]=25500.0f;
00963         scopes->minmax[c][1]=-25500.0f;
00964     }
00965     
00966     scopes->waveform_tot = ibuf->x*scopes->sample_lines;
00967     
00968     if (scopes->waveform_1)
00969         MEM_freeN(scopes->waveform_1);
00970     if (scopes->waveform_2)
00971         MEM_freeN(scopes->waveform_2);
00972     if (scopes->waveform_3)
00973         MEM_freeN(scopes->waveform_3);
00974     if (scopes->vecscope)
00975         MEM_freeN(scopes->vecscope);
00976     
00977     scopes->waveform_1= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 1");
00978     scopes->waveform_2= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 2");
00979     scopes->waveform_3= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 3");
00980     scopes->vecscope= MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "vectorscope point channel");
00981     
00982     if (is_float)
00983         rf = ibuf->rect_float;
00984     else
00985         rc = (unsigned char *)ibuf->rect;
00986 
00987     for (y = 0; y < ibuf->y; y++) {
00988         if (savedlines<scopes->sample_lines && y>=((savedlines)*ibuf->y)/(scopes->sample_lines+1)) {
00989             saveline=1;
00990         } else saveline=0;
00991         for (x = 0; x < ibuf->x; x++) {
00992 
00993             if (is_float) {
00994                 if (use_color_management)
00995                     linearrgb_to_srgb_v3_v3(rgb, rf);
00996                 else
00997                     copy_v3_v3(rgb, rf);
00998             }
00999             else {
01000                 for (c=0; c<3; c++)
01001                     rgb[c] = rc[c] * INV_255;
01002             }
01003 
01004             /* we still need luma for histogram */
01005             luma = rgb_to_luma(rgb);
01006 
01007             /* check for min max */
01008             if(ycc_mode == -1 ) {
01009                 for (c=0; c<3; c++) {
01010                     if (rgb[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = rgb[c];
01011                     if (rgb[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = rgb[c];
01012                 }
01013             }
01014             else {
01015                 rgb_to_ycc(rgb[0],rgb[1],rgb[2],&ycc[0],&ycc[1],&ycc[2], ycc_mode);
01016                 for (c=0; c<3; c++) {
01017                     ycc[c] *=INV_255;
01018                     if (ycc[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = ycc[c];
01019                     if (ycc[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = ycc[c];
01020                 }
01021             }
01022             /* increment count for histo*/
01023             bin_r[ get_bin_float(rgb[0]) ] += 1;
01024             bin_g[ get_bin_float(rgb[1]) ] += 1;
01025             bin_b[ get_bin_float(rgb[2]) ] += 1;
01026             bin_lum[ get_bin_float(luma) ] += 1;
01027 
01028             /* save sample if needed */
01029             if(saveline) {
01030                 const float fx = (float)x / (float)ibuf->x;
01031                 const int idx = 2*(ibuf->x*savedlines+x);
01032                 save_sample_line(scopes, idx, fx, rgb, ycc);
01033             }
01034 
01035             rf+= ibuf->channels;
01036             rc+= ibuf->channels;
01037         }
01038         if (saveline)
01039             savedlines +=1;
01040     }
01041 
01042     /* convert hist data to float (proportional to max count) */
01043     n=0;
01044     nl=0;
01045     for (x=0; x<256; x++) {
01046         if (bin_r[x] > n)
01047             n = bin_r[x];
01048         if (bin_g[x] > n)
01049             n = bin_g[x];
01050         if (bin_b[x] > n)
01051             n = bin_b[x];
01052         if (bin_lum[x] > nl)
01053             nl = bin_lum[x];
01054     }
01055     div = 1.0/(double)n;
01056     divl = 1.0/(double)nl;
01057     for (x=0; x<256; x++) {
01058         scopes->hist.data_r[x] = bin_r[x] * div;
01059         scopes->hist.data_g[x] = bin_g[x] * div;
01060         scopes->hist.data_b[x] = bin_b[x] * div;
01061         scopes->hist.data_luma[x] = bin_lum[x] * divl;
01062     }
01063     MEM_freeN(bin_r);
01064     MEM_freeN(bin_g);
01065     MEM_freeN(bin_b);
01066     MEM_freeN(bin_lum);
01067 
01068     scopes->ok = 1;
01069 }
01070 
01071 void scopes_free(Scopes *scopes)
01072 {
01073     if (scopes->waveform_1) {
01074         MEM_freeN(scopes->waveform_1);
01075         scopes->waveform_1 = NULL;
01076     }
01077     if (scopes->waveform_2) {
01078         MEM_freeN(scopes->waveform_2);
01079         scopes->waveform_2 = NULL;
01080     }
01081     if (scopes->waveform_3) {
01082         MEM_freeN(scopes->waveform_3);
01083         scopes->waveform_3 = NULL;
01084     }
01085     if (scopes->vecscope) {
01086         MEM_freeN(scopes->vecscope);
01087         scopes->vecscope = NULL;
01088     }
01089 }
01090 
01091 void scopes_new(Scopes *scopes)
01092 {
01093     scopes->accuracy=30.0;
01094     scopes->hist.mode=HISTO_MODE_RGB;
01095     scopes->wavefrm_alpha=0.3;
01096     scopes->vecscope_alpha=0.3;
01097     scopes->wavefrm_height= 100;
01098     scopes->vecscope_height= 100;
01099     scopes->hist.height= 100;
01100     scopes->ok= 0;
01101     scopes->waveform_1 = NULL;
01102     scopes->waveform_2 = NULL;
01103     scopes->waveform_3 = NULL;
01104     scopes->vecscope = NULL;
01105 }