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