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