Color management: use partial buffer update when painting image
[blender.git] / source / blender / imbuf / intern / openexr / openexr_api.cpp
1 /*
2  * ***** BEGIN GPLLICENSE 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  * Copyright by Gernot Ziegler <gz@lysator.liu.se>.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Austin Benesh, Ton Roosendaal (float, half, speedup, cleanup...).
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/imbuf/intern/openexr/openexr_api.cpp
29  *  \ingroup openexr
30  */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <stddef.h>
35 #include <string>
36 #include <set>
37
38
39 #include <openexr_api.h>
40
41 extern "C"
42 {
43
44 // The following prevents a linking error in debug mode for MSVC using the libs in CVS
45 #if defined(WITH_OPENEXR) && defined(_WIN32) && defined(_DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__)
46 _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
47 {
48 }
49 #endif
50
51 #include "MEM_guardedalloc.h"
52
53 #include "BLI_blenlib.h"
54 #include "BLI_math_color.h"
55 #include "BLI_threads.h"
56
57 #include "IMB_imbuf_types.h"
58 #include "IMB_imbuf.h"
59 #include "IMB_allocimbuf.h"
60 #include "IMB_metadata.h"
61
62 #include "openexr_multi.h"
63 }
64
65 #include <iostream>
66
67 #if defined(_WIN32) && !defined(FREE_WINDOWS)
68 #include <half.h>
69 #include <IlmImf/ImfVersion.h>
70 #include <IlmImf/ImfArray.h>
71 #include <IlmImf/ImfIO.h>
72 #include <IlmImf/ImfChannelList.h>
73 #include <IlmImf/ImfPixelType.h>
74 #include <IlmImf/ImfInputFile.h>
75 #include <IlmImf/ImfOutputFile.h>
76 #include <IlmImf/ImfCompression.h>
77 #include <IlmImf/ImfCompressionAttribute.h>
78 #include <IlmImf/ImfStringAttribute.h>
79 #include <Imath/ImathBox.h>
80 #else
81 #include <half.h>
82 #include <ImfVersion.h>
83 #include <ImathBox.h>
84 #include <ImfArray.h>
85 #include <ImfIO.h>
86 #include <ImfChannelList.h>
87 #include <ImfPixelType.h>
88 #include <ImfInputFile.h>
89 #include <ImfOutputFile.h>
90 #include <ImfCompression.h>
91 #include <ImfCompressionAttribute.h>
92 #include <ImfStringAttribute.h>
93 #endif
94
95 using namespace Imf;
96 using namespace Imath;
97
98 class Mem_IStream : public Imf::IStream
99 {
100 public:
101
102         Mem_IStream (unsigned char *exrbuf, size_t exrsize) :
103                 IStream("dummy"), _exrpos(0), _exrsize(exrsize) {
104                 _exrbuf = exrbuf;
105         }
106
107         virtual bool    read(char c[], int n);
108         virtual Int64   tellg();
109         virtual void    seekg(Int64 pos);
110         virtual void    clear();
111         //virtual ~Mem_IStream() {}; // unused
112
113 private:
114
115         Int64 _exrpos;
116         Int64 _exrsize;
117         unsigned char *_exrbuf;
118 };
119
120 bool Mem_IStream::read(char c[], int n)
121 {
122         if (n + _exrpos <= _exrsize) {
123                 memcpy(c, (void *)(&_exrbuf[_exrpos]), n);
124                 _exrpos += n;
125                 return true;
126         }
127         else
128                 return false;
129 }
130
131 Int64 Mem_IStream::tellg()
132 {
133         return _exrpos;
134 }
135
136 void Mem_IStream::seekg(Int64 pos)
137 {
138         _exrpos = pos;
139 }
140
141 void Mem_IStream::clear()
142 {
143 }
144
145 struct _RGBAZ {
146         half r;
147         half g;
148         half b;
149         half a;
150         half z;
151 };
152
153 typedef struct _RGBAZ RGBAZ;
154
155 extern "C"
156 {
157
158 int imb_is_a_openexr(unsigned char *mem)
159 {
160         return Imf::isImfMagic((const char *)mem);
161 }
162
163 static void openexr_header_compression(Header *header, int compression)
164 {
165         switch (compression) {
166                 case 0:
167                         header->compression() = NO_COMPRESSION;
168                         break;
169                 case 1:
170                         header->compression() = PXR24_COMPRESSION;
171                         break;
172                 case 2:
173                         header->compression() = ZIP_COMPRESSION;
174                         break;
175                 case 3:
176                         header->compression() = PIZ_COMPRESSION;
177                         break;
178                 case 4:
179                         header->compression() = RLE_COMPRESSION;
180                         break;
181                 default:
182                         header->compression() = ZIP_COMPRESSION;
183                         break;
184         }
185 }
186
187 static void openexr_header_metadata(Header *header, struct ImBuf *ibuf)
188 {
189         ImMetaData *info;
190
191         for (info = ibuf->metadata; info; info = info->next)
192                 header->insert(info->key, StringAttribute(info->value));
193 }
194
195 static int imb_save_openexr_half(struct ImBuf *ibuf, const char *name, int flags)
196 {
197         const int channels = ibuf->channels;
198         const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
199         const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
200         const int width = ibuf->x;
201         const int height = ibuf->y;
202
203         try
204         {
205                 Header header(width, height);
206
207                 openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
208                 openexr_header_metadata(&header, ibuf);
209
210                 header.channels().insert("R", Channel(HALF));
211                 header.channels().insert("G", Channel(HALF));
212                 header.channels().insert("B", Channel(HALF));
213                 if (is_alpha)
214                         header.channels().insert("A", Channel(HALF));
215                 if (is_zbuf)     // z we do as float always
216                         header.channels().insert("Z", Channel(Imf::FLOAT));
217
218                 FrameBuffer frameBuffer;
219                 OutputFile *file = new OutputFile(name, header);
220
221                 /* we store first everything in half array */
222                 RGBAZ *pixels = new RGBAZ[height * width];
223                 RGBAZ *to = pixels;
224                 int xstride = sizeof(RGBAZ);
225                 int ystride = xstride * width;
226
227                 /* indicate used buffers */
228                 frameBuffer.insert("R", Slice(HALF,  (char *) &pixels[0].r, xstride, ystride));
229                 frameBuffer.insert("G", Slice(HALF,  (char *) &pixels[0].g, xstride, ystride));
230                 frameBuffer.insert("B", Slice(HALF,  (char *) &pixels[0].b, xstride, ystride));
231                 if (is_alpha)
232                         frameBuffer.insert("A", Slice(HALF, (char *) &pixels[0].a, xstride, ystride));
233                 if (is_zbuf)
234                         frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *)(ibuf->zbuf_float + (height - 1) * width),
235                                                       sizeof(float), sizeof(float) * -width));
236                 if (ibuf->rect_float) {
237                         float *from;
238
239                         for (int i = ibuf->y - 1; i >= 0; i--) {
240                                 from = ibuf->rect_float + channels * i * width;
241
242                                 for (int j = ibuf->x; j > 0; j--) {
243                                         to->r = from[0];
244                                         to->g = from[1];
245                                         to->b = from[2];
246                                         to->a = (channels >= 4) ? from[3] : 1.0f;
247                                         to++; from += 4;
248                                 }
249                         }
250                 }
251                 else {
252                         unsigned char *from;
253
254                         if (ibuf->profile == IB_PROFILE_LINEAR_RGB) {
255                                 for (int i = ibuf->y - 1; i >= 0; i--) {
256                                         from = (unsigned char *)ibuf->rect + channels * i * width;
257
258                                         for (int j = ibuf->x; j > 0; j--) {
259                                                 to->r = (float)(from[0]) / 255.0f;
260                                                 to->g = (float)(from[1]) / 255.0f;
261                                                 to->b = (float)(from[2]) / 255.0f;
262                                                 to->a = (float)(channels >= 4) ? from[3] / 255.0f : 1.0f;
263                                                 to++; from += 4;
264                                         }
265                                 }
266                         }
267                         else {
268                                 for (int i = ibuf->y - 1; i >= 0; i--) {
269                                         from = (unsigned char *)ibuf->rect + channels * i * width;
270
271                                         for (int j = ibuf->x; j > 0; j--) {
272                                                 to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
273                                                 to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
274                                                 to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
275                                                 to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
276                                                 to++; from += 4;
277                                         }
278                                 }
279                         }
280                 }
281
282 //              printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
283
284                 file->setFrameBuffer(frameBuffer);
285                 file->writePixels(height);
286                 delete file;
287                 delete[] pixels;
288         }
289         catch (const std::exception &exc)
290         {
291                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
292                 if (ibuf) IMB_freeImBuf(ibuf);
293
294                 return (0);
295         }
296
297         return (1);
298 }
299
300 static int imb_save_openexr_float(struct ImBuf *ibuf, const char *name, int flags)
301 {
302         const int channels = ibuf->channels;
303         const int is_alpha = (channels >= 4) && (ibuf->planes == 32);
304         const int is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
305         const int width = ibuf->x;
306         const int height = ibuf->y;
307
308         try
309         {
310                 Header header(width, height);
311
312                 openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
313                 openexr_header_metadata(&header, ibuf);
314
315                 header.channels().insert("R", Channel(Imf::FLOAT));
316                 header.channels().insert("G", Channel(Imf::FLOAT));
317                 header.channels().insert("B", Channel(Imf::FLOAT));
318                 if (is_alpha)
319                         header.channels().insert("A", Channel(Imf::FLOAT));
320                 if (is_zbuf)
321                         header.channels().insert("Z", Channel(Imf::FLOAT));
322
323                 FrameBuffer frameBuffer;
324                 OutputFile *file = new OutputFile(name, header);
325                 int xstride = sizeof(float) * channels;
326                 int ystride = -xstride * width;
327                 float *rect[4] = {NULL, NULL, NULL, NULL};
328
329                 /* last scanline, stride negative */
330                 rect[0] = ibuf->rect_float + channels * (height - 1) * width;
331                 rect[1] = rect[0] + 1;
332                 rect[2] = rect[0] + 2;
333                 rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */
334
335                 frameBuffer.insert("R", Slice(Imf::FLOAT,  (char *)rect[0], xstride, ystride));
336                 frameBuffer.insert("G", Slice(Imf::FLOAT,  (char *)rect[1], xstride, ystride));
337                 frameBuffer.insert("B", Slice(Imf::FLOAT,  (char *)rect[2], xstride, ystride));
338                 if (is_alpha)
339                         frameBuffer.insert("A", Slice(Imf::FLOAT,  (char *)rect[3], xstride, ystride));
340                 if (is_zbuf)
341                         frameBuffer.insert("Z", Slice(Imf::FLOAT, (char *) (ibuf->zbuf_float + (height - 1) * width),
342                                                       sizeof(float), sizeof(float) * -width));
343                 file->setFrameBuffer(frameBuffer);
344                 file->writePixels(height);
345                 delete file;
346         }
347         catch (const std::exception &exc)
348         {
349                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
350                 if (ibuf) IMB_freeImBuf(ibuf);
351
352                 return (0);
353         }
354
355         return (1);
356         //      printf("OpenEXR-save: Done.\n");
357 }
358
359
360 int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
361 {
362         if (flags & IB_mem) {
363                 printf("OpenEXR-save: Create EXR in memory CURRENTLY NOT SUPPORTED !\n");
364                 imb_addencodedbufferImBuf(ibuf);
365                 ibuf->encodedsize = 0;
366                 return(0);
367         }
368
369         if (ibuf->ftype & OPENEXR_HALF)
370                 return imb_save_openexr_half(ibuf, name, flags);
371         else {
372                 /* when no float rect, we save as half (16 bits is sufficient) */
373                 if (ibuf->rect_float == NULL)
374                         return imb_save_openexr_half(ibuf, name, flags);
375                 else
376                         return imb_save_openexr_float(ibuf, name, flags);
377         }
378 }
379
380 /* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */
381
382 /* naming rules:
383  * - parse name from right to left
384  * - last character is channel ID, 1 char like 'A' 'R' 'G' 'B' 'X' 'Y' 'Z' 'W' 'U' 'V'
385  * - separated with a dot; the Pass name (like "Depth", "Color", "Diffuse" or "Combined")
386  * - separated with a dot: the Layer name (like "Lamp1" or "Walls" or "Characters")
387  */
388
389 static ListBase exrhandles = {NULL, NULL};
390
391 typedef struct ExrHandle {
392         struct ExrHandle *next, *prev;
393
394         InputFile *ifile;
395         TiledOutputFile *tofile;
396         OutputFile *ofile;
397         int tilex, tiley;
398         int width, height;
399         int mipmap;
400
401         ListBase channels;  /* flattened out, ExrChannel */
402         ListBase layers;    /* hierarchical, pointing in end to ExrChannel */
403 } ExrHandle;
404
405 /* flattened out channel */
406 typedef struct ExrChannel {
407         struct ExrChannel *next, *prev;
408
409         char name[EXR_TOT_MAXNAME + 1];  /* full name of layer+pass */
410         int xstride, ystride;            /* step to next pixel, to next scanline */
411         float *rect;                     /* first pointer to write in */
412         char chan_id;                    /* quick lookup of channel char */
413 } ExrChannel;
414
415
416 /* hierarchical; layers -> passes -> channels[] */
417 typedef struct ExrPass {
418         struct ExrPass *next, *prev;
419         char name[EXR_PASS_MAXNAME];
420         int totchan;
421         float *rect;
422         struct ExrChannel *chan[EXR_PASS_MAXCHAN];
423         char chan_id[EXR_PASS_MAXCHAN];
424 } ExrPass;
425
426 typedef struct ExrLayer {
427         struct ExrLayer *next, *prev;
428         char name[EXR_LAY_MAXNAME + 1];
429         ListBase passes;
430 } ExrLayer;
431
432 /* ********************** */
433
434 void *IMB_exr_get_handle(void)
435 {
436         ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
437         BLI_addtail(&exrhandles, data);
438         return data;
439 }
440
441 /* adds flattened ExrChannels */
442 /* xstride, ystride and rect can be done in set_channel too, for tile writing */
443 void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
444 {
445         ExrHandle *data = (ExrHandle *)handle;
446         ExrChannel *echan;
447
448         echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel");
449
450         if (layname) {
451                 char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
452                 BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
453                 BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
454
455                 BLI_snprintf(echan->name, sizeof(echan->name), "%s.%s", lay, pass);
456         }
457         else {
458                 BLI_strncpy(echan->name, passname, EXR_TOT_MAXNAME - 1);
459         }
460
461         echan->xstride = xstride;
462         echan->ystride = ystride;
463         echan->rect = rect;
464
465         // printf("added channel %s\n", echan->name);
466         BLI_addtail(&data->channels, echan);
467 }
468
469 /* only used for writing temp. render results (not image files) */
470 int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress)
471 {
472         ExrHandle *data = (ExrHandle *)handle;
473         Header header(width, height);
474         ExrChannel *echan;
475
476         data->width = width;
477         data->height = height;
478
479         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
480                 header.channels().insert(echan->name, Channel(Imf::FLOAT));
481
482         openexr_header_compression(&header, compress);
483         // openexr_header_metadata(&header, ibuf); // no imbuf. cant write
484         /* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */
485
486         header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
487
488         /* avoid crash/abort when we don't have permission to write here */
489         try {
490                 data->ofile = new OutputFile(filename, header);
491         }
492         catch (const std::exception &exc) {
493                 std::cerr << "IMB_exr_begin_write: ERROR: " << exc.what() << std::endl;
494                 data->ofile = NULL;
495         }
496
497         return (data->ofile != NULL);
498 }
499
500 void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
501 {
502         ExrHandle *data = (ExrHandle *)handle;
503         Header header(width, height);
504         ExrChannel *echan;
505
506         data->tilex = tilex;
507         data->tiley = tiley;
508         data->width = width;
509         data->height = height;
510         data->mipmap = mipmap;
511
512         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next)
513                 header.channels().insert(echan->name, Channel(Imf::FLOAT));
514
515         header.setTileDescription(TileDescription(tilex, tiley, (mipmap) ? MIPMAP_LEVELS : ONE_LEVEL));
516         header.lineOrder() = RANDOM_Y;
517         header.compression() = RLE_COMPRESSION;
518
519         header.insert("BlenderMultiChannel", StringAttribute("Blender V2.43"));
520
521         data->tofile = new TiledOutputFile(filename, header);
522 }
523
524 /* read from file */
525 int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height)
526 {
527         ExrHandle *data = (ExrHandle *)handle;
528
529         if (BLI_exists(filename) && BLI_file_size(filename) > 32) {   /* 32 is arbitrary, but zero length files crashes exr */
530                 data->ifile = new InputFile(filename);
531                 if (data->ifile) {
532                         Box2i dw = data->ifile->header().dataWindow();
533                         data->width = *width  = dw.max.x - dw.min.x + 1;
534                         data->height = *height = dw.max.y - dw.min.y + 1;
535
536                         const ChannelList &channels = data->ifile->header().channels();
537
538                         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
539                                 IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
540
541                         return 1;
542                 }
543         }
544         return 0;
545 }
546
547 /* still clumsy name handling, layers/channels can be ordered as list in list later */
548 void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
549 {
550         ExrHandle *data = (ExrHandle *)handle;
551         ExrChannel *echan;
552         char name[EXR_TOT_MAXNAME + 1];
553
554         if (layname) {
555                 char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
556                 BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
557                 BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
558
559                 BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
560         }
561         else
562                 BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
563
564         echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
565
566         if (echan) {
567                 echan->xstride = xstride;
568                 echan->ystride = ystride;
569                 echan->rect = rect;
570         }
571         else
572                 printf("IMB_exrtile_set_channel error %s\n", name);
573 }
574
575 void IMB_exrtile_clear_channels(void *handle)
576 {
577         ExrHandle *data = (ExrHandle *)handle;
578         BLI_freelistN(&data->channels);
579 }
580
581 void IMB_exrtile_write_channels(void *handle, int partx, int party, int level)
582 {
583         ExrHandle *data = (ExrHandle *)handle;
584         FrameBuffer frameBuffer;
585         ExrChannel *echan;
586
587         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
588                 float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
589
590                 frameBuffer.insert(echan->name, Slice(Imf::FLOAT,  (char *)rect,
591                                                       echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
592         }
593
594         data->tofile->setFrameBuffer(frameBuffer);
595
596         try {
597                 // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
598                 data->tofile->writeTile(partx / data->tilex, party / data->tiley, level);
599         }
600         catch (const std::exception &exc) {
601                 std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
602         }
603 }
604
605 void IMB_exr_write_channels(void *handle)
606 {
607         ExrHandle *data = (ExrHandle *)handle;
608         FrameBuffer frameBuffer;
609         ExrChannel *echan;
610
611         if (data->channels.first) {
612                 for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
613                         /* last scanline, stride negative */
614                         float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
615
616                         frameBuffer.insert(echan->name, Slice(Imf::FLOAT,  (char *)rect,
617                                                               echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
618                 }
619
620                 data->ofile->setFrameBuffer(frameBuffer);
621                 try {
622                         data->ofile->writePixels(data->height);
623                 }
624                 catch (const std::exception &exc) {
625                         std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
626                 }
627         }
628         else {
629                 printf("Error: attempt to save MultiLayer without layers.\n");
630         }
631 }
632
633 void IMB_exr_read_channels(void *handle)
634 {
635         ExrHandle *data = (ExrHandle *)handle;
636         FrameBuffer frameBuffer;
637         ExrChannel *echan;
638
639         /* check if exr was saved with previous versions of blender which flipped images */
640         const StringAttribute *ta = data->ifile->header().findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
641         short flip = (ta && strncmp(ta->value().c_str(), "Blender V2.43", 13) == 0); /* 'previous multilayer attribute, flipped */
642
643         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
644
645                 if (echan->rect) {
646                         if (flip)
647                                 frameBuffer.insert(echan->name, Slice(Imf::FLOAT,  (char *)echan->rect,
648                                                                       echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
649                         else
650                                 frameBuffer.insert(echan->name, Slice(Imf::FLOAT,  (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width),
651                                                                       echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
652                 }
653                 else
654                         printf("warning, channel with no rect set %s\n", echan->name);
655         }
656
657         data->ifile->setFrameBuffer(frameBuffer);
658
659         try {
660                 data->ifile->readPixels(0, data->height - 1);
661         }
662         catch (const std::exception &exc) {
663                 std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
664         }
665 }
666
667 void IMB_exr_multilayer_convert(void *handle, void *base,
668                                 void * (*addlayer)(void *base, const char *str),
669                                 void (*addpass)(void *base, void *lay, const char *str,
670                                                 float *rect, int totchan, const char *chan_id))
671 {
672         ExrHandle *data = (ExrHandle *)handle;
673         ExrLayer *lay;
674         ExrPass *pass;
675
676         if (data->layers.first == NULL) {
677                 printf("cannot convert multilayer, no layers in handle\n");
678                 return;
679         }
680
681         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
682                 void *laybase = addlayer(base, lay->name);
683                 if (laybase) {
684                         for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
685                                 addpass(base, laybase, pass->name, pass->rect, pass->totchan, pass->chan_id);
686                                 pass->rect = NULL;
687                         }
688                 }
689         }
690 }
691
692
693 void IMB_exr_close(void *handle)
694 {
695         ExrHandle *data = (ExrHandle *)handle;
696         ExrLayer *lay;
697         ExrPass *pass;
698
699         if (data->ifile)
700                 delete data->ifile;
701         else if (data->ofile)
702                 delete data->ofile;
703         else if (data->tofile)
704                 delete data->tofile;
705
706         data->ifile = NULL;
707         data->ofile = NULL;
708         data->tofile = NULL;
709
710         BLI_freelistN(&data->channels);
711
712         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
713                 for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next)
714                         if (pass->rect)
715                                 MEM_freeN(pass->rect);
716                 BLI_freelistN(&lay->passes);
717         }
718         BLI_freelistN(&data->layers);
719
720         BLI_remlink(&exrhandles, data);
721         MEM_freeN(data);
722 }
723
724 /* ********* */
725
726 /* get a substring from the end of the name, separated by '.' */
727 static int imb_exr_split_token(const char *str, const char *end, const char **token)
728 {
729         int maxlen = end - str;
730         int len = 0;
731         while (len < maxlen && *(end - len - 1) != '.') {
732                 len++;
733         }
734
735         *token = end - len;
736         return len;
737 }
738
739 static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
740 {
741         const char *name = echan->name;
742         const char *end = name + strlen(name);
743         const char *token;
744         char tokenbuf[EXR_TOT_MAXNAME];
745         int len;
746
747         /* last token is single character channel identifier */
748         len = imb_exr_split_token(name, end, &token);
749         if (len == 0) {
750                 printf("multilayer read: bad channel name: %s\n", name);
751                 return 0;
752         }
753         else if (len > 1) {
754                 BLI_strncpy(tokenbuf, token, len);
755                 printf("multilayer read: channel token too long: %s\n", tokenbuf);
756                 return 0;
757         }
758         echan->chan_id = token[0];
759         end -= len + 1; /* +1 to skip '.' separator */
760
761         /* second token is pass name */
762         len = imb_exr_split_token(name, end, &token);
763         if (len == 0) {
764                 printf("multilayer read: bad channel name: %s\n", name);
765                 return 0;
766         }
767         BLI_strncpy(passname, token, len + 1);
768         end -= len + 1; /* +1 to skip '.' separator */
769
770         /* all preceding tokens combined as layer name */
771         if (end > name)
772                 BLI_strncpy(layname, name, (int)(end - name) + 1);
773         else
774                 layname[0] = '\0';
775
776         return 1;
777 }
778
779 static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
780 {
781         ExrLayer *lay = (ExrLayer *)BLI_findstring(lb, layname, offsetof(ExrLayer, name));
782
783         if (lay == NULL) {
784                 lay = (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
785                 BLI_addtail(lb, lay);
786                 BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
787         }
788
789         return lay;
790 }
791
792 static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
793 {
794         ExrPass *pass = (ExrPass *)BLI_findstring(lb, passname, offsetof(ExrPass, name));
795
796         if (pass == NULL) {
797                 pass = (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
798
799                 if (strcmp(passname, "Combined") == 0)
800                         BLI_addhead(lb, pass);
801                 else
802                         BLI_addtail(lb, pass);
803         }
804
805         BLI_strncpy(pass->name, passname, EXR_LAY_MAXNAME);
806
807         return pass;
808 }
809
810 /* creates channels, makes a hierarchy and assigns memory to channels */
811 static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
812 {
813         ExrLayer *lay;
814         ExrPass *pass;
815         ExrChannel *echan;
816         ExrHandle *data = (ExrHandle *)IMB_exr_get_handle();
817         int a;
818         char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
819
820         data->ifile = file;
821         data->width = width;
822         data->height = height;
823
824         const ChannelList &channels = data->ifile->header().channels();
825
826         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
827                 IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
828
829         /* now try to sort out how to assign memory to the channels */
830         /* first build hierarchical layer list */
831         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
832                 if (imb_exr_split_channel_name(echan, layname, passname) ) {
833                         ExrLayer *lay = imb_exr_get_layer(&data->layers, layname);
834                         ExrPass *pass = imb_exr_get_pass(&lay->passes, passname);
835
836                         pass->chan[pass->totchan] = echan;
837                         pass->totchan++;
838                         if (pass->totchan >= EXR_PASS_MAXCHAN)
839                                 break;
840                 }
841         }
842         if (echan) {
843                 printf("error, too many channels in one pass: %s\n", echan->name);
844                 IMB_exr_close(data);
845                 return NULL;
846         }
847
848         /* with some heuristics, try to merge the channels in buffers */
849         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
850                 for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
851                         if (pass->totchan) {
852                                 pass->rect = (float *)MEM_mapallocN(width * height * pass->totchan * sizeof(float), "pass rect");
853                                 if (pass->totchan == 1) {
854                                         echan = pass->chan[0];
855                                         echan->rect = pass->rect;
856                                         echan->xstride = 1;
857                                         echan->ystride = width;
858                                         pass->chan_id[0] = echan->chan_id;
859                                 }
860                                 else {
861                                         char lookup[256];
862
863                                         memset(lookup, 0, sizeof(lookup));
864
865                                         /* we can have RGB(A), XYZ(W), UVA */
866                                         if (pass->totchan == 3 || pass->totchan == 4) {
867                                                 if (pass->chan[0]->chan_id == 'B' || pass->chan[1]->chan_id == 'B' ||  pass->chan[2]->chan_id == 'B') {
868                                                         lookup[(unsigned int)'R'] = 0;
869                                                         lookup[(unsigned int)'G'] = 1;
870                                                         lookup[(unsigned int)'B'] = 2;
871                                                         lookup[(unsigned int)'A'] = 3;
872                                                 }
873                                                 else if (pass->chan[0]->chan_id == 'Y' || pass->chan[1]->chan_id == 'Y' ||  pass->chan[2]->chan_id == 'Y') {
874                                                         lookup[(unsigned int)'X'] = 0;
875                                                         lookup[(unsigned int)'Y'] = 1;
876                                                         lookup[(unsigned int)'Z'] = 2;
877                                                         lookup[(unsigned int)'W'] = 3;
878                                                 }
879                                                 else {
880                                                         lookup[(unsigned int)'U'] = 0;
881                                                         lookup[(unsigned int)'V'] = 1;
882                                                         lookup[(unsigned int)'A'] = 2;
883                                                 }
884                                                 for (a = 0; a < pass->totchan; a++) {
885                                                         echan = pass->chan[a];
886                                                         echan->rect = pass->rect + lookup[(unsigned int)echan->chan_id];
887                                                         echan->xstride = pass->totchan;
888                                                         echan->ystride = width * pass->totchan;
889                                                         pass->chan_id[(unsigned int)lookup[(unsigned int)echan->chan_id]] = echan->chan_id;
890                                                 }
891                                         }
892                                         else { /* unknown */
893                                                 for (a = 0; a < pass->totchan; a++) {
894                                                         echan = pass->chan[a];
895                                                         echan->rect = pass->rect + a;
896                                                         echan->xstride = pass->totchan;
897                                                         echan->ystride = width * pass->totchan;
898                                                         pass->chan_id[a] = echan->chan_id;
899                                                 }
900                                         }
901                                 }
902                         }
903                 }
904         }
905
906         return data;
907 }
908
909
910 /* ********************************************************* */
911
912 /* debug only */
913 static void exr_print_filecontents(InputFile *file)
914 {
915         const ChannelList &channels = file->header().channels();
916
917         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
918                 const Channel &channel = i.channel();
919                 printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
920         }
921 }
922
923 /* for non-multilayer, map  R G B A channel names to something that's in this file */
924 static const char *exr_rgba_channelname(InputFile *file, const char *chan)
925 {
926         const ChannelList &channels = file->header().channels();
927
928         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
929                 /* const Channel &channel = i.channel(); */ /* Not used yet */
930                 const char *str = i.name();
931                 int len = strlen(str);
932                 if (len) {
933                         if (BLI_strcasecmp(chan, str + len - 1) == 0) {
934                                 return str;
935                         }
936                 }
937         }
938         return chan;
939 }
940
941 static int exr_has_zbuffer(InputFile *file)
942 {
943         return !(file->header().channels().findChannel("Z") == NULL);
944 }
945
946 static int exr_has_alpha(InputFile *file)
947 {
948         return !(file->header().channels().findChannel("A") == NULL);
949 }
950
951 static int exr_is_multilayer(InputFile *file)
952 {
953         const StringAttribute *comments = file->header().findTypedAttribute<StringAttribute>("BlenderMultiChannel");
954         const ChannelList &channels = file->header().channels();
955         std::set <std::string> layerNames;
956
957         channels.layers(layerNames);
958
959         if (comments || layerNames.size() > 1)
960                 return 1;
961
962         return 0;
963 }
964
965 struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags)
966 {
967         struct ImBuf *ibuf = NULL;
968         InputFile *file = NULL;
969
970         if (imb_is_a_openexr(mem) == 0) return(NULL);
971
972         try
973         {
974                 Mem_IStream *membuf = new Mem_IStream(mem, size);
975                 int is_multi;
976                 file = new InputFile(*membuf);
977
978                 Box2i dw = file->header().dataWindow();
979                 const int width  = dw.max.x - dw.min.x + 1;
980                 const int height = dw.max.y - dw.min.y + 1;
981
982                 //printf("OpenEXR-load: image data window %d %d %d %d\n",
983                 //         dw.min.x, dw.min.y, dw.max.x, dw.max.y);
984
985                 if (0) // debug
986                         exr_print_filecontents(file);
987
988                 is_multi = exr_is_multilayer(file);
989
990                 /* do not make an ibuf when */
991                 if (is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) {
992                         printf("Error: can't process EXR multilayer file\n");
993                 }
994                 else {
995                         const int is_alpha = exr_has_alpha(file);
996
997                         ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, 0);
998                         ibuf->ftype = OPENEXR;
999
1000                         /* openEXR is linear as per EXR spec */
1001                         ibuf->profile = IB_PROFILE_LINEAR_RGB;
1002
1003                         if (!(flags & IB_test)) {
1004                                 if (is_multi) { /* only enters with IB_multilayer flag set */
1005                                         /* constructs channels for reading, allocates memory in channels */
1006                                         ExrHandle *handle = imb_exr_begin_read_mem(file, width, height);
1007                                         if (handle) {
1008                                                 IMB_exr_read_channels(handle);
1009                                                 ibuf->userdata = handle;         /* potential danger, the caller has to check for this! */
1010                                         }
1011                                 }
1012                                 else {
1013                                         FrameBuffer frameBuffer;
1014                                         float *first;
1015                                         int xstride = sizeof(float) * 4;
1016                                         int ystride = -xstride * width;
1017
1018                                         imb_addrectfloatImBuf(ibuf);
1019
1020                                         /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */
1021                                         first = ibuf->rect_float - 4 * (dw.min.x - dw.min.y * width);
1022                                         /* but, since we read y-flipped (negative y stride) we move to last scanline */
1023                                         first += 4 * (height - 1) * width;
1024
1025                                         frameBuffer.insert(exr_rgba_channelname(file, "R"),
1026                                                            Slice(Imf::FLOAT,  (char *) first, xstride, ystride));
1027                                         frameBuffer.insert(exr_rgba_channelname(file, "G"),
1028                                                            Slice(Imf::FLOAT,  (char *) (first + 1), xstride, ystride));
1029                                         frameBuffer.insert(exr_rgba_channelname(file, "B"),
1030                                                            Slice(Imf::FLOAT,  (char *) (first + 2), xstride, ystride));
1031
1032                                         /* 1.0 is fill value, this still neesd to be assigned even when (is_alpha == 0) */
1033                                         frameBuffer.insert(exr_rgba_channelname(file, "A"),
1034                                                            Slice(Imf::FLOAT,  (char *) (first + 3), xstride, ystride, 1, 1, 1.0f));
1035
1036                                         if (exr_has_zbuffer(file)) {
1037                                                 float *firstz;
1038
1039                                                 addzbuffloatImBuf(ibuf);
1040                                                 firstz = ibuf->zbuf_float - (dw.min.x - dw.min.y * width);
1041                                                 firstz += (height - 1) * width;
1042                                                 frameBuffer.insert("Z", Slice(Imf::FLOAT,  (char *)firstz, sizeof(float), -width * sizeof(float)));
1043                                         }
1044
1045                                         file->setFrameBuffer(frameBuffer);
1046                                         file->readPixels(dw.min.y, dw.max.y);
1047
1048                                         // XXX, ImBuf has no nice way to deal with this.
1049                                         // ideally IM_rect would be used when the caller wants a rect BUT
1050                                         // at the moment all functions use IM_rect.
1051                                         // Disabling this is ok because all functions should check if a rect exists and create one on demand.
1052                                         //
1053                                         // Disabling this because the sequencer frees immediate.
1054                                         //
1055                                         // if (flag & IM_rect)
1056                                         //     IMB_rect_from_float(ibuf);
1057
1058                                         /* file is no longer needed */
1059                                         delete file;
1060                                 }
1061                         }
1062                 }
1063                 return(ibuf);
1064         }
1065         catch (const std::exception &exc)
1066         {
1067                 std::cerr << exc.what() << std::endl;
1068                 if (ibuf) IMB_freeImBuf(ibuf);
1069                 delete file;
1070
1071                 return (0);
1072         }
1073
1074 }
1075
1076 void imb_initopenexr(void)
1077 {
1078         int num_threads = BLI_system_thread_count();
1079
1080         setGlobalThreadCount(num_threads);
1081 }
1082
1083 } // export "C"