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