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