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