Remove MinGW support
[blender-staging.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 <stdexcept>
36 #include <fstream>
37 #include <string>
38 #include <set>
39 #include <errno.h>
40 #include <algorithm>
41 #include <iostream>
42
43 #include <half.h>
44 #include <Iex.h>
45 #include <ImfVersion.h>
46 #include <ImathBox.h>
47 #include <ImfArray.h>
48 #include <ImfIO.h>
49 #include <ImfChannelList.h>
50 #include <ImfPixelType.h>
51 #include <ImfInputFile.h>
52 #include <ImfOutputFile.h>
53 #include <ImfCompression.h>
54 #include <ImfCompressionAttribute.h>
55 #include <ImfStringAttribute.h>
56 #include <ImfStandardAttributes.h>
57
58 /* multiview/multipart */
59 #include <ImfMultiView.h>
60 #include <ImfMultiPartInputFile.h>
61 #include <ImfInputPart.h>
62 #include <ImfOutputPart.h>
63 #include <ImfMultiPartOutputFile.h>
64 #include <ImfTiledOutputPart.h>
65 #include <ImfPartType.h>
66 #include <ImfPartHelper.h>
67
68 #include "DNA_scene_types.h" /* For OpenEXR compression constants */
69
70 #include <openexr_api.h>
71
72 #if defined (WIN32)
73 #include "utfconv.h"
74 #endif
75
76 extern "C"
77 {
78
79 // The following prevents a linking error in debug mode for MSVC using the libs in CVS
80 #if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && _MSC_VER < 1900
81 _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
82 {
83 }
84 #endif
85
86 #include "MEM_guardedalloc.h"
87
88 #include "BLI_blenlib.h"
89 #include "BLI_math_color.h"
90 #include "BLI_threads.h"
91
92 #include "BKE_idprop.h"
93 #include "BKE_image.h"
94
95 #include "IMB_imbuf_types.h"
96 #include "IMB_imbuf.h"
97 #include "IMB_allocimbuf.h"
98 #include "IMB_metadata.h"
99
100 #include "openexr_multi.h"
101 }
102
103 extern "C" {
104 #include "IMB_colormanagement.h"
105 #include "IMB_colormanagement_intern.h"
106 }
107
108 using namespace Imf;
109 using namespace Imath;
110
111 extern "C"
112 {
113 /* prototype */
114 static struct ExrPass *imb_exr_get_pass(ListBase *lb, char *passname);
115 static bool exr_has_multiview(MultiPartInputFile& file);
116 static bool exr_has_multipart_file(MultiPartInputFile& file);
117 static bool exr_has_alpha(MultiPartInputFile& file);
118 static bool exr_has_zbuffer(MultiPartInputFile& file);
119 static void exr_printf(const char *__restrict format, ...);
120 static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
121                                      bool *r_singlelayer, bool *r_multilayer, bool *r_multiview);
122 }
123
124 /* Memory Input Stream */
125
126 class Mem_IStream : public Imf::IStream
127 {
128 public:
129
130         Mem_IStream(unsigned char *exrbuf, size_t exrsize) :
131                 IStream("dummy"), _exrpos(0), _exrsize(exrsize)
132         {
133                 _exrbuf = exrbuf;
134         }
135
136         virtual bool    read(char c[], int n);
137         virtual Int64   tellg();
138         virtual void    seekg(Int64 pos);
139         virtual void    clear();
140         //virtual ~Mem_IStream() {}; // unused
141
142 private:
143
144         Int64 _exrpos;
145         Int64 _exrsize;
146         unsigned char *_exrbuf;
147 };
148
149 bool Mem_IStream::read(char c[], int n)
150 {
151         if (n + _exrpos <= _exrsize) {
152                 memcpy(c, (void *)(&_exrbuf[_exrpos]), n);
153                 _exrpos += n;
154                 return true;
155         }
156         else
157                 return false;
158 }
159
160 Int64 Mem_IStream::tellg()
161 {
162         return _exrpos;
163 }
164
165 void Mem_IStream::seekg(Int64 pos)
166 {
167         _exrpos = pos;
168 }
169
170 void Mem_IStream::clear()
171 {
172 }
173
174 /* File Input Stream */
175
176 class IFileStream : public Imf::IStream
177 {
178 public:
179         IFileStream(const char *filename)
180         : IStream(filename)
181         {
182                 /* utf-8 file path support on windows */
183 #if defined (WIN32)
184                 wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
185                 ifs.open(wfilename, std::ios_base::binary);
186                 free(wfilename);
187 #else
188                 ifs.open(filename, std::ios_base::binary);
189 #endif
190
191                 if (!ifs)
192                         Iex::throwErrnoExc();
193         }
194
195         virtual bool read(char c[], int n)
196         {
197                 if (!ifs)
198                         throw Iex::InputExc("Unexpected end of file.");
199
200                 errno = 0;
201                 ifs.read(c, n);
202                 return check_error();
203         }
204
205         virtual Int64 tellg()
206         {
207                 return std::streamoff(ifs.tellg());
208         }
209
210         virtual void seekg(Int64 pos)
211         {
212                 ifs.seekg(pos);
213                 check_error();
214         }
215
216         virtual void clear()
217         {
218                 ifs.clear();
219         }
220
221 private:
222         bool check_error()
223         {
224                 if (!ifs) {
225                         if (errno)
226                                 Iex::throwErrnoExc();
227
228                         return false;
229                 }
230
231                 return true;
232         }
233
234         std::ifstream ifs;
235 };
236
237 /* File Output Stream */
238
239 class OFileStream : public OStream
240 {
241 public:
242         OFileStream(const char *filename)
243         : OStream(filename)
244         {
245                 /* utf-8 file path support on windows */
246 #if defined (WIN32)
247                 wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
248                 ofs.open(wfilename, std::ios_base::binary);
249                 free(wfilename);
250 #else
251                 ofs.open(filename, std::ios_base::binary);
252 #endif
253
254                 if (!ofs)
255                         Iex::throwErrnoExc();
256         }
257
258         virtual void write(const char c[], int n)
259         {
260                 errno = 0;
261                 ofs.write(c, n);
262                 check_error();
263         }
264
265         virtual Int64 tellp()
266         {
267                 return std::streamoff(ofs.tellp());
268         }
269
270         virtual void seekp(Int64 pos)
271         {
272                 ofs.seekp(pos);
273                 check_error();
274         }
275
276 private:
277         void check_error()
278         {
279                 if (!ofs) {
280                         if (errno)
281                                 Iex::throwErrnoExc();
282
283                         throw Iex::ErrnoExc("File output failed.");
284                 }
285         }
286
287         std::ofstream ofs;
288 };
289
290 struct _RGBAZ {
291         half r;
292         half g;
293         half b;
294         half a;
295         half z;
296 };
297
298 typedef struct _RGBAZ RGBAZ;
299
300 extern "C"
301 {
302
303 /**
304  * Test presence of OpenEXR file.
305  * \param mem pointer to loaded OpenEXR bitstream
306  */
307 int imb_is_a_openexr(const unsigned char *mem)
308 {
309         return Imf::isImfMagic((const char *)mem);
310 }
311
312 static void openexr_header_compression(Header *header, int compression)
313 {
314         switch (compression) {
315                 case R_IMF_EXR_CODEC_NONE:
316                         header->compression() = NO_COMPRESSION;
317                         break;
318                 case R_IMF_EXR_CODEC_PXR24:
319                         header->compression() = PXR24_COMPRESSION;
320                         break;
321                 case R_IMF_EXR_CODEC_ZIP:
322                         header->compression() = ZIP_COMPRESSION;
323                         break;
324                 case R_IMF_EXR_CODEC_PIZ:
325                         header->compression() = PIZ_COMPRESSION;
326                         break;
327                 case R_IMF_EXR_CODEC_RLE:
328                         header->compression() = RLE_COMPRESSION;
329                         break;
330                 case R_IMF_EXR_CODEC_ZIPS:
331                         header->compression() = ZIPS_COMPRESSION;
332                         break;
333                 case R_IMF_EXR_CODEC_B44:
334                         header->compression() = B44_COMPRESSION;
335                         break;
336                 case R_IMF_EXR_CODEC_B44A:
337                         header->compression() = B44A_COMPRESSION;
338                         break;
339 #if OPENEXR_VERSION_MAJOR >= 2 && OPENEXR_VERSION_MINOR >= 2
340                 case R_IMF_EXR_CODEC_DWAA:
341                         header->compression() = DWAA_COMPRESSION;
342                         break;
343                 case R_IMF_EXR_CODEC_DWAB:
344                         header->compression() = DWAB_COMPRESSION;
345                         break;
346 #endif
347                 default:
348                         header->compression() = ZIP_COMPRESSION;
349                         break;
350         }
351 }
352
353 static void openexr_header_metadata(Header *header, struct ImBuf *ibuf)
354 {
355         if (ibuf->metadata) {
356                 IDProperty *prop;
357
358                 for (prop = (IDProperty *)ibuf->metadata->data.group.first; prop; prop = prop->next) {
359                         if (prop->type == IDP_STRING) {
360                                 header->insert(prop->name, StringAttribute(IDP_String(prop)));
361                         }
362                 }
363         }
364
365         if (ibuf->ppm[0] > 0.0)
366                 addXDensity(*header, ibuf->ppm[0] / 39.3700787); /* 1 meter = 39.3700787 inches */
367 }
368
369 static void openexr_header_metadata_callback(void *data, const char *propname, char *prop, int UNUSED(len))
370 {
371         Header *header = (Header *)data;
372         header->insert(propname, StringAttribute(prop));
373 }
374
375
376 static bool imb_save_openexr_half(
377         ImBuf *ibuf, const char *name, const int flags, const int totviews,
378         const char * (*getview)(void *base, int view_id),
379         ImBuf *(*getbuffer)(void *base, const int view_id))
380 {
381         const int channels = ibuf->channels;
382         const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
383         const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
384         const int width = ibuf->x;
385         const int height = ibuf->y;
386         const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
387
388         BLI_assert((!is_multiview) || (getview && getbuffer));
389
390         std::vector <string> views;
391         int view_id;
392
393         try
394         {
395                 Header header(width, height);
396
397                 openexr_header_compression(&header, ibuf->foptions.flag & OPENEXR_COMPRESS);
398                 openexr_header_metadata(&header, ibuf);
399
400                 /* create views when possible */
401                 for (view_id = 0; view_id < totviews; view_id ++)
402                         views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
403
404                 if (is_multiview)
405                         addMultiView(header, views);
406
407                 for (view_id = 0; view_id < totviews; view_id ++) {
408                         header.channels().insert(insertViewName("R", views, view_id), Channel(HALF));
409                         header.channels().insert(insertViewName("G", views, view_id), Channel(HALF));
410                         header.channels().insert(insertViewName("B", views, view_id), Channel(HALF));
411                         if (is_alpha)
412                                 header.channels().insert(insertViewName("A", views, view_id), Channel(HALF));
413                         if (is_zbuf)     // z we do as float always
414                                 header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
415                 }
416
417                 FrameBuffer frameBuffer;
418
419                 /* manually create ofstream, so we can handle utf-8 filepaths on windows */
420                 OFileStream file_stream(name);
421                 OutputFile file(file_stream, header);
422
423                 /* we store first everything in half array */
424                 std::vector<RGBAZ> pixels(height * width * totviews);
425                 int xstride = sizeof(RGBAZ);
426                 int ystride = xstride * width;
427
428                 for (view_id = 0; view_id < totviews; view_id ++) {
429                         ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
430                         const size_t offset = view_id * width * height;
431                         RGBAZ *to = &pixels[offset];
432
433                         /* TODO (dfelinto)
434                          * In some cases we get NULL ibufs, it needs investigation, meanwhile prevent crash
435                          * Multiview Render + Image Editor + OpenEXR + Multi-View
436                          */
437                         if (view_ibuf == NULL) {
438                                 throw std::runtime_error(std::string("Missing data to write to ") + name);
439                         }
440
441                         /* indicate used buffers */
442                         frameBuffer.insert(insertViewName("R", views, view_id), Slice(HALF,  (char *) &pixels[offset].r, xstride, ystride));
443                         frameBuffer.insert(insertViewName("G", views, view_id), Slice(HALF,  (char *) &pixels[offset].g, xstride, ystride));
444                         frameBuffer.insert(insertViewName("B", views, view_id), Slice(HALF,  (char *) &pixels[offset].b, xstride, ystride));
445                         if (is_alpha)
446                                 frameBuffer.insert(insertViewName("A", views, view_id), Slice(HALF, (char *) &pixels[offset].a, xstride, ystride));
447                         if (is_zbuf)
448                                 frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *)(view_ibuf->zbuf_float + (height - 1) * width),
449                                                    sizeof(float), sizeof(float) * -width));
450                         if (view_ibuf->rect_float) {
451                                 float *from;
452
453                                 for (int i = view_ibuf->y - 1; i >= 0; i--) {
454                                         from = view_ibuf->rect_float + channels * i * width;
455
456                                         for (int j = view_ibuf->x; j > 0; j--) {
457                                                 to->r = from[0];
458                                                 to->g = (channels >= 2) ? from[1] : from[0];
459                                                 to->b = (channels >= 3) ? from[2] : from[0];
460                                                 to->a = (channels >= 4) ? from[3] : 1.0f;
461                                                 to++; from += channels;
462                                         }
463                                 }
464                         }
465                         else {
466                                 unsigned char *from;
467
468                                 for (int i = view_ibuf->y - 1; i >= 0; i--) {
469                                         from = (unsigned char *)view_ibuf->rect + 4 * i * width;
470
471                                         for (int j = view_ibuf->x; j > 0; j--) {
472                                                 to->r = srgb_to_linearrgb((float)from[0] / 255.0f);
473                                                 to->g = srgb_to_linearrgb((float)from[1] / 255.0f);
474                                                 to->b = srgb_to_linearrgb((float)from[2] / 255.0f);
475                                                 to->a = channels >= 4 ? (float)from[3] / 255.0f : 1.0f;
476                                                 to++; from += 4;
477                                         }
478                                 }
479                         }
480
481                         if (is_multiview)
482                                 IMB_freeImBuf(view_ibuf);
483                 }
484
485                 exr_printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
486
487                 file.setFrameBuffer(frameBuffer);
488                 file.writePixels(height);
489         }
490         catch (const std::exception& exc)
491         {
492                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
493
494                 return false;
495         }
496
497         return true;
498 }
499
500 static bool imb_save_openexr_float(
501         ImBuf *ibuf, const char *name, const int flags, const int totviews,
502         const char * (*getview)(void *base, const int view_id),
503         ImBuf *(*getbuffer)(void *base, const int view_id))
504 {
505         const int channels = ibuf->channels;
506         const bool is_alpha = (channels >= 4) && (ibuf->planes == 32);
507         const bool is_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; /* summarize */
508         const int width = ibuf->x;
509         const int height = ibuf->y;
510         const bool is_multiview = (flags & IB_multiview) && ibuf->userdata;
511
512         BLI_assert((!is_multiview) || (getview && getbuffer));
513
514         std::vector <string> views;
515         int view_id;
516
517         try
518         {
519                 Header header(width, height);
520
521                 openexr_header_compression(&header, ibuf->foptions.flag & OPENEXR_COMPRESS);
522                 openexr_header_metadata(&header, ibuf);
523
524                 /* create views when possible */
525                 for (view_id = 0; view_id < totviews; view_id ++)
526                         views.push_back(is_multiview ? getview(ibuf->userdata, view_id) : "");
527
528                 if (is_multiview)
529                         addMultiView(header, views);
530
531                 for (view_id = 0; view_id < totviews; view_id ++) {
532                         header.channels().insert(insertViewName("R", views, view_id), Channel(Imf::FLOAT));
533                         header.channels().insert(insertViewName("G", views, view_id), Channel(Imf::FLOAT));
534                         header.channels().insert(insertViewName("B", views, view_id), Channel(Imf::FLOAT));
535                         if (is_alpha)
536                                 header.channels().insert(insertViewName("A", views, view_id), Channel(Imf::FLOAT));
537                         if (is_zbuf)
538                                 header.channels().insert(insertViewName("Z", views, view_id), Channel(Imf::FLOAT));
539                 }
540
541                 FrameBuffer frameBuffer;
542
543                 /* manually create ofstream, so we can handle utf-8 filepaths on windows */
544                 OFileStream file_stream(name);
545                 OutputFile file(file_stream, header);
546
547                 int xstride = sizeof(float) * channels;
548                 int ystride = -xstride * width;
549
550                 for (view_id = 0; view_id < totviews; view_id ++) {
551                         float *rect[4] = {NULL, NULL, NULL, NULL};
552                         ImBuf *view_ibuf = is_multiview ? getbuffer(ibuf->userdata, view_id) : ibuf;
553
554                         /* TODO (dfelinto)
555                          * In some cases we get NULL ibufs, it needs investigation, meanwhile prevent crash
556                          * Multiview Render + Image Editor + OpenEXR + Multi-View
557                          */
558                         if (view_ibuf == NULL) {
559                                 throw std::runtime_error(std::string("Missing data to write to ") + name);
560                         }
561
562                         /* last scanline, stride negative */
563                         rect[0] = view_ibuf->rect_float + channels * (height - 1) * width;
564                         rect[1] = (channels >= 2) ? rect[0] + 1 : rect[0];
565                         rect[2] = (channels >= 3) ? rect[0] + 2 : rect[0];
566                         rect[3] = (channels >= 4) ? rect[0] + 3 : rect[0]; /* red as alpha, is this needed since alpha isn't written? */
567
568                         frameBuffer.insert(insertViewName("R", views, view_id), Slice(Imf::FLOAT,  (char *)rect[0], xstride, ystride));
569                         frameBuffer.insert(insertViewName("G", views, view_id), Slice(Imf::FLOAT,  (char *)rect[1], xstride, ystride));
570                         frameBuffer.insert(insertViewName("B", views, view_id), Slice(Imf::FLOAT,  (char *)rect[2], xstride, ystride));
571                         if (is_alpha)
572                                 frameBuffer.insert(insertViewName("A", views, view_id), Slice(Imf::FLOAT,  (char *)rect[3], xstride, ystride));
573                         if (is_zbuf)
574                                 frameBuffer.insert(insertViewName("Z", views, view_id), Slice(Imf::FLOAT, (char *) (view_ibuf->zbuf_float + (height - 1) * width),
575                                                                   sizeof(float), sizeof(float) * -width));
576
577                         if (is_multiview)
578                                 IMB_freeImBuf(view_ibuf);
579                 }
580                 file.setFrameBuffer(frameBuffer);
581                 file.writePixels(height);
582         }
583         catch (const std::exception& exc)
584         {
585                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
586                 return false;
587         }
588
589         return true;
590 }
591
592 int imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags)
593 {
594         if (flags & IB_mem) {
595                 printf("OpenEXR-save: Create EXR in memory CURRENTLY NOT SUPPORTED !\n");
596                 imb_addencodedbufferImBuf(ibuf);
597                 ibuf->encodedsize = 0;
598                 return(0);
599         }
600
601         if (ibuf->foptions.flag & OPENEXR_HALF)
602                 return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
603         else {
604                 /* when no float rect, we save as half (16 bits is sufficient) */
605                 if (ibuf->rect_float == NULL)
606                         return (int) imb_save_openexr_half(ibuf, name, flags, 1, NULL, NULL);
607                 else
608                         return (int) imb_save_openexr_float(ibuf, name, flags, 1, NULL, NULL);
609         }
610 }
611
612 static bool imb_save_openexr_multiview(
613         ImBuf *ibuf, const char *name, const int flags, const int totviews,
614         const char *(*getview)(void *base, const int view_id),
615         ImBuf *(*getbuffer)(void *base, const int view_id))
616 {
617         if (flags & IB_mem) {
618                 printf("OpenEXR-save: Create multiview EXR in memory CURRENTLY NOT SUPPORTED !\n");
619                 imb_addencodedbufferImBuf(ibuf);
620                 ibuf->encodedsize = 0;
621                 return false;
622         }
623
624         if (ibuf->foptions.flag & OPENEXR_HALF)
625                 return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
626         else {
627                 /* when no float rect, we save as half (16 bits is sufficient) */
628                 if (ibuf->rect_float == NULL)
629                         return imb_save_openexr_half(ibuf, name, flags, totviews, getview, getbuffer);
630                 else
631                         return imb_save_openexr_float(ibuf, name, flags, totviews, getview, getbuffer);
632         }
633 }
634
635 /* Save single-layer multiview OpenEXR
636  * If we have more multiview formats in the future, the function below could be incorporated
637  * in our ImBuf write functions, meanwhile this is an OpenEXR special case only */
638 bool IMB_exr_multiview_save(
639         ImBuf *ibuf, const char *name, const int flags, const int totviews,
640         const char *(*getview)(void *base, const int view_id),
641         ImBuf *(*getbuffer)(void *base, const int view_id))
642 {
643         return imb_save_openexr_multiview(ibuf, name, flags, totviews, getview, getbuffer);
644 }
645
646 /* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */
647
648 /* naming rules:
649  * - parse name from right to left
650  * - last character is channel ID, 1 char like 'A' 'R' 'G' 'B' 'X' 'Y' 'Z' 'W' 'U' 'V'
651  * - separated with a dot; the Pass name (like "Depth", "Color", "Diffuse" or "Combined")
652  * - separated with a dot: the Layer name (like "Lamp1" or "Walls" or "Characters")
653  */
654
655 static ListBase exrhandles = {NULL, NULL};
656
657 typedef struct ExrHandle {
658         struct ExrHandle *next, *prev;
659         char name[FILE_MAX];
660
661         IStream *ifile_stream;
662         MultiPartInputFile *ifile;
663
664         OFileStream *ofile_stream;
665         MultiPartOutputFile *mpofile;
666         OutputFile *ofile;
667
668         int tilex, tiley;
669         int width, height;
670         int mipmap;
671
672         StringVector *multiView; /* it needs to be a pointer due to Windows release builds of EXR2.0 segfault when opening EXR bug */
673         int parts;
674
675         ListBase channels;  /* flattened out, ExrChannel */
676         ListBase layers;    /* hierarchical, pointing in end to ExrChannel */
677
678         int num_half_channels;  /* used during filr save, allows faster temporary buffers allocation */
679 } ExrHandle;
680
681 /* flattened out channel */
682 typedef struct ExrChannel {
683         struct ExrChannel *next, *prev;
684
685         char name[EXR_TOT_MAXNAME + 1];  /* full name with everything */
686         struct MultiViewChannelName *m;  /* struct to store all multipart channel info */
687         int xstride, ystride;            /* step to next pixel, to next scanline */
688         float *rect;                     /* first pointer to write in */
689         char chan_id;                    /* quick lookup of channel char */
690         int view_id;                     /* quick lookup of channel view */
691         bool use_half_float;             /* when saving use half float for file storage */
692 } ExrChannel;
693
694
695 /* hierarchical; layers -> passes -> channels[] */
696 typedef struct ExrPass {
697         struct ExrPass *next, *prev;
698         char name[EXR_PASS_MAXNAME];
699         int totchan;
700         float *rect;
701         struct ExrChannel *chan[EXR_PASS_MAXCHAN];
702         char chan_id[EXR_PASS_MAXCHAN];
703
704         char internal_name[EXR_PASS_MAXNAME]; /* name with no view */
705         char view[EXR_VIEW_MAXNAME];
706         int view_id;
707 } ExrPass;
708
709 typedef struct ExrLayer {
710         struct ExrLayer *next, *prev;
711         char name[EXR_LAY_MAXNAME + 1];
712         ListBase passes;
713 } ExrLayer;
714
715 /* ********************** */
716
717 void *IMB_exr_get_handle(void)
718 {
719         ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
720         data->multiView = new StringVector();
721
722         BLI_addtail(&exrhandles, data);
723         return data;
724 }
725
726 void *IMB_exr_get_handle_name(const char *name)
727 {
728         ExrHandle *data = (ExrHandle *) BLI_rfindstring(&exrhandles, name, offsetof(ExrHandle, name));
729
730         if (data == NULL) {
731                 data = (ExrHandle *)IMB_exr_get_handle();
732                 BLI_strncpy(data->name, name, strlen(name) + 1);
733         }
734         return data;
735 }
736
737 /* multiview functions */
738 } // extern "C"
739
740 extern "C"
741 {
742
743 void IMB_exr_add_view(void *handle, const char *name)
744 {
745         ExrHandle *data = (ExrHandle *)handle;
746         data->multiView->push_back(name);
747 }
748
749 static int imb_exr_get_multiView_id(StringVector& views, const std::string& name)
750 {
751         int count = 0;
752         for (StringVector::const_iterator i = views.begin(); count < views.size(); ++i) {
753                 if (name == *i)
754                         return count;
755                 else
756                         count ++;
757         }
758
759         /* no views or wrong name */
760         return -1;
761 }
762
763 static void imb_exr_get_views(MultiPartInputFile& file, StringVector& views)
764 {
765         if (exr_has_multipart_file(file) == false) {
766                 if (exr_has_multiview(file)) {
767                         StringVector sv = multiView(file.header(0));
768                         for (StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i)
769                                 views.push_back(*i);
770                 }
771         }
772
773         else {
774                 for (int p = 0; p < file.parts(); p++) {
775                         std::string view = "";
776                         if (file.header(p).hasView())
777                                 view = file.header(p).view();
778
779                         if (imb_exr_get_multiView_id(views, view) == -1)
780                                 views.push_back(view);
781                 }
782         }
783 }
784
785 /* Multilayer Blender files have the view name in all the passes (even the default view one) */
786 static void imb_exr_insert_view_name(char *name_full, const char *passname, const char *viewname)
787 {
788         BLI_assert(!ELEM(name_full, passname, viewname));
789
790         if (viewname == NULL || viewname[0] == '\0') {
791                 BLI_strncpy(name_full, passname, sizeof(((ExrChannel *)NULL)->name));
792                 return;
793         }
794
795         const char delims[] = {'.', '\0'};
796         const char *sep;
797         const char *token;
798         size_t len;
799
800         len = BLI_str_rpartition(passname, delims, &sep, &token);
801
802         if (sep) {
803                 BLI_snprintf(name_full, EXR_PASS_MAXNAME, "%.*s.%s.%s", (int)len, passname, viewname, token);
804         }
805         else {
806                 BLI_snprintf(name_full, EXR_PASS_MAXNAME, "%s.%s", passname, viewname);
807         }
808 }
809
810 /* adds flattened ExrChannels */
811 /* xstride, ystride and rect can be done in set_channel too, for tile writing */
812 /* passname does not include view */
813 void IMB_exr_add_channel(void *handle,
814                          const char *layname, const char *passname, const char *viewname,
815                          int xstride, int ystride, float *rect,
816                          bool use_half_float)
817 {
818         ExrHandle *data = (ExrHandle *)handle;
819         ExrChannel *echan;
820
821         echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel");
822         echan->m = new MultiViewChannelName ();
823
824         if (layname && layname[0] != '\0') {
825                 echan->m->name = layname;
826                 echan->m->name.append(".");
827                 echan->m->name.append(passname);
828         }
829         else {
830                 echan->m->name.assign(passname);
831         }
832
833         echan->m->internal_name = echan->m->name;
834
835         echan->m->view.assign(viewname ? viewname : "");
836
837         /* quick look up */
838         echan->view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, echan->m->view));
839
840         /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
841         if (layname && layname[0] != '\0') {
842                 imb_exr_insert_view_name(echan->name, echan->m->name.c_str(), echan->m->view.c_str());
843         }
844         else if (data->multiView->size() > 1) {
845                 std::string raw_name = insertViewName(echan->m->name, *data->multiView, echan->view_id);
846                 BLI_strncpy(echan->name, raw_name.c_str(), sizeof(echan->name));
847         }
848         else {
849                 BLI_strncpy(echan->name, echan->m->name.c_str(), sizeof(echan->name));
850         }
851
852         echan->xstride = xstride;
853         echan->ystride = ystride;
854         echan->rect = rect;
855         echan->use_half_float = use_half_float;
856
857         if (echan->use_half_float) {
858                 data->num_half_channels++;
859         }
860
861         exr_printf("added channel %s\n", echan->name);
862         BLI_addtail(&data->channels, echan);
863 }
864
865 /* used for output files (from RenderResult) (single and multilayer, single and multiview) */
866 int IMB_exr_begin_write(void *handle, const char *filename, int width, int height, int compress, const StampData *stamp)
867 {
868         ExrHandle *data = (ExrHandle *)handle;
869         Header header(width, height);
870         ExrChannel *echan;
871
872         data->width = width;
873         data->height = height;
874
875         bool is_singlelayer, is_multilayer, is_multiview;
876
877         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
878                 header.channels().insert(echan->name,
879                                          Channel(echan->use_half_float ? Imf::HALF : Imf::FLOAT));
880         }
881
882         openexr_header_compression(&header, compress);
883         BKE_stamp_info_callback(&header, const_cast<StampData *>(stamp), openexr_header_metadata_callback, false);
884         /* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */
885
886         imb_exr_type_by_channels(header.channels(), *data->multiView, &is_singlelayer, &is_multilayer, &is_multiview);
887
888         if (is_multilayer)
889                 header.insert("BlenderMultiChannel", StringAttribute("Blender V2.55.1 and newer"));
890
891         if (is_multiview)
892                 addMultiView(header, *data->multiView);
893
894         /* avoid crash/abort when we don't have permission to write here */
895         /* manually create ofstream, so we can handle utf-8 filepaths on windows */
896         try {
897                 data->ofile_stream = new OFileStream(filename);
898                 data->ofile = new OutputFile(*(data->ofile_stream), header);
899         }
900         catch (const std::exception& exc) {
901                 std::cerr << "IMB_exr_begin_write: ERROR: " << exc.what() << std::endl;
902
903                 delete data->ofile;
904                 delete data->ofile_stream;
905
906                 data->ofile = NULL;
907                 data->ofile_stream = NULL;
908         }
909
910         return (data->ofile != NULL);
911 }
912
913 /* only used for writing temp. render results (not image files)
914  * (FSA and Save Buffers) */
915 void IMB_exrtile_begin_write(void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
916 {
917         ExrHandle *data = (ExrHandle *)handle;
918         Header header(width, height);
919         std::vector<Header> headers;
920         ExrChannel *echan;
921
922         data->tilex = tilex;
923         data->tiley = tiley;
924         data->width = width;
925         data->height = height;
926         data->mipmap = mipmap;
927
928         header.setTileDescription(TileDescription(tilex, tiley, (mipmap) ? MIPMAP_LEVELS : ONE_LEVEL));
929         header.compression() = RLE_COMPRESSION;
930         header.setType(TILEDIMAGE);
931
932         header.insert("BlenderMultiChannel", StringAttribute("Blender V2.43"));
933
934         int numparts = data->multiView->size();
935
936         /* copy header from all parts of input to our header array
937          * those temporary files have one part per view */
938         for (int i = 0; i < numparts; i++) {
939                 headers.push_back (header);
940                 headers[headers.size() - 1].setView((*(data->multiView))[i]);
941                 headers[headers.size() - 1].setName((*(data->multiView))[i]);
942         }
943
944         exr_printf("\nIMB_exrtile_begin_write\n");
945         exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
946         exr_printf("---------------------------------------------------------------\n");
947
948         /* assign channels  */
949         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
950                 /* Tiles are expected to be saved with full float currently. */
951                 BLI_assert(echan->use_half_float == 0);
952
953                 echan->m->internal_name = echan->m->name;
954                 echan->m->part_number = echan->view_id;
955
956                 headers[echan->view_id].channels().insert(echan->m->internal_name, Channel(Imf::FLOAT));
957                 exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
958         }
959
960         /* avoid crash/abort when we don't have permission to write here */
961         /* manually create ofstream, so we can handle utf-8 filepaths on windows */
962         try {
963                 data->ofile_stream = new OFileStream(filename);
964                 data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
965         }
966         catch (const std::exception &) {
967                 delete data->mpofile;
968                 delete data->ofile_stream;
969
970                 data->mpofile = NULL;
971                 data->ofile_stream = NULL;
972         }
973 }
974
975 /* read from file */
976 int IMB_exr_begin_read(void *handle, const char *filename, int *width, int *height)
977 {
978         ExrHandle *data = (ExrHandle *)handle;
979         ExrChannel *echan;
980
981         if (BLI_exists(filename) && BLI_file_size(filename) > 32) {   /* 32 is arbitrary, but zero length files crashes exr */
982                 /* avoid crash/abort when we don't have permission to write here */
983                 try {
984                         data->ifile_stream = new IFileStream(filename);
985                         data->ifile = new MultiPartInputFile(*(data->ifile_stream));
986                 }
987                 catch (const std::exception &) {
988                         delete data->ifile;
989                         delete data->ifile_stream;
990
991                         data->ifile = NULL;
992                         data->ifile_stream = NULL;
993                 }
994
995                 if (data->ifile) {
996                         Box2i dw = data->ifile->header(0).dataWindow();
997                         data->width = *width  = dw.max.x - dw.min.x + 1;
998                         data->height = *height = dw.max.y - dw.min.y + 1;
999
1000                         imb_exr_get_views(*data->ifile, *data->multiView);
1001
1002                         std::vector<MultiViewChannelName> channels;
1003                         GetChannelsInMultiPartFile(*data->ifile, channels);
1004
1005                         for (size_t i = 0; i < channels.size(); i++) {
1006                                 IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL, false);
1007                 
1008                                 echan = (ExrChannel *)data->channels.last;
1009                                 echan->m->name = channels[i].name;
1010                                 echan->m->view = channels[i].view;
1011                                 echan->m->part_number = channels[i].part_number;
1012                                 echan->m->internal_name = channels[i].internal_name;
1013                         }
1014
1015                         return 1;
1016                 }
1017         }
1018         return 0;
1019 }
1020
1021 /* still clumsy name handling, layers/channels can be ordered as list in list later */
1022 /* passname here is the raw channel name without the layer */
1023 void IMB_exr_set_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
1024 {
1025         ExrHandle *data = (ExrHandle *)handle;
1026         ExrChannel *echan;
1027         char name[EXR_TOT_MAXNAME + 1];
1028
1029         if (layname && layname[0] != '\0') {
1030                 char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
1031                 BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
1032                 BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
1033
1034                 BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
1035         }
1036         else {
1037                 BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
1038         }
1039
1040         echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
1041
1042         if (echan) {
1043                 echan->xstride = xstride;
1044                 echan->ystride = ystride;
1045                 echan->rect = rect;
1046         }
1047         else {
1048                 printf("IMB_exr_set_channel error %s\n", name);
1049         }
1050 }
1051
1052 float  *IMB_exr_channel_rect(void *handle, const char *layname, const char *passname, const char *viewname)
1053 {
1054         ExrHandle *data = (ExrHandle *)handle;
1055         ExrChannel *echan;
1056         char name[EXR_TOT_MAXNAME + 1];
1057
1058         if (layname) {
1059                 char lay[EXR_LAY_MAXNAME + 1], pass[EXR_PASS_MAXNAME + 1];
1060                 BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
1061                 BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
1062
1063                 BLI_snprintf(name, sizeof(name), "%s.%s", lay, pass);
1064         }
1065         else
1066                 BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
1067
1068         /* name has to be unique, thus it's a combination of layer, pass, view, and channel */
1069         if (layname && layname[0] != '\0') {
1070                 char temp_buf[EXR_PASS_MAXNAME];
1071                 imb_exr_insert_view_name(temp_buf, name, viewname);
1072                 BLI_strncpy(name, temp_buf, sizeof(name));
1073         }
1074         else if (data->multiView->size() > 1) {
1075                 const int view_id = std::max(0, imb_exr_get_multiView_id(*data->multiView, viewname));
1076                 std::string raw_name = insertViewName(name, *data->multiView, view_id);
1077                 BLI_strncpy(name, raw_name.c_str(), sizeof(name));
1078         }
1079
1080         echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name));
1081
1082         if (echan)
1083                 return echan->rect;
1084
1085         return NULL;
1086 }
1087
1088 void IMB_exr_clear_channels(void *handle)
1089 {
1090         ExrHandle *data = (ExrHandle *)handle;
1091         ExrChannel *chan;
1092
1093         for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next)
1094                 delete chan->m;
1095
1096         BLI_freelistN(&data->channels);
1097 }
1098
1099 void IMB_exr_write_channels(void *handle)
1100 {
1101         ExrHandle *data = (ExrHandle *)handle;
1102         FrameBuffer frameBuffer;
1103         ExrChannel *echan;
1104
1105         if (data->channels.first) {
1106                 const size_t num_pixels = ((size_t)data->width) * data->height;
1107                 half *rect_half = NULL, *current_rect_half;
1108
1109                 /* We allocate teporary storage for half pixels for all the channels at once. */
1110                 if (data->num_half_channels != 0) {
1111                         rect_half = (half *)MEM_mallocN(sizeof(half) * data->num_half_channels * num_pixels, __func__);
1112                         current_rect_half = rect_half;
1113                 }
1114
1115                 for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1116                         /* Writting starts from last scanline, stride negative. */
1117                         if (echan->use_half_float) {
1118                                 float *rect = echan->rect;
1119                                 half *cur = current_rect_half;
1120                                 for (size_t i = 0; i < num_pixels; ++i, ++cur) {
1121                                         *cur = rect[i * echan->xstride];
1122                                 }
1123                                 half *rect_to_write = current_rect_half + (data->height - 1) * data->width;
1124                                 frameBuffer.insert(echan->name, Slice(Imf::HALF,  (char *)rect_to_write,
1125                                                                       sizeof(half), -data->width * sizeof(half)));
1126                                 current_rect_half += num_pixels;
1127                         }
1128                         else {
1129                                 float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
1130                                 frameBuffer.insert(echan->name, Slice(Imf::FLOAT,  (char *)rect,
1131                                                                       echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
1132                         }
1133                 }
1134
1135                 data->ofile->setFrameBuffer(frameBuffer);
1136                 try {
1137                         data->ofile->writePixels(data->height);
1138                 }
1139                 catch (const std::exception& exc) {
1140                         std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
1141                 }
1142                 /* Free temporary buffers. */
1143                 if (rect_half != NULL) {
1144                         MEM_freeN(rect_half);
1145                 }
1146         }
1147         else {
1148                 printf("Error: attempt to save MultiLayer without layers.\n");
1149         }
1150 }
1151
1152 /* temporary function, used for FSA and Save Buffers */
1153 /* called once per tile * view */
1154 void IMB_exrtile_write_channels(void *handle, int partx, int party, int level, const char *viewname)
1155 {
1156         ExrHandle *data = (ExrHandle *)handle;
1157         FrameBuffer frameBuffer;
1158         ExrChannel *echan;
1159         std::string view(viewname);
1160         const int view_id = imb_exr_get_multiView_id(*data->multiView, view);
1161
1162         exr_printf("\nIMB_exrtile_write_channels(view: %s)\n", viewname);
1163         exr_printf("%s %-6s %-22s \"%s\"\n", "p", "view", "name", "internal_name");
1164         exr_printf("---------------------------------------------------------------------\n");
1165
1166         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1167
1168                 /* eventually we can make the parts' channels to include
1169                    only the current view TODO */
1170                 if (strcmp(viewname, echan->m->view.c_str()) != 0)
1171                         continue;
1172
1173                 exr_printf("%d %-6s %-22s \"%s\"\n",
1174                            echan->m->part_number,
1175                            echan->m->view.c_str(),
1176                            echan->m->name.c_str(),
1177                            echan->m->internal_name.c_str()
1178                            );
1179
1180                 float *rect = echan->rect - echan->xstride * partx - echan->ystride * party;
1181                 frameBuffer.insert(echan->m->internal_name,
1182                                    Slice(Imf::FLOAT,
1183                                          (char *)rect,
1184                                          echan->xstride * sizeof(float),
1185                                          echan->ystride * sizeof(float)
1186                                         )
1187                                   );
1188         }
1189
1190         TiledOutputPart out (*data->mpofile, view_id);
1191         out.setFrameBuffer(frameBuffer);
1192
1193         try {
1194                 // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
1195                 out.writeTile(partx / data->tilex, party / data->tiley, level);
1196         }
1197         catch (const std::exception& exc) {
1198                 std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
1199         }
1200 }
1201
1202 /* called only when handle has all views */
1203 void IMB_exrmultiview_write_channels(void *handle, const char *viewname)
1204 {
1205         ExrHandle *data = (ExrHandle *)handle;
1206         const int view_id = viewname ? imb_exr_get_multiView_id(*data->multiView, viewname) : -1;
1207         int numparts = (view_id == -1 ? data->parts : view_id + 1);
1208         std::vector <FrameBuffer> frameBuffers(numparts);
1209         std::vector <OutputPart> outputParts;
1210         ExrChannel *echan;
1211         int i, part;
1212
1213         if (data->channels.first == NULL)
1214                 return;
1215
1216         exr_printf("\nIMB_exrmultiview_write_channels()\n");
1217
1218         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1219                 if (view_id != -1 && echan->view_id != view_id)
1220                         continue;
1221
1222                 part = (view_id == -1 ? echan->m->part_number : echan->view_id);
1223
1224                 /* last scanline, stride negative */
1225                 float *rect = echan->rect + echan->xstride * (data->height - 1) * data->width;
1226                 frameBuffers[part].insert(echan->m->internal_name,
1227                                           Slice(Imf::FLOAT,
1228                                                 (char *)rect,
1229                                                 echan->xstride * sizeof(float),
1230                                                 -echan->ystride * sizeof(float))
1231                 );
1232         }
1233
1234         for (i = 0; i < numparts; i++) {
1235                 OutputPart out(*data->mpofile, i);
1236                 out.setFrameBuffer(frameBuffers[i]);
1237                 outputParts.push_back(out);
1238         }
1239
1240         try {
1241                 for (i = 0; i < numparts; i++) {
1242                         if (view_id != -1 && i != view_id)
1243                                 continue;
1244
1245                         outputParts[i].writePixels(data->height);
1246                 }
1247         }
1248         catch (const std::exception& exc) {
1249                 std::cerr << "OpenEXR-write Multi Part: ERROR: " << exc.what() << std::endl;
1250         }
1251 }
1252
1253 void IMB_exr_read_channels(void *handle)
1254 {
1255         ExrHandle *data = (ExrHandle *)handle;
1256         ExrChannel *echan;
1257         int numparts = data->ifile->parts();
1258         std::vector<FrameBuffer> frameBuffers(numparts);
1259         std::vector<InputPart> inputParts;
1260
1261         /* check if exr was saved with previous versions of blender which flipped images */
1262         const StringAttribute *ta = data->ifile->header(0).findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
1263         short flip = (ta && STREQLEN(ta->value().c_str(), "Blender V2.43", 13)); /* 'previous multilayer attribute, flipped */
1264
1265         exr_printf("\nIMB_exr_read_channels\n%s %-6s %-22s \"%s\"\n---------------------------------------------------------------------\n", "p", "view", "name", "internal_name");
1266
1267         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1268                 exr_printf("%d %-6s %-22s \"%s\"\n", echan->m->part_number, echan->m->view.c_str(), echan->m->name.c_str(), echan->m->internal_name.c_str());
1269
1270                 if (echan->rect) {
1271                         if (flip)
1272                                 frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT,  (char *)echan->rect,
1273                                                                       echan->xstride * sizeof(float), echan->ystride * sizeof(float)));
1274                         else
1275                                 frameBuffers[echan->m->part_number].insert(echan->m->internal_name, Slice(Imf::FLOAT,  (char *)(echan->rect + echan->xstride * (data->height - 1) * data->width),
1276                                                                       echan->xstride * sizeof(float), -echan->ystride * sizeof(float)));
1277                 }
1278                 else
1279                         printf("warning, channel with no rect set %s\n", echan->m->internal_name.c_str());
1280         }
1281
1282         for (int i = 0; i < numparts; i++) {
1283                 InputPart in (*data->ifile, i);
1284                 in.setFrameBuffer(frameBuffers[i]);
1285                 inputParts.push_back(in);
1286         }
1287
1288         try {
1289                 for (int i = 0; i < numparts; i++) {
1290                         Header header = inputParts[i].header();
1291                         exr_printf("readPixels:readPixels[%d]: min.y: %d, max.y: %d\n", i, header.dataWindow().min.y, header.dataWindow().max.y);
1292                         inputParts[i].readPixels(header.dataWindow().min.y, header.dataWindow().max.y);
1293                         inputParts[i].readPixels(0, data->height - 1);
1294                 }
1295         }
1296         catch (const std::exception& exc) {
1297                 std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
1298         }
1299 }
1300
1301 void IMB_exr_multilayer_convert(void *handle, void *base,
1302                                 void * (*addview)(void *base, const char *str),
1303                                 void * (*addlayer)(void *base, const char *str),
1304                                 void (*addpass)(void *base, void *lay, const char *str,
1305                                                 float *rect, int totchan, const char *chan_id,
1306                                                 const char *view))
1307 {
1308         ExrHandle *data = (ExrHandle *)handle;
1309         ExrLayer *lay;
1310         ExrPass *pass;
1311
1312         /* RenderResult needs at least one RenderView */
1313         if (data->multiView->size() == 0) {
1314                 addview(base, "");
1315         }
1316         else {
1317                 /* add views to RenderResult */
1318                 for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
1319                         addview(base, (*i).c_str());
1320                 }
1321         }
1322
1323         if (BLI_listbase_is_empty(&data->layers)) {
1324                 printf("cannot convert multilayer, no layers in handle\n");
1325                 return;
1326         }
1327
1328         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
1329                 void *laybase = addlayer(base, lay->name);
1330                 if (laybase) {
1331                         for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
1332                                 addpass(base, laybase, pass->internal_name, pass->rect, pass->totchan, pass->chan_id, pass->view);
1333                                 pass->rect = NULL;
1334                         }
1335                 }
1336         }
1337 }
1338
1339 void IMB_exr_multiview_convert(void *handle, void *base,
1340                                void (*addview)(void *base, const char *str),
1341                                void (*addbuffer)(void *base, const char *str, ImBuf *ibuf, const int frame),
1342                                const int frame)
1343 {
1344         ExrHandle *data = (ExrHandle *)handle;
1345         MultiPartInputFile *file = data->ifile;
1346         ExrLayer *lay;
1347         ExrPass *pass;
1348         ImBuf *ibuf = NULL;
1349         const bool is_alpha = exr_has_alpha(*file);
1350         Box2i dw = file->header(0).dataWindow();
1351         const size_t width  = dw.max.x - dw.min.x + 1;
1352         const size_t height = dw.max.y - dw.min.y + 1;
1353         const bool is_depth = exr_has_zbuffer(*file);
1354         
1355         /* add views to RenderResult */
1356         for (StringVector::const_iterator i = data->multiView->begin(); i != data->multiView->end(); ++i) {
1357                 addview(base, (*i).c_str());
1358         }
1359         
1360         if (BLI_listbase_is_empty(&data->layers)) {
1361                 printf("cannot convert multiviews, no views in handle\n");
1362                 return;
1363         }
1364         
1365         /* there is one float/pass per layer (layer here is a view) */
1366         BLI_assert(BLI_listbase_count_ex(&data->layers, 2) == 1);
1367         lay = (ExrLayer *)data->layers.first;
1368         for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
1369                 if (STREQ(pass->chan_id, "RGB") || STREQ(pass->chan_id, "RGBA")) {
1370                         ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, IB_rectfloat);
1371
1372                         if (!ibuf) {
1373                                 printf("error creating multiview buffer\n");
1374                                 return;
1375                         }
1376
1377                         IMB_buffer_float_from_float(
1378                                 ibuf->rect_float, pass->rect, pass->totchan,
1379                                 IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
1380                                 ibuf->x, ibuf->y, ibuf->x, ibuf->x);
1381
1382                         if (hasXDensity(file->header(0))) {
1383                                 ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
1384                                 ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
1385                         }
1386
1387                         if (is_depth) {
1388                                 ExrPass *zpass;
1389                                 for (zpass = (ExrPass *)lay->passes.first; zpass; zpass = zpass->next) {
1390                                         if (STREQ(zpass->chan_id, "Z") && STREQ(zpass->view, pass->view)) {
1391                                                 addzbuffloatImBuf(ibuf);
1392                                                 memcpy(ibuf->zbuf_float, zpass->rect, sizeof(float) * ibuf->x * ibuf->y);
1393                                         }
1394                                 }
1395                         }
1396
1397                         addbuffer(base, pass->view, ibuf, frame);
1398                 }
1399         }
1400 }
1401
1402 void IMB_exr_close(void *handle)
1403 {
1404         ExrHandle *data = (ExrHandle *)handle;
1405         ExrLayer *lay;
1406         ExrPass *pass;
1407         ExrChannel *chan;
1408
1409         delete data->ifile;
1410         delete data->ifile_stream;
1411         delete data->ofile;
1412         delete data->mpofile;
1413         delete data->ofile_stream;
1414         delete data->multiView;
1415
1416         data->ifile = NULL;
1417         data->ifile_stream = NULL;
1418         data->ofile = NULL;
1419         data->mpofile = NULL;
1420         data->ofile_stream = NULL;
1421
1422         for (chan = (ExrChannel *)data->channels.first; chan; chan = chan->next) {
1423                 delete chan->m;
1424         }
1425         BLI_freelistN(&data->channels);
1426
1427         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
1428                 for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next)
1429                         if (pass->rect)
1430                                 MEM_freeN(pass->rect);
1431                 BLI_freelistN(&lay->passes);
1432         }
1433         BLI_freelistN(&data->layers);
1434
1435         BLI_remlink(&exrhandles, data);
1436         MEM_freeN(data);
1437 }
1438
1439 /* ********* */
1440
1441 /* get a substring from the end of the name, separated by '.' */
1442 static int imb_exr_split_token(const char *str, const char *end, const char **token)
1443 {
1444         const char delims[] = {'.', '\0'};
1445         const char *sep;
1446
1447         BLI_str_partition_ex(str, end, delims, &sep, token, true);
1448
1449         if (!sep) {
1450                 *token = str;
1451         }
1452
1453         return (int)(end - *token);
1454 }
1455
1456 static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
1457 {
1458         const char *name = echan->m->name.c_str();
1459         const char *end = name + strlen(name);
1460         const char *token;
1461         char tokenbuf[EXR_TOT_MAXNAME];
1462         int len;
1463         
1464         /* some multilayers have the combined buffer with names A B G R saved */
1465         if (name[1] == 0) {
1466                 echan->chan_id = name[0];
1467                 layname[0] = '\0';
1468
1469                 if (ELEM(name[0], 'R', 'G', 'B', 'A'))
1470                         strcpy(passname, "Combined");
1471                 else if (name[0] == 'Z')
1472                         strcpy(passname, "Depth");
1473                 else
1474                         strcpy(passname, name);
1475
1476                 return 1;
1477         }
1478
1479         /* last token is single character channel identifier */
1480         len = imb_exr_split_token(name, end, &token);
1481         if (len == 0) {
1482                 printf("multilayer read: bad channel name: %s\n", name);
1483                 return 0;
1484         }
1485         else if (len == 1) {
1486                 echan->chan_id = token[0];
1487         }
1488         else if (len > 1) {
1489                 bool ok = false;
1490
1491                 if (len == 2) {
1492                         /* some multilayers are using two-letter channels name,
1493                          * like, MX or NZ, which is basically has structure of
1494                          *   <pass_prefix><component>
1495                          *
1496                          * This is a bit silly, but see file from [#35658].
1497                          *
1498                          * Here we do some magic to distinguish such cases.
1499                          */
1500                         if (ELEM(token[1], 'X', 'Y', 'Z') ||
1501                             ELEM(token[1], 'R', 'G', 'B') ||
1502                             ELEM(token[1], 'U', 'V', 'A'))
1503                         {
1504                                 echan->chan_id = token[1];
1505                                 ok = true;
1506                         }
1507                 }
1508
1509                 if (ok == false) {
1510                         BLI_strncpy(tokenbuf, token, std::min(len + 1, EXR_TOT_MAXNAME));
1511                         printf("multilayer read: channel token too long: %s\n", tokenbuf);
1512                         return 0;
1513                 }
1514         }
1515         end -= len + 1; /* +1 to skip '.' separator */
1516
1517         /* second token is pass name */
1518         len = imb_exr_split_token(name, end, &token);
1519         if (len == 0) {
1520                 printf("multilayer read: bad channel name: %s\n", name);
1521                 return 0;
1522         }
1523         BLI_strncpy(passname, token, len + 1);
1524         end -= len + 1; /* +1 to skip '.' separator */
1525
1526         /* all preceding tokens combined as layer name */
1527         if (end > name)
1528                 BLI_strncpy(layname, name, (int)(end - name) + 1);
1529         else
1530                 layname[0] = '\0';
1531
1532         return 1;
1533 }
1534
1535 static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
1536 {
1537         ExrLayer *lay = (ExrLayer *)BLI_findstring(lb, layname, offsetof(ExrLayer, name));
1538
1539         if (lay == NULL) {
1540                 lay = (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
1541                 BLI_addtail(lb, lay);
1542                 BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
1543         }
1544
1545         return lay;
1546 }
1547
1548 static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
1549 {
1550         ExrPass *pass = (ExrPass *)BLI_findstring(lb, passname, offsetof(ExrPass, name));
1551
1552         if (pass == NULL) {
1553                 pass = (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
1554
1555                 if (STREQ(passname, "Combined"))
1556                         BLI_addhead(lb, pass);
1557                 else
1558                         BLI_addtail(lb, pass);
1559         }
1560
1561         BLI_strncpy(pass->name, passname, EXR_LAY_MAXNAME);
1562
1563         return pass;
1564 }
1565
1566 /* creates channels, makes a hierarchy and assigns memory to channels */
1567 static ExrHandle *imb_exr_begin_read_mem(IStream &file_stream, MultiPartInputFile &file, int width, int height)
1568 {
1569         ExrLayer *lay;
1570         ExrPass *pass;
1571         ExrChannel *echan;
1572         ExrHandle *data = (ExrHandle *)IMB_exr_get_handle();
1573         int a;
1574         char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
1575
1576         data->ifile_stream = &file_stream;
1577         data->ifile = &file;
1578
1579         data->width = width;
1580         data->height = height;
1581
1582         std::vector<MultiViewChannelName> channels;
1583         GetChannelsInMultiPartFile(*data->ifile, channels);
1584
1585         imb_exr_get_views(*data->ifile, *data->multiView);
1586
1587         for (size_t i = 0; i < channels.size(); i++) {
1588                 IMB_exr_add_channel(data, NULL, channels[i].name.c_str(), channels[i].view.c_str(), 0, 0, NULL, false);
1589
1590                 echan = (ExrChannel *)data->channels.last;
1591                 echan->m->name = channels[i].name;
1592                 echan->m->view = channels[i].view;
1593                 echan->m->part_number = channels[i].part_number;
1594                 echan->m->internal_name = channels[i].internal_name;
1595         }
1596
1597         /* now try to sort out how to assign memory to the channels */
1598         /* first build hierarchical layer list */
1599         for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
1600                 if (imb_exr_split_channel_name(echan, layname, passname)) {
1601
1602                         const char *view = echan->m->view.c_str();
1603                         char internal_name[EXR_PASS_MAXNAME];
1604
1605                         BLI_strncpy(internal_name, passname, EXR_PASS_MAXNAME);
1606
1607                         if (view[0] != '\0') {
1608                                 char tmp_pass[EXR_PASS_MAXNAME];
1609                                 BLI_snprintf(tmp_pass, sizeof(tmp_pass), "%s.%s", passname, view);
1610                                 BLI_strncpy(passname, tmp_pass, sizeof(passname));
1611                         }
1612
1613                         ExrLayer *lay = imb_exr_get_layer(&data->layers, layname);
1614                         ExrPass *pass = imb_exr_get_pass(&lay->passes, passname);
1615
1616                         pass->chan[pass->totchan] = echan;
1617                         pass->totchan++;
1618                         pass->view_id = echan->view_id;
1619                         BLI_strncpy(pass->view, view, sizeof(pass->view));
1620                         BLI_strncpy(pass->internal_name, internal_name, EXR_PASS_MAXNAME);
1621
1622                         if (pass->totchan >= EXR_PASS_MAXCHAN)
1623                                 break;
1624                 }
1625         }
1626         if (echan) {
1627                 printf("error, too many channels in one pass: %s\n", echan->m->name.c_str());
1628                 IMB_exr_close(data);
1629                 return NULL;
1630         }
1631
1632         /* with some heuristics, try to merge the channels in buffers */
1633         for (lay = (ExrLayer *)data->layers.first; lay; lay = lay->next) {
1634                 for (pass = (ExrPass *)lay->passes.first; pass; pass = pass->next) {
1635                         if (pass->totchan) {
1636                                 pass->rect = (float *)MEM_mapallocN(width * height * pass->totchan * sizeof(float), "pass rect");
1637                                 if (pass->totchan == 1) {
1638                                         echan = pass->chan[0];
1639                                         echan->rect = pass->rect;
1640                                         echan->xstride = 1;
1641                                         echan->ystride = width;
1642                                         pass->chan_id[0] = echan->chan_id;
1643                                 }
1644                                 else {
1645                                         char lookup[256];
1646
1647                                         memset(lookup, 0, sizeof(lookup));
1648
1649                                         /* we can have RGB(A), XYZ(W), UVA */
1650                                         if (pass->totchan == 3 || pass->totchan == 4) {
1651                                                 if (pass->chan[0]->chan_id == 'B' || pass->chan[1]->chan_id == 'B' ||  pass->chan[2]->chan_id == 'B') {
1652                                                         lookup[(unsigned int)'R'] = 0;
1653                                                         lookup[(unsigned int)'G'] = 1;
1654                                                         lookup[(unsigned int)'B'] = 2;
1655                                                         lookup[(unsigned int)'A'] = 3;
1656                                                 }
1657                                                 else if (pass->chan[0]->chan_id == 'Y' || pass->chan[1]->chan_id == 'Y' ||  pass->chan[2]->chan_id == 'Y') {
1658                                                         lookup[(unsigned int)'X'] = 0;
1659                                                         lookup[(unsigned int)'Y'] = 1;
1660                                                         lookup[(unsigned int)'Z'] = 2;
1661                                                         lookup[(unsigned int)'W'] = 3;
1662                                                 }
1663                                                 else {
1664                                                         lookup[(unsigned int)'U'] = 0;
1665                                                         lookup[(unsigned int)'V'] = 1;
1666                                                         lookup[(unsigned int)'A'] = 2;
1667                                                 }
1668                                                 for (a = 0; a < pass->totchan; a++) {
1669                                                         echan = pass->chan[a];
1670                                                         echan->rect = pass->rect + lookup[(unsigned int)echan->chan_id];
1671                                                         echan->xstride = pass->totchan;
1672                                                         echan->ystride = width * pass->totchan;
1673                                                         pass->chan_id[(unsigned int)lookup[(unsigned int)echan->chan_id]] = echan->chan_id;
1674                                                 }
1675                                         }
1676                                         else { /* unknown */
1677                                                 for (a = 0; a < pass->totchan; a++) {
1678                                                         echan = pass->chan[a];
1679                                                         echan->rect = pass->rect + a;
1680                                                         echan->xstride = pass->totchan;
1681                                                         echan->ystride = width * pass->totchan;
1682                                                         pass->chan_id[a] = echan->chan_id;
1683                                                 }
1684                                         }
1685                                 }
1686                         }
1687                 }
1688         }
1689
1690         return data;
1691 }
1692
1693
1694 /* ********************************************************* */
1695
1696 /* debug only */
1697 static void exr_printf(const char *fmt, ...)
1698 {
1699 #if 0
1700         char output[1024];
1701         va_list args;
1702         va_start(args, fmt);
1703         std::vsprintf(output, fmt, args);
1704         va_end(args);
1705         printf("%s", output);
1706 #else
1707         (void)fmt;
1708 #endif
1709 }
1710
1711 static void exr_print_filecontents(MultiPartInputFile& file)
1712 {
1713         int numparts = file.parts();
1714         if (numparts == 1 && hasMultiView(file.header(0))) {
1715                 const StringVector views = multiView(file.header(0));
1716                 printf("OpenEXR-load: MultiView file\n");
1717                 printf("OpenEXR-load: Default view: %s\n", defaultViewName(views).c_str());
1718                 for (StringVector::const_iterator i = views.begin(); i != views.end(); ++i) {
1719                         printf("OpenEXR-load: Found view %s\n", (*i).c_str());
1720                 }
1721         }
1722         else if (numparts > 1) {
1723                 printf("OpenEXR-load: MultiPart file\n");
1724                 for (int i = 0; i < numparts; i++) {
1725                         if (file.header(i).hasView())
1726                                 printf("OpenEXR-load: Part %d: view = \"%s\"\n", i, file.header(i).view().c_str());
1727                 }
1728         }
1729
1730         for (int j = 0; j < numparts; j++) {
1731                 const ChannelList& channels = file.header(j).channels();
1732                 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1733                         const Channel& channel = i.channel();
1734                         printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
1735                 }
1736         }
1737 }
1738
1739 /* for non-multilayer, map  R G B A channel names to something that's in this file */
1740 static const char *exr_rgba_channelname(MultiPartInputFile& file, const char *chan)
1741 {
1742         const ChannelList& channels = file.header(0).channels();
1743
1744         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
1745                 /* const Channel &channel = i.channel(); */ /* Not used yet */
1746                 const char *str = i.name();
1747                 int len = strlen(str);
1748                 if (len) {
1749                         if (BLI_strcasecmp(chan, str + len - 1) == 0) {
1750                                 return str;
1751                         }
1752                 }
1753         }
1754         return chan;
1755 }
1756
1757 static bool exr_has_rgb(MultiPartInputFile& file)
1758 {
1759         return file.header(0).channels().findChannel("R") != NULL &&
1760                file.header(0).channels().findChannel("G") != NULL &&
1761                file.header(0).channels().findChannel("B") != NULL;
1762 }
1763
1764 static bool exr_has_luma(MultiPartInputFile& file)
1765 {
1766         /* Y channel is the luma and should always present fir luma space images,
1767          * optionally it could be also channels for chromas called BY and RY.
1768          */
1769         return file.header(0).channels().findChannel("Y") != NULL;
1770 }
1771
1772 static bool exr_has_chroma(MultiPartInputFile& file)
1773 {
1774         return file.header(0).channels().findChannel("BY") != NULL &&
1775                file.header(0).channels().findChannel("RY") != NULL;
1776 }
1777
1778 static bool exr_has_zbuffer(MultiPartInputFile& file)
1779 {
1780         return !(file.header(0).channels().findChannel("Z") == NULL);
1781 }
1782
1783 static bool exr_has_alpha(MultiPartInputFile& file)
1784 {
1785         return !(file.header(0).channels().findChannel("A") == NULL);
1786 }
1787
1788 static bool imb_exr_is_multilayer_file(MultiPartInputFile& file)
1789 {
1790         const StringAttribute *comments = file.header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
1791         const ChannelList& channels = file.header(0).channels();
1792         std::set <std::string> layerNames;
1793
1794         /* will not include empty layer names */
1795         channels.layers(layerNames);
1796
1797         if (comments || layerNames.size() > 1)
1798                 return true;
1799
1800         if (layerNames.size()) {
1801                 /* if layerNames is not empty, it means at least one layer is non-empty,
1802                  * but it also could be layers without names in the file and such case
1803                  * shall be considered a multilayer exr
1804                  *
1805                  * that's what we do here: test whether there're empty layer names together
1806                  * with non-empty ones in the file
1807                  */
1808                 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++) {
1809                         std::string layerName = i.name();
1810                         size_t pos = layerName.rfind ('.');
1811
1812                         if (pos == std::string::npos)
1813                                 return true;
1814                 }
1815         }
1816
1817         return false;
1818 }
1819
1820 static void imb_exr_type_by_channels(ChannelList& channels, StringVector& views,
1821                                      bool *r_singlelayer, bool *r_multilayer, bool *r_multiview)
1822 {
1823         std::set <std::string> layerNames;
1824
1825         *r_singlelayer = true;
1826         *r_multilayer = *r_multiview = false;
1827
1828         /* will not include empty layer names */
1829         channels.layers(layerNames);
1830
1831         if (views.size() && views[0] != "") {
1832                 *r_multiview = true;
1833         }
1834         else {
1835                 *r_singlelayer = false;
1836                 *r_multilayer = true;
1837                 *r_multiview = false;
1838                 return;
1839         }
1840
1841         if (layerNames.size()) {
1842                 /* if layerNames is not empty, it means at least one layer is non-empty,
1843                  * but it also could be layers without names in the file and such case
1844                  * shall be considered a multilayer exr
1845                  *
1846                  * that's what we do here: test whether there're empty layer names together
1847                  * with non-empty ones in the file
1848                  */
1849                 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); i++)
1850                         for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
1851                                 /* see if any layername differs from a viewname */
1852                                 if (imb_exr_get_multiView_id(views, *i) == -1) {
1853                                         std::string layerName = *i;
1854                                         size_t pos = layerName.rfind ('.');
1855
1856                                         if (pos == std::string::npos) {
1857                                                 *r_multilayer = true;
1858                                                 *r_singlelayer = false;
1859                                                 return;
1860                                         }
1861                                 }
1862         }
1863         else {
1864                 *r_singlelayer = true;
1865                 *r_multilayer = false;
1866                 *r_multiview = false;
1867         }
1868
1869         BLI_assert(r_singlelayer != r_multilayer);
1870 }
1871
1872 bool IMB_exr_has_singlelayer_multiview(void *handle)
1873 {
1874         ExrHandle *data = (ExrHandle *)handle;
1875         MultiPartInputFile *file = data->ifile;
1876         std::set <std::string> layerNames;
1877         const ChannelList& channels = file->header(0).channels();
1878         const StringAttribute *comments;
1879
1880         if (exr_has_multiview(*file) == false)
1881                 return false;
1882
1883         comments = file->header(0).findTypedAttribute<StringAttribute>("BlenderMultiChannel");
1884
1885         if (comments)
1886                 return false;
1887
1888         /* will not include empty layer names */
1889         channels.layers(layerNames);
1890
1891         /* returns false if any layer differs from views list */
1892         if (layerNames.size())
1893                 for (std::set<string>::iterator i = layerNames.begin(); i != layerNames.end(); i++)
1894                         if (imb_exr_get_multiView_id(*data->multiView, *i) == -1)
1895                                 return false;
1896
1897         return true;
1898 }
1899
1900 bool IMB_exr_has_multilayer(void *handle)
1901 {
1902         ExrHandle *data = (ExrHandle *)handle;
1903         return imb_exr_is_multilayer_file(*data->ifile);
1904 }
1905
1906 static bool exr_has_multiview(MultiPartInputFile& file)
1907 {
1908         return hasMultiView(file.header(0));
1909 }
1910
1911 static bool exr_has_multipart_file(MultiPartInputFile& file)
1912 {
1913         return file.parts() > 1;
1914 }
1915
1916 /* it returns true if the file is multilayer or multiview */
1917 static bool imb_exr_is_multi(MultiPartInputFile& file)
1918 {
1919         /* multipart files are treated as multilayer in blender - even if they are single layer openexr with multiview */
1920         if (exr_has_multipart_file(file))
1921                 return true;
1922
1923         if (exr_has_multiview(file))
1924                 return true;
1925
1926         if (imb_exr_is_multilayer_file(file))
1927                 return true;
1928
1929         return false;
1930 }
1931
1932 struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
1933 {
1934         struct ImBuf *ibuf = NULL;
1935         Mem_IStream *membuf = NULL;
1936         MultiPartInputFile *file = NULL;
1937
1938         if (imb_is_a_openexr(mem) == 0) return(NULL);
1939
1940         colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
1941
1942         try
1943         {
1944                 bool is_multi;
1945
1946                 membuf = new Mem_IStream((unsigned char *)mem, size);
1947                 file = new MultiPartInputFile(*membuf);
1948
1949                 Box2i dw = file->header(0).dataWindow();
1950                 const int width  = dw.max.x - dw.min.x + 1;
1951                 const int height = dw.max.y - dw.min.y + 1;
1952
1953                 //printf("OpenEXR-load: image data window %d %d %d %d\n",
1954                 //         dw.min.x, dw.min.y, dw.max.x, dw.max.y);
1955
1956                 if (0) // debug
1957                         exr_print_filecontents(*file);
1958
1959                 is_multi = imb_exr_is_multi(*file);
1960
1961                 /* do not make an ibuf when */
1962                 if (is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) {
1963                         printf("Error: can't process EXR multilayer file\n");
1964                 }
1965                 else {
1966                         const int is_alpha = exr_has_alpha(*file);
1967
1968                         ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, 0);
1969
1970                         if (hasXDensity(file->header(0))) {
1971                                 ibuf->ppm[0] = xDensity(file->header(0)) * 39.3700787f;
1972                                 ibuf->ppm[1] = ibuf->ppm[0] * (double)file->header(0).pixelAspectRatio();
1973                         }
1974
1975                         ibuf->ftype = IMB_FTYPE_OPENEXR;
1976
1977                         if (!(flags & IB_test)) {
1978
1979                                 if (flags & IB_metadata) {
1980                                         const Header & header = file->header(0);
1981                                         Header::ConstIterator iter;
1982
1983                                         for (iter = header.begin(); iter != header.end(); iter++) {
1984                                                 const StringAttribute *attrib = file->header(0).findTypedAttribute <StringAttribute> (iter.name());
1985
1986                                                 /* not all attributes are string attributes so we might get some NULLs here */
1987                                                 if (attrib) {
1988                                                         IMB_metadata_add_field(ibuf, iter.name(), attrib->value().c_str());
1989                                                         ibuf->flags |= IB_metadata;
1990                                                 }
1991                                         }
1992                                 }
1993
1994                                 if (is_multi && ((flags & IB_thumbnail) == 0)) { /* only enters with IB_multilayer flag set */
1995                                         /* constructs channels for reading, allocates memory in channels */
1996                                         ExrHandle *handle = imb_exr_begin_read_mem(*membuf, *file, width, height);
1997                                         if (handle) {
1998                                                 IMB_exr_read_channels(handle);
1999                                                 ibuf->userdata = handle;         /* potential danger, the caller has to check for this! */
2000                                         }
2001                                 }
2002                                 else {
2003                                         const bool has_rgb = exr_has_rgb(*file);
2004                                         const bool has_luma = exr_has_luma(*file);
2005                                         FrameBuffer frameBuffer;
2006                                         float *first;
2007                                         int xstride = sizeof(float) * 4;
2008                                         int ystride = -xstride * width;
2009
2010                                         imb_addrectfloatImBuf(ibuf);
2011
2012                                         /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */
2013                                         first = ibuf->rect_float - 4 * (dw.min.x - dw.min.y * width);
2014                                         /* but, since we read y-flipped (negative y stride) we move to last scanline */
2015                                         first += 4 * (height - 1) * width;
2016
2017                                         if (has_rgb) {
2018                                                 frameBuffer.insert(exr_rgba_channelname(*file, "R"),
2019                                                                    Slice(Imf::FLOAT,  (char *) first, xstride, ystride));
2020                                                 frameBuffer.insert(exr_rgba_channelname(*file, "G"),
2021                                                                    Slice(Imf::FLOAT,  (char *) (first + 1), xstride, ystride));
2022                                                 frameBuffer.insert(exr_rgba_channelname(*file, "B"),
2023                                                                    Slice(Imf::FLOAT,  (char *) (first + 2), xstride, ystride));
2024                                         }
2025                                         else if (has_luma) {
2026                                                 frameBuffer.insert(exr_rgba_channelname(*file, "Y"),
2027                                                                    Slice(Imf::FLOAT,  (char *) first, xstride, ystride));
2028                                                 frameBuffer.insert(exr_rgba_channelname(*file, "BY"),
2029                                                                    Slice(Imf::FLOAT,  (char *) (first + 1), xstride, ystride, 1, 1, 0.5f));
2030                                                 frameBuffer.insert(exr_rgba_channelname(*file, "RY"),
2031                                                                    Slice(Imf::FLOAT,  (char *) (first + 2), xstride, ystride, 1, 1, 0.5f));
2032                                         }
2033
2034                                         /* 1.0 is fill value, this still needs to be assigned even when (is_alpha == 0) */
2035                                         frameBuffer.insert(exr_rgba_channelname(*file, "A"),
2036                                                            Slice(Imf::FLOAT,  (char *) (first + 3), xstride, ystride, 1, 1, 1.0f));
2037
2038                                         if (exr_has_zbuffer(*file)) {
2039                                                 float *firstz;
2040
2041                                                 addzbuffloatImBuf(ibuf);
2042                                                 firstz = ibuf->zbuf_float - (dw.min.x - dw.min.y * width);
2043                                                 firstz += (height - 1) * width;
2044                                                 frameBuffer.insert("Z", Slice(Imf::FLOAT,  (char *)firstz, sizeof(float), -width * sizeof(float)));
2045                                         }
2046
2047                                         InputPart in (*file, 0);
2048                                         in.setFrameBuffer(frameBuffer);
2049                                         in.readPixels(dw.min.y, dw.max.y);
2050
2051                                         // XXX, ImBuf has no nice way to deal with this.
2052                                         // ideally IM_rect would be used when the caller wants a rect BUT
2053                                         // at the moment all functions use IM_rect.
2054                                         // Disabling this is ok because all functions should check if a rect exists and create one on demand.
2055                                         //
2056                                         // Disabling this because the sequencer frees immediate.
2057                                         //
2058                                         // if (flag & IM_rect)
2059                                         //     IMB_rect_from_float(ibuf);
2060
2061                                         if (!has_rgb && has_luma) {
2062                                                 size_t a;
2063                                                 if (exr_has_chroma(*file)) {
2064                                                         for (a = 0; a < (size_t) ibuf->x * ibuf->y; ++a) {
2065                                                                 float *color = ibuf->rect_float + a * 4;
2066                                                                 ycc_to_rgb(color[0] * 255.0f, color[1] * 255.0f, color[2] * 255.0f,
2067                                                                            &color[0], &color[1], &color[2],
2068                                                                            BLI_YCC_ITU_BT709);
2069                                                         }
2070                                                 }
2071                                                 else {
2072                                                         for (a = 0; a < (size_t) ibuf->x * ibuf->y; ++a) {
2073                                                                 float *color = ibuf->rect_float + a * 4;
2074                                                                 color[1] = color[2] = color[0];
2075                                                         }
2076                                                 }
2077                                         }
2078
2079                                         /* file is no longer needed */
2080                                         delete membuf;
2081                                         delete file;
2082                                 }
2083                         }
2084                         else {
2085                                 delete membuf;
2086                                 delete file;
2087                         }
2088
2089                         if (flags & IB_alphamode_detect)
2090                                 ibuf->flags |= IB_alphamode_premul;
2091                 }
2092                 return(ibuf);
2093         }
2094         catch (const std::exception& exc)
2095         {
2096                 std::cerr << exc.what() << std::endl;
2097                 if (ibuf) IMB_freeImBuf(ibuf);
2098                 delete file;
2099                 delete membuf;
2100
2101                 return (0);
2102         }
2103
2104 }
2105
2106 void imb_initopenexr(void)
2107 {
2108         int num_threads = BLI_system_thread_count();
2109
2110         setGlobalThreadCount(num_threads);
2111 }
2112
2113 } // export "C"