MultiLayer images: added support for choosing compression type.
[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
530 void IMB_exrtile_write_channels(void *handle, int partx, int party)
531 {
532         ExrHandle *data= (ExrHandle *)handle;
533         FrameBuffer frameBuffer;
534         ExrChannel *echan;
535         
536         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
537                 float *rect= echan->rect - echan->xstride*partx - echan->ystride*party;
538
539                 frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)rect, 
540                                                         echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
541         }
542         
543         data->tofile->setFrameBuffer (frameBuffer);
544         // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
545         data->tofile->writeTile (partx/data->tilex, party/data->tiley); 
546         
547 }
548
549 void IMB_exr_write_channels(void *handle)
550 {
551         ExrHandle *data= (ExrHandle *)handle;
552         FrameBuffer frameBuffer;
553         ExrChannel *echan;
554         
555         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
556                 frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)echan->rect, 
557                                                                                                 echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
558         
559         data->ofile->setFrameBuffer (frameBuffer);
560         data->ofile->writePixels (data->height);        
561         
562 }
563
564 void IMB_exr_read_channels(void *handle)
565 {
566         ExrHandle *data= (ExrHandle *)handle;
567         FrameBuffer frameBuffer;
568         ExrChannel *echan;
569         
570         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
571                 /* no datawindow correction needed */
572                 if(echan->rect)
573                         frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)echan->rect, 
574                                                                                                 echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
575                 else 
576                         printf("warning, channel with no rect set %s\n", echan->name);
577         }
578         
579         data->ifile->setFrameBuffer (frameBuffer);
580         data->ifile->readPixels (0, data->height-1);    
581 }
582
583 void IMB_exr_multilayer_convert(void *handle, void *base,  
584                                                                 void * (*addlayer)(void *base, char *str), 
585                                                                 void (*addpass)(void *base, void *lay, char *str, 
586                                                                                                 float *rect, int totchan, char *chan_id))
587 {
588         ExrHandle *data= (ExrHandle *)handle;
589         ExrLayer *lay;
590         ExrPass *pass;
591
592         if(data->layers.first==NULL) {
593                 printf("cannot convert multilayer, no layers in handle\n");
594                 return;
595         }
596
597         for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) {
598                 void *laybase= addlayer(base, lay->name);
599                 if(laybase) {
600                         for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) {
601                                 addpass(base, laybase, pass->name, pass->rect, pass->totchan, pass->chan_id);
602                                 pass->rect= NULL;
603                         }
604                 }
605         }
606 }
607
608
609 void IMB_exr_close(void *handle)
610 {
611         ExrHandle *data= (ExrHandle *)handle;
612         ExrChannel *echan;
613         ExrLayer *lay;
614         ExrPass *pass;
615         
616         if(data->ifile)
617                 delete data->ifile;
618         else if(data->ofile)
619                 delete data->ofile;
620         else if(data->tofile)
621                 delete data->tofile;
622         
623         data->ifile= NULL;
624         data->ofile= NULL;
625         data->tofile= NULL;
626         
627         BLI_freelistN(&data->channels);
628         
629         for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) {
630                 for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next)
631                         if(pass->rect)
632                                 MEM_freeN(pass->rect);
633                 BLI_freelistN(&lay->passes);
634         }
635         BLI_freelistN(&data->layers);
636         
637         BLI_remlink(&exrhandles, data);
638         MEM_freeN(data);
639 }
640
641 /* ********* */
642
643 static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
644 {
645         int plen, len= strlen(echan->name);
646         
647         if(len < 4) {
648                 printf("multilayer read: name too short: %s\n", echan->name);
649                 return 0;
650         }
651         if(echan->name[len-2]!='.') {
652                 printf("multilayer read: name has no Channel: %s\n", echan->name);
653                 return 0;
654         }
655         echan->chan_id= echan->name[len-1];
656         
657         len-= 3;
658         while(len>=0) {
659                 if(echan->name[len]=='.')
660                         break;
661                 len--;
662         }
663         BLI_strncpy(passname, echan->name+len+1, EXR_PASS_MAXNAME);
664         plen= strlen(passname);
665         if(plen < 3) {
666                 printf("multilayer read: should not happen: %s\n", echan->name);
667                 return 0;
668         }
669         passname[plen-2]= 0;
670         
671         if(len<1)
672                 layname[0]= 0;
673         else {
674                 BLI_strncpy(layname, echan->name, EXR_LAY_MAXNAME);
675                 layname[len]= 0;
676         }
677         // printf("found lay %s pass %s chan %c\n", layname, passname, echan->chan_id);
678         return 1;
679 }
680
681 static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
682 {
683         ExrLayer *lay;
684         
685         for(lay= (ExrLayer *)lb->first; lay; lay= lay->next) {
686                 if( strcmp(lay->name, layname)==0 )
687                         return lay;
688         }
689         lay= (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
690         BLI_addtail(lb, lay);
691         BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
692         
693         return lay;
694 }
695
696 static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
697 {
698         ExrPass *pass;
699         
700         for(pass= (ExrPass *)lb->first; pass; pass= pass->next) {
701                 if( strcmp(pass->name, passname)==0 )
702                         return pass;
703         }
704         
705         pass= (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
706
707         if(strcmp(passname, "Combined")==0)
708                 BLI_addhead(lb, pass);
709         else
710                 BLI_addtail(lb, pass);
711         
712         BLI_strncpy(pass->name, passname, EXR_LAY_MAXNAME);
713         
714         return pass;
715 }
716
717 /* creates channels, makes a hierarchy and assigns memory to channels */
718 static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
719 {
720         ExrLayer *lay;
721         ExrPass *pass;
722         ExrChannel *echan;
723         ExrHandle *data= (ExrHandle *)IMB_exr_get_handle();
724         int a;
725         char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
726         
727         data->ifile= file;
728         data->width= width;
729         data->height= height;
730         
731         const ChannelList &channels = data->ifile->header().channels();
732
733         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
734                 IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
735         
736         /* now try to sort out how to assign memory to the channels */
737         /* first build hierarchical layer list */
738         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
739                 if( imb_exr_split_channel_name(echan, layname, passname) ) {
740                         ExrLayer *lay= imb_exr_get_layer(&data->layers, layname);
741                         ExrPass *pass= imb_exr_get_pass(&lay->passes, passname);
742                         
743                         pass->chan[pass->totchan]= echan;
744                         pass->totchan++;
745                         if(pass->totchan>=EXR_PASS_MAXCHAN)
746                                 break;
747                 }
748         }
749         if(echan) {
750                 printf("error, too many channels in one pass: %s\n", echan->name);
751                 IMB_exr_close(data);
752                 return NULL;
753         }
754         
755         /* with some heuristics, try to merge the channels in buffers */
756         for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) {
757                 for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) {
758                         if(pass->totchan) {
759                                 pass->rect= (float *)MEM_mapallocN(width*height*pass->totchan*sizeof(float), "pass rect");
760                                 if(pass->totchan==1) {
761                                         echan= pass->chan[0];
762                                         echan->rect= pass->rect;
763                                         echan->xstride= 1;
764                                         echan->ystride= width;
765                                         pass->chan_id[0]= echan->chan_id;
766                                 }
767                                 else {
768                                         char lookup[256];
769                                         
770                                         memset(lookup, 0, sizeof(lookup));
771                                                    
772                                         /* we can have RGB(A), XYZ(W), UVA */
773                                         if(pass->totchan==3 || pass->totchan==4) {
774                                                 if(pass->chan[0]->chan_id=='B' || pass->chan[1]->chan_id=='B' ||  pass->chan[2]->chan_id=='B') {
775                                                         lookup['R']= 0;
776                                                         lookup['G']= 1;
777                                                         lookup['B']= 2;
778                                                         lookup['A']= 3;
779                                                 }
780                                                 else if(pass->chan[0]->chan_id=='Y' || pass->chan[1]->chan_id=='Y' ||  pass->chan[2]->chan_id=='Y') {
781                                                         lookup['X']= 0;
782                                                         lookup['Y']= 1;
783                                                         lookup['Z']= 2;
784                                                         lookup['W']= 3;
785                                                 }
786                                                 else {
787                                                         lookup['U']= 0;
788                                                         lookup['V']= 1;
789                                                         lookup['A']= 2;
790                                                 }
791                                                 for(a=0; a<pass->totchan; a++) {
792                                                         echan= pass->chan[a];
793                                                         echan->rect= pass->rect + lookup[echan->chan_id];
794                                                         echan->xstride= pass->totchan;
795                                                         echan->ystride= width*pass->totchan;
796                                                         pass->chan_id[ lookup[echan->chan_id] ]= echan->chan_id;
797                                                 }
798                                         }
799                                         else { /* unknown */
800                                                 for(a=0; a<pass->totchan; a++) {
801                                                         echan= pass->chan[a];
802                                                         echan->rect= pass->rect + a;
803                                                         echan->xstride= pass->totchan;
804                                                         echan->ystride= width*pass->totchan;
805                                                         pass->chan_id[a]= echan->chan_id;
806                                                 }
807                                         }
808                                 }
809                         }
810                 }
811         }
812         
813         return data;
814 }
815
816
817 /* ********************************************************* */
818
819 typedef struct RGBA
820 {
821         float r;
822         float g;
823         float b;
824         float a;
825 } RGBA;
826
827
828 static void exr_print_filecontents(InputFile *file)
829 {
830         const ChannelList &channels = file->header().channels();
831         
832         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
833         {
834                 const Channel &channel = i.channel();
835                 printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
836         }
837 }
838
839 static int exr_has_zbuffer(InputFile *file)
840 {
841         const ChannelList &channels = file->header().channels();
842         
843         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
844         {
845                 const Channel &channel = i.channel();
846                 if(strcmp("Z", i.name())==0)
847                         return 1;
848         }
849         return 0;
850 }
851
852 static int exr_is_renderresult(InputFile *file)
853 {
854         const StringAttribute *comments= file->header().findTypedAttribute<StringAttribute>("BlenderMultiChannel");
855         if(comments)
856 //              if(comments->value() == "Blender MultiChannel")
857                         return 1;
858         return 0;
859 }
860
861 struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags)
862 {
863         struct ImBuf *ibuf = NULL;
864         InputFile *file = NULL;
865         
866         if (imb_is_a_openexr(mem) == 0) return(NULL);
867         
868         try
869         {
870                 Mem_IStream membuf(mem, size); 
871                 int is_multi;
872                 file = new InputFile(membuf);
873                 
874                 Box2i dw = file->header().dataWindow();
875                 int width  = dw.max.x - dw.min.x + 1;
876                 int height = dw.max.y - dw.min.y + 1;
877                 
878                 //printf("OpenEXR-load: image data window %d %d %d %d\n", 
879                 //         dw.min.x, dw.min.y, dw.max.x, dw.max.y);
880
881                 // exr_print_filecontents(file);
882                 
883                 is_multi= exr_is_renderresult(file);
884                 
885                 /* do not make an ibuf when */
886                 if(is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) 
887                 {
888                         printf("Error: can't process EXR multilayer file\n");
889                 }
890                 else {
891                 
892                         ibuf = IMB_allocImBuf(width, height, 32, 0, 0);
893                         ibuf->ftype = OPENEXR;
894                         
895                         if (!(flags & IB_test))
896                         {
897                                 if(is_multi) /* only enters with IB_multilayer flag set */
898                                 {
899                                         /* constructs channels for reading, allocates memory in channels */
900                                         ExrHandle *handle= imb_exr_begin_read_mem(file, width, height);
901                                         if(handle) {
902                                                 IMB_exr_read_channels(handle);
903                                                 ibuf->userdata= handle;                 /* potential danger, the caller has to check for this! */
904                                                 return ibuf;
905                                         }
906                                 }
907                                 else {
908                                         FrameBuffer frameBuffer;
909                                         float *first;
910                                         int xstride = sizeof(float) * 4;
911                                         int ystride = - xstride*width;
912                                         
913                                         imb_addrectfloatImBuf(ibuf);
914                                         
915                                         /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */
916                                         first= ibuf->rect_float - 4*(dw.min.x - dw.min.y*width);
917                                         /* but, since we read y-flipped (negative y stride) we move to last scanline */
918                                         first+= 4*(height-1)*width;
919                                         
920                                         frameBuffer.insert ("R", Slice (FLOAT,  (char *) first, xstride, ystride));
921                                         frameBuffer.insert ("G", Slice (FLOAT,  (char *) (first+1), xstride, ystride));
922                                         frameBuffer.insert ("B", Slice (FLOAT,  (char *) (first+2), xstride, ystride));
923                                                                                                                                                         /* 1.0 is fill value */
924                                         frameBuffer.insert ("A", Slice (FLOAT,  (char *) (first+3), xstride, ystride, 1, 1, 1.0f));
925
926                                         if(exr_has_zbuffer(file)) 
927                                         {
928                                                 float *firstz;
929                                                 
930                                                 addzbuffloatImBuf(ibuf);
931                                                 firstz= ibuf->zbuf_float - (dw.min.x - dw.min.y*width);
932                                                 firstz+= (height-1)*width;
933                                                 frameBuffer.insert ("Z", Slice (FLOAT,  (char *)firstz , sizeof(float), -width*sizeof(float)));
934                                         }
935                                         
936                                         file->setFrameBuffer (frameBuffer);
937                                         file->readPixels (dw.min.y, dw.max.y);
938                                         
939                                         IMB_rect_from_float(ibuf);
940                                 }
941                         }
942                         
943                         delete file;
944                 }
945                 
946                 return(ibuf);
947                                 
948         }
949         catch (const std::exception &exc)
950         {
951                 std::cerr << exc.what() << std::endl;
952                 if (ibuf) IMB_freeImBuf(ibuf);
953                 
954                 return (0);
955         }
956         
957 }
958
959
960 } // export "C"