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