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