2fa66e5d2f5de06e23983654a3cc9a8b7c7bb5e4
[blender.git] / intern / opencolorio / ocio_capi.cpp
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 <string.h>
30
31 #include <OpenColorIO/OpenColorIO.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #define OCIO_CAPI_IMPLEMENTATION
36 #include "ocio_capi.h"
37
38 #ifdef NDEBUG
39 #  define OCIO_abort()
40 #else
41 #  include <stdlib.h>
42 #  define OCIO_abort() abort()
43 #endif
44
45 #if defined(_MSC_VER)
46 #  define __func__ __FUNCTION__
47 #endif
48
49 #define MEM_NEW(type) new(MEM_mallocN(sizeof(type), __func__)) type()
50 #define MEM_DELETE(what, type) if(what) { what->~type(); MEM_freeN(what); } (void)0
51
52 static void OCIO_reportError(const char *err)
53 {
54         std::cerr << "OpenColorIO Error: " << err << std::endl;
55
56         // OCIO_abort();
57 }
58
59 static void OCIO_reportException(Exception &exception)
60 {
61         OCIO_reportError(exception.what());
62 }
63
64 ConstConfigRcPtr *OCIO_getCurrentConfig(void)
65 {
66         ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr);
67
68         try {
69                 *config = GetCurrentConfig();
70
71                 if(*config)
72                         return config;
73         }
74         catch (Exception &exception) {
75                 OCIO_reportException(exception);
76         }
77
78         MEM_DELETE(config, ConstConfigRcPtr);
79
80         return NULL;
81 }
82
83 ConstConfigRcPtr *OCIO_getDefaultConfig(void)
84 {
85         return NULL;
86 }
87
88 void OCIO_setCurrentConfig(const ConstConfigRcPtr *config)
89 {
90         try {
91                 SetCurrentConfig(*config);
92         }
93         catch (Exception &exception) {
94                 OCIO_reportException(exception);
95         }
96 }
97
98 ConstConfigRcPtr *OCIO_configCreateFromEnv(void)
99 {
100         ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr);
101
102         try {
103                 *config = Config::CreateFromEnv();
104
105                 if (*config)
106                         return config;
107         }
108         catch (Exception &exception) {
109                 OCIO_reportException(exception);
110         }
111
112         MEM_DELETE(config, ConstConfigRcPtr);
113
114         return NULL;
115 }
116
117
118 ConstConfigRcPtr *OCIO_configCreateFromFile(const char *filename)
119 {
120         ConstConfigRcPtr *config = MEM_NEW(ConstConfigRcPtr);
121
122         try {
123                 *config = Config::CreateFromFile(filename);
124
125                 if (*config)
126                         return config;
127         }
128         catch (Exception &exception) {
129                 OCIO_reportException(exception);
130         }
131
132         MEM_DELETE(config, ConstConfigRcPtr);
133
134         return NULL;
135 }
136
137 void OCIO_configRelease(ConstConfigRcPtr *config)
138 {
139         MEM_DELETE(config, ConstConfigRcPtr);
140 }
141
142 int OCIO_configGetNumColorSpaces(ConstConfigRcPtr *config)
143 {
144         try {
145                 return (*config)->getNumColorSpaces();
146         }
147         catch (Exception &exception) {
148                 OCIO_reportException(exception);
149         }
150
151         return 0;
152 }
153
154 const char *OCIO_configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index)
155 {
156         try {
157                 return (*config)->getColorSpaceNameByIndex(index);
158         }
159         catch (Exception &exception) {
160                 OCIO_reportException(exception);
161         }
162
163         return NULL;
164 }
165
166 ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *config, const char *name)
167 {
168         ConstColorSpaceRcPtr *cs = MEM_NEW(ConstColorSpaceRcPtr);
169
170         try {
171                 *cs = (*config)->getColorSpace(name);
172
173                 if (*cs)
174                         return cs;
175         }
176         catch (Exception &exception) {
177                 OCIO_reportException(exception);
178         }
179
180         MEM_DELETE(cs, ConstColorSpaceRcPtr);
181
182         return NULL;
183 }
184
185 int OCIO_configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name)
186 {
187         try {
188                 return (*config)->getIndexForColorSpace(name);
189         }
190         catch (Exception &exception) {
191                 OCIO_reportException(exception);
192         }
193
194         return -1;
195 }
196
197 const char *OCIO_configGetDefaultDisplay(ConstConfigRcPtr *config)
198 {
199         try {
200                 return (*config)->getDefaultDisplay();
201         }
202         catch (Exception &exception) {
203                 OCIO_reportException(exception);
204         }
205
206         return NULL;
207 }
208
209 int OCIO_configGetNumDisplays(ConstConfigRcPtr* config)
210 {
211         try {
212                 return (*config)->getNumDisplays();
213         }
214         catch (Exception &exception) {
215                 OCIO_reportException(exception);
216         }
217
218         return 0;
219 }
220
221 const char *OCIO_configGetDisplay(ConstConfigRcPtr *config, int index)
222 {
223         try {
224                 return (*config)->getDisplay(index);
225         }
226         catch (Exception &exception) {
227                 OCIO_reportException(exception);
228         }
229
230         return NULL;
231 }
232
233 const char *OCIO_configGetDefaultView(ConstConfigRcPtr *config, const char *display)
234 {
235         try {
236                 return (*config)->getDefaultView(display);
237         }
238         catch (Exception &exception) {
239                 OCIO_reportException(exception);
240         }
241
242         return NULL;
243 }
244
245 int OCIO_configGetNumViews(ConstConfigRcPtr *config, const char *display)
246 {
247         try {
248                 return (*config)->getNumViews(display);
249         }
250         catch (Exception &exception) {
251                 OCIO_reportException(exception);
252         }
253
254         return 0;
255 }
256
257 const char *OCIO_configGetView(ConstConfigRcPtr *config, const char *display, int index)
258 {
259         try {
260                 return (*config)->getView(display, index);
261         }
262         catch (Exception &exception) {
263                 OCIO_reportException(exception);
264         }
265
266         return NULL;
267 }
268
269 const char *OCIO_configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view)
270 {
271         try {
272                 return (*config)->getDisplayColorSpaceName(display, view);
273         }
274         catch (Exception &exception) {
275                 OCIO_reportException(exception);
276         }
277
278         return NULL;
279 }
280
281 int OCIO_colorSpaceIsInvertible(ConstColorSpaceRcPtr *cs)
282 {
283         const char *family = (*cs)->getFamily();
284
285         if (!strcmp(family, "rrt") || !strcmp(family, "display")) {
286                 /* assume display and rrt transformations are not invertible
287                  * in fact some of them could be, but it doesn't make much sense to allow use them as invertible
288                  */
289                 return false;
290         }
291
292         if ((*cs)->isData()) {
293                 /* data color spaces don't have transformation at all */
294                 return true;
295         }
296
297         if ((*cs)->getTransform(COLORSPACE_DIR_TO_REFERENCE)) {
298                 /* if there's defined transform to reference space, color space could be converted to scene linear */
299                 return true;
300         }
301
302         return true;
303 }
304
305 void OCIO_colorSpaceRelease(ConstColorSpaceRcPtr *cs)
306 {
307         MEM_DELETE(cs, ConstColorSpaceRcPtr);
308 }
309
310 ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName)
311 {
312         ConstProcessorRcPtr *p = MEM_NEW(ConstProcessorRcPtr);
313
314         try {
315                 *p = (*config)->getProcessor(srcName, dstName);
316
317                 if (*p)
318                         return p;
319         }
320         catch (Exception &exception) {
321                 OCIO_reportException(exception);
322         }
323
324         MEM_DELETE(p, ConstProcessorRcPtr);
325
326         return 0;
327 }
328
329 ConstProcessorRcPtr *OCIO_configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform)
330 {
331         ConstProcessorRcPtr *p = MEM_NEW(ConstProcessorRcPtr);
332
333         try {
334                 *p = (*config)->getProcessor(*transform);
335
336                 if (*p)
337                         return p;
338         }
339         catch (Exception &exception) {
340                 OCIO_reportException(exception);
341         }
342
343         MEM_DELETE(p, ConstProcessorRcPtr);
344
345         return NULL;
346 }
347
348 void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img)
349 {
350         try {
351                 (*processor)->apply(*img);
352         }
353         catch (Exception &exception) {
354                 OCIO_reportException(exception);
355         }
356 }
357
358 void OCIO_processorApply_predivide(ConstProcessorRcPtr *processor, PackedImageDesc *img)
359 {
360         try {
361                 int channels = img->getNumChannels();
362
363                 if (channels == 4) {
364                         float *pixels = img->getData();
365
366                         int width = img->getWidth();
367                         int height = img->getHeight();
368
369                         for (int y = 0; y < height; y++) {
370                                 for (int x = 0; x < width; x++) {
371                                         float *pixel = pixels + 4 * (y * width + x);
372
373                                         OCIO_processorApplyRGBA_predivide(processor, pixel);
374                                 }
375                         }
376                 }
377                 else {
378                         (*processor)->apply(*img);
379                 }
380         }
381         catch (Exception &exception) {
382                 OCIO_reportException(exception);
383         }
384 }
385
386 void OCIO_processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel)
387 {
388         (*processor)->applyRGB(pixel);
389 }
390
391 void OCIO_processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel)
392 {
393         (*processor)->applyRGBA(pixel);
394 }
395
396 void OCIO_processorApplyRGBA_predivide(ConstProcessorRcPtr *processor, float *pixel)
397 {
398         if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
399                 (*processor)->applyRGBA(pixel);
400         }
401         else {
402                 float alpha, inv_alpha;
403
404                 alpha = pixel[3];
405                 inv_alpha = 1.0f / alpha;
406
407                 pixel[0] *= inv_alpha;
408                 pixel[1] *= inv_alpha;
409                 pixel[2] *= inv_alpha;
410
411                 (*processor)->applyRGBA(pixel);
412
413                 pixel[0] *= alpha;
414                 pixel[1] *= alpha;
415                 pixel[2] *= alpha;
416         }
417 }
418
419 void OCIO_processorRelease(ConstProcessorRcPtr *p)
420 {
421         p->~ConstProcessorRcPtr();
422         MEM_freeN(p);
423 }
424
425 const char *OCIO_colorSpaceGetName(ConstColorSpaceRcPtr *cs)
426 {
427         return (*cs)->getName();
428 }
429
430 const char *OCIO_colorSpaceGetDescription(ConstColorSpaceRcPtr *cs)
431 {
432         return (*cs)->getDescription();
433 }
434
435 const char *OCIO_colorSpaceGetFamily(ConstColorSpaceRcPtr *cs)
436 {
437         return (*cs)->getFamily();
438 }
439
440 DisplayTransformRcPtr *OCIO_createDisplayTransform(void)
441 {
442         DisplayTransformRcPtr *dt = MEM_NEW(DisplayTransformRcPtr);
443
444         *dt = DisplayTransform::Create();
445
446         return dt;
447 }
448
449 void OCIO_displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name)
450 {
451         (*dt)->setInputColorSpaceName(name);
452 }
453
454 void OCIO_displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name)
455 {
456         (*dt)->setDisplay(name);
457 }
458
459 void OCIO_displayTransformSetView(DisplayTransformRcPtr *dt, const char *name)
460 {
461         (*dt)->setView(name);
462 }
463
464 void OCIO_displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t)
465 {
466         (*dt)->setDisplayCC(*t);
467 }
468
469 void OCIO_displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t)
470 {
471         (*dt)->setLinearCC(*t);
472 }
473
474 void OCIO_displayTransformRelease(DisplayTransformRcPtr *dt)
475 {
476         MEM_DELETE(dt, DisplayTransformRcPtr);
477 }
478
479 PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height, long numChannels,
480                                             long chanStrideBytes, long xStrideBytes, long yStrideBytes)
481 {
482         try {
483                 void *mem = MEM_mallocN(sizeof(PackedImageDesc), __func__);
484                 PackedImageDesc *id = new(mem) PackedImageDesc(data, width, height, numChannels, chanStrideBytes, xStrideBytes, yStrideBytes);
485
486                 return id;
487         }
488         catch (Exception &exception) {
489                 OCIO_reportException(exception);
490         }
491
492         return NULL;
493 }
494
495 void OCIO_packedImageDescRelease(PackedImageDesc* id)
496 {
497         MEM_DELETE(id, PackedImageDesc);
498 }
499
500 ExponentTransformRcPtr *OCIO_createExponentTransform(void)
501 {
502         ExponentTransformRcPtr *et = MEM_NEW(ExponentTransformRcPtr);
503
504         *et = ExponentTransform::Create();
505
506         return et;
507 }
508
509 void OCIO_exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent)
510 {
511         (*et)->setValue(exponent);
512 }
513
514 void OCIO_exponentTransformRelease(ExponentTransformRcPtr *et)
515 {
516         MEM_DELETE(et, ExponentTransformRcPtr);
517 }
518
519 MatrixTransformRcPtr *OCIO_createMatrixTransform(void)
520 {
521         MatrixTransformRcPtr *mt = MEM_NEW(MatrixTransformRcPtr);
522
523         *mt = MatrixTransform::Create();
524
525         return mt;
526 }
527
528 void OCIO_matrixTransformSetValue(MatrixTransformRcPtr *mt, const float *m44, const float *offset4)
529 {
530         (*mt)->setValue(m44, offset4);
531 }
532
533 void OCIO_matrixTransformRelease(MatrixTransformRcPtr *mt)
534 {
535         MEM_DELETE(mt, MatrixTransformRcPtr);
536 }
537
538 void OCIO_matrixTransformScale(float * m44, float * offset4, const float *scale4f)
539 {
540         MatrixTransform::Scale(m44, offset4, scale4f);
541 }