Blender V4.3
ocio_impl.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <cassert>
6#include <iostream>
7#include <math.h>
8#include <sstream>
9#include <string.h>
10
11#ifdef _MSC_VER
12# pragma warning(push)
13# pragma warning(disable : 4251 4275)
14#endif
15#include <OpenColorIO/OpenColorIO.h>
16#ifdef _MSC_VER
17# pragma warning(pop)
18#endif
19
20using namespace OCIO_NAMESPACE;
21
22#include "MEM_guardedalloc.h"
23
24#include "BLI_math_color.h"
25#include "BLI_math_color.hh"
26#include "BLI_math_matrix.h"
27#include "BLI_math_matrix.hh"
28
29#include "ocio_impl.h"
30
31#if !defined(WITH_ASSERT_ABORT)
32# define OCIO_abort()
33#else
34# include <stdlib.h>
35# define OCIO_abort() abort()
36#endif
37
38#if defined(_MSC_VER)
39# define __func__ __FUNCTION__
40#endif
41
43using blender::float3;
45
46static void OCIO_reportError(const char *err)
47{
48 std::cerr << "OpenColorIO Error: " << err << std::endl;
49
50 OCIO_abort();
51}
52
53static void OCIO_reportException(Exception &exception)
54{
55 OCIO_reportError(exception.what());
56}
57
58OCIO_ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void)
59{
60 ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__);
61
62 try {
63 *config = GetCurrentConfig();
64
65 if (*config) {
66 return (OCIO_ConstConfigRcPtr *)config;
67 }
68 }
69 catch (Exception &exception) {
70 OCIO_reportException(exception);
71 }
72
73 MEM_delete(config);
74
75 return NULL;
76}
77
78void OCIOImpl::setCurrentConfig(const OCIO_ConstConfigRcPtr *config)
79{
80 try {
81 SetCurrentConfig(*(ConstConfigRcPtr *)config);
82 }
83 catch (Exception &exception) {
84 OCIO_reportException(exception);
85 }
86}
87
88OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void)
89{
90 ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__);
91
92 try {
93 *config = Config::CreateFromEnv();
94
95 if (*config) {
96 return (OCIO_ConstConfigRcPtr *)config;
97 }
98 }
99 catch (Exception &exception) {
100 OCIO_reportException(exception);
101 }
102
103 MEM_delete(config);
104
105 return NULL;
106}
107
108OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename)
109{
110 ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__);
111
112 try {
113 *config = Config::CreateFromFile(filename);
114
115 if (*config) {
116 return (OCIO_ConstConfigRcPtr *)config;
117 }
118 }
119 catch (Exception &exception) {
120 OCIO_reportException(exception);
121 }
122
123 MEM_delete(config);
124
125 return NULL;
126}
127
128void OCIOImpl::configRelease(OCIO_ConstConfigRcPtr *config)
129{
130 MEM_delete((ConstConfigRcPtr *)config);
131}
132
133int OCIOImpl::configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config)
134{
135 try {
136 return (*(ConstConfigRcPtr *)config)->getNumColorSpaces();
137 }
138 catch (Exception &exception) {
139 OCIO_reportException(exception);
140 }
141
142 return 0;
143}
144
145const char *OCIOImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *config, int index)
146{
147 try {
148 return (*(ConstConfigRcPtr *)config)->getColorSpaceNameByIndex(index);
149 }
150 catch (Exception &exception) {
151 OCIO_reportException(exception);
152 }
153
154 return NULL;
155}
156
157OCIO_ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(OCIO_ConstConfigRcPtr *config,
158 const char *name)
159{
160 ConstColorSpaceRcPtr *cs = MEM_new<ConstColorSpaceRcPtr>(__func__);
161
162 try {
163 *cs = (*(ConstConfigRcPtr *)config)->getColorSpace(name);
164
165 if (*cs) {
166 return (OCIO_ConstColorSpaceRcPtr *)cs;
167 }
168 }
169 catch (Exception &exception) {
170 OCIO_reportException(exception);
171 }
172
173 MEM_delete(cs);
174
175 return NULL;
176}
177
178int OCIOImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name)
179{
180 try {
181 return (*(ConstConfigRcPtr *)config)->getIndexForColorSpace(name);
182 }
183 catch (Exception &exception) {
184 OCIO_reportException(exception);
185 }
186
187 return -1;
188}
189
190const char *OCIOImpl::configGetDefaultDisplay(OCIO_ConstConfigRcPtr *config)
191{
192 try {
193 return (*(ConstConfigRcPtr *)config)->getDefaultDisplay();
194 }
195 catch (Exception &exception) {
196 OCIO_reportException(exception);
197 }
198
199 return NULL;
200}
201
202int OCIOImpl::configGetNumDisplays(OCIO_ConstConfigRcPtr *config)
203{
204 try {
205 return (*(ConstConfigRcPtr *)config)->getNumDisplays();
206 }
207 catch (Exception &exception) {
208 OCIO_reportException(exception);
209 }
210
211 return 0;
212}
213
214const char *OCIOImpl::configGetDisplay(OCIO_ConstConfigRcPtr *config, int index)
215{
216 try {
217 return (*(ConstConfigRcPtr *)config)->getDisplay(index);
218 }
219 catch (Exception &exception) {
220 OCIO_reportException(exception);
221 }
222
223 return NULL;
224}
225
226const char *OCIOImpl::configGetDefaultView(OCIO_ConstConfigRcPtr *config, const char *display)
227{
228 try {
229 return (*(ConstConfigRcPtr *)config)->getDefaultView(display);
230 }
231 catch (Exception &exception) {
232 OCIO_reportException(exception);
233 }
234
235 return NULL;
236}
237
238int OCIOImpl::configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *display)
239{
240 try {
241 return (*(ConstConfigRcPtr *)config)->getNumViews(display);
242 }
243 catch (Exception &exception) {
244 OCIO_reportException(exception);
245 }
246
247 return 0;
248}
249
250const char *OCIOImpl::configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index)
251{
252 try {
253 return (*(ConstConfigRcPtr *)config)->getView(display, index);
254 }
255 catch (Exception &exception) {
256 OCIO_reportException(exception);
257 }
258
259 return NULL;
260}
261
262const char *OCIOImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config,
263 const char *display,
264 const char *view)
265{
266 try {
267 const char *name = (*(ConstConfigRcPtr *)config)->getDisplayViewColorSpaceName(display, view);
268 /* OpenColorIO does not resolve this token for us, so do it ourselves. */
269 if (strcasecmp(name, "<USE_DISPLAY_NAME>") == 0) {
270 return display;
271 }
272 return name;
273 }
274 catch (Exception &exception) {
275 OCIO_reportException(exception);
276 }
277
278 return NULL;
279}
280
281void OCIOImpl::configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr *config, float *rgb)
282{
283 try {
284 double rgb_double[3];
285 (*(ConstConfigRcPtr *)config)->getDefaultLumaCoefs(rgb_double);
286 rgb[0] = rgb_double[0];
287 rgb[1] = rgb_double[1];
288 rgb[2] = rgb_double[2];
289 }
290 catch (Exception &exception) {
291 OCIO_reportException(exception);
292 }
293}
294
295static bool to_scene_linear_matrix(ConstConfigRcPtr &config,
296 const char *colorspace,
297 float to_scene_linear[3][3])
298{
299 ConstProcessorRcPtr processor;
300 try {
301 processor = config->getProcessor(colorspace, ROLE_SCENE_LINEAR);
302 }
303 catch (Exception &exception) {
304 OCIO_reportException(exception);
305 return false;
306 }
307
308 if (!processor) {
309 return false;
310 }
311
312 ConstCPUProcessorRcPtr cpu_processor = processor->getDefaultCPUProcessor();
313 if (!cpu_processor) {
314 return false;
315 }
316
317 unit_m3(to_scene_linear);
318 cpu_processor->applyRGB(to_scene_linear[0]);
319 cpu_processor->applyRGB(to_scene_linear[1]);
320 cpu_processor->applyRGB(to_scene_linear[2]);
321 return true;
322}
323
324void OCIOImpl::configGetXYZtoSceneLinear(OCIO_ConstConfigRcPtr *config_,
325 float xyz_to_scene_linear[3][3])
326{
327 ConstConfigRcPtr config = (*(ConstConfigRcPtr *)config_);
328
329 /* Default to ITU-BT.709 in case no appropriate transform found.
330 * Note XYZ is defined here as having a D65 white point. */
331 memcpy(xyz_to_scene_linear, OCIO_XYZ_TO_REC709, sizeof(OCIO_XYZ_TO_REC709));
332
333 /* Get from OpenColorO config if it has the required roles. */
334 if (!config->hasRole(ROLE_SCENE_LINEAR)) {
335 return;
336 }
337
338 if (config->hasRole("aces_interchange")) {
339 /* Standard OpenColorIO role, defined as ACES AP0 (ACES2065-1). */
340 float aces_to_scene_linear[3][3];
341 if (to_scene_linear_matrix(config, "aces_interchange", aces_to_scene_linear)) {
342 float xyz_to_aces[3][3];
343 invert_m3_m3(xyz_to_aces, OCIO_ACES_TO_XYZ);
344
345 mul_m3_m3m3(xyz_to_scene_linear, aces_to_scene_linear, xyz_to_aces);
346 }
347 }
348 else if (config->hasRole("XYZ")) {
349 /* Custom role used before the standard existed. */
350 to_scene_linear_matrix(config, "XYZ", xyz_to_scene_linear);
351 }
352}
353
354int OCIOImpl::configGetNumLooks(OCIO_ConstConfigRcPtr *config)
355{
356 try {
357 return (*(ConstConfigRcPtr *)config)->getNumLooks();
358 }
359 catch (Exception &exception) {
360 OCIO_reportException(exception);
361 }
362
363 return 0;
364}
365
366const char *OCIOImpl::configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index)
367{
368 try {
369 return (*(ConstConfigRcPtr *)config)->getLookNameByIndex(index);
370 }
371 catch (Exception &exception) {
372 OCIO_reportException(exception);
373 }
374
375 return NULL;
376}
377
378OCIO_ConstLookRcPtr *OCIOImpl::configGetLook(OCIO_ConstConfigRcPtr *config, const char *name)
379{
380 ConstLookRcPtr *look = MEM_new<ConstLookRcPtr>(__func__);
381
382 try {
383 *look = (*(ConstConfigRcPtr *)config)->getLook(name);
384
385 if (*look) {
386 return (OCIO_ConstLookRcPtr *)look;
387 }
388 }
389 catch (Exception &exception) {
390 OCIO_reportException(exception);
391 }
392
393 MEM_delete(look);
394
395 return NULL;
396}
397
398const char *OCIOImpl::lookGetProcessSpace(OCIO_ConstLookRcPtr *look)
399{
400 return (*(ConstLookRcPtr *)look)->getProcessSpace();
401}
402
403void OCIOImpl::lookRelease(OCIO_ConstLookRcPtr *look)
404{
405 MEM_delete((ConstLookRcPtr *)look);
406}
407
408int OCIOImpl::colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs_)
409{
410 ConstColorSpaceRcPtr *cs = (ConstColorSpaceRcPtr *)cs_;
411 const char *family = (*cs)->getFamily();
412
413 if (!strcmp(family, "rrt") || !strcmp(family, "display")) {
414 /* assume display and rrt transformations are not invertible in fact some of them could be,
415 * but it doesn't make much sense to allow use them as invertible. */
416 return false;
417 }
418
419 if ((*cs)->isData()) {
420 /* data color spaces don't have transformation at all */
421 return true;
422 }
423
424 if ((*cs)->getTransform(COLORSPACE_DIR_TO_REFERENCE)) {
425 /* if there's defined transform to reference space,
426 * color space could be converted to scene linear. */
427 return true;
428 }
429
430 return true;
431}
432
433int OCIOImpl::colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs)
434{
435 return (*(ConstColorSpaceRcPtr *)cs)->isData();
436}
437
438static float compare_floats(float a, float b, float abs_diff, int ulp_diff)
439{
440 /* Returns true if the absolute difference is smaller than abs_diff (for numbers near zero)
441 * or their relative difference is less than ulp_diff ULPs. Based on:
442 * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ */
443 if (fabsf(a - b) < abs_diff) {
444 return true;
445 }
446
447 if ((a < 0.0f) != (b < 0.0f)) {
448 return false;
449 }
450
451 return (abs((*(int *)&a) - (*(int *)&b)) < ulp_diff);
452}
453
454void OCIOImpl::colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config_,
455 OCIO_ConstColorSpaceRcPtr *cs_,
456 bool &is_scene_linear,
457 bool &is_srgb)
458{
459 ConstConfigRcPtr *config = (ConstConfigRcPtr *)config_;
460 ConstColorSpaceRcPtr *cs = (ConstColorSpaceRcPtr *)cs_;
461 ConstProcessorRcPtr processor;
462
463 try {
464 processor = (*config)->getProcessor((*cs)->getName(), "scene_linear");
465 }
466 catch (Exception &) {
467 /* Silently ignore if no conversion possible, then it's not scene linear or sRGB. */
468 is_scene_linear = false;
469 is_srgb = false;
470 return;
471 }
472
473 ConstCPUProcessorRcPtr cpu_processor = processor->getDefaultCPUProcessor();
474
475 is_scene_linear = true;
476 is_srgb = true;
477 for (int i = 0; i < 256; i++) {
478 float v = i / 255.0f;
479
480 float cR[3] = {v, 0, 0};
481 float cG[3] = {0, v, 0};
482 float cB[3] = {0, 0, v};
483 float cW[3] = {v, v, v};
484 cpu_processor->applyRGB(cR);
485 cpu_processor->applyRGB(cG);
486 cpu_processor->applyRGB(cB);
487 cpu_processor->applyRGB(cW);
488
489 /* Make sure that there is no channel crosstalk. */
490 if (fabsf(cR[1]) > 1e-5f || fabsf(cR[2]) > 1e-5f || fabsf(cG[0]) > 1e-5f ||
491 fabsf(cG[2]) > 1e-5f || fabsf(cB[0]) > 1e-5f || fabsf(cB[1]) > 1e-5f)
492 {
493 is_scene_linear = false;
494 is_srgb = false;
495 break;
496 }
497 /* Make sure that the three primaries combine linearly. */
498 if (!compare_floats(cR[0], cW[0], 1e-6f, 64) || !compare_floats(cG[1], cW[1], 1e-6f, 64) ||
499 !compare_floats(cB[2], cW[2], 1e-6f, 64))
500 {
501 is_scene_linear = false;
502 is_srgb = false;
503 break;
504 }
505 /* Make sure that the three channels behave identically. */
506 if (!compare_floats(cW[0], cW[1], 1e-6f, 64) || !compare_floats(cW[1], cW[2], 1e-6f, 64)) {
507 is_scene_linear = false;
508 is_srgb = false;
509 break;
510 }
511
512 float out_v = (cW[0] + cW[1] + cW[2]) * (1.0f / 3.0f);
513 if (!compare_floats(v, out_v, 1e-6f, 64)) {
514 is_scene_linear = false;
515 }
516 if (!compare_floats(srgb_to_linearrgb(v), out_v, 1e-4f, 64)) {
517 is_srgb = false;
518 }
519 }
520}
521
522void OCIOImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs)
523{
524 MEM_delete((ConstColorSpaceRcPtr *)cs);
525}
526
527OCIO_ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config,
528 const char *srcName,
529 const char *dstName)
530{
531 ConstProcessorRcPtr *processor = MEM_new<ConstProcessorRcPtr>(__func__);
532
533 try {
534 *processor = (*(ConstConfigRcPtr *)config)->getProcessor(srcName, dstName);
535
536 if (*processor) {
537 return (OCIO_ConstProcessorRcPtr *)processor;
538 }
539 }
540 catch (Exception &exception) {
541 OCIO_reportException(exception);
542 }
543
544 MEM_delete(processor);
545
546 return 0;
547}
548
549void OCIOImpl::processorRelease(OCIO_ConstProcessorRcPtr *processor)
550{
551 MEM_delete(processor);
552}
553
554OCIO_ConstCPUProcessorRcPtr *OCIOImpl::processorGetCPUProcessor(
555 OCIO_ConstProcessorRcPtr *processor)
556{
557 ConstCPUProcessorRcPtr *cpu_processor = MEM_new<ConstCPUProcessorRcPtr>(__func__);
558 *cpu_processor = (*(ConstProcessorRcPtr *)processor)->getDefaultCPUProcessor();
559 return (OCIO_ConstCPUProcessorRcPtr *)cpu_processor;
560}
561
562void OCIOImpl::cpuProcessorApply(OCIO_ConstCPUProcessorRcPtr *cpu_processor,
563 OCIO_PackedImageDesc *img)
564{
565 try {
566 (*(ConstCPUProcessorRcPtr *)cpu_processor)->apply(*(PackedImageDesc *)img);
567 }
568 catch (Exception &exception) {
569 OCIO_reportException(exception);
570 }
571}
572
573void OCIOImpl::cpuProcessorApply_predivide(OCIO_ConstCPUProcessorRcPtr *cpu_processor,
574 OCIO_PackedImageDesc *img_)
575{
576 try {
577 PackedImageDesc *img = (PackedImageDesc *)img_;
578 int channels = img->getNumChannels();
579
580 if (channels == 4) {
581 /* Convert from premultiplied alpha to straight alpha. */
582 assert(img->isFloat());
583 float *pixel = (float *)img->getData();
584 size_t pixel_count = img->getWidth() * img->getHeight();
585 for (size_t i = 0; i < pixel_count; i++, pixel += 4) {
586 float alpha = pixel[3];
587 if (alpha != 0.0f && alpha != 1.0f) {
588 float inv_alpha = 1.0f / alpha;
589 pixel[0] *= inv_alpha;
590 pixel[1] *= inv_alpha;
591 pixel[2] *= inv_alpha;
592 }
593 }
594 }
595
596 (*(ConstCPUProcessorRcPtr *)cpu_processor)->apply(*img);
597
598 if (channels == 4) {
599 /* Back to premultiplied alpha. */
600 assert(img->isFloat());
601 float *pixel = (float *)img->getData();
602 size_t pixel_count = img->getWidth() * img->getHeight();
603 for (size_t i = 0; i < pixel_count; i++, pixel += 4) {
604 float alpha = pixel[3];
605 if (alpha != 0.0f && alpha != 1.0f) {
606 pixel[0] *= alpha;
607 pixel[1] *= alpha;
608 pixel[2] *= alpha;
609 }
610 }
611 }
612 }
613 catch (Exception &exception) {
614 OCIO_reportException(exception);
615 }
616}
617
618bool OCIOImpl::cpuProcessorIsNoOp(OCIO_ConstCPUProcessorRcPtr *cpu_processor)
619{
620 return (*(ConstCPUProcessorRcPtr *)cpu_processor)->isNoOp();
621}
622
623void OCIOImpl::cpuProcessorApplyRGB(OCIO_ConstCPUProcessorRcPtr *cpu_processor, float *pixel)
624{
625 (*(ConstCPUProcessorRcPtr *)cpu_processor)->applyRGB(pixel);
626}
627
628void OCIOImpl::cpuProcessorApplyRGBA(OCIO_ConstCPUProcessorRcPtr *cpu_processor, float *pixel)
629{
630 (*(ConstCPUProcessorRcPtr *)cpu_processor)->applyRGBA(pixel);
631}
632
633void OCIOImpl::cpuProcessorApplyRGBA_predivide(OCIO_ConstCPUProcessorRcPtr *cpu_processor,
634 float *pixel)
635{
636 if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
637 (*(ConstCPUProcessorRcPtr *)cpu_processor)->applyRGBA(pixel);
638 }
639 else {
640 float alpha, inv_alpha;
641
642 alpha = pixel[3];
643 inv_alpha = 1.0f / alpha;
644
645 pixel[0] *= inv_alpha;
646 pixel[1] *= inv_alpha;
647 pixel[2] *= inv_alpha;
648
649 (*(ConstCPUProcessorRcPtr *)cpu_processor)->applyRGBA(pixel);
650
651 pixel[0] *= alpha;
652 pixel[1] *= alpha;
653 pixel[2] *= alpha;
654 }
655}
656
657void OCIOImpl::cpuProcessorRelease(OCIO_ConstCPUProcessorRcPtr *cpu_processor)
658{
659 MEM_delete(cpu_processor);
660}
661
662const char *OCIOImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs)
663{
664 return (*(ConstColorSpaceRcPtr *)cs)->getName();
665}
666
667const char *OCIOImpl::colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs)
668{
669 return (*(ConstColorSpaceRcPtr *)cs)->getDescription();
670}
671
672const char *OCIOImpl::colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs)
673{
674 return (*(ConstColorSpaceRcPtr *)cs)->getFamily();
675}
676
677int OCIOImpl::colorSpaceGetNumAliases(OCIO_ConstColorSpaceRcPtr *cs)
678{
679 return (*(ConstColorSpaceRcPtr *)cs)->getNumAliases();
680}
681const char *OCIOImpl::colorSpaceGetAlias(OCIO_ConstColorSpaceRcPtr *cs, const int index)
682{
683 return (*(ConstColorSpaceRcPtr *)cs)->getAlias(index);
684}
685
686OCIO_ConstProcessorRcPtr *OCIOImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr *config_,
687 const char *input,
688 const char *view,
689 const char *display,
690 const char *look,
691 const float scale,
692 const float exponent,
693 const float temperature,
694 const float tint,
695 const bool use_white_balance,
696 const bool inverse)
697
698{
699 ConstConfigRcPtr config = *(ConstConfigRcPtr *)config_;
700 GroupTransformRcPtr group = GroupTransform::Create();
701
702 /* Linear transforms. */
703 if (scale != 1.0f || use_white_balance) {
704 /* Always apply exposure and/or white balance in scene linear. */
705 ColorSpaceTransformRcPtr ct = ColorSpaceTransform::Create();
706 ct->setSrc(input);
707 ct->setDst(ROLE_SCENE_LINEAR);
708 group->appendTransform(ct);
709
710 /* Make further transforms aware of the color space change. */
711 input = ROLE_SCENE_LINEAR;
712
713 /* Apply scale. */
714 MatrixTransformRcPtr mt = MatrixTransform::Create();
715 float3x3 matrix = float3x3::identity() * scale;
716
717 /* Apply white balance. */
718 if (use_white_balance) {
719 /* Compute white point of the scene space in XYZ.*/
720 float3x3 xyz_to_scene;
721 configGetXYZtoSceneLinear(config_, xyz_to_scene.ptr());
722 float3x3 scene_to_xyz = blender::math::invert(xyz_to_scene);
723 float3 target = scene_to_xyz * float3(1.0f);
724
725 /* Add operations to the matrix.
726 * Note: Since we're multiplying from the right, the operations here will be performed in
727 * reverse list order (scene-to-XYZ, then adaption, then XYZ-to-scene, then exposure). */
728 matrix *= xyz_to_scene;
730 blender::math::whitepoint_from_temp_tint(temperature, tint), target);
731 matrix *= scene_to_xyz;
732 }
733
734 mt->setMatrix(double4x4(blender::math::transpose(matrix)).base_ptr());
735 group->appendTransform(mt);
736 }
737
738 /* Add look transform. */
739 bool use_look = (look != nullptr && look[0] != 0);
740 if (use_look) {
741 const char *look_output = LookTransform::GetLooksResultColorSpace(
742 config, config->getCurrentContext(), look);
743
744 if (look_output != nullptr && look_output[0] != 0) {
745 LookTransformRcPtr lt = LookTransform::Create();
746 lt->setSrc(input);
747 lt->setDst(look_output);
748 lt->setLooks(look);
749 group->appendTransform(lt);
750
751 /* Make further transforms aware of the color space change. */
752 input = look_output;
753 }
754 else {
755 /* For empty looks, no output color space is returned. */
756 use_look = false;
757 }
758 }
759
760 /* Add view and display transform. */
761 DisplayViewTransformRcPtr dvt = DisplayViewTransform::Create();
762 dvt->setSrc(input);
763 dvt->setLooksBypass(use_look);
764 dvt->setView(view);
765 dvt->setDisplay(display);
766 group->appendTransform(dvt);
767
768 /* Gamma. */
769 if (exponent != 1.0f) {
770 ExponentTransformRcPtr et = ExponentTransform::Create();
771 const double value[4] = {exponent, exponent, exponent, 1.0};
772 et->setValue(value);
773 group->appendTransform(et);
774 }
775
776 if (inverse) {
777 group->setDirection(TRANSFORM_DIR_INVERSE);
778 }
779
780 /* Create processor from transform. This is the moment were OCIO validates
781 * the entire transform, no need to check for the validity of inputs above. */
782 ConstProcessorRcPtr *p = MEM_new<ConstProcessorRcPtr>(__func__);
783
784 try {
785 *p = config->getProcessor(group);
786
787 if (*p) {
788 return (OCIO_ConstProcessorRcPtr *)p;
789 }
790 }
791 catch (Exception &exception) {
792 OCIO_reportException(exception);
793 }
794
795 MEM_delete(p);
796 return NULL;
797}
798
799OCIO_PackedImageDesc *OCIOImpl::createOCIO_PackedImageDesc(float *data,
800 long width,
801 long height,
802 long numChannels,
803 long chanStrideBytes,
804 long xStrideBytes,
805 long yStrideBytes)
806{
807 try {
808 void *mem = MEM_mallocN(sizeof(PackedImageDesc), __func__);
809 PackedImageDesc *id = new (mem) PackedImageDesc(data,
810 width,
811 height,
812 numChannels,
813 BIT_DEPTH_F32,
814 chanStrideBytes,
815 xStrideBytes,
816 yStrideBytes);
817
818 return (OCIO_PackedImageDesc *)id;
819 }
820 catch (Exception &exception) {
821 OCIO_reportException(exception);
822 }
823
824 return NULL;
825}
826
827void OCIOImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
828{
829 MEM_delete((PackedImageDesc *)id);
830}
831
832const char *OCIOImpl::getVersionString(void)
833{
834 return GetVersion();
835}
836
837int OCIOImpl::getVersionHex(void)
838{
839 return GetVersionHex();
840}
float srgb_to_linearrgb(float c)
void unit_m3(float m[3][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])
struct OCIO_ConstCPUProcessorRc * OCIO_ConstCPUProcessorRcPtr
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v
btMatrix3x3 inverse() const
Return the inverse of the matrix.
local_group_size(16, 16) .push_constant(Type b
#define NULL
#define fabsf(x)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
MatBase< T, NumCol, NumRow > transpose(const MatBase< T, NumRow, NumCol > &mat)
float3 whitepoint_from_temp_tint(float temperature, float tint)
CartesianBasis invert(const CartesianBasis &basis)
float3x3 chromatic_adaption_matrix(const float3 &from_XYZ, const float3 &to_XYZ)
MatBase< float, 3, 3 > float3x3
MatBase< double, 4, 4 > double4x4
static const float OCIO_XYZ_TO_REC709[3][3]
Definition ocio_capi.h:35
static const float OCIO_ACES_TO_XYZ[3][3]
Definition ocio_capi.h:40
static void OCIO_reportException(Exception &exception)
Definition ocio_impl.cc:53
static bool to_scene_linear_matrix(ConstConfigRcPtr &config, const char *colorspace, float to_scene_linear[3][3])
Definition ocio_impl.cc:295
static void OCIO_reportError(const char *err)
Definition ocio_impl.cc:46
static float compare_floats(float a, float b, float abs_diff, int ulp_diff)
Definition ocio_impl.cc:438
#define OCIO_abort()
Definition ocio_impl.cc:32
ccl_device_inline int abs(int x)
Definition util/math.h:120