Blender  V3.3
colortools.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2005 Blender Foundation. All rights reserved. */
3 
8 #include <float.h>
9 #include <math.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include "MEM_guardedalloc.h"
14 
15 #include "DNA_color_types.h"
16 #include "DNA_curve_types.h"
17 
18 #include "BLI_blenlib.h"
19 #include "BLI_math.h"
20 #include "BLI_task.h"
21 #include "BLI_threads.h"
22 #include "BLI_utildefines.h"
23 
24 #include "BKE_colortools.h"
25 #include "BKE_curve.h"
26 #include "BKE_fcurve.h"
27 
28 #include "IMB_colormanagement.h"
29 #include "IMB_imbuf_types.h"
30 
31 #include "BLO_read_write.h"
32 
33 /* ********************************* color curve ********************* */
34 
35 /* ***************** operations on full struct ************* */
36 
38  CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy)
39 {
40  int a;
41  float clipminx, clipminy, clipmaxx, clipmaxy;
42 
44  if (tot == 4) {
45  cumap->cur = 3; /* rhms, hack for 'col' curve? */
46  }
47 
48  clipminx = min_ff(minx, maxx);
49  clipminy = min_ff(miny, maxy);
50  clipmaxx = max_ff(minx, maxx);
51  clipmaxy = max_ff(miny, maxy);
52 
53  BLI_rctf_init(&cumap->curr, clipminx, clipmaxx, clipminy, clipmaxy);
54  cumap->clipr = cumap->curr;
55 
56  cumap->white[0] = cumap->white[1] = cumap->white[2] = 1.0f;
57  cumap->bwmul[0] = cumap->bwmul[1] = cumap->bwmul[2] = 1.0f;
58 
59  for (a = 0; a < tot; a++) {
60  cumap->cm[a].totpoint = 2;
61  cumap->cm[a].curve = MEM_callocN(2 * sizeof(CurveMapPoint), "curve points");
62 
63  cumap->cm[a].curve[0].x = minx;
64  cumap->cm[a].curve[0].y = miny;
65  cumap->cm[a].curve[1].x = maxx;
66  cumap->cm[a].curve[1].y = maxy;
67  }
68 
69  cumap->changed_timestamp = 0;
70 }
71 
72 CurveMapping *BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
73 {
74  CurveMapping *cumap;
75 
76  cumap = MEM_callocN(sizeof(CurveMapping), "new curvemap");
77 
78  BKE_curvemapping_set_defaults(cumap, tot, minx, miny, maxx, maxy);
79 
80  return cumap;
81 }
82 
84 {
85  int a;
86 
87  for (a = 0; a < CM_TOT; a++) {
88  if (cumap->cm[a].curve) {
89  MEM_freeN(cumap->cm[a].curve);
90  cumap->cm[a].curve = NULL;
91  }
92  if (cumap->cm[a].table) {
93  MEM_freeN(cumap->cm[a].table);
94  cumap->cm[a].table = NULL;
95  }
96  if (cumap->cm[a].premultable) {
97  MEM_freeN(cumap->cm[a].premultable);
98  cumap->cm[a].premultable = NULL;
99  }
100  }
101 }
102 
104 {
105  if (cumap) {
107  MEM_freeN(cumap);
108  }
109 }
110 
112 {
113  int a;
114 
115  *target = *cumap;
116 
117  for (a = 0; a < CM_TOT; a++) {
118  if (cumap->cm[a].curve) {
119  target->cm[a].curve = MEM_dupallocN(cumap->cm[a].curve);
120  }
121  if (cumap->cm[a].table) {
122  target->cm[a].table = MEM_dupallocN(cumap->cm[a].table);
123  }
124  if (cumap->cm[a].premultable) {
125  target->cm[a].premultable = MEM_dupallocN(cumap->cm[a].premultable);
126  }
127  }
128 }
129 
131 {
132  if (cumap) {
133  CurveMapping *cumapn = MEM_dupallocN(cumap);
134  BKE_curvemapping_copy_data(cumapn, cumap);
135  return cumapn;
136  }
137  return NULL;
138 }
139 
140 void BKE_curvemapping_set_black_white_ex(const float black[3],
141  const float white[3],
142  float r_bwmul[3])
143 {
144  int a;
145 
146  for (a = 0; a < 3; a++) {
147  const float delta = max_ff(white[a] - black[a], 1e-5f);
148  r_bwmul[a] = 1.0f / delta;
149  }
150 }
151 
153  const float black[3],
154  const float white[3])
155 {
156  if (white) {
157  copy_v3_v3(cumap->white, white);
158  }
159  if (black) {
160  copy_v3_v3(cumap->black, black);
161  }
162 
163  BKE_curvemapping_set_black_white_ex(cumap->black, cumap->white, cumap->bwmul);
164  cumap->changed_timestamp++;
165 }
166 
167 /* ***************** operations on single curve ************* */
168 /* ********** NOTE: requires BKE_curvemapping_changed() call after ******** */
169 
171 {
172  CurveMapPoint *cmp;
173  int a, b, removed = 0;
174 
175  /* must have 2 points minimum */
176  if (cuma->totpoint <= 2) {
177  return false;
178  }
179 
180  cmp = MEM_mallocN((cuma->totpoint) * sizeof(CurveMapPoint), "curve points");
181 
182  /* well, lets keep the two outer points! */
183  for (a = 0, b = 0; a < cuma->totpoint; a++) {
184  if (&cuma->curve[a] != point) {
185  cmp[b] = cuma->curve[a];
186  b++;
187  }
188  else {
189  removed++;
190  }
191  }
192 
193  MEM_freeN(cuma->curve);
194  cuma->curve = cmp;
195  cuma->totpoint -= removed;
196  return (removed != 0);
197 }
198 
199 void BKE_curvemap_remove(CurveMap *cuma, const short flag)
200 {
201  CurveMapPoint *cmp = MEM_mallocN((cuma->totpoint) * sizeof(CurveMapPoint), "curve points");
202  int a, b, removed = 0;
203 
204  /* well, lets keep the two outer points! */
205  cmp[0] = cuma->curve[0];
206  for (a = 1, b = 1; a < cuma->totpoint - 1; a++) {
207  if (!(cuma->curve[a].flag & flag)) {
208  cmp[b] = cuma->curve[a];
209  b++;
210  }
211  else {
212  removed++;
213  }
214  }
215  cmp[b] = cuma->curve[a];
216 
217  MEM_freeN(cuma->curve);
218  cuma->curve = cmp;
219  cuma->totpoint -= removed;
220 }
221 
223 {
224  CurveMapPoint *cmp = MEM_callocN((cuma->totpoint + 1) * sizeof(CurveMapPoint), "curve points");
225  CurveMapPoint *newcmp = NULL;
226  int a, b;
227  bool foundloc = false;
228 
229  /* insert fragments of the old one and the new point to the new curve */
230  cuma->totpoint++;
231  for (a = 0, b = 0; a < cuma->totpoint; a++) {
232  if ((foundloc == false) && ((a + 1 == cuma->totpoint) || (x < cuma->curve[a].x))) {
233  cmp[a].x = x;
234  cmp[a].y = y;
235  cmp[a].flag = CUMA_SELECT;
236  foundloc = true;
237  newcmp = &cmp[a];
238  }
239  else {
240  cmp[a].x = cuma->curve[b].x;
241  cmp[a].y = cuma->curve[b].y;
242  /* make sure old points don't remain selected */
243  cmp[a].flag = cuma->curve[b].flag & ~CUMA_SELECT;
244  cmp[a].shorty = cuma->curve[b].shorty;
245  b++;
246  }
247  }
248 
249  /* free old curve and replace it with new one */
250  MEM_freeN(cuma->curve);
251  cuma->curve = cmp;
252 
253  return newcmp;
254 }
255 
256 void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
257 {
258  if (cuma->curve) {
259  MEM_freeN(cuma->curve);
260  }
261 
262  switch (preset) {
263  case CURVE_PRESET_LINE:
264  cuma->totpoint = 2;
265  break;
266  case CURVE_PRESET_SHARP:
267  cuma->totpoint = 4;
268  break;
269  case CURVE_PRESET_SMOOTH:
270  cuma->totpoint = 4;
271  break;
272  case CURVE_PRESET_MAX:
273  cuma->totpoint = 2;
274  break;
275  case CURVE_PRESET_MID9:
276  cuma->totpoint = 9;
277  break;
278  case CURVE_PRESET_ROUND:
279  cuma->totpoint = 4;
280  break;
281  case CURVE_PRESET_ROOT:
282  cuma->totpoint = 4;
283  break;
284  case CURVE_PRESET_GAUSS:
285  cuma->totpoint = 7;
286  break;
287  case CURVE_PRESET_BELL:
288  cuma->totpoint = 3;
289  break;
290  }
291 
292  cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points");
293 
294  switch (preset) {
295  case CURVE_PRESET_LINE:
296  cuma->curve[0].x = clipr->xmin;
297  cuma->curve[0].y = clipr->ymax;
298  cuma->curve[1].x = clipr->xmax;
299  cuma->curve[1].y = clipr->ymin;
300  if (slope == CURVEMAP_SLOPE_POS_NEG) {
301  cuma->curve[0].flag |= CUMA_HANDLE_VECTOR;
302  cuma->curve[1].flag |= CUMA_HANDLE_VECTOR;
303  }
304  break;
305  case CURVE_PRESET_SHARP:
306  cuma->curve[0].x = 0;
307  cuma->curve[0].y = 1;
308  cuma->curve[1].x = 0.25;
309  cuma->curve[1].y = 0.50;
310  cuma->curve[2].x = 0.75;
311  cuma->curve[2].y = 0.04;
312  cuma->curve[3].x = 1;
313  cuma->curve[3].y = 0;
314  break;
315  case CURVE_PRESET_SMOOTH:
316  cuma->curve[0].x = 0;
317  cuma->curve[0].y = 1;
318  cuma->curve[1].x = 0.25;
319  cuma->curve[1].y = 0.94;
320  cuma->curve[2].x = 0.75;
321  cuma->curve[2].y = 0.06;
322  cuma->curve[3].x = 1;
323  cuma->curve[3].y = 0;
324  break;
325  case CURVE_PRESET_MAX:
326  cuma->curve[0].x = 0;
327  cuma->curve[0].y = 1;
328  cuma->curve[1].x = 1;
329  cuma->curve[1].y = 1;
330  break;
331  case CURVE_PRESET_MID9: {
332  for (int i = 0; i < cuma->totpoint; i++) {
333  cuma->curve[i].x = i / ((float)cuma->totpoint - 1);
334  cuma->curve[i].y = 0.5;
335  }
336  break;
337  }
338  case CURVE_PRESET_ROUND:
339  cuma->curve[0].x = 0;
340  cuma->curve[0].y = 1;
341  cuma->curve[1].x = 0.5;
342  cuma->curve[1].y = 0.90;
343  cuma->curve[2].x = 0.86;
344  cuma->curve[2].y = 0.5;
345  cuma->curve[3].x = 1;
346  cuma->curve[3].y = 0;
347  break;
348  case CURVE_PRESET_ROOT:
349  cuma->curve[0].x = 0;
350  cuma->curve[0].y = 1;
351  cuma->curve[1].x = 0.25;
352  cuma->curve[1].y = 0.95;
353  cuma->curve[2].x = 0.75;
354  cuma->curve[2].y = 0.44;
355  cuma->curve[3].x = 1;
356  cuma->curve[3].y = 0;
357  break;
358  case CURVE_PRESET_GAUSS:
359  cuma->curve[0].x = 0;
360  cuma->curve[0].y = 0.025f;
361  cuma->curve[1].x = 0.16f;
362  cuma->curve[1].y = 0.135f;
363  cuma->curve[2].x = 0.298f;
364  cuma->curve[2].y = 0.36f;
365 
366  cuma->curve[3].x = 0.50f;
367  cuma->curve[3].y = 1.0f;
368 
369  cuma->curve[4].x = 0.70f;
370  cuma->curve[4].y = 0.36f;
371  cuma->curve[5].x = 0.84f;
372  cuma->curve[5].y = 0.135f;
373  cuma->curve[6].x = 1.0f;
374  cuma->curve[6].y = 0.025f;
375  break;
376  case CURVE_PRESET_BELL:
377  cuma->curve[0].x = 0.0f;
378  cuma->curve[0].y = 0.025f;
379 
380  cuma->curve[1].x = 0.50f;
381  cuma->curve[1].y = 1.0f;
382 
383  cuma->curve[2].x = 1.0f;
384  cuma->curve[2].y = 0.025f;
385  break;
386  }
387 
388  /* mirror curve in x direction to have positive slope
389  * rather than default negative slope */
390  if (slope == CURVEMAP_SLOPE_POSITIVE) {
391  int i, last = cuma->totpoint - 1;
392  CurveMapPoint *newpoints = MEM_dupallocN(cuma->curve);
393 
394  for (i = 0; i < cuma->totpoint; i++) {
395  newpoints[i].y = cuma->curve[last - i].y;
396  }
397 
398  MEM_freeN(cuma->curve);
399  cuma->curve = newpoints;
400  }
401  else if (slope == CURVEMAP_SLOPE_POS_NEG) {
402  const int num_points = cuma->totpoint * 2 - 1;
403  CurveMapPoint *new_points = MEM_mallocN(num_points * sizeof(CurveMapPoint),
404  "curve symmetric points");
405  for (int i = 0; i < cuma->totpoint; i++) {
406  const int src_last_point = cuma->totpoint - i - 1;
407  const int dst_last_point = num_points - i - 1;
408  new_points[i] = cuma->curve[src_last_point];
409  new_points[i].x = (1.0f - cuma->curve[src_last_point].x) * 0.5f;
410  new_points[dst_last_point] = new_points[i];
411  new_points[dst_last_point].x = 0.5f + cuma->curve[src_last_point].x * 0.5f;
412  }
413  cuma->totpoint = num_points;
414  MEM_freeN(cuma->curve);
415  cuma->curve = new_points;
416  }
417 
418  if (cuma->table) {
419  MEM_freeN(cuma->table);
420  cuma->table = NULL;
421  }
422 }
423 
425 {
426  int a;
427 
428  for (a = 0; a < cuma->totpoint; a++) {
429  if (cuma->curve[a].flag & CUMA_SELECT) {
431  if (type == HD_VECT) {
432  cuma->curve[a].flag |= CUMA_HANDLE_VECTOR;
433  }
434  else if (type == HD_AUTO_ANIM) {
435  cuma->curve[a].flag |= CUMA_HANDLE_AUTO_ANIM;
436  }
437  else {
438  /* pass */
439  }
440  }
441  }
442 }
443 
444 /* *********************** Making the tables and display ************** */
445 
449 static void calchandle_curvemap(BezTriple *bezt, const BezTriple *prev, const BezTriple *next)
450 {
451  /* defines to avoid confusion */
452 #define p2_h1 ((p2)-3)
453 #define p2_h2 ((p2) + 3)
454 
455  const float *p1, *p3;
456  float *p2;
457  float pt[3];
458  float len, len_a, len_b;
459  float dvec_a[2], dvec_b[2];
460 
461  if (bezt->h1 == 0 && bezt->h2 == 0) {
462  return;
463  }
464 
465  p2 = bezt->vec[1];
466 
467  if (prev == NULL) {
468  p3 = next->vec[1];
469  pt[0] = 2.0f * p2[0] - p3[0];
470  pt[1] = 2.0f * p2[1] - p3[1];
471  p1 = pt;
472  }
473  else {
474  p1 = prev->vec[1];
475  }
476 
477  if (next == NULL) {
478  p1 = prev->vec[1];
479  pt[0] = 2.0f * p2[0] - p1[0];
480  pt[1] = 2.0f * p2[1] - p1[1];
481  p3 = pt;
482  }
483  else {
484  p3 = next->vec[1];
485  }
486 
487  sub_v2_v2v2(dvec_a, p2, p1);
488  sub_v2_v2v2(dvec_b, p3, p2);
489 
490  len_a = len_v2(dvec_a);
491  len_b = len_v2(dvec_b);
492 
493  if (len_a == 0.0f) {
494  len_a = 1.0f;
495  }
496  if (len_b == 0.0f) {
497  len_b = 1.0f;
498  }
499 
500  if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */
501  float tvec[2];
502  tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a;
503  tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a;
504 
505  len = len_v2(tvec) * 2.5614f;
506  if (len != 0.0f) {
507 
508  if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) {
509  len_a /= len;
510  madd_v2_v2v2fl(p2_h1, p2, tvec, -len_a);
511 
512  if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
513  const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
514  const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
515  if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
516  bezt->vec[0][1] = bezt->vec[1][1];
517  }
518  else { /* handles should not be beyond y coord of two others */
519  if (ydiff1 <= 0.0f) {
520  if (prev->vec[1][1] > bezt->vec[0][1]) {
521  bezt->vec[0][1] = prev->vec[1][1];
522  }
523  }
524  else {
525  if (prev->vec[1][1] < bezt->vec[0][1]) {
526  bezt->vec[0][1] = prev->vec[1][1];
527  }
528  }
529  }
530  }
531  }
532  if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) {
533  len_b /= len;
534  madd_v2_v2v2fl(p2_h2, p2, tvec, len_b);
535 
536  if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */
537  const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1];
538  const float ydiff2 = next->vec[1][1] - bezt->vec[1][1];
539  if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) {
540  bezt->vec[2][1] = bezt->vec[1][1];
541  }
542  else { /* handles should not be beyond y coord of two others */
543  if (ydiff1 <= 0.0f) {
544  if (next->vec[1][1] < bezt->vec[2][1]) {
545  bezt->vec[2][1] = next->vec[1][1];
546  }
547  }
548  else {
549  if (next->vec[1][1] > bezt->vec[2][1]) {
550  bezt->vec[2][1] = next->vec[1][1];
551  }
552  }
553  }
554  }
555  }
556  }
557  }
558 
559  if (bezt->h1 == HD_VECT) { /* vector */
560  madd_v2_v2v2fl(p2_h1, p2, dvec_a, -1.0f / 3.0f);
561  }
562  if (bezt->h2 == HD_VECT) {
563  madd_v2_v2v2fl(p2_h2, p2, dvec_b, 1.0f / 3.0f);
564  }
565 
566 #undef p2_h1
567 #undef p2_h2
568 }
569 
570 /* in X, out Y.
571  * X is presumed to be outside first or last */
572 static float curvemap_calc_extend(const CurveMapping *cumap,
573  const CurveMap *cuma,
574  float x,
575  const float first[2],
576  const float last[2])
577 {
578  if (x <= first[0]) {
579  if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
580  /* extrapolate horizontally */
581  return first[1];
582  }
583 
584  if (cuma->ext_in[0] == 0.0f) {
585  return first[1] + cuma->ext_in[1] * 10000.0f;
586  }
587 
588  return first[1] + cuma->ext_in[1] * (x - first[0]) / cuma->ext_in[0];
589  }
590  if (x >= last[0]) {
591  if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) == 0) {
592  /* extrapolate horizontally */
593  return last[1];
594  }
595 
596  if (cuma->ext_out[0] == 0.0f) {
597  return last[1] - cuma->ext_out[1] * 10000.0f;
598  }
599 
600  return last[1] + cuma->ext_out[1] * (x - last[0]) / cuma->ext_out[0];
601  }
602  return 0.0f;
603 }
604 
605 /* only creates a table for a single channel in CurveMapping */
606 static void curvemap_make_table(const CurveMapping *cumap, CurveMap *cuma)
607 {
608  const rctf *clipr = &cumap->clipr;
609  CurveMapPoint *cmp = cuma->curve;
610  BezTriple *bezt;
611 
612  if (cuma->curve == NULL) {
613  return;
614  }
615 
616  /* default rect also is table range */
617  cuma->mintable = clipr->xmin;
618  cuma->maxtable = clipr->xmax;
619 
620  /* Rely on Blender interpolation for bezier curves, support extra functionality here as well. */
621  bezt = MEM_callocN(cuma->totpoint * sizeof(BezTriple), "beztarr");
622 
623  for (int a = 0; a < cuma->totpoint; a++) {
624  cuma->mintable = min_ff(cuma->mintable, cmp[a].x);
625  cuma->maxtable = max_ff(cuma->maxtable, cmp[a].x);
626  bezt[a].vec[1][0] = cmp[a].x;
627  bezt[a].vec[1][1] = cmp[a].y;
628  if (cmp[a].flag & CUMA_HANDLE_VECTOR) {
629  bezt[a].h1 = bezt[a].h2 = HD_VECT;
630  }
631  else if (cmp[a].flag & CUMA_HANDLE_AUTO_ANIM) {
632  bezt[a].h1 = bezt[a].h2 = HD_AUTO_ANIM;
633  }
634  else {
635  bezt[a].h1 = bezt[a].h2 = HD_AUTO;
636  }
637  }
638 
639  const BezTriple *bezt_prev = NULL;
640  for (int a = 0; a < cuma->totpoint; a++) {
641  const BezTriple *bezt_next = (a != cuma->totpoint - 1) ? &bezt[a + 1] : NULL;
642  calchandle_curvemap(&bezt[a], bezt_prev, bezt_next);
643  bezt_prev = &bezt[a];
644  }
645 
646  /* first and last handle need correction, instead of pointing to center of next/prev,
647  * we let it point to the closest handle */
648  if (cuma->totpoint > 2) {
649  float hlen, nlen, vec[3];
650 
651  if (bezt[0].h2 == HD_AUTO) {
652 
653  hlen = len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */
654  /* clip handle point */
655  copy_v3_v3(vec, bezt[1].vec[0]);
656  if (vec[0] < bezt[0].vec[1][0]) {
657  vec[0] = bezt[0].vec[1][0];
658  }
659 
660  sub_v3_v3(vec, bezt[0].vec[1]);
661  nlen = len_v3(vec);
662  if (nlen > FLT_EPSILON) {
663  mul_v3_fl(vec, hlen / nlen);
664  add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]);
665  sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec);
666  }
667  }
668  int a = cuma->totpoint - 1;
669  if (bezt[a].h2 == HD_AUTO) {
670 
671  hlen = len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */
672  /* clip handle point */
673  copy_v3_v3(vec, bezt[a - 1].vec[2]);
674  if (vec[0] > bezt[a].vec[1][0]) {
675  vec[0] = bezt[a].vec[1][0];
676  }
677 
678  sub_v3_v3(vec, bezt[a].vec[1]);
679  nlen = len_v3(vec);
680  if (nlen > FLT_EPSILON) {
681  mul_v3_fl(vec, hlen / nlen);
682  add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]);
683  sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec);
684  }
685  }
686  }
687  /* make the bezier curve */
688  if (cuma->table) {
689  MEM_freeN(cuma->table);
690  }
691 
692  int totpoint = (cuma->totpoint - 1) * CM_RESOL;
693  float *allpoints = MEM_callocN(totpoint * 2 * sizeof(float), "table");
694  float *point = allpoints;
695 
696  for (int a = 0; a < cuma->totpoint - 1; a++, point += 2 * CM_RESOL) {
698  bezt[a].vec[1], bezt[a].vec[2], bezt[a + 1].vec[0], bezt[a + 1].vec[1]);
699  BKE_curve_forward_diff_bezier(bezt[a].vec[1][0],
700  bezt[a].vec[2][0],
701  bezt[a + 1].vec[0][0],
702  bezt[a + 1].vec[1][0],
703  point,
704  CM_RESOL - 1,
705  sizeof(float[2]));
706  BKE_curve_forward_diff_bezier(bezt[a].vec[1][1],
707  bezt[a].vec[2][1],
708  bezt[a + 1].vec[0][1],
709  bezt[a + 1].vec[1][1],
710  point + 1,
711  CM_RESOL - 1,
712  sizeof(float[2]));
713  }
714 
715  /* store first and last handle for extrapolation, unit length */
716  cuma->ext_in[0] = bezt[0].vec[0][0] - bezt[0].vec[1][0];
717  cuma->ext_in[1] = bezt[0].vec[0][1] - bezt[0].vec[1][1];
718  float ext_in_range = sqrtf(cuma->ext_in[0] * cuma->ext_in[0] +
719  cuma->ext_in[1] * cuma->ext_in[1]);
720  cuma->ext_in[0] /= ext_in_range;
721  cuma->ext_in[1] /= ext_in_range;
722 
723  int out_a = cuma->totpoint - 1;
724  cuma->ext_out[0] = bezt[out_a].vec[1][0] - bezt[out_a].vec[2][0];
725  cuma->ext_out[1] = bezt[out_a].vec[1][1] - bezt[out_a].vec[2][1];
726  float ext_out_range = sqrtf(cuma->ext_out[0] * cuma->ext_out[0] +
727  cuma->ext_out[1] * cuma->ext_out[1]);
728  cuma->ext_out[0] /= ext_out_range;
729  cuma->ext_out[1] /= ext_out_range;
730 
731  /* cleanup */
732  MEM_freeN(bezt);
733 
734  float range = CM_TABLEDIV * (cuma->maxtable - cuma->mintable);
735  cuma->range = 1.0f / range;
736 
737  /* now make a table with CM_TABLE equal x distances */
738  float *firstpoint = allpoints;
739  float *lastpoint = allpoints + 2 * (totpoint - 1);
740  point = allpoints;
741 
742  cmp = MEM_callocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "dist table");
743 
744  for (int a = 0; a <= CM_TABLE; a++) {
745  float cur_x = cuma->mintable + range * (float)a;
746  cmp[a].x = cur_x;
747 
748  /* Get the first point with x coordinate larger than cur_x. */
749  while (cur_x >= point[0] && point != lastpoint) {
750  point += 2;
751  }
752 
753  /* Check if we are on or outside the start or end point. */
754  if (point == firstpoint || (point == lastpoint && cur_x >= point[0])) {
755  if (compare_ff(cur_x, point[0], 1e-6f)) {
756  /* When on the point exactly, use the value directly to avoid precision
757  * issues with extrapolation of extreme slopes. */
758  cmp[a].y = point[1];
759  }
760  else {
761  /* Extrapolate values that lie outside the start and end point. */
762  cmp[a].y = curvemap_calc_extend(cumap, cuma, cur_x, firstpoint, lastpoint);
763  }
764  }
765  else {
766  float fac1 = point[0] - point[-2];
767  float fac2 = point[0] - cur_x;
768  if (fac1 > FLT_EPSILON) {
769  fac1 = fac2 / fac1;
770  }
771  else {
772  fac1 = 0.0f;
773  }
774  cmp[a].y = fac1 * point[-1] + (1.0f - fac1) * point[1];
775  }
776  }
777 
778  MEM_freeN(allpoints);
779  cuma->table = cmp;
780 }
781 
782 void BKE_curvemapping_premultiply(CurveMapping *cumap, bool restore)
783 {
784  /* It uses a flag to prevent pre-multiply or free to happen twice. */
785 
786  int a;
787 
788  if (restore) {
789  if (cumap->flag & CUMA_PREMULLED) {
790  for (a = 0; a < 3; a++) {
791  MEM_freeN(cumap->cm[a].table);
792  cumap->cm[a].table = cumap->cm[a].premultable;
793  cumap->cm[a].premultable = NULL;
794 
795  copy_v2_v2(cumap->cm[a].ext_in, cumap->cm[a].premul_ext_in);
796  copy_v2_v2(cumap->cm[a].ext_out, cumap->cm[a].premul_ext_out);
797  zero_v2(cumap->cm[a].premul_ext_in);
798  zero_v2(cumap->cm[a].premul_ext_out);
799  }
800 
801  cumap->flag &= ~CUMA_PREMULLED;
802  }
803  }
804  else {
805  if ((cumap->flag & CUMA_PREMULLED) == 0) {
806  /* verify and copy */
807  for (a = 0; a < 3; a++) {
808  if (cumap->cm[a].table == NULL) {
809  curvemap_make_table(cumap, cumap->cm + a);
810  }
811  cumap->cm[a].premultable = cumap->cm[a].table;
812  cumap->cm[a].table = MEM_mallocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "premul table");
813  memcpy(
814  cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE + 1) * sizeof(CurveMapPoint));
815  }
816 
817  if (cumap->cm[3].table == NULL) {
818  curvemap_make_table(cumap, cumap->cm + 3);
819  }
820 
821  /* premul */
822  for (a = 0; a < 3; a++) {
823  int b;
824  for (b = 0; b <= CM_TABLE; b++) {
825  cumap->cm[a].table[b].y = BKE_curvemap_evaluateF(
826  cumap, cumap->cm + 3, cumap->cm[a].table[b].y);
827  }
828 
829  copy_v2_v2(cumap->cm[a].premul_ext_in, cumap->cm[a].ext_in);
830  copy_v2_v2(cumap->cm[a].premul_ext_out, cumap->cm[a].ext_out);
831  mul_v2_v2(cumap->cm[a].ext_in, cumap->cm[3].ext_in);
832  mul_v2_v2(cumap->cm[a].ext_out, cumap->cm[3].ext_out);
833  }
834 
835  cumap->flag |= CUMA_PREMULLED;
836  }
837  }
838 }
839 
840 static int sort_curvepoints(const void *a1, const void *a2)
841 {
842  const struct CurveMapPoint *x1 = a1, *x2 = a2;
843 
844  if (x1->x > x2->x) {
845  return 1;
846  }
847  if (x1->x < x2->x) {
848  return -1;
849  }
850  return 0;
851 }
852 
853 /* ************************ more CurveMapping calls *************** */
854 
855 void BKE_curvemapping_changed(CurveMapping *cumap, const bool rem_doubles)
856 {
857  CurveMap *cuma = cumap->cm + cumap->cur;
858  CurveMapPoint *cmp = cuma->curve;
859  rctf *clipr = &cumap->clipr;
860  float thresh = 0.01f * BLI_rctf_size_x(clipr);
861  float dx = 0.0f, dy = 0.0f;
862  int a;
863 
864  cumap->changed_timestamp++;
865 
866  /* clamp with clip */
867  if (cumap->flag & CUMA_DO_CLIP) {
868  for (a = 0; a < cuma->totpoint; a++) {
869  if (cmp[a].flag & CUMA_SELECT) {
870  if (cmp[a].x < clipr->xmin) {
871  dx = min_ff(dx, cmp[a].x - clipr->xmin);
872  }
873  else if (cmp[a].x > clipr->xmax) {
874  dx = max_ff(dx, cmp[a].x - clipr->xmax);
875  }
876  if (cmp[a].y < clipr->ymin) {
877  dy = min_ff(dy, cmp[a].y - clipr->ymin);
878  }
879  else if (cmp[a].y > clipr->ymax) {
880  dy = max_ff(dy, cmp[a].y - clipr->ymax);
881  }
882  }
883  }
884  for (a = 0; a < cuma->totpoint; a++) {
885  if (cmp[a].flag & CUMA_SELECT) {
886  cmp[a].x -= dx;
887  cmp[a].y -= dy;
888  }
889  }
890 
891  /* ensure zoom-level respects clipping */
892  if (BLI_rctf_size_x(&cumap->curr) > BLI_rctf_size_x(&cumap->clipr)) {
893  cumap->curr.xmin = cumap->clipr.xmin;
894  cumap->curr.xmax = cumap->clipr.xmax;
895  }
896  if (BLI_rctf_size_y(&cumap->curr) > BLI_rctf_size_y(&cumap->clipr)) {
897  cumap->curr.ymin = cumap->clipr.ymin;
898  cumap->curr.ymax = cumap->clipr.ymax;
899  }
900  }
901 
902  qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints);
903 
904  /* remove doubles, threshold set on 1% of default range */
905  if (rem_doubles && cuma->totpoint > 2) {
906  for (a = 0; a < cuma->totpoint - 1; a++) {
907  dx = cmp[a].x - cmp[a + 1].x;
908  dy = cmp[a].y - cmp[a + 1].y;
909  if (sqrtf(dx * dx + dy * dy) < thresh) {
910  if (a == 0) {
911  cmp[a + 1].flag |= CUMA_HANDLE_VECTOR;
912  if (cmp[a + 1].flag & CUMA_SELECT) {
913  cmp[a].flag |= CUMA_SELECT;
914  }
915  }
916  else {
917  cmp[a].flag |= CUMA_HANDLE_VECTOR;
918  if (cmp[a].flag & CUMA_SELECT) {
919  cmp[a + 1].flag |= CUMA_SELECT;
920  }
921  }
922  break; /* we assume 1 deletion per edit is ok */
923  }
924  }
925  if (a != cuma->totpoint - 1) {
926  BKE_curvemap_remove(cuma, 2);
927  }
928  }
929  curvemap_make_table(cumap, cuma);
930 }
931 
933 {
934  int a, cur = cumap->cur;
935 
936  for (a = 0; a < CM_TOT; a++) {
937  if (cumap->cm[a].curve) {
938  cumap->cur = a;
939  BKE_curvemapping_changed(cumap, false);
940  }
941  }
942 
943  cumap->cur = cur;
944 }
945 
947 {
948  cumap->curr = cumap->clipr;
949 }
950 
951 float BKE_curvemap_evaluateF(const CurveMapping *cumap, const CurveMap *cuma, float value)
952 {
953  /* index in table */
954  float fi = (value - cuma->mintable) * cuma->range;
955  int i = (int)fi;
956 
957  /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */
958  if (fi < 0.0f || fi > CM_TABLE) {
959  return curvemap_calc_extend(cumap, cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x);
960  }
961 
962  if (i < 0) {
963  return cuma->table[0].y;
964  }
965  if (i >= CM_TABLE) {
966  return cuma->table[CM_TABLE].y;
967  }
968 
969  fi = fi - (float)i;
970  return (1.0f - fi) * cuma->table[i].y + (fi)*cuma->table[i + 1].y;
971 }
972 
973 float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
974 {
975  const CurveMap *cuma = cumap->cm + cur;
976  float val = BKE_curvemap_evaluateF(cumap, cuma, value);
977 
978  /* account for clipping */
979  if (cumap->flag & CUMA_DO_CLIP) {
980  if (val < cumap->clipr.ymin) {
981  val = cumap->clipr.ymin;
982  }
983  else if (val > cumap->clipr.ymax) {
984  val = cumap->clipr.ymax;
985  }
986  }
987 
988  return val;
989 }
990 
991 void BKE_curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], const float vecin[3])
992 {
993  vecout[0] = BKE_curvemap_evaluateF(cumap, &cumap->cm[0], vecin[0]);
994  vecout[1] = BKE_curvemap_evaluateF(cumap, &cumap->cm[1], vecin[1]);
995  vecout[2] = BKE_curvemap_evaluateF(cumap, &cumap->cm[2], vecin[2]);
996 }
997 
999  float vecout[3],
1000  const float vecin[3])
1001 {
1002  vecout[0] = BKE_curvemap_evaluateF(
1003  cumap, &cumap->cm[0], BKE_curvemap_evaluateF(cumap, &cumap->cm[3], vecin[0]));
1004  vecout[1] = BKE_curvemap_evaluateF(
1005  cumap, &cumap->cm[1], BKE_curvemap_evaluateF(cumap, &cumap->cm[3], vecin[1]));
1006  vecout[2] = BKE_curvemap_evaluateF(
1007  cumap, &cumap->cm[2], BKE_curvemap_evaluateF(cumap, &cumap->cm[3], vecin[2]));
1008 }
1009 
1011  float vecout[3],
1012  const float vecin[3],
1013  const int channel_offset[3])
1014 {
1015  const float v0in = vecin[channel_offset[0]];
1016  const float v1in = vecin[channel_offset[1]];
1017  const float v2in = vecin[channel_offset[2]];
1018 
1019  const float v0 = BKE_curvemap_evaluateF(cumap, &cumap->cm[channel_offset[0]], v0in);
1020  const float v2 = BKE_curvemap_evaluateF(cumap, &cumap->cm[channel_offset[2]], v2in);
1021  const float v1 = v2 + ((v0 - v2) * (v1in - v2in) / (v0in - v2in));
1022 
1023  vecout[channel_offset[0]] = v0;
1024  vecout[channel_offset[1]] = v1;
1025  vecout[channel_offset[2]] = v2;
1026 }
1027 
1029  float vecout[3],
1030  const float vecin[3],
1031  const float black[3],
1032  const float bwmul[3])
1033 {
1034  const float r = (vecin[0] - black[0]) * bwmul[0];
1035  const float g = (vecin[1] - black[1]) * bwmul[1];
1036  const float b = (vecin[2] - black[2]) * bwmul[2];
1037 
1038  switch (cumap->tone) {
1039  default:
1040  case CURVE_TONE_STANDARD: {
1041  vecout[0] = BKE_curvemap_evaluateF(cumap, &cumap->cm[0], r);
1042  vecout[1] = BKE_curvemap_evaluateF(cumap, &cumap->cm[1], g);
1043  vecout[2] = BKE_curvemap_evaluateF(cumap, &cumap->cm[2], b);
1044  break;
1045  }
1046  case CURVE_TONE_FILMLIKE: {
1047  if (r >= g) {
1048  if (g > b) {
1049  /* Case 1: r >= g > b */
1050  const int shuffeled_channels[] = {0, 1, 2};
1051  curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
1052  }
1053  else if (b > r) {
1054  /* Case 2: b > r >= g */
1055  const int shuffeled_channels[] = {2, 0, 1};
1056  curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
1057  }
1058  else if (b > g) {
1059  /* Case 3: r >= b > g */
1060  const int shuffeled_channels[] = {0, 2, 1};
1061  curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
1062  }
1063  else {
1064  /* Case 4: r >= g == b */
1065  copy_v2_fl2(vecout,
1066  BKE_curvemap_evaluateF(cumap, &cumap->cm[0], r),
1067  BKE_curvemap_evaluateF(cumap, &cumap->cm[1], g));
1068  vecout[2] = vecout[1];
1069  }
1070  }
1071  else {
1072  if (r >= b) {
1073  /* Case 5: g > r >= b */
1074  const int shuffeled_channels[] = {1, 0, 2};
1075  curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
1076  }
1077  else if (b > g) {
1078  /* Case 6: b > g > r */
1079  const int shuffeled_channels[] = {2, 1, 0};
1080  curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
1081  }
1082  else {
1083  /* Case 7: g >= b > r */
1084  const int shuffeled_channels[] = {1, 2, 0};
1085  curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
1086  }
1087  }
1088  break;
1089  }
1090  }
1091 }
1092 
1094  float vecout[3],
1095  const float vecin[3])
1096 {
1097  BKE_curvemapping_evaluate_premulRGBF_ex(cumap, vecout, vecin, cumap->black, cumap->bwmul);
1098 }
1099 
1101  unsigned char vecout_byte[3],
1102  const unsigned char vecin_byte[3])
1103 {
1104  float vecin[3], vecout[3];
1105 
1106  vecin[0] = (float)vecin_byte[0] / 255.0f;
1107  vecin[1] = (float)vecin_byte[1] / 255.0f;
1108  vecin[2] = (float)vecin_byte[2] / 255.0f;
1109 
1110  BKE_curvemapping_evaluate_premulRGBF(cumap, vecout, vecin);
1111 
1112  vecout_byte[0] = unit_float_to_uchar_clamp(vecout[0]);
1113  vecout_byte[1] = unit_float_to_uchar_clamp(vecout[1]);
1114  vecout_byte[2] = unit_float_to_uchar_clamp(vecout[2]);
1115 }
1116 
1118 {
1119  if (cumap->black[0] != 0.0f) {
1120  return true;
1121  }
1122  if (cumap->black[1] != 0.0f) {
1123  return true;
1124  }
1125  if (cumap->black[2] != 0.0f) {
1126  return true;
1127  }
1128  if (cumap->white[0] != 1.0f) {
1129  return true;
1130  }
1131  if (cumap->white[1] != 1.0f) {
1132  return true;
1133  }
1134  if (cumap->white[2] != 1.0f) {
1135  return true;
1136  }
1137 
1138  for (int a = 0; a < CM_TOT; a++) {
1139  if (cumap->cm[a].curve) {
1140  if (cumap->cm[a].totpoint != 2) {
1141  return true;
1142  }
1143 
1144  if (cumap->cm[a].curve[0].x != 0.0f) {
1145  return true;
1146  }
1147  if (cumap->cm[a].curve[0].y != 0.0f) {
1148  return true;
1149  }
1150  if (cumap->cm[a].curve[1].x != 1.0f) {
1151  return true;
1152  }
1153  if (cumap->cm[a].curve[1].y != 1.0f) {
1154  return true;
1155  }
1156  }
1157  }
1158  return false;
1159 }
1160 
1161 void BKE_curvemapping_get_range_minimums(const CurveMapping *curve_mapping, float minimums[CM_TOT])
1162 {
1163  for (int i = 0; i < CM_TOT; i++) {
1164  minimums[i] = curve_mapping->cm[i].mintable;
1165  }
1166 }
1167 
1169  float dividers[CM_TOT])
1170 {
1171  for (int i = 0; i < CM_TOT; i++) {
1172  const CurveMap *curve_map = &curve_mapping->cm[i];
1173  dividers[i] = 1.0f / max_ff(1e-8f, curve_map->maxtable - curve_map->mintable);
1174  }
1175 }
1176 
1178  float start_slopes[CM_TOT],
1179  float end_slopes[CM_TOT])
1180 {
1181  float range_dividers[CM_TOT];
1182  BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers);
1183  for (int i = 0; i < CM_TOT; i++) {
1184  const CurveMap *curve_map = &curve_mapping->cm[i];
1185  /* If extrapolation is not enabled, the slopes are horizontal. */
1186  if (!(curve_mapping->flag & CUMA_EXTEND_EXTRAPOLATE)) {
1187  start_slopes[i] = 0.0f;
1188  end_slopes[i] = 0.0f;
1189  continue;
1190  }
1191 
1192  if (curve_map->ext_in[0] != 0.0f) {
1193  start_slopes[i] = curve_map->ext_in[1] / (curve_map->ext_in[0] * range_dividers[i]);
1194  }
1195  else {
1196  start_slopes[i] = 1e8f;
1197  }
1198 
1199  if (curve_map->ext_out[0] != 0.0f) {
1200  end_slopes[i] = curve_map->ext_out[1] / (curve_map->ext_out[0] * range_dividers[i]);
1201  }
1202  else {
1203  end_slopes[i] = 1e8f;
1204  }
1205  }
1206 }
1207 
1208 bool BKE_curvemapping_is_map_identity(const CurveMapping *curve_mapping, int index)
1209 {
1210  if (!(curve_mapping->flag & CUMA_EXTEND_EXTRAPOLATE)) {
1211  return false;
1212  }
1213  const CurveMap *curve_map = &curve_mapping->cm[index];
1214  if (curve_map->maxtable - curve_map->mintable != 1.0f) {
1215  return false;
1216  }
1217  if (curve_map->ext_in[0] != curve_map->ext_in[1]) {
1218  return false;
1219  }
1220  if (curve_map->ext_out[0] != curve_map->ext_out[1]) {
1221  return false;
1222  }
1223  if (curve_map->totpoint != 2) {
1224  return false;
1225  }
1226  if (curve_map->curve[0].x != 0 || curve_map->curve[0].y != 0) {
1227  return false;
1228  }
1229  if (curve_map->curve[1].x != 0 || curve_map->curve[1].y != 0) {
1230  return false;
1231  }
1232  return true;
1233 }
1234 
1236 {
1237  int a;
1238 
1239  if (cumap == NULL) {
1240  return;
1241  }
1242 
1243  for (a = 0; a < CM_TOT; a++) {
1244  if (cumap->cm[a].table == NULL) {
1245  curvemap_make_table(cumap, cumap->cm + a);
1246  }
1247  }
1248 }
1249 
1250 void BKE_curvemapping_table_F(const CurveMapping *cumap, float **array, int *size)
1251 {
1252  int a;
1253 
1254  *size = CM_TABLE + 1;
1255  *array = MEM_callocN(sizeof(float) * (*size) * 4, "CurveMapping");
1256 
1257  for (a = 0; a < *size; a++) {
1258  if (cumap->cm[0].table) {
1259  (*array)[a * 4 + 0] = cumap->cm[0].table[a].y;
1260  }
1261  }
1262 }
1263 
1264 void BKE_curvemapping_table_RGBA(const CurveMapping *cumap, float **array, int *size)
1265 {
1266  int a;
1267 
1268  *size = CM_TABLE + 1;
1269  *array = MEM_callocN(sizeof(float) * (*size) * 4, "CurveMapping");
1270 
1271  for (a = 0; a < *size; a++) {
1272  if (cumap->cm[0].table) {
1273  (*array)[a * 4 + 0] = cumap->cm[0].table[a].y;
1274  }
1275  if (cumap->cm[1].table) {
1276  (*array)[a * 4 + 1] = cumap->cm[1].table[a].y;
1277  }
1278  if (cumap->cm[2].table) {
1279  (*array)[a * 4 + 2] = cumap->cm[2].table[a].y;
1280  }
1281  if (cumap->cm[3].table) {
1282  (*array)[a * 4 + 3] = cumap->cm[3].table[a].y;
1283  }
1284  }
1285 }
1286 
1288 {
1289  BLO_write_struct(writer, CurveMapping, cumap);
1290  BKE_curvemapping_curves_blend_write(writer, cumap);
1291 }
1292 
1294 {
1295  for (int a = 0; a < CM_TOT; a++) {
1296  BLO_write_struct_array(writer, CurveMapPoint, cumap->cm[a].totpoint, cumap->cm[a].curve);
1297  }
1298 }
1299 
1301 {
1302  /* flag seems to be able to hang? Maybe old files... not bad to clear anyway */
1303  cumap->flag &= ~CUMA_PREMULLED;
1304 
1305  for (int a = 0; a < CM_TOT; a++) {
1306  BLO_read_data_address(reader, &cumap->cm[a].curve);
1307  cumap->cm[a].table = NULL;
1308  cumap->cm[a].premultable = NULL;
1309  }
1310 }
1311 
1312 /* ***************** Histogram **************** */
1313 
1314 #define INV_255 (1.0f / 255.0f)
1315 
1317 {
1318  int bin = (int)((f * 255.0f) + 0.5f); /* 0.5 to prevent quantization differences */
1319 
1320  /* NOTE: clamp integer instead of float to avoid problems with NaN. */
1321  CLAMP(bin, 0, 255);
1322 
1323  return bin;
1324 }
1325 
1326 static void save_sample_line(
1327  Scopes *scopes, const int idx, const float fx, const float rgb[3], const float ycc[3])
1328 {
1329  float yuv[3];
1330 
1331  /* Vector-scope. */
1332  rgb_to_yuv(rgb[0], rgb[1], rgb[2], &yuv[0], &yuv[1], &yuv[2], BLI_YUV_ITU_BT709);
1333  scopes->vecscope[idx + 0] = yuv[1];
1334  scopes->vecscope[idx + 1] = yuv[2];
1335 
1336  /* Waveform. */
1337  switch (scopes->wavefrm_mode) {
1338  case SCOPES_WAVEFRM_RGB:
1340  scopes->waveform_1[idx + 0] = fx;
1341  scopes->waveform_1[idx + 1] = rgb[0];
1342  scopes->waveform_2[idx + 0] = fx;
1343  scopes->waveform_2[idx + 1] = rgb[1];
1344  scopes->waveform_3[idx + 0] = fx;
1345  scopes->waveform_3[idx + 1] = rgb[2];
1346  break;
1347  case SCOPES_WAVEFRM_LUMA:
1348  scopes->waveform_1[idx + 0] = fx;
1349  scopes->waveform_1[idx + 1] = ycc[0];
1350  break;
1354  scopes->waveform_1[idx + 0] = fx;
1355  scopes->waveform_1[idx + 1] = ycc[0];
1356  scopes->waveform_2[idx + 0] = fx;
1357  scopes->waveform_2[idx + 1] = ycc[1];
1358  scopes->waveform_3[idx + 0] = fx;
1359  scopes->waveform_3[idx + 1] = ycc[2];
1360  break;
1361  }
1362 }
1363 
1365  ImBuf *ibuf,
1366  const ColorManagedViewSettings *view_settings,
1367  const ColorManagedDisplaySettings *display_settings)
1368 {
1369  int i, x, y;
1370  const float *fp;
1371  unsigned char *cp;
1372 
1373  int x1 = roundf(hist->co[0][0] * ibuf->x);
1374  int x2 = roundf(hist->co[1][0] * ibuf->x);
1375  int y1 = roundf(hist->co[0][1] * ibuf->y);
1376  int y2 = roundf(hist->co[1][1] * ibuf->y);
1377 
1378  struct ColormanageProcessor *cm_processor = NULL;
1379 
1380  hist->channels = 3;
1381  hist->x_resolution = 256;
1382  hist->xmax = 1.0f;
1383  /* hist->ymax = 1.0f; */ /* now do this on the operator _only_ */
1384 
1385  if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
1386  return;
1387  }
1388 
1389  if (ibuf->rect_float) {
1390  cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1391  }
1392 
1393  for (i = 0; i < 256; i++) {
1394  x = (int)(0.5f + x1 + (float)i * (x2 - x1) / 255.0f);
1395  y = (int)(0.5f + y1 + (float)i * (y2 - y1) / 255.0f);
1396 
1397  if (x < 0 || y < 0 || x >= ibuf->x || y >= ibuf->y) {
1398  hist->data_luma[i] = hist->data_r[i] = hist->data_g[i] = hist->data_b[i] = hist->data_a[i] =
1399  0.0f;
1400  }
1401  else {
1402  if (ibuf->rect_float) {
1403  float rgba[4];
1404  fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
1405 
1406  switch (ibuf->channels) {
1407  case 4:
1408  copy_v4_v4(rgba, fp);
1410  break;
1411  case 3:
1412  copy_v3_v3(rgba, fp);
1414  rgba[3] = 1.0f;
1415  break;
1416  case 2:
1417  copy_v3_fl(rgba, fp[0]);
1418  rgba[3] = fp[1];
1419  break;
1420  case 1:
1421  copy_v3_fl(rgba, fp[0]);
1422  rgba[3] = 1.0f;
1423  break;
1424  default:
1426  }
1427 
1429  hist->data_r[i] = rgba[0];
1430  hist->data_g[i] = rgba[1];
1431  hist->data_b[i] = rgba[2];
1432  hist->data_a[i] = rgba[3];
1433  }
1434  else if (ibuf->rect) {
1435  cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
1436  hist->data_luma[i] = (float)IMB_colormanagement_get_luminance_byte(cp) / 255.0f;
1437  hist->data_r[i] = (float)cp[0] / 255.0f;
1438  hist->data_g[i] = (float)cp[1] / 255.0f;
1439  hist->data_b[i] = (float)cp[2] / 255.0f;
1440  hist->data_a[i] = (float)cp[3] / 255.0f;
1441  }
1442  }
1443  }
1444 
1445  if (cm_processor) {
1446  IMB_colormanagement_processor_free(cm_processor);
1447  }
1448 }
1449 
1450 /* if view_settings, it also applies this to byte buffers */
1451 typedef struct ScopesUpdateData {
1453  const ImBuf *ibuf;
1455  const unsigned char *display_buffer;
1456  const int ycc_mode;
1458 
1459 typedef struct ScopesUpdateDataChunk {
1460  unsigned int bin_lum[256];
1461  unsigned int bin_r[256];
1462  unsigned int bin_g[256];
1463  unsigned int bin_b[256];
1464  unsigned int bin_a[256];
1465  float min[3], max[3];
1467 
1468 static void scopes_update_cb(void *__restrict userdata,
1469  const int y,
1470  const TaskParallelTLS *__restrict tls)
1471 {
1472  const ScopesUpdateData *data = userdata;
1473 
1474  Scopes *scopes = data->scopes;
1475  const ImBuf *ibuf = data->ibuf;
1476  struct ColormanageProcessor *cm_processor = data->cm_processor;
1477  const unsigned char *display_buffer = data->display_buffer;
1478  const int ycc_mode = data->ycc_mode;
1479 
1480  ScopesUpdateDataChunk *data_chunk = tls->userdata_chunk;
1481  unsigned int *bin_lum = data_chunk->bin_lum;
1482  unsigned int *bin_r = data_chunk->bin_r;
1483  unsigned int *bin_g = data_chunk->bin_g;
1484  unsigned int *bin_b = data_chunk->bin_b;
1485  unsigned int *bin_a = data_chunk->bin_a;
1486  float *min = data_chunk->min;
1487  float *max = data_chunk->max;
1488 
1489  const float *rf = NULL;
1490  const unsigned char *rc = NULL;
1491  const int rows_per_sample_line = ibuf->y / scopes->sample_lines;
1492  const int savedlines = y / rows_per_sample_line;
1493  const bool do_sample_line = (savedlines < scopes->sample_lines) &&
1494  (y % rows_per_sample_line) == 0;
1495  const bool is_float = (ibuf->rect_float != NULL);
1496 
1497  if (is_float) {
1498  rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels;
1499  }
1500  else {
1501  rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels;
1502  }
1503 
1504  for (int x = 0; x < ibuf->x; x++) {
1505  float rgba[4], ycc[3], luma;
1506 
1507  if (is_float) {
1508  switch (ibuf->channels) {
1509  case 4:
1510  copy_v4_v4(rgba, rf);
1512  break;
1513  case 3:
1514  copy_v3_v3(rgba, rf);
1516  rgba[3] = 1.0f;
1517  break;
1518  case 2:
1519  copy_v3_fl(rgba, rf[0]);
1520  rgba[3] = rf[1];
1521  break;
1522  case 1:
1523  copy_v3_fl(rgba, rf[0]);
1524  rgba[3] = 1.0f;
1525  break;
1526  default:
1528  }
1529  }
1530  else {
1531  for (int c = 4; c--;) {
1532  rgba[c] = rc[c] * INV_255;
1533  }
1534  }
1535 
1536  /* we still need luma for histogram */
1538 
1539  /* check for min max */
1540  if (ycc_mode == -1) {
1542  }
1543  else {
1544  rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode);
1545  mul_v3_fl(ycc, INV_255);
1546  minmax_v3v3_v3(min, max, ycc);
1547  }
1548  /* Increment count for histogram. */
1549  bin_lum[get_bin_float(luma)]++;
1550  bin_r[get_bin_float(rgba[0])]++;
1551  bin_g[get_bin_float(rgba[1])]++;
1552  bin_b[get_bin_float(rgba[2])]++;
1553  bin_a[get_bin_float(rgba[3])]++;
1554 
1555  /* save sample if needed */
1556  if (do_sample_line) {
1557  const float fx = (float)x / (float)ibuf->x;
1558  const int idx = 2 * (ibuf->x * savedlines + x);
1559  save_sample_line(scopes, idx, fx, rgba, ycc);
1560  }
1561 
1562  rf += ibuf->channels;
1563  rc += ibuf->channels;
1564  }
1565 }
1566 
1567 static void scopes_update_reduce(const void *__restrict UNUSED(userdata),
1568  void *__restrict chunk_join,
1569  void *__restrict chunk)
1570 {
1571  ScopesUpdateDataChunk *join_chunk = chunk_join;
1572  const ScopesUpdateDataChunk *data_chunk = chunk;
1573 
1574  unsigned int *bin_lum = join_chunk->bin_lum;
1575  unsigned int *bin_r = join_chunk->bin_r;
1576  unsigned int *bin_g = join_chunk->bin_g;
1577  unsigned int *bin_b = join_chunk->bin_b;
1578  unsigned int *bin_a = join_chunk->bin_a;
1579  const unsigned int *bin_lum_c = data_chunk->bin_lum;
1580  const unsigned int *bin_r_c = data_chunk->bin_r;
1581  const unsigned int *bin_g_c = data_chunk->bin_g;
1582  const unsigned int *bin_b_c = data_chunk->bin_b;
1583  const unsigned int *bin_a_c = data_chunk->bin_a;
1584 
1585  const float *min = data_chunk->min;
1586  const float *max = data_chunk->max;
1587 
1588  for (int b = 256; b--;) {
1589  bin_lum[b] += bin_lum_c[b];
1590  bin_r[b] += bin_r_c[b];
1591  bin_g[b] += bin_g_c[b];
1592  bin_b[b] += bin_b_c[b];
1593  bin_a[b] += bin_a_c[b];
1594  }
1595 
1596  for (int c = 3; c--;) {
1597  if (min[c] < join_chunk->min[c]) {
1598  join_chunk->min[c] = min[c];
1599  }
1600  if (max[c] > join_chunk->max[c]) {
1601  join_chunk->max[c] = max[c];
1602  }
1603  }
1604 }
1605 
1607  ImBuf *ibuf,
1608  const ColorManagedViewSettings *view_settings,
1609  const ColorManagedDisplaySettings *display_settings)
1610 {
1611  int a;
1612  unsigned int nl, na, nr, ng, nb;
1613  double divl, diva, divr, divg, divb;
1614  const unsigned char *display_buffer = NULL;
1615  int ycc_mode = -1;
1616  void *cache_handle = NULL;
1617  struct ColormanageProcessor *cm_processor = NULL;
1618 
1619  if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
1620  return;
1621  }
1622 
1623  if (scopes->ok == 1) {
1624  return;
1625  }
1626 
1627  if (scopes->hist.ymax == 0.0f) {
1628  scopes->hist.ymax = 1.0f;
1629  }
1630 
1631  /* hmmmm */
1632  if (!(ELEM(ibuf->channels, 3, 4))) {
1633  return;
1634  }
1635 
1636  scopes->hist.channels = 3;
1637  scopes->hist.x_resolution = 256;
1638 
1639  switch (scopes->wavefrm_mode) {
1640  case SCOPES_WAVEFRM_RGB:
1641  /* fall-through */
1643  ycc_mode = -1;
1644  break;
1645  case SCOPES_WAVEFRM_LUMA:
1647  ycc_mode = BLI_YCC_JFIF_0_255;
1648  break;
1650  ycc_mode = BLI_YCC_ITU_BT601;
1651  break;
1653  ycc_mode = BLI_YCC_ITU_BT709;
1654  break;
1655  }
1656 
1657  /* convert to number of lines with logarithmic scale */
1658  scopes->sample_lines = (scopes->accuracy * 0.01f) * (scopes->accuracy * 0.01f) * ibuf->y;
1659  CLAMP_MIN(scopes->sample_lines, 1);
1660 
1661  if (scopes->sample_full) {
1662  scopes->sample_lines = ibuf->y;
1663  }
1664 
1665  /* scan the image */
1666  for (a = 0; a < 3; a++) {
1667  scopes->minmax[a][0] = 25500.0f;
1668  scopes->minmax[a][1] = -25500.0f;
1669  }
1670 
1671  scopes->waveform_tot = ibuf->x * scopes->sample_lines;
1672 
1673  if (scopes->waveform_1) {
1674  MEM_freeN(scopes->waveform_1);
1675  }
1676  if (scopes->waveform_2) {
1677  MEM_freeN(scopes->waveform_2);
1678  }
1679  if (scopes->waveform_3) {
1680  MEM_freeN(scopes->waveform_3);
1681  }
1682  if (scopes->vecscope) {
1683  MEM_freeN(scopes->vecscope);
1684  }
1685 
1686  scopes->waveform_1 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float),
1687  "waveform point channel 1");
1688  scopes->waveform_2 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float),
1689  "waveform point channel 2");
1690  scopes->waveform_3 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float),
1691  "waveform point channel 3");
1692  scopes->vecscope = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float),
1693  "vectorscope point channel");
1694 
1695  if (ibuf->rect_float) {
1696  cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1697  }
1698  else {
1699  display_buffer = (const unsigned char *)IMB_display_buffer_acquire(
1700  ibuf, view_settings, display_settings, &cache_handle);
1701  }
1702 
1703  /* Keep number of threads in sync with the merge parts below. */
1705  .scopes = scopes,
1706  .ibuf = ibuf,
1707  .cm_processor = cm_processor,
1708  .display_buffer = display_buffer,
1709  .ycc_mode = ycc_mode,
1710  };
1711  ScopesUpdateDataChunk data_chunk = {{0}};
1712  INIT_MINMAX(data_chunk.min, data_chunk.max);
1713 
1714  TaskParallelSettings settings;
1716  settings.use_threading = (ibuf->y > 256);
1717  settings.userdata_chunk = &data_chunk;
1718  settings.userdata_chunk_size = sizeof(data_chunk);
1719  settings.func_reduce = scopes_update_reduce;
1720  BLI_task_parallel_range(0, ibuf->y, &data, scopes_update_cb, &settings);
1721 
1722  /* convert hist data to float (proportional to max count) */
1723  nl = na = nr = nb = ng = 0;
1724  for (a = 0; a < 256; a++) {
1725  if (data_chunk.bin_lum[a] > nl) {
1726  nl = data_chunk.bin_lum[a];
1727  }
1728  if (data_chunk.bin_r[a] > nr) {
1729  nr = data_chunk.bin_r[a];
1730  }
1731  if (data_chunk.bin_g[a] > ng) {
1732  ng = data_chunk.bin_g[a];
1733  }
1734  if (data_chunk.bin_b[a] > nb) {
1735  nb = data_chunk.bin_b[a];
1736  }
1737  if (data_chunk.bin_a[a] > na) {
1738  na = data_chunk.bin_a[a];
1739  }
1740  }
1741  divl = nl ? 1.0 / (double)nl : 1.0;
1742  diva = na ? 1.0 / (double)na : 1.0;
1743  divr = nr ? 1.0 / (double)nr : 1.0;
1744  divg = ng ? 1.0 / (double)ng : 1.0;
1745  divb = nb ? 1.0 / (double)nb : 1.0;
1746 
1747  for (a = 0; a < 256; a++) {
1748  scopes->hist.data_luma[a] = data_chunk.bin_lum[a] * divl;
1749  scopes->hist.data_r[a] = data_chunk.bin_r[a] * divr;
1750  scopes->hist.data_g[a] = data_chunk.bin_g[a] * divg;
1751  scopes->hist.data_b[a] = data_chunk.bin_b[a] * divb;
1752  scopes->hist.data_a[a] = data_chunk.bin_a[a] * diva;
1753  }
1754 
1755  if (cm_processor) {
1756  IMB_colormanagement_processor_free(cm_processor);
1757  }
1758  if (cache_handle) {
1759  IMB_display_buffer_release(cache_handle);
1760  }
1761 
1762  scopes->ok = 1;
1763 }
1764 
1766 {
1767  MEM_SAFE_FREE(scopes->waveform_1);
1768  MEM_SAFE_FREE(scopes->waveform_2);
1769  MEM_SAFE_FREE(scopes->waveform_3);
1770  MEM_SAFE_FREE(scopes->vecscope);
1771 }
1772 
1773 void BKE_scopes_new(Scopes *scopes)
1774 {
1775  scopes->accuracy = 30.0;
1776  scopes->hist.mode = HISTO_MODE_RGB;
1777  scopes->wavefrm_alpha = 0.3;
1778  scopes->vecscope_alpha = 0.3;
1779  scopes->wavefrm_height = 100;
1780  scopes->vecscope_height = 100;
1781  scopes->hist.height = 100;
1782  scopes->ok = 0;
1783  scopes->waveform_1 = NULL;
1784  scopes->waveform_2 = NULL;
1785  scopes->waveform_3 = NULL;
1786  scopes->vecscope = NULL;
1787 }
1788 
1790 {
1791  const char *display_name = IMB_colormanagement_display_get_default_name();
1792 
1793  BLI_strncpy(settings->display_device, display_name, sizeof(settings->display_device));
1794 }
1795 
1797  const ColorManagedDisplaySettings *settings)
1798 {
1799  BLI_strncpy(new_settings->display_device,
1800  settings->display_device,
1801  sizeof(new_settings->display_device));
1802 }
1803 
1805  ColorManagedViewSettings *view_settings,
1806  const ColorManagedDisplaySettings *display_settings,
1807  const char *view_transform)
1808 {
1810  display_settings->display_device);
1811 
1812  if (!view_transform) {
1814  }
1815 
1816  /* TODO(sergey): Find a way to make look query more reliable with non
1817  * default configuration. */
1818  STRNCPY(view_settings->view_transform, view_transform);
1819  STRNCPY(view_settings->look, "None");
1820 
1821  view_settings->flag = 0;
1822  view_settings->gamma = 1.0f;
1823  view_settings->exposure = 0.0f;
1824  view_settings->curve_mapping = NULL;
1825 
1826  IMB_colormanagement_validate_settings(display_settings, view_settings);
1827 }
1828 
1830  struct ColorManagedViewSettings *view_settings,
1831  const struct ColorManagedDisplaySettings *display_settings)
1832 {
1833  IMB_colormanagement_init_default_view_settings(view_settings, display_settings);
1834 }
1835 
1837  const ColorManagedViewSettings *settings)
1838 {
1839  BLI_strncpy(new_settings->look, settings->look, sizeof(new_settings->look));
1840  BLI_strncpy(new_settings->view_transform,
1841  settings->view_transform,
1842  sizeof(new_settings->view_transform));
1843 
1844  new_settings->flag = settings->flag;
1845  new_settings->exposure = settings->exposure;
1846  new_settings->gamma = settings->gamma;
1847 
1848  if (settings->curve_mapping) {
1849  new_settings->curve_mapping = BKE_curvemapping_copy(settings->curve_mapping);
1850  }
1851  else {
1852  new_settings->curve_mapping = NULL;
1853  }
1854 }
1855 
1857 {
1858  if (settings->curve_mapping) {
1860  settings->curve_mapping = NULL;
1861  }
1862 }
1863 
1865  ColorManagedViewSettings *settings)
1866 {
1867  if (settings->curve_mapping) {
1868  BKE_curvemapping_blend_write(writer, settings->curve_mapping);
1869  }
1870 }
1871 
1873  ColorManagedViewSettings *settings)
1874 {
1875  BLO_read_data_address(reader, &settings->curve_mapping);
1876 
1877  if (settings->curve_mapping) {
1878  BKE_curvemapping_blend_read(reader, settings->curve_mapping);
1879  }
1880 }
1881 
1883  ColorManagedColorspaceSettings *colorspace_settings)
1884 {
1885  BLI_strncpy(colorspace_settings->name, "", sizeof(colorspace_settings->name));
1886 }
1887 
1889  ColorManagedColorspaceSettings *colorspace_settings,
1890  const ColorManagedColorspaceSettings *settings)
1891 {
1892  BLI_strncpy(colorspace_settings->name, settings->name, sizeof(colorspace_settings->name));
1893 }
1894 
1896  const ColorManagedColorspaceSettings *settings2)
1897 {
1898  return STREQ(settings1->name, settings2->name);
1899 }
typedef float(TangentPoint)[2]
@ CURVEMAP_SLOPE_POS_NEG
@ CURVEMAP_SLOPE_POSITIVE
void BKE_curve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
Definition: curve.cc:5465
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
Definition: curve.cc:1717
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_INLINE
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE int compare_ff(float a, float b, float max_diff)
#define BLI_YUV_ITU_BT709
#define BLI_YCC_JFIF_0_255
#define BLI_YCC_ITU_BT601
void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr, int colorspace)
Definition: math_color.c:107
void rgb_to_yuv(float r, float g, float b, float *r_y, float *r_u, float *r_v, int colorspace)
Definition: math_color.c:59
#define BLI_YCC_ITU_BT709
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:867
MINLINE void copy_v2_fl2(float v[2], float x, float y)
MINLINE void madd_v2_v2v2fl(float r[2], const float a[2], const float b[2], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void mul_v2_v2(float r[2], const float a[2])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition: rct.c:407
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:198
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
#define INIT_MINMAX(min, max)
#define UNUSED(x)
#define ELEM(...)
#define STREQ(a, b)
#define CLAMP_MIN(a, b)
#define BLO_read_data_address(reader, ptr_p)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
typedef double(DMatrix)[4][4]
#define CM_TOT
@ CUMA_PREMULLED
@ CUMA_EXTEND_EXTRAPOLATE
@ CUMA_DO_CLIP
@ SCOPES_WAVEFRM_YCC_JPEG
@ SCOPES_WAVEFRM_RGB
@ SCOPES_WAVEFRM_YCC_601
@ SCOPES_WAVEFRM_YCC_709
@ SCOPES_WAVEFRM_LUMA
@ SCOPES_WAVEFRM_RGB_PARADE
@ HISTO_MODE_RGB
#define CM_TABLEDIV
@ CUMA_HANDLE_AUTO_ANIM
@ CUMA_SELECT
@ CUMA_HANDLE_VECTOR
@ CURVE_TONE_STANDARD
@ CURVE_TONE_FILMLIKE
#define CM_RESOL
#define CM_TABLE
@ CURVE_PRESET_ROOT
@ CURVE_PRESET_GAUSS
@ CURVE_PRESET_SMOOTH
@ CURVE_PRESET_ROUND
@ CURVE_PRESET_LINE
@ CURVE_PRESET_SHARP
@ CURVE_PRESET_MID9
@ CURVE_PRESET_BELL
@ CURVE_PRESET_MAX
@ HD_AUTO_ANIM
@ HD_VECT
@ HD_AUTO
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble y1
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble x2
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
void IMB_colormanagement_processor_apply_v3(struct ColormanageProcessor *cm_processor, float pixel[3])
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3])
void IMB_colormanagement_processor_free(struct ColormanageProcessor *cm_processor)
void IMB_colormanagement_validate_settings(const struct ColorManagedDisplaySettings *display_settings, struct ColorManagedViewSettings *view_settings)
void IMB_colormanagement_processor_apply_v4(struct ColormanageProcessor *cm_processor, float pixel[4])
void IMB_display_buffer_release(void *cache_handle)
struct ColormanageProcessor * IMB_colormanagement_display_processor_new(const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings)
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
void IMB_colormanagement_init_default_view_settings(struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings)
unsigned char * IMB_display_buffer_acquire(struct ImBuf *ibuf, const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings, void **cache_handle)
const char * IMB_colormanagement_display_get_default_name(void)
struct ColorManagedDisplay * IMB_colormanagement_display_get_named(const char *name)
const char * IMB_colormanagement_display_get_default_view_transform_name(struct ColorManagedDisplay *display)
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
ATTR_WARN_UNUSED_RESULT const BMVert * v2
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
struct ScopesUpdateData ScopesUpdateData
void BKE_curvemapping_evaluate_premulRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3])
Definition: colortools.c:1093
void BKE_color_managed_colorspace_settings_init(ColorManagedColorspaceSettings *colorspace_settings)
Definition: colortools.c:1882
static int sort_curvepoints(const void *a1, const void *a2)
Definition: colortools.c:840
struct ScopesUpdateDataChunk ScopesUpdateDataChunk
void BKE_curvemapping_table_F(const CurveMapping *cumap, float **array, int *size)
Definition: colortools.c:1250
void BKE_curvemapping_premultiply(CurveMapping *cumap, bool restore)
Definition: colortools.c:782
static void calchandle_curvemap(BezTriple *bezt, const BezTriple *prev, const BezTriple *next)
Definition: colortools.c:449
static void scopes_update_cb(void *__restrict userdata, const int y, const TaskParallelTLS *__restrict tls)
Definition: colortools.c:1468
CurveMapPoint * BKE_curvemap_insert(CurveMap *cuma, float x, float y)
Definition: colortools.c:222
static void curvemap_make_table(const CurveMapping *cumap, CurveMap *cuma)
Definition: colortools.c:606
void BKE_curvemapping_free_data(CurveMapping *cumap)
Definition: colortools.c:83
void BKE_curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap, float vecout[3], const float vecin[3], const float black[3], const float bwmul[3])
Definition: colortools.c:1028
void BKE_curvemapping_set_black_white(CurveMapping *cumap, const float black[3], const float white[3])
Definition: colortools.c:152
#define INV_255
Definition: colortools.c:1314
bool BKE_curvemapping_is_map_identity(const CurveMapping *curve_mapping, int index)
Definition: colortools.c:1208
void BKE_color_managed_view_settings_init_default(struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings)
Definition: colortools.c:1829
void BKE_color_managed_view_settings_blend_read_data(BlendDataReader *reader, ColorManagedViewSettings *settings)
Definition: colortools.c:1872
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
Definition: colortools.c:973
void BKE_curvemapping_changed_all(CurveMapping *cumap)
Definition: colortools.c:932
void BKE_curvemapping_set_defaults(CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy)
Definition: colortools.c:37
void BKE_curvemapping_curves_blend_write(BlendWriter *writer, const CurveMapping *cumap)
Definition: colortools.c:1293
CurveMapping * BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
Definition: colortools.c:72
bool BKE_curvemap_remove_point(CurveMap *cuma, CurveMapPoint *point)
Definition: colortools.c:170
void BKE_curvemapping_blend_read(BlendDataReader *reader, CurveMapping *cumap)
Definition: colortools.c:1300
static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap, float vecout[3], const float vecin[3], const int channel_offset[3])
Definition: colortools.c:1010
static float curvemap_calc_extend(const CurveMapping *cumap, const CurveMap *cuma, float x, const float first[2], const float last[2])
Definition: colortools.c:572
void BKE_curvemapping_evaluateRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3])
Definition: colortools.c:998
void BKE_color_managed_display_settings_copy(ColorManagedDisplaySettings *new_settings, const ColorManagedDisplaySettings *settings)
Definition: colortools.c:1796
void BKE_curvemapping_evaluate_premulRGB(const CurveMapping *cumap, unsigned char vecout_byte[3], const unsigned char vecin_byte[3])
Definition: colortools.c:1100
void BKE_color_managed_display_settings_init(ColorManagedDisplaySettings *settings)
Definition: colortools.c:1789
void BKE_curvemapping_set_black_white_ex(const float black[3], const float white[3], float r_bwmul[3])
Definition: colortools.c:140
BLI_INLINE int get_bin_float(float f)
Definition: colortools.c:1316
void BKE_color_managed_view_settings_free(ColorManagedViewSettings *settings)
Definition: colortools.c:1856
void BKE_curvemapping_reset_view(CurveMapping *cumap)
Definition: colortools.c:946
void BKE_curvemap_remove(CurveMap *cuma, const short flag)
Definition: colortools.c:199
void BKE_curvemapping_compute_slopes(const CurveMapping *curve_mapping, float start_slopes[CM_TOT], float end_slopes[CM_TOT])
Definition: colortools.c:1177
void BKE_scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
Definition: colortools.c:1606
void BKE_curvemapping_init(CurveMapping *cumap)
Definition: colortools.c:1235
void BKE_histogram_update_sample_line(Histogram *hist, ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
Definition: colortools.c:1364
void BKE_color_managed_view_settings_copy(ColorManagedViewSettings *new_settings, const ColorManagedViewSettings *settings)
Definition: colortools.c:1836
#define p2_h1
void BKE_color_managed_view_settings_init_render(ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, const char *view_transform)
Definition: colortools.c:1804
void BKE_color_managed_view_settings_blend_write(BlendWriter *writer, ColorManagedViewSettings *settings)
Definition: colortools.c:1864
void BKE_curvemapping_compute_range_dividers(const CurveMapping *curve_mapping, float dividers[CM_TOT])
Definition: colortools.c:1168
static void save_sample_line(Scopes *scopes, const int idx, const float fx, const float rgb[3], const float ycc[3])
Definition: colortools.c:1326
void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
Definition: colortools.c:256
void BKE_curvemapping_table_RGBA(const CurveMapping *cumap, float **array, int *size)
Definition: colortools.c:1264
void BKE_curvemapping_free(CurveMapping *cumap)
Definition: colortools.c:103
void BKE_curvemapping_blend_write(BlendWriter *writer, const CurveMapping *cumap)
Definition: colortools.c:1287
void BKE_curvemapping_get_range_minimums(const CurveMapping *curve_mapping, float minimums[CM_TOT])
Definition: colortools.c:1161
CurveMapping * BKE_curvemapping_copy(const CurveMapping *cumap)
Definition: colortools.c:130
static void scopes_update_reduce(const void *__restrict UNUSED(userdata), void *__restrict chunk_join, void *__restrict chunk)
Definition: colortools.c:1567
void BKE_curvemapping_evaluate3F(const CurveMapping *cumap, float vecout[3], const float vecin[3])
Definition: colortools.c:991
#define p2_h2
void BKE_curvemapping_changed(CurveMapping *cumap, const bool rem_doubles)
Definition: colortools.c:855
void BKE_curvemap_handle_set(CurveMap *cuma, int type)
Definition: colortools.c:424
float BKE_curvemap_evaluateF(const CurveMapping *cumap, const CurveMap *cuma, float value)
Definition: colortools.c:951
void BKE_scopes_new(Scopes *scopes)
Definition: colortools.c:1773
void BKE_curvemapping_copy_data(CurveMapping *target, const CurveMapping *cumap)
Definition: colortools.c:111
void BKE_scopes_free(Scopes *scopes)
Definition: colortools.c:1765
void BKE_color_managed_colorspace_settings_copy(ColorManagedColorspaceSettings *colorspace_settings, const ColorManagedColorspaceSettings *settings)
Definition: colortools.c:1888
bool BKE_color_managed_colorspace_settings_equals(const ColorManagedColorspaceSettings *settings1, const ColorManagedColorspaceSettings *settings2)
Definition: colortools.c:1895
bool BKE_curvemapping_RGBA_does_something(const CurveMapping *cumap)
Definition: colortools.c:1117
Curve curve
int len
Definition: draw_manager.c:108
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
static ulong * next
#define sqrtf(x)
Definition: metal/compat.h:243
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
SymEdge< T > * prev(const SymEdge< T > *se)
Definition: delaunay_2d.cc:105
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static const pxr::TfToken rgba("rgba", pxr::TfToken::Immortal)
static const pxr::TfToken g("g", pxr::TfToken::Immortal)
static const pxr::TfToken rgb("rgb", pxr::TfToken::Immortal)
#define min(a, b)
Definition: sort.c:35
uint8_t h1
float vec[3][3]
uint8_t h2
struct CurveMapping * curve_mapping
CurveMapPoint * table
float maxtable
short totpoint
CurveMapPoint * curve
CurveMapPoint * premultable
float mintable
float ext_out[2]
float ext_in[2]
float premul_ext_out[2]
float premul_ext_in[2]
float bwmul[3]
float white[3]
CurveMap cm[4]
float black[3]
float data_a[256]
float data_luma[256]
float data_r[256]
float co[2][2]
float data_b[256]
float data_g[256]
int channels
unsigned int * rect
float * rect_float
unsigned int bin_g[256]
Definition: colortools.c:1462
unsigned int bin_a[256]
Definition: colortools.c:1464
unsigned int bin_r[256]
Definition: colortools.c:1461
unsigned int bin_b[256]
Definition: colortools.c:1463
unsigned int bin_lum[256]
Definition: colortools.c:1460
const ImBuf * ibuf
Definition: colortools.c:1453
const int ycc_mode
Definition: colortools.c:1456
struct ColormanageProcessor * cm_processor
Definition: colortools.c:1454
const unsigned char * display_buffer
Definition: colortools.c:1455
int waveform_tot
int wavefrm_height
int wavefrm_mode
float * waveform_3
float * waveform_2
int sample_full
int vecscope_height
float wavefrm_alpha
float minmax[3][2]
float vecscope_alpha
float * waveform_1
int sample_lines
float * vecscope
float accuracy
struct Histogram hist
TaskParallelReduceFunc func_reduce
Definition: BLI_task.h:181
size_t userdata_chunk_size
Definition: BLI_task.h:169
float xmax
Definition: DNA_vec_types.h:69
float xmin
Definition: DNA_vec_types.h:69
float ymax
Definition: DNA_vec_types.h:70
float ymin
Definition: DNA_vec_types.h:70
float max