Blender  V3.3
colormanagement.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2012 Blender Foundation. All rights reserved. */
3 
8 #include "IMB_colormanagement.h"
10 
11 #include <math.h>
12 #include <string.h>
13 
14 #include "DNA_color_types.h"
15 #include "DNA_image_types.h"
16 #include "DNA_movieclip_types.h"
17 #include "DNA_scene_types.h"
18 #include "DNA_space_types.h"
19 
20 #include "IMB_filetype.h"
21 #include "IMB_filter.h"
22 #include "IMB_imbuf.h"
23 #include "IMB_imbuf_types.h"
24 #include "IMB_metadata.h"
25 #include "IMB_moviecache.h"
26 
27 #include "MEM_guardedalloc.h"
28 
29 #include "BLI_blenlib.h"
30 #include "BLI_math.h"
31 #include "BLI_math_color.h"
32 #include "BLI_rect.h"
33 #include "BLI_string.h"
34 #include "BLI_threads.h"
35 
36 #include "BKE_appdir.h"
37 #include "BKE_colortools.h"
38 #include "BKE_context.h"
39 #include "BKE_image.h"
40 #include "BKE_image_format.h"
41 #include "BKE_main.h"
42 
43 #include "RNA_define.h"
44 
45 #include "SEQ_iterator.h"
46 
47 #include <ocio_capi.h>
48 
49 /* -------------------------------------------------------------------- */
53 #define DISPLAY_BUFFER_CHANNELS 4
54 
55 /* ** list of all supported color spaces, displays and views */
63 
68 
69 static int global_tot_colorspace = 0;
70 static int global_tot_display = 0;
71 static int global_tot_view = 0;
72 static int global_tot_looks = 0;
73 
74 /* Luma coefficients and XYZ to RGB to be initialized by OCIO. */
75 float imbuf_luma_coefficients[3] = {0.0f};
76 float imbuf_scene_linear_to_xyz[3][3] = {{0.0f}};
77 float imbuf_xyz_to_scene_linear[3][3] = {{0.0f}};
78 float imbuf_scene_linear_to_rec709[3][3] = {{0.0f}};
79 float imbuf_rec709_to_scene_linear[3][3] = {{0.0f}};
80 float imbuf_scene_linear_to_aces[3][3] = {{0.0f}};
81 float imbuf_aces_to_scene_linear[3][3] = {{0.0f}};
82 
83 /* lock used by pre-cached processors getters, so processor wouldn't
84  * be created several times
85  * LOCK_COLORMANAGE can not be used since this mutex could be needed to
86  * be locked before pre-cached processor are creating
87  */
88 static pthread_mutex_t processor_lock = BLI_MUTEX_INITIALIZER;
89 
90 typedef struct ColormanageProcessor {
91  OCIO_ConstCPUProcessorRcPtr *cpu_processor;
95 
96 static struct global_gpu_state {
97  /* GPU shader currently bound. */
99 
100  /* Curve mapping. */
105 } global_gpu_state = {false};
106 
108  /* Cached processor for color picking conversion. */
109  OCIO_ConstCPUProcessorRcPtr *cpu_processor_to;
110  OCIO_ConstCPUProcessorRcPtr *cpu_processor_from;
111  bool failed;
113 
116 /* -------------------------------------------------------------------- */
176 /* NOTE: ColormanageCacheViewSettings and ColormanageCacheDisplaySettings are
177  * quite the same as ColorManagedViewSettings and ColorManageDisplaySettings
178  * but they holds indexes of all transformations and color spaces, not
179  * their names.
180  *
181  * This helps avoid extra colorspace / display / view lookup without
182  * requiring to pass all variables which affects on display buffer
183  * to color management cache system and keeps calls small and nice.
184  */
186  int flag;
187  int look;
188  int view;
189  float exposure;
190  float gamma;
191  float dither;
194 
196  int display;
198 
199 typedef struct ColormanageCacheKey {
200  int view; /* view transformation used for display buffer */
201  int display; /* display device name */
203 
204 typedef struct ColormanageCacheData {
205  int flag; /* view flags of cached buffer */
206  int look; /* Additional artistics transform */
207  float exposure; /* exposure value cached buffer is calculated with */
208  float gamma; /* gamma value cached buffer is calculated with */
209  float dither; /* dither value cached buffer is calculated with */
210  CurveMapping *curve_mapping; /* curve mapping used for cached buffer */
211  int curve_mapping_timestamp; /* time stamp of curve mapping used for cached buffer */
213 
214 typedef struct ColormanageCache {
216 
219 
220 static struct MovieCache *colormanage_moviecache_get(const ImBuf *ibuf)
221 {
222  if (!ibuf->colormanage_cache) {
223  return NULL;
224  }
225 
226  return ibuf->colormanage_cache->moviecache;
227 }
228 
230 {
231  if (!ibuf->colormanage_cache) {
232  return NULL;
233  }
234 
235  return ibuf->colormanage_cache->data;
236 }
237 
238 static unsigned int colormanage_hashhash(const void *key_v)
239 {
240  const ColormanageCacheKey *key = key_v;
241 
242  unsigned int rval = (key->display << 16) | (key->view % 0xffff);
243 
244  return rval;
245 }
246 
247 static bool colormanage_hashcmp(const void *av, const void *bv)
248 {
249  const ColormanageCacheKey *a = av;
250  const ColormanageCacheKey *b = bv;
251 
252  return ((a->view != b->view) || (a->display != b->display));
253 }
254 
256 {
257  if (!ibuf->colormanage_cache) {
258  ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
259  }
260 
261  if (!ibuf->colormanage_cache->moviecache) {
262  struct MovieCache *moviecache;
263 
264  moviecache = IMB_moviecache_create("colormanage cache",
265  sizeof(ColormanageCacheKey),
268 
269  ibuf->colormanage_cache->moviecache = moviecache;
270  }
271 
272  return ibuf->colormanage_cache->moviecache;
273 }
274 
276 {
277  if (!ibuf->colormanage_cache) {
278  ibuf->colormanage_cache = MEM_callocN(sizeof(ColormanageCache), "imbuf colormanage cache");
279  }
280 
281  ibuf->colormanage_cache->data = data;
282 }
283 
285  ColormanageCacheViewSettings *cache_view_settings,
286  const ColorManagedViewSettings *view_settings)
287 {
288  int look = IMB_colormanagement_look_get_named_index(view_settings->look);
290 
291  cache_view_settings->look = look;
292  cache_view_settings->view = view;
293  cache_view_settings->exposure = view_settings->exposure;
294  cache_view_settings->gamma = view_settings->gamma;
295  cache_view_settings->dither = ibuf->dither;
296  cache_view_settings->flag = view_settings->flag;
297  cache_view_settings->curve_mapping = view_settings->curve_mapping;
298 }
299 
301  ColormanageCacheDisplaySettings *cache_display_settings,
302  const ColorManagedDisplaySettings *display_settings)
303 {
304  int display = IMB_colormanagement_display_get_named_index(display_settings->display_device);
305 
306  cache_display_settings->display = display;
307 }
308 
310  const ColormanageCacheViewSettings *view_settings,
311  const ColormanageCacheDisplaySettings *display_settings)
312 {
313  key->view = view_settings->view;
314  key->display = display_settings->display;
315 }
316 
318  ColormanageCacheKey *key,
319  void **cache_handle)
320 {
321  ImBuf *cache_ibuf;
322  struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
323 
324  if (!moviecache) {
325  /* If there's no moviecache it means no color management was applied
326  * on given image buffer before. */
327  return NULL;
328  }
329 
330  *cache_handle = NULL;
331 
332  cache_ibuf = IMB_moviecache_get(moviecache, key, NULL);
333 
334  *cache_handle = cache_ibuf;
335 
336  return cache_ibuf;
337 }
338 
339 static unsigned char *colormanage_cache_get(
340  ImBuf *ibuf,
341  const ColormanageCacheViewSettings *view_settings,
342  const ColormanageCacheDisplaySettings *display_settings,
343  void **cache_handle)
344 {
346  ImBuf *cache_ibuf;
347  int view_flag = 1 << (view_settings->view - 1);
348  CurveMapping *curve_mapping = view_settings->curve_mapping;
349  int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
350 
351  colormanage_settings_to_key(&key, view_settings, display_settings);
352 
353  /* check whether image was marked as dirty for requested transform */
354  if ((ibuf->display_buffer_flags[display_settings->display - 1] & view_flag) == 0) {
355  return NULL;
356  }
357 
358  cache_ibuf = colormanage_cache_get_ibuf(ibuf, &key, cache_handle);
359 
360  if (cache_ibuf) {
361  ColormanageCacheData *cache_data;
362 
363  BLI_assert(cache_ibuf->x == ibuf->x && cache_ibuf->y == ibuf->y);
364 
365  /* only buffers with different color space conversions are being stored
366  * in cache separately. buffer which were used only different exposure/gamma
367  * are re-suing the same cached buffer
368  *
369  * check here which exposure/gamma/curve was used for cached buffer and if they're
370  * different from requested buffer should be re-generated
371  */
372  cache_data = colormanage_cachedata_get(cache_ibuf);
373 
374  if (cache_data->look != view_settings->look ||
375  cache_data->exposure != view_settings->exposure ||
376  cache_data->gamma != view_settings->gamma || cache_data->dither != view_settings->dither ||
377  cache_data->flag != view_settings->flag || cache_data->curve_mapping != curve_mapping ||
378  cache_data->curve_mapping_timestamp != curve_mapping_timestamp) {
379  *cache_handle = NULL;
380 
381  IMB_freeImBuf(cache_ibuf);
382 
383  return NULL;
384  }
385 
386  return (unsigned char *)cache_ibuf->rect;
387  }
388 
389  return NULL;
390 }
391 
392 static void colormanage_cache_put(ImBuf *ibuf,
393  const ColormanageCacheViewSettings *view_settings,
394  const ColormanageCacheDisplaySettings *display_settings,
395  unsigned char *display_buffer,
396  void **cache_handle)
397 {
399  ImBuf *cache_ibuf;
400  ColormanageCacheData *cache_data;
401  int view_flag = 1 << (view_settings->view - 1);
402  struct MovieCache *moviecache = colormanage_moviecache_ensure(ibuf);
403  CurveMapping *curve_mapping = view_settings->curve_mapping;
404  int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
405 
406  colormanage_settings_to_key(&key, view_settings, display_settings);
407 
408  /* mark display buffer as valid */
409  ibuf->display_buffer_flags[display_settings->display - 1] |= view_flag;
410 
411  /* buffer itself */
412  cache_ibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, 0);
413  cache_ibuf->rect = (unsigned int *)display_buffer;
414 
415  cache_ibuf->mall |= IB_rect;
416  cache_ibuf->flags |= IB_rect;
417 
418  /* Store data which is needed to check whether cached buffer
419  * could be used for color managed display settings. */
420  cache_data = MEM_callocN(sizeof(ColormanageCacheData), "color manage cache imbuf data");
421  cache_data->look = view_settings->look;
422  cache_data->exposure = view_settings->exposure;
423  cache_data->gamma = view_settings->gamma;
424  cache_data->dither = view_settings->dither;
425  cache_data->flag = view_settings->flag;
426  cache_data->curve_mapping = curve_mapping;
427  cache_data->curve_mapping_timestamp = curve_mapping_timestamp;
428 
429  colormanage_cachedata_set(cache_ibuf, cache_data);
430 
431  *cache_handle = cache_ibuf;
432 
433  IMB_moviecache_put(moviecache, &key, cache_ibuf);
434 }
435 
436 static void colormanage_cache_handle_release(void *cache_handle)
437 {
438  ImBuf *cache_ibuf = cache_handle;
439 
440  IMB_freeImBuf(cache_ibuf);
441 }
442 
445 /* -------------------------------------------------------------------- */
449 static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config,
450  char *colorspace_name,
451  const char *role,
452  const char *backup_role)
453 {
454  OCIO_ConstColorSpaceRcPtr *ociocs;
455 
456  ociocs = OCIO_configGetColorSpace(config, role);
457 
458  if (!ociocs && backup_role) {
459  ociocs = OCIO_configGetColorSpace(config, backup_role);
460  }
461 
462  if (ociocs) {
463  const char *name = OCIO_colorSpaceGetName(ociocs);
464 
465  /* assume function was called with buffer properly allocated to MAX_COLORSPACE_NAME chars */
466  BLI_strncpy(colorspace_name, name, MAX_COLORSPACE_NAME);
467  OCIO_colorSpaceRelease(ociocs);
468  }
469  else {
470  printf("Color management: Error could not find role %s role.\n", role);
471  }
472 }
473 
474 static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
475 {
476  int tot_colorspace, tot_display, tot_display_view, tot_looks;
477  int index, viewindex, viewindex2;
478  const char *name;
479 
480  /* get roles */
494 
495  /* load colorspaces */
496  tot_colorspace = OCIO_configGetNumColorSpaces(config);
497  for (index = 0; index < tot_colorspace; index++) {
498  OCIO_ConstColorSpaceRcPtr *ocio_colorspace;
499  const char *description;
500  bool is_invertible, is_data;
501 
502  name = OCIO_configGetColorSpaceNameByIndex(config, index);
503 
504  ocio_colorspace = OCIO_configGetColorSpace(config, name);
505  description = OCIO_colorSpaceGetDescription(ocio_colorspace);
506  is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace);
507  is_data = OCIO_colorSpaceIsData(ocio_colorspace);
508 
509  ColorSpace *colorspace = colormanage_colorspace_add(name, description, is_invertible, is_data);
510 
511  colorspace->num_aliases = OCIO_colorSpaceGetNumAliases(ocio_colorspace);
512  if (colorspace->num_aliases > 0) {
513  colorspace->aliases = MEM_callocN(sizeof(*colorspace->aliases) * colorspace->num_aliases,
514  "ColorSpace aliases");
515  for (int i = 0; i < colorspace->num_aliases; i++) {
516  BLI_strncpy(colorspace->aliases[i],
517  OCIO_colorSpaceGetAlias(ocio_colorspace, i),
519  }
520  }
521 
522  OCIO_colorSpaceRelease(ocio_colorspace);
523  }
524 
525  /* load displays */
526  viewindex2 = 0;
527  tot_display = OCIO_configGetNumDisplays(config);
528 
529  for (index = 0; index < tot_display; index++) {
530  const char *displayname;
531  ColorManagedDisplay *display;
532 
533  displayname = OCIO_configGetDisplay(config, index);
534 
535  display = colormanage_display_add(displayname);
536 
537  /* load views */
538  tot_display_view = OCIO_configGetNumViews(config, displayname);
539  for (viewindex = 0; viewindex < tot_display_view; viewindex++, viewindex2++) {
540  const char *viewname;
542  LinkData *display_view;
543 
544  viewname = OCIO_configGetView(config, displayname, viewindex);
545 
546  /* first check if view transform with given name was already loaded */
547  view = colormanage_view_get_named(viewname);
548 
549  if (!view) {
550  view = colormanage_view_add(viewname);
551  }
552 
553  display_view = BLI_genericNodeN(view);
554 
555  BLI_addtail(&display->views, display_view);
556  }
557  }
558 
559  global_tot_display = tot_display;
560 
561  /* load looks */
562  tot_looks = OCIO_configGetNumLooks(config);
563  colormanage_look_add("None", "", true);
564  for (index = 0; index < tot_looks; index++) {
565  OCIO_ConstLookRcPtr *ocio_look;
566  const char *process_space;
567 
568  name = OCIO_configGetLookNameByIndex(config, index);
569  ocio_look = OCIO_configGetLook(config, name);
570  process_space = OCIO_lookGetProcessSpace(ocio_look);
571  OCIO_lookRelease(ocio_look);
572 
573  colormanage_look_add(name, process_space, false);
574  }
575 
576  /* Load luminance coefficients. */
578 
579  /* Load standard color spaces. */
582 
585 
588 }
589 
590 static void colormanage_free_config(void)
591 {
592  ColorSpace *colorspace;
593  ColorManagedDisplay *display;
594 
595  /* free color spaces */
596  colorspace = global_colorspaces.first;
597  while (colorspace) {
598  ColorSpace *colorspace_next = colorspace->next;
599 
600  /* Free precomputed processors. */
601  if (colorspace->to_scene_linear) {
602  OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)colorspace->to_scene_linear);
603  }
604  if (colorspace->from_scene_linear) {
605  OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)colorspace->from_scene_linear);
606  }
607 
608  /* free color space itself */
609  MEM_SAFE_FREE(colorspace->aliases);
610  MEM_freeN(colorspace);
611 
612  colorspace = colorspace_next;
613  }
616 
617  /* free displays */
618  display = global_displays.first;
619  while (display) {
620  ColorManagedDisplay *display_next = display->next;
621 
622  /* free precomputer processors */
623  if (display->to_scene_linear) {
624  OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)display->to_scene_linear);
625  }
626  if (display->from_scene_linear) {
627  OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)display->from_scene_linear);
628  }
629 
630  /* free list of views */
631  BLI_freelistN(&display->views);
632 
633  MEM_freeN(display);
634  display = display_next;
635  }
637  global_tot_display = 0;
638 
639  /* free views */
641  global_tot_view = 0;
642 
643  /* free looks */
645  global_tot_looks = 0;
646 
647  OCIO_exit();
648 }
649 
651 {
652  const char *ocio_env;
653  const char *configdir;
654  char configfile[FILE_MAX];
655  OCIO_ConstConfigRcPtr *config = NULL;
656 
657  OCIO_init();
658 
659  ocio_env = BLI_getenv("OCIO");
660 
661  if (ocio_env && ocio_env[0] != '\0') {
662  config = OCIO_configCreateFromEnv();
663  if (config != NULL) {
664  printf("Color management: Using %s as a configuration file\n", ocio_env);
665  }
666  }
667 
668  if (config == NULL) {
669  configdir = BKE_appdir_folder_id(BLENDER_DATAFILES, "colormanagement");
670 
671  if (configdir) {
672  BLI_join_dirfile(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE);
673 
674 #ifdef WIN32
675  {
676  /* Quite a hack to support loading configuration from path with non-ACII symbols. */
677 
678  char short_name[256];
679  BLI_get_short_name(short_name, configfile);
680  config = OCIO_configCreateFromFile(short_name);
681  }
682 #else
683  config = OCIO_configCreateFromFile(configfile);
684 #endif
685  }
686  }
687 
688  if (config == NULL) {
689  printf("Color management: using fallback mode for management\n");
690 
691  config = OCIO_configCreateFallback();
692  }
693 
694  if (config) {
695  OCIO_setCurrentConfig(config);
696 
697  colormanage_load_config(config);
698 
699  OCIO_configRelease(config);
700  }
701 
702  /* If there are no valid display/views, use fallback mode. */
703  if (global_tot_display == 0 || global_tot_view == 0) {
704  printf("Color management: no displays/views in the config, using fallback mode instead\n");
705 
706  /* Free old config. */
708 
709  /* Initialize fallback config. */
710  config = OCIO_configCreateFallback();
711  colormanage_load_config(config);
712  }
713 
715 }
716 
718 {
720 
723  }
724 
727  }
728 
731  }
732 
735  }
736 
737  memset(&global_gpu_state, 0, sizeof(global_gpu_state));
739 
741 }
742 
745 /* -------------------------------------------------------------------- */
749 static bool colormanage_compatible_look(ColorManagedLook *look, const char *view_name)
750 {
751  if (look->is_noop) {
752  return true;
753  }
754 
755  /* Skip looks only relevant to specific view transforms. */
756  return (look->view[0] == 0 || (view_name && STREQ(look->view, view_name)));
757 }
758 
759 static bool colormanage_use_look(const char *look, const char *view_name)
760 {
761  ColorManagedLook *look_descr = colormanage_look_get_named(look);
762  return (look_descr->is_noop == false && colormanage_compatible_look(look_descr, view_name));
763 }
764 
766 {
768 
769  if (ibuf->colormanage_cache) {
771  struct MovieCache *moviecache = colormanage_moviecache_get(ibuf);
772 
773  if (cache_data) {
774  MEM_freeN(cache_data);
775  }
776 
777  if (moviecache) {
778  IMB_moviecache_free(moviecache);
779  }
780 
782 
783  ibuf->colormanage_cache = NULL;
784  }
785 }
786 
788  const bContext *C,
789  ColorManagedViewSettings **r_view_settings,
790  ColorManagedDisplaySettings **r_display_settings)
791 {
794 
795  *r_view_settings = &scene->view_settings;
796  *r_display_settings = &scene->display_settings;
797 
798  if (sima && sima->image) {
799  if ((sima->image->flag & IMA_VIEW_AS_RENDER) == 0) {
800  *r_view_settings = NULL;
801  }
802  }
803 }
804 
805 static const char *get_display_colorspace_name(const ColorManagedViewSettings *view_settings,
806  const ColorManagedDisplaySettings *display_settings)
807 {
808  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
809 
810  const char *display = display_settings->display_device;
811  const char *view = view_settings->view_transform;
812  const char *colorspace_name;
813 
814  colorspace_name = OCIO_configGetDisplayColorSpaceName(config, display, view);
815 
816  OCIO_configRelease(config);
817 
818  return colorspace_name;
819 }
820 
822  const ColorManagedViewSettings *view_settings,
823  const ColorManagedDisplaySettings *display_settings)
824 {
825  const char *colorspace_name = get_display_colorspace_name(view_settings, display_settings);
826 
827  if (colorspace_name) {
828  return colormanage_colorspace_get_named(colorspace_name);
829  }
830 
831  return NULL;
832 }
833 
834 static OCIO_ConstCPUProcessorRcPtr *create_display_buffer_processor(const char *look,
835  const char *view_transform,
836  const char *display,
837  float exposure,
838  float gamma,
839  const char *from_colorspace)
840 {
841  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
842  const bool use_look = colormanage_use_look(look, view_transform);
843  const float scale = (exposure == 0.0f) ? 1.0f : powf(2.0f, exposure);
844  const float exponent = (gamma == 1.0f) ? 1.0f : 1.0f / max_ff(FLT_EPSILON, gamma);
845 
846  OCIO_ConstProcessorRcPtr *processor = OCIO_createDisplayProcessor(config,
847  from_colorspace,
848  view_transform,
849  display,
850  (use_look) ? look : "",
851  scale,
852  exponent,
853  false);
854 
855  OCIO_configRelease(config);
856 
857  if (processor == NULL) {
858  return NULL;
859  }
860 
861  OCIO_ConstCPUProcessorRcPtr *cpu_processor = OCIO_processorGetCPUProcessor(processor);
862  OCIO_processorRelease(processor);
863 
864  return cpu_processor;
865 }
866 
867 static OCIO_ConstProcessorRcPtr *create_colorspace_transform_processor(const char *from_colorspace,
868  const char *to_colorspace)
869 {
870  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
871  OCIO_ConstProcessorRcPtr *processor;
872 
873  processor = OCIO_configGetProcessorWithNames(config, from_colorspace, to_colorspace);
874 
875  OCIO_configRelease(config);
876 
877  return processor;
878 }
879 
880 static OCIO_ConstCPUProcessorRcPtr *colorspace_to_scene_linear_cpu_processor(
881  ColorSpace *colorspace)
882 {
883  if (colorspace->to_scene_linear == NULL) {
885 
886  if (colorspace->to_scene_linear == NULL) {
887  OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
888  colorspace->name, global_role_scene_linear);
889 
890  if (processor != NULL) {
891  colorspace->to_scene_linear = (struct OCIO_ConstCPUProcessorRcPtr *)
893  OCIO_processorRelease(processor);
894  }
895  }
896 
898  }
899 
900  return (OCIO_ConstCPUProcessorRcPtr *)colorspace->to_scene_linear;
901 }
902 
903 static OCIO_ConstCPUProcessorRcPtr *colorspace_from_scene_linear_cpu_processor(
904  ColorSpace *colorspace)
905 {
906  if (colorspace->from_scene_linear == NULL) {
908 
909  if (colorspace->from_scene_linear == NULL) {
910  OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
911  global_role_scene_linear, colorspace->name);
912 
913  if (processor != NULL) {
914  colorspace->from_scene_linear = (struct OCIO_ConstCPUProcessorRcPtr *)
916  OCIO_processorRelease(processor);
917  }
918  }
919 
921  }
922 
923  return (OCIO_ConstCPUProcessorRcPtr *)colorspace->from_scene_linear;
924 }
925 
926 static OCIO_ConstCPUProcessorRcPtr *display_from_scene_linear_processor(
927  ColorManagedDisplay *display)
928 {
929  if (display->from_scene_linear == NULL) {
931 
932  if (display->from_scene_linear == NULL) {
933  const char *view_name = colormanage_view_get_default_name(display);
934  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
935  OCIO_ConstProcessorRcPtr *processor = NULL;
936 
937  if (view_name && config) {
938  processor = OCIO_createDisplayProcessor(
939  config, global_role_scene_linear, view_name, display->name, NULL, 1.0f, 1.0f, false);
940 
941  OCIO_configRelease(config);
942  }
943 
944  if (processor != NULL) {
945  display->from_scene_linear = (struct OCIO_ConstCPUProcessorRcPtr *)
947  OCIO_processorRelease(processor);
948  }
949  }
950 
952  }
953 
954  return (OCIO_ConstCPUProcessorRcPtr *)display->from_scene_linear;
955 }
956 
957 static OCIO_ConstCPUProcessorRcPtr *display_to_scene_linear_processor(ColorManagedDisplay *display)
958 {
959  if (display->to_scene_linear == NULL) {
961 
962  if (display->to_scene_linear == NULL) {
963  const char *view_name = colormanage_view_get_default_name(display);
964  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
965  OCIO_ConstProcessorRcPtr *processor = NULL;
966 
967  if (view_name && config) {
968  processor = OCIO_createDisplayProcessor(
969  config, global_role_scene_linear, view_name, display->name, NULL, 1.0f, 1.0f, true);
970 
971  OCIO_configRelease(config);
972  }
973 
974  if (processor != NULL) {
975  display->to_scene_linear = (struct OCIO_ConstCPUProcessorRcPtr *)
977  OCIO_processorRelease(processor);
978  }
979  }
980 
982  }
983 
984  return (OCIO_ConstCPUProcessorRcPtr *)display->to_scene_linear;
985 }
986 
988  ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
989 {
990  /* First, try use "Standard" view transform of the requested device. */
992  display_settings->display_device, "Standard");
993  /* If that fails, we fall back to the default view transform of the display
994  * as per OCIO configuration. */
995  if (default_view == NULL) {
997  if (display != NULL) {
998  default_view = colormanage_view_get_default(display);
999  }
1000  }
1001  if (default_view != NULL) {
1002  BLI_strncpy(
1003  view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
1004  }
1005  else {
1006  view_settings->view_transform[0] = '\0';
1007  }
1008  /* TODO(sergey): Find a way to safely/reliable un-hardcode this. */
1009  BLI_strncpy(view_settings->look, "None", sizeof(view_settings->look));
1010  /* Initialize rest of the settings. */
1011  view_settings->flag = 0;
1012  view_settings->gamma = 1.0f;
1013  view_settings->exposure = 0.0f;
1014  view_settings->curve_mapping = NULL;
1015 }
1016 
1017 static void curve_mapping_apply_pixel(CurveMapping *curve_mapping, float *pixel, int channels)
1018 {
1019  if (channels == 1) {
1020  pixel[0] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[0]);
1021  }
1022  else if (channels == 2) {
1023  pixel[0] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[0]);
1024  pixel[1] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[1]);
1025  }
1026  else {
1027  BKE_curvemapping_evaluate_premulRGBF(curve_mapping, pixel, pixel);
1028  }
1029 }
1030 
1031 void colorspace_set_default_role(char *colorspace, int size, int role)
1032 {
1033  if (colorspace && colorspace[0] == '\0') {
1034  const char *role_colorspace;
1035 
1036  role_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
1037 
1038  BLI_strncpy(colorspace, role_colorspace, size);
1039  }
1040 }
1041 
1043 {
1045 }
1046 
1047 void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace)
1048 {
1049  ColorSpace *colorspace = colormanage_colorspace_get_named(from_colorspace);
1050 
1051  if (colorspace && colorspace->is_data) {
1053  return;
1054  }
1055 
1056  if (ibuf->rect_float) {
1057  const char *to_colorspace = global_role_scene_linear;
1058  const bool predivide = IMB_alpha_affects_rgb(ibuf);
1059 
1060  if (ibuf->rect) {
1061  imb_freerectImBuf(ibuf);
1062  }
1063 
1065  ibuf->x,
1066  ibuf->y,
1067  ibuf->channels,
1068  from_colorspace,
1069  to_colorspace,
1070  predivide);
1071  }
1072 }
1073 
1076 /* -------------------------------------------------------------------- */
1081  const char *what,
1082  const ColorManagedDisplay *default_display)
1083 {
1084  if (display_settings->display_device[0] == '\0') {
1085  BLI_strncpy(display_settings->display_device,
1086  default_display->name,
1087  sizeof(display_settings->display_device));
1088  }
1089  else {
1091 
1092  if (!display) {
1093  printf(
1094  "Color management: display \"%s\" used by %s not found, setting to default (\"%s\").\n",
1095  display_settings->display_device,
1096  what,
1097  default_display->name);
1098 
1099  BLI_strncpy(display_settings->display_device,
1100  default_display->name,
1101  sizeof(display_settings->display_device));
1102  }
1103  }
1104 }
1105 
1107  ColorManagedViewSettings *view_settings,
1108  const char *what)
1109 {
1110  ColorManagedDisplay *display;
1111  ColorManagedView *default_view = NULL;
1113 
1114  if (view_settings->view_transform[0] == '\0') {
1115  display = colormanage_display_get_named(display_settings->display_device);
1116 
1117  if (display) {
1118  default_view = colormanage_view_get_default(display);
1119  }
1120 
1121  if (default_view) {
1122  BLI_strncpy(view_settings->view_transform,
1123  default_view->name,
1124  sizeof(view_settings->view_transform));
1125  }
1126  }
1127  else {
1129 
1130  if (!view) {
1131  display = colormanage_display_get_named(display_settings->display_device);
1132 
1133  if (display) {
1134  default_view = colormanage_view_get_default(display);
1135  }
1136 
1137  if (default_view) {
1138  printf("Color management: %s view \"%s\" not found, setting default \"%s\".\n",
1139  what,
1140  view_settings->view_transform,
1141  default_view->name);
1142 
1143  BLI_strncpy(view_settings->view_transform,
1144  default_view->name,
1145  sizeof(view_settings->view_transform));
1146  }
1147  }
1148  }
1149 
1150  if (view_settings->look[0] == '\0') {
1151  BLI_strncpy(view_settings->look, default_look->name, sizeof(view_settings->look));
1152  }
1153  else {
1154  ColorManagedLook *look = colormanage_look_get_named(view_settings->look);
1155  if (look == NULL) {
1156  printf("Color management: %s look \"%s\" not found, setting default \"%s\".\n",
1157  what,
1158  view_settings->look,
1159  default_look->name);
1160 
1161  BLI_strncpy(view_settings->look, default_look->name, sizeof(view_settings->look));
1162  }
1163  }
1164 
1165  /* OCIO_TODO: move to do_versions() */
1166  if (view_settings->exposure == 0.0f && view_settings->gamma == 0.0f) {
1167  view_settings->exposure = 0.0f;
1168  view_settings->gamma = 1.0f;
1169  }
1170 }
1171 
1173  ColorManagedColorspaceSettings *colorspace_settings, const char *what)
1174 {
1175  if (colorspace_settings->name[0] == '\0') {
1176  /* pass */
1177  }
1178  else {
1179  ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
1180 
1181  if (!colorspace) {
1182  printf("Color management: %s colorspace \"%s\" not found, will use default instead.\n",
1183  what,
1184  colorspace_settings->name);
1185 
1186  BLI_strncpy(colorspace_settings->name, "", sizeof(colorspace_settings->name));
1187  }
1188  }
1189 
1190  (void)what;
1191 }
1192 
1193 static bool seq_callback(Sequence *seq, void *UNUSED(user_data))
1194 {
1195  if (seq->strip) {
1197  }
1198  return true;
1199 }
1200 
1202 {
1203  Scene *scene;
1204  Image *image;
1205  MovieClip *clip;
1206 
1207  ColorManagedDisplay *default_display;
1208 
1209  default_display = colormanage_display_get_default();
1210 
1211  if (!default_display) {
1212  /* happens when OCIO configuration is incorrect */
1213  return;
1214  }
1215 
1216  for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
1217  ColorManagedColorspaceSettings *sequencer_colorspace_settings;
1218 
1219  /* check scene color management settings */
1220  colormanage_check_display_settings(&scene->display_settings, "scene", default_display);
1222 
1223  sequencer_colorspace_settings = &scene->sequencer_colorspace_settings;
1224 
1225  colormanage_check_colorspace_settings(sequencer_colorspace_settings, "sequencer");
1226 
1227  if (sequencer_colorspace_settings->name[0] == '\0') {
1228  BLI_strncpy(
1229  sequencer_colorspace_settings->name, global_role_default_sequencer, MAX_COLORSPACE_NAME);
1230  }
1231 
1232  /* check sequencer strip input color space settings */
1233  if (scene->ed != NULL) {
1235  }
1236  }
1237 
1238  /* ** check input color space settings ** */
1239 
1240  for (image = bmain->images.first; image; image = image->id.next) {
1241  colormanage_check_colorspace_settings(&image->colorspace_settings, "image");
1242  }
1243 
1244  for (clip = bmain->movieclips.first; clip; clip = clip->id.next) {
1246  }
1247 }
1248 
1250  ColorManagedViewSettings *view_settings)
1251 {
1252  ColorManagedDisplay *display;
1253  ColorManagedView *default_view = NULL;
1254  LinkData *view_link;
1255 
1256  display = colormanage_display_get_named(display_settings->display_device);
1257 
1258  default_view = colormanage_view_get_default(display);
1259 
1260  for (view_link = display->views.first; view_link; view_link = view_link->next) {
1261  ColorManagedView *view = view_link->data;
1262 
1263  if (STREQ(view->name, view_settings->view_transform)) {
1264  break;
1265  }
1266  }
1267 
1268  if (view_link == NULL && default_view) {
1269  BLI_strncpy(
1270  view_settings->view_transform, default_view->name, sizeof(view_settings->view_transform));
1271  }
1272 }
1273 
1275 {
1276  switch (role) {
1277  case COLOR_ROLE_DATA:
1278  return global_role_data;
1280  return global_role_scene_linear;
1290  return global_role_default_byte;
1291  default:
1292  printf("Unknown role was passed to %s\n", __func__);
1293  BLI_assert(0);
1294  break;
1295  }
1296 
1297  return NULL;
1298 }
1299 
1300 void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name)
1301 {
1302  ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1303 
1304  if (colorspace && colorspace->is_data) {
1306  }
1307  else {
1309  }
1310 }
1311 
1313 {
1318  if (ibuf_src->flags & IB_alphamode_premul) {
1319  ibuf_dst->flags |= IB_alphamode_premul;
1320  }
1321  else if (ibuf_src->flags & IB_alphamode_channel_packed) {
1322  ibuf_dst->flags |= IB_alphamode_channel_packed;
1323  }
1324  else if (ibuf_src->flags & IB_alphamode_ignore) {
1325  ibuf_dst->flags |= IB_alphamode_ignore;
1326  }
1327 }
1328 
1330 {
1331  ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1332 
1333  ibuf->float_colorspace = colorspace;
1334 
1335  if (colorspace && colorspace->is_data) {
1337  }
1338  else {
1340  }
1341 }
1342 
1344 {
1345  ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1346 
1347  ibuf->rect_colorspace = colorspace;
1348 
1349  if (colorspace && colorspace->is_data) {
1351  }
1352  else {
1354  }
1355 }
1356 
1358 {
1359  if (ibuf->float_colorspace) {
1360  return ibuf->float_colorspace->name;
1361  }
1362 
1364 }
1365 
1367 {
1368  if (ibuf->rect_colorspace) {
1369  return ibuf->rect_colorspace->name;
1370  }
1371 
1373 }
1374 
1376 {
1377  return (colorspace && colorspace->is_data);
1378 }
1379 
1381 {
1382  if (!colorspace->info.cached) {
1383  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
1384  OCIO_ConstColorSpaceRcPtr *ocio_colorspace = OCIO_configGetColorSpace(config,
1385  colorspace->name);
1386 
1387  bool is_scene_linear, is_srgb;
1388  OCIO_colorSpaceIsBuiltin(config, ocio_colorspace, &is_scene_linear, &is_srgb);
1389 
1390  OCIO_colorSpaceRelease(ocio_colorspace);
1391  OCIO_configRelease(config);
1392 
1393  colorspace->info.is_scene_linear = is_scene_linear;
1394  colorspace->info.is_srgb = is_srgb;
1395  colorspace->info.cached = true;
1396  }
1397 }
1398 
1400 {
1402  return (colorspace && colorspace->info.is_scene_linear);
1403 }
1404 
1406 {
1408  return (colorspace && colorspace->info.is_srgb);
1409 }
1410 
1412 {
1413  ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1414  return (colorspace && colorspace->is_data);
1415 }
1416 
1418 {
1419  ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1420  return (colorspace && IMB_colormanagement_space_is_scene_linear(colorspace));
1421 }
1422 
1424 {
1425  ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1426  return (colorspace && IMB_colormanagement_space_is_srgb(colorspace));
1427 }
1428 
1430 {
1431  return &imbuf_xyz_to_scene_linear[0][0];
1432 }
1433 
1436 /* -------------------------------------------------------------------- */
1440 typedef struct DisplayBufferThread {
1442 
1443  const float *buffer;
1444  unsigned char *byte_buffer;
1445 
1447  unsigned char *display_buffer_byte;
1448 
1449  int width;
1452 
1454  float dither;
1455  bool is_data;
1457 
1458  const char *byte_colorspace;
1459  const char *float_colorspace;
1461 
1462 typedef struct DisplayBufferInitData {
1465  const float *buffer;
1466  unsigned char *byte_buffer;
1467 
1469  unsigned char *display_buffer_byte;
1470 
1471  int width;
1472 
1473  const char *byte_colorspace;
1474  const char *float_colorspace;
1476 
1477 static void display_buffer_init_handle(void *handle_v,
1478  int start_line,
1479  int tot_line,
1480  void *init_data_v)
1481 {
1482  DisplayBufferThread *handle = (DisplayBufferThread *)handle_v;
1484  ImBuf *ibuf = init_data->ibuf;
1485 
1486  int channels = ibuf->channels;
1487  float dither = ibuf->dither;
1488  bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
1489 
1490  size_t offset = ((size_t)channels) * start_line * ibuf->x;
1491  size_t display_buffer_byte_offset = ((size_t)DISPLAY_BUFFER_CHANNELS) * start_line * ibuf->x;
1492 
1493  memset(handle, 0, sizeof(DisplayBufferThread));
1494 
1495  handle->cm_processor = init_data->cm_processor;
1496 
1497  if (init_data->buffer) {
1498  handle->buffer = init_data->buffer + offset;
1499  }
1500 
1501  if (init_data->byte_buffer) {
1502  handle->byte_buffer = init_data->byte_buffer + offset;
1503  }
1504 
1505  if (init_data->display_buffer) {
1506  handle->display_buffer = init_data->display_buffer + offset;
1507  }
1508 
1509  if (init_data->display_buffer_byte) {
1510  handle->display_buffer_byte = init_data->display_buffer_byte + display_buffer_byte_offset;
1511  }
1512 
1513  handle->width = ibuf->x;
1514 
1515  handle->start_line = start_line;
1516  handle->tot_line = tot_line;
1517 
1518  handle->channels = channels;
1519  handle->dither = dither;
1520  handle->is_data = is_data;
1521  handle->predivide = IMB_alpha_affects_rgb(ibuf);
1522 
1523  handle->byte_colorspace = init_data->byte_colorspace;
1524  handle->float_colorspace = init_data->float_colorspace;
1525 }
1526 
1528  int height,
1529  float *linear_buffer,
1530  bool *is_straight_alpha)
1531 {
1532  int channels = handle->channels;
1533  int width = handle->width;
1534 
1535  size_t buffer_size = ((size_t)channels) * width * height;
1536 
1537  bool is_data = handle->is_data;
1538  bool is_data_display = handle->cm_processor->is_data_result;
1539  bool predivide = handle->predivide;
1540 
1541  if (!handle->buffer) {
1542  unsigned char *byte_buffer = handle->byte_buffer;
1543 
1544  const char *from_colorspace = handle->byte_colorspace;
1545  const char *to_colorspace = global_role_scene_linear;
1546 
1547  float *fp;
1548  unsigned char *cp;
1549  const size_t i_last = ((size_t)width) * height;
1550  size_t i;
1551 
1552  /* first convert byte buffer to float, keep in image space */
1553  for (i = 0, fp = linear_buffer, cp = byte_buffer; i != i_last;
1554  i++, fp += channels, cp += channels) {
1555  if (channels == 3) {
1556  rgb_uchar_to_float(fp, cp);
1557  }
1558  else if (channels == 4) {
1559  rgba_uchar_to_float(fp, cp);
1560  }
1561  else {
1562  BLI_assert_msg(0, "Buffers of 3 or 4 channels are only supported here");
1563  }
1564  }
1565 
1566  if (!is_data && !is_data_display) {
1567  /* convert float buffer to scene linear space */
1569  linear_buffer, width, height, channels, from_colorspace, to_colorspace, false);
1570  }
1571 
1572  *is_straight_alpha = true;
1573  }
1574  else if (handle->float_colorspace) {
1575  /* currently float is non-linear only in sequencer, which is working
1576  * in its own color space even to handle float buffers.
1577  * This color space is the same for byte and float images.
1578  * Need to convert float buffer to linear space before applying display transform
1579  */
1580 
1581  const char *from_colorspace = handle->float_colorspace;
1582  const char *to_colorspace = global_role_scene_linear;
1583 
1584  memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
1585 
1586  if (!is_data && !is_data_display) {
1588  linear_buffer, width, height, channels, from_colorspace, to_colorspace, predivide);
1589  }
1590 
1591  *is_straight_alpha = false;
1592  }
1593  else {
1594  /* some processors would want to modify float original buffer
1595  * before converting it into display byte buffer, so we need to
1596  * make sure original's ImBuf buffers wouldn't be modified by
1597  * using duplicated buffer here
1598  */
1599 
1600  memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
1601 
1602  *is_straight_alpha = false;
1603  }
1604 }
1605 
1606 static void *do_display_buffer_apply_thread(void *handle_v)
1607 {
1608  DisplayBufferThread *handle = (DisplayBufferThread *)handle_v;
1609  ColormanageProcessor *cm_processor = handle->cm_processor;
1610  float *display_buffer = handle->display_buffer;
1611  unsigned char *display_buffer_byte = handle->display_buffer_byte;
1612  int channels = handle->channels;
1613  int width = handle->width;
1614  int height = handle->tot_line;
1615  float dither = handle->dither;
1616  bool is_data = handle->is_data;
1617 
1618  if (cm_processor == NULL) {
1619  if (display_buffer_byte && display_buffer_byte != handle->byte_buffer) {
1620  IMB_buffer_byte_from_byte(display_buffer_byte,
1621  handle->byte_buffer,
1624  false,
1625  width,
1626  height,
1627  width,
1628  width);
1629  }
1630 
1631  if (display_buffer) {
1632  IMB_buffer_float_from_byte(display_buffer,
1633  handle->byte_buffer,
1636  false,
1637  width,
1638  height,
1639  width,
1640  width);
1641  }
1642  }
1643  else {
1644  bool is_straight_alpha;
1645  float *linear_buffer = MEM_mallocN(((size_t)channels) * width * height * sizeof(float),
1646  "color conversion linear buffer");
1647 
1648  display_buffer_apply_get_linear_buffer(handle, height, linear_buffer, &is_straight_alpha);
1649 
1650  bool predivide = handle->predivide && (is_straight_alpha == false);
1651 
1652  if (is_data) {
1653  /* special case for data buffers - no color space conversions,
1654  * only generate byte buffers
1655  */
1656  }
1657  else {
1658  /* apply processor */
1660  cm_processor, linear_buffer, width, height, channels, predivide);
1661  }
1662 
1663  /* copy result to output buffers */
1664  if (display_buffer_byte) {
1665  /* do conversion */
1666  IMB_buffer_byte_from_float(display_buffer_byte,
1667  linear_buffer,
1668  channels,
1669  dither,
1672  predivide,
1673  width,
1674  height,
1675  width,
1676  width);
1677  }
1678 
1679  if (display_buffer) {
1680  memcpy(display_buffer, linear_buffer, ((size_t)width) * height * channels * sizeof(float));
1681 
1682  if (is_straight_alpha && channels == 4) {
1683  const size_t i_last = ((size_t)width) * height;
1684  size_t i;
1685  float *fp;
1686 
1687  for (i = 0, fp = display_buffer; i != i_last; i++, fp += channels) {
1689  }
1690  }
1691  }
1692 
1693  MEM_freeN(linear_buffer);
1694  }
1695 
1696  return NULL;
1697 }
1698 
1700  const float *buffer,
1701  unsigned char *byte_buffer,
1702  float *display_buffer,
1703  unsigned char *display_buffer_byte,
1704  ColormanageProcessor *cm_processor)
1705 {
1707 
1708  init_data.ibuf = ibuf;
1709  init_data.cm_processor = cm_processor;
1710  init_data.buffer = buffer;
1711  init_data.byte_buffer = byte_buffer;
1712  init_data.display_buffer = display_buffer;
1713  init_data.display_buffer_byte = display_buffer_byte;
1714 
1715  if (ibuf->rect_colorspace != NULL) {
1716  init_data.byte_colorspace = ibuf->rect_colorspace->name;
1717  }
1718  else {
1719  /* happens for viewer images, which are not so simple to determine where to
1720  * set image buffer's color spaces
1721  */
1722  init_data.byte_colorspace = global_role_default_byte;
1723  }
1724 
1725  if (ibuf->float_colorspace != NULL) {
1726  /* sequencer stores float buffers in non-linear space */
1727  init_data.float_colorspace = ibuf->float_colorspace->name;
1728  }
1729  else {
1730  init_data.float_colorspace = NULL;
1731  }
1732 
1734  sizeof(DisplayBufferThread),
1735  &init_data,
1738 }
1739 
1741  const ColorManagedViewSettings *view_settings,
1742  const ColorManagedDisplaySettings *display_settings)
1743 {
1744  if ((view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) == 0 &&
1745  view_settings->exposure == 0.0f && view_settings->gamma == 1.0f) {
1746  const char *from_colorspace = ibuf->rect_colorspace->name;
1747  const char *to_colorspace = get_display_colorspace_name(view_settings, display_settings);
1748  ColorManagedLook *look_descr = colormanage_look_get_named(view_settings->look);
1749  if (look_descr != NULL && !STREQ(look_descr->process_space, "")) {
1750  return false;
1751  }
1752 
1753  if (to_colorspace && STREQ(from_colorspace, to_colorspace)) {
1754  return true;
1755  }
1756  }
1757 
1758  return false;
1759 }
1760 
1762  ImBuf *ibuf,
1763  float *display_buffer,
1764  unsigned char *display_buffer_byte,
1765  const ColorManagedViewSettings *view_settings,
1766  const ColorManagedDisplaySettings *display_settings)
1767 {
1768  ColormanageProcessor *cm_processor = NULL;
1769  bool skip_transform = false;
1770 
1771  /* if we're going to transform byte buffer, check whether transformation would
1772  * happen to the same color space as byte buffer itself is
1773  * this would save byte -> float -> byte conversions making display buffer
1774  * computation noticeable faster
1775  */
1776  if (ibuf->rect_float == NULL && ibuf->rect_colorspace) {
1777  skip_transform = is_ibuf_rect_in_display_space(ibuf, view_settings, display_settings);
1778  }
1779 
1780  if (skip_transform == false) {
1781  cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1782  }
1783 
1785  ibuf->rect_float,
1786  (unsigned char *)ibuf->rect,
1787  display_buffer,
1788  display_buffer_byte,
1789  cm_processor);
1790 
1791  if (cm_processor) {
1792  IMB_colormanagement_processor_free(cm_processor);
1793  }
1794 }
1795 
1797  unsigned char *display_buffer,
1798  const ColorManagedViewSettings *view_settings,
1799  const ColorManagedDisplaySettings *display_settings)
1800 {
1802  ibuf, NULL, display_buffer, view_settings, display_settings);
1803 }
1804 
1807 /* -------------------------------------------------------------------- */
1813  unsigned char *byte_buffer;
1815  int width;
1822 
1823 typedef struct ProcessorTransformInit {
1825  unsigned char *byte_buffer;
1827  int width;
1828  int height;
1833 
1834 static void processor_transform_init_handle(void *handle_v,
1835  int start_line,
1836  int tot_line,
1837  void *init_data_v)
1838 {
1839  ProcessorTransformThread *handle = (ProcessorTransformThread *)handle_v;
1841 
1842  const int channels = init_data->channels;
1843  const int width = init_data->width;
1844  const bool predivide = init_data->predivide;
1845  const bool float_from_byte = init_data->float_from_byte;
1846 
1847  const size_t offset = ((size_t)channels) * start_line * width;
1848 
1849  memset(handle, 0, sizeof(ProcessorTransformThread));
1850 
1851  handle->cm_processor = init_data->cm_processor;
1852 
1853  if (init_data->byte_buffer != NULL) {
1854  /* TODO(serge): Offset might be different for byte and float buffers. */
1855  handle->byte_buffer = init_data->byte_buffer + offset;
1856  }
1857  if (init_data->float_buffer != NULL) {
1858  handle->float_buffer = init_data->float_buffer + offset;
1859  }
1860 
1861  handle->width = width;
1862 
1863  handle->start_line = start_line;
1864  handle->tot_line = tot_line;
1865 
1866  handle->channels = channels;
1867  handle->predivide = predivide;
1868  handle->float_from_byte = float_from_byte;
1869 }
1870 
1871 static void *do_processor_transform_thread(void *handle_v)
1872 {
1873  ProcessorTransformThread *handle = (ProcessorTransformThread *)handle_v;
1874  unsigned char *byte_buffer = handle->byte_buffer;
1875  float *float_buffer = handle->float_buffer;
1876  const int channels = handle->channels;
1877  const int width = handle->width;
1878  const int height = handle->tot_line;
1879  const bool predivide = handle->predivide;
1880  const bool float_from_byte = handle->float_from_byte;
1881 
1882  if (float_from_byte) {
1883  IMB_buffer_float_from_byte(float_buffer,
1884  byte_buffer,
1887  false,
1888  width,
1889  height,
1890  width,
1891  width);
1893  handle->cm_processor, float_buffer, width, height, channels, predivide);
1894  IMB_premultiply_rect_float(float_buffer, 4, width, height);
1895  }
1896  else {
1897  if (byte_buffer != NULL) {
1899  handle->cm_processor, byte_buffer, width, height, channels);
1900  }
1901  if (float_buffer != NULL) {
1903  handle->cm_processor, float_buffer, width, height, channels, predivide);
1904  }
1905  }
1906 
1907  return NULL;
1908 }
1909 
1910 static void processor_transform_apply_threaded(unsigned char *byte_buffer,
1911  float *float_buffer,
1912  const int width,
1913  const int height,
1914  const int channels,
1915  ColormanageProcessor *cm_processor,
1916  const bool predivide,
1917  const bool float_from_byte)
1918 {
1920 
1921  init_data.cm_processor = cm_processor;
1922  init_data.byte_buffer = byte_buffer;
1923  init_data.float_buffer = float_buffer;
1924  init_data.width = width;
1925  init_data.height = height;
1926  init_data.channels = channels;
1927  init_data.predivide = predivide;
1928  init_data.float_from_byte = float_from_byte;
1929 
1931  sizeof(ProcessorTransformThread),
1932  &init_data,
1935 }
1936 
1939 /* -------------------------------------------------------------------- */
1943 /* Convert the whole buffer from specified by name color space to another -
1944  * internal implementation. */
1945 static void colormanagement_transform_ex(unsigned char *byte_buffer,
1946  float *float_buffer,
1947  int width,
1948  int height,
1949  int channels,
1950  const char *from_colorspace,
1951  const char *to_colorspace,
1952  bool predivide,
1953  bool do_threaded)
1954 {
1955  ColormanageProcessor *cm_processor;
1956 
1957  if (from_colorspace[0] == '\0') {
1958  return;
1959  }
1960 
1961  if (STREQ(from_colorspace, to_colorspace)) {
1962  /* if source and destination color spaces are identical, skip
1963  * threading overhead and simply do nothing
1964  */
1965  return;
1966  }
1967 
1968  cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
1969 
1970  if (do_threaded) {
1972  byte_buffer, float_buffer, width, height, channels, cm_processor, predivide, false);
1973  }
1974  else {
1975  if (byte_buffer != NULL) {
1976  IMB_colormanagement_processor_apply_byte(cm_processor, byte_buffer, width, height, channels);
1977  }
1978  if (float_buffer != NULL) {
1980  cm_processor, float_buffer, width, height, channels, predivide);
1981  }
1982  }
1983 
1984  IMB_colormanagement_processor_free(cm_processor);
1985 }
1986 
1988  int width,
1989  int height,
1990  int channels,
1991  const char *from_colorspace,
1992  const char *to_colorspace,
1993  bool predivide)
1994 {
1996  NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
1997 }
1998 
2000  int width,
2001  int height,
2002  int channels,
2003  const char *from_colorspace,
2004  const char *to_colorspace,
2005  bool predivide)
2006 {
2008  NULL, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
2009 }
2010 
2012  int width,
2013  int height,
2014  int channels,
2015  const char *from_colorspace,
2016  const char *to_colorspace)
2017 {
2019  buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, false);
2020 }
2022  int width,
2023  int height,
2024  int channels,
2025  const char *from_colorspace,
2026  const char *to_colorspace)
2027 {
2029  buffer, NULL, width, height, channels, from_colorspace, to_colorspace, false, true);
2030 }
2031 
2033  unsigned char *byte_buffer,
2034  int width,
2035  int height,
2036  int channels,
2037  const char *from_colorspace,
2038  const char *to_colorspace)
2039 {
2040  IMB_buffer_float_from_byte(float_buffer,
2041  byte_buffer,
2044  true,
2045  width,
2046  height,
2047  width,
2048  width);
2050  float_buffer, width, height, channels, from_colorspace, to_colorspace, true);
2051 }
2053  unsigned char *byte_buffer,
2054  int width,
2055  int height,
2056  int channels,
2057  const char *from_colorspace,
2058  const char *to_colorspace)
2059 {
2060  ColormanageProcessor *cm_processor;
2061  if (from_colorspace == NULL || from_colorspace[0] == '\0') {
2062  return;
2063  }
2064  if (STREQ(from_colorspace, to_colorspace)) {
2065  /* Because this function always takes a byte buffer and returns a float buffer, it must
2066  * always do byte-to-float conversion of some kind. To avoid threading overhead
2067  * IMB_buffer_float_from_byte is used when color spaces are identical. See T51002.
2068  */
2069  IMB_buffer_float_from_byte(float_buffer,
2070  byte_buffer,
2073  false,
2074  width,
2075  height,
2076  width,
2077  width);
2078  IMB_premultiply_rect_float(float_buffer, 4, width, height);
2079  return;
2080  }
2081  cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
2083  byte_buffer, float_buffer, width, height, channels, cm_processor, false, true);
2084  IMB_colormanagement_processor_free(cm_processor);
2085 }
2086 
2088  const char *from_colorspace,
2089  const char *to_colorspace)
2090 {
2091  ColormanageProcessor *cm_processor;
2092 
2093  if (from_colorspace[0] == '\0') {
2094  return;
2095  }
2096 
2097  if (STREQ(from_colorspace, to_colorspace)) {
2098  /* if source and destination color spaces are identical, skip
2099  * threading overhead and simply do nothing
2100  */
2101  return;
2102  }
2103 
2104  cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
2105 
2106  IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
2107 
2108  IMB_colormanagement_processor_free(cm_processor);
2109 }
2110 
2112 {
2113  OCIO_ConstCPUProcessorRcPtr *processor;
2114 
2115  if (!colorspace) {
2116  /* should never happen */
2117  printf("%s: perform conversion from unknown color space\n", __func__);
2118  return;
2119  }
2120 
2121  processor = colorspace_to_scene_linear_cpu_processor(colorspace);
2122 
2123  if (processor != NULL) {
2124  OCIO_cpuProcessorApplyRGB(processor, pixel);
2125  }
2126 }
2127 
2129 {
2130  OCIO_ConstCPUProcessorRcPtr *processor;
2131 
2132  if (!colorspace) {
2133  /* should never happen */
2134  printf("%s: perform conversion from unknown color space\n", __func__);
2135  return;
2136  }
2137 
2138  processor = colorspace_from_scene_linear_cpu_processor(colorspace);
2139 
2140  if (processor != NULL) {
2141  OCIO_cpuProcessorApplyRGB(processor, pixel);
2142  }
2143 }
2144 
2146  bool predivide,
2147  ColorSpace *colorspace)
2148 {
2149  OCIO_ConstCPUProcessorRcPtr *processor;
2150 
2151  if (!colorspace) {
2152  /* should never happen */
2153  printf("%s: perform conversion from unknown color space\n", __func__);
2154  return;
2155  }
2156 
2157  processor = colorspace_to_scene_linear_cpu_processor(colorspace);
2158 
2159  if (processor != NULL) {
2160  if (predivide) {
2161  OCIO_cpuProcessorApplyRGBA_predivide(processor, pixel);
2162  }
2163  else {
2164  OCIO_cpuProcessorApplyRGBA(processor, pixel);
2165  }
2166  }
2167 }
2168 
2170  int width,
2171  int height,
2172  int channels,
2173  struct ColorSpace *colorspace,
2174  bool predivide)
2175 {
2176  OCIO_ConstCPUProcessorRcPtr *processor;
2177 
2178  if (!colorspace) {
2179  /* should never happen */
2180  printf("%s: perform conversion from unknown color space\n", __func__);
2181  return;
2182  }
2183 
2184  processor = colorspace_to_scene_linear_cpu_processor(colorspace);
2185 
2186  if (processor != NULL) {
2187  OCIO_PackedImageDesc *img;
2188 
2190  width,
2191  height,
2192  channels,
2193  sizeof(float),
2194  (size_t)channels * sizeof(float),
2195  (size_t)channels * sizeof(float) * width);
2196 
2197  if (predivide) {
2198  OCIO_cpuProcessorApply_predivide(processor, img);
2199  }
2200  else {
2201  OCIO_cpuProcessorApply(processor, img);
2202  }
2203 
2205  }
2206 }
2207 
2208 void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
2209  const int offset_x,
2210  const int offset_y,
2211  const int width,
2212  const int height,
2213  const struct ImBuf *ibuf,
2214  const bool store_premultiplied)
2215 {
2216  /* Byte buffer storage, only for sRGB, scene linear and data texture since other
2217  * color space conversions can't be done on the GPU. */
2218  BLI_assert(ibuf->rect && ibuf->rect_float == NULL);
2222 
2223  const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
2224  const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
2225 
2226  for (int y = 0; y < height; y++) {
2227  const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
2228  const size_t out_offset = y * width;
2229  const unsigned char *in = in_buffer + in_offset * 4;
2230  unsigned char *out = out_buffer + out_offset * 4;
2231 
2232  if (use_premultiply) {
2233  /* Premultiply only. */
2234  for (int x = 0; x < width; x++, in += 4, out += 4) {
2235  out[0] = (in[0] * in[3]) >> 8;
2236  out[1] = (in[1] * in[3]) >> 8;
2237  out[2] = (in[2] * in[3]) >> 8;
2238  out[3] = in[3];
2239  }
2240  }
2241  else {
2242  /* Copy only. */
2243  for (int x = 0; x < width; x++, in += 4, out += 4) {
2244  out[0] = in[0];
2245  out[1] = in[1];
2246  out[2] = in[2];
2247  out[3] = in[3];
2248  }
2249  }
2250  }
2251 }
2252 
2254  const int offset_x,
2255  const int offset_y,
2256  const int width,
2257  const int height,
2258  const struct ImBuf *ibuf,
2259  const bool store_premultiplied)
2260 {
2261  /* Float texture are stored in scene linear color space, with premultiplied
2262  * alpha depending on the image alpha mode. */
2263  if (ibuf->rect_float) {
2264  /* Float source buffer. */
2265  const float *in_buffer = ibuf->rect_float;
2266  const int in_channels = ibuf->channels;
2267  const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied;
2268 
2269  for (int y = 0; y < height; y++) {
2270  const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
2271  const size_t out_offset = y * width;
2272  const float *in = in_buffer + in_offset * in_channels;
2273  float *out = out_buffer + out_offset * 4;
2274 
2275  if (in_channels == 1) {
2276  /* Copy single channel. */
2277  for (int x = 0; x < width; x++, in += 1, out += 4) {
2278  out[0] = in[0];
2279  out[1] = in[0];
2280  out[2] = in[0];
2281  out[3] = in[0];
2282  }
2283  }
2284  else if (in_channels == 3) {
2285  /* Copy RGB. */
2286  for (int x = 0; x < width; x++, in += 3, out += 4) {
2287  out[0] = in[0];
2288  out[1] = in[1];
2289  out[2] = in[2];
2290  out[3] = 1.0f;
2291  }
2292  }
2293  else if (in_channels == 4) {
2294  /* Copy or convert RGBA. */
2295  if (use_unpremultiply) {
2296  for (int x = 0; x < width; x++, in += 4, out += 4) {
2298  }
2299  }
2300  else {
2301  memcpy(out, in, sizeof(float[4]) * width);
2302  }
2303  }
2304  }
2305  }
2306  else {
2307  /* Byte source buffer. */
2308  const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
2309  const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
2310 
2311  /* TODO(brecht): make this multi-threaded, or at least process in batches. */
2312  OCIO_ConstCPUProcessorRcPtr *processor = (ibuf->rect_colorspace) ?
2314  ibuf->rect_colorspace) :
2315  NULL;
2316 
2317  for (int y = 0; y < height; y++) {
2318  const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
2319  const size_t out_offset = y * width;
2320  const unsigned char *in = in_buffer + in_offset * 4;
2321  float *out = out_buffer + out_offset * 4;
2322 
2323  /* Convert to scene linear, to sRGB and premultiply. */
2324  for (int x = 0; x < width; x++, in += 4, out += 4) {
2325  float pixel[4];
2326  rgba_uchar_to_float(pixel, in);
2327  if (processor) {
2328  OCIO_cpuProcessorApplyRGB(processor, pixel);
2329  }
2330  else {
2331  srgb_to_linearrgb_v3_v3(pixel, pixel);
2332  }
2333  if (use_premultiply) {
2334  mul_v3_fl(pixel, pixel[3]);
2335  }
2336  copy_v4_v4(out, pixel);
2337  }
2338  }
2339  }
2340 }
2341 
2343  const float scene_linear[3])
2344 {
2346  /* Create processor if none exists. */
2348 
2350  OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
2352 
2353  if (processor != NULL) {
2355  OCIO_processorRelease(processor);
2356  }
2357  else {
2359  }
2360  }
2361 
2363  }
2364 
2365  copy_v3_v3(color_picking, scene_linear);
2366 
2369  }
2370 }
2371 
2373  const float color_picking[3])
2374 {
2376  /* Create processor if none exists. */
2378 
2380  OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
2382 
2383  if (processor != NULL) {
2385  OCIO_processorRelease(processor);
2386  }
2387  else {
2389  }
2390  }
2391 
2393  }
2394 
2395  copy_v3_v3(scene_linear, color_picking);
2396 
2399  }
2400 }
2401 
2403 {
2404  OCIO_ConstCPUProcessorRcPtr *processor = display_from_scene_linear_processor(display);
2405 
2406  if (processor != NULL) {
2407  OCIO_cpuProcessorApplyRGB(processor, pixel);
2408  }
2409 }
2410 
2412 {
2413  OCIO_ConstCPUProcessorRcPtr *processor = display_to_scene_linear_processor(display);
2414 
2415  if (processor != NULL) {
2416  OCIO_cpuProcessorApplyRGB(processor, pixel);
2417  }
2418 }
2419 
2421  float result[4],
2422  const float pixel[4],
2423  const ColorManagedViewSettings *view_settings,
2424  const ColorManagedDisplaySettings *display_settings)
2425 {
2426  ColormanageProcessor *cm_processor;
2427 
2428  copy_v4_v4(result, pixel);
2429 
2430  cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
2432  IMB_colormanagement_processor_free(cm_processor);
2433 }
2434 
2436  float result[3],
2437  const float pixel[3],
2438  const ColorManagedViewSettings *view_settings,
2439  const ColorManagedDisplaySettings *display_settings)
2440 {
2441  ColormanageProcessor *cm_processor;
2442 
2443  copy_v3_v3(result, pixel);
2444 
2445  cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
2447  IMB_colormanagement_processor_free(cm_processor);
2448 }
2449 
2451  ImBuf *ibuf,
2452  const ColorManagedViewSettings *view_settings,
2453  const ColorManagedDisplaySettings *display_settings,
2454  bool make_byte)
2455 {
2456  if (!ibuf->rect && make_byte) {
2457  imb_addrectImBuf(ibuf);
2458  }
2459 
2461  ibuf, ibuf->rect_float, (unsigned char *)ibuf->rect, view_settings, display_settings);
2462 }
2463 
2465  ImBuf *ibuf,
2466  const ColorManagedViewSettings *view_settings,
2467  const ColorManagedDisplaySettings *display_settings)
2468 {
2469  colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false);
2470 }
2471 
2472 static ImBuf *imbuf_ensure_editable(ImBuf *ibuf, ImBuf *colormanaged_ibuf, bool allocate_result)
2473 {
2474  if (colormanaged_ibuf != ibuf) {
2475  /* Is already an editable copy. */
2476  return colormanaged_ibuf;
2477  }
2478 
2479  if (allocate_result) {
2480  /* Copy full image buffer. */
2481  colormanaged_ibuf = IMB_dupImBuf(ibuf);
2482  IMB_metadata_copy(colormanaged_ibuf, ibuf);
2483  return colormanaged_ibuf;
2484  }
2485 
2486  /* Render pipeline is constructing image buffer itself,
2487  * but it's re-using byte and float buffers from render result make copy of this buffers
2488  * here sine this buffers would be transformed to other color space here. */
2489  if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
2490  ibuf->rect = MEM_dupallocN(ibuf->rect);
2491  ibuf->mall |= IB_rect;
2492  }
2493 
2494  if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
2495  ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
2496  ibuf->mall |= IB_rectfloat;
2497  }
2498 
2499  return ibuf;
2500 }
2501 
2503  bool save_as_render,
2504  bool allocate_result,
2505  const ImageFormatData *image_format)
2506 {
2507  ImBuf *colormanaged_ibuf = ibuf;
2508 
2509  /* Update byte buffer if exists but invalid. */
2510  if (ibuf->rect_float && ibuf->rect &&
2512  IMB_rect_from_float(ibuf);
2514  }
2515 
2516  /* Detect if we are writing to a file format that needs a linear float buffer. */
2517  const bool linear_float_output = BKE_imtype_requires_linear_float(image_format->imtype);
2518 
2519  /* Detect if we are writing output a byte buffer, which we would need to create
2520  * with color management conversions applied. This may be for either applying the
2521  * display transform for renders, or a user specified color space for the file. */
2522  const bool byte_output = BKE_image_format_is_byte(image_format);
2523 
2524  BLI_assert(!(byte_output && linear_float_output));
2525 
2526  /* If we're saving from RGBA to RGB buffer then it's not so much useful to just ignore alpha --
2527  * it leads to bad artifacts especially when saving byte images.
2528  *
2529  * What we do here is we're overlaying our image on top of background color (which is currently
2530  * black). This is quite much the same as what Gimp does and it seems to be what artists expects
2531  * from saving.
2532  *
2533  * Do a conversion here, so image format writers could happily assume all the alpha tricks were
2534  * made already. helps keep things locally here, not spreading it to all possible image writers
2535  * we've got.
2536  */
2537  if (image_format->planes != R_IMF_PLANES_RGBA) {
2538  float color[3] = {0, 0, 0};
2539 
2540  colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
2541 
2542  if (colormanaged_ibuf->rect_float && colormanaged_ibuf->channels == 4) {
2544  colormanaged_ibuf->rect_float, colormanaged_ibuf->x, colormanaged_ibuf->y, color);
2545  }
2546 
2547  if (colormanaged_ibuf->rect) {
2548  IMB_alpha_under_color_byte((unsigned char *)colormanaged_ibuf->rect,
2549  colormanaged_ibuf->x,
2550  colormanaged_ibuf->y,
2551  color);
2552  }
2553  }
2554 
2555  if (save_as_render && !linear_float_output) {
2556  /* Render output: perform conversion to display space using view transform. */
2557  colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
2558 
2559  colormanagement_imbuf_make_display_space(colormanaged_ibuf,
2560  &image_format->view_settings,
2561  &image_format->display_settings,
2562  byte_output);
2563 
2564  if (colormanaged_ibuf->rect_float) {
2565  /* Float buffer isn't linear anymore,
2566  * image format write callback should check for this flag and assume
2567  * no space conversion should happen if ibuf->float_colorspace != NULL. */
2569  &image_format->view_settings, &image_format->display_settings);
2570  if (byte_output) {
2571  colormanaged_ibuf->rect_colorspace = colormanaged_ibuf->float_colorspace;
2572  }
2573  }
2574  }
2575  else {
2576  /* Linear render or regular file output: conversion between two color spaces. */
2577 
2578  /* Detect which color space we need to convert between. */
2579  const char *from_colorspace = (ibuf->rect_float && !(byte_output && ibuf->rect)) ?
2580  /* From float buffer. */
2581  (ibuf->float_colorspace) ? ibuf->float_colorspace->name :
2583  /* From byte buffer. */
2584  (ibuf->rect_colorspace) ? ibuf->rect_colorspace->name :
2586 
2587  const char *to_colorspace = image_format->linear_colorspace_settings.name;
2588 
2589  /* TODO: can we check with OCIO if color spaces are the same but have different names? */
2590  if (to_colorspace[0] == '\0' || STREQ(from_colorspace, to_colorspace)) {
2591  /* No conversion needed, but may still need to allocate byte buffer for output. */
2592  if (byte_output && !ibuf->rect) {
2593  ibuf->rect_colorspace = ibuf->float_colorspace;
2594  IMB_rect_from_float(ibuf);
2595  }
2596  }
2597  else {
2598  /* Color space conversion needed. */
2599  colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
2600 
2601  if (byte_output) {
2602  colormanaged_ibuf->rect_colorspace = colormanage_colorspace_get_named(to_colorspace);
2603 
2604  if (colormanaged_ibuf->rect) {
2605  /* Byte to byte. */
2606  IMB_colormanagement_transform_byte_threaded((unsigned char *)colormanaged_ibuf->rect,
2607  colormanaged_ibuf->x,
2608  colormanaged_ibuf->y,
2609  colormanaged_ibuf->channels,
2610  from_colorspace,
2611  to_colorspace);
2612  }
2613  else {
2614  /* Float to byte. */
2615  IMB_rect_from_float(colormanaged_ibuf);
2616  }
2617  }
2618  else {
2619  if (!colormanaged_ibuf->rect_float) {
2620  /* Byte to float. */
2621  IMB_float_from_rect(colormanaged_ibuf);
2622  imb_freerectImBuf(colormanaged_ibuf);
2623 
2624  /* This conversion always goes to scene linear. */
2625  from_colorspace = global_role_scene_linear;
2626  }
2627 
2628  if (colormanaged_ibuf->rect_float) {
2629  /* Float to float. */
2630  IMB_colormanagement_transform(colormanaged_ibuf->rect_float,
2631  colormanaged_ibuf->x,
2632  colormanaged_ibuf->y,
2633  colormanaged_ibuf->channels,
2634  from_colorspace,
2635  to_colorspace,
2636  false);
2637 
2638  colormanaged_ibuf->float_colorspace = colormanage_colorspace_get_named(to_colorspace);
2639  }
2640  }
2641  }
2642  }
2643 
2644  return colormanaged_ibuf;
2645 }
2646 
2649 /* -------------------------------------------------------------------- */
2653 unsigned char *IMB_display_buffer_acquire(ImBuf *ibuf,
2654  const ColorManagedViewSettings *view_settings,
2655  const ColorManagedDisplaySettings *display_settings,
2656  void **cache_handle)
2657 {
2658  unsigned char *display_buffer;
2659  size_t buffer_size;
2660  ColormanageCacheViewSettings cache_view_settings;
2661  ColormanageCacheDisplaySettings cache_display_settings;
2662  ColorManagedViewSettings default_view_settings;
2663  const ColorManagedViewSettings *applied_view_settings;
2664 
2665  *cache_handle = NULL;
2666 
2667  if (!ibuf->x || !ibuf->y) {
2668  return NULL;
2669  }
2670 
2671  if (view_settings) {
2672  applied_view_settings = view_settings;
2673  }
2674  else {
2675  /* If no view settings were specified, use default ones, which will
2676  * attempt not to do any extra color correction. */
2677  IMB_colormanagement_init_default_view_settings(&default_view_settings, display_settings);
2678  applied_view_settings = &default_view_settings;
2679  }
2680 
2681  /* early out: no float buffer and byte buffer is already in display space,
2682  * let's just use if
2683  */
2684  if (ibuf->rect_float == NULL && ibuf->rect_colorspace && ibuf->channels == 4) {
2685  if (is_ibuf_rect_in_display_space(ibuf, applied_view_settings, display_settings)) {
2686  return (unsigned char *)ibuf->rect;
2687  }
2688  }
2689 
2690  colormanage_view_settings_to_cache(ibuf, &cache_view_settings, applied_view_settings);
2691  colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
2692 
2693  if (ibuf->invalid_rect.xmin != ibuf->invalid_rect.xmax) {
2694  if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0) {
2696  ibuf->rect_float,
2697  (unsigned char *)ibuf->rect,
2698  ibuf->x,
2699  0,
2700  0,
2701  applied_view_settings,
2702  display_settings,
2703  ibuf->invalid_rect.xmin,
2704  ibuf->invalid_rect.ymin,
2705  ibuf->invalid_rect.xmax,
2706  ibuf->invalid_rect.ymax);
2707  }
2708 
2709  BLI_rcti_init(&ibuf->invalid_rect, 0, 0, 0, 0);
2710  }
2711 
2713 
2714  /* ensure color management bit fields exists */
2715  if (!ibuf->display_buffer_flags) {
2716  ibuf->display_buffer_flags = MEM_callocN(sizeof(unsigned int) * global_tot_display,
2717  "imbuf display_buffer_flags");
2718  }
2719  else if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) {
2720  /* all display buffers were marked as invalid from other areas,
2721  * now propagate this flag to internal color management routines
2722  */
2723  memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
2724 
2726  }
2727 
2728  display_buffer = colormanage_cache_get(
2729  ibuf, &cache_view_settings, &cache_display_settings, cache_handle);
2730 
2731  if (display_buffer) {
2733  return display_buffer;
2734  }
2735 
2736  buffer_size = DISPLAY_BUFFER_CHANNELS * ((size_t)ibuf->x) * ibuf->y * sizeof(char);
2737  display_buffer = MEM_callocN(buffer_size, "imbuf display buffer");
2738 
2740  ibuf, display_buffer, applied_view_settings, display_settings);
2741 
2743  ibuf, &cache_view_settings, &cache_display_settings, display_buffer, cache_handle);
2744 
2746 
2747  return display_buffer;
2748 }
2749 
2750 unsigned char *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
2751 {
2752  ColorManagedViewSettings *view_settings;
2753  ColorManagedDisplaySettings *display_settings;
2754 
2755  IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
2756 
2757  return IMB_display_buffer_acquire(ibuf, view_settings, display_settings, cache_handle);
2758 }
2759 
2760 void IMB_display_buffer_transform_apply(unsigned char *display_buffer,
2761  float *linear_buffer,
2762  int width,
2763  int height,
2764  int channels,
2765  const ColorManagedViewSettings *view_settings,
2766  const ColorManagedDisplaySettings *display_settings,
2767  bool predivide)
2768 {
2769  float *buffer;
2771  display_settings);
2772 
2773  buffer = MEM_mallocN((size_t)channels * width * height * sizeof(float),
2774  "display transform temp buffer");
2775  memcpy(buffer, linear_buffer, (size_t)channels * width * height * sizeof(float));
2776 
2777  IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
2778 
2779  IMB_colormanagement_processor_free(cm_processor);
2780 
2781  IMB_buffer_byte_from_float(display_buffer,
2782  buffer,
2783  channels,
2784  0.0f,
2787  false,
2788  width,
2789  height,
2790  width,
2791  width);
2792 
2793  MEM_freeN(buffer);
2794 }
2795 
2796 void IMB_display_buffer_release(void *cache_handle)
2797 {
2798  if (cache_handle) {
2800 
2801  colormanage_cache_handle_release(cache_handle);
2802 
2804  }
2805 }
2806 
2809 /* -------------------------------------------------------------------- */
2814 {
2815  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
2816  const char *display_name;
2817 
2818  display_name = OCIO_configGetDefaultDisplay(config);
2819 
2820  OCIO_configRelease(config);
2821 
2822  return display_name;
2823 }
2824 
2826 {
2827  const char *display_name = colormanage_display_get_default_name();
2828 
2829  if (display_name[0] == '\0') {
2830  return NULL;
2831  }
2832 
2833  return colormanage_display_get_named(display_name);
2834 }
2835 
2837 {
2838  ColorManagedDisplay *display;
2839  int index = 0;
2840 
2841  if (global_displays.last) {
2842  ColorManagedDisplay *last_display = global_displays.last;
2843 
2844  index = last_display->index;
2845  }
2846 
2847  display = MEM_callocN(sizeof(ColorManagedDisplay), "ColorManagedDisplay");
2848 
2849  display->index = index + 1;
2850 
2851  BLI_strncpy(display->name, name, sizeof(display->name));
2852 
2853  BLI_addtail(&global_displays, display);
2854 
2855  return display;
2856 }
2857 
2859 {
2860  ColorManagedDisplay *display;
2861 
2862  for (display = global_displays.first; display; display = display->next) {
2863  if (STREQ(display->name, name)) {
2864  return display;
2865  }
2866  }
2867 
2868  return NULL;
2869 }
2870 
2872 {
2873  /* display indices are 1-based */
2874  return BLI_findlink(&global_displays, index - 1);
2875 }
2876 
2878 {
2879  ColorManagedDisplay *display;
2880 
2881  display = colormanage_display_get_named(name);
2882 
2883  if (display) {
2884  return display->index;
2885  }
2886 
2887  return 0;
2888 }
2889 
2891 {
2892  ColorManagedDisplay *display;
2893 
2894  display = colormanage_display_get_indexed(index);
2895 
2896  if (display) {
2897  return display->name;
2898  }
2899 
2900  return NULL;
2901 }
2902 
2904 {
2906 
2907  return display->name;
2908 }
2909 
2911 {
2912  return colormanage_display_get_named(name);
2913 }
2914 
2916 {
2917  if (colormanage_display_get_named("None") != NULL) {
2918  return "None";
2919  }
2920 
2922 }
2923 
2925  struct ColorManagedDisplay *display)
2926 {
2927  return colormanage_view_get_default_name(display);
2928 }
2929 
2932 /* -------------------------------------------------------------------- */
2937 {
2938  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
2939  const char *name;
2940 
2941  name = OCIO_configGetDefaultView(config, display->name);
2942 
2943  OCIO_configRelease(config);
2944 
2945  return name;
2946 }
2947 
2949 {
2950  const char *name = colormanage_view_get_default_name(display);
2951 
2952  if (!name || name[0] == '\0') {
2953  return NULL;
2954  }
2955 
2956  return colormanage_view_get_named(name);
2957 }
2958 
2960 {
2962  int index = global_tot_view;
2963 
2964  view = MEM_callocN(sizeof(ColorManagedView), "ColorManagedView");
2965  view->index = index + 1;
2966  BLI_strncpy(view->name, name, sizeof(view->name));
2967 
2969 
2970  global_tot_view++;
2971 
2972  return view;
2973 }
2974 
2976 {
2978 
2979  for (view = global_views.first; view; view = view->next) {
2980  if (STREQ(view->name, name)) {
2981  return view;
2982  }
2983  }
2984 
2985  return NULL;
2986 }
2987 
2989 {
2990  /* view transform indices are 1-based */
2991  return BLI_findlink(&global_views, index - 1);
2992 }
2993 
2995  const char *name)
2996 {
2997  ColorManagedDisplay *display = colormanage_display_get_named(display_name);
2998  if (display == NULL) {
2999  return NULL;
3000  }
3001  LISTBASE_FOREACH (LinkData *, view_link, &display->views) {
3002  ColorManagedView *view = view_link->data;
3003  if (STRCASEEQ(name, view->name)) {
3004  return view;
3005  }
3006  }
3007  return NULL;
3008 }
3009 
3011 {
3013 
3014  if (view) {
3015  return view->index;
3016  }
3017 
3018  return 0;
3019 }
3020 
3022 {
3024 
3025  if (view) {
3026  return view->name;
3027  }
3028 
3029  return NULL;
3030 }
3031 
3032 const char *IMB_colormanagement_view_get_default_name(const char *display_name)
3033 {
3034  ColorManagedDisplay *display = colormanage_display_get_named(display_name);
3036 
3037  if (display) {
3039  }
3040 
3041  if (view) {
3042  return view->name;
3043  }
3044 
3045  return NULL;
3046 }
3047 
3050 /* -------------------------------------------------------------------- */
3054 static void colormanage_description_strip(char *description)
3055 {
3056  int i, n;
3057 
3058  for (i = (int)strlen(description) - 1; i >= 0; i--) {
3059  if (ELEM(description[i], '\r', '\n')) {
3060  description[i] = '\0';
3061  }
3062  else {
3063  break;
3064  }
3065  }
3066 
3067  for (i = 0, n = strlen(description); i < n; i++) {
3068  if (ELEM(description[i], '\r', '\n')) {
3069  description[i] = ' ';
3070  }
3071  }
3072 }
3073 
3075  const char *description,
3076  bool is_invertible,
3077  bool is_data)
3078 {
3079  ColorSpace *colorspace, *prev_space;
3080  int counter = 1;
3081 
3082  colorspace = MEM_callocN(sizeof(ColorSpace), "ColorSpace");
3083 
3084  BLI_strncpy(colorspace->name, name, sizeof(colorspace->name));
3085 
3086  if (description) {
3087  BLI_strncpy(colorspace->description, description, sizeof(colorspace->description));
3088 
3090  }
3091 
3092  colorspace->is_invertible = is_invertible;
3093  colorspace->is_data = is_data;
3094 
3095  for (prev_space = global_colorspaces.first; prev_space; prev_space = prev_space->next) {
3096  if (BLI_strcasecmp(prev_space->name, colorspace->name) > 0) {
3097  break;
3098  }
3099 
3100  prev_space->index = counter++;
3101  }
3102 
3103  if (!prev_space) {
3104  BLI_addtail(&global_colorspaces, colorspace);
3105  }
3106  else {
3107  BLI_insertlinkbefore(&global_colorspaces, prev_space, colorspace);
3108  }
3109 
3110  colorspace->index = counter++;
3111  for (; prev_space; prev_space = prev_space->next) {
3112  prev_space->index = counter++;
3113  }
3114 
3116 
3117  return colorspace;
3118 }
3119 
3121 {
3122  ColorSpace *colorspace;
3123 
3124  for (colorspace = global_colorspaces.first; colorspace; colorspace = colorspace->next) {
3125  if (STREQ(colorspace->name, name)) {
3126  return colorspace;
3127  }
3128 
3129  for (int i = 0; i < colorspace->num_aliases; i++) {
3130  if (STREQ(colorspace->aliases[i], name)) {
3131  return colorspace;
3132  }
3133  }
3134  }
3135 
3136  return NULL;
3137 }
3138 
3140 {
3141  const char *role_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
3142 
3143  return colormanage_colorspace_get_named(role_colorspace);
3144 }
3145 
3147 {
3148  /* color space indices are 1-based */
3149  return BLI_findlink(&global_colorspaces, index - 1);
3150 }
3151 
3153 {
3154  ColorSpace *colorspace;
3155 
3156  colorspace = colormanage_colorspace_get_named(name);
3157 
3158  if (colorspace) {
3159  return colorspace->index;
3160  }
3161 
3162  return 0;
3163 }
3164 
3166 {
3167  ColorSpace *colorspace;
3168 
3169  colorspace = colormanage_colorspace_get_indexed(index);
3170 
3171  if (colorspace) {
3172  return colorspace->name;
3173  }
3174 
3175  return "";
3176 }
3177 
3179 {
3180  return colorspace->name;
3181 }
3182 
3184  ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
3185 {
3186  /* Don't modify non-color data space, it does not change with file type. */
3187  ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
3188 
3189  if (colorspace && colorspace->is_data) {
3190  return;
3191  }
3192 
3193  /* Get color space from file type. */
3194  const ImFileType *type = IMB_file_type_from_ibuf(ibuf);
3195  if (type != NULL) {
3196  if (type->save != NULL) {
3197  const char *role_colorspace = IMB_colormanagement_role_colorspace_name_get(
3198  type->default_save_role);
3199  BLI_strncpy(colorspace_settings->name, role_colorspace, sizeof(colorspace_settings->name));
3200  }
3201  }
3202 }
3203 
3206 /* -------------------------------------------------------------------- */
3210 ColorManagedLook *colormanage_look_add(const char *name, const char *process_space, bool is_noop)
3211 {
3212  ColorManagedLook *look;
3213  int index = global_tot_looks;
3214 
3215  look = MEM_callocN(sizeof(ColorManagedLook), "ColorManagedLook");
3216  look->index = index + 1;
3217  BLI_strncpy(look->name, name, sizeof(look->name));
3218  BLI_strncpy(look->ui_name, name, sizeof(look->ui_name));
3219  BLI_strncpy(look->process_space, process_space, sizeof(look->process_space));
3220  look->is_noop = is_noop;
3221 
3222  /* Detect view specific looks. */
3223  const char *separator_offset = strstr(look->name, " - ");
3224  if (separator_offset) {
3225  BLI_strncpy(look->view, look->name, separator_offset - look->name + 1);
3226  BLI_strncpy(look->ui_name, separator_offset + strlen(" - "), sizeof(look->ui_name));
3227  }
3228 
3229  BLI_addtail(&global_looks, look);
3230 
3231  global_tot_looks++;
3232 
3233  return look;
3234 }
3235 
3237 {
3238  ColorManagedLook *look;
3239 
3240  for (look = global_looks.first; look; look = look->next) {
3241  if (STREQ(look->name, name)) {
3242  return look;
3243  }
3244  }
3245 
3246  return NULL;
3247 }
3248 
3250 {
3251  /* look indices are 1-based */
3252  return BLI_findlink(&global_looks, index - 1);
3253 }
3254 
3256 {
3257  ColorManagedLook *look;
3258 
3259  look = colormanage_look_get_named(name);
3260 
3261  if (look) {
3262  return look->index;
3263  }
3264 
3265  return 0;
3266 }
3267 
3269 {
3270  ColorManagedLook *look;
3271 
3272  look = colormanage_look_get_indexed(index);
3273 
3274  if (look) {
3275  return look->name;
3276  }
3277 
3278  return NULL;
3279 }
3280 
3283 /* -------------------------------------------------------------------- */
3288 {
3289  ColorManagedDisplay *display;
3290 
3291  for (display = global_displays.first; display; display = display->next) {
3292  EnumPropertyItem item;
3293 
3294  item.value = display->index;
3295  item.name = display->name;
3296  item.identifier = display->name;
3297  item.icon = 0;
3298  item.description = "";
3299 
3300  RNA_enum_item_add(items, totitem, &item);
3301  }
3302 }
3303 
3305  int *totitem,
3307 {
3308  EnumPropertyItem item;
3309 
3310  item.value = view->index;
3311  item.name = view->name;
3312  item.identifier = view->name;
3313  item.icon = 0;
3314  item.description = "";
3315 
3316  RNA_enum_item_add(items, totitem, &item);
3317 }
3318 
3320  int *totitem,
3321  const char *display_name)
3322 {
3323  ColorManagedDisplay *display = colormanage_display_get_named(display_name);
3325 
3326  if (display) {
3327  LinkData *display_view;
3328 
3329  for (display_view = display->views.first; display_view; display_view = display_view->next) {
3330  view = display_view->data;
3331 
3332  colormanagement_view_item_add(items, totitem, view);
3333  }
3334  }
3335 }
3336 
3338  int *totitem,
3339  const char *view_name)
3340 {
3341  ColorManagedLook *look;
3342 
3343  for (look = global_looks.first; look; look = look->next) {
3344  if (!colormanage_compatible_look(look, view_name)) {
3345  continue;
3346  }
3347 
3348  EnumPropertyItem item;
3349 
3350  item.value = look->index;
3351  item.name = look->ui_name;
3352  item.identifier = look->name;
3353  item.icon = 0;
3354  item.description = "";
3355 
3356  RNA_enum_item_add(items, totitem, &item);
3357  }
3358 }
3359 
3361 {
3362  ColorSpace *colorspace;
3363 
3364  for (colorspace = global_colorspaces.first; colorspace; colorspace = colorspace->next) {
3365  EnumPropertyItem item;
3366 
3367  if (!colorspace->is_invertible) {
3368  continue;
3369  }
3370 
3371  item.value = colorspace->index;
3372  item.name = colorspace->name;
3373  item.identifier = colorspace->name;
3374  item.icon = 0;
3375  item.description = colorspace->description;
3376 
3377  RNA_enum_item_add(items, totitem, &item);
3378  }
3379 }
3380 
3383 /* -------------------------------------------------------------------- */
3387 /*
3388  * Partial display update is supposed to be used by such areas as
3389  * compositor and renderer, This areas are calculating tiles of the
3390  * images and because of performance reasons only this tiles should
3391  * be color managed.
3392  * This gives nice visual feedback without slowing things down.
3393  *
3394  * Updating happens for active display transformation only, all
3395  * the rest buffers would be marked as dirty
3396  */
3397 
3399  unsigned char *display_buffer,
3400  const float *linear_buffer,
3401  const unsigned char *byte_buffer,
3402  int display_stride,
3403  int linear_stride,
3404  int linear_offset_x,
3405  int linear_offset_y,
3406  ColormanageProcessor *cm_processor,
3407  const int xmin,
3408  const int ymin,
3409  const int xmax,
3410  const int ymax)
3411 {
3412  int x, y;
3413  int channels = ibuf->channels;
3414  float dither = ibuf->dither;
3415  ColorSpace *rect_colorspace = ibuf->rect_colorspace;
3416  float *display_buffer_float = NULL;
3417  const int width = xmax - xmin;
3418  const int height = ymax - ymin;
3419  bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
3420 
3421  if (dither != 0.0f) {
3422  /* cm_processor is NULL in cases byte_buffer's space matches display
3423  * buffer's space
3424  * in this case we could skip extra transform and only apply dither
3425  * use 4 channels for easier byte->float->byte conversion here so
3426  * (this is only needed to apply dither, in other cases we'll convert
3427  * byte buffer to display directly)
3428  */
3429  if (!cm_processor) {
3430  channels = 4;
3431  }
3432 
3433  display_buffer_float = MEM_callocN((size_t)channels * width * height * sizeof(float),
3434  "display buffer for dither");
3435  }
3436 
3437  if (cm_processor) {
3438  for (y = ymin; y < ymax; y++) {
3439  for (x = xmin; x < xmax; x++) {
3440  size_t display_index = ((size_t)y * display_stride + x) * 4;
3441  size_t linear_index = ((size_t)(y - linear_offset_y) * linear_stride +
3442  (x - linear_offset_x)) *
3443  channels;
3444  float pixel[4];
3445 
3446  if (linear_buffer) {
3447  if (channels == 4) {
3448  copy_v4_v4(pixel, (float *)linear_buffer + linear_index);
3449  }
3450  else if (channels == 3) {
3451  copy_v3_v3(pixel, (float *)linear_buffer + linear_index);
3452  pixel[3] = 1.0f;
3453  }
3454  else if (channels == 1) {
3455  pixel[0] = linear_buffer[linear_index];
3456  }
3457  else {
3458  BLI_assert_msg(0, "Unsupported number of channels in partial buffer update");
3459  }
3460  }
3461  else if (byte_buffer) {
3462  rgba_uchar_to_float(pixel, byte_buffer + linear_index);
3463  IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, rect_colorspace);
3464  straight_to_premul_v4(pixel);
3465  }
3466 
3467  if (!is_data) {
3469  }
3470 
3471  if (display_buffer_float) {
3472  size_t index = ((size_t)(y - ymin) * width + (x - xmin)) * channels;
3473 
3474  if (channels == 4) {
3475  copy_v4_v4(display_buffer_float + index, pixel);
3476  }
3477  else if (channels == 3) {
3478  copy_v3_v3(display_buffer_float + index, pixel);
3479  }
3480  else /* if (channels == 1) */ {
3481  display_buffer_float[index] = pixel[0];
3482  }
3483  }
3484  else {
3485  if (channels == 4) {
3486  float pixel_straight[4];
3487  premul_to_straight_v4_v4(pixel_straight, pixel);
3488  rgba_float_to_uchar(display_buffer + display_index, pixel_straight);
3489  }
3490  else if (channels == 3) {
3491  rgb_float_to_uchar(display_buffer + display_index, pixel);
3492  display_buffer[display_index + 3] = 255;
3493  }
3494  else /* if (channels == 1) */ {
3495  display_buffer[display_index] = display_buffer[display_index + 1] =
3496  display_buffer[display_index + 2] = display_buffer[display_index + 3] =
3497  unit_float_to_uchar_clamp(pixel[0]);
3498  }
3499  }
3500  }
3501  }
3502  }
3503  else {
3504  if (display_buffer_float) {
3505  /* huh, for dither we need float buffer first, no cheaper way. currently */
3506  IMB_buffer_float_from_byte(display_buffer_float,
3507  byte_buffer,
3510  true,
3511  width,
3512  height,
3513  width,
3514  display_stride);
3515  }
3516  else {
3517  int i;
3518 
3519  for (i = ymin; i < ymax; i++) {
3520  size_t byte_offset = ((size_t)linear_stride * i + xmin) * 4;
3521  size_t display_offset = ((size_t)display_stride * i + xmin) * 4;
3522 
3523  memcpy(
3524  display_buffer + display_offset, byte_buffer + byte_offset, sizeof(char[4]) * width);
3525  }
3526  }
3527  }
3528 
3529  if (display_buffer_float) {
3530  size_t display_index = ((size_t)ymin * display_stride + xmin) * channels;
3531 
3532  IMB_buffer_byte_from_float(display_buffer + display_index,
3533  display_buffer_float,
3534  channels,
3535  dither,
3538  true,
3539  width,
3540  height,
3541  display_stride,
3542  width);
3543 
3544  MEM_freeN(display_buffer_float);
3545  }
3546 }
3547 
3548 typedef struct PartialThreadData {
3550  unsigned char *display_buffer;
3551  const float *linear_buffer;
3552  const unsigned char *byte_buffer;
3557  int xmin, ymin, xmax;
3559 
3560 static void partial_buffer_update_rect_thread_do(void *data_v, int scanline)
3561 {
3563  int ymin = data->ymin + scanline;
3564  const int num_scanlines = 1;
3566  data->display_buffer,
3567  data->linear_buffer,
3568  data->byte_buffer,
3569  data->display_stride,
3570  data->linear_stride,
3571  data->linear_offset_x,
3572  data->linear_offset_y,
3573  data->cm_processor,
3574  data->xmin,
3575  ymin,
3576  data->xmax,
3577  ymin + num_scanlines);
3578 }
3579 
3581  ImBuf *ibuf,
3582  const float *linear_buffer,
3583  const unsigned char *byte_buffer,
3584  int stride,
3585  int offset_x,
3586  int offset_y,
3587  const ColorManagedViewSettings *view_settings,
3588  const ColorManagedDisplaySettings *display_settings,
3589  int xmin,
3590  int ymin,
3591  int xmax,
3592  int ymax,
3593  bool do_threads)
3594 {
3595  ColormanageCacheViewSettings cache_view_settings;
3596  ColormanageCacheDisplaySettings cache_display_settings;
3597  void *cache_handle = NULL;
3598  unsigned char *display_buffer = NULL;
3599  int buffer_width = ibuf->x;
3600 
3601  if (ibuf->display_buffer_flags) {
3602  int view_flag, display_index;
3603 
3604  colormanage_view_settings_to_cache(ibuf, &cache_view_settings, view_settings);
3605  colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
3606 
3607  view_flag = 1 << (cache_view_settings.view - 1);
3608  display_index = cache_display_settings.display - 1;
3609 
3611 
3612  if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0) {
3613  display_buffer = colormanage_cache_get(
3614  ibuf, &cache_view_settings, &cache_display_settings, &cache_handle);
3615  }
3616 
3617  /* In some rare cases buffer's dimension could be changing directly from
3618  * different thread
3619  * this i.e. happens when image editor acquires render result
3620  */
3621  buffer_width = ibuf->x;
3622 
3623  /* Mark all other buffers as invalid. */
3624  memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(unsigned int));
3625  ibuf->display_buffer_flags[display_index] |= view_flag;
3626 
3628  }
3629 
3630  if (display_buffer) {
3631  ColormanageProcessor *cm_processor = NULL;
3632  bool skip_transform = false;
3633 
3634  /* Byte buffer is assumed to be in imbuf's rect space, so if byte buffer
3635  * is known we could skip display->linear->display conversion in case
3636  * display color space matches imbuf's rect space.
3637  *
3638  * But if there's a float buffer it's likely operation was performed on
3639  * it first and byte buffer is likely to be out of date here.
3640  */
3641  if (linear_buffer == NULL && byte_buffer != NULL) {
3642  skip_transform = is_ibuf_rect_in_display_space(ibuf, view_settings, display_settings);
3643  }
3644 
3645  if (!skip_transform) {
3646  cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
3647  }
3648 
3649  if (do_threads) {
3651  data.ibuf = ibuf;
3652  data.display_buffer = display_buffer;
3653  data.linear_buffer = linear_buffer;
3654  data.byte_buffer = byte_buffer;
3655  data.display_stride = buffer_width;
3656  data.linear_stride = stride;
3657  data.linear_offset_x = offset_x;
3658  data.linear_offset_y = offset_y;
3659  data.cm_processor = cm_processor;
3660  data.xmin = xmin;
3661  data.ymin = ymin;
3662  data.xmax = xmax;
3665  }
3666  else {
3668  display_buffer,
3669  linear_buffer,
3670  byte_buffer,
3671  buffer_width,
3672  stride,
3673  offset_x,
3674  offset_y,
3675  cm_processor,
3676  xmin,
3677  ymin,
3678  xmax,
3679  ymax);
3680  }
3681 
3682  if (cm_processor) {
3683  IMB_colormanagement_processor_free(cm_processor);
3684  }
3685 
3686  IMB_display_buffer_release(cache_handle);
3687  }
3688 }
3689 
3691  const float *linear_buffer,
3692  const unsigned char *byte_buffer,
3693  int stride,
3694  int offset_x,
3695  int offset_y,
3696  const ColorManagedViewSettings *view_settings,
3697  const ColorManagedDisplaySettings *display_settings,
3698  int xmin,
3699  int ymin,
3700  int xmax,
3701  int ymax)
3702 {
3704  linear_buffer,
3705  byte_buffer,
3706  stride,
3707  offset_x,
3708  offset_y,
3709  view_settings,
3710  display_settings,
3711  xmin,
3712  ymin,
3713  xmax,
3714  ymax,
3715  false);
3716 }
3717 
3719  struct ImBuf *ibuf,
3720  const float *linear_buffer,
3721  const unsigned char *byte_buffer,
3722  int stride,
3723  int offset_x,
3724  int offset_y,
3725  const struct ColorManagedViewSettings *view_settings,
3726  const struct ColorManagedDisplaySettings *display_settings,
3727  int xmin,
3728  int ymin,
3729  int xmax,
3730  int ymax)
3731 {
3732  int width = xmax - xmin;
3733  int height = ymax - ymin;
3734  bool do_threads = (((size_t)width) * height >= 64 * 64);
3736  linear_buffer,
3737  byte_buffer,
3738  stride,
3739  offset_x,
3740  offset_y,
3741  view_settings,
3742  display_settings,
3743  xmin,
3744  ymin,
3745  xmax,
3746  ymax,
3747  do_threads);
3748 }
3749 
3750 void IMB_partial_display_buffer_update_delayed(ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax)
3751 {
3752  if (ibuf->invalid_rect.xmin == ibuf->invalid_rect.xmax) {
3753  BLI_rcti_init(&ibuf->invalid_rect, xmin, xmax, ymin, ymax);
3754  }
3755  else {
3756  rcti rect;
3757  BLI_rcti_init(&rect, xmin, xmax, ymin, ymax);
3758  BLI_rcti_union(&ibuf->invalid_rect, &rect);
3759  }
3760 }
3761 
3764 /* -------------------------------------------------------------------- */
3769  const ColorManagedViewSettings *view_settings,
3770  const ColorManagedDisplaySettings *display_settings)
3771 {
3772  ColormanageProcessor *cm_processor;
3773  ColorManagedViewSettings default_view_settings;
3774  const ColorManagedViewSettings *applied_view_settings;
3775  ColorSpace *display_space;
3776 
3777  cm_processor = MEM_callocN(sizeof(ColormanageProcessor), "colormanagement processor");
3778 
3779  if (view_settings) {
3780  applied_view_settings = view_settings;
3781  }
3782  else {
3783  IMB_colormanagement_init_default_view_settings(&default_view_settings, display_settings);
3784  applied_view_settings = &default_view_settings;
3785  }
3786 
3787  display_space = display_transform_get_colorspace(applied_view_settings, display_settings);
3788  if (display_space) {
3789  cm_processor->is_data_result = display_space->is_data;
3790  }
3791 
3793  applied_view_settings->look,
3794  applied_view_settings->view_transform,
3795  display_settings->display_device,
3796  applied_view_settings->exposure,
3797  applied_view_settings->gamma,
3799 
3800  if (applied_view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
3801  cm_processor->curve_mapping = BKE_curvemapping_copy(applied_view_settings->curve_mapping);
3802  BKE_curvemapping_premultiply(cm_processor->curve_mapping, false);
3803  }
3804 
3805  return cm_processor;
3806 }
3807 
3809  const char *to_colorspace)
3810 {
3811  ColormanageProcessor *cm_processor;
3812  ColorSpace *color_space;
3813 
3814  cm_processor = MEM_callocN(sizeof(ColormanageProcessor), "colormanagement processor");
3815 
3816  color_space = colormanage_colorspace_get_named(to_colorspace);
3817  cm_processor->is_data_result = color_space->is_data;
3818 
3819  OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(from_colorspace,
3820  to_colorspace);
3821  if (processor != NULL) {
3822  cm_processor->cpu_processor = OCIO_processorGetCPUProcessor(processor);
3823  }
3824  OCIO_processorRelease(processor);
3825 
3826  return cm_processor;
3827 }
3828 
3830 {
3831  if (cm_processor->curve_mapping) {
3832  BKE_curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
3833  }
3834 
3835  if (cm_processor->cpu_processor) {
3836  OCIO_cpuProcessorApplyRGBA(cm_processor->cpu_processor, pixel);
3837  }
3838 }
3839 
3841  float pixel[4])
3842 {
3843  if (cm_processor->curve_mapping) {
3844  BKE_curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
3845  }
3846 
3847  if (cm_processor->cpu_processor) {
3849  }
3850 }
3851 
3853 {
3854  if (cm_processor->curve_mapping) {
3855  BKE_curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
3856  }
3857 
3858  if (cm_processor->cpu_processor) {
3859  OCIO_cpuProcessorApplyRGB(cm_processor->cpu_processor, pixel);
3860  }
3861 }
3862 
3864  float *pixel,
3865  int channels)
3866 {
3867  if (channels == 4) {
3869  }
3870  else if (channels == 3) {
3871  IMB_colormanagement_processor_apply_v3(cm_processor, pixel);
3872  }
3873  else if (channels == 1) {
3874  if (cm_processor->curve_mapping) {
3875  curve_mapping_apply_pixel(cm_processor->curve_mapping, pixel, 1);
3876  }
3877  }
3878  else {
3879  BLI_assert(
3880  !"Incorrect number of channels passed to IMB_colormanagement_processor_apply_pixel");
3881  }
3882 }
3883 
3885  float *buffer,
3886  int width,
3887  int height,
3888  int channels,
3889  bool predivide)
3890 {
3891  /* apply curve mapping */
3892  if (cm_processor->curve_mapping) {
3893  int x, y;
3894 
3895  for (y = 0; y < height; y++) {
3896  for (x = 0; x < width; x++) {
3897  float *pixel = buffer + channels * (((size_t)y) * width + x);
3898 
3899  curve_mapping_apply_pixel(cm_processor->curve_mapping, pixel, channels);
3900  }
3901  }
3902  }
3903 
3904  if (cm_processor->cpu_processor && channels >= 3) {
3905  OCIO_PackedImageDesc *img;
3906 
3907  /* apply OCIO processor */
3909  width,
3910  height,
3911  channels,
3912  sizeof(float),
3913  (size_t)channels * sizeof(float),
3914  (size_t)channels * sizeof(float) * width);
3915 
3916  if (predivide) {
3917  OCIO_cpuProcessorApply_predivide(cm_processor->cpu_processor, img);
3918  }
3919  else {
3920  OCIO_cpuProcessorApply(cm_processor->cpu_processor, img);
3921  }
3922 
3924  }
3925 }
3926 
3928  ColormanageProcessor *cm_processor, unsigned char *buffer, int width, int height, int channels)
3929 {
3930  /* TODO(sergey): Would be nice to support arbitrary channels configurations,
3931  * but for now it's not so important.
3932  */
3933  BLI_assert(channels == 4);
3934  float pixel[4];
3935  for (int y = 0; y < height; y++) {
3936  for (int x = 0; x < width; x++) {
3937  size_t offset = channels * (((size_t)y) * width + x);
3938  rgba_uchar_to_float(pixel, buffer + offset);
3939  IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
3940  rgba_float_to_uchar(buffer + offset, pixel);
3941  }
3942  }
3943 }
3944 
3946 {
3947  if (cm_processor->curve_mapping) {
3948  BKE_curvemapping_free(cm_processor->curve_mapping);
3949  }
3950  if (cm_processor->cpu_processor) {
3951  OCIO_cpuProcessorRelease(cm_processor->cpu_processor);
3952  }
3953 
3954  MEM_freeN(cm_processor);
3955 }
3956 
3957 /* **** OpenGL drawing routines using GLSL for color space transform ***** */
3958 
3960  OCIO_CurveMappingSettings *curve_mapping_settings)
3961 {
3962  int i;
3963 
3964  BKE_curvemapping_init(curve_mapping);
3965  BKE_curvemapping_premultiply(curve_mapping, false);
3967  curve_mapping, &curve_mapping_settings->lut, &curve_mapping_settings->lut_size);
3968 
3969  curve_mapping_settings->use_extend_extrapolate = (curve_mapping->flag &
3971 
3972  for (i = 0; i < 4; i++) {
3973  CurveMap *cuma = curve_mapping->cm + i;
3974  curve_mapping_settings->range[i] = cuma->range;
3975  curve_mapping_settings->mintable[i] = cuma->mintable;
3976  curve_mapping_settings->ext_in_x[i] = cuma->ext_in[0];
3977  curve_mapping_settings->ext_in_y[i] = cuma->ext_in[1];
3978  curve_mapping_settings->ext_out_x[i] = cuma->ext_out[0];
3979  curve_mapping_settings->ext_out_y[i] = cuma->ext_out[1];
3980  curve_mapping_settings->first_x[i] = cuma->table[0].x;
3981  curve_mapping_settings->first_y[i] = cuma->table[0].y;
3982  curve_mapping_settings->last_x[i] = cuma->table[CM_TABLE].x;
3983  curve_mapping_settings->last_y[i] = cuma->table[CM_TABLE].y;
3984  }
3985 
3986  copy_v3_v3(curve_mapping_settings->black, curve_mapping->black);
3987  copy_v3_v3(curve_mapping_settings->bwmul, curve_mapping->bwmul);
3988 
3989  curve_mapping_settings->cache_id = (size_t)curve_mapping + curve_mapping->changed_timestamp;
3990 }
3991 
3993  const ColorManagedViewSettings *view_settings)
3994 {
3995  /* Using curve mapping? */
3996  const bool use_curve_mapping = (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) != 0;
3997  if (!use_curve_mapping) {
3998  return NULL;
3999  }
4000 
4001  /* Already up to date? */
4003  if (view_settings->curve_mapping->changed_timestamp ==
4006  return curve_mapping_settings;
4007  }
4008 
4009  /* Need to update. */
4010  CurveMapping *new_curve_mapping = NULL;
4011 
4012  /* We're using curve mapping's address as a cache ID,
4013  * so we need to make sure re-allocation gives new address here.
4014  * We do this by allocating new curve mapping before freeing old one. */
4015  if (use_curve_mapping) {
4016  new_curve_mapping = BKE_curvemapping_copy(view_settings->curve_mapping);
4017  }
4018 
4021  MEM_freeN(curve_mapping_settings->lut);
4023  curve_mapping_settings->lut = NULL;
4024  }
4025 
4026  /* Fill in OCIO's curve mapping settings. */
4027  if (use_curve_mapping) {
4029 
4030  global_gpu_state.curve_mapping = new_curve_mapping;
4034  }
4035  else {
4038  }
4039 
4040  return curve_mapping_settings;
4041 }
4042 
4044 {
4045  return OCIO_supportGPUShader();
4046 }
4047 
4049  const ColorManagedViewSettings *view_settings,
4050  const ColorManagedDisplaySettings *display_settings,
4051  struct ColorSpace *from_colorspace,
4052  float dither,
4053  bool predivide,
4054  bool do_overlay_merge)
4055 {
4056  ColorManagedViewSettings default_view_settings;
4057  const ColorManagedViewSettings *applied_view_settings;
4058 
4059  if (view_settings) {
4060  applied_view_settings = view_settings;
4061  }
4062  else {
4063  /* If no view settings were specified, use default ones, which will
4064  * attempt not to do any extra color correction. */
4065  IMB_colormanagement_init_default_view_settings(&default_view_settings, display_settings);
4066  applied_view_settings = &default_view_settings;
4067  }
4068 
4069  /* Ensure curve mapping is up to data. */
4070  OCIO_CurveMappingSettings *curve_mapping_settings = update_glsl_curve_mapping(
4071  applied_view_settings);
4072 
4073  /* GPU shader parameters. */
4074  const char *input = from_colorspace ? from_colorspace->name : global_role_scene_linear;
4075  const char *view = applied_view_settings->view_transform;
4076  const char *display = display_settings->display_device;
4077  const bool use_look = colormanage_use_look(applied_view_settings->look,
4078  applied_view_settings->view_transform);
4079  const char *look = (use_look) ? applied_view_settings->look : "";
4080  const float exposure = applied_view_settings->exposure;
4081  const float gamma = applied_view_settings->gamma;
4082  const float scale = (exposure == 0.0f) ? 1.0f : powf(2.0f, exposure);
4083  const float exponent = (gamma == 1.0f) ? 1.0f : 1.0f / max_ff(FLT_EPSILON, gamma);
4084 
4085  OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
4086 
4087  /* Bind shader. Internally GPU shaders are created and cached on demand. */
4089  input,
4090  view,
4091  display,
4092  look,
4093  curve_mapping_settings,
4094  scale,
4095  exponent,
4096  dither,
4097  predivide,
4098  do_overlay_merge);
4099 
4100  OCIO_configRelease(config);
4101 
4103 }
4104 
4106  const ColorManagedDisplaySettings *display_settings,
4107  float dither,
4108  bool predivide)
4109 {
4111  view_settings, display_settings, NULL, dither, predivide, false);
4112 }
4113 
4115  struct ColorSpace *from_colorspace,
4116  float dither,
4117  bool predivide)
4118 {
4119  ColorManagedViewSettings *view_settings;
4120  ColorManagedDisplaySettings *display_settings;
4121 
4122  IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
4123 
4125  view_settings, display_settings, from_colorspace, dither, predivide, false);
4126 }
4127 
4128 bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bool predivide)
4129 {
4130  return IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, NULL, dither, predivide);
4131 }
4132 
4134 {
4138  }
4139 }
4140 
4143 /* -------------------------------------------------------------------- */
4147 /* Calculate color in range 800..12000 using an approximation
4148  * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
4149  *
4150  * The result of this can be negative to support gamut wider than
4151  * than rec.709, just needs to be clamped. */
4152 
4153 static const float blackbody_table_r[7][3] = {{1.61919106e+03f, -2.05010916e-03f, 5.02995757e+00f},
4154  {2.48845471e+03f, -1.11330907e-03f, 3.22621544e+00f},
4155  {3.34143193e+03f, -4.86551192e-04f, 1.76486769e+00f},
4156  {4.09461742e+03f, -1.27446582e-04f, 7.25731635e-01f},
4157  {4.67028036e+03f, 2.91258199e-05f, 1.26703442e-01f},
4158  {4.59509185e+03f, 2.87495649e-05f, 1.50345020e-01f},
4159  {3.78717450e+03f, 9.35907826e-06f, 3.99075871e-01f}};
4160 
4161 static const float blackbody_table_g[7][3] = {
4162  {-4.88999748e+02f, 6.04330754e-04f, -7.55807526e-02f},
4163  {-7.55994277e+02f, 3.16730098e-04f, 4.78306139e-01f},
4164  {-1.02363977e+03f, 1.20223470e-04f, 9.36662319e-01f},
4165  {-1.26571316e+03f, 4.87340896e-06f, 1.27054498e+00f},
4166  {-1.42529332e+03f, -4.01150431e-05f, 1.43972784e+00f},
4167  {-1.17554822e+03f, -2.16378048e-05f, 1.30408023e+00f},
4168  {-5.00799571e+02f, -4.59832026e-06f, 1.09098763e+00f}};
4169 
4170 static const float blackbody_table_b[7][4] = {
4171  {5.96945309e-11f, -4.85742887e-08f, -9.70622247e-05f, -4.07936148e-03f},
4172  {2.40430366e-11f, 5.55021075e-08f, -1.98503712e-04f, 2.89312858e-02f},
4173  {-1.40949732e-11f, 1.89878968e-07f, -3.56632824e-04f, 9.10767778e-02f},
4174  {-3.61460868e-11f, 2.84822009e-07f, -4.93211319e-04f, 1.56723440e-01f},
4175  {-1.97075738e-11f, 1.75359352e-07f, -2.50542825e-04f, -2.22783266e-02f},
4176  {-1.61997957e-13f, -1.64216008e-08f, 3.86216271e-04f, -7.38077418e-01f},
4177  {6.72650283e-13f, -2.73078809e-08f, 4.24098264e-04f, -7.52335691e-01f}};
4178 
4179 static void blackbody_temperature_to_rec709(float rec709[3], float t)
4180 {
4181  if (t >= 12000.0f) {
4182  rec709[0] = 0.8262954810464208f;
4183  rec709[1] = 0.9945080501520986f;
4184  rec709[2] = 1.566307710274283f;
4185  }
4186  else if (t < 800.0f) {
4187  rec709[0] = 5.413294490189271f;
4188  rec709[1] = -0.20319390035873933f;
4189  rec709[2] = -0.0822535242887164f;
4190  }
4191  else {
4192  int i = (t >= 6365.0f) ? 6 :
4193  (t >= 3315.0f) ? 5 :
4194  (t >= 1902.0f) ? 4 :
4195  (t >= 1449.0f) ? 3 :
4196  (t >= 1167.0f) ? 2 :
4197  (t >= 965.0f) ? 1 :
4198  0;
4199 
4200  const float *r = blackbody_table_r[i];
4201  const float *g = blackbody_table_g[i];
4202  const float *b = blackbody_table_b[i];
4203 
4204  const float t_inv = 1.0f / t;
4205  rec709[0] = r[0] * t_inv + r[1] * t + r[2];
4206  rec709[1] = g[0] * t_inv + g[1] * t + g[2];
4207  rec709[2] = ((b[0] * t + b[1]) * t + b[2]) * t + b[3];
4208  }
4209 }
4210 
4212  const int width,
4213  const float min,
4214  const float max)
4215 {
4216  for (int i = 0; i < width; i++) {
4217  float temperature = min + (max - min) / (float)width * (float)i;
4218 
4219  float rec709[3];
4220  blackbody_temperature_to_rec709(rec709, temperature);
4221 
4222  float rgb[3];
4224  clamp_v3(rgb, 0.0f, FLT_MAX);
4225 
4226  copy_v3_v3(&r_table[i * 4], rgb);
4227  r_table[i * 4 + 3] = 0.0f;
4228  }
4229 }
4230 
4243 static float cie_colour_match[81][3] = {
4244  {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
4245  {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
4246  {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
4247  {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
4248  {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
4249  {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
4250  {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
4251  {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
4252  {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
4253  {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
4254  {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
4255  {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
4256  {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
4257  {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
4258  {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
4259  {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
4260  {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
4261  {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
4262  {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
4263  {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
4264  {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
4265  {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
4266  {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
4267  {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
4268  {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
4269  {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
4270  {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}};
4271 
4272 static void wavelength_to_xyz(float xyz[3], float lambda_nm)
4273 {
4274  float ii = (lambda_nm - 380.0f) * (1.0f / 5.0f); /* Scaled 0..80. */
4275  int i = (int)ii;
4276 
4277  if (i < 0 || i >= 80) {
4278  xyz[0] = 0.0f;
4279  xyz[1] = 0.0f;
4280  xyz[2] = 0.0f;
4281  }
4282  else {
4283  ii -= (float)i;
4284  const float *c = cie_colour_match[i];
4285  xyz[0] = c[0] + ii * (c[3] - c[0]);
4286  xyz[1] = c[1] + ii * (c[4] - c[1]);
4287  xyz[2] = c[2] + ii * (c[5] - c[2]);
4288  }
4289 }
4290 
4292 {
4293  for (int i = 0; i < width; i++) {
4294  float temperature = 380 + 400 / (float)width * (float)i;
4295 
4296  float xyz[3];
4297  wavelength_to_xyz(xyz, temperature);
4298 
4299  float rgb[3];
4301  clamp_v3(rgb, 0.0f, FLT_MAX);
4302 
4303  copy_v3_v3(&r_table[i * 4], rgb);
4304  r_table[i * 4 + 3] = 0.0f;
4305  }
4306 }
4307 
typedef float(TangentPoint)[2]
const char * BKE_appdir_folder_id(int folder_id, const char *subfolder)
Definition: appdir.c:672
@ BLENDER_DATAFILES
Definition: BKE_appdir.h:154
void BKE_curvemapping_evaluate_premulRGBF(const struct CurveMapping *cumap, float vecout[3], const float vecin[3])
void BKE_curvemapping_premultiply(struct CurveMapping *cumap, bool restore)
Definition: colortools.c:782
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1235
struct CurveMapping * BKE_curvemapping_copy(const struct CurveMapping *cumap)
float BKE_curvemap_evaluateF(const struct CurveMapping *cumap, const struct CurveMap *cuma, float value)
void BKE_curvemapping_table_RGBA(const struct CurveMapping *cumap, float **array, int *size)
void BKE_curvemapping_free(struct CurveMapping *cumap)
Definition: colortools.c:103
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:824
bool BKE_imtype_requires_linear_float(char imtype)
bool BKE_image_format_is_byte(const struct ImageFormatData *imf)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
struct LinkData * BLI_genericNodeN(void *data)
Definition: listbase.c:842
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:340
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
MINLINE void straight_to_premul_v4(float color[4])
void BLI_init_srgb_conversion(void)
Definition: math_color.c:567
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
Definition: math_color.c:383
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
Definition: math_color.c:396
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4])
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
Definition: math_color.c:376
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
Definition: math_color.c:391
bool invert_m3_m3(float R[3][3], const float A[3][3])
Definition: math_matrix.c:1180
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
Definition: math_matrix.c:388
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void clamp_v3(float vec[3], float min, float max)
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define FILE_MAX
const char * BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
Definition: path_util.c:1168
void BLI_join_dirfile(char *__restrict dst, size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1531
void BLI_rcti_union(struct rcti *rct_a, const struct rcti *rct_b)
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition: rct.c:417
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:623
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
void BLI_thread_unlock(int type)
Definition: threads.cc:361
@ LOCK_COLORMANAGE
Definition: BLI_threads.h:72
void BLI_thread_lock(int type)
Definition: threads.cc:356
#define BLI_MUTEX_INITIALIZER
Definition: BLI_threads.h:83
void BLI_mutex_lock(ThreadMutex *mutex)
Definition: threads.cc:373
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition: threads.cc:378
#define UNUSED(x)
#define ELEM(...)
#define STRCASEEQ(a, b)
#define STREQ(a, b)
@ CUMA_EXTEND_EXTRAPOLATE
#define CM_TABLE
@ COLORMANAGE_VIEW_USE_CURVES
@ IMA_VIEW_AS_RENDER
#define R_IMF_PLANES_RGBA
static AppView * view
_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 height
_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 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 width
_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 stride
_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 t
@ COLOR_ROLE_DEFAULT_FLOAT
@ COLOR_ROLE_DATA
@ COLOR_ROLE_DEFAULT_BYTE
@ COLOR_ROLE_SCENE_LINEAR
@ COLOR_ROLE_COLOR_PICKING
@ COLOR_ROLE_DEFAULT_SEQUENCER
@ COLOR_ROLE_TEXTURE_PAINTING
BLI_INLINE void IMB_colormanagement_xyz_to_scene_linear(float scene_linear[3], const float xyz[3])
#define BCM_CONFIG_FILE
BLI_INLINE void IMB_colormanagement_rec709_to_scene_linear(float scene_linear[3], const float rec709[3])
#define MAX_COLORSPACE_NAME
Function declarations for filter.c.
void IMB_float_from_rect(struct ImBuf *ibuf)
Definition: divers.c:805
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:500
struct ImBuf * IMB_dupImBuf(const struct ImBuf *ibuf1)
void IMB_rect_from_float(struct ImBuf *ibuf)
Definition: divers.c:696
void imb_freerectImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:97
void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_customdata, void(init_handle)(void *handle, int start_line, int tot_line, void *customdata), void *(do_thread)(void *))
Definition: imageprocess.c:355
void IMB_buffer_byte_from_byte(unsigned char *rect_to, const unsigned char *rect_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
Definition: divers.c:627
void IMB_buffer_float_from_byte(float *rect_to, const unsigned char *rect_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
Definition: divers.c:350
void IMB_processor_apply_threaded_scanlines(int total_scanlines, ScanlineThreadFunc do_thread, void *custom_data)
Definition: imageprocess.c:415
void IMB_buffer_byte_from_float(unsigned char *rect_to, const float *rect_from, int channels_from, float dither, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
Definition: divers.c:94
bool IMB_alpha_affects_rgb(const struct ImBuf *ibuf)
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3])
Definition: imageprocess.c:435
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float backcol[3])
Definition: imageprocess.c:449
bool imb_addrectImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:387
Contains defines and structs used throughout the imbuf module.
@ IMB_COLORMANAGE_IS_DATA
@ IB_RECT_INVALID
@ IB_DISPLAY_BUFFER_INVALID
#define IB_PROFILE_SRGB
@ IB_alphamode_channel_packed
@ IB_alphamode_premul
@ IB_alphamode_ignore
@ IB_rectfloat
@ IB_rect
void IMB_metadata_copy(struct ImBuf *dimb, struct ImBuf *simb)
Definition: metadata.c:64
struct MovieCache * IMB_moviecache_create(const char *name, int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp)
Definition: moviecache.cc:265
struct ImBuf * IMB_moviecache_get(struct MovieCache *cache, void *userkey, bool *r_is_cached_empty)
Definition: moviecache.cc:401
void IMB_moviecache_put(struct MovieCache *cache, void *userkey, struct ImBuf *ibuf)
Definition: moviecache.cc:367
void IMB_moviecache_free(struct MovieCache *cache)
Definition: moviecache.cc:444
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static void init_data(ModifierData *md)
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 a value between a minimum and a maximum Vector Perform vector math operation Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
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 a value between a minimum and a maximum Vector Perform vector math operation Invert a color
#define C
Definition: RandGen.cpp:25
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
const char * IMB_colormanagement_colorspace_get_indexed_name(int index)
static char global_role_data[MAX_COLORSPACE_NAME]
static void * do_processor_transform_thread(void *handle_v)
ColorManagedView * colormanage_view_get_default(const ColorManagedDisplay *display)
static float cie_colour_match[81][3]
static ListBase global_colorspaces
static void display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle, int height, float *linear_buffer, bool *is_straight_alpha)
void IMB_colormanagement_pixel_to_display_space_v3(float result[3], const float pixel[3], const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
unsigned char * IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, void **cache_handle)
static const float blackbody_table_r[7][3]
void IMB_colormanagement_display_to_scene_linear_v3(float pixel[3], ColorManagedDisplay *display)
float imbuf_scene_linear_to_aces[3][3]
static void blackbody_temperature_to_rec709(float rec709[3], float t)
void IMB_colormanagement_processor_apply_byte(ColormanageProcessor *cm_processor, unsigned char *buffer, int width, int height, int channels)
void IMB_partial_display_buffer_update_threaded(struct ImBuf *ibuf, const float *linear_buffer, const unsigned char *byte_buffer, int stride, int offset_x, int offset_y, const struct ColorManagedViewSettings *view_settings, const struct ColorManagedDisplaySettings *display_settings, int xmin, int ymin, int xmax, int ymax)
static void display_buffer_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
bool IMB_colormanagement_space_is_data(ColorSpace *colorspace)
void IMB_colormanagement_colorspace_items_add(EnumPropertyItem **items, int *totitem)
float imbuf_luma_coefficients[3]
static void curve_mapping_to_ocio_settings(CurveMapping *curve_mapping, OCIO_CurveMappingSettings *curve_mapping_settings)
void IMB_colormanagement_processor_apply_pixel(struct ColormanageProcessor *cm_processor, float *pixel, int channels)
void colormanagement_init(void)
ColormanageProcessor * IMB_colormanagement_colorspace_processor_new(const char *from_colorspace, const char *to_colorspace)
struct ColormanageCache ColormanageCache
void colormanage_cache_free(ImBuf *ibuf)
static void curve_mapping_apply_pixel(CurveMapping *curve_mapping, float *pixel, int channels)
void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, bool predivide)
ColorManagedView * colormanage_view_get_named_for_display(const char *display_name, const char *name)
void IMB_colormanagement_assign_float_colorspace(ImBuf *ibuf, const char *name)
const char * IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
static void colormanage_check_colorspace_settings(ColorManagedColorspaceSettings *colorspace_settings, const char *what)
bool IMB_colormanagement_space_is_srgb(ColorSpace *colorspace)
static OCIO_ConstProcessorRcPtr * create_colorspace_transform_processor(const char *from_colorspace, const char *to_colorspace)
void IMB_colormanagement_pixel_to_display_space_v4(float result[4], const float pixel[4], const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
const char * IMB_colormanagement_colorspace_get_name(const ColorSpace *colorspace)
static void colormanage_cachedata_set(ImBuf *ibuf, ColormanageCacheData *data)
static void colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, bool make_byte)
static void colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config, char *colorspace_name, const char *role, const char *backup_role)
bool IMB_colormanagement_space_is_scene_linear(ColorSpace *colorspace)
static OCIO_ConstCPUProcessorRcPtr * colorspace_to_scene_linear_cpu_processor(ColorSpace *colorspace)
float imbuf_rec709_to_scene_linear[3][3]
void IMB_colormanagement_color_picking_to_scene_linear_v3(float scene_linear[3], const float color_picking[3])
void IMB_colormanagement_view_items_add(EnumPropertyItem **items, int *totitem, const char *display_name)
static unsigned char * colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheViewSettings *view_settings, const ColormanageCacheDisplaySettings *display_settings, void **cache_handle)
static ColorSpace * display_transform_get_colorspace(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static char global_role_default_sequencer[MAX_COLORSPACE_NAME]
static void * do_display_buffer_apply_thread(void *handle_v)
void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name)
static void processor_transform_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
bool IMB_colormanagement_setup_glsl_draw(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, float dither, bool predivide)
static OCIO_ConstCPUProcessorRcPtr * colorspace_from_scene_linear_cpu_processor(ColorSpace *colorspace)
float imbuf_scene_linear_to_rec709[3][3]
bool IMB_colormanagement_space_name_is_srgb(const char *name)
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
void IMB_colormanagement_look_items_add(struct EnumPropertyItem **items, int *totitem, const char *view_name)
const char * IMB_colormanagement_view_get_default_name(const char *display_name)
ColorSpace * colormanage_colorspace_add(const char *name, const char *description, bool is_invertible, bool is_data)
bool IMB_colormanagement_space_name_is_scene_linear(const char *name)
static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffer, const float *linear_buffer, const unsigned char *byte_buffer, int display_stride, int linear_stride, int linear_offset_x, int linear_offset_y, ColormanageProcessor *cm_processor, const int xmin, const int ymin, const int xmax, const int ymax)
void IMB_colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
struct ProcessorTransformThread ProcessorTransformThread
void colormanagement_exit(void)
bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C, struct ColorSpace *from_colorspace, float dither, bool predivide)
static pthread_mutex_t processor_lock
static bool is_ibuf_rect_in_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static ColormanageCacheData * colormanage_cachedata_get(const ImBuf *ibuf)
static void imb_partial_display_buffer_update_ex(ImBuf *ibuf, const float *linear_buffer, const unsigned char *byte_buffer, int stride, int offset_x, int offset_y, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, int xmin, int ymin, int xmax, int ymax, bool do_threads)
struct PartialThreadData PartialThreadData
ColorManagedLook * colormanage_look_get_indexed(int index)
static struct MovieCache * colormanage_moviecache_get(const ImBuf *ibuf)
unsigned char * IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
int IMB_colormanagement_view_get_named_index(const char *name)
static void colormanage_check_display_settings(ColorManagedDisplaySettings *display_settings, const char *what, const ColorManagedDisplay *default_display)
const char * colormanage_view_get_default_name(const ColorManagedDisplay *display)
void IMB_colormanagement_check_file_config(Main *bmain)
struct DisplayBufferThread DisplayBufferThread
struct ColormanageProcessor ColormanageProcessor
void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, unsigned char *byte_buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
bool IMB_colormanagement_space_name_is_data(const char *name)
float imbuf_scene_linear_to_xyz[3][3]
static ImBuf * imbuf_ensure_editable(ImBuf *ibuf, ImBuf *colormanaged_ibuf, bool allocate_result)
static bool colormanage_hashcmp(const void *av, const void *bv)
void IMB_colormanagement_transform_from_byte(float *float_buffer, unsigned char *byte_buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
void IMB_colormanagement_init_default_view_settings(ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static bool colormanage_use_look(const char *look, const char *view_name)
void IMB_colormanagement_transform_threaded(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide)
void IMB_colormanagement_validate_settings(const ColorManagedDisplaySettings *display_settings, ColorManagedViewSettings *view_settings)
void IMB_colormanagement_wavelength_to_rgb_table(float *r_table, const int width)
static void colormanage_ensure_srgb_scene_linear_info(ColorSpace *colorspace)
void IMB_colormanagement_colorspace_from_ibuf_ftype(ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
void IMB_colormanagement_processor_apply_v3(ColormanageProcessor *cm_processor, float pixel[3])
static void colormanage_free_config(void)
static const float blackbody_table_g[7][3]
void IMB_colormanagegent_copy_settings(ImBuf *ibuf_src, ImBuf *ibuf_dst)
void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, float *buffer, int width, int height, int channels, bool predivide)
void IMB_colormanagement_transform_byte_threaded(unsigned char *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
static int global_tot_view
bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bool predivide)
bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *UNUSED(view_settings))
static ImBuf * colormanage_cache_get_ibuf(ImBuf *ibuf, ColormanageCacheKey *key, void **cache_handle)
void IMB_display_buffer_release(void *cache_handle)
ColorManagedLook * colormanage_look_add(const char *name, const char *process_space, bool is_noop)
static void processor_transform_apply_threaded(unsigned char *byte_buffer, float *float_buffer, const int width, const int height, const int channels, ColormanageProcessor *cm_processor, const bool predivide, const bool float_from_byte)
void IMB_colormanagement_display_settings_from_ctx(const bContext *C, ColorManagedViewSettings **r_view_settings, ColorManagedDisplaySettings **r_display_settings)
ColorManagedLook * colormanage_look_get_named(const char *name)
static void colormanage_display_buffer_process(ImBuf *ibuf, unsigned char *display_buffer, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpace *colorspace)
static void colormanage_cache_handle_release(void *cache_handle)
struct ColormanageCacheDisplaySettings ColormanageCacheDisplaySettings
static ListBase global_looks
float imbuf_xyz_to_scene_linear[3][3]
static ListBase global_views
static OCIO_ConstCPUProcessorRcPtr * create_display_buffer_processor(const char *look, const char *view_transform, const char *display, float exposure, float gamma, const char *from_colorspace)
#define DISPLAY_BUFFER_CHANNELS
void IMB_colormanagement_assign_rect_colorspace(ImBuf *ibuf, const char *name)
float imbuf_aces_to_scene_linear[3][3]
const char * IMB_colormanagement_display_get_default_name(void)
void colormanage_imbuf_set_default_spaces(ImBuf *ibuf)
static const float blackbody_table_b[7][4]
const float * IMB_colormanagement_get_xyz_to_scene_linear()
const char * IMB_colormanagement_display_get_none_name(void)
static void colormanage_description_strip(char *description)
const char * IMB_colormanagement_view_get_indexed_name(int index)
int IMB_colormanagement_look_get_named_index(const char *name)
const char * IMB_colormanagement_role_colorspace_name_get(int role)
ColorManagedDisplay * colormanage_display_get_named(const char *name)
static void colormanage_display_settings_to_cache(ColormanageCacheDisplaySettings *cache_display_settings, const ColorManagedDisplaySettings *display_settings)
ColorManagedDisplay * colormanage_display_get_indexed(int index)
void colorspace_set_default_role(char *colorspace, int size, int role)
static ListBase global_displays
static bool colormanage_compatible_look(ColorManagedLook *look, const char *view_name)
bool IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, struct ColorSpace *from_colorspace, float dither, bool predivide, bool do_overlay_merge)
static int global_tot_display
void IMB_colormanagement_transform_byte(unsigned char *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
ColorManagedDisplay * colormanage_display_get_default(void)
static void partial_buffer_update_rect_thread_do(void *data_v, int scanline)
ColorSpace * colormanage_colorspace_get_indexed(int index)
const char * colormanage_display_get_default_name(void)
void IMB_colormanagement_display_items_add(EnumPropertyItem **items, int *totitem)
struct ColormanageCacheData ColormanageCacheData
void IMB_colormanagement_blackbody_temperature_to_rgb_table(float *r_table, const int width, const float min, const float max)
void IMB_colormanagement_finish_glsl_draw(void)
void IMB_colormanagement_scene_linear_to_color_picking_v3(float color_picking[3], const float scene_linear[3])
static int global_tot_colorspace
static char global_role_scene_linear[MAX_COLORSPACE_NAME]
static void colormanagement_view_item_add(EnumPropertyItem **items, int *totitem, ColorManagedView *view)
int IMB_colormanagement_colorspace_get_named_index(const char *name)
static void colormanagement_transform_ex(unsigned char *byte_buffer, float *float_buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide, bool do_threaded)
static char global_role_texture_painting[MAX_COLORSPACE_NAME]
ColorSpace * colormanage_colorspace_get_named(const char *name)
void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, const unsigned char *byte_buffer, int stride, int offset_x, int offset_y, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, int xmin, int ymin, int xmax, int ymax)
static const char * get_display_colorspace_name(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static void colormanage_settings_to_key(ColormanageCacheKey *key, const ColormanageCacheViewSettings *view_settings, const ColormanageCacheDisplaySettings *display_settings)
void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace)
static unsigned int colormanage_hashhash(const void *key_v)
void IMB_display_buffer_transform_apply(unsigned char *display_buffer, float *linear_buffer, int width, int height, int channels, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, bool predivide)
void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer, const int offset_x, const int offset_y, const int width, const int height, const struct ImBuf *ibuf, const bool store_premultiplied)
const char * IMB_colormanagement_get_float_colorspace(ImBuf *ibuf)
void IMB_colormanagement_processor_apply_v4_predivide(ColormanageProcessor *cm_processor, float pixel[4])
static OCIO_CurveMappingSettings * update_glsl_curve_mapping(const ColorManagedViewSettings *view_settings)
static void colormanage_display_buffer_process_ex(ImBuf *ibuf, float *display_buffer, unsigned char *display_buffer_byte, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSettings *view_settings, const ColormanageCacheDisplaySettings *display_settings, unsigned char *display_buffer, void **cache_handle)
const char * IMB_colormanagement_look_get_indexed_name(int index)
struct DisplayBufferInitData DisplayBufferInitData
static int global_tot_looks
ColorManagedDisplay * IMB_colormanagement_display_get_named(const char *name)
static OCIO_ConstCPUProcessorRcPtr * display_to_scene_linear_processor(ColorManagedDisplay *display)
struct ProcessorTransformInit ProcessorTransformInitData
struct ColormanageCacheViewSettings ColormanageCacheViewSettings
static char global_role_default_byte[MAX_COLORSPACE_NAME]
static char global_role_default_float[MAX_COLORSPACE_NAME]
void IMB_colormanagement_processor_free(ColormanageProcessor *cm_processor)
const char * IMB_colormanagement_display_get_default_view_transform_name(struct ColorManagedDisplay *display)
void IMB_partial_display_buffer_update_delayed(ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax)
void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace)
ColorManagedDisplay * colormanage_display_add(const char *name)
void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4], bool predivide, ColorSpace *colorspace)
const char * IMB_colormanagement_display_get_indexed_name(int index)
void IMB_colormanagement_scene_linear_to_display_v3(float pixel[3], ColorManagedDisplay *display)
static void colormanage_view_settings_to_cache(ImBuf *ibuf, ColormanageCacheViewSettings *cache_view_settings, const ColorManagedViewSettings *view_settings)
void IMB_colormanagement_transform(float *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace, bool predivide)
void IMB_colormanagement_processor_apply_v4(ColormanageProcessor *cm_processor, float pixel[4])
int IMB_colormanagement_display_get_named_index(const char *name)
static char global_role_color_picking[MAX_COLORSPACE_NAME]
ImBuf * IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, bool allocate_result, const ImageFormatData *image_format)
static bool seq_callback(Sequence *seq, void *UNUSED(user_data))
static void colormanage_check_view_settings(ColorManagedDisplaySettings *display_settings, ColorManagedViewSettings *view_settings, const char *what)
static void display_buffer_apply_threaded(ImBuf *ibuf, const float *buffer, unsigned char *byte_buffer, float *display_buffer, unsigned char *display_buffer_byte, ColormanageProcessor *cm_processor)
static void wavelength_to_xyz(float xyz[3], float lambda_nm)
static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
struct ColormanageCacheKey ColormanageCacheKey
ColorManagedView * colormanage_view_get_named(const char *name)
ColorSpace * colormanage_colorspace_get_roled(int role)
ColorManagedView * colormanage_view_add(const char *name)
void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer, const int offset_x, const int offset_y, const int width, const int height, const struct ImBuf *ibuf, const bool store_premultiplied)
ColorManagedView * colormanage_view_get_indexed(int index)
ColormanageProcessor * IMB_colormanagement_display_processor_new(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static OCIO_ConstCPUProcessorRcPtr * display_from_scene_linear_processor(ColorManagedDisplay *display)
static struct MovieCache * colormanage_moviecache_ensure(ImBuf *ibuf)
#define powf(x, y)
Definition: cuda/compat.h:103
Scene scene
void * user_data
SyclQueue void void size_t num_bytes void
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
const ImFileType * IMB_file_type_from_ibuf(const ImBuf *ibuf)
Definition: filetype.c:243
void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h)
Definition: filter.c:644
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
void SEQ_for_each_callback(ListBase *seqbase, SeqForEachFunc callback, void *user_data)
Definition: iterator.c:76
ccl_global float * buffer
ccl_gpu_kernel_postfix ccl_global int * counter
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
ccl_global KernelShaderEvalInput * input
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 unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static const pxr::TfToken g("g", pxr::TfToken::Immortal)
static const pxr::TfToken rgb("rgb", pxr::TfToken::Immortal)
void OCIO_cpuProcessorApplyRGB(OCIO_ConstCPUProcessorRcPtr *cpu_processor, float *pixel)
Definition: ocio_capi.cc:202
void OCIO_cpuProcessorApplyRGBA(OCIO_ConstCPUProcessorRcPtr *cpu_processor, float *pixel)
Definition: ocio_capi.cc:207
const char * OCIO_configGetDefaultView(OCIO_ConstConfigRcPtr *config, const char *display)
Definition: ocio_capi.cc:94
void OCIO_configGetXYZtoSceneLinear(OCIO_ConstConfigRcPtr *config, float xyz_to_scene_linear[3][3])
Definition: ocio_capi.cc:121
const char * OCIO_configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *config, int index)
Definition: ocio_capi.cc:63
OCIO_ConstCPUProcessorRcPtr * OCIO_processorGetCPUProcessor(OCIO_ConstProcessorRcPtr *processor)
Definition: ocio_capi.cc:186
void OCIO_lookRelease(OCIO_ConstLookRcPtr *look)
Definition: ocio_capi.cc:146
const char * OCIO_lookGetProcessSpace(OCIO_ConstLookRcPtr *look)
Definition: ocio_capi.cc:141
void OCIO_cpuProcessorApply(OCIO_ConstCPUProcessorRcPtr *cpu_processor, OCIO_PackedImageDesc *img)
Definition: ocio_capi.cc:191
void OCIO_gpuDisplayShaderUnbind()
Definition: ocio_capi.cc:307
void OCIO_colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config, OCIO_ConstColorSpaceRcPtr *cs, bool *is_scene_linear, bool *is_srgb)
Definition: ocio_capi.cc:161
void OCIO_colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs)
Definition: ocio_capi.cc:169
const char * OCIO_configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index)
Definition: ocio_capi.cc:104
OCIO_PackedImageDesc * OCIO_createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, long chanStrideBytes, long xStrideBytes, long yStrideBytes)
Definition: ocio_capi.cc:260
int OCIO_colorSpaceGetNumAliases(OCIO_ConstColorSpaceRcPtr *cs)
Definition: ocio_capi.cc:237
OCIO_ConstConfigRcPtr * OCIO_getCurrentConfig()
Definition: ocio_capi.cc:25
const char * OCIO_colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs)
Definition: ocio_capi.cc:222
void OCIO_init()
Definition: ocio_capi.cc:10
const char * OCIO_configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index)
Definition: ocio_capi.cc:131
void OCIO_cpuProcessorApply_predivide(OCIO_ConstCPUProcessorRcPtr *cpu_processor, OCIO_PackedImageDesc *img)
Definition: ocio_capi.cc:196
void OCIO_setCurrentConfig(const OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:38
int OCIO_configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:58
void OCIO_configRelease(OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:53
OCIO_ConstColorSpaceRcPtr * OCIO_configGetColorSpace(OCIO_ConstConfigRcPtr *config, const char *name)
Definition: ocio_capi.cc:68
void OCIO_gpuCacheFree()
Definition: ocio_capi.cc:312
int OCIO_configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *display)
Definition: ocio_capi.cc:99
OCIO_ConstConfigRcPtr * OCIO_configCreateFromEnv()
Definition: ocio_capi.cc:43
bool OCIO_gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config, const char *input, const char *view, const char *display, const char *look, OCIO_CurveMappingSettings *curve_mapping_settings, const float scale, const float exponent, const float dither, const bool use_predivide, const bool use_overlay)
Definition: ocio_capi.cc:282
const char * OCIO_colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs)
Definition: ocio_capi.cc:227
void OCIO_cpuProcessorRelease(OCIO_ConstCPUProcessorRcPtr *cpu_processor)
Definition: ocio_capi.cc:217
void OCIO_exit()
Definition: ocio_capi.cc:19
OCIO_ConstProcessorRcPtr * OCIO_configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName)
Definition: ocio_capi.cc:174
void OCIO_cpuProcessorApplyRGBA_predivide(OCIO_ConstCPUProcessorRcPtr *processor, float *pixel)
Definition: ocio_capi.cc:212
int OCIO_colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs)
Definition: ocio_capi.cc:151
bool OCIO_supportGPUShader()
Definition: ocio_capi.cc:277
OCIO_ConstProcessorRcPtr * OCIO_createDisplayProcessor(OCIO_ConstConfigRcPtr *config, const char *input, const char *view, const char *display, const char *look, const float scale, const float exponent, const bool inverse)
Definition: ocio_capi.cc:247
void OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
Definition: ocio_capi.cc:272
const char * OCIO_configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view)
Definition: ocio_capi.cc:109
OCIO_ConstLookRcPtr * OCIO_configGetLook(OCIO_ConstConfigRcPtr *config, const char *name)
Definition: ocio_capi.cc:136
const char * OCIO_configGetDisplay(OCIO_ConstConfigRcPtr *config, int index)
Definition: ocio_capi.cc:89
const char * OCIO_colorSpaceGetAlias(OCIO_ConstColorSpaceRcPtr *cs, const int index)
Definition: ocio_capi.cc:242
int OCIO_configGetNumLooks(OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:126
void OCIO_processorRelease(OCIO_ConstProcessorRcPtr *processor)
Definition: ocio_capi.cc:181
const char * OCIO_configGetDefaultDisplay(OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:79
OCIO_ConstConfigRcPtr * OCIO_configCreateFromFile(const char *filename)
Definition: ocio_capi.cc:48
int OCIO_configGetNumDisplays(OCIO_ConstConfigRcPtr *config)
Definition: ocio_capi.cc:84
OCIO_ConstConfigRcPtr * OCIO_configCreateFallback()
Definition: ocio_capi.cc:30
int OCIO_colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs)
Definition: ocio_capi.cc:156
void OCIO_configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb)
Definition: ocio_capi.cc:116
#define OCIO_ROLE_COLOR_PICKING
Definition: ocio_capi.h:20
#define OCIO_ROLE_TEXTURE_PAINT
Definition: ocio_capi.h:21
static const float OCIO_XYZ_TO_REC709[3][3]
Definition: ocio_capi.h:35
#define OCIO_ROLE_DEFAULT_FLOAT
Definition: ocio_capi.h:23
#define OCIO_ROLE_DEFAULT_SEQUENCER
Definition: ocio_capi.h:24
#define OCIO_ROLE_DEFAULT_BYTE
Definition: ocio_capi.h:22
static const float OCIO_ACES_TO_XYZ[3][3]
Definition: ocio_capi.h:40
#define OCIO_ROLE_DATA
Definition: ocio_capi.h:18
#define OCIO_ROLE_SCENE_LINEAR
Definition: ocio_capi.h:19
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
Definition: rna_define.c:4436
#define min(a, b)
Definition: sort.c:35
struct OCIO_ConstCPUProcessorRcPtr * to_scene_linear
char name[MAX_COLORSPACE_NAME]
struct ColorManagedDisplay * next
struct OCIO_ConstCPUProcessorRcPtr * from_scene_linear
char ui_name[MAX_COLORSPACE_NAME]
char view[MAX_COLORSPACE_NAME]
struct ColorManagedLook * next
char process_space[MAX_COLORSPACE_NAME]
char name[MAX_COLORSPACE_NAME]
struct CurveMapping * curve_mapping
char name[MAX_COLORSPACE_NAME]
struct ColorSpace * next
struct OCIO_ConstCPUProcessorRcPtr * to_scene_linear
struct OCIO_ConstCPUProcessorRcPtr * from_scene_linear
char(* aliases)[MAX_COLORSPACE_NAME]
char name[MAX_COLORSPACE_NAME]
char description[MAX_COLORSPACE_DESCRIPTION]
struct ColorSpace::@711 info
CurveMapping * curve_mapping
struct MovieCache * moviecache
ColormanageCacheData * data
CurveMapping * curve_mapping
OCIO_ConstCPUProcessorRcPtr * cpu_processor
CurveMapPoint * table
float mintable
float ext_out[2]
float ext_in[2]
float bwmul[3]
CurveMap cm[4]
float black[3]
ColormanageProcessor * cm_processor
unsigned char * byte_buffer
const char * float_colorspace
const char * byte_colorspace
unsigned char * display_buffer_byte
const char * byte_colorspace
ColormanageProcessor * cm_processor
const char * float_colorspace
unsigned char * byte_buffer
unsigned char * display_buffer_byte
ListBase seqbase
const char * identifier
Definition: RNA_types.h:461
const char * name
Definition: RNA_types.h:465
const char * description
Definition: RNA_types.h:467
void * next
Definition: DNA_ID.h:369
rcti invalid_rect
int channels
int userflags
struct ColorSpace * rect_colorspace
float dither
int colormanage_flag
unsigned char planes
unsigned int * rect
float * rect_float
struct ColorSpace * float_colorspace
unsigned int * display_buffer_flags
struct ColormanageCache * colormanage_cache
ColorManagedColorspaceSettings linear_colorspace_settings
ColorManagedDisplaySettings display_settings
ColorManagedViewSettings view_settings
void * data
Definition: DNA_listBase.h:26
struct LinkData * next
Definition: DNA_listBase.h:25
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
ListBase scenes
Definition: BKE_main.h:168
ListBase movieclips
Definition: BKE_main.h:199
ListBase images
Definition: BKE_main.h:176
char name[64]
Definition: moviecache.cc:47
ColorManagedColorspaceSettings colorspace_settings
ColormanageProcessor * cm_processor
const unsigned char * byte_buffer
unsigned char * display_buffer
const float * linear_buffer
unsigned char * byte_buffer
ColormanageProcessor * cm_processor
ColormanageProcessor * cm_processor
ColorManagedViewSettings view_settings
struct Editing * ed
ColorManagedColorspaceSettings sequencer_colorspace_settings
ColorManagedDisplaySettings display_settings
struct Image * image
ColorManagedColorspaceSettings colorspace_settings
OCIO_ConstCPUProcessorRcPtr * cpu_processor_to
OCIO_ConstCPUProcessorRcPtr * cpu_processor_from
CurveMapping * orig_curve_mapping
OCIO_CurveMappingSettings curve_mapping_settings
CurveMapping * curve_mapping
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63
float max