Blender V4.3
colormanagement.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11
12#include <cmath>
13#include <cstring>
14
15#include "DNA_color_types.h"
16#include "DNA_image_types.h"
17#include "DNA_movieclip_types.h"
18#include "DNA_scene_types.h"
19#include "DNA_sequence_types.h"
20#include "DNA_space_types.h"
21
22#include "IMB_filetype.hh"
23#include "IMB_filter.hh"
24#include "IMB_imbuf.hh"
25#include "IMB_imbuf_types.hh"
26#include "IMB_metadata.hh"
27#include "IMB_moviecache.hh"
28
29#include "MEM_guardedalloc.h"
30
31#include "BLI_blenlib.h"
32#include "BLI_math_color.h"
33#include "BLI_math_color.hh"
34#include "BLI_rect.h"
35#include "BLI_string.h"
36#include "BLI_task.h"
37#include "BLI_task.hh"
38#include "BLI_threads.h"
39
40#include "BKE_appdir.hh"
41#include "BKE_colortools.hh"
42#include "BKE_context.hh"
43#include "BKE_global.hh"
44#include "BKE_image_format.hh"
45#include "BKE_main.hh"
46
47#include "GPU_capabilities.hh"
48
49#include "RNA_define.hh"
50
51#include "SEQ_iterator.hh"
52
53#include <ocio_capi.h>
54
56
57/* -------------------------------------------------------------------- */
61#define DISPLAY_BUFFER_CHANNELS 4
62
63/* ** list of all supported color spaces, displays and views */
71
72static ListBase global_colorspaces = {nullptr, nullptr};
73static ListBase global_displays = {nullptr, nullptr};
74static ListBase global_views = {nullptr, nullptr};
75static ListBase global_looks = {nullptr, nullptr};
76
77static int global_tot_colorspace = 0;
78static int global_tot_display = 0;
79static int global_tot_view = 0;
80static int global_tot_looks = 0;
81
82/* Luma coefficients and XYZ to RGB to be initialized by OCIO. */
83
84float imbuf_luma_coefficients[3] = {0.0f};
85float imbuf_scene_linear_to_xyz[3][3] = {{0.0f}};
86float imbuf_xyz_to_scene_linear[3][3] = {{0.0f}};
87float imbuf_scene_linear_to_rec709[3][3] = {{0.0f}};
88float imbuf_rec709_to_scene_linear[3][3] = {{0.0f}};
89float imbuf_scene_linear_to_aces[3][3] = {{0.0f}};
90float imbuf_aces_to_scene_linear[3][3] = {{0.0f}};
91
92/* lock used by pre-cached processors getters, so processor wouldn't
93 * be created several times
94 * LOCK_COLORMANAGE can not be used since this mutex could be needed to
95 * be locked before pre-cached processor are creating
96 */
97static pthread_mutex_t processor_lock = BLI_MUTEX_INITIALIZER;
98
104
115
122
125/* -------------------------------------------------------------------- */
185/* NOTE: ColormanageCacheViewSettings and ColormanageCacheDisplaySettings are
186 * quite the same as ColorManagedViewSettings and ColorManageDisplaySettings
187 * but they holds indexes of all transformations and color spaces, not
188 * their names.
189 *
190 * This helps avoid extra colorspace / display / view lookup without
191 * requiring to pass all variables which affects on display buffer
192 * to color management cache system and keeps calls small and nice.
193 */
205
209
211 int view; /* view transformation used for display buffer */
212 int display; /* display device name */
213};
214
216 int flag; /* view flags of cached buffer */
217 int look; /* Additional artistic transform. */
218 float exposure; /* exposure value cached buffer is calculated with */
219 float gamma; /* gamma value cached buffer is calculated with */
220 float dither; /* dither value cached buffer is calculated with */
221 float temperature; /* temperature value cached buffer is calculated with */
222 float tint; /* tint value cached buffer is calculated with */
223 CurveMapping *curve_mapping; /* curve mapping used for cached buffer */
224 int curve_mapping_timestamp; /* time stamp of curve mapping used for cached buffer */
225};
226
232
234{
235 if (!ibuf->colormanage_cache) {
236 return nullptr;
237 }
238
239 return ibuf->colormanage_cache->moviecache;
240}
241
243{
244 if (!ibuf->colormanage_cache) {
245 return nullptr;
246 }
247
248 return ibuf->colormanage_cache->data;
249}
250
251static uint colormanage_hashhash(const void *key_v)
252{
253 const ColormanageCacheKey *key = static_cast<const ColormanageCacheKey *>(key_v);
254
255 uint rval = (key->display << 16) | (key->view % 0xffff);
256
257 return rval;
258}
259
260static bool colormanage_hashcmp(const void *av, const void *bv)
261{
262 const ColormanageCacheKey *a = static_cast<const ColormanageCacheKey *>(av);
263 const ColormanageCacheKey *b = static_cast<const ColormanageCacheKey *>(bv);
264
265 return ((a->view != b->view) || (a->display != b->display));
266}
267
269{
270 if (!ibuf->colormanage_cache) {
271 ibuf->colormanage_cache = MEM_cnew<ColormanageCache>("imbuf colormanage cache");
272 }
273
274 if (!ibuf->colormanage_cache->moviecache) {
275 MovieCache *moviecache;
276
277 moviecache = IMB_moviecache_create("colormanage cache",
278 sizeof(ColormanageCacheKey),
281
282 ibuf->colormanage_cache->moviecache = moviecache;
283 }
284
285 return ibuf->colormanage_cache->moviecache;
286}
287
289{
290 if (!ibuf->colormanage_cache) {
291 ibuf->colormanage_cache = MEM_cnew<ColormanageCache>("imbuf colormanage cache");
292 }
293
294 ibuf->colormanage_cache->data = data;
295}
296
298 ColormanageCacheViewSettings *cache_view_settings,
299 const ColorManagedViewSettings *view_settings)
300{
301 int look = IMB_colormanagement_look_get_named_index(view_settings->look);
303
304 cache_view_settings->look = look;
305 cache_view_settings->view = view;
306 cache_view_settings->exposure = view_settings->exposure;
307 cache_view_settings->gamma = view_settings->gamma;
308 cache_view_settings->dither = ibuf->dither;
309 cache_view_settings->temperature = view_settings->temperature;
310 cache_view_settings->tint = view_settings->tint;
311 cache_view_settings->flag = view_settings->flag;
312 cache_view_settings->curve_mapping = view_settings->curve_mapping;
313}
314
316 ColormanageCacheDisplaySettings *cache_display_settings,
317 const ColorManagedDisplaySettings *display_settings)
318{
319 int display = IMB_colormanagement_display_get_named_index(display_settings->display_device);
320
321 cache_display_settings->display = display;
322}
323
325 const ColormanageCacheViewSettings *view_settings,
326 const ColormanageCacheDisplaySettings *display_settings)
327{
328 key->view = view_settings->view;
329 key->display = display_settings->display;
330}
331
334 void **cache_handle)
335{
336 ImBuf *cache_ibuf;
337 MovieCache *moviecache = colormanage_moviecache_get(ibuf);
338
339 if (!moviecache) {
340 /* If there's no moviecache it means no color management was applied
341 * on given image buffer before. */
342 return nullptr;
343 }
344
345 *cache_handle = nullptr;
346
347 cache_ibuf = IMB_moviecache_get(moviecache, key, nullptr);
348
349 *cache_handle = cache_ibuf;
350
351 return cache_ibuf;
352}
353
355 const ColormanageCacheViewSettings *view_settings,
356 const ColormanageCacheDisplaySettings *display_settings,
357 void **cache_handle)
358{
360 ImBuf *cache_ibuf;
361 int view_flag = 1 << (view_settings->view - 1);
362 CurveMapping *curve_mapping = view_settings->curve_mapping;
363 int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
364
365 colormanage_settings_to_key(&key, view_settings, display_settings);
366
367 /* check whether image was marked as dirty for requested transform */
368 if ((ibuf->display_buffer_flags[display_settings->display - 1] & view_flag) == 0) {
369 return nullptr;
370 }
371
372 cache_ibuf = colormanage_cache_get_ibuf(ibuf, &key, cache_handle);
373
374 if (cache_ibuf) {
375
376 BLI_assert(cache_ibuf->x == ibuf->x && cache_ibuf->y == ibuf->y);
377
378 /* only buffers with different color space conversions are being stored
379 * in cache separately. buffer which were used only different exposure/gamma
380 * are re-suing the same cached buffer
381 *
382 * check here which exposure/gamma/curve was used for cached buffer and if they're
383 * different from requested buffer should be re-generated
384 */
385 const ColormanageCacheData *cache_data = colormanage_cachedata_get(cache_ibuf);
386
387 if (cache_data->look != view_settings->look ||
388 cache_data->exposure != view_settings->exposure ||
389 cache_data->gamma != view_settings->gamma || cache_data->dither != view_settings->dither ||
390 cache_data->temperature != view_settings->temperature ||
391 cache_data->tint != view_settings->tint || cache_data->flag != view_settings->flag ||
392 cache_data->curve_mapping != curve_mapping ||
393 cache_data->curve_mapping_timestamp != curve_mapping_timestamp)
394 {
395 *cache_handle = nullptr;
396
397 IMB_freeImBuf(cache_ibuf);
398
399 return nullptr;
400 }
401
402 return (uchar *)cache_ibuf->byte_buffer.data;
403 }
404
405 return nullptr;
406}
407
408static void colormanage_cache_put(ImBuf *ibuf,
409 const ColormanageCacheViewSettings *view_settings,
410 const ColormanageCacheDisplaySettings *display_settings,
411 uchar *display_buffer,
412 void **cache_handle)
413{
415 ImBuf *cache_ibuf;
416 ColormanageCacheData *cache_data;
417 int view_flag = 1 << (view_settings->view - 1);
418 MovieCache *moviecache = colormanage_moviecache_ensure(ibuf);
419 CurveMapping *curve_mapping = view_settings->curve_mapping;
420 int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
421
422 colormanage_settings_to_key(&key, view_settings, display_settings);
423
424 /* mark display buffer as valid */
425 ibuf->display_buffer_flags[display_settings->display - 1] |= view_flag;
426
427 /* buffer itself */
428 cache_ibuf = IMB_allocImBuf(ibuf->x, ibuf->y, ibuf->planes, 0);
429 IMB_assign_byte_buffer(cache_ibuf, display_buffer, IB_TAKE_OWNERSHIP);
430
431 /* Store data which is needed to check whether cached buffer
432 * could be used for color managed display settings. */
433 cache_data = MEM_cnew<ColormanageCacheData>("color manage cache imbuf data");
434 cache_data->look = view_settings->look;
435 cache_data->exposure = view_settings->exposure;
436 cache_data->gamma = view_settings->gamma;
437 cache_data->dither = view_settings->dither;
438 cache_data->temperature = view_settings->temperature;
439 cache_data->tint = view_settings->tint;
440 cache_data->flag = view_settings->flag;
441 cache_data->curve_mapping = curve_mapping;
442 cache_data->curve_mapping_timestamp = curve_mapping_timestamp;
443
444 colormanage_cachedata_set(cache_ibuf, cache_data);
445
446 *cache_handle = cache_ibuf;
447
448 IMB_moviecache_put(moviecache, &key, cache_ibuf);
449}
450
451static void colormanage_cache_handle_release(void *cache_handle)
452{
453 ImBuf *cache_ibuf = static_cast<ImBuf *>(cache_handle);
454
455 IMB_freeImBuf(cache_ibuf);
456}
457
460/* -------------------------------------------------------------------- */
464static bool colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config,
465 char *colorspace_name,
466 const char *role,
467 const char *backup_role)
468{
469 OCIO_ConstColorSpaceRcPtr *ociocs;
470
471 ociocs = OCIO_configGetColorSpace(config, role);
472
473 if (ociocs == nullptr && backup_role) {
474 ociocs = OCIO_configGetColorSpace(config, backup_role);
475 }
476
477 if (ociocs == nullptr) {
478 /* Overall fallback role. */
479 ociocs = OCIO_configGetColorSpace(config, "default");
480 }
481
482 if (ociocs == nullptr) {
483 if (!G.quiet) {
484 printf("Color management: Error, could not find role \"%s\"\n", role);
485 }
486 return false;
487 }
488
489 const char *name = OCIO_colorSpaceGetName(ociocs);
490
491 /* assume function was called with buffer properly allocated to MAX_COLORSPACE_NAME chars */
492 BLI_strncpy(colorspace_name, name, MAX_COLORSPACE_NAME);
494 return true;
495}
496
497static bool colormanage_load_config(OCIO_ConstConfigRcPtr *config)
498{
499 bool ok = true;
500
501 /* get roles */
515
516 /* load colorspaces */
517 const int tot_colorspace = OCIO_configGetNumColorSpaces(config);
518 for (int index = 0; index < tot_colorspace; index++) {
519 const char *name = OCIO_configGetColorSpaceNameByIndex(config, index);
520
521 OCIO_ConstColorSpaceRcPtr *ocio_colorspace = OCIO_configGetColorSpace(config, name);
522 const char *description = OCIO_colorSpaceGetDescription(ocio_colorspace);
523 const bool is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace);
524 const bool is_data = OCIO_colorSpaceIsData(ocio_colorspace);
525
526 ColorSpace *colorspace = colormanage_colorspace_add(name, description, is_invertible, is_data);
527
528 colorspace->num_aliases = OCIO_colorSpaceGetNumAliases(ocio_colorspace);
529 if (colorspace->num_aliases > 0) {
530 colorspace->aliases = static_cast<char(*)[MAX_COLORSPACE_NAME]>(MEM_callocN(
531 sizeof(*colorspace->aliases) * colorspace->num_aliases, "ColorSpace aliases"));
532 for (int i = 0; i < colorspace->num_aliases; i++) {
533 BLI_strncpy(colorspace->aliases[i],
534 OCIO_colorSpaceGetAlias(ocio_colorspace, i),
536 }
537 }
538
539 OCIO_colorSpaceRelease(ocio_colorspace);
540 }
541
542 /* load displays */
543 const int tot_display = OCIO_configGetNumDisplays(config);
544 int viewindex2 = 0;
545
546 for (int index = 0; index < tot_display; index++) {
547 const char *displayname = OCIO_configGetDisplay(config, index);
548
549 ColorManagedDisplay *display = colormanage_display_add(displayname);
550
551 /* load views */
552 const int tot_display_view = OCIO_configGetNumViews(config, displayname);
553 for (int viewindex = 0; viewindex < tot_display_view; viewindex++, viewindex2++) {
554 const char *viewname = OCIO_configGetView(config, displayname, viewindex);
555
556 /* first check if view transform with given name was already loaded */
558
559 if (!view) {
560 view = colormanage_view_add(viewname);
561 }
562
563 LinkData *display_view = BLI_genericNodeN(view);
564
565 BLI_addtail(&display->views, display_view);
566 }
567 }
568
569 global_tot_display = tot_display;
570 if (global_tot_display == 0) {
571 if (!G.quiet) {
572 printf("Color management: Error, could not find any displays\n");
573 }
574 ok = false;
575 }
576 else if (global_tot_view == 0) {
577 if (!G.quiet) {
578 printf("Color management: Error, could not find any views\n");
579 }
580 ok = false;
581 }
582
583 /* load looks */
584 const int tot_looks = OCIO_configGetNumLooks(config);
585 colormanage_look_add("None", "", true);
586 for (int index = 0; index < tot_looks; index++) {
587 const char *name = OCIO_configGetLookNameByIndex(config, index);
588 OCIO_ConstLookRcPtr *ocio_look = OCIO_configGetLook(config, name);
589 const char *process_space = OCIO_lookGetProcessSpace(ocio_look);
590 OCIO_lookRelease(ocio_look);
591
592 colormanage_look_add(name, process_space, false);
593 }
594
595 /* Load luminance coefficients. */
597
598 /* Load standard color spaces. */
601
604
607
608 return ok;
609}
610
612{
613 ColorSpace *colorspace;
614 ColorManagedDisplay *display;
615
616 /* free color spaces */
617 colorspace = static_cast<ColorSpace *>(global_colorspaces.first);
618 while (colorspace) {
619 ColorSpace *colorspace_next = colorspace->next;
620
621 /* Free precomputed processors. */
622 if (colorspace->to_scene_linear) {
624 }
625 if (colorspace->from_scene_linear) {
627 }
628
629 /* free color space itself */
630 MEM_SAFE_FREE(colorspace->aliases);
631 MEM_freeN(colorspace);
632
633 colorspace = colorspace_next;
634 }
637
638 /* free displays */
639 display = static_cast<ColorManagedDisplay *>(global_displays.first);
640 while (display) {
641 ColorManagedDisplay *display_next = display->next;
642
643 /* free precomputer processors */
644 if (display->to_scene_linear) {
645 OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)display->to_scene_linear);
646 }
647 if (display->from_scene_linear) {
648 OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)display->from_scene_linear);
649 }
650
651 /* free list of views */
652 BLI_freelistN(&display->views);
653
654 MEM_freeN(display);
655 display = display_next;
656 }
659
660 /* free views */
662 global_tot_view = 0;
663
664 /* free looks */
667}
668
670{
671 OCIO_ConstConfigRcPtr *config = nullptr;
672
673 OCIO_init();
674
675 /* First try config from environment variable. */
676 const char *ocio_env = BLI_getenv("OCIO");
677
678 if (ocio_env && ocio_env[0] != '\0') {
679 config = OCIO_configCreateFromEnv();
680 if (config != nullptr) {
681 if (!G.quiet) {
682 printf("Color management: Using %s as a configuration file\n", ocio_env);
683 }
684 OCIO_setCurrentConfig(config);
685 const bool ok = colormanage_load_config(config);
686 OCIO_configRelease(config);
687
688 if (!ok) {
689 if (!G.quiet) {
690 printf("Color management: Failed to load config from environment\n");
691 }
693 config = nullptr;
694 }
695 }
696 }
697
698 /* Then try bundled configuration file. */
699 if (config == nullptr) {
700 const std::optional<std::string> configdir = BKE_appdir_folder_id(BLENDER_DATAFILES,
701 "colormanagement");
702 if (configdir.has_value()) {
703 char configfile[FILE_MAX];
704 BLI_path_join(configfile, sizeof(configfile), configdir->c_str(), BCM_CONFIG_FILE);
705
706 config = OCIO_configCreateFromFile(configfile);
707
708 if (config != nullptr) {
709 OCIO_setCurrentConfig(config);
710 const bool ok = colormanage_load_config(config);
711 OCIO_configRelease(config);
712
713 if (!ok) {
714 if (!G.quiet) {
715 printf("Color management: Failed to load bundled config\n");
716 }
718 config = nullptr;
719 }
720 }
721 }
722 }
723
724 /* Then use fallback. */
725 if (config == nullptr) {
726 if (!G.quiet) {
727 printf("Color management: Using fallback mode for management\n");
728 }
729 config = OCIO_configCreateFallback();
731 }
732
734}
735
762
765/* -------------------------------------------------------------------- */
769static bool has_explicit_look_for_view(const char *view_name)
770{
771 if (!view_name) {
772 return false;
773 }
774
776 if (STREQ(look->view, view_name)) {
777 return true;
778 }
779 }
780
781 return false;
782}
783
785 const char *view_name,
786 const bool has_explicit_look)
787{
788 if (look->is_noop) {
789 return true;
790 }
791
792 /* Skip looks only relevant to specific view transforms.
793 * If the view transform has view-specific look ignore non-specific looks. */
794
795 if (view_name && STREQ(look->view, view_name)) {
796 return true;
797 }
798
799 if (has_explicit_look) {
800 return false;
801 }
802
803 return look->view[0] == '\0';
804}
805
806static bool colormanage_compatible_look(const ColorManagedLook *look, const char *view_name)
807{
808 const bool has_explicit_look = has_explicit_look_for_view(view_name);
809 return colormanage_compatible_look(look, view_name, has_explicit_look);
810}
811
812static bool colormanage_use_look(const char *look, const char *view_name)
813{
815 return (look_descr->is_noop == false && colormanage_compatible_look(look_descr, view_name));
816}
817
819{
821
822 if (ibuf->colormanage_cache) {
824 MovieCache *moviecache = colormanage_moviecache_get(ibuf);
825
826 if (cache_data) {
827 MEM_freeN(cache_data);
828 }
829
830 if (moviecache) {
831 IMB_moviecache_free(moviecache);
832 }
833
835
836 ibuf->colormanage_cache = nullptr;
837 }
838}
839
841 const bContext *C,
842 ColorManagedViewSettings **r_view_settings,
843 ColorManagedDisplaySettings **r_display_settings)
844{
845 Scene *scene = CTX_data_scene(C);
847
848 *r_view_settings = &scene->view_settings;
849 *r_display_settings = &scene->display_settings;
850
851 if (sima && sima->image) {
852 if ((sima->image->flag & IMA_VIEW_AS_RENDER) == 0) {
853 *r_view_settings = nullptr;
854 }
855 }
856}
857
858static const char *get_display_colorspace_name(const ColorManagedViewSettings *view_settings,
859 const ColorManagedDisplaySettings *display_settings)
860{
861 OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
862
863 const char *display = display_settings->display_device;
864 const char *view = view_settings->view_transform;
865 const char *colorspace_name;
866
867 colorspace_name = OCIO_configGetDisplayColorSpaceName(config, display, view);
868
869 OCIO_configRelease(config);
870
871 return colorspace_name;
872}
873
875 const ColorManagedViewSettings *view_settings,
876 const ColorManagedDisplaySettings *display_settings)
877{
878 const char *colorspace_name = get_display_colorspace_name(view_settings, display_settings);
879
880 if (colorspace_name) {
881 return colormanage_colorspace_get_named(colorspace_name);
882 }
883
884 return nullptr;
885}
886
888 const char *view_transform,
889 const char *display,
890 const float exposure,
891 const float gamma,
892 const float temperature,
893 const float tint,
894 const bool use_white_balance,
895 const char *from_colorspace)
896{
897 OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
898 const bool use_look = colormanage_use_look(look, view_transform);
899 const float scale = (exposure == 0.0f) ? 1.0f : powf(2.0f, exposure);
900 const float exponent = (gamma == 1.0f) ? 1.0f : 1.0f / max_ff(FLT_EPSILON, gamma);
901
902 OCIO_ConstProcessorRcPtr *processor = OCIO_createDisplayProcessor(config,
903 from_colorspace,
904 view_transform,
905 display,
906 (use_look) ? look : "",
907 scale,
908 exponent,
909 temperature,
910 tint,
911 use_white_balance,
912 false);
913
914 OCIO_configRelease(config);
915
916 if (processor == nullptr) {
917 return nullptr;
918 }
919
921 OCIO_processorRelease(processor);
922
923 return cpu_processor;
924}
925
926static OCIO_ConstProcessorRcPtr *create_colorspace_transform_processor(const char *from_colorspace,
927 const char *to_colorspace)
928{
929 OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
930 OCIO_ConstProcessorRcPtr *processor;
931
932 processor = OCIO_configGetProcessorWithNames(config, from_colorspace, to_colorspace);
933
934 OCIO_configRelease(config);
935
936 return processor;
937}
938
940 ColorSpace *colorspace)
941{
942 if (colorspace->to_scene_linear == nullptr) {
944
945 if (colorspace->to_scene_linear == nullptr) {
946 OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
947 colorspace->name, global_role_scene_linear);
948
949 if (processor != nullptr) {
951 processor);
952 OCIO_processorRelease(processor);
953 }
954 }
955
957 }
958
959 return (OCIO_ConstCPUProcessorRcPtr *)colorspace->to_scene_linear;
960}
961
963 ColorSpace *colorspace)
964{
965 if (colorspace->from_scene_linear == nullptr) {
967
968 if (colorspace->from_scene_linear == nullptr) {
969 OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
970 global_role_scene_linear, colorspace->name);
971
972 if (processor != nullptr) {
975 OCIO_processorRelease(processor);
976 }
977 }
978
980 }
981
983}
984
986 ColorManagedDisplay *display)
987{
988 if (display->from_scene_linear == nullptr) {
990
991 if (display->from_scene_linear == nullptr) {
992 const char *view_name = colormanage_view_get_default_name(display);
993 OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
994 OCIO_ConstProcessorRcPtr *processor = nullptr;
995
996 if (view_name && config) {
997 processor = OCIO_createDisplayProcessor(config,
999 view_name,
1000 display->name,
1001 nullptr,
1002 1.0f,
1003 1.0f,
1004 0.0f,
1005 0.0f,
1006 false,
1007 false);
1008
1009 OCIO_configRelease(config);
1010 }
1011
1012 if (processor != nullptr) {
1013 display->from_scene_linear = (OCIO_ConstCPUProcessorRcPtr *)OCIO_processorGetCPUProcessor(
1014 processor);
1015 OCIO_processorRelease(processor);
1016 }
1017 }
1018
1020 }
1021
1022 return (OCIO_ConstCPUProcessorRcPtr *)display->from_scene_linear;
1023}
1024
1026{
1027 if (display->to_scene_linear == nullptr) {
1029
1030 if (display->to_scene_linear == nullptr) {
1031 const char *view_name = colormanage_view_get_default_name(display);
1032 OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
1033 OCIO_ConstProcessorRcPtr *processor = nullptr;
1034
1035 if (view_name && config) {
1036 processor = OCIO_createDisplayProcessor(config,
1038 view_name,
1039 display->name,
1040 nullptr,
1041 1.0f,
1042 1.0f,
1043 0.0f,
1044 0.0f,
1045 false,
1046 true);
1047
1048 OCIO_configRelease(config);
1049 }
1050
1051 if (processor != nullptr) {
1052 display->to_scene_linear = (OCIO_ConstCPUProcessorRcPtr *)OCIO_processorGetCPUProcessor(
1053 processor);
1054 OCIO_processorRelease(processor);
1055 }
1056 }
1057
1059 }
1060
1061 return (OCIO_ConstCPUProcessorRcPtr *)display->to_scene_linear;
1062}
1063
1065 ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
1066{
1067 /* First, try use "Standard" view transform of the requested device. */
1069 display_settings->display_device, "Standard");
1070 /* If that fails, we fall back to the default view transform of the display
1071 * as per OCIO configuration. */
1072 if (default_view == nullptr) {
1074 if (display != nullptr) {
1075 default_view = colormanage_view_get_default(display);
1076 }
1077 }
1078 if (default_view != nullptr) {
1079 STRNCPY(view_settings->view_transform, default_view->name);
1080 }
1081 else {
1082 view_settings->view_transform[0] = '\0';
1083 }
1084 /* TODO(sergey): Find a way to safely/reliable un-hardcode this. */
1085 STRNCPY(view_settings->look, "None");
1086 /* Initialize rest of the settings. */
1087 view_settings->flag = 0;
1088 view_settings->gamma = 1.0f;
1089 view_settings->exposure = 0.0f;
1090 view_settings->temperature = 6500.0f;
1091 view_settings->tint = 10.0f;
1092 view_settings->curve_mapping = nullptr;
1093}
1094
1095static void curve_mapping_apply_pixel(const CurveMapping *curve_mapping,
1096 float *pixel,
1097 int channels)
1098{
1099 if (channels == 1) {
1100 pixel[0] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[0]);
1101 }
1102 else if (channels == 2) {
1103 pixel[0] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[0]);
1104 pixel[1] = BKE_curvemap_evaluateF(curve_mapping, curve_mapping->cm, pixel[1]);
1105 }
1106 else {
1107 BKE_curvemapping_evaluate_premulRGBF(curve_mapping, pixel, pixel);
1108 }
1109}
1110
1111void colorspace_set_default_role(char *colorspace, int size, int role)
1112{
1113 if (colorspace && colorspace[0] == '\0') {
1114 const char *role_colorspace;
1115
1116 role_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
1117
1118 BLI_strncpy(colorspace, role_colorspace, size);
1119 }
1120}
1121
1126
1127void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace)
1128{
1129 ColorSpace *colorspace = colormanage_colorspace_get_named(from_colorspace);
1130
1131 if (colorspace && colorspace->is_data) {
1133 return;
1134 }
1135
1136 if (ibuf->float_buffer.data) {
1137 const char *to_colorspace = global_role_scene_linear;
1138 const bool predivide = IMB_alpha_affects_rgb(ibuf);
1139
1140 if (ibuf->byte_buffer.data) {
1141 imb_freerectImBuf(ibuf);
1142 }
1143
1145 ibuf->x,
1146 ibuf->y,
1147 ibuf->channels,
1148 from_colorspace,
1149 to_colorspace,
1150 predivide);
1151 }
1152}
1153
1156/* -------------------------------------------------------------------- */
1161 const char *what,
1162 const ColorManagedDisplay *default_display)
1163{
1164 if (display_settings->display_device[0] == '\0') {
1165 STRNCPY(display_settings->display_device, default_display->name);
1166 }
1167 else {
1169
1170 if (!display) {
1171 if (!G.quiet) {
1172 printf(
1173 "Color management: display \"%s\" used by %s not found, setting to default "
1174 "(\"%s\").\n",
1175 display_settings->display_device,
1176 what,
1177 default_display->name);
1178 }
1179
1180 STRNCPY(display_settings->display_device, default_display->name);
1181 }
1182 }
1183}
1184
1186 ColorManagedViewSettings *view_settings,
1187 const char *what)
1188{
1189 ColorManagedDisplay *display;
1190 ColorManagedView *default_view = nullptr;
1191 const char *default_look_name = IMB_colormanagement_look_get_default_name();
1192
1193 if (view_settings->view_transform[0] == '\0') {
1194 display = colormanage_display_get_named(display_settings->display_device);
1195
1196 if (display) {
1197 default_view = colormanage_view_get_default(display);
1198 }
1199
1200 if (default_view) {
1201 STRNCPY(view_settings->view_transform, default_view->name);
1202 }
1203 }
1204 else {
1206
1207 if (!view) {
1208 display = colormanage_display_get_named(display_settings->display_device);
1209
1210 if (display) {
1211 default_view = colormanage_view_get_default(display);
1212 }
1213
1214 if (default_view) {
1215 if (!G.quiet) {
1216 printf("Color management: %s view \"%s\" not found, setting default \"%s\".\n",
1217 what,
1218 view_settings->view_transform,
1219 default_view->name);
1220 }
1221
1222 STRNCPY(view_settings->view_transform, default_view->name);
1223 }
1224 }
1225 }
1226
1227 if (view_settings->look[0] == '\0') {
1228 STRNCPY(view_settings->look, default_look_name);
1229 }
1230 else {
1231 ColorManagedLook *look = colormanage_look_get_named(view_settings->look);
1232 if (look == nullptr) {
1233 if (!G.quiet) {
1234 printf("Color management: %s look \"%s\" not found, setting default \"%s\".\n",
1235 what,
1236 view_settings->look,
1237 default_look_name);
1238 }
1239
1240 STRNCPY(view_settings->look, default_look_name);
1241 }
1242 else if (!colormanage_compatible_look(look, view_settings->view_transform)) {
1243 if (!G.quiet) {
1244 printf(
1245 "Color management: %s look \"%s\" is not compatible with view \"%s\", setting default "
1246 "\"%s\".\n",
1247 what,
1248 view_settings->look,
1249 view_settings->view_transform,
1250 default_look_name);
1251 }
1252
1253 STRNCPY(view_settings->look, default_look_name);
1254 }
1255 }
1256
1257 /* OCIO_TODO: move to do_versions() */
1258 if (view_settings->exposure == 0.0f && view_settings->gamma == 0.0f) {
1259 view_settings->exposure = 0.0f;
1260 view_settings->gamma = 1.0f;
1261 }
1262}
1263
1265 ColorManagedColorspaceSettings *colorspace_settings, const char *what)
1266{
1267 if (colorspace_settings->name[0] == '\0') {
1268 /* pass */
1269 }
1270 else {
1271 ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
1272
1273 if (!colorspace) {
1274 if (!G.quiet) {
1275 printf("Color management: %s colorspace \"%s\" not found, will use default instead.\n",
1276 what,
1277 colorspace_settings->name);
1278 }
1279
1280 STRNCPY(colorspace_settings->name, "");
1281 }
1282 }
1283
1284 (void)what;
1285}
1286
1287static bool seq_callback(Sequence *seq, void * /*user_data*/)
1288{
1289 if (seq->strip) {
1291 }
1292 return true;
1293}
1294
1296{
1298 if (!default_display) {
1299 /* happens when OCIO configuration is incorrect */
1300 return;
1301 }
1302
1303 LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
1304 ColorManagedColorspaceSettings *sequencer_colorspace_settings;
1305
1306 /* check scene color management settings */
1307 colormanage_check_display_settings(&scene->display_settings, "scene", default_display);
1308 colormanage_check_view_settings(&scene->display_settings, &scene->view_settings, "scene");
1309
1310 sequencer_colorspace_settings = &scene->sequencer_colorspace_settings;
1311
1312 colormanage_check_colorspace_settings(sequencer_colorspace_settings, "sequencer");
1313
1314 if (sequencer_colorspace_settings->name[0] == '\0') {
1315 STRNCPY(sequencer_colorspace_settings->name, global_role_default_sequencer);
1316 }
1317
1318 /* check sequencer strip input color space settings */
1319 if (scene->ed != nullptr) {
1320 SEQ_for_each_callback(&scene->ed->seqbase, seq_callback, nullptr);
1321 }
1322 }
1323
1324 /* ** check input color space settings ** */
1325
1326 LISTBASE_FOREACH (Image *, image, &bmain->images) {
1327 colormanage_check_colorspace_settings(&image->colorspace_settings, "image");
1328 }
1329
1330 LISTBASE_FOREACH (MovieClip *, clip, &bmain->movieclips) {
1331 colormanage_check_colorspace_settings(&clip->colorspace_settings, "clip");
1332 }
1333}
1334
1336 ColorManagedViewSettings *view_settings)
1337{
1339 ColorManagedView *default_view = colormanage_view_get_default(display);
1340
1341 bool found = false;
1342 LISTBASE_FOREACH (LinkData *, view_link, &display->views) {
1343 ColorManagedView *view = static_cast<ColorManagedView *>(view_link->data);
1344
1345 if (STREQ(view->name, view_settings->view_transform)) {
1346 found = true;
1347 break;
1348 }
1349 }
1350
1351 if (!found && default_view) {
1352 STRNCPY(view_settings->view_transform, default_view->name);
1353 }
1354}
1355
1357{
1358 switch (role) {
1359 case COLOR_ROLE_DATA:
1360 return global_role_data;
1373 default:
1374 if (!G.quiet) {
1375 printf("Unknown role was passed to %s\n", __func__);
1376 }
1377 BLI_assert(0);
1378 break;
1379 }
1380
1381 return nullptr;
1382}
1383
1384void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name)
1385{
1386 ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1387
1388 if (colorspace && colorspace->is_data) {
1390 }
1391 else {
1392 ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA;
1393 }
1394}
1395
1397{
1402 if (ibuf_src->flags & IB_alphamode_premul) {
1403 ibuf_dst->flags |= IB_alphamode_premul;
1404 }
1405 else if (ibuf_src->flags & IB_alphamode_channel_packed) {
1407 }
1408 else if (ibuf_src->flags & IB_alphamode_ignore) {
1409 ibuf_dst->flags |= IB_alphamode_ignore;
1410 }
1411}
1412
1414{
1415 ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1416
1417 ibuf->float_buffer.colorspace = colorspace;
1418
1419 if (colorspace && colorspace->is_data) {
1421 }
1422 else {
1423 ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA;
1424 }
1425}
1426
1428{
1429 ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1430
1431 ibuf->byte_buffer.colorspace = colorspace;
1432
1433 if (colorspace && colorspace->is_data) {
1435 }
1436 else {
1437 ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA;
1438 }
1439}
1440
1449
1458
1460{
1461 return (colorspace && colorspace->is_data);
1462}
1463
1465{
1466 if (colorspace && !colorspace->info.cached) {
1467 OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
1468 OCIO_ConstColorSpaceRcPtr *ocio_colorspace = OCIO_configGetColorSpace(config,
1469 colorspace->name);
1470
1471 bool is_scene_linear, is_srgb;
1472 OCIO_colorSpaceIsBuiltin(config, ocio_colorspace, &is_scene_linear, &is_srgb);
1473
1474 OCIO_colorSpaceRelease(ocio_colorspace);
1475 OCIO_configRelease(config);
1476
1477 colorspace->info.is_scene_linear = is_scene_linear;
1478 colorspace->info.is_srgb = is_srgb;
1479 colorspace->info.cached = true;
1480 }
1481}
1482
1484{
1486 return (colorspace && colorspace->info.is_scene_linear);
1487}
1488
1490{
1492 return (colorspace && colorspace->info.is_srgb);
1493}
1494
1496{
1497 ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1498 return (colorspace && colorspace->is_data);
1499}
1500
1502{
1503 ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1504 return (colorspace && IMB_colormanagement_space_is_scene_linear(colorspace));
1505}
1506
1508{
1509 ColorSpace *colorspace = colormanage_colorspace_get_named(name);
1510 return (colorspace && IMB_colormanagement_space_is_srgb(colorspace));
1511}
1512
1517
1522
1525/* -------------------------------------------------------------------- */
1529void IMB_colormanagement_get_whitepoint(const float temperature,
1530 const float tint,
1531 float whitepoint[3])
1532{
1535}
1536
1537bool IMB_colormanagement_set_whitepoint(const float whitepoint[3], float &temperature, float &tint)
1538{
1539 blender::float3 xyz;
1541 return blender::math::whitepoint_to_temp_tint(xyz, temperature, tint);
1542}
1543
1546/* -------------------------------------------------------------------- */
1571
1586
1587static void display_buffer_init_handle(void *handle_v,
1588 int start_line,
1589 int tot_line,
1590 void *init_data_v)
1591{
1592 DisplayBufferThread *handle = (DisplayBufferThread *)handle_v;
1594 ImBuf *ibuf = init_data->ibuf;
1595
1596 int channels = ibuf->channels;
1597 float dither = ibuf->dither;
1598 bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
1599
1600 size_t offset = size_t(channels) * start_line * ibuf->x;
1601 size_t display_buffer_byte_offset = size_t(DISPLAY_BUFFER_CHANNELS) * start_line * ibuf->x;
1602
1603 memset(handle, 0, sizeof(DisplayBufferThread));
1604
1605 handle->cm_processor = init_data->cm_processor;
1606
1607 if (init_data->buffer) {
1608 handle->buffer = init_data->buffer + offset;
1609 }
1610
1611 if (init_data->byte_buffer) {
1612 handle->byte_buffer = init_data->byte_buffer + offset;
1613 }
1614
1615 if (init_data->display_buffer) {
1616 handle->display_buffer = init_data->display_buffer + offset;
1617 }
1618
1619 if (init_data->display_buffer_byte) {
1620 handle->display_buffer_byte = init_data->display_buffer_byte + display_buffer_byte_offset;
1621 }
1622
1623 handle->width = ibuf->x;
1624
1625 handle->start_line = start_line;
1626 handle->tot_line = tot_line;
1627
1628 handle->channels = channels;
1629 handle->dither = dither;
1630 handle->is_data = is_data;
1631 handle->predivide = IMB_alpha_affects_rgb(ibuf);
1632
1633 handle->byte_colorspace = init_data->byte_colorspace;
1634 handle->float_colorspace = init_data->float_colorspace;
1635}
1636
1638 int height,
1639 float *linear_buffer,
1640 bool *is_straight_alpha)
1641{
1642 int channels = handle->channels;
1643 int width = handle->width;
1644
1645 size_t buffer_size = size_t(channels) * width * height;
1646
1647 bool is_data = handle->is_data;
1648 bool is_data_display = handle->cm_processor->is_data_result;
1649 bool predivide = handle->predivide;
1650
1651 if (!handle->buffer) {
1652 uchar *byte_buffer = handle->byte_buffer;
1653
1654 const char *from_colorspace = handle->byte_colorspace;
1655 const char *to_colorspace = global_role_scene_linear;
1656
1657 float *fp;
1658 uchar *cp;
1659 const size_t i_last = size_t(width) * height;
1660 size_t i;
1661
1662 /* first convert byte buffer to float, keep in image space */
1663 for (i = 0, fp = linear_buffer, cp = byte_buffer; i != i_last;
1664 i++, fp += channels, cp += channels)
1665 {
1666 if (channels == 3) {
1667 rgb_uchar_to_float(fp, cp);
1668 }
1669 else if (channels == 4) {
1670 rgba_uchar_to_float(fp, cp);
1671 }
1672 else {
1673 BLI_assert_msg(0, "Buffers of 3 or 4 channels are only supported here");
1674 }
1675 }
1676
1677 if (!is_data && !is_data_display) {
1678 /* convert float buffer to scene linear space */
1680 linear_buffer, width, height, channels, from_colorspace, to_colorspace, false);
1681 }
1682
1683 *is_straight_alpha = true;
1684 }
1685 else if (handle->float_colorspace) {
1686 /* currently float is non-linear only in sequencer, which is working
1687 * in its own color space even to handle float buffers.
1688 * This color space is the same for byte and float images.
1689 * Need to convert float buffer to linear space before applying display transform
1690 */
1691
1692 const char *from_colorspace = handle->float_colorspace;
1693 const char *to_colorspace = global_role_scene_linear;
1694
1695 memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
1696
1697 if (!is_data && !is_data_display) {
1699 linear_buffer, width, height, channels, from_colorspace, to_colorspace, predivide);
1700 }
1701
1702 *is_straight_alpha = false;
1703 }
1704 else {
1705 /* some processors would want to modify float original buffer
1706 * before converting it into display byte buffer, so we need to
1707 * make sure original's ImBuf buffers wouldn't be modified by
1708 * using duplicated buffer here
1709 */
1710
1711 memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
1712
1713 *is_straight_alpha = false;
1714 }
1715}
1716
1718{
1719 const int width = handle->width;
1720 const int height = handle->tot_line;
1721 if (handle->display_buffer_byte && handle->display_buffer_byte != handle->byte_buffer) {
1722 if (handle->byte_buffer) {
1723 IMB_buffer_byte_from_byte(handle->display_buffer_byte,
1724 handle->byte_buffer,
1727 false,
1728 width,
1729 height,
1730 width,
1731 width);
1732 }
1733 else if (handle->buffer) {
1734 IMB_buffer_byte_from_float(handle->display_buffer_byte,
1735 handle->buffer,
1736 handle->channels,
1737 handle->dither,
1740 handle->predivide,
1741 width,
1742 height,
1743 width,
1744 width);
1745 }
1746 }
1747
1748 if (handle->display_buffer) {
1749 if (handle->byte_buffer) {
1750 IMB_buffer_float_from_byte(handle->display_buffer,
1751 handle->byte_buffer,
1754 false,
1755 width,
1756 height,
1757 width,
1758 width);
1759 }
1760 else if (handle->buffer) {
1761 IMB_buffer_float_from_float(handle->display_buffer,
1762 handle->buffer,
1763 handle->channels,
1766 handle->predivide,
1767 width,
1768 height,
1769 width,
1770 width);
1771 }
1772 }
1773}
1774
1775static void *do_display_buffer_apply_thread(void *handle_v)
1776{
1777 DisplayBufferThread *handle = (DisplayBufferThread *)handle_v;
1778 ColormanageProcessor *cm_processor = handle->cm_processor;
1779 if (cm_processor == nullptr) {
1781 return nullptr;
1782 }
1783
1784 float *display_buffer = handle->display_buffer;
1785 uchar *display_buffer_byte = handle->display_buffer_byte;
1786 int channels = handle->channels;
1787 int width = handle->width;
1788 int height = handle->tot_line;
1789 float *linear_buffer = static_cast<float *>(MEM_mallocN(
1790 size_t(channels) * width * height * sizeof(float), "color conversion linear buffer"));
1791
1792 bool is_straight_alpha;
1793 display_buffer_apply_get_linear_buffer(handle, height, linear_buffer, &is_straight_alpha);
1794
1795 bool predivide = handle->predivide && (is_straight_alpha == false);
1796
1797 /* Apply processor (note: data buffers never get color space conversions). */
1798 if (!handle->is_data) {
1800 cm_processor, linear_buffer, width, height, channels, predivide);
1801 }
1802
1803 /* copy result to output buffers */
1804 if (display_buffer_byte) {
1805 /* do conversion */
1806 IMB_buffer_byte_from_float(display_buffer_byte,
1807 linear_buffer,
1808 channels,
1809 handle->dither,
1812 predivide,
1813 width,
1814 height,
1815 width,
1816 width);
1817 }
1818
1819 if (display_buffer) {
1820 memcpy(display_buffer, linear_buffer, size_t(width) * height * channels * sizeof(float));
1821
1822 if (is_straight_alpha && channels == 4) {
1823 const size_t i_last = size_t(width) * height;
1824 size_t i;
1825 float *fp;
1826
1827 for (i = 0, fp = display_buffer; i != i_last; i++, fp += channels) {
1829 }
1830 }
1831 }
1832
1833 MEM_freeN(linear_buffer);
1834
1835 return nullptr;
1836}
1837
1839 const float *buffer,
1840 uchar *byte_buffer,
1841 float *display_buffer,
1842 uchar *display_buffer_byte,
1843 ColormanageProcessor *cm_processor)
1844{
1846
1847 init_data.ibuf = ibuf;
1848 init_data.cm_processor = cm_processor;
1849 init_data.buffer = buffer;
1850 init_data.byte_buffer = byte_buffer;
1851 init_data.display_buffer = display_buffer;
1852 init_data.display_buffer_byte = display_buffer_byte;
1853
1854 if (ibuf->byte_buffer.colorspace != nullptr) {
1855 init_data.byte_colorspace = ibuf->byte_buffer.colorspace->name;
1856 }
1857 else {
1858 /* happens for viewer images, which are not so simple to determine where to
1859 * set image buffer's color spaces
1860 */
1861 init_data.byte_colorspace = global_role_default_byte;
1862 }
1863
1864 if (ibuf->float_buffer.colorspace != nullptr) {
1865 /* sequencer stores float buffers in non-linear space */
1866 init_data.float_colorspace = ibuf->float_buffer.colorspace->name;
1867 }
1868 else {
1869 init_data.float_colorspace = nullptr;
1870 }
1871
1873 sizeof(DisplayBufferThread),
1874 &init_data,
1877}
1878
1879/* Checks if given colorspace can be used for display as-is:
1880 * - View settings do not have extra curves, exposure, gamma or look applied, and
1881 * - Display colorspace is the same as given colorspace. */
1882static bool is_colorspace_same_as_display(const ColorSpace *colorspace,
1883 const ColorManagedViewSettings *view_settings,
1884 const ColorManagedDisplaySettings *display_settings)
1885{
1886 if ((view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) != 0 ||
1887 view_settings->exposure != 0.0f || view_settings->gamma != 1.0f)
1888 {
1889 return false;
1890 }
1891
1892 ColorManagedLook *look_descr = colormanage_look_get_named(view_settings->look);
1893 if (look_descr != nullptr && !STREQ(look_descr->process_space, "")) {
1894 return false;
1895 }
1896
1897 const char *from_colorspace = colorspace->name;
1898 const char *to_colorspace = get_display_colorspace_name(view_settings, display_settings);
1899 if (to_colorspace && STREQ(from_colorspace, to_colorspace)) {
1900 return true;
1901 }
1902
1903 return false;
1904}
1905
1907 ImBuf *ibuf,
1908 float *display_buffer,
1909 uchar *display_buffer_byte,
1910 const ColorManagedViewSettings *view_settings,
1911 const ColorManagedDisplaySettings *display_settings)
1912{
1913 ColormanageProcessor *cm_processor = nullptr;
1914 /* Check if we can skip colorspace transforms. */
1915 bool skip_transform = false;
1916 if (ibuf->float_buffer.data == nullptr && ibuf->byte_buffer.colorspace) {
1917 skip_transform = is_colorspace_same_as_display(
1918 ibuf->byte_buffer.colorspace, view_settings, display_settings);
1919 }
1920 if (ibuf->byte_buffer.data == nullptr && ibuf->float_buffer.colorspace) {
1921 skip_transform = is_colorspace_same_as_display(
1922 ibuf->float_buffer.colorspace, view_settings, display_settings);
1923 }
1924
1925 if (skip_transform == false) {
1926 cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
1927 }
1928
1930 ibuf->float_buffer.data,
1931 ibuf->byte_buffer.data,
1932 display_buffer,
1933 display_buffer_byte,
1934 cm_processor);
1935
1936 if (cm_processor) {
1938 }
1939}
1940
1942 uchar *display_buffer,
1943 const ColorManagedViewSettings *view_settings,
1944 const ColorManagedDisplaySettings *display_settings)
1945{
1947 ibuf, nullptr, display_buffer, view_settings, display_settings);
1948}
1949
1952/* -------------------------------------------------------------------- */
1967
1978
1979static void processor_transform_init_handle(void *handle_v,
1980 int start_line,
1981 int tot_line,
1982 void *init_data_v)
1983{
1986
1987 const int channels = init_data->channels;
1988 const int width = init_data->width;
1989 const bool predivide = init_data->predivide;
1990 const bool float_from_byte = init_data->float_from_byte;
1991
1992 const size_t offset = size_t(channels) * start_line * width;
1993
1994 memset(handle, 0, sizeof(ProcessorTransformThread));
1995
1996 handle->cm_processor = init_data->cm_processor;
1997
1998 if (init_data->byte_buffer != nullptr) {
1999 /* TODO(serge): Offset might be different for byte and float buffers. */
2000 handle->byte_buffer = init_data->byte_buffer + offset;
2001 }
2002 if (init_data->float_buffer != nullptr) {
2003 handle->float_buffer = init_data->float_buffer + offset;
2004 }
2005
2006 handle->width = width;
2007
2008 handle->start_line = start_line;
2009 handle->tot_line = tot_line;
2010
2011 handle->channels = channels;
2012 handle->predivide = predivide;
2013 handle->float_from_byte = float_from_byte;
2014}
2015
2016static void *do_processor_transform_thread(void *handle_v)
2017{
2019 uchar *byte_buffer = handle->byte_buffer;
2020 float *float_buffer = handle->float_buffer;
2021 const int channels = handle->channels;
2022 const int width = handle->width;
2023 const int height = handle->tot_line;
2024 const bool predivide = handle->predivide;
2025 const bool float_from_byte = handle->float_from_byte;
2026
2027 if (float_from_byte) {
2028 IMB_buffer_float_from_byte(float_buffer,
2029 byte_buffer,
2032 false,
2033 width,
2034 height,
2035 width,
2036 width);
2038 handle->cm_processor, float_buffer, width, height, channels, predivide);
2039 IMB_premultiply_rect_float(float_buffer, 4, width, height);
2040 }
2041 else {
2042 if (byte_buffer != nullptr) {
2044 handle->cm_processor, byte_buffer, width, height, channels);
2045 }
2046 if (float_buffer != nullptr) {
2048 handle->cm_processor, float_buffer, width, height, channels, predivide);
2049 }
2050 }
2051
2052 return nullptr;
2053}
2054
2056 float *float_buffer,
2057 const int width,
2058 const int height,
2059 const int channels,
2060 ColormanageProcessor *cm_processor,
2061 const bool predivide,
2062 const bool float_from_byte)
2063{
2065
2066 init_data.cm_processor = cm_processor;
2067 init_data.byte_buffer = byte_buffer;
2068 init_data.float_buffer = float_buffer;
2069 init_data.width = width;
2070 init_data.height = height;
2071 init_data.channels = channels;
2072 init_data.predivide = predivide;
2073 init_data.float_from_byte = float_from_byte;
2074
2077 &init_data,
2080}
2081
2084/* -------------------------------------------------------------------- */
2088/* Convert the whole buffer from specified by name color space to another -
2089 * internal implementation. */
2090static void colormanagement_transform_ex(uchar *byte_buffer,
2091 float *float_buffer,
2092 int width,
2093 int height,
2094 int channels,
2095 const char *from_colorspace,
2096 const char *to_colorspace,
2097 bool predivide,
2098 bool do_threaded)
2099{
2100 if (from_colorspace[0] == '\0') {
2101 return;
2102 }
2103
2104 if (STREQ(from_colorspace, to_colorspace)) {
2105 /* if source and destination color spaces are identical, skip
2106 * threading overhead and simply do nothing
2107 */
2108 return;
2109 }
2110
2112 from_colorspace, to_colorspace);
2113 if (IMB_colormanagement_processor_is_noop(cm_processor)) {
2115 return;
2116 }
2117
2118 if (do_threaded) {
2120 byte_buffer, float_buffer, width, height, channels, cm_processor, predivide, false);
2121 }
2122 else {
2123 if (byte_buffer != nullptr) {
2124 IMB_colormanagement_processor_apply_byte(cm_processor, byte_buffer, width, height, channels);
2125 }
2126 if (float_buffer != nullptr) {
2128 cm_processor, float_buffer, width, height, channels, predivide);
2129 }
2130 }
2131
2133}
2134
2136 int width,
2137 int height,
2138 int channels,
2139 const char *from_colorspace,
2140 const char *to_colorspace,
2141 bool predivide)
2142{
2144 nullptr, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, false);
2145}
2146
2148 int width,
2149 int height,
2150 int channels,
2151 const char *from_colorspace,
2152 const char *to_colorspace,
2153 bool predivide)
2154{
2156 nullptr, buffer, width, height, channels, from_colorspace, to_colorspace, predivide, true);
2157}
2158
2160 int width,
2161 int height,
2162 int channels,
2163 const char *from_colorspace,
2164 const char *to_colorspace)
2165{
2167 buffer, nullptr, width, height, channels, from_colorspace, to_colorspace, false, false);
2168}
2170 int width,
2171 int height,
2172 int channels,
2173 const char *from_colorspace,
2174 const char *to_colorspace)
2175{
2177 buffer, nullptr, width, height, channels, from_colorspace, to_colorspace, false, true);
2178}
2179
2181 uchar *byte_buffer,
2182 int width,
2183 int height,
2184 int channels,
2185 const char *from_colorspace,
2186 const char *to_colorspace)
2187{
2188 IMB_buffer_float_from_byte(float_buffer,
2189 byte_buffer,
2192 true,
2193 width,
2194 height,
2195 width,
2196 width);
2198 float_buffer, width, height, channels, from_colorspace, to_colorspace, true);
2199}
2201 uchar *byte_buffer,
2202 int width,
2203 int height,
2204 int channels,
2205 const char *from_colorspace,
2206 const char *to_colorspace)
2207{
2208 using namespace blender;
2209 ColormanageProcessor *cm_processor;
2210 if (from_colorspace == nullptr || from_colorspace[0] == '\0') {
2211 return;
2212 }
2213 if (STREQ(from_colorspace, to_colorspace) && channels == 4) {
2214 /* Color spaces are the same, just do a simple byte->float conversion. */
2215 int64_t pixel_count = int64_t(width) * height;
2216 threading::parallel_for(IndexRange(pixel_count), 256 * 1024, [&](IndexRange pix_range) {
2217 float *dst_ptr = float_buffer + pix_range.first() * channels;
2218 uchar *src_ptr = byte_buffer + pix_range.first() * channels;
2219 for ([[maybe_unused]] const int i : pix_range) {
2220 /* Equivalent of rgba_uchar_to_float + premultiply. */
2221 float cr = float(src_ptr[0]) * (1.0f / 255.0f);
2222 float cg = float(src_ptr[1]) * (1.0f / 255.0f);
2223 float cb = float(src_ptr[2]) * (1.0f / 255.0f);
2224 float ca = float(src_ptr[3]) * (1.0f / 255.0f);
2225 dst_ptr[0] = cr * ca;
2226 dst_ptr[1] = cg * ca;
2227 dst_ptr[2] = cb * ca;
2228 dst_ptr[3] = ca;
2229 src_ptr += 4;
2230 dst_ptr += 4;
2231 }
2232 });
2233 return;
2234 }
2235 cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
2237 byte_buffer, float_buffer, width, height, channels, cm_processor, false, true);
2239}
2240
2242 const char *from_colorspace,
2243 const char *to_colorspace)
2244{
2245 ColormanageProcessor *cm_processor;
2246
2247 if (from_colorspace[0] == '\0') {
2248 return;
2249 }
2250
2251 if (STREQ(from_colorspace, to_colorspace)) {
2252 /* if source and destination color spaces are identical, skip
2253 * threading overhead and simply do nothing
2254 */
2255 return;
2256 }
2257
2258 cm_processor = IMB_colormanagement_colorspace_processor_new(from_colorspace, to_colorspace);
2259
2260 IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
2261
2263}
2264
2266{
2267 if (colorspace == nullptr) { /* should never happen */
2268 printf("%s: perform conversion from unknown color space\n", __func__);
2269 return;
2270 }
2272 if (processor == nullptr) {
2273 return;
2274 }
2275 OCIO_cpuProcessorApplyRGB(processor, pixel);
2276}
2277
2279{
2280 if (colorspace == nullptr) { /* should never happen */
2281 printf("%s: perform conversion from unknown color space\n", __func__);
2282 return;
2283 }
2285 if (processor == nullptr) {
2286 return;
2287 }
2288 OCIO_cpuProcessorApplyRGB(processor, pixel);
2289}
2290
2292 bool predivide,
2293 ColorSpace *colorspace)
2294{
2295 if (colorspace == nullptr) { /* should never happen */
2296 printf("%s: perform conversion from unknown color space\n", __func__);
2297 return;
2298 }
2300 if (processor == nullptr) {
2301 return;
2302 }
2303 if (predivide) {
2304 OCIO_cpuProcessorApplyRGBA_predivide(processor, pixel);
2305 }
2306 else {
2307 OCIO_cpuProcessorApplyRGBA(processor, pixel);
2308 }
2309}
2310
2312 float *buffer, int width, int height, int channels, ColorSpace *colorspace, bool predivide)
2313{
2314 if (colorspace == nullptr) { /* should never happen */
2315 printf("%s: perform conversion from unknown color space\n", __func__);
2316 return;
2317 }
2319 if (processor == nullptr) {
2320 return;
2321 }
2322 OCIO_PackedImageDesc *img = OCIO_createOCIO_PackedImageDesc(buffer,
2323 width,
2324 height,
2325 channels,
2326 sizeof(float),
2327 size_t(channels) * sizeof(float),
2328 size_t(channels) * sizeof(float) *
2329 width);
2330
2331 if (predivide) {
2332 OCIO_cpuProcessorApply_predivide(processor, img);
2333 }
2334 else {
2335 OCIO_cpuProcessorApply(processor, img);
2336 }
2337
2339}
2340
2342 float *buffer, int width, int height, int channels, ColorSpace *colorspace)
2343{
2344 if (colorspace == nullptr) { /* should never happen */
2345 printf("%s: perform conversion from unknown color space\n", __func__);
2346 return;
2347 }
2349 if (processor == nullptr) {
2350 return;
2351 }
2352 OCIO_PackedImageDesc *img = OCIO_createOCIO_PackedImageDesc(buffer,
2353 width,
2354 height,
2355 channels,
2356 sizeof(float),
2357 size_t(channels) * sizeof(float),
2358 size_t(channels) * sizeof(float) *
2359 width);
2360 OCIO_cpuProcessorApply(processor, img);
2362}
2363
2365 const int offset_x,
2366 const int offset_y,
2367 const int width,
2368 const int height,
2369 const ImBuf *ibuf,
2370 const bool store_premultiplied)
2371{
2372 /* Byte buffer storage, only for sRGB, scene linear and data texture since other
2373 * color space conversions can't be done on the GPU. */
2375 BLI_assert(ibuf->float_buffer.data == nullptr);
2379
2380 const uchar *in_buffer = ibuf->byte_buffer.data;
2381 const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
2382
2383 for (int y = 0; y < height; y++) {
2384 const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
2385 const size_t out_offset = y * width;
2386 const uchar *in = in_buffer + in_offset * 4;
2387 uchar *out = out_buffer + out_offset * 4;
2388
2389 if (use_premultiply) {
2390 /* Premultiply only. */
2391 for (int x = 0; x < width; x++, in += 4, out += 4) {
2392 out[0] = (in[0] * in[3]) >> 8;
2393 out[1] = (in[1] * in[3]) >> 8;
2394 out[2] = (in[2] * in[3]) >> 8;
2395 out[3] = in[3];
2396 }
2397 }
2398 else {
2399 /* Copy only. */
2400 for (int x = 0; x < width; x++, in += 4, out += 4) {
2401 out[0] = in[0];
2402 out[1] = in[1];
2403 out[2] = in[2];
2404 out[3] = in[3];
2405 }
2406 }
2407 }
2408}
2409
2418
2419static void imbuf_byte_to_float_cb(void *__restrict userdata,
2420 const int y,
2421 const TaskParallelTLS *__restrict /*tls*/)
2422{
2423 ImbufByteToFloatData *data = static_cast<ImbufByteToFloatData *>(userdata);
2424
2425 const size_t in_offset = data->offset + y * data->stride;
2426 const size_t out_offset = y * data->width;
2427 const uchar *in = data->in_buffer + in_offset * 4;
2428 float *out = data->out_buffer + out_offset * 4;
2429
2430 /* Convert to scene linear, to sRGB and premultiply. */
2431 for (int x = 0; x < data->width; x++, in += 4, out += 4) {
2432 float pixel[4];
2433 rgba_uchar_to_float(pixel, in);
2434 if (data->processor) {
2435 OCIO_cpuProcessorApplyRGB(data->processor, pixel);
2436 }
2437 else {
2438 srgb_to_linearrgb_v3_v3(pixel, pixel);
2439 }
2440 if (data->use_premultiply) {
2441 mul_v3_fl(pixel, pixel[3]);
2442 }
2443 copy_v4_v4(out, pixel);
2444 }
2445}
2446
2448 const int offset_x,
2449 const int offset_y,
2450 const int width,
2451 const int height,
2452 const ImBuf *ibuf,
2453 const bool store_premultiplied)
2454{
2455 /* Float texture are stored in scene linear color space, with premultiplied
2456 * alpha depending on the image alpha mode. */
2457 if (ibuf->float_buffer.data) {
2458 /* Float source buffer. */
2459 const float *in_buffer = ibuf->float_buffer.data;
2460 const int in_channels = ibuf->channels;
2461 const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied;
2462
2463 for (int y = 0; y < height; y++) {
2464 const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
2465 const size_t out_offset = y * width;
2466 const float *in = in_buffer + in_offset * in_channels;
2467 float *out = out_buffer + out_offset * 4;
2468
2469 if (in_channels == 1) {
2470 /* Copy single channel. */
2471 for (int x = 0; x < width; x++, in += 1, out += 4) {
2472 out[0] = in[0];
2473 out[1] = in[0];
2474 out[2] = in[0];
2475 out[3] = in[0];
2476 }
2477 }
2478 else if (in_channels == 3) {
2479 /* Copy RGB. */
2480 for (int x = 0; x < width; x++, in += 3, out += 4) {
2481 out[0] = in[0];
2482 out[1] = in[1];
2483 out[2] = in[2];
2484 out[3] = 1.0f;
2485 }
2486 }
2487 else if (in_channels == 4) {
2488 /* Copy or convert RGBA. */
2489 if (use_unpremultiply) {
2490 for (int x = 0; x < width; x++, in += 4, out += 4) {
2491 premul_to_straight_v4_v4(out, in);
2492 }
2493 }
2494 else {
2495 memcpy(out, in, sizeof(float[4]) * width);
2496 }
2497 }
2498 }
2499 }
2500 else {
2501 /* Byte source buffer. */
2502 const uchar *in_buffer = ibuf->byte_buffer.data;
2503 const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
2504
2507 ibuf->byte_buffer.colorspace) :
2508 nullptr;
2509
2510 ImbufByteToFloatData data = {};
2511 data.processor = processor;
2512 data.width = width;
2513 data.offset = offset_y * ibuf->x + offset_x;
2514 data.stride = ibuf->x;
2515 data.in_buffer = in_buffer;
2516 data.out_buffer = out_buffer;
2517 data.use_premultiply = use_premultiply;
2518
2519 TaskParallelSettings settings;
2521 settings.use_threading = (height > 128);
2522 BLI_task_parallel_range(0, height, &data, imbuf_byte_to_float_cb, &settings);
2523 }
2524}
2525
2527 const float scene_linear[3])
2528{
2530 /* Create processor if none exists. */
2532
2534 OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
2536
2537 if (processor != nullptr) {
2539 OCIO_processorRelease(processor);
2540 }
2541 else {
2543 }
2544 }
2545
2547 }
2548
2549 copy_v3_v3(color_picking, scene_linear);
2550
2553 }
2554}
2555
2557 const float color_picking[3])
2558{
2560 /* Create processor if none exists. */
2562
2564 OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(
2566
2567 if (processor != nullptr) {
2569 OCIO_processorRelease(processor);
2570 }
2571 else {
2573 }
2574 }
2575
2577 }
2578
2579 copy_v3_v3(scene_linear, color_picking);
2580
2583 }
2584}
2585
2587{
2589
2590 if (processor != nullptr) {
2591 OCIO_cpuProcessorApplyRGB(processor, pixel);
2592 }
2593}
2594
2596{
2598
2599 if (processor != nullptr) {
2600 OCIO_cpuProcessorApplyRGB(processor, pixel);
2601 }
2602}
2603
2605 float result[4],
2606 const float pixel[4],
2607 const ColorManagedViewSettings *view_settings,
2608 const ColorManagedDisplaySettings *display_settings)
2609{
2610 ColormanageProcessor *cm_processor;
2611
2612 copy_v4_v4(result, pixel);
2613
2614 cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
2615 IMB_colormanagement_processor_apply_v4(cm_processor, result);
2617}
2618
2620 float result[3],
2621 const float pixel[3],
2622 const ColorManagedViewSettings *view_settings,
2623 const ColorManagedDisplaySettings *display_settings)
2624{
2625 ColormanageProcessor *cm_processor;
2626
2627 copy_v3_v3(result, pixel);
2628
2629 cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
2630 IMB_colormanagement_processor_apply_v3(cm_processor, result);
2632}
2633
2635 ImBuf *ibuf,
2636 const ColorManagedViewSettings *view_settings,
2637 const ColorManagedDisplaySettings *display_settings,
2638 bool make_byte)
2639{
2640 if (!ibuf->byte_buffer.data && make_byte) {
2641 imb_addrectImBuf(ibuf);
2642 }
2643
2645 ibuf, ibuf->float_buffer.data, ibuf->byte_buffer.data, view_settings, display_settings);
2646}
2647
2649 ImBuf *ibuf,
2650 const ColorManagedViewSettings *view_settings,
2651 const ColorManagedDisplaySettings *display_settings)
2652{
2653 colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false);
2654}
2655
2656static ImBuf *imbuf_ensure_editable(ImBuf *ibuf, ImBuf *colormanaged_ibuf, bool allocate_result)
2657{
2658 if (colormanaged_ibuf != ibuf) {
2659 /* Is already an editable copy. */
2660 return colormanaged_ibuf;
2661 }
2662
2663 if (allocate_result) {
2664 /* Copy full image buffer. */
2665 colormanaged_ibuf = IMB_dupImBuf(ibuf);
2666 IMB_metadata_copy(colormanaged_ibuf, ibuf);
2667 return colormanaged_ibuf;
2668 }
2669
2670 /* Render pipeline is constructing image buffer itself,
2671 * but it's re-using byte and float buffers from render result make copy of this buffers
2672 * here sine this buffers would be transformed to other color space here. */
2675
2676 return ibuf;
2677}
2678
2680 bool save_as_render,
2681 bool allocate_result,
2682 const ImageFormatData *image_format)
2683{
2684 ImBuf *colormanaged_ibuf = ibuf;
2685
2686 /* Update byte buffer if exists but invalid. */
2687 if (ibuf->float_buffer.data && ibuf->byte_buffer.data &&
2689 {
2690 IMB_rect_from_float(ibuf);
2692 }
2693
2694 /* Detect if we are writing to a file format that needs a linear float buffer. */
2695 const bool linear_float_output = BKE_imtype_requires_linear_float(image_format->imtype);
2696
2697 /* Detect if we are writing output a byte buffer, which we would need to create
2698 * with color management conversions applied. This may be for either applying the
2699 * display transform for renders, or a user specified color space for the file. */
2700 const bool byte_output = BKE_image_format_is_byte(image_format);
2701
2702 /* If we're saving from RGBA to RGB buffer then it's not so much useful to just ignore alpha --
2703 * it leads to bad artifacts especially when saving byte images.
2704 *
2705 * What we do here is we're overlaying our image on top of background color (which is currently
2706 * black). This is quite much the same as what Gimp does and it seems to be what artists expects
2707 * from saving.
2708 *
2709 * Do a conversion here, so image format writers could happily assume all the alpha tricks were
2710 * made already. helps keep things locally here, not spreading it to all possible image writers
2711 * we've got.
2712 */
2713 if (image_format->planes != R_IMF_PLANES_RGBA) {
2714 float color[3] = {0, 0, 0};
2715
2716 colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
2717
2718 if (colormanaged_ibuf->float_buffer.data && colormanaged_ibuf->channels == 4) {
2720 colormanaged_ibuf->float_buffer.data, colormanaged_ibuf->x, colormanaged_ibuf->y, color);
2721 }
2722
2723 if (colormanaged_ibuf->byte_buffer.data) {
2725 colormanaged_ibuf->byte_buffer.data, colormanaged_ibuf->x, colormanaged_ibuf->y, color);
2726 }
2727 }
2728
2729 if (save_as_render && !linear_float_output) {
2730 /* Render output: perform conversion to display space using view transform. */
2731 colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
2732
2734 &image_format->view_settings,
2735 &image_format->display_settings,
2736 byte_output);
2737
2738 if (colormanaged_ibuf->float_buffer.data) {
2739 /* Float buffer isn't linear anymore,
2740 * image format write callback should check for this flag and assume
2741 * no space conversion should happen if ibuf->float_buffer.colorspace != nullptr. */
2743 &image_format->view_settings, &image_format->display_settings);
2744 if (byte_output) {
2745 colormanaged_ibuf->byte_buffer.colorspace = colormanaged_ibuf->float_buffer.colorspace;
2746 }
2747 }
2748 }
2749 else {
2750 /* Linear render or regular file output: conversion between two color spaces. */
2751
2752 /* Detect which color space we need to convert between. */
2753 const char *from_colorspace = (ibuf->float_buffer.data &&
2754 !(byte_output && ibuf->byte_buffer.data)) ?
2755 /* From float buffer. */
2756 (ibuf->float_buffer.colorspace) ?
2759 /* From byte buffer. */
2760 (ibuf->byte_buffer.colorspace) ?
2761 ibuf->byte_buffer.colorspace->name :
2763
2764 const char *to_colorspace = image_format->linear_colorspace_settings.name;
2765
2766 /* TODO: can we check with OCIO if color spaces are the same but have different names? */
2767 if (to_colorspace[0] == '\0' || STREQ(from_colorspace, to_colorspace)) {
2768 /* No conversion needed, but may still need to allocate byte buffer for output. */
2769 if (byte_output && !ibuf->byte_buffer.data) {
2771 IMB_rect_from_float(ibuf);
2772 }
2773 }
2774 else {
2775 /* Color space conversion needed. */
2776 colormanaged_ibuf = imbuf_ensure_editable(ibuf, colormanaged_ibuf, allocate_result);
2777
2778 if (byte_output) {
2780 to_colorspace);
2781
2782 if (colormanaged_ibuf->byte_buffer.data) {
2783 /* Byte to byte. */
2785 colormanaged_ibuf->x,
2786 colormanaged_ibuf->y,
2787 colormanaged_ibuf->channels,
2788 from_colorspace,
2789 to_colorspace);
2790 }
2791 else {
2792 /* Float to byte. */
2793 IMB_rect_from_float(colormanaged_ibuf);
2794 }
2795 }
2796 else {
2797 if (!colormanaged_ibuf->float_buffer.data) {
2798 /* Byte to float. */
2799 IMB_float_from_rect(colormanaged_ibuf);
2800 imb_freerectImBuf(colormanaged_ibuf);
2801
2802 /* This conversion always goes to scene linear. */
2803 from_colorspace = global_role_scene_linear;
2804 }
2805
2806 if (colormanaged_ibuf->float_buffer.data) {
2807 /* Float to float. */
2809 colormanaged_ibuf->x,
2810 colormanaged_ibuf->y,
2811 colormanaged_ibuf->channels,
2812 from_colorspace,
2813 to_colorspace,
2814 false);
2815
2817 to_colorspace);
2818 }
2819 }
2820 }
2821 }
2822
2823 return colormanaged_ibuf;
2824}
2825
2828/* -------------------------------------------------------------------- */
2833 const ColorManagedViewSettings *view_settings,
2834 const ColorManagedDisplaySettings *display_settings,
2835 void **cache_handle)
2836{
2837 uchar *display_buffer;
2838 size_t buffer_size;
2839 ColormanageCacheViewSettings cache_view_settings;
2840 ColormanageCacheDisplaySettings cache_display_settings;
2841 ColorManagedViewSettings default_view_settings;
2842 const ColorManagedViewSettings *applied_view_settings;
2843
2844 *cache_handle = nullptr;
2845
2846 if (!ibuf->x || !ibuf->y) {
2847 return nullptr;
2848 }
2849
2850 if (view_settings) {
2851 applied_view_settings = view_settings;
2852 }
2853 else {
2854 /* If no view settings were specified, use default ones, which will
2855 * attempt not to do any extra color correction. */
2856 IMB_colormanagement_init_default_view_settings(&default_view_settings, display_settings);
2857 applied_view_settings = &default_view_settings;
2858 }
2859
2860 /* No float buffer and byte buffer is already in display space, let's just use it. */
2861 if (ibuf->float_buffer.data == nullptr && ibuf->byte_buffer.colorspace && ibuf->channels == 4) {
2863 ibuf->byte_buffer.colorspace, applied_view_settings, display_settings))
2864 {
2865 return ibuf->byte_buffer.data;
2866 }
2867 }
2868
2869 colormanage_view_settings_to_cache(ibuf, &cache_view_settings, applied_view_settings);
2870 colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
2871
2872 if (ibuf->invalid_rect.xmin != ibuf->invalid_rect.xmax) {
2873 if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0) {
2875 ibuf->float_buffer.data,
2876 ibuf->byte_buffer.data,
2877 ibuf->x,
2878 0,
2879 0,
2880 applied_view_settings,
2881 display_settings,
2882 ibuf->invalid_rect.xmin,
2883 ibuf->invalid_rect.ymin,
2884 ibuf->invalid_rect.xmax,
2885 ibuf->invalid_rect.ymax);
2886 }
2887
2888 BLI_rcti_init(&ibuf->invalid_rect, 0, 0, 0, 0);
2889 }
2890
2892
2893 /* ensure color management bit fields exists */
2894 if (!ibuf->display_buffer_flags) {
2895 ibuf->display_buffer_flags = static_cast<uint *>(
2896 MEM_callocN(sizeof(uint) * global_tot_display, "imbuf display_buffer_flags"));
2897 }
2898 else if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) {
2899 /* all display buffers were marked as invalid from other areas,
2900 * now propagate this flag to internal color management routines
2901 */
2902 memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(uint));
2903
2904 ibuf->userflags &= ~IB_DISPLAY_BUFFER_INVALID;
2905 }
2906
2907 display_buffer = colormanage_cache_get(
2908 ibuf, &cache_view_settings, &cache_display_settings, cache_handle);
2909
2910 if (display_buffer) {
2912 return display_buffer;
2913 }
2914
2915 buffer_size = DISPLAY_BUFFER_CHANNELS * size_t(ibuf->x) * ibuf->y * sizeof(char);
2916 display_buffer = static_cast<uchar *>(MEM_callocN(buffer_size, "imbuf display buffer"));
2917
2919 ibuf, display_buffer, applied_view_settings, display_settings);
2920
2922 ibuf, &cache_view_settings, &cache_display_settings, display_buffer, cache_handle);
2923
2925
2926 return display_buffer;
2927}
2928
2929uchar *IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
2930{
2931 ColorManagedViewSettings *view_settings;
2932 ColorManagedDisplaySettings *display_settings;
2933
2934 IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
2935
2936 return IMB_display_buffer_acquire(ibuf, view_settings, display_settings, cache_handle);
2937}
2938
2940 float *linear_buffer,
2941 int width,
2942 int height,
2943 int channels,
2944 const ColorManagedViewSettings *view_settings,
2945 const ColorManagedDisplaySettings *display_settings,
2946 bool predivide)
2947{
2948 float *buffer;
2950 display_settings);
2951
2952 buffer = static_cast<float *>(MEM_mallocN(size_t(channels) * width * height * sizeof(float),
2953 "display transform temp buffer"));
2954 memcpy(buffer, linear_buffer, size_t(channels) * width * height * sizeof(float));
2955
2956 IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
2957
2959
2960 IMB_buffer_byte_from_float(display_buffer,
2961 buffer,
2962 channels,
2963 0.0f,
2966 false,
2967 width,
2968 height,
2969 width,
2970 width);
2971
2972 MEM_freeN(buffer);
2973}
2974
2975void IMB_display_buffer_transform_apply_float(float *float_display_buffer,
2976 float *linear_buffer,
2977 int width,
2978 int height,
2979 int channels,
2980 const ColorManagedViewSettings *view_settings,
2981 const ColorManagedDisplaySettings *display_settings,
2982 bool predivide)
2983{
2984 float *buffer;
2986 display_settings);
2987
2988 buffer = static_cast<float *>(MEM_mallocN(size_t(channels) * width * height * sizeof(float),
2989 "display transform temp buffer"));
2990 memcpy(buffer, linear_buffer, size_t(channels) * width * height * sizeof(float));
2991
2992 IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
2993
2995
2996 memcpy(float_display_buffer, buffer, size_t(channels) * width * height * sizeof(float));
2997 MEM_freeN(buffer);
2998}
2999
3000void IMB_display_buffer_release(void *cache_handle)
3001{
3002 if (cache_handle) {
3004
3006
3008 }
3009}
3010
3013/* -------------------------------------------------------------------- */
3018{
3019 OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
3020 const char *display_name;
3021
3022 display_name = OCIO_configGetDefaultDisplay(config);
3023
3024 OCIO_configRelease(config);
3025
3026 return display_name;
3027}
3028
3030{
3031 const char *display_name = colormanage_display_get_default_name();
3032
3033 if (display_name[0] == '\0') {
3034 return nullptr;
3035 }
3036
3037 return colormanage_display_get_named(display_name);
3038}
3039
3041{
3042 ColorManagedDisplay *display;
3043 int index = 0;
3044
3045 if (global_displays.last) {
3046 ColorManagedDisplay *last_display = static_cast<ColorManagedDisplay *>(global_displays.last);
3047
3048 index = last_display->index;
3049 }
3050
3051 display = MEM_cnew<ColorManagedDisplay>("ColorManagedDisplay");
3052
3053 display->index = index + 1;
3054
3055 STRNCPY(display->name, name);
3056
3057 BLI_addtail(&global_displays, display);
3058
3059 return display;
3060}
3061
3063{
3065 if (STREQ(display->name, name)) {
3066 return display;
3067 }
3068 }
3069
3070 return nullptr;
3071}
3072
3074{
3075 /* display indices are 1-based */
3076 return static_cast<ColorManagedDisplay *>(BLI_findlink(&global_displays, index - 1));
3077}
3078
3080{
3081 ColorManagedDisplay *display;
3082
3083 display = colormanage_display_get_named(name);
3084
3085 if (display) {
3086 return display->index;
3087 }
3088
3089 return 0;
3090}
3091
3093{
3094 ColorManagedDisplay *display;
3095
3096 display = colormanage_display_get_indexed(index);
3097
3098 if (display) {
3099 return display->name;
3100 }
3101
3102 return nullptr;
3103}
3104
3106{
3108
3109 return display->name;
3110}
3111
3116
3118{
3119 if (colormanage_display_get_named("None") != nullptr) {
3120 return "None";
3121 }
3122
3124}
3125
3131
3134/* -------------------------------------------------------------------- */
3139{
3140 OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
3141 const char *name = OCIO_configGetDefaultView(config, display->name);
3142
3143 OCIO_configRelease(config);
3144
3145 return name;
3146}
3147
3149{
3150 const char *name = colormanage_view_get_default_name(display);
3151
3152 if (!name || name[0] == '\0') {
3153 return nullptr;
3154 }
3155
3156 return colormanage_view_get_named(name);
3157}
3158
3160{
3162 int index = global_tot_view;
3163
3164 view = MEM_cnew<ColorManagedView>("ColorManagedView");
3165 view->index = index + 1;
3166 STRNCPY(view->name, name);
3167
3168 BLI_addtail(&global_views, view);
3169
3171
3172 return view;
3173}
3174
3176{
3178 if (STREQ(view->name, name)) {
3179 return view;
3180 }
3181 }
3182
3183 return nullptr;
3184}
3185
3187{
3188 /* view transform indices are 1-based */
3189 return static_cast<ColorManagedView *>(BLI_findlink(&global_views, index - 1));
3190}
3191
3193 const char *name)
3194{
3195 ColorManagedDisplay *display = colormanage_display_get_named(display_name);
3196 if (display == nullptr) {
3197 return nullptr;
3198 }
3199 LISTBASE_FOREACH (LinkData *, view_link, &display->views) {
3200 ColorManagedView *view = static_cast<ColorManagedView *>(view_link->data);
3201 if (STRCASEEQ(name, view->name)) {
3202 return view;
3203 }
3204 }
3205 return nullptr;
3206}
3207
3209{
3211
3212 if (view) {
3213 return view->index;
3214 }
3215
3216 return 0;
3217}
3218
3220{
3222
3223 if (view) {
3224 return view->name;
3225 }
3226
3227 return nullptr;
3228}
3229
3230const char *IMB_colormanagement_view_get_default_name(const char *display_name)
3231{
3232 ColorManagedDisplay *display = colormanage_display_get_named(display_name);
3233 ColorManagedView *view = nullptr;
3234
3235 if (display) {
3236 view = colormanage_view_get_default(display);
3237 }
3238
3239 if (view) {
3240 return view->name;
3241 }
3242
3243 return nullptr;
3244}
3245
3246const char *IMB_colormanagement_view_get_raw_or_default_name(const char *display_name)
3247{
3248 ColorManagedDisplay *display = colormanage_display_get_named(display_name);
3249 if (!display) {
3250 return nullptr;
3251 }
3252
3253 ColorManagedView *view = nullptr;
3254
3255 if (!view) {
3256 view = colormanage_view_get_named_for_display(display_name, "Raw");
3257 }
3258
3259 if (!view) {
3260 view = colormanage_view_get_default(display);
3261 }
3262
3263 if (!view) {
3264 return nullptr;
3265 }
3266
3267 return view->name;
3268}
3269
3272/* -------------------------------------------------------------------- */
3276static void colormanage_description_strip(char *description)
3277{
3278 int i, n;
3279
3280 for (i = int(strlen(description)) - 1; i >= 0; i--) {
3281 if (ELEM(description[i], '\r', '\n')) {
3282 description[i] = '\0';
3283 }
3284 else {
3285 break;
3286 }
3287 }
3288
3289 for (i = 0, n = strlen(description); i < n; i++) {
3290 if (ELEM(description[i], '\r', '\n')) {
3291 description[i] = ' ';
3292 }
3293 }
3294}
3295
3297 const char *description,
3298 bool is_invertible,
3299 bool is_data)
3300{
3301 ColorSpace *colorspace, *prev_space;
3302 int counter = 1;
3303
3304 colorspace = MEM_cnew<ColorSpace>("ColorSpace");
3305
3306 STRNCPY(colorspace->name, name);
3307
3308 if (description) {
3309 STRNCPY(colorspace->description, description);
3310
3312 }
3313
3314 colorspace->is_invertible = is_invertible;
3315 colorspace->is_data = is_data;
3316
3317 for (prev_space = static_cast<ColorSpace *>(global_colorspaces.first); prev_space;
3318 prev_space = prev_space->next)
3319 {
3320 if (BLI_strcasecmp(prev_space->name, colorspace->name) > 0) {
3321 break;
3322 }
3323
3324 prev_space->index = counter++;
3325 }
3326
3327 if (!prev_space) {
3328 BLI_addtail(&global_colorspaces, colorspace);
3329 }
3330 else {
3331 BLI_insertlinkbefore(&global_colorspaces, prev_space, colorspace);
3332 }
3333
3334 colorspace->index = counter++;
3335 for (; prev_space; prev_space = prev_space->next) {
3336 prev_space->index = counter++;
3337 }
3338
3340
3341 return colorspace;
3342}
3343
3345{
3347 if (STREQ(colorspace->name, name)) {
3348 return colorspace;
3349 }
3350
3351 for (int i = 0; i < colorspace->num_aliases; i++) {
3352 if (STREQ(colorspace->aliases[i], name)) {
3353 return colorspace;
3354 }
3355 }
3356 }
3357
3358 return nullptr;
3359}
3360
3362{
3363 const char *role_colorspace = IMB_colormanagement_role_colorspace_name_get(role);
3364
3365 return colormanage_colorspace_get_named(role_colorspace);
3366}
3367
3369{
3370 /* color space indices are 1-based */
3371 return static_cast<ColorSpace *>(BLI_findlink(&global_colorspaces, index - 1));
3372}
3373
3375{
3376 ColorSpace *colorspace = colormanage_colorspace_get_named(name);
3377
3378 if (colorspace) {
3379 return colorspace->index;
3380 }
3381
3382 return 0;
3383}
3384
3386{
3388
3389 if (colorspace) {
3390 return colorspace->name;
3391 }
3392
3393 return "";
3394}
3395
3397{
3398 return colorspace->name;
3399}
3400
3402 ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
3403{
3404 /* Don't modify non-color data space, it does not change with file type. */
3405 ColorSpace *colorspace = colormanage_colorspace_get_named(colorspace_settings->name);
3406
3407 if (colorspace && colorspace->is_data) {
3408 return;
3409 }
3410
3411 /* Get color space from file type. */
3412 const ImFileType *type = IMB_file_type_from_ibuf(ibuf);
3413 if (type != nullptr) {
3414 if (type->save != nullptr) {
3415 const char *role_colorspace = IMB_colormanagement_role_colorspace_name_get(
3416 type->default_save_role);
3417 STRNCPY(colorspace_settings->name, role_colorspace);
3418 }
3419 }
3420}
3421
3424/* -------------------------------------------------------------------- */
3428ColorManagedLook *colormanage_look_add(const char *name, const char *process_space, bool is_noop)
3429{
3430 ColorManagedLook *look;
3431 int index = global_tot_looks;
3432
3433 look = MEM_cnew<ColorManagedLook>("ColorManagedLook");
3434 look->index = index + 1;
3435 STRNCPY(look->name, name);
3436 STRNCPY(look->ui_name, name);
3437 STRNCPY(look->process_space, process_space);
3438 look->is_noop = is_noop;
3439
3440 /* Detect view specific looks. */
3441 const char *separator_offset = strstr(look->name, " - ");
3442 if (separator_offset) {
3443 BLI_strncpy(look->view, look->name, separator_offset - look->name + 1);
3444 STRNCPY(look->ui_name, separator_offset + strlen(" - "));
3445 }
3446
3447 BLI_addtail(&global_looks, look);
3448
3450
3451 return look;
3452}
3453
3455{
3457 if (STREQ(look->name, name)) {
3458 return look;
3459 }
3460 }
3461
3462 return nullptr;
3463}
3464
3466{
3467 /* look indices are 1-based */
3468 return static_cast<ColorManagedLook *>(BLI_findlink(&global_looks, index - 1));
3469}
3470
3472{
3474
3475 if (look) {
3476 return look->index;
3477 }
3478
3479 return 0;
3480}
3481
3483{
3484 ColorManagedLook *look;
3485
3486 look = colormanage_look_get_indexed(index);
3487
3488 if (look) {
3489 return look->name;
3490 }
3491
3492 return nullptr;
3493}
3494
3496{
3497 const ColorManagedLook *default_look = static_cast<const ColorManagedLook *>(global_looks.first);
3498 if (!default_look) {
3499 return "";
3500 }
3501
3502 return default_look->name;
3503}
3504
3505const char *IMB_colormanagement_look_validate_for_view(const char *view_name,
3506 const char *look_name)
3507{
3508 ColorManagedLook *look_descr = colormanage_look_get_named(look_name);
3509 if (!look_descr) {
3510 return look_name;
3511 }
3512
3513 /* Keep same look if compatible. */
3514 if (colormanage_compatible_look(look_descr, view_name)) {
3515 return look_name;
3516 }
3517
3518 /* Try to find another compatible look with the same UI name, in case
3519 * of looks specialized for view transform, */
3521 if (STREQ(look_descr->ui_name, other_look->ui_name) &&
3522 colormanage_compatible_look(other_look, view_name))
3523 {
3524 return other_look->name;
3525 }
3526 }
3527
3529}
3530
3533/* -------------------------------------------------------------------- */
3538{
3540 EnumPropertyItem item;
3541
3542 item.value = display->index;
3543 item.name = display->name;
3544 item.identifier = display->name;
3545 item.icon = 0;
3546 item.description = "";
3547
3548 RNA_enum_item_add(items, totitem, &item);
3549 }
3550}
3551
3553 int *totitem,
3554 ColorManagedView *view)
3555{
3556 EnumPropertyItem item;
3557
3558 item.value = view->index;
3559 item.name = view->name;
3560 item.identifier = view->name;
3561 item.icon = 0;
3562 item.description = "";
3563
3564 RNA_enum_item_add(items, totitem, &item);
3565}
3566
3568 int *totitem,
3569 const char *display_name)
3570{
3571 ColorManagedDisplay *display = colormanage_display_get_named(display_name);
3572
3573 if (display) {
3574 LISTBASE_FOREACH (LinkData *, display_view, &display->views) {
3575 ColorManagedView *view = static_cast<ColorManagedView *>(display_view->data);
3576
3577 colormanagement_view_item_add(items, totitem, view);
3578 }
3579 }
3580}
3581
3583 int *totitem,
3584 const char *view_name)
3585{
3586 const bool has_explicit_look = has_explicit_look_for_view(view_name);
3587
3589 if (!colormanage_compatible_look(look, view_name, has_explicit_look)) {
3590 continue;
3591 }
3592
3593 EnumPropertyItem item;
3594
3595 item.value = look->index;
3596 item.name = look->ui_name;
3597 item.identifier = look->name;
3598 item.icon = 0;
3599 item.description = "";
3600
3601 RNA_enum_item_add(items, totitem, &item);
3602 }
3603}
3604
3606{
3608 EnumPropertyItem item;
3609
3610 if (!colorspace->is_invertible) {
3611 continue;
3612 }
3613
3614 item.value = colorspace->index;
3615 item.name = colorspace->name;
3616 item.identifier = colorspace->name;
3617 item.icon = 0;
3618 item.description = colorspace->description;
3619
3620 RNA_enum_item_add(items, totitem, &item);
3621 }
3622}
3623
3626/* -------------------------------------------------------------------- */
3630/*
3631 * Partial display update is supposed to be used by such areas as
3632 * compositor and renderer, This areas are calculating tiles of the
3633 * images and because of performance reasons only this tiles should
3634 * be color managed.
3635 * This gives nice visual feedback without slowing things down.
3636 *
3637 * Updating happens for active display transformation only, all
3638 * the rest buffers would be marked as dirty
3639 */
3640
3642 uchar *display_buffer,
3643 const float *linear_buffer,
3644 const uchar *byte_buffer,
3645 int display_stride,
3646 int linear_stride,
3647 int linear_offset_x,
3648 int linear_offset_y,
3649 ColormanageProcessor *cm_processor,
3650 const int xmin,
3651 const int ymin,
3652 const int xmax,
3653 const int ymax)
3654{
3655 int x, y;
3656 int channels = ibuf->channels;
3657 float dither = ibuf->dither;
3658 ColorSpace *rect_colorspace = ibuf->byte_buffer.colorspace;
3659 float *display_buffer_float = nullptr;
3660 const int width = xmax - xmin;
3661 const int height = ymax - ymin;
3662 bool is_data = (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) != 0;
3663
3664 if (dither != 0.0f) {
3665 /* cm_processor is nullptr in cases byte_buffer's space matches display
3666 * buffer's space
3667 * in this case we could skip extra transform and only apply dither
3668 * use 4 channels for easier byte->float->byte conversion here so
3669 * (this is only needed to apply dither, in other cases we'll convert
3670 * byte buffer to display directly)
3671 */
3672 if (!cm_processor) {
3673 channels = 4;
3674 }
3675
3676 display_buffer_float = static_cast<float *>(MEM_callocN(
3677 size_t(channels) * width * height * sizeof(float), "display buffer for dither"));
3678 }
3679
3680 if (cm_processor) {
3681 for (y = ymin; y < ymax; y++) {
3682 for (x = xmin; x < xmax; x++) {
3683 size_t display_index = (size_t(y) * display_stride + x) * 4;
3684 size_t linear_index = (size_t(y - linear_offset_y) * linear_stride +
3685 (x - linear_offset_x)) *
3686 channels;
3687 float pixel[4];
3688
3689 if (linear_buffer) {
3690 if (channels == 4) {
3691 copy_v4_v4(pixel, (float *)linear_buffer + linear_index);
3692 }
3693 else if (channels == 3) {
3694 copy_v3_v3(pixel, (float *)linear_buffer + linear_index);
3695 pixel[3] = 1.0f;
3696 }
3697 else if (channels == 1) {
3698 pixel[0] = linear_buffer[linear_index];
3699 }
3700 else {
3701 BLI_assert_msg(0, "Unsupported number of channels in partial buffer update");
3702 }
3703 }
3704 else if (byte_buffer) {
3705 rgba_uchar_to_float(pixel, byte_buffer + linear_index);
3707 straight_to_premul_v4(pixel);
3708 }
3709
3710 if (!is_data) {
3711 IMB_colormanagement_processor_apply_pixel(cm_processor, pixel, channels);
3712 }
3713
3714 if (display_buffer_float) {
3715 size_t index = (size_t(y - ymin) * width + (x - xmin)) * channels;
3716
3717 if (channels == 4) {
3718 copy_v4_v4(display_buffer_float + index, pixel);
3719 }
3720 else if (channels == 3) {
3721 copy_v3_v3(display_buffer_float + index, pixel);
3722 }
3723 else /* if (channels == 1) */ {
3724 display_buffer_float[index] = pixel[0];
3725 }
3726 }
3727 else {
3728 if (channels == 4) {
3729 float pixel_straight[4];
3730 premul_to_straight_v4_v4(pixel_straight, pixel);
3731 rgba_float_to_uchar(display_buffer + display_index, pixel_straight);
3732 }
3733 else if (channels == 3) {
3734 rgb_float_to_uchar(display_buffer + display_index, pixel);
3735 display_buffer[display_index + 3] = 255;
3736 }
3737 else /* if (channels == 1) */ {
3738 display_buffer[display_index] = display_buffer[display_index + 1] =
3739 display_buffer[display_index + 2] = display_buffer[display_index + 3] =
3740 unit_float_to_uchar_clamp(pixel[0]);
3741 }
3742 }
3743 }
3744 }
3745 }
3746 else {
3747 if (display_buffer_float) {
3748 /* huh, for dither we need float buffer first, no cheaper way. currently */
3749 IMB_buffer_float_from_byte(display_buffer_float,
3750 byte_buffer,
3753 true,
3754 width,
3755 height,
3756 width,
3757 display_stride);
3758 }
3759 else {
3760 int i;
3761
3762 for (i = ymin; i < ymax; i++) {
3763 size_t byte_offset = (size_t(linear_stride) * i + xmin) * 4;
3764 size_t display_offset = (size_t(display_stride) * i + xmin) * 4;
3765
3766 memcpy(
3767 display_buffer + display_offset, byte_buffer + byte_offset, sizeof(char[4]) * width);
3768 }
3769 }
3770 }
3771
3772 if (display_buffer_float) {
3773 size_t display_index = (size_t(ymin) * display_stride + xmin) * channels;
3774
3775 IMB_buffer_byte_from_float(display_buffer + display_index,
3776 display_buffer_float,
3777 channels,
3778 dither,
3781 true,
3782 width,
3783 height,
3784 display_stride,
3785 width);
3786
3787 MEM_freeN(display_buffer_float);
3788 }
3789}
3790
3802
3803static void partial_buffer_update_rect_thread_do(void *data_v, int scanline)
3804{
3805 PartialThreadData *data = (PartialThreadData *)data_v;
3806 int ymin = data->ymin + scanline;
3807 const int num_scanlines = 1;
3808 partial_buffer_update_rect(data->ibuf,
3809 data->display_buffer,
3810 data->linear_buffer,
3811 data->byte_buffer,
3812 data->display_stride,
3813 data->linear_stride,
3814 data->linear_offset_x,
3815 data->linear_offset_y,
3816 data->cm_processor,
3817 data->xmin,
3818 ymin,
3819 data->xmax,
3820 ymin + num_scanlines);
3821}
3822
3824 ImBuf *ibuf,
3825 const float *linear_buffer,
3826 const uchar *byte_buffer,
3827 int stride,
3828 int offset_x,
3829 int offset_y,
3830 const ColorManagedViewSettings *view_settings,
3831 const ColorManagedDisplaySettings *display_settings,
3832 int xmin,
3833 int ymin,
3834 int xmax,
3835 int ymax,
3836 bool do_threads)
3837{
3838 ColormanageCacheViewSettings cache_view_settings;
3839 ColormanageCacheDisplaySettings cache_display_settings;
3840 void *cache_handle = nullptr;
3841 uchar *display_buffer = nullptr;
3842 int buffer_width = ibuf->x;
3843
3844 if (ibuf->display_buffer_flags) {
3845 int view_flag, display_index;
3846
3847 colormanage_view_settings_to_cache(ibuf, &cache_view_settings, view_settings);
3848 colormanage_display_settings_to_cache(&cache_display_settings, display_settings);
3849
3850 view_flag = 1 << (cache_view_settings.view - 1);
3851 display_index = cache_display_settings.display - 1;
3852
3854
3855 if ((ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) == 0) {
3856 display_buffer = colormanage_cache_get(
3857 ibuf, &cache_view_settings, &cache_display_settings, &cache_handle);
3858 }
3859
3860 /* In some rare cases buffer's dimension could be changing directly from
3861 * different thread
3862 * this i.e. happens when image editor acquires render result
3863 */
3864 buffer_width = ibuf->x;
3865
3866 /* Mark all other buffers as invalid. */
3867 memset(ibuf->display_buffer_flags, 0, global_tot_display * sizeof(uint));
3868 ibuf->display_buffer_flags[display_index] |= view_flag;
3869
3871 }
3872
3873 if (display_buffer) {
3874 ColormanageProcessor *cm_processor = nullptr;
3875 bool skip_transform = false;
3876
3877 /* If we only have a byte or a float buffer, and color space already
3878 * matches display, there's no need to do color transforms.
3879 * However if both float and byte buffers exist, it is likely that
3880 * some operation was performed on float buffer first, and the byte
3881 * buffer is out of date. */
3882 if (linear_buffer == nullptr && byte_buffer != nullptr) {
3883 skip_transform = is_colorspace_same_as_display(
3884 ibuf->byte_buffer.colorspace, view_settings, display_settings);
3885 }
3886 if (byte_buffer == nullptr && linear_buffer != nullptr) {
3887 skip_transform = is_colorspace_same_as_display(
3888 ibuf->float_buffer.colorspace, view_settings, display_settings);
3889 }
3890
3891 if (!skip_transform) {
3892 cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
3893 }
3894
3895 if (do_threads) {
3897 data.ibuf = ibuf;
3898 data.display_buffer = display_buffer;
3899 data.linear_buffer = linear_buffer;
3900 data.byte_buffer = byte_buffer;
3901 data.display_stride = buffer_width;
3902 data.linear_stride = stride;
3903 data.linear_offset_x = offset_x;
3904 data.linear_offset_y = offset_y;
3905 data.cm_processor = cm_processor;
3906 data.xmin = xmin;
3907 data.ymin = ymin;
3908 data.xmax = xmax;
3910 ymax - ymin, partial_buffer_update_rect_thread_do, &data);
3911 }
3912 else {
3914 display_buffer,
3915 linear_buffer,
3916 byte_buffer,
3917 buffer_width,
3918 stride,
3919 offset_x,
3920 offset_y,
3921 cm_processor,
3922 xmin,
3923 ymin,
3924 xmax,
3925 ymax);
3926 }
3927
3928 if (cm_processor) {
3930 }
3931
3932 IMB_display_buffer_release(cache_handle);
3933 }
3934}
3935
3937 const float *linear_buffer,
3938 const uchar *byte_buffer,
3939 int stride,
3940 int offset_x,
3941 int offset_y,
3942 const ColorManagedViewSettings *view_settings,
3943 const ColorManagedDisplaySettings *display_settings,
3944 int xmin,
3945 int ymin,
3946 int xmax,
3947 int ymax)
3948{
3950 linear_buffer,
3951 byte_buffer,
3952 stride,
3953 offset_x,
3954 offset_y,
3955 view_settings,
3956 display_settings,
3957 xmin,
3958 ymin,
3959 xmax,
3960 ymax,
3961 false);
3962}
3963
3965 ImBuf *ibuf,
3966 const float *linear_buffer,
3967 const uchar *byte_buffer,
3968 int stride,
3969 int offset_x,
3970 int offset_y,
3971 const ColorManagedViewSettings *view_settings,
3972 const ColorManagedDisplaySettings *display_settings,
3973 int xmin,
3974 int ymin,
3975 int xmax,
3976 int ymax)
3977{
3978 int width = xmax - xmin;
3979 int height = ymax - ymin;
3980 bool do_threads = (size_t(width) * height >= 64 * 64);
3982 linear_buffer,
3983 byte_buffer,
3984 stride,
3985 offset_x,
3986 offset_y,
3987 view_settings,
3988 display_settings,
3989 xmin,
3990 ymin,
3991 xmax,
3992 ymax,
3993 do_threads);
3994}
3995
3996void IMB_partial_display_buffer_update_delayed(ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax)
3997{
3998 if (ibuf->invalid_rect.xmin == ibuf->invalid_rect.xmax) {
3999 BLI_rcti_init(&ibuf->invalid_rect, xmin, xmax, ymin, ymax);
4000 }
4001 else {
4002 rcti rect;
4003 BLI_rcti_init(&rect, xmin, xmax, ymin, ymax);
4004 BLI_rcti_union(&ibuf->invalid_rect, &rect);
4005 }
4006}
4007
4010/* -------------------------------------------------------------------- */
4015 const ColorManagedViewSettings *view_settings,
4016 const ColorManagedDisplaySettings *display_settings)
4017{
4018 ColormanageProcessor *cm_processor;
4019 ColorManagedViewSettings default_view_settings;
4020 const ColorManagedViewSettings *applied_view_settings;
4021 ColorSpace *display_space;
4022
4023 cm_processor = MEM_cnew<ColormanageProcessor>("colormanagement processor");
4024
4025 if (view_settings) {
4026 applied_view_settings = view_settings;
4027 }
4028 else {
4029 IMB_colormanagement_init_default_view_settings(&default_view_settings, display_settings);
4030 applied_view_settings = &default_view_settings;
4031 }
4032
4033 display_space = display_transform_get_colorspace(applied_view_settings, display_settings);
4034 if (display_space) {
4035 cm_processor->is_data_result = display_space->is_data;
4036 }
4037
4038 const bool use_white_balance = applied_view_settings->flag & COLORMANAGE_VIEW_USE_WHITE_BALANCE;
4040 applied_view_settings->look,
4041 applied_view_settings->view_transform,
4042 display_settings->display_device,
4043 applied_view_settings->exposure,
4044 applied_view_settings->gamma,
4045 applied_view_settings->temperature,
4046 applied_view_settings->tint,
4047 use_white_balance,
4049
4050 if (applied_view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
4051 cm_processor->curve_mapping = BKE_curvemapping_copy(applied_view_settings->curve_mapping);
4052 BKE_curvemapping_premultiply(cm_processor->curve_mapping, false);
4053 }
4054
4055 return cm_processor;
4056}
4057
4059 const char *to_colorspace)
4060{
4061 ColormanageProcessor *cm_processor;
4062
4063 cm_processor = MEM_cnew<ColormanageProcessor>("colormanagement processor");
4064 cm_processor->is_data_result = IMB_colormanagement_space_name_is_data(to_colorspace);
4065
4066 OCIO_ConstProcessorRcPtr *processor = create_colorspace_transform_processor(from_colorspace,
4067 to_colorspace);
4068 if (processor != nullptr) {
4069 cm_processor->cpu_processor = OCIO_processorGetCPUProcessor(processor);
4070 }
4071 OCIO_processorRelease(processor);
4072
4073 return cm_processor;
4074}
4075
4077{
4078 if (cm_processor->curve_mapping) {
4079 /* Consider processor which has curve mapping as a non no-op.
4080 * This is mainly for the simplicity of the check, since the current cases where this function
4081 * is used the curve mapping is never assigned. */
4082 return false;
4083 }
4084
4085 if (!cm_processor->cpu_processor) {
4086 /* The CPU processor might have failed to be created, for example when the requested color
4087 * space does not exist in the configuration, or if there is a missing lookup table, or the
4088 * configuration is invalid due to other reasons.
4089 *
4090 * The actual processing checks for the cpu_processor not being null pointer, and it if is then
4091 * processing does not apply it. However, processing could still apply curve mapping.
4092 *
4093 * Hence a null-pointer here, which happens after the curve mapping check, but before accessing
4094 * cpu_processor. */
4095 return true;
4096 }
4097
4098 return OCIO_cpuProcessorIsNoOp(cm_processor->cpu_processor);
4099}
4100
4102{
4103 if (cm_processor->curve_mapping) {
4104 BKE_curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
4105 }
4106
4107 if (cm_processor->cpu_processor) {
4108 OCIO_cpuProcessorApplyRGBA(cm_processor->cpu_processor, pixel);
4109 }
4110}
4111
4113 float pixel[4])
4114{
4115 if (cm_processor->curve_mapping) {
4116 BKE_curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
4117 }
4118
4119 if (cm_processor->cpu_processor) {
4121 }
4122}
4123
4125{
4126 if (cm_processor->curve_mapping) {
4127 BKE_curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
4128 }
4129
4130 if (cm_processor->cpu_processor) {
4131 OCIO_cpuProcessorApplyRGB(cm_processor->cpu_processor, pixel);
4132 }
4133}
4134
4136 float *pixel,
4137 int channels)
4138{
4139 if (channels == 4) {
4141 }
4142 else if (channels == 3) {
4143 IMB_colormanagement_processor_apply_v3(cm_processor, pixel);
4144 }
4145 else if (channels == 1) {
4146 if (cm_processor->curve_mapping) {
4147 curve_mapping_apply_pixel(cm_processor->curve_mapping, pixel, 1);
4148 }
4149 }
4150 else {
4152 false, "Incorrect number of channels passed to IMB_colormanagement_processor_apply_pixel");
4153 }
4154}
4155
4157 float *buffer,
4158 int width,
4159 int height,
4160 int channels,
4161 bool predivide)
4162{
4163 /* apply curve mapping */
4164 if (cm_processor->curve_mapping) {
4165 int x, y;
4166
4167 for (y = 0; y < height; y++) {
4168 for (x = 0; x < width; x++) {
4169 float *pixel = buffer + channels * (size_t(y) * width + x);
4170
4171 curve_mapping_apply_pixel(cm_processor->curve_mapping, pixel, channels);
4172 }
4173 }
4174 }
4175
4176 if (cm_processor->cpu_processor && channels >= 3) {
4177 OCIO_PackedImageDesc *img;
4178
4179 /* apply OCIO processor */
4181 width,
4182 height,
4183 channels,
4184 sizeof(float),
4185 size_t(channels) * sizeof(float),
4186 size_t(channels) * sizeof(float) * width);
4187
4188 if (predivide) {
4190 }
4191 else {
4192 OCIO_cpuProcessorApply(cm_processor->cpu_processor, img);
4193 }
4194
4196 }
4197}
4198
4200 ColormanageProcessor *cm_processor, uchar *buffer, int width, int height, int channels)
4201{
4202 /* TODO(sergey): Would be nice to support arbitrary channels configurations,
4203 * but for now it's not so important.
4204 */
4205 BLI_assert(channels == 4);
4206 float pixel[4];
4207 for (int y = 0; y < height; y++) {
4208 for (int x = 0; x < width; x++) {
4209 size_t offset = channels * (size_t(y) * width + x);
4210 rgba_uchar_to_float(pixel, buffer + offset);
4211 IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
4212 rgba_float_to_uchar(buffer + offset, pixel);
4213 }
4214 }
4215}
4216
4218{
4219 if (cm_processor->curve_mapping) {
4220 BKE_curvemapping_free(cm_processor->curve_mapping);
4221 }
4222 if (cm_processor->cpu_processor) {
4224 }
4225
4226 MEM_freeN(cm_processor);
4227}
4228
4229/* **** OpenGL drawing routines using GLSL for color space transform ***** */
4230
4232 OCIO_CurveMappingSettings *curve_mapping_settings)
4233{
4234 int i;
4235
4236 BKE_curvemapping_init(curve_mapping);
4237 BKE_curvemapping_premultiply(curve_mapping, false);
4239 curve_mapping, &curve_mapping_settings->lut, &curve_mapping_settings->lut_size);
4240
4241 curve_mapping_settings->use_extend_extrapolate = (curve_mapping->flag &
4243
4244 for (i = 0; i < 4; i++) {
4245 CurveMap *cuma = curve_mapping->cm + i;
4246 curve_mapping_settings->range[i] = cuma->range;
4247 curve_mapping_settings->mintable[i] = cuma->mintable;
4248 curve_mapping_settings->ext_in_x[i] = cuma->ext_in[0];
4249 curve_mapping_settings->ext_in_y[i] = cuma->ext_in[1];
4250 curve_mapping_settings->ext_out_x[i] = cuma->ext_out[0];
4251 curve_mapping_settings->ext_out_y[i] = cuma->ext_out[1];
4252 curve_mapping_settings->first_x[i] = cuma->table[0].x;
4253 curve_mapping_settings->first_y[i] = cuma->table[0].y;
4254 curve_mapping_settings->last_x[i] = cuma->table[CM_TABLE].x;
4255 curve_mapping_settings->last_y[i] = cuma->table[CM_TABLE].y;
4256 }
4257
4258 copy_v3_v3(curve_mapping_settings->black, curve_mapping->black);
4259 copy_v3_v3(curve_mapping_settings->bwmul, curve_mapping->bwmul);
4260
4261 curve_mapping_settings->cache_id = size_t(curve_mapping) + curve_mapping->changed_timestamp;
4262}
4263
4265 const ColorManagedViewSettings *view_settings)
4266{
4267 /* Using curve mapping? */
4268 const bool use_curve_mapping = (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) != 0;
4269 if (!use_curve_mapping) {
4270 return nullptr;
4271 }
4272
4273 /* Already up to date? */
4275 if (view_settings->curve_mapping->changed_timestamp ==
4278 {
4279 return curve_mapping_settings;
4280 }
4281
4282 /* Need to update. */
4283 CurveMapping *new_curve_mapping = nullptr;
4284
4285 /* We're using curve mapping's address as a cache ID,
4286 * so we need to make sure re-allocation gives new address here.
4287 * We do this by allocating new curve mapping before freeing old one. */
4288 if (use_curve_mapping) {
4289 new_curve_mapping = BKE_curvemapping_copy(view_settings->curve_mapping);
4290 }
4291
4294 MEM_freeN(curve_mapping_settings->lut);
4296 curve_mapping_settings->lut = nullptr;
4297 }
4298
4299 /* Fill in OCIO's curve mapping settings. */
4300 if (use_curve_mapping) {
4302
4303 global_gpu_state.curve_mapping = new_curve_mapping;
4307 }
4308 else {
4311 }
4312
4313 return curve_mapping_settings;
4314}
4315
4317{
4318 return OCIO_supportGPUShader();
4319}
4320
4322 const ColorManagedViewSettings *view_settings,
4323 const ColorManagedDisplaySettings *display_settings,
4324 ColorSpace *from_colorspace,
4325 float dither,
4326 bool predivide,
4327 bool do_overlay_merge)
4328{
4329 ColorManagedViewSettings default_view_settings;
4330 const ColorManagedViewSettings *applied_view_settings;
4331
4332 if (view_settings) {
4333 applied_view_settings = view_settings;
4334 }
4335 else {
4336 /* If no view settings were specified, use default ones, which will
4337 * attempt not to do any extra color correction. */
4338 IMB_colormanagement_init_default_view_settings(&default_view_settings, display_settings);
4339 applied_view_settings = &default_view_settings;
4340 }
4341
4342 /* Ensure curve mapping is up to data. */
4343 OCIO_CurveMappingSettings *curve_mapping_settings = update_glsl_curve_mapping(
4344 applied_view_settings);
4345
4346 /* GPU shader parameters. */
4347 const char *input = from_colorspace ? from_colorspace->name : global_role_scene_linear;
4348 const char *view = applied_view_settings->view_transform;
4349 const char *display = display_settings->display_device;
4350 const bool use_look = colormanage_use_look(applied_view_settings->look,
4351 applied_view_settings->view_transform);
4352 const char *look = (use_look) ? applied_view_settings->look : "";
4353 const float exposure = applied_view_settings->exposure;
4354 const float gamma = applied_view_settings->gamma;
4355 const float scale = (exposure == 0.0f) ? 1.0f : powf(2.0f, exposure);
4356 const float exponent = (gamma == 1.0f) ? 1.0f : 1.0f / max_ff(FLT_EPSILON, gamma);
4357 const float temperature = applied_view_settings->temperature;
4358 const float tint = applied_view_settings->tint;
4359 const bool use_white_balance = (applied_view_settings->flag &
4361 const bool use_hdr = GPU_hdr_support() &&
4362 (applied_view_settings->flag & COLORMANAGE_VIEW_USE_HDR) != 0;
4363
4364 OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
4365
4366 /* Bind shader. Internally GPU shaders are created and cached on demand. */
4368 input,
4369 view,
4370 display,
4371 look,
4372 curve_mapping_settings,
4373 scale,
4374 exponent,
4375 dither,
4376 temperature,
4377 tint,
4378 predivide,
4379 do_overlay_merge,
4380 use_hdr,
4381 use_white_balance);
4382
4383 OCIO_configRelease(config);
4384
4386}
4387
4389 const ColorManagedDisplaySettings *display_settings,
4390 float dither,
4391 bool predivide)
4392{
4394 view_settings, display_settings, nullptr, dither, predivide, false);
4395}
4396
4398 ColorSpace *from_colorspace,
4399 float dither,
4400 bool predivide)
4401{
4402 ColorManagedViewSettings *view_settings;
4403 ColorManagedDisplaySettings *display_settings;
4404
4405 IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
4406
4408 view_settings, display_settings, from_colorspace, dither, predivide, false);
4409}
4410
4411bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bool predivide)
4412{
4413 return IMB_colormanagement_setup_glsl_draw_from_space_ctx(C, nullptr, dither, predivide);
4414}
4415
4423
4426/* -------------------------------------------------------------------- */
4430/* Calculate color in range 800..12000 using an approximation
4431 * a/x+bx+c for R and G and ((at + b)t + c)t + d) for B
4432 *
4433 * The result of this can be negative to support gamut wider than
4434 * than rec.709, just needs to be clamped. */
4435
4436static const float blackbody_table_r[7][3] = {{1.61919106e+03f, -2.05010916e-03f, 5.02995757e+00f},
4437 {2.48845471e+03f, -1.11330907e-03f, 3.22621544e+00f},
4438 {3.34143193e+03f, -4.86551192e-04f, 1.76486769e+00f},
4439 {4.09461742e+03f, -1.27446582e-04f, 7.25731635e-01f},
4440 {4.67028036e+03f, 2.91258199e-05f, 1.26703442e-01f},
4441 {4.59509185e+03f, 2.87495649e-05f, 1.50345020e-01f},
4442 {3.78717450e+03f, 9.35907826e-06f, 3.99075871e-01f}};
4443
4444static const float blackbody_table_g[7][3] = {
4445 {-4.88999748e+02f, 6.04330754e-04f, -7.55807526e-02f},
4446 {-7.55994277e+02f, 3.16730098e-04f, 4.78306139e-01f},
4447 {-1.02363977e+03f, 1.20223470e-04f, 9.36662319e-01f},
4448 {-1.26571316e+03f, 4.87340896e-06f, 1.27054498e+00f},
4449 {-1.42529332e+03f, -4.01150431e-05f, 1.43972784e+00f},
4450 {-1.17554822e+03f, -2.16378048e-05f, 1.30408023e+00f},
4451 {-5.00799571e+02f, -4.59832026e-06f, 1.09098763e+00f}};
4452
4453static const float blackbody_table_b[7][4] = {
4454 {5.96945309e-11f, -4.85742887e-08f, -9.70622247e-05f, -4.07936148e-03f},
4455 {2.40430366e-11f, 5.55021075e-08f, -1.98503712e-04f, 2.89312858e-02f},
4456 {-1.40949732e-11f, 1.89878968e-07f, -3.56632824e-04f, 9.10767778e-02f},
4457 {-3.61460868e-11f, 2.84822009e-07f, -4.93211319e-04f, 1.56723440e-01f},
4458 {-1.97075738e-11f, 1.75359352e-07f, -2.50542825e-04f, -2.22783266e-02f},
4459 {-1.61997957e-13f, -1.64216008e-08f, 3.86216271e-04f, -7.38077418e-01f},
4460 {6.72650283e-13f, -2.73078809e-08f, 4.24098264e-04f, -7.52335691e-01f}};
4461
4462static void blackbody_temperature_to_rec709(float rec709[3], float t)
4463{
4464 if (t >= 12000.0f) {
4465 rec709[0] = 0.8262954810464208f;
4466 rec709[1] = 0.9945080501520986f;
4467 rec709[2] = 1.566307710274283f;
4468 }
4469 else if (t < 800.0f) {
4470 rec709[0] = 5.413294490189271f;
4471 rec709[1] = -0.20319390035873933f;
4472 rec709[2] = -0.0822535242887164f;
4473 }
4474 else {
4475 int i = (t >= 6365.0f) ? 6 :
4476 (t >= 3315.0f) ? 5 :
4477 (t >= 1902.0f) ? 4 :
4478 (t >= 1449.0f) ? 3 :
4479 (t >= 1167.0f) ? 2 :
4480 (t >= 965.0f) ? 1 :
4481 0;
4482
4483 const float *r = blackbody_table_r[i];
4484 const float *g = blackbody_table_g[i];
4485 const float *b = blackbody_table_b[i];
4486
4487 const float t_inv = 1.0f / t;
4488 rec709[0] = r[0] * t_inv + r[1] * t + r[2];
4489 rec709[1] = g[0] * t_inv + g[1] * t + g[2];
4490 rec709[2] = ((b[0] * t + b[1]) * t + b[2]) * t + b[3];
4491 }
4492}
4493
4495{
4496 float rec709[3];
4497 blackbody_temperature_to_rec709(rec709, value);
4498
4499 float rgb[3];
4501 clamp_v3(rgb, 0.0f, FLT_MAX);
4502
4503 copy_v3_v3(r_dest, rgb);
4504 r_dest[3] = 1.0f;
4505}
4506
4508 const int width,
4509 const float min,
4510 const float max)
4511{
4512 for (int i = 0; i < width; i++) {
4513 float temperature = min + (max - min) / float(width) * float(i);
4514 IMB_colormanagement_blackbody_temperature_to_rgb(&r_table[i * 4], temperature);
4515 }
4516}
4517
4530static float cie_color_match[81][3] = {
4531 {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f},
4532 {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f},
4533 {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f},
4534 {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f},
4535 {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f},
4536 {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f},
4537 {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f},
4538 {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f},
4539 {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f},
4540 {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f},
4541 {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f},
4542 {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f},
4543 {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f},
4544 {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f},
4545 {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f},
4546 {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f},
4547 {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f},
4548 {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f},
4549 {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f},
4550 {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f},
4551 {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f},
4552 {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f},
4553 {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f},
4554 {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f},
4555 {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f},
4556 {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f},
4557 {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}};
4558
4559static void wavelength_to_xyz(float xyz[3], float lambda_nm)
4560{
4561 float ii = (lambda_nm - 380.0f) * (1.0f / 5.0f); /* Scaled 0..80. */
4562 int i = int(ii);
4563
4564 if (i < 0 || i >= 80) {
4565 xyz[0] = 0.0f;
4566 xyz[1] = 0.0f;
4567 xyz[2] = 0.0f;
4568 }
4569 else {
4570 ii -= float(i);
4571 const float *c = cie_color_match[i];
4572 xyz[0] = c[0] + ii * (c[3] - c[0]);
4573 xyz[1] = c[1] + ii * (c[4] - c[1]);
4574 xyz[2] = c[2] + ii * (c[5] - c[2]);
4575 }
4576}
4577
4578void IMB_colormanagement_wavelength_to_rgb(float r_dest[4], float value)
4579{
4580 float xyz[3];
4581 wavelength_to_xyz(xyz, value);
4582
4583 float rgb[3];
4585 clamp_v3(rgb, 0.0f, FLT_MAX);
4586
4587 copy_v3_v3(r_dest, rgb);
4588 r_dest[3] = 1.0f;
4589}
4590
4591void IMB_colormanagement_wavelength_to_rgb_table(float *r_table, const int width)
4592{
4593 for (int i = 0; i < width; i++) {
4594 float wavelength = 380 + 400 / float(width) * float(i);
4595 IMB_colormanagement_wavelength_to_rgb(&r_table[i * 4], wavelength);
4596 }
4597}
4598
@ BLENDER_DATAFILES
std::optional< std::string > BKE_appdir_folder_id(int folder_id, const char *subfolder) ATTR_WARN_UNUSED_RESULT
Definition appdir.cc:704
void BKE_curvemapping_evaluate_premulRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3])
void BKE_curvemapping_premultiply(CurveMapping *cumap, bool restore)
CurveMapping * BKE_curvemapping_copy(const CurveMapping *cumap)
void BKE_curvemapping_init(CurveMapping *cumap)
void BKE_curvemapping_table_RGBA(const CurveMapping *cumap, float **array, int *size)
void BKE_curvemapping_free(CurveMapping *cumap)
float BKE_curvemap_evaluateF(const CurveMapping *cumap, const CurveMap *cuma, float value)
SpaceImage * CTX_wm_space_image(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
bool BKE_image_format_is_byte(const ImageFormatData *imf)
bool BKE_imtype_requires_linear_float(char imtype)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1)
Definition listbase.cc:370
struct LinkData * BLI_genericNodeN(void *data)
Definition listbase.cc:909
MINLINE float max_ff(float a, float b)
MINLINE void straight_to_premul_v4(float color[4])
void BLI_init_srgb_conversion(void)
void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4])
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
bool invert_m3_m3(float inverse[3][3], const float mat[3][3])
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
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
#define BLI_path_join(...)
const char * BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
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:418
#define STRNCPY(dst, src)
Definition BLI_string.h:593
int char char int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:230
void BLI_thread_unlock(int type)
Definition threads.cc:333
void BLI_thread_lock(int type)
Definition threads.cc:328
#define BLI_MUTEX_INITIALIZER
Definition BLI_threads.h:84
void BLI_mutex_lock(ThreadMutex *mutex)
Definition threads.cc:345
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition threads.cc:350
@ LOCK_COLORMANAGE
Definition BLI_threads.h:73
#define ELEM(...)
#define STRCASEEQ(a, b)
#define STREQ(a, b)
@ CUMA_EXTEND_EXTRAPOLATE
@ COLORMANAGE_VIEW_USE_WHITE_BALANCE
@ COLORMANAGE_VIEW_USE_CURVES
@ COLORMANAGE_VIEW_USE_HDR
#define CM_TABLE
@ IMA_VIEW_AS_RENDER
@ R_IMF_PLANES_RGBA
static AppView * view
bool GPU_hdr_support()
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])
BLI_INLINE void IMB_colormanagement_scene_linear_to_xyz(float xyz[3], const float scene_linear[3])
@ 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
#define MAX_COLORSPACE_NAME
struct OCIO_ConstCPUProcessorRc * OCIO_ConstCPUProcessorRcPtr
Function declarations for filter.cc.
void imb_freerectImBuf(ImBuf *ibuf)
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
void IMB_make_writable_byte_buffer(ImBuf *ibuf)
void IMB_rect_from_float(ImBuf *ibuf)
Definition divers.cc:694
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 *))
bool IMB_alpha_affects_rgb(const ImBuf *ibuf)
Definition divers.cc:91
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.cc:625
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.cc:348
void IMB_buffer_float_from_float(float *rect_to, const float *rect_from, int channels_from, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
Definition divers.cc:407
void IMB_make_writable_float_buffer(ImBuf *ibuf)
void IMB_processor_apply_threaded_scanlines(int total_scanlines, ScanlineThreadFunc do_thread, void *custom_data)
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.cc:96
bool imb_addrectImBuf(ImBuf *ibuf, bool initialize_pixels=true)
void IMB_alpha_under_color_float(float *rect_float, int x, int y, float backcol[3])
void IMB_assign_byte_buffer(ImBuf *ibuf, uint8_t *buffer_data, ImBufOwnership ownership)
void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, const float backcol[3])
void IMB_float_from_rect(ImBuf *ibuf)
Definition divers.cc:802
Contains defines and structs used throughout the imbuf module.
#define IB_PROFILE_SRGB
@ IMB_COLORMANAGE_IS_DATA
@ IB_TAKE_OWNERSHIP
@ IB_alphamode_channel_packed
@ IB_alphamode_premul
@ IB_alphamode_ignore
@ IB_RECT_INVALID
@ IB_DISPLAY_BUFFER_INVALID
void IMB_metadata_copy(ImBuf *ibuf_dst, const ImBuf *ibuf_src)
Definition metadata.cc:60
void IMB_moviecache_free(MovieCache *cache)
ImBuf * IMB_moviecache_get(MovieCache *cache, void *userkey, bool *r_is_cached_empty)
void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf)
MovieCache * IMB_moviecache_create(const char *name, int keysize, GHashHashFP hashfp, GHashCmpFP cmpfp)
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 Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves 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 Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
constexpr int64_t first() const
static void partial_buffer_update_rect(ImBuf *ibuf, uchar *display_buffer, const float *linear_buffer, const uchar *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)
static char global_role_data[MAX_COLORSPACE_NAME]
ColorManagedView * colormanage_view_add(const char *name)
static void * do_display_buffer_apply_thread(void *handle_v)
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)
static const float blackbody_table_r[7][3]
void IMB_colormanagement_assign_byte_colorspace(ImBuf *ibuf, const char *name)
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)
static uint colormanage_hashhash(const void *key_v)
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)
ColorManagedLook * colormanage_look_add(const char *name, const char *process_space, bool is_noop)
bool IMB_colormanagement_set_whitepoint(const float whitepoint[3], float &temperature, float &tint)
const char * IMB_colormanagement_colorspace_get_indexed_name(int index)
const char * colormanage_view_get_default_name(const ColorManagedDisplay *display)
void colormanage_cache_free(ImBuf *ibuf)
static float cie_color_match[81][3]
ColormanageProcessor * IMB_colormanagement_colorspace_processor_new(const char *from_colorspace, const char *to_colorspace)
void IMB_colormanagement_assign_float_colorspace(ImBuf *ibuf, const char *name)
void IMB_colormanagement_wavelength_to_rgb(float r_dest[4], float value)
ColorManagedView * colormanage_view_get_indexed(int index)
static void colormanage_check_colorspace_settings(ColorManagedColorspaceSettings *colorspace_settings, const char *what)
const char * IMB_colormanagement_display_get_none_name()
bool IMB_colormanagement_space_is_srgb(ColorSpace *colorspace)
uchar * IMB_display_buffer_acquire(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, void **cache_handle)
void IMB_colormanagement_pixel_to_display_space_v4(float result[4], const float pixel[4], const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
void IMB_colormanagement_transform_byte(uchar *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
ColorManagedDisplay * IMB_colormanagement_display_get_named(const char *name)
static void colormanage_cachedata_set(ImBuf *ibuf, ColormanageCacheData *data)
static OCIO_ConstCPUProcessorRcPtr * create_display_buffer_processor(const char *look, const char *view_transform, const char *display, const float exposure, const float gamma, const float temperature, const float tint, const bool use_white_balance, const char *from_colorspace)
static void colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, bool make_byte)
blender::float3x3 IMB_colormanagement_get_scene_linear_to_xyz()
bool IMB_colormanagement_space_is_scene_linear(ColorSpace *colorspace)
float imbuf_rec709_to_scene_linear[3][3]
static OCIO_ConstCPUProcessorRcPtr * colorspace_from_scene_linear_cpu_processor(ColorSpace *colorspace)
void IMB_colormanagement_processor_apply_byte(ColormanageProcessor *cm_processor, uchar *buffer, int width, int height, int channels)
void IMB_colormanagement_color_picking_to_scene_linear_v3(float scene_linear[3], const float color_picking[3])
uchar * IMB_display_buffer_acquire_ctx(const bContext *C, ImBuf *ibuf, void **cache_handle)
void IMB_colormanagement_view_items_add(EnumPropertyItem **items, int *totitem, const char *display_name)
const char * IMB_colormanagement_view_get_raw_or_default_name(const char *display_name)
static ImBuf * colormanage_cache_get_ibuf(ImBuf *ibuf, ColormanageCacheKey *key, void **cache_handle)
static char global_role_default_sequencer[MAX_COLORSPACE_NAME]
void colormanagement_exit()
const char * IMB_colormanagement_look_get_default_name()
void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name)
void colormanagement_init()
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)
float imbuf_scene_linear_to_rec709[3][3]
const char * IMB_colormanagement_look_get_indexed_name(int index)
bool IMB_colormanagement_space_name_is_srgb(const char *name)
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], ColorSpace *colorspace)
bool IMB_colormanagement_space_name_is_scene_linear(const char *name)
void IMB_colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
const char * IMB_colormanagement_look_validate_for_view(const char *view_name, const char *look_name)
static OCIO_ConstCPUProcessorRcPtr * colorspace_to_scene_linear_cpu_processor(ColorSpace *colorspace)
static pthread_mutex_t processor_lock
const char * IMB_colormanagement_display_get_default_view_transform_name(ColorManagedDisplay *display)
ColorManagedLook * colormanage_look_get_named(const char *name)
void IMB_display_buffer_transform_apply(uchar *display_buffer, float *linear_buffer, int width, int height, int channels, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, bool predivide)
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)
void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer, const uchar *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 IMB_colormanagement_processor_is_noop(ColormanageProcessor *cm_processor)
static void colormanage_display_buffer_process_ex(ImBuf *ibuf, float *display_buffer, uchar *display_buffer_byte, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static MovieCache * colormanage_moviecache_get(const ImBuf *ibuf)
void IMB_colormanagement_check_file_config(Main *bmain)
const char * colormanage_display_get_default_name()
static ColormanageCacheData * colormanage_cachedata_get(const ImBuf *ibuf)
static bool has_explicit_look_for_view(const char *view_name)
ImBuf * IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, bool allocate_result, const ImageFormatData *image_format)
ColormanageProcessor * IMB_colormanagement_display_processor_new(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
bool IMB_colormanagement_space_name_is_data(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 ImBuf *ibuf, const bool store_premultiplied)
float imbuf_scene_linear_to_xyz[3][3]
static bool colormanage_hashcmp(const void *av, const void *bv)
static OCIO_CurveMappingSettings * update_glsl_curve_mapping(const ColorManagedViewSettings *view_settings)
void IMB_colormanagement_init_default_view_settings(ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static bool is_colorspace_same_as_display(const ColorSpace *colorspace, const 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)
ColorManagedView * colormanage_view_get_named_for_display(const char *display_name, const char *name)
ColorManagedDisplay * colormanage_display_get_indexed(int index)
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 const float blackbody_table_g[7][3]
void IMB_colormanagegent_copy_settings(ImBuf *ibuf_src, ImBuf *ibuf_dst)
static void processor_transform_apply_threaded(uchar *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)
ColorManagedDisplay * colormanage_display_get_default()
void IMB_colormanagement_processor_apply(ColormanageProcessor *cm_processor, float *buffer, int width, int height, int channels, bool predivide)
const char * IMB_colormanagement_colorspace_get_name(const ColorSpace *colorspace)
static void colormanage_display_buffer_process(ImBuf *ibuf, uchar *display_buffer, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static int global_tot_view
ColorSpace * colormanage_colorspace_add(const char *name, const char *description, bool is_invertible, bool is_data)
bool IMB_colormanagement_setup_glsl_draw_ctx(const bContext *C, float dither, bool predivide)
ColorManagedDisplay * colormanage_display_get_named(const char *name)
void IMB_display_buffer_release(void *cache_handle)
ColorSpace * colormanage_colorspace_get_indexed(int index)
void IMB_colormanagement_get_whitepoint(const float temperature, const float tint, float whitepoint[3])
static OCIO_ConstCPUProcessorRcPtr * display_from_scene_linear_processor(ColorManagedDisplay *display)
const char * IMB_colormanagement_role_colorspace_name_get(int role)
void IMB_colormanagement_display_settings_from_ctx(const bContext *C, ColorManagedViewSettings **r_view_settings, ColorManagedDisplaySettings **r_display_settings)
blender::float3x3 IMB_colormanagement_get_xyz_to_scene_linear()
const char * IMB_colormanagement_display_get_indexed_name(int index)
void IMB_partial_display_buffer_update_threaded(ImBuf *ibuf, const float *linear_buffer, const uchar *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)
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], ColorSpace *colorspace)
const char * IMB_colormanagement_view_get_default_name(const char *display_name)
static void colormanage_cache_handle_release(void *cache_handle)
static ListBase global_looks
float imbuf_xyz_to_scene_linear[3][3]
static void do_display_buffer_apply_no_processor(DisplayBufferThread *handle)
static ListBase global_views
ColorManagedDisplay * colormanage_display_add(const char *name)
static const char * get_display_colorspace_name(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
ColorManagedView * colormanage_view_get_default(const ColorManagedDisplay *display)
#define DISPLAY_BUFFER_CHANNELS
void IMB_colormanagement_finish_glsl_draw()
float imbuf_aces_to_scene_linear[3][3]
void IMB_colormanagement_imbuf_to_byte_texture(uchar *out_buffer, const int offset_x, const int offset_y, const int width, const int height, const ImBuf *ibuf, const bool store_premultiplied)
void colormanage_imbuf_set_default_spaces(ImBuf *ibuf)
static const float blackbody_table_b[7][4]
static void imbuf_byte_to_float_cb(void *__restrict userdata, const int y, const TaskParallelTLS *__restrict)
ColorManagedLook * colormanage_look_get_indexed(int index)
ColorManagedView * colormanage_view_get_named(const char *name)
void IMB_colormanagement_scene_linear_to_colorspace(float *buffer, int width, int height, int channels, ColorSpace *colorspace)
static void * do_processor_transform_thread(void *handle_v)
static void colormanage_description_strip(char *description)
int IMB_colormanagement_look_get_named_index(const char *name)
void IMB_colormanagement_transform_from_byte(float *float_buffer, uchar *byte_buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
static ImBuf * imbuf_ensure_editable(ImBuf *ibuf, ImBuf *colormanaged_ibuf, bool allocate_result)
static void colormanage_display_settings_to_cache(ColormanageCacheDisplaySettings *cache_display_settings, const ColorManagedDisplaySettings *display_settings)
static void display_buffer_apply_threaded(ImBuf *ibuf, const float *buffer, uchar *byte_buffer, float *display_buffer, uchar *display_buffer_byte, ColormanageProcessor *cm_processor)
void colorspace_set_default_role(char *colorspace, int size, int role)
static ListBase global_displays
static void colormanagement_transform_ex(uchar *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 bool colormanage_load_config(OCIO_ConstConfigRcPtr *config)
static int global_tot_display
static OCIO_ConstCPUProcessorRcPtr * display_to_scene_linear_processor(ColorManagedDisplay *display)
static void imb_partial_display_buffer_update_ex(ImBuf *ibuf, const float *linear_buffer, const uchar *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)
static void partial_buffer_update_rect_thread_do(void *data_v, int scanline)
static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSettings *view_settings, const ColormanageCacheDisplaySettings *display_settings, uchar *display_buffer, void **cache_handle)
const char * IMB_colormanagement_view_get_indexed_name(int index)
void IMB_colormanagement_display_items_add(EnumPropertyItem **items, int *totitem)
void IMB_colormanagement_blackbody_temperature_to_rgb_table(float *r_table, const int width, const float min, const float max)
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]
bool IMB_colormanagement_setup_glsl_draw_from_space(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, ColorSpace *from_colorspace, float dither, bool predivide, bool do_overlay_merge)
static void colormanagement_view_item_add(EnumPropertyItem **items, int *totitem, ColorManagedView *view)
void IMB_colormanagement_blackbody_temperature_to_rgb(float r_dest[4], float value)
int IMB_colormanagement_colorspace_get_named_index(const char *name)
void IMB_display_buffer_transform_apply_float(float *float_display_buffer, float *linear_buffer, int width, int height, int channels, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings, bool predivide)
static char global_role_texture_painting[MAX_COLORSPACE_NAME]
static ColorSpace * display_transform_get_colorspace(const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
static void colormanage_settings_to_key(ColormanageCacheKey *key, const ColormanageCacheViewSettings *view_settings, const ColormanageCacheDisplaySettings *display_settings)
static void curve_mapping_apply_pixel(const CurveMapping *curve_mapping, float *pixel, int channels)
bool IMB_colormanagement_setup_glsl_draw_from_space_ctx(const bContext *C, ColorSpace *from_colorspace, float dither, bool predivide)
void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace)
void IMB_colormanagement_processor_apply_v4_predivide(ColormanageProcessor *cm_processor, float pixel[4])
static bool seq_callback(Sequence *seq, void *)
void IMB_colormanagement_transform_byte_threaded(uchar *buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
void IMB_colormanagement_look_items_add(EnumPropertyItem **items, int *totitem, const char *view_name)
static int global_tot_looks
static bool colormanage_role_color_space_name_get(OCIO_ConstConfigRcPtr *config, char *colorspace_name, const char *role, const char *backup_role)
static OCIO_ConstProcessorRcPtr * create_colorspace_transform_processor(const char *from_colorspace, const char *to_colorspace)
static char global_role_default_byte[MAX_COLORSPACE_NAME]
static char global_role_default_float[MAX_COLORSPACE_NAME]
ColorSpace * colormanage_colorspace_get_named(const char *name)
void IMB_colormanagement_processor_free(ColormanageProcessor *cm_processor)
const char * IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf)
void IMB_partial_display_buffer_update_delayed(ImBuf *ibuf, int xmin, int ymin, int xmax, int ymax)
static void colormanage_free_config()
void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace)
void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4], bool predivide, ColorSpace *colorspace)
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]
static uchar * colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheViewSettings *view_settings, const ColormanageCacheDisplaySettings *display_settings, void **cache_handle)
const char * IMB_colormanagement_get_float_colorspace(ImBuf *ibuf)
static void colormanage_check_view_settings(ColorManagedDisplaySettings *display_settings, ColorManagedViewSettings *view_settings, const char *what)
static void wavelength_to_xyz(float xyz[3], float lambda_nm)
const char * IMB_colormanagement_display_get_default_name()
static MovieCache * colormanage_moviecache_ensure(ImBuf *ibuf)
static bool colormanage_compatible_look(const ColorManagedLook *look, const char *view_name, const bool has_explicit_look)
bool IMB_colormanagement_support_glsl_draw(const ColorManagedViewSettings *)
void IMB_colormanagement_processor_apply_pixel(ColormanageProcessor *cm_processor, float *pixel, int channels)
void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, uchar *byte_buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, ColorSpace *colorspace, bool predivide)
ColorSpace * colormanage_colorspace_get_roled(int role)
local_group_size(16, 16) .push_constant(Type b
#define printf
#define powf(x, y)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
const ImFileType * IMB_file_type_from_ibuf(const ImBuf *ibuf)
Definition filetype.cc:232
void IMB_premultiply_rect_float(float *rect_float, int channels, int w, int h)
Definition filter.cc:561
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
void IMB_freeImBuf(ImBuf *)
void SEQ_for_each_callback(ListBase *seqbase, SeqForEachFunc callback, void *user_data)
Definition iterator.cc:43
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define unit_float_to_uchar_clamp(val)
#define G(x, y, z)
float3 whitepoint_from_temp_tint(float temperature, float tint)
bool whitepoint_to_temp_tint(const float3 &white, float &temperature, float &tint)
MatBase< float, 3, 3 > float3x3
const char * OCIO_configGetDefaultView(OCIO_ConstConfigRcPtr *config, const char *display)
Definition ocio_capi.cc:95
void OCIO_cpuProcessorApplyRGB(OCIO_ConstCPUProcessorRcPtr *cpu_processor, float *pixel)
Definition ocio_capi.cc:208
void OCIO_cpuProcessorApplyRGBA(OCIO_ConstCPUProcessorRcPtr *cpu_processor, float *pixel)
Definition ocio_capi.cc:213
OCIO_ConstConfigRcPtr * OCIO_getCurrentConfig()
Definition ocio_capi.cc:26
const char * OCIO_colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs)
Definition ocio_capi.cc:228
void OCIO_configGetXYZtoSceneLinear(OCIO_ConstConfigRcPtr *config, float xyz_to_scene_linear[3][3])
Definition ocio_capi.cc:122
const char * OCIO_configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *config, int index)
Definition ocio_capi.cc:64
OCIO_PackedImageDesc * OCIO_createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, long chanStrideBytes, long xStrideBytes, long yStrideBytes)
Definition ocio_capi.cc:278
OCIO_ConstConfigRcPtr * OCIO_configCreateFromEnv()
Definition ocio_capi.cc:44
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 float temperature, const float tint, const bool use_predivide, const bool use_overlay, const bool use_hdr, const bool use_white_balance)
Definition ocio_capi.cc:300
void OCIO_lookRelease(OCIO_ConstLookRcPtr *look)
Definition ocio_capi.cc:147
const char * OCIO_configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view)
Definition ocio_capi.cc:110
void OCIO_cpuProcessorApply(OCIO_ConstCPUProcessorRcPtr *cpu_processor, OCIO_PackedImageDesc *img)
Definition ocio_capi.cc:197
void OCIO_gpuDisplayShaderUnbind()
Definition ocio_capi.cc:333
void OCIO_colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config, OCIO_ConstColorSpaceRcPtr *cs, bool *is_scene_linear, bool *is_srgb)
Definition ocio_capi.cc:162
OCIO_ConstConfigRcPtr * OCIO_configCreateFromFile(const char *filename)
Definition ocio_capi.cc:49
void OCIO_colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs)
Definition ocio_capi.cc:170
OCIO_ConstColorSpaceRcPtr * OCIO_configGetColorSpace(OCIO_ConstConfigRcPtr *config, const char *name)
Definition ocio_capi.cc:69
const char * OCIO_configGetDefaultDisplay(OCIO_ConstConfigRcPtr *config)
Definition ocio_capi.cc:80
OCIO_ConstLookRcPtr * OCIO_configGetLook(OCIO_ConstConfigRcPtr *config, const char *name)
Definition ocio_capi.cc:137
int OCIO_colorSpaceGetNumAliases(OCIO_ConstColorSpaceRcPtr *cs)
Definition ocio_capi.cc:243
const char * OCIO_lookGetProcessSpace(OCIO_ConstLookRcPtr *look)
Definition ocio_capi.cc:142
OCIO_ConstConfigRcPtr * OCIO_configCreateFallback()
Definition ocio_capi.cc:31
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 float temperature, const float tint, const bool use_white_balance, const bool inverse)
Definition ocio_capi.cc:253
OCIO_ConstCPUProcessorRcPtr * OCIO_processorGetCPUProcessor(OCIO_ConstProcessorRcPtr *processor)
Definition ocio_capi.cc:187
void OCIO_init()
Definition ocio_capi.cc:11
void OCIO_cpuProcessorApply_predivide(OCIO_ConstCPUProcessorRcPtr *cpu_processor, OCIO_PackedImageDesc *img)
Definition ocio_capi.cc:202
OCIO_ConstProcessorRcPtr * OCIO_configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName)
Definition ocio_capi.cc:175
const char * OCIO_configGetDisplay(OCIO_ConstConfigRcPtr *config, int index)
Definition ocio_capi.cc:90
void OCIO_setCurrentConfig(const OCIO_ConstConfigRcPtr *config)
Definition ocio_capi.cc:39
int OCIO_configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config)
Definition ocio_capi.cc:59
void OCIO_configRelease(OCIO_ConstConfigRcPtr *config)
Definition ocio_capi.cc:54
void OCIO_gpuCacheFree()
Definition ocio_capi.cc:338
int OCIO_configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *display)
Definition ocio_capi.cc:100
void OCIO_cpuProcessorRelease(OCIO_ConstCPUProcessorRcPtr *cpu_processor)
Definition ocio_capi.cc:223
const char * OCIO_colorSpaceGetAlias(OCIO_ConstColorSpaceRcPtr *cs, const int index)
Definition ocio_capi.cc:248
void OCIO_exit()
Definition ocio_capi.cc:20
void OCIO_cpuProcessorApplyRGBA_predivide(OCIO_ConstCPUProcessorRcPtr *processor, float *pixel)
Definition ocio_capi.cc:218
int OCIO_colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs)
Definition ocio_capi.cc:152
const char * OCIO_configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index)
Definition ocio_capi.cc:132
bool OCIO_supportGPUShader()
Definition ocio_capi.cc:295
void OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
Definition ocio_capi.cc:290
const char * OCIO_configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index)
Definition ocio_capi.cc:105
bool OCIO_cpuProcessorIsNoOp(OCIO_ConstCPUProcessorRcPtr *cpu_processor)
Definition ocio_capi.cc:192
int OCIO_configGetNumLooks(OCIO_ConstConfigRcPtr *config)
Definition ocio_capi.cc:127
void OCIO_processorRelease(OCIO_ConstProcessorRcPtr *processor)
Definition ocio_capi.cc:182
int OCIO_configGetNumDisplays(OCIO_ConstConfigRcPtr *config)
Definition ocio_capi.cc:85
int OCIO_colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs)
Definition ocio_capi.cc:157
const char * OCIO_colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs)
Definition ocio_capi.cc:233
void OCIO_configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb)
Definition ocio_capi.cc:117
#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)
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
__int64 int64_t
Definition stdint.h:89
char name[MAX_COLORSPACE_NAME]
char ui_name[MAX_COLORSPACE_NAME]
char view[MAX_COLORSPACE_NAME]
char process_space[MAX_COLORSPACE_NAME]
char name[MAX_COLORSPACE_NAME]
struct CurveMapping * curve_mapping
char name[MAX_COLORSPACE_NAME]
struct ColorSpace::@676 info
OCIO_ConstCPUProcessorRcPtr * from_scene_linear
char(* aliases)[MAX_COLORSPACE_NAME]
char name[MAX_COLORSPACE_NAME]
char description[MAX_COLORSPACE_DESCRIPTION]
OCIO_ConstCPUProcessorRcPtr * to_scene_linear
CurveMapping * curve_mapping
ColormanageCacheData * data
MovieCache * moviecache
CurveMapping * curve_mapping
OCIO_ConstCPUProcessorRcPtr * cpu_processor
CurveMapPoint * table
float ext_out[2]
float ext_in[2]
CurveMap cm[4]
ColormanageProcessor * cm_processor
ColormanageProcessor * cm_processor
const char * float_colorspace
const char * identifier
Definition RNA_types.hh:506
const char * name
Definition RNA_types.hh:510
const char * description
Definition RNA_types.hh:512
ColorSpace * colorspace
ColorSpace * colorspace
rcti invalid_rect
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
int colormanage_flag
unsigned char planes
unsigned int * display_buffer_flags
ColormanageCache * colormanage_cache
ColorManagedColorspaceSettings linear_colorspace_settings
ColorManagedDisplaySettings display_settings
ColorManagedViewSettings view_settings
OCIO_ConstCPUProcessorRcPtr * processor
void * last
void * first
ListBase scenes
Definition BKE_main.hh:210
ListBase movieclips
Definition BKE_main.hh:242
ListBase images
Definition BKE_main.hh:218
ColormanageProcessor * cm_processor
const uchar * byte_buffer
const float * linear_buffer
ColormanageProcessor * cm_processor
ColormanageProcessor * cm_processor
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
int ymax
int xmin
int xmax