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