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