Ghost Context Refactor
[blender-staging.git] / intern / opencolorio / ocio_impl.cc
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2012 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Xavier Thomas
22  *                 Lukas Toene,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <iostream>
29 #include <sstream>
30 #include <string.h>
31
32 #include <OpenColorIO/OpenColorIO.h>
33
34 using namespace OCIO_NAMESPACE;
35
36 #include "MEM_guardedalloc.h"
37
38 #include "ocio_impl.h"
39
40 #if !defined(WITH_ASSERT_ABORT)
41 #  define OCIO_abort()
42 #else
43 #  include <stdlib.h>
44 #  define OCIO_abort() abort()
45 #endif
46
47 #if defined(_MSC_VER)
48 #  define __func__ __FUNCTION__
49 #endif
50
51 static void OCIO_reportError(const char *err)
52 {
53         std::cerr << "OpenColorIO Error: " << err << std::endl;
54
55         OCIO_abort();
56 }
57
58 static void OCIO_reportException(Exception &exception)
59 {
60         OCIO_reportError(exception.what());
61 }
62
63 OCIO_ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void)
64 {
65         ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr);
66
67         try {
68                 *config = GetCurrentConfig();
69
70                 if (*config)
71                         return (OCIO_ConstConfigRcPtr *) config;
72         }
73         catch (Exception &exception) {
74                 OCIO_reportException(exception);
75         }
76
77         OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr);
78
79         return NULL;
80 }
81
82 void OCIOImpl::setCurrentConfig(const OCIO_ConstConfigRcPtr *config)
83 {
84         try {
85                 SetCurrentConfig(*(ConstConfigRcPtr *) config);
86         }
87         catch (Exception &exception) {
88                 OCIO_reportException(exception);
89         }
90 }
91
92 OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void)
93 {
94         ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr);
95
96         try {
97                 *config = Config::CreateFromEnv();
98
99                 if (*config)
100                         return (OCIO_ConstConfigRcPtr *) config;
101         }
102         catch (Exception &exception) {
103                 OCIO_reportException(exception);
104         }
105
106         OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr);
107
108         return NULL;
109 }
110
111
112 OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename)
113 {
114         ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr);
115
116         try {
117                 *config = Config::CreateFromFile(filename);
118
119                 if (*config)
120                         return (OCIO_ConstConfigRcPtr *) config;
121         }
122         catch (Exception &exception) {
123                 OCIO_reportException(exception);
124         }
125
126         OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr);
127
128         return NULL;
129 }
130
131 void OCIOImpl::configRelease(OCIO_ConstConfigRcPtr *config)
132 {
133         OBJECT_GUARDED_DELETE((ConstConfigRcPtr *) config, ConstConfigRcPtr);
134 }
135
136 int OCIOImpl::configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config)
137 {
138         try {
139                 return (*(ConstConfigRcPtr *) config)->getNumColorSpaces();
140         }
141         catch (Exception &exception) {
142                 OCIO_reportException(exception);
143         }
144
145         return 0;
146 }
147
148 const char *OCIOImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *config, int index)
149 {
150         try {
151                 return (*(ConstConfigRcPtr *) config)->getColorSpaceNameByIndex(index);
152         }
153         catch (Exception &exception) {
154                 OCIO_reportException(exception);
155         }
156
157         return NULL;
158 }
159
160 OCIO_ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(OCIO_ConstConfigRcPtr *config, const char *name)
161 {
162         ConstColorSpaceRcPtr *cs = OBJECT_GUARDED_NEW(ConstColorSpaceRcPtr);
163
164         try {
165                 *cs = (*(ConstConfigRcPtr *) config)->getColorSpace(name);
166
167                 if (*cs)
168                         return (OCIO_ConstColorSpaceRcPtr *) cs;
169         }
170         catch (Exception &exception) {
171                 OCIO_reportException(exception);
172         }
173
174         OBJECT_GUARDED_DELETE(cs, ConstColorSpaceRcPtr);
175
176         return NULL;
177 }
178
179 int OCIOImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name)
180 {
181         try {
182                 return (*(ConstConfigRcPtr *) config)->getIndexForColorSpace(name);
183         }
184         catch (Exception &exception) {
185                 OCIO_reportException(exception);
186         }
187
188         return -1;
189 }
190
191 const char *OCIOImpl::configGetDefaultDisplay(OCIO_ConstConfigRcPtr *config)
192 {
193         try {
194                 return (*(ConstConfigRcPtr *) config)->getDefaultDisplay();
195         }
196         catch (Exception &exception) {
197                 OCIO_reportException(exception);
198         }
199
200         return NULL;
201 }
202
203 int OCIOImpl::configGetNumDisplays(OCIO_ConstConfigRcPtr* config)
204 {
205         try {
206                 return (*(ConstConfigRcPtr *) config)->getNumDisplays();
207         }
208         catch (Exception &exception) {
209                 OCIO_reportException(exception);
210         }
211
212         return 0;
213 }
214
215 const char *OCIOImpl::configGetDisplay(OCIO_ConstConfigRcPtr *config, int index)
216 {
217         try {
218                 return (*(ConstConfigRcPtr *) config)->getDisplay(index);
219         }
220         catch (Exception &exception) {
221                 OCIO_reportException(exception);
222         }
223
224         return NULL;
225 }
226
227 const char *OCIOImpl::configGetDefaultView(OCIO_ConstConfigRcPtr *config, const char *display)
228 {
229         try {
230                 return (*(ConstConfigRcPtr *) config)->getDefaultView(display);
231         }
232         catch (Exception &exception) {
233                 OCIO_reportException(exception);
234         }
235
236         return NULL;
237 }
238
239 int OCIOImpl::configGetNumViews(OCIO_ConstConfigRcPtr *config, const char *display)
240 {
241         try {
242                 return (*(ConstConfigRcPtr *) config)->getNumViews(display);
243         }
244         catch (Exception &exception) {
245                 OCIO_reportException(exception);
246         }
247
248         return 0;
249 }
250
251 const char *OCIOImpl::configGetView(OCIO_ConstConfigRcPtr *config, const char *display, int index)
252 {
253         try {
254                 return (*(ConstConfigRcPtr *) config)->getView(display, index);
255         }
256         catch (Exception &exception) {
257                 OCIO_reportException(exception);
258         }
259
260         return NULL;
261 }
262
263 const char *OCIOImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr *config, const char *display, const char *view)
264 {
265         try {
266                 return (*(ConstConfigRcPtr *) config)->getDisplayColorSpaceName(display, view);
267         }
268         catch (Exception &exception) {
269                 OCIO_reportException(exception);
270         }
271
272         return NULL;
273 }
274
275 int OCIOImpl::configGetNumLooks(OCIO_ConstConfigRcPtr *config)
276 {
277         try {
278                 return (*(ConstConfigRcPtr *) config)->getNumLooks();
279         }
280         catch (Exception &exception) {
281                 OCIO_reportException(exception);
282         }
283
284         return 0;
285 }
286
287 const char *OCIOImpl::configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, int index)
288 {
289         try {
290                 return (*(ConstConfigRcPtr *) config)->getLookNameByIndex(index);
291         }
292         catch (Exception &exception) {
293                 OCIO_reportException(exception);
294         }
295
296         return NULL;
297 }
298
299 OCIO_ConstLookRcPtr *OCIOImpl::configGetLook(OCIO_ConstConfigRcPtr *config, const char *name)
300 {
301         ConstLookRcPtr *look = OBJECT_GUARDED_NEW(ConstLookRcPtr);
302
303         try {
304                 *look = (*(ConstConfigRcPtr *) config)->getLook(name);
305
306                 if (*look)
307                         return (OCIO_ConstLookRcPtr *) look;
308         }
309         catch (Exception &exception) {
310                 OCIO_reportException(exception);
311         }
312
313         OBJECT_GUARDED_DELETE(look, ConstLookRcPtr);
314
315         return NULL;
316 }
317
318 const char *OCIOImpl::lookGetProcessSpace(OCIO_ConstLookRcPtr *look)
319 {
320         return (*(ConstLookRcPtr *) look)->getProcessSpace();
321 }
322
323 void OCIOImpl::lookRelease(OCIO_ConstLookRcPtr *look)
324 {
325         OBJECT_GUARDED_DELETE((ConstLookRcPtr *) look, ConstLookRcPtr);
326 }
327
328 int OCIOImpl::colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs_)
329 {
330         ConstColorSpaceRcPtr *cs = (ConstColorSpaceRcPtr *) cs_;
331         const char *family = (*cs)->getFamily();
332
333         if (!strcmp(family, "rrt") || !strcmp(family, "display")) {
334                 /* assume display and rrt transformations are not invertible
335                  * in fact some of them could be, but it doesn't make much sense to allow use them as invertible
336                  */
337                 return false;
338         }
339
340         if ((*cs)->isData()) {
341                 /* data color spaces don't have transformation at all */
342                 return true;
343         }
344
345         if ((*cs)->getTransform(COLORSPACE_DIR_TO_REFERENCE)) {
346                 /* if there's defined transform to reference space, color space could be converted to scene linear */
347                 return true;
348         }
349
350         return true;
351 }
352
353 int OCIOImpl::colorSpaceIsData(OCIO_ConstColorSpaceRcPtr *cs)
354 {
355         return (*(ConstColorSpaceRcPtr *) cs)->isData();
356 }
357
358 void OCIOImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs)
359 {
360         OBJECT_GUARDED_DELETE((ConstColorSpaceRcPtr *) cs, ConstColorSpaceRcPtr);
361 }
362
363 OCIO_ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName)
364 {
365         ConstProcessorRcPtr *p = OBJECT_GUARDED_NEW(ConstProcessorRcPtr);
366
367         try {
368                 *p = (*(ConstConfigRcPtr *) config)->getProcessor(srcName, dstName);
369
370                 if (*p)
371                         return (OCIO_ConstProcessorRcPtr *) p;
372         }
373         catch (Exception &exception) {
374                 OCIO_reportException(exception);
375         }
376
377         OBJECT_GUARDED_DELETE(p, ConstProcessorRcPtr);
378
379         return 0;
380 }
381
382 OCIO_ConstProcessorRcPtr *OCIOImpl::configGetProcessor(OCIO_ConstConfigRcPtr *config, OCIO_ConstTransformRcPtr *transform)
383 {
384         ConstProcessorRcPtr *p = OBJECT_GUARDED_NEW(ConstProcessorRcPtr);
385
386         try {
387                 *p = (*(ConstConfigRcPtr *) config)->getProcessor(*(ConstTransformRcPtr *) transform);
388
389                 if (*p)
390                         return (OCIO_ConstProcessorRcPtr *) p;
391         }
392         catch (Exception &exception) {
393                 OCIO_reportException(exception);
394         }
395
396         OBJECT_GUARDED_DELETE(p, ConstProcessorRcPtr);
397
398         return NULL;
399 }
400
401 void OCIOImpl::processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img)
402 {
403         try {
404                 (*(ConstProcessorRcPtr *) processor)->apply(*(PackedImageDesc *) img);
405         }
406         catch (Exception &exception) {
407                 OCIO_reportException(exception);
408         }
409 }
410
411 void OCIOImpl::processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img_)
412 {
413         try {
414                 PackedImageDesc *img = (PackedImageDesc *) img_;
415                 int channels = img->getNumChannels();
416
417                 if (channels == 4) {
418                         float *pixels = img->getData();
419
420                         int width = img->getWidth();
421                         int height = img->getHeight();
422
423                         for (int y = 0; y < height; y++) {
424                                 for (int x = 0; x < width; x++) {
425                                         float *pixel = pixels + 4 * (y * width + x);
426
427                                         processorApplyRGBA_predivide(processor, pixel);
428                                 }
429                         }
430                 }
431                 else {
432                         (*(ConstProcessorRcPtr *) processor)->apply(*img);
433                 }
434         }
435         catch (Exception &exception) {
436                 OCIO_reportException(exception);
437         }
438 }
439
440 void OCIOImpl::processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel)
441 {
442         (*(ConstProcessorRcPtr *) processor)->applyRGB(pixel);
443 }
444
445 void OCIOImpl::processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel)
446 {
447         (*(ConstProcessorRcPtr *) processor)->applyRGBA(pixel);
448 }
449
450 void OCIOImpl::processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, float *pixel)
451 {
452         if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
453                 (*(ConstProcessorRcPtr *) processor)->applyRGBA(pixel);
454         }
455         else {
456                 float alpha, inv_alpha;
457
458                 alpha = pixel[3];
459                 inv_alpha = 1.0f / alpha;
460
461                 pixel[0] *= inv_alpha;
462                 pixel[1] *= inv_alpha;
463                 pixel[2] *= inv_alpha;
464
465                 (*(ConstProcessorRcPtr *) processor)->applyRGBA(pixel);
466
467                 pixel[0] *= alpha;
468                 pixel[1] *= alpha;
469                 pixel[2] *= alpha;
470         }
471 }
472
473 void OCIOImpl::processorRelease(OCIO_ConstProcessorRcPtr *p)
474 {
475         OBJECT_GUARDED_DELETE(p, ConstProcessorRcPtr);
476 }
477
478 const char *OCIOImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs)
479 {
480         return (*(ConstColorSpaceRcPtr *) cs)->getName();
481 }
482
483 const char *OCIOImpl::colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs)
484 {
485         return (*(ConstColorSpaceRcPtr *) cs)->getDescription();
486 }
487
488 const char *OCIOImpl::colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs)
489 {
490         return (*(ConstColorSpaceRcPtr *)cs)->getFamily();
491 }
492
493 OCIO_DisplayTransformRcPtr *OCIOImpl::createDisplayTransform(void)
494 {
495         DisplayTransformRcPtr *dt = OBJECT_GUARDED_NEW(DisplayTransformRcPtr);
496
497         *dt = DisplayTransform::Create();
498
499         return (OCIO_DisplayTransformRcPtr *) dt;
500 }
501
502 void OCIOImpl::displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr *dt, const char *name)
503 {
504         (*(DisplayTransformRcPtr *) dt)->setInputColorSpaceName(name);
505 }
506
507 void OCIOImpl::displayTransformSetDisplay(OCIO_DisplayTransformRcPtr *dt, const char *name)
508 {
509         (*(DisplayTransformRcPtr *) dt)->setDisplay(name);
510 }
511
512 void OCIOImpl::displayTransformSetView(OCIO_DisplayTransformRcPtr *dt, const char *name)
513 {
514         (*(DisplayTransformRcPtr *) dt)->setView(name);
515 }
516
517 void OCIOImpl::displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *t)
518 {
519         (*(DisplayTransformRcPtr *) dt)->setDisplayCC(* (ConstTransformRcPtr *) t);
520 }
521
522 void OCIOImpl::displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr *dt, OCIO_ConstTransformRcPtr *t)
523 {
524         (*(DisplayTransformRcPtr *) dt)->setLinearCC(*(ConstTransformRcPtr *) t);
525 }
526
527 void OCIOImpl::displayTransformSetLooksOverride(OCIO_DisplayTransformRcPtr *dt, const char *looks)
528 {
529         (*(DisplayTransformRcPtr *) dt)->setLooksOverride(looks);
530 }
531
532 void OCIOImpl::displayTransformSetLooksOverrideEnabled(OCIO_DisplayTransformRcPtr *dt, bool enabled)
533 {
534         (*(DisplayTransformRcPtr *) dt)->setLooksOverrideEnabled(enabled);
535 }
536
537 void OCIOImpl::displayTransformRelease(OCIO_DisplayTransformRcPtr *dt)
538 {
539         OBJECT_GUARDED_DELETE((DisplayTransformRcPtr *) dt, DisplayTransformRcPtr);
540 }
541
542 OCIO_PackedImageDesc *OCIOImpl::createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels,
543                                                            long chanStrideBytes, long xStrideBytes, long yStrideBytes)
544 {
545         try {
546                 void *mem = MEM_mallocN(sizeof(PackedImageDesc), __func__);
547                 PackedImageDesc *id = new(mem) PackedImageDesc(data, width, height, numChannels, chanStrideBytes, xStrideBytes, yStrideBytes);
548
549                 return (OCIO_PackedImageDesc *) id;
550         }
551         catch (Exception &exception) {
552                 OCIO_reportException(exception);
553         }
554
555         return NULL;
556 }
557
558 void OCIOImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc* id)
559 {
560         OBJECT_GUARDED_DELETE((PackedImageDesc *) id, PackedImageDesc);
561 }
562
563 OCIO_ExponentTransformRcPtr *OCIOImpl::createExponentTransform(void)
564 {
565         ExponentTransformRcPtr *et = OBJECT_GUARDED_NEW(ExponentTransformRcPtr);
566
567         *et = ExponentTransform::Create();
568
569         return (OCIO_ExponentTransformRcPtr *) et;
570 }
571
572 void OCIOImpl::exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, const float *exponent)
573 {
574         (*(ExponentTransformRcPtr *) et)->setValue(exponent);
575 }
576
577 void OCIOImpl::exponentTransformRelease(OCIO_ExponentTransformRcPtr *et)
578 {
579         OBJECT_GUARDED_DELETE((ExponentTransformRcPtr *) et, ExponentTransformRcPtr);
580 }
581
582 OCIO_MatrixTransformRcPtr *OCIOImpl::createMatrixTransform(void)
583 {
584         MatrixTransformRcPtr *mt = OBJECT_GUARDED_NEW(MatrixTransformRcPtr);
585
586         *mt = MatrixTransform::Create();
587
588         return (OCIO_MatrixTransformRcPtr *) mt;
589 }
590
591 void OCIOImpl::matrixTransformSetValue(OCIO_MatrixTransformRcPtr *mt, const float *m44, const float *offset4)
592 {
593         (*(MatrixTransformRcPtr *) mt)->setValue(m44, offset4);
594 }
595
596 void OCIOImpl::matrixTransformRelease(OCIO_MatrixTransformRcPtr *mt)
597 {
598         OBJECT_GUARDED_DELETE((MatrixTransformRcPtr *) mt, MatrixTransformRcPtr);
599 }
600
601 void OCIOImpl::matrixTransformScale(float *m44, float *offset4, const float *scale4f)
602 {
603         MatrixTransform::Scale(m44, offset4, scale4f);
604 }
605
606 const char *OCIOImpl::getVersionString(void)
607 {
608         return GetVersion();
609 }
610
611 int OCIOImpl::getVersionHex(void)
612 {
613         return GetVersionHex();
614 }