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