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