Audaspace: porting upstream pulseaudio fixes.
[blender.git] / intern / opencolorio / fallback_impl.cc
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2012 Blender Foundation.
17  * All rights reserved.
18  */
19
20 #include <algorithm>
21 #include <cstring>
22 #include <vector>
23
24 #include "BLI_math_color.h"
25 #include "BLI_math_vector.h"
26 #include "MEM_guardedalloc.h"
27
28 #include "ocio_impl.h"
29
30 using std::max;
31
32 #define CONFIG_DEFAULT ((OCIO_ConstConfigRcPtr *)1)
33
34 enum TransformType {
35   TRANSFORM_LINEAR_TO_SRGB,
36   TRANSFORM_SRGB_TO_LINEAR,
37   TRANSFORM_SCALE,
38   TRANSFORM_EXPONENT,
39   TRANSFORM_UNKNOWN,
40 };
41
42 #define COLORSPACE_LINEAR ((OCIO_ConstColorSpaceRcPtr *)1)
43 #define COLORSPACE_SRGB ((OCIO_ConstColorSpaceRcPtr *)2)
44
45 typedef struct OCIO_PackedImageDescription {
46   float *data;
47   long width;
48   long height;
49   long numChannels;
50   long chanStrideBytes;
51   long xStrideBytes;
52   long yStrideBytes;
53 } OCIO_PackedImageDescription;
54
55 struct FallbackTransform {
56   FallbackTransform() : type(TRANSFORM_UNKNOWN), scale(1.0f), exponent(1.0f)
57   {
58   }
59
60   virtual ~FallbackTransform()
61   {
62   }
63
64   void applyRGB(float *pixel)
65   {
66     if (type == TRANSFORM_LINEAR_TO_SRGB) {
67       pixel[0] *= scale;
68       pixel[1] *= scale;
69       pixel[2] *= scale;
70
71       linearrgb_to_srgb_v3_v3(pixel, pixel);
72
73       pixel[0] = powf(max(0.0f, pixel[0]), exponent);
74       pixel[1] = powf(max(0.0f, pixel[1]), exponent);
75       pixel[2] = powf(max(0.0f, pixel[2]), exponent);
76     }
77     else if (type == TRANSFORM_SRGB_TO_LINEAR) {
78       srgb_to_linearrgb_v3_v3(pixel, pixel);
79     }
80     else if (type == TRANSFORM_EXPONENT) {
81       pixel[0] = powf(max(0.0f, pixel[0]), exponent);
82       pixel[1] = powf(max(0.0f, pixel[1]), exponent);
83       pixel[2] = powf(max(0.0f, pixel[2]), exponent);
84     }
85     else if (type == TRANSFORM_SCALE) {
86       pixel[0] *= scale;
87       pixel[1] *= scale;
88       pixel[2] *= scale;
89     }
90   }
91
92   void applyRGBA(float *pixel)
93   {
94     applyRGB(pixel);
95   }
96
97   TransformType type;
98   /* Scale transform. */
99   float scale;
100   /* Exponent transform. */
101   float exponent;
102
103   MEM_CXX_CLASS_ALLOC_FUNCS("FallbackTransform");
104 };
105
106 struct FallbackProcessor {
107   FallbackProcessor(const FallbackTransform &transform) : transform(transform)
108   {
109   }
110
111   void applyRGB(float *pixel)
112   {
113     transform.applyRGB(pixel);
114   }
115
116   void applyRGBA(float *pixel)
117   {
118     transform.applyRGBA(pixel);
119   }
120
121   FallbackTransform transform;
122
123   MEM_CXX_CLASS_ALLOC_FUNCS("FallbackProcessor");
124 };
125
126 OCIO_ConstConfigRcPtr *FallbackImpl::getCurrentConfig(void)
127 {
128   return CONFIG_DEFAULT;
129 }
130
131 void FallbackImpl::setCurrentConfig(const OCIO_ConstConfigRcPtr * /*config*/)
132 {
133 }
134
135 OCIO_ConstConfigRcPtr *FallbackImpl::configCreateFromEnv(void)
136 {
137   return NULL;
138 }
139
140 OCIO_ConstConfigRcPtr *FallbackImpl::configCreateFromFile(const char * /*filename*/)
141 {
142   return CONFIG_DEFAULT;
143 }
144
145 void FallbackImpl::configRelease(OCIO_ConstConfigRcPtr * /*config*/)
146 {
147 }
148
149 int FallbackImpl::configGetNumColorSpaces(OCIO_ConstConfigRcPtr * /*config*/)
150 {
151   return 2;
152 }
153
154 const char *FallbackImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr * /*config*/,
155                                                          int index)
156 {
157   if (index == 0)
158     return "Linear";
159   else if (index == 1)
160     return "sRGB";
161
162   return NULL;
163 }
164
165 OCIO_ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(OCIO_ConstConfigRcPtr * /*config*/,
166                                                              const char *name)
167 {
168   if (strcmp(name, "scene_linear") == 0)
169     return COLORSPACE_LINEAR;
170   else if (strcmp(name, "color_picking") == 0)
171     return COLORSPACE_SRGB;
172   else if (strcmp(name, "texture_paint") == 0)
173     return COLORSPACE_LINEAR;
174   else if (strcmp(name, "default_byte") == 0)
175     return COLORSPACE_SRGB;
176   else if (strcmp(name, "default_float") == 0)
177     return COLORSPACE_LINEAR;
178   else if (strcmp(name, "default_sequencer") == 0)
179     return COLORSPACE_SRGB;
180   else if (strcmp(name, "Linear") == 0)
181     return COLORSPACE_LINEAR;
182   else if (strcmp(name, "sRGB") == 0)
183     return COLORSPACE_SRGB;
184
185   return NULL;
186 }
187
188 int FallbackImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name)
189 {
190   OCIO_ConstColorSpaceRcPtr *cs = configGetColorSpace(config, name);
191
192   if (cs == COLORSPACE_LINEAR) {
193     return 0;
194   }
195   else if (cs == COLORSPACE_SRGB) {
196     return 1;
197   }
198   return -1;
199 }
200
201 const char *FallbackImpl::configGetDefaultDisplay(OCIO_ConstConfigRcPtr * /*config*/)
202 {
203   return "sRGB";
204 }
205
206 int FallbackImpl::configGetNumDisplays(OCIO_ConstConfigRcPtr * /*config*/)
207 {
208   return 1;
209 }
210
211 const char *FallbackImpl::configGetDisplay(OCIO_ConstConfigRcPtr * /*config*/, int index)
212 {
213   if (index == 0) {
214     return "sRGB";
215   }
216   return NULL;
217 }
218
219 const char *FallbackImpl::configGetDefaultView(OCIO_ConstConfigRcPtr * /*config*/,
220                                                const char * /*display*/)
221 {
222   return "Standard";
223 }
224
225 int FallbackImpl::configGetNumViews(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/)
226 {
227   return 1;
228 }
229
230 const char *FallbackImpl::configGetView(OCIO_ConstConfigRcPtr * /*config*/,
231                                         const char * /*display*/,
232                                         int index)
233 {
234   if (index == 0) {
235     return "Standard";
236   }
237   return NULL;
238 }
239
240 const char *FallbackImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr * /*config*/,
241                                                          const char * /*display*/,
242                                                          const char * /*view*/)
243 {
244   return "sRGB";
245 }
246
247 void FallbackImpl::configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr * /*config*/, float *rgb)
248 {
249   /* Here we simply use the older Blender assumed primaries of
250    * ITU-BT.709 / sRGB, or 0.2126729 0.7151522 0.0721750. Brute
251    * force stupid, but only plausible option given no color management
252    * system in place.
253    */
254
255   rgb[0] = 0.2126f;
256   rgb[1] = 0.7152f;
257   rgb[2] = 0.0722f;
258 }
259
260 void FallbackImpl::configGetXYZtoRGB(OCIO_ConstConfigRcPtr * /*config*/, float xyz_to_rgb[3][3])
261 {
262   /* Default to ITU-BT.709. */
263   memcpy(xyz_to_rgb, OCIO_XYZ_TO_LINEAR_SRGB, sizeof(OCIO_XYZ_TO_LINEAR_SRGB));
264 }
265
266 int FallbackImpl::configGetNumLooks(OCIO_ConstConfigRcPtr * /*config*/)
267 {
268   return 0;
269 }
270
271 const char *FallbackImpl::configGetLookNameByIndex(OCIO_ConstConfigRcPtr * /*config*/,
272                                                    int /*index*/)
273 {
274   return "";
275 }
276
277 OCIO_ConstLookRcPtr *FallbackImpl::configGetLook(OCIO_ConstConfigRcPtr * /*config*/,
278                                                  const char * /*name*/)
279 {
280   return NULL;
281 }
282
283 const char *FallbackImpl::lookGetProcessSpace(OCIO_ConstLookRcPtr * /*look*/)
284 {
285   return NULL;
286 }
287
288 void FallbackImpl::lookRelease(OCIO_ConstLookRcPtr * /*look*/)
289 {
290 }
291
292 int FallbackImpl::colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr * /*cs*/)
293 {
294   return 1;
295 }
296
297 int FallbackImpl::colorSpaceIsData(OCIO_ConstColorSpaceRcPtr * /*cs*/)
298 {
299   return 0;
300 }
301
302 void FallbackImpl::colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr * /*config*/,
303                                        OCIO_ConstColorSpaceRcPtr *cs,
304                                        bool &is_scene_linear,
305                                        bool &is_srgb)
306 {
307   if (cs == COLORSPACE_LINEAR) {
308     is_scene_linear = true;
309     is_srgb = false;
310   }
311   else if (cs == COLORSPACE_SRGB) {
312     is_scene_linear = false;
313     is_srgb = true;
314   }
315   else {
316     is_scene_linear = false;
317     is_srgb = false;
318   }
319 }
320
321 void FallbackImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr * /*cs*/)
322 {
323 }
324
325 OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config,
326                                                                     const char *srcName,
327                                                                     const char *dstName)
328 {
329   OCIO_ConstColorSpaceRcPtr *cs_src = configGetColorSpace(config, srcName);
330   OCIO_ConstColorSpaceRcPtr *cs_dst = configGetColorSpace(config, dstName);
331   FallbackTransform transform;
332   if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) {
333     transform.type = TRANSFORM_LINEAR_TO_SRGB;
334   }
335   else if (cs_src == COLORSPACE_SRGB && cs_dst == COLORSPACE_LINEAR) {
336     transform.type = TRANSFORM_SRGB_TO_LINEAR;
337   }
338   else {
339     transform.type = TRANSFORM_UNKNOWN;
340   }
341   return (OCIO_ConstProcessorRcPtr *)new FallbackProcessor(transform);
342 }
343
344 OCIO_ConstCPUProcessorRcPtr *FallbackImpl::processorGetCPUProcessor(
345     OCIO_ConstProcessorRcPtr *processor)
346 {
347   /* Just make a copy of the processor so that we are compatible with OCIO
348    * which does need it as a separate object. */
349   FallbackProcessor *fallback_processor = (FallbackProcessor *)processor;
350   return (OCIO_ConstCPUProcessorRcPtr *)new FallbackProcessor(*fallback_processor);
351 }
352
353 void FallbackImpl::processorRelease(OCIO_ConstProcessorRcPtr *processor)
354 {
355   delete (FallbackProcessor *)(processor);
356 }
357
358 void FallbackImpl::cpuProcessorApply(OCIO_ConstCPUProcessorRcPtr *cpu_processor,
359                                      OCIO_PackedImageDesc *img)
360 {
361   /* OCIO_TODO stride not respected, channels must be 3 or 4 */
362   OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription *)img;
363   int channels = desc->numChannels;
364   float *pixels = desc->data;
365   int width = desc->width;
366   int height = desc->height;
367   int x, y;
368
369   for (y = 0; y < height; y++) {
370     for (x = 0; x < width; x++) {
371       float *pixel = pixels + channels * (y * width + x);
372
373       if (channels == 4)
374         cpuProcessorApplyRGBA(cpu_processor, pixel);
375       else if (channels == 3)
376         cpuProcessorApplyRGB(cpu_processor, pixel);
377     }
378   }
379 }
380
381 void FallbackImpl::cpuProcessorApply_predivide(OCIO_ConstCPUProcessorRcPtr *cpu_processor,
382                                                OCIO_PackedImageDesc *img)
383 {
384   /* OCIO_TODO stride not respected, channels must be 3 or 4 */
385   OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription *)img;
386   int channels = desc->numChannels;
387   float *pixels = desc->data;
388   int width = desc->width;
389   int height = desc->height;
390   int x, y;
391
392   for (y = 0; y < height; y++) {
393     for (x = 0; x < width; x++) {
394       float *pixel = pixels + channels * (y * width + x);
395
396       if (channels == 4)
397         cpuProcessorApplyRGBA_predivide(cpu_processor, pixel);
398       else if (channels == 3)
399         cpuProcessorApplyRGB(cpu_processor, pixel);
400     }
401   }
402 }
403
404 void FallbackImpl::cpuProcessorApplyRGB(OCIO_ConstCPUProcessorRcPtr *cpu_processor, float *pixel)
405 {
406   ((FallbackProcessor *)cpu_processor)->applyRGB(pixel);
407 }
408
409 void FallbackImpl::cpuProcessorApplyRGBA(OCIO_ConstCPUProcessorRcPtr *cpu_processor, float *pixel)
410 {
411   ((FallbackProcessor *)cpu_processor)->applyRGBA(pixel);
412 }
413
414 void FallbackImpl::cpuProcessorApplyRGBA_predivide(OCIO_ConstCPUProcessorRcPtr *cpu_processor,
415                                                    float *pixel)
416 {
417   if (pixel[3] == 1.0f || pixel[3] == 0.0f) {
418     cpuProcessorApplyRGBA(cpu_processor, pixel);
419   }
420   else {
421     float alpha, inv_alpha;
422
423     alpha = pixel[3];
424     inv_alpha = 1.0f / alpha;
425
426     pixel[0] *= inv_alpha;
427     pixel[1] *= inv_alpha;
428     pixel[2] *= inv_alpha;
429
430     cpuProcessorApplyRGBA(cpu_processor, pixel);
431
432     pixel[0] *= alpha;
433     pixel[1] *= alpha;
434     pixel[2] *= alpha;
435   }
436 }
437
438 void FallbackImpl::cpuProcessorRelease(OCIO_ConstCPUProcessorRcPtr *cpu_processor)
439 {
440   delete (FallbackProcessor *)(cpu_processor);
441 }
442
443 const char *FallbackImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs)
444 {
445   if (cs == COLORSPACE_LINEAR) {
446     return "Linear";
447   }
448   else if (cs == COLORSPACE_SRGB) {
449     return "sRGB";
450   }
451   return NULL;
452 }
453
454 const char *FallbackImpl::colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr * /*cs*/)
455 {
456   return "";
457 }
458
459 const char *FallbackImpl::colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr * /*cs*/)
460 {
461   return "";
462 }
463
464 OCIO_ConstProcessorRcPtr *FallbackImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr * /*config*/,
465                                                                const char * /*input*/,
466                                                                const char * /*view*/,
467                                                                const char * /*display*/,
468                                                                const char * /*look*/,
469                                                                const float scale,
470                                                                const float exponent)
471 {
472   FallbackTransform transform;
473   transform.type = TRANSFORM_LINEAR_TO_SRGB;
474   transform.scale = scale;
475   transform.exponent = exponent;
476
477   return (OCIO_ConstProcessorRcPtr *)new FallbackProcessor(transform);
478 }
479
480 OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc(float *data,
481                                                                long width,
482                                                                long height,
483                                                                long numChannels,
484                                                                long chanStrideBytes,
485                                                                long xStrideBytes,
486                                                                long yStrideBytes)
487 {
488   OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription *)MEM_callocN(
489       sizeof(OCIO_PackedImageDescription), "OCIO_PackedImageDescription");
490   desc->data = data;
491   desc->width = width;
492   desc->height = height;
493   desc->numChannels = numChannels;
494   desc->chanStrideBytes = chanStrideBytes;
495   desc->xStrideBytes = xStrideBytes;
496   desc->yStrideBytes = yStrideBytes;
497   return (OCIO_PackedImageDesc *)desc;
498 }
499
500 void FallbackImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
501 {
502   MEM_freeN(id);
503 }
504
505 const char *FallbackImpl::getVersionString(void)
506 {
507   return "fallback";
508 }
509
510 int FallbackImpl::getVersionHex(void)
511 {
512   return 0;
513 }