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