Image viewer scopes update: OMP->BLI_task.
[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 #include "BLI_task.h"
47 #include "BLI_threads.h"
48
49 #include "BKE_colortools.h"
50 #include "BKE_curve.h"
51 #include "BKE_fcurve.h"
52
53
54 #include "IMB_colormanagement.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 bool 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[1].x = clipr->xmax;
294                         cuma->curve[1].y = clipr->ymin;
295                         if (slope == CURVEMAP_SLOPE_POS_NEG) {
296                                 cuma->curve[0].flag |= CUMA_VECTOR;
297                                 cuma->curve[1].flag |= CUMA_VECTOR;
298                         }
299                         break;
300                 case CURVE_PRESET_SHARP:
301                         cuma->curve[0].x = 0;
302                         cuma->curve[0].y = 1;
303                         cuma->curve[1].x = 0.25;
304                         cuma->curve[1].y = 0.50;
305                         cuma->curve[2].x = 0.75;
306                         cuma->curve[2].y = 0.04;
307                         cuma->curve[3].x = 1;
308                         cuma->curve[3].y = 0;
309                         break;
310                 case CURVE_PRESET_SMOOTH:
311                         cuma->curve[0].x = 0;
312                         cuma->curve[0].y = 1;
313                         cuma->curve[1].x = 0.25;
314                         cuma->curve[1].y = 0.94;
315                         cuma->curve[2].x = 0.75;
316                         cuma->curve[2].y = 0.06;
317                         cuma->curve[3].x = 1;
318                         cuma->curve[3].y = 0;
319                         break;
320                 case CURVE_PRESET_MAX:
321                         cuma->curve[0].x = 0;
322                         cuma->curve[0].y = 1;
323                         cuma->curve[1].x = 1;
324                         cuma->curve[1].y = 1;
325                         break;
326                 case CURVE_PRESET_MID9:
327                 {
328                         int i;
329                         for (i = 0; i < cuma->totpoint; i++) {
330                                 cuma->curve[i].x = i / ((float)cuma->totpoint - 1);
331                                 cuma->curve[i].y = 0.5;
332                         }
333                         break;
334                 }
335                 case CURVE_PRESET_ROUND:
336                         cuma->curve[0].x = 0;
337                         cuma->curve[0].y = 1;
338                         cuma->curve[1].x = 0.5;
339                         cuma->curve[1].y = 0.90;
340                         cuma->curve[2].x = 0.86;
341                         cuma->curve[2].y = 0.5;
342                         cuma->curve[3].x = 1;
343                         cuma->curve[3].y = 0;
344                         break;
345                 case CURVE_PRESET_ROOT:
346                         cuma->curve[0].x = 0;
347                         cuma->curve[0].y = 1;
348                         cuma->curve[1].x = 0.25;
349                         cuma->curve[1].y = 0.95;
350                         cuma->curve[2].x = 0.75;
351                         cuma->curve[2].y = 0.44;
352                         cuma->curve[3].x = 1;
353                         cuma->curve[3].y = 0;
354                         break;
355         }
356
357         /* mirror curve in x direction to have positive slope
358          * rather than default negative slope */
359         if (slope == CURVEMAP_SLOPE_POSITIVE) {
360                 int i, last = cuma->totpoint - 1;
361                 CurveMapPoint *newpoints = MEM_dupallocN(cuma->curve);
362                 
363                 for (i = 0; i < cuma->totpoint; i++) {
364                         newpoints[i].y = cuma->curve[last - i].y;
365                 }
366                 
367                 MEM_freeN(cuma->curve);
368                 cuma->curve = newpoints;
369         }
370         else if (slope == CURVEMAP_SLOPE_POS_NEG) {
371                 const int num_points = cuma->totpoint * 2 - 1;
372                 CurveMapPoint *new_points = MEM_mallocN(num_points * sizeof(CurveMapPoint),
373                                                        "curve symmetric points");
374                 int i;
375                 for (i = 0; i < cuma->totpoint; i++) {
376                         const int src_last_point = cuma->totpoint - i - 1;
377                         const int dst_last_point = num_points - i - 1;
378                         new_points[i] = cuma->curve[src_last_point];
379                         new_points[i].x = (1.0f - cuma->curve[src_last_point].x) * 0.5f;
380                         new_points[dst_last_point] = new_points[i];
381                         new_points[dst_last_point].x = 0.5f + cuma->curve[src_last_point].x * 0.5f;
382                 }
383                 cuma->totpoint = num_points;
384                 MEM_freeN(cuma->curve);
385                 cuma->curve = new_points;
386         }
387
388         if (cuma->table) {
389                 MEM_freeN(cuma->table);
390                 cuma->table = NULL;
391         }
392 }
393
394 /* if type==1: vector, else auto */
395 void curvemap_sethandle(CurveMap *cuma, int type)
396 {
397         int a;
398         
399         for (a = 0; a < cuma->totpoint; a++) {
400                 if (cuma->curve[a].flag & CUMA_SELECT) {
401                         if (type) cuma->curve[a].flag |= CUMA_VECTOR;
402                         else cuma->curve[a].flag &= ~CUMA_VECTOR;
403                 }
404         }
405 }
406
407 /* *********************** Making the tables and display ************** */
408
409 /**
410  * reduced copy of #calchandleNurb_intern code in curve.c
411  */
412 static void calchandle_curvemap(
413         BezTriple *bezt, const BezTriple *prev, const BezTriple *next)
414 {
415         /* defines to avoid confusion */
416 #define p2_h1 ((p2) - 3)
417 #define p2_h2 ((p2) + 3)
418
419         const float *p1, *p3;
420         float *p2;
421         float pt[3];
422         float len, len_a, len_b;
423         float dvec_a[2], dvec_b[2];
424
425         if (bezt->h1 == 0 && bezt->h2 == 0) {
426                 return;
427         }
428         
429         p2 = bezt->vec[1];
430         
431         if (prev == NULL) {
432                 p3 = next->vec[1];
433                 pt[0] = 2.0f * p2[0] - p3[0];
434                 pt[1] = 2.0f * p2[1] - p3[1];
435                 p1 = pt;
436         }
437         else {
438                 p1 = prev->vec[1];
439         }
440         
441         if (next == NULL) {
442                 p1 = prev->vec[1];
443                 pt[0] = 2.0f * p2[0] - p1[0];
444                 pt[1] = 2.0f * p2[1] - p1[1];
445                 p3 = pt;
446         }
447         else {
448                 p3 = next->vec[1];
449         }
450
451         sub_v2_v2v2(dvec_a, p2, p1);
452         sub_v2_v2v2(dvec_b, p3, p2);
453
454         len_a = len_v2(dvec_a);
455         len_b = len_v2(dvec_b);
456
457         if (len_a == 0.0f) len_a = 1.0f;
458         if (len_b == 0.0f) len_b = 1.0f;
459
460         if (bezt->h1 == HD_AUTO || bezt->h2 == HD_AUTO) { /* auto */
461                 float tvec[2];
462                 tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
463                 tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;
464
465                 len = len_v2(tvec) * 2.5614f;
466                 if (len != 0.0f) {
467                         
468                         if (bezt->h1 == HD_AUTO) {
469                                 len_a /= len;
470                                 madd_v2_v2v2fl(p2_h1, p2, tvec, -len_a);
471                         }
472                         if (bezt->h2 == HD_AUTO) {
473                                 len_b /= len;
474                                 madd_v2_v2v2fl(p2_h2, p2, tvec,  len_b);
475                         }
476                 }
477         }
478
479         if (bezt->h1 == HD_VECT) {    /* vector */
480                 madd_v2_v2v2fl(p2_h1, p2, dvec_a, -1.0f / 3.0f);
481         }
482         if (bezt->h2 == HD_VECT) {
483                 madd_v2_v2v2fl(p2_h2, p2, dvec_b,  1.0f / 3.0f);
484         }
485
486 #undef p2_h1
487 #undef p2_h2
488 }
489
490 /* in X, out Y. 
491  * X is presumed to be outside first or last */
492 static float curvemap_calc_extend(const CurveMap *cuma, float x, const float first[2], const float last[2])
493 {
494         if (x <= first[0]) {
495                 if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
496                         /* no extrapolate */
497                         return first[1];
498                 }
499                 else {
500                         if (cuma->ext_in[0] == 0.0f)
501                                 return first[1] + cuma->ext_in[1] * 10000.0f;
502                         else
503                                 return first[1] + cuma->ext_in[1] * (x - first[0]) / cuma->ext_in[0];
504                 }
505         }
506         else if (x >= last[0]) {
507                 if ((cuma->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
508                         /* no extrapolate */
509                         return last[1];
510                 }
511                 else {
512                         if (cuma->ext_out[0] == 0.0f)
513                                 return last[1] - cuma->ext_out[1] * 10000.0f;
514                         else
515                                 return last[1] + cuma->ext_out[1] * (x - last[0]) / cuma->ext_out[0];
516                 }
517         }
518         return 0.0f;
519 }
520
521 /* only creates a table for a single channel in CurveMapping */
522 static void curvemap_make_table(CurveMap *cuma, const rctf *clipr)
523 {
524         CurveMapPoint *cmp = cuma->curve;
525         BezTriple *bezt;
526         float *fp, *allpoints, *lastpoint, curf, range;
527         int a, totpoint;
528         
529         if (cuma->curve == NULL) return;
530         
531         /* default rect also is table range */
532         cuma->mintable = clipr->xmin;
533         cuma->maxtable = clipr->xmax;
534         
535         /* hrmf... we now rely on blender ipo beziers, these are more advanced */
536         bezt = MEM_callocN(cuma->totpoint * sizeof(BezTriple), "beztarr");
537         
538         for (a = 0; a < cuma->totpoint; a++) {
539                 cuma->mintable = min_ff(cuma->mintable, cmp[a].x);
540                 cuma->maxtable = max_ff(cuma->maxtable, cmp[a].x);
541                 bezt[a].vec[1][0] = cmp[a].x;
542                 bezt[a].vec[1][1] = cmp[a].y;
543                 if (cmp[a].flag & CUMA_VECTOR)
544                         bezt[a].h1 = bezt[a].h2 = HD_VECT;
545                 else
546                         bezt[a].h1 = bezt[a].h2 = HD_AUTO;
547         }
548         
549         const BezTriple *bezt_prev = NULL;
550         for (a = 0; a < cuma->totpoint; a++) {
551                 const BezTriple *bezt_next = (a != cuma->totpoint - 1) ? &bezt[a + 1] : NULL;
552                 calchandle_curvemap(&bezt[a], bezt_prev, bezt_next);
553                 bezt_prev = &bezt[a];
554         }
555         
556         /* first and last handle need correction, instead of pointing to center of next/prev, 
557          * we let it point to the closest handle */
558         if (cuma->totpoint > 2) {
559                 float hlen, nlen, vec[3];
560                 
561                 if (bezt[0].h2 == HD_AUTO) {
562                         
563                         hlen = len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */
564                         /* clip handle point */
565                         copy_v3_v3(vec, bezt[1].vec[0]);
566                         if (vec[0] < bezt[0].vec[1][0])
567                                 vec[0] = bezt[0].vec[1][0];
568                         
569                         sub_v3_v3(vec, bezt[0].vec[1]);
570                         nlen = len_v3(vec);
571                         if (nlen > FLT_EPSILON) {
572                                 mul_v3_fl(vec, hlen / nlen);
573                                 add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]);
574                                 sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec);
575                         }
576                 }
577                 a = cuma->totpoint - 1;
578                 if (bezt[a].h2 == HD_AUTO) {
579                         
580                         hlen = len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */
581                         /* clip handle point */
582                         copy_v3_v3(vec, bezt[a - 1].vec[2]);
583                         if (vec[0] > bezt[a].vec[1][0])
584                                 vec[0] = bezt[a].vec[1][0];
585                         
586                         sub_v3_v3(vec, bezt[a].vec[1]);
587                         nlen = len_v3(vec);
588                         if (nlen > FLT_EPSILON) {
589                                 mul_v3_fl(vec, hlen / nlen);
590                                 add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]);
591                                 sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec);
592                         }
593                 }
594         }
595         /* make the bezier curve */
596         if (cuma->table)
597                 MEM_freeN(cuma->table);
598         totpoint = (cuma->totpoint - 1) * CM_RESOL;
599         fp = allpoints = MEM_callocN(totpoint * 2 * sizeof(float), "table");
600         
601         for (a = 0; a < cuma->totpoint - 1; a++, fp += 2 * CM_RESOL) {
602                 correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a + 1].vec[0], bezt[a + 1].vec[1]);
603                 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));
604                 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));
605         }
606         
607         /* store first and last handle for extrapolation, unit length */
608         cuma->ext_in[0] = bezt[0].vec[0][0] - bezt[0].vec[1][0];
609         cuma->ext_in[1] = bezt[0].vec[0][1] - bezt[0].vec[1][1];
610         range = sqrtf(cuma->ext_in[0] * cuma->ext_in[0] + cuma->ext_in[1] * cuma->ext_in[1]);
611         cuma->ext_in[0] /= range;
612         cuma->ext_in[1] /= range;
613
614         a = cuma->totpoint - 1;
615         cuma->ext_out[0] = bezt[a].vec[1][0] - bezt[a].vec[2][0];
616         cuma->ext_out[1] = bezt[a].vec[1][1] - bezt[a].vec[2][1];
617         range = sqrtf(cuma->ext_out[0] * cuma->ext_out[0] + cuma->ext_out[1] * cuma->ext_out[1]);
618         cuma->ext_out[0] /= range;
619         cuma->ext_out[1] /= range;
620         
621         /* cleanup */
622         MEM_freeN(bezt);
623
624         range = CM_TABLEDIV * (cuma->maxtable - cuma->mintable);
625         cuma->range = 1.0f / range;
626         
627         /* now make a table with CM_TABLE equal x distances */
628         fp = allpoints;
629         lastpoint = allpoints + 2 * (totpoint - 1);
630         cmp = MEM_callocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "dist table");
631
632         for (a = 0; a <= CM_TABLE; a++) {
633                 curf = cuma->mintable + range * (float)a;
634                 cmp[a].x = curf;
635                 
636                 /* get the first x coordinate larger than curf */
637                 while (curf >= fp[0] && fp != lastpoint) {
638                         fp += 2;
639                 }
640                 if (fp == allpoints || (curf >= fp[0] && fp == lastpoint))
641                         cmp[a].y = curvemap_calc_extend(cuma, curf, allpoints, lastpoint);
642                 else {
643                         float fac1 = fp[0] - fp[-2];
644                         float fac2 = fp[0] - curf;
645                         if (fac1 > FLT_EPSILON)
646                                 fac1 = fac2 / fac1;
647                         else
648                                 fac1 = 0.0f;
649                         cmp[a].y = fac1 * fp[-1] + (1.0f - fac1) * fp[1];
650                 }
651         }
652         
653         MEM_freeN(allpoints);
654         cuma->table = cmp;
655 }
656
657 /* call when you do images etc, needs restore too. also verifies tables */
658 /* it uses a flag to prevent premul or free to happen twice */
659 void curvemapping_premultiply(CurveMapping *cumap, int restore)
660 {
661         int a;
662         
663         if (restore) {
664                 if (cumap->flag & CUMA_PREMULLED) {
665                         for (a = 0; a < 3; a++) {
666                                 MEM_freeN(cumap->cm[a].table);
667                                 cumap->cm[a].table = cumap->cm[a].premultable;
668                                 cumap->cm[a].premultable = NULL;
669
670                                 copy_v2_v2(cumap->cm[a].ext_in, cumap->cm[a].premul_ext_in);
671                                 copy_v2_v2(cumap->cm[a].ext_out, cumap->cm[a].premul_ext_out);
672                                 zero_v2(cumap->cm[a].premul_ext_in);
673                                 zero_v2(cumap->cm[a].premul_ext_out);
674                         }
675                         
676                         cumap->flag &= ~CUMA_PREMULLED;
677                 }
678         }
679         else {
680                 if ((cumap->flag & CUMA_PREMULLED) == 0) {
681                         /* verify and copy */
682                         for (a = 0; a < 3; a++) {
683                                 if (cumap->cm[a].table == NULL)
684                                         curvemap_make_table(cumap->cm + a, &cumap->clipr);
685                                 cumap->cm[a].premultable = cumap->cm[a].table;
686                                 cumap->cm[a].table = MEM_mallocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "premul table");
687                                 memcpy(cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE + 1) * sizeof(CurveMapPoint));
688                         }
689                         
690                         if (cumap->cm[3].table == NULL)
691                                 curvemap_make_table(cumap->cm + 3, &cumap->clipr);
692                 
693                         /* premul */
694                         for (a = 0; a < 3; a++) {
695                                 int b;
696                                 for (b = 0; b <= CM_TABLE; b++) {
697                                         cumap->cm[a].table[b].y = curvemap_evaluateF(cumap->cm + 3, cumap->cm[a].table[b].y);
698                                 }
699
700                                 copy_v2_v2(cumap->cm[a].premul_ext_in, cumap->cm[a].ext_in);
701                                 copy_v2_v2(cumap->cm[a].premul_ext_out, cumap->cm[a].ext_out);
702                                 mul_v2_v2(cumap->cm[a].ext_in, cumap->cm[3].ext_in);
703                                 mul_v2_v2(cumap->cm[a].ext_out, cumap->cm[3].ext_out);
704                         }
705                         
706                         cumap->flag |= CUMA_PREMULLED;
707                 }
708         }
709 }
710
711 static int sort_curvepoints(const void *a1, const void *a2)
712 {
713         const struct CurveMapPoint *x1 = a1, *x2 = a2;
714         
715         if (x1->x > x2->x) return 1;
716         else if (x1->x < x2->x) return -1;
717         return 0;
718 }
719
720 /* ************************ more CurveMapping calls *************** */
721
722 /* note; only does current curvemap! */
723 void curvemapping_changed(CurveMapping *cumap, const bool rem_doubles)
724 {
725         CurveMap *cuma = cumap->cm + cumap->cur;
726         CurveMapPoint *cmp = cuma->curve;
727         rctf *clipr = &cumap->clipr;
728         float thresh = 0.01f * BLI_rctf_size_x(clipr);
729         float dx = 0.0f, dy = 0.0f;
730         int a;
731
732         cumap->changed_timestamp++;
733
734         /* clamp with clip */
735         if (cumap->flag & CUMA_DO_CLIP) {
736                 for (a = 0; a < cuma->totpoint; a++) {
737                         if (cmp[a].flag & CUMA_SELECT) {
738                                 if (cmp[a].x < clipr->xmin)
739                                         dx = min_ff(dx, cmp[a].x - clipr->xmin);
740                                 else if (cmp[a].x > clipr->xmax)
741                                         dx = max_ff(dx, cmp[a].x - clipr->xmax);
742                                 if (cmp[a].y < clipr->ymin)
743                                         dy = min_ff(dy, cmp[a].y - clipr->ymin);
744                                 else if (cmp[a].y > clipr->ymax)
745                                         dy = max_ff(dy, cmp[a].y - clipr->ymax);
746                         }
747                 }
748                 for (a = 0; a < cuma->totpoint; a++) {
749                         if (cmp[a].flag & CUMA_SELECT) {
750                                 cmp[a].x -= dx;
751                                 cmp[a].y -= dy;
752                         }
753                 }
754
755                 /* ensure zoom-level respects clipping */
756                 if (BLI_rctf_size_x(&cumap->curr) > BLI_rctf_size_x(&cumap->clipr)) {
757                         cumap->curr.xmin = cumap->clipr.xmin;
758                         cumap->curr.xmax = cumap->clipr.xmax;
759                 }
760                 if (BLI_rctf_size_y(&cumap->curr) > BLI_rctf_size_y(&cumap->clipr)) {
761                         cumap->curr.ymin = cumap->clipr.ymin;
762                         cumap->curr.ymax = cumap->clipr.ymax;
763                 }
764         }
765         
766         
767         qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints);
768         
769         /* remove doubles, threshold set on 1% of default range */
770         if (rem_doubles && cuma->totpoint > 2) {
771                 for (a = 0; a < cuma->totpoint - 1; a++) {
772                         dx = cmp[a].x - cmp[a + 1].x;
773                         dy = cmp[a].y - cmp[a + 1].y;
774                         if (sqrtf(dx * dx + dy * dy) < thresh) {
775                                 if (a == 0) {
776                                         cmp[a + 1].flag |= CUMA_VECTOR;
777                                         if (cmp[a + 1].flag & CUMA_SELECT)
778                                                 cmp[a].flag |= CUMA_SELECT;
779                                 }
780                                 else {
781                                         cmp[a].flag |= CUMA_VECTOR;
782                                         if (cmp[a].flag & CUMA_SELECT)
783                                                 cmp[a + 1].flag |= CUMA_SELECT;
784                                 }
785                                 break;  /* we assume 1 deletion per edit is ok */
786                         }
787                 }
788                 if (a != cuma->totpoint - 1)
789                         curvemap_remove(cuma, 2);
790         }
791         curvemap_make_table(cuma, clipr);
792 }
793
794 void curvemapping_changed_all(CurveMapping *cumap)
795 {
796         int a, cur = cumap->cur;
797
798         for (a = 0; a < CM_TOT; a++) {
799                 if (cumap->cm[a].curve) {
800                         cumap->cur = a;
801                         curvemapping_changed(cumap, false);
802                 }
803         }
804
805         cumap->cur = cur;
806 }
807
808 /* table should be verified */
809 float curvemap_evaluateF(const CurveMap *cuma, float value)
810 {
811         float fi;
812         int i;
813
814         /* index in table */
815         fi = (value - cuma->mintable) * cuma->range;
816         i = (int)fi;
817         
818         /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */
819         if (fi < 0.0f || fi > CM_TABLE)
820                 return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x);
821         else {
822                 if (i < 0) return cuma->table[0].y;
823                 if (i >= CM_TABLE) return cuma->table[CM_TABLE].y;
824                 
825                 fi = fi - (float)i;
826                 return (1.0f - fi) * cuma->table[i].y + (fi) * cuma->table[i + 1].y;
827         }
828 }
829
830 /* works with curve 'cur' */
831 float curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
832 {
833         const CurveMap *cuma = cumap->cm + cur;
834         float val = curvemap_evaluateF(cuma, value);
835
836         /* account for clipping */
837         if (cumap->flag & CUMA_DO_CLIP) {
838                 if (val < cumap->curr.ymin)
839                         val = cumap->curr.ymin;
840                 else if (val > cumap->curr.ymax)
841                         val = cumap->curr.ymax;
842         }
843
844         return val;
845 }
846
847 /* vector case */
848 void curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], const float vecin[3])
849 {
850         vecout[0] = curvemap_evaluateF(&cumap->cm[0], vecin[0]);
851         vecout[1] = curvemap_evaluateF(&cumap->cm[1], vecin[1]);
852         vecout[2] = curvemap_evaluateF(&cumap->cm[2], vecin[2]);
853 }
854
855 /* RGB case, no black/white points, no premult */
856 void curvemapping_evaluateRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3])
857 {
858         vecout[0] = curvemap_evaluateF(&cumap->cm[0], curvemap_evaluateF(&cumap->cm[3], vecin[0]));
859         vecout[1] = curvemap_evaluateF(&cumap->cm[1], curvemap_evaluateF(&cumap->cm[3], vecin[1]));
860         vecout[2] = curvemap_evaluateF(&cumap->cm[2], curvemap_evaluateF(&cumap->cm[3], vecin[2]));
861 }
862
863 /** same as #curvemapping_evaluate_premulRGBF
864  * but black/bwmul are passed as args for the compositor
865  * where they can change per pixel.
866  *
867  * Use in conjunction with #curvemapping_set_black_white_ex
868  *
869  * \param black Use instead of cumap->black
870  * \param bwmul Use instead of cumap->bwmul
871  */
872 void curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap, float vecout[3], const float vecin[3],
873                                          const float black[3], const float bwmul[3])
874 {
875         vecout[0] = curvemap_evaluateF(&cumap->cm[0], (vecin[0] - black[0]) * bwmul[0]);
876         vecout[1] = curvemap_evaluateF(&cumap->cm[1], (vecin[1] - black[1]) * bwmul[1]);
877         vecout[2] = curvemap_evaluateF(&cumap->cm[2], (vecin[2] - black[2]) * bwmul[2]);
878 }
879
880 /* RGB with black/white points and premult. tables are checked */
881 void curvemapping_evaluate_premulRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3])
882 {
883         vecout[0] = curvemap_evaluateF(&cumap->cm[0], (vecin[0] - cumap->black[0]) * cumap->bwmul[0]);
884         vecout[1] = curvemap_evaluateF(&cumap->cm[1], (vecin[1] - cumap->black[1]) * cumap->bwmul[1]);
885         vecout[2] = curvemap_evaluateF(&cumap->cm[2], (vecin[2] - cumap->black[2]) * cumap->bwmul[2]);
886 }
887
888 /* same as above, byte version */
889 void curvemapping_evaluate_premulRGB(const CurveMapping *cumap, unsigned char vecout_byte[3], const unsigned char vecin_byte[3])
890 {
891         float vecin[3], vecout[3];
892
893         vecin[0] = (float) vecin_byte[0] / 255.0f;
894         vecin[1] = (float) vecin_byte[1] / 255.0f;
895         vecin[2] = (float) vecin_byte[2] / 255.0f;
896
897         curvemapping_evaluate_premulRGBF(cumap, vecout, vecin);
898
899         vecout_byte[0] = FTOCHAR(vecout[0]);
900         vecout_byte[1] = FTOCHAR(vecout[1]);
901         vecout_byte[2] = FTOCHAR(vecout[2]);
902 }
903
904 int curvemapping_RGBA_does_something(const CurveMapping *cumap)
905 {
906         int a;
907         
908         if (cumap->black[0] != 0.0f) return 1;
909         if (cumap->black[1] != 0.0f) return 1;
910         if (cumap->black[2] != 0.0f) return 1;
911         if (cumap->white[0] != 1.0f) return 1;
912         if (cumap->white[1] != 1.0f) return 1;
913         if (cumap->white[2] != 1.0f) return 1;
914         
915         for (a = 0; a < CM_TOT; a++) {
916                 if (cumap->cm[a].curve) {
917                         if (cumap->cm[a].totpoint != 2) return 1;
918                         
919                         if (cumap->cm[a].curve[0].x != 0.0f) return 1;
920                         if (cumap->cm[a].curve[0].y != 0.0f) return 1;
921                         if (cumap->cm[a].curve[1].x != 1.0f) return 1;
922                         if (cumap->cm[a].curve[1].y != 1.0f) return 1;
923                 }
924         }
925         return 0;
926 }
927
928 void curvemapping_initialize(CurveMapping *cumap)
929 {
930         int a;
931         
932         if (cumap == NULL) return;
933         
934         for (a = 0; a < CM_TOT; a++) {
935                 if (cumap->cm[a].table == NULL)
936                         curvemap_make_table(cumap->cm + a, &cumap->clipr);
937         }
938 }
939
940 void curvemapping_table_RGBA(const CurveMapping *cumap, float **array, int *size)
941 {
942         int a;
943         
944         *size = CM_TABLE + 1;
945         *array = MEM_callocN(sizeof(float) * (*size) * 4, "CurveMapping");
946
947         for (a = 0; a < *size; a++) {
948                 if (cumap->cm[0].table)
949                         (*array)[a * 4 + 0] = cumap->cm[0].table[a].y;
950                 if (cumap->cm[1].table)
951                         (*array)[a * 4 + 1] = cumap->cm[1].table[a].y;
952                 if (cumap->cm[2].table)
953                         (*array)[a * 4 + 2] = cumap->cm[2].table[a].y;
954                 if (cumap->cm[3].table)
955                         (*array)[a * 4 + 3] = cumap->cm[3].table[a].y;
956         }
957 }
958
959 /* ***************** Histogram **************** */
960
961 #define INV_255     (1.f / 255.f)
962
963 BLI_INLINE int get_bin_float(float f)
964 {
965         int bin = (int)((f * 255.0f) + 0.5f);  /* 0.5 to prevent quantisation differences */
966
967         /* note: clamp integer instead of float to avoid problems with NaN */
968         CLAMP(bin, 0, 255);
969
970         return bin;
971 }
972
973 static void save_sample_line(Scopes *scopes, const int idx, const float fx, const float rgb[3], const float ycc[3])
974 {
975         float yuv[3];
976
977         /* vectorscope*/
978         rgb_to_yuv(rgb[0], rgb[1], rgb[2], &yuv[0], &yuv[1], &yuv[2]);
979         scopes->vecscope[idx + 0] = yuv[1];
980         scopes->vecscope[idx + 1] = yuv[2];
981
982         /* waveform */
983         switch (scopes->wavefrm_mode) {
984                 case SCOPES_WAVEFRM_RGB:
985                         scopes->waveform_1[idx + 0] = fx;
986                         scopes->waveform_1[idx + 1] = rgb[0];
987                         scopes->waveform_2[idx + 0] = fx;
988                         scopes->waveform_2[idx + 1] = rgb[1];
989                         scopes->waveform_3[idx + 0] = fx;
990                         scopes->waveform_3[idx + 1] = rgb[2];
991                         break;
992                 case SCOPES_WAVEFRM_LUMA:
993                         scopes->waveform_1[idx + 0] = fx;
994                         scopes->waveform_1[idx + 1] = ycc[0];
995                         break;
996                 case SCOPES_WAVEFRM_YCC_JPEG:
997                 case SCOPES_WAVEFRM_YCC_709:
998                 case SCOPES_WAVEFRM_YCC_601:
999                         scopes->waveform_1[idx + 0] = fx;
1000                         scopes->waveform_1[idx + 1] = ycc[0];
1001                         scopes->waveform_2[idx + 0] = fx;
1002                         scopes->waveform_2[idx + 1] = ycc[1];
1003                         scopes->waveform_3[idx + 0] = fx;
1004                         scopes->waveform_3[idx + 1] = ycc[2];
1005                         break;
1006         }
1007 }
1008
1009 void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
1010                                       const ColorManagedDisplaySettings *display_settings)
1011 {
1012         int i, x, y;
1013         const float *fp;
1014         unsigned char *cp;
1015
1016         int x1 = 0.5f + hist->co[0][0] * ibuf->x;
1017         int x2 = 0.5f + hist->co[1][0] * ibuf->x;
1018         int y1 = 0.5f + hist->co[0][1] * ibuf->y;
1019         int y2 = 0.5f + hist->co[1][1] * ibuf->y;
1020
1021         struct ColormanageProcessor *cm_processor = NULL;
1022
1023         hist->channels = 3;
1024         hist->x_resolution = 256;
1025         hist->xmax = 1.0f;
1026         /* hist->ymax = 1.0f; */ /* now do this on the operator _only_ */
1027
1028         if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
1029
1030         if (ibuf->rect_float)
1031                 cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1032
1033         for (i = 0; i < 256; i++) {
1034                 x = (int)(0.5f + x1 + (float)i * (x2 - x1) / 255.0f);
1035                 y = (int)(0.5f + y1 + (float)i * (y2 - y1) / 255.0f);
1036
1037                 if (x < 0 || y < 0 || x >= ibuf->x || y >= ibuf->y) {
1038                         hist->data_luma[i] = hist->data_r[i] = hist->data_g[i] = hist->data_b[i] = hist->data_a[i] = 0.0f;
1039                 }
1040                 else {
1041                         if (ibuf->rect_float) {
1042                                 float rgba[4];
1043                                 fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
1044
1045                                 switch (ibuf->channels) {
1046                                         case 4:
1047                                                 copy_v4_v4(rgba, fp);
1048                                                 IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
1049                                                 break;
1050                                         case 3:
1051                                                 copy_v3_v3(rgba, fp);
1052                                                 IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
1053                                                 rgba[3] = 1.0f;
1054                                                 break;
1055                                         case 2:
1056                                                 copy_v3_fl(rgba, fp[0]);
1057                                                 rgba[3] = fp[1];
1058                                                 break;
1059                                         case 1:
1060                                                 copy_v3_fl(rgba, fp[0]);
1061                                                 rgba[3] = 1.0f;
1062                                                 break;
1063                                         default:
1064                                                 BLI_assert(0);
1065                                 }
1066
1067                                 hist->data_luma[i]  = IMB_colormanagement_get_luminance(rgba);
1068                                 hist->data_r[i]     = rgba[0];
1069                                 hist->data_g[i]     = rgba[1];
1070                                 hist->data_b[i]     = rgba[2];
1071                                 hist->data_a[i]     = rgba[3];
1072                         }
1073                         else if (ibuf->rect) {
1074                                 cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
1075                                 hist->data_luma[i]  = (float)IMB_colormanagement_get_luminance_byte(cp) / 255.0f;
1076                                 hist->data_r[i]     = (float)cp[0] / 255.0f;
1077                                 hist->data_g[i]     = (float)cp[1] / 255.0f;
1078                                 hist->data_b[i]     = (float)cp[2] / 255.0f;
1079                                 hist->data_a[i]     = (float)cp[3] / 255.0f;
1080                         }
1081                 }
1082         }
1083
1084         if (cm_processor)
1085                 IMB_colormanagement_processor_free(cm_processor);
1086 }
1087
1088 /* if view_settings, it also applies this to byte buffers */
1089 typedef struct ScopesUpdateData {
1090         Scopes *scopes;
1091         const ImBuf *ibuf;
1092         struct ColormanageProcessor *cm_processor;
1093         const unsigned char *display_buffer;
1094         const int ycc_mode;
1095
1096         unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a;
1097 } ScopesUpdateData;
1098
1099 typedef struct ScopesUpdateDataChunk {
1100         unsigned int bin_lum[256];
1101         unsigned int bin_r[256];
1102         unsigned int bin_g[256];
1103         unsigned int bin_b[256];
1104         unsigned int bin_a[256];
1105         float min[3], max[3];
1106 } ScopesUpdateDataChunk;
1107
1108 static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid))
1109 {
1110         const ScopesUpdateData *data = userdata;
1111
1112         Scopes *scopes = data->scopes;
1113         const ImBuf *ibuf = data->ibuf;
1114         struct ColormanageProcessor *cm_processor = data->cm_processor;
1115         const unsigned char *display_buffer = data->display_buffer;
1116         const int ycc_mode = data->ycc_mode;
1117
1118         ScopesUpdateDataChunk *data_chunk = userdata_chunk;
1119         unsigned int *bin_lum = data_chunk->bin_lum;
1120         unsigned int *bin_r = data_chunk->bin_r;
1121         unsigned int *bin_g = data_chunk->bin_g;
1122         unsigned int *bin_b = data_chunk->bin_b;
1123         unsigned int *bin_a = data_chunk->bin_a;
1124         float *min = data_chunk->min;
1125         float *max = data_chunk->max;
1126
1127         const float *rf = NULL;
1128         const unsigned char *rc = NULL;
1129         const int rows_per_sample_line = ibuf->y / scopes->sample_lines;
1130         const int savedlines = y / rows_per_sample_line;
1131         const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0;
1132         const bool is_float = (ibuf->rect_float != NULL);
1133
1134         if (is_float)
1135                 rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
1136         else {
1137                 rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
1138         }
1139
1140         for (int x = 0; x < ibuf->x; x++) {
1141                 float rgba[4], ycc[3], luma;
1142
1143                 if (is_float) {
1144                         switch (ibuf->channels) {
1145                                 case 4:
1146                                         copy_v4_v4(rgba, rf);
1147                                         IMB_colormanagement_processor_apply_v4(cm_processor, rgba);
1148                                         break;
1149                                 case 3:
1150                                         copy_v3_v3(rgba, rf);
1151                                         IMB_colormanagement_processor_apply_v3(cm_processor, rgba);
1152                                         rgba[3] = 1.0f;
1153                                         break;
1154                                 case 2:
1155                                         copy_v3_fl(rgba, rf[0]);
1156                                         rgba[3] = rf[1];
1157                                         break;
1158                                 case 1:
1159                                         copy_v3_fl(rgba, rf[0]);
1160                                         rgba[3] = 1.0f;
1161                                         break;
1162                                 default:
1163                                         BLI_assert(0);
1164                         }
1165                 }
1166                 else {
1167                         for (int c = 4; c--;)
1168                                 rgba[c] = rc[c] * INV_255;
1169                 }
1170
1171                 /* we still need luma for histogram */
1172                 luma = IMB_colormanagement_get_luminance(rgba);
1173
1174                 /* check for min max */
1175                 if (ycc_mode == -1) {
1176                         minmax_v3v3_v3(min, max, rgba);
1177                 }
1178                 else {
1179                         rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
1180                         mul_v3_fl(ycc, INV_255);
1181                         minmax_v3v3_v3(min, max, ycc);
1182                 }
1183                 /* increment count for histo*/
1184                 bin_lum[get_bin_float(luma)]++;
1185                 bin_r[get_bin_float(rgba[0])]++;
1186                 bin_g[get_bin_float(rgba[1])]++;
1187                 bin_b[get_bin_float(rgba[2])]++;
1188                 bin_a[get_bin_float(rgba[3])]++;
1189
1190                 /* save sample if needed */
1191                 if (do_sample_line) {
1192                         const float fx = (float)x / (float)ibuf->x;
1193                         const int idx = 2 * (ibuf->x * savedlines + x);
1194                         save_sample_line(scopes, idx, fx, rgba, ycc);
1195                 }
1196
1197                 rf += ibuf->channels;
1198                 rc += ibuf->channels;
1199         }
1200 }
1201
1202 static void scopes_update_finalize(void *userdata, void *userdata_chunk)
1203 {
1204         const ScopesUpdateData *data = userdata;
1205         const ScopesUpdateDataChunk *data_chunk = userdata_chunk;
1206
1207         unsigned int *bin_lum = data->bin_lum;
1208         unsigned int *bin_r = data->bin_r;
1209         unsigned int *bin_g = data->bin_g;
1210         unsigned int *bin_b = data->bin_b;
1211         unsigned int *bin_a = data->bin_a;
1212         const unsigned int *bin_lum_c = data_chunk->bin_lum;
1213         const unsigned int *bin_r_c = data_chunk->bin_r;
1214         const unsigned int *bin_g_c = data_chunk->bin_g;
1215         const unsigned int *bin_b_c = data_chunk->bin_b;
1216         const unsigned int *bin_a_c = data_chunk->bin_a;
1217
1218         float (*minmax)[2] = data->scopes->minmax;
1219         const float *min = data_chunk->min;
1220         const float *max = data_chunk->max;
1221
1222         for (int b = 256; b--;) {
1223                 bin_lum[b] += bin_lum_c[b];
1224                 bin_r[b] += bin_r_c[b];
1225                 bin_g[b] += bin_g_c[b];
1226                 bin_b[b] += bin_b_c[b];
1227                 bin_a[b] += bin_a_c[b];
1228         }
1229
1230         for (int c = 3; c--;) {
1231                 if (min[c] < minmax[c][0])
1232                         minmax[c][0] = min[c];
1233                 if (max[c] > minmax[c][1])
1234                         minmax[c][1] = max[c];
1235         }
1236 }
1237
1238 void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings,
1239                    const ColorManagedDisplaySettings *display_settings)
1240 {
1241         int a;
1242         unsigned int nl, na, nr, ng, nb;
1243         double divl, diva, divr, divg, divb;
1244         const unsigned char *display_buffer = NULL;
1245         unsigned int bin_lum[256] = {0},
1246                      bin_r[256] = {0},
1247                      bin_g[256] = {0},
1248                      bin_b[256] = {0},
1249                      bin_a[256] = {0};
1250         int ycc_mode = -1;
1251         void *cache_handle = NULL;
1252         struct ColormanageProcessor *cm_processor = NULL;
1253
1254         if (ibuf->rect == NULL && ibuf->rect_float == NULL) return;
1255
1256         if (scopes->ok == 1) return;
1257
1258         if (scopes->hist.ymax == 0.f) scopes->hist.ymax = 1.f;
1259
1260         /* hmmmm */
1261         if (!(ELEM(ibuf->channels, 3, 4))) return;
1262
1263         scopes->hist.channels = 3;
1264         scopes->hist.x_resolution = 256;
1265
1266         switch (scopes->wavefrm_mode) {
1267                 case SCOPES_WAVEFRM_RGB:
1268                         ycc_mode = -1;
1269                         break;
1270                 case SCOPES_WAVEFRM_LUMA:
1271                 case SCOPES_WAVEFRM_YCC_JPEG:
1272                         ycc_mode = BLI_YCC_JFIF_0_255;
1273                         break;
1274                 case SCOPES_WAVEFRM_YCC_601:
1275                         ycc_mode = BLI_YCC_ITU_BT601;
1276                         break;
1277                 case SCOPES_WAVEFRM_YCC_709:
1278                         ycc_mode = BLI_YCC_ITU_BT709;
1279                         break;
1280         }
1281
1282         /* convert to number of lines with logarithmic scale */
1283         scopes->sample_lines = (scopes->accuracy * 0.01f) * (scopes->accuracy * 0.01f) * ibuf->y;
1284         CLAMP_MIN(scopes->sample_lines, 1);
1285         
1286         if (scopes->sample_full)
1287                 scopes->sample_lines = ibuf->y;
1288
1289         /* scan the image */
1290         for (a = 0; a < 3; a++) {
1291                 scopes->minmax[a][0] = 25500.0f;
1292                 scopes->minmax[a][1] = -25500.0f;
1293         }
1294         
1295         scopes->waveform_tot = ibuf->x * scopes->sample_lines;
1296         
1297         if (scopes->waveform_1)
1298                 MEM_freeN(scopes->waveform_1);
1299         if (scopes->waveform_2)
1300                 MEM_freeN(scopes->waveform_2);
1301         if (scopes->waveform_3)
1302                 MEM_freeN(scopes->waveform_3);
1303         if (scopes->vecscope)
1304                 MEM_freeN(scopes->vecscope);
1305         
1306         scopes->waveform_1 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 1");
1307         scopes->waveform_2 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 2");
1308         scopes->waveform_3 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 3");
1309         scopes->vecscope = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "vectorscope point channel");
1310         
1311         if (ibuf->rect_float) {
1312                 cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1313         }
1314         else {
1315                 display_buffer = (const unsigned char *)IMB_display_buffer_acquire(
1316                                                             ibuf, view_settings, display_settings, &cache_handle);
1317         }
1318
1319         /* Keep number of threads in sync with the merge parts below. */
1320         ScopesUpdateData data = {
1321                 .scopes = scopes, . ibuf = ibuf,
1322                 .cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode,
1323                 .bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a,
1324         };
1325         ScopesUpdateDataChunk data_chunk = {0};
1326         INIT_MINMAX(data_chunk.min, data_chunk.max);
1327
1328         BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk),
1329                                          scopes_update_cb, scopes_update_finalize, ibuf->y > 256, false);
1330
1331         /* test for nicer distribution even - non standard, leave it out for a while */
1332 #if 0
1333         for (a = 0; a < 256; a++) {
1334                 bin_lum[a] = sqrt (bin_lum[a]);
1335                 bin_r[a] = sqrt(bin_r[a]);
1336                 bin_g[a] = sqrt(bin_g[a]);
1337                 bin_b[a] = sqrt(bin_b[a]);
1338                 bin_a[a] = sqrt(bin_a[a]);
1339         }
1340 #endif
1341         
1342         /* convert hist data to float (proportional to max count) */
1343         nl = na = nr = nb = ng = 0;
1344         for (a = 0; a < 256; a++) {
1345                 if (bin_lum[a] > nl) nl = bin_lum[a];
1346                 if (bin_r[a]   > nr) nr = bin_r[a];
1347                 if (bin_g[a]   > ng) ng = bin_g[a];
1348                 if (bin_b[a]   > nb) nb = bin_b[a];
1349                 if (bin_a[a]   > na) na = bin_a[a];
1350         }
1351         divl = nl ? 1.0 / (double)nl : 1.0;
1352         diva = na ? 1.0 / (double)na : 1.0;
1353         divr = nr ? 1.0 / (double)nr : 1.0;
1354         divg = ng ? 1.0 / (double)ng : 1.0;
1355         divb = nb ? 1.0 / (double)nb : 1.0;
1356         
1357         for (a = 0; a < 256; a++) {
1358                 scopes->hist.data_luma[a] = bin_lum[a] * divl;
1359                 scopes->hist.data_r[a] = bin_r[a] * divr;
1360                 scopes->hist.data_g[a] = bin_g[a] * divg;
1361                 scopes->hist.data_b[a] = bin_b[a] * divb;
1362                 scopes->hist.data_a[a] = bin_a[a] * diva;
1363         }
1364
1365         if (cm_processor)
1366                 IMB_colormanagement_processor_free(cm_processor);
1367         if (cache_handle)
1368                 IMB_display_buffer_release(cache_handle);
1369         
1370         scopes->ok = 1;
1371 }
1372
1373 void scopes_free(Scopes *scopes)
1374 {
1375         if (scopes->waveform_1) {
1376                 MEM_freeN(scopes->waveform_1);
1377                 scopes->waveform_1 = NULL;
1378         }
1379         if (scopes->waveform_2) {
1380                 MEM_freeN(scopes->waveform_2);
1381                 scopes->waveform_2 = NULL;
1382         }
1383         if (scopes->waveform_3) {
1384                 MEM_freeN(scopes->waveform_3);
1385                 scopes->waveform_3 = NULL;
1386         }
1387         if (scopes->vecscope) {
1388                 MEM_freeN(scopes->vecscope);
1389                 scopes->vecscope = NULL;
1390         }
1391 }
1392
1393 void scopes_new(Scopes *scopes)
1394 {
1395         scopes->accuracy = 30.0;
1396         scopes->hist.mode = HISTO_MODE_RGB;
1397         scopes->wavefrm_alpha = 0.3;
1398         scopes->vecscope_alpha = 0.3;
1399         scopes->wavefrm_height = 100;
1400         scopes->vecscope_height = 100;
1401         scopes->hist.height = 100;
1402         scopes->ok = 0;
1403         scopes->waveform_1 = NULL;
1404         scopes->waveform_2 = NULL;
1405         scopes->waveform_3 = NULL;
1406         scopes->vecscope = NULL;
1407 }
1408
1409 void BKE_color_managed_display_settings_init(ColorManagedDisplaySettings *settings)
1410 {
1411         const char *display_name = IMB_colormanagement_display_get_default_name();
1412
1413         BLI_strncpy(settings->display_device, display_name, sizeof(settings->display_device));
1414 }
1415
1416 void BKE_color_managed_display_settings_copy(ColorManagedDisplaySettings *new_settings,
1417                                              const ColorManagedDisplaySettings *settings)
1418 {
1419         BLI_strncpy(new_settings->display_device, settings->display_device, sizeof(new_settings->display_device));
1420 }
1421
1422 void BKE_color_managed_view_settings_init(ColorManagedViewSettings *settings)
1423 {
1424         /* OCIO_TODO: use default view transform here when OCIO is completely integrated
1425          *            and proper versioning stuff is added.
1426          *            for now use NONE to be compatible with all current files
1427          */
1428         BLI_strncpy(settings->view_transform, "Default", sizeof(settings->view_transform));
1429         BLI_strncpy(settings->look, "None", sizeof(settings->look));
1430
1431         settings->gamma = 1.0f;
1432         settings->exposure = 0.0f;
1433 }
1434
1435 void BKE_color_managed_view_settings_copy(ColorManagedViewSettings *new_settings,
1436                                           const ColorManagedViewSettings *settings)
1437 {
1438         BLI_strncpy(new_settings->look, settings->look, sizeof(new_settings->look));
1439         BLI_strncpy(new_settings->view_transform, settings->view_transform, sizeof(new_settings->view_transform));
1440
1441         new_settings->flag = settings->flag;
1442         new_settings->exposure = settings->exposure;
1443         new_settings->gamma = settings->gamma;
1444
1445         if (settings->curve_mapping)
1446                 new_settings->curve_mapping = curvemapping_copy(settings->curve_mapping);
1447         else
1448                 new_settings->curve_mapping = NULL;
1449 }
1450
1451 void BKE_color_managed_view_settings_free(ColorManagedViewSettings *settings)
1452 {
1453         if (settings->curve_mapping)
1454                 curvemapping_free(settings->curve_mapping);
1455 }
1456
1457 void BKE_color_managed_colorspace_settings_init(ColorManagedColorspaceSettings *colorspace_settings)
1458 {
1459         BLI_strncpy(colorspace_settings->name, "", sizeof(colorspace_settings->name));
1460 }
1461
1462 void BKE_color_managed_colorspace_settings_copy(ColorManagedColorspaceSettings *colorspace_settings,
1463                                                 const ColorManagedColorspaceSettings *settings)
1464 {
1465         BLI_strncpy(colorspace_settings->name, settings->name, sizeof(colorspace_settings->name));
1466 }
1467
1468 bool BKE_color_managed_colorspace_settings_equals(const ColorManagedColorspaceSettings *settings1,
1469                                                   const ColorManagedColorspaceSettings *settings2)
1470 {
1471         return STREQ(settings1->name, settings2->name);
1472 }