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