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