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