soc-2008-mxcurioni: implemented (without testing) StrokeShader, Stroke and MediumType...
[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(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
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         int channels = ibuf->channels;
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 && channels >= 4)
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 && channels >= 4)
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 + (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 + channels*i*width;
226                                 
227                                 for (int j = ibuf->x; j > 0; j--) 
228                                 {
229                                         to->r = from[0];
230                                         to->g = (channels >= 2)? from[1]: from[0];
231                                         to->b = (channels >= 3)? from[2]: from[0];
232                                         to->a = (channels >= 4)? from[3]: from[0];
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 + channels*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)((channels >= 2)? from[1]: from[0])/255.0;
248                                         to->b = (float)((channels >= 3)? from[2]: from[0])/255.0;
249                                         to->a = (float)((channels >= 4)? from[3]: from[0])/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         int channels = ibuf->channels;
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 && channels >= 4)
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                 int xstride = sizeof(float) * channels;
297                 int ystride = - xstride*width;
298                 float *rect[4] = {NULL, NULL, NULL, NULL};
299
300                 rect[0]= ibuf->rect_float + channels*(height-1)*width;
301                 rect[1]= (channels >= 2)? rect[0]+1: rect[0];
302                 rect[2]= (channels >= 3)? rect[0]+2: rect[0];
303                 rect[3]= (channels >= 4)? rect[0]+3: rect[0];
304
305                 frameBuffer.insert ("R", Slice (FLOAT,  (char *)rect[0], xstride, ystride));
306                 frameBuffer.insert ("G", Slice (FLOAT,  (char *)rect[1], xstride, ystride));
307                 frameBuffer.insert ("B", Slice (FLOAT,  (char *)rect[2], xstride, ystride));
308                 if (ibuf->depth==32 && channels >= 4)
309                         frameBuffer.insert ("A", Slice (FLOAT,  (char *)rect[3], xstride, ystride));
310                 if (write_zbuf)
311                         frameBuffer.insert ("Z", Slice (FLOAT, (char *) (ibuf->zbuf_float + (height-1)*width),
312                                                                                         sizeof(float), sizeof(float) * -width));
313                 file->setFrameBuffer (frameBuffer);                               
314                 file->writePixels (height);                                       
315                 delete file;
316         }
317         catch (const std::exception &exc)
318         {      
319                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
320                 if (ibuf) IMB_freeImBuf(ibuf);
321                 
322                 return (0);
323         }
324         
325         return (1);
326         //      printf("OpenEXR-save: Done.\n");
327 }
328
329
330 short imb_save_openexr(struct ImBuf *ibuf, char *name, int flags)
331 {
332         if (flags & IB_mem) 
333         {
334                 printf("OpenEXR-save: Create EXR in memory CURRENTLY NOT SUPPORTED !\n");
335                 imb_addencodedbufferImBuf(ibuf);
336                 ibuf->encodedsize = 0;    
337                 return(0);
338         } 
339         
340         if (ibuf->ftype & OPENEXR_HALF) 
341                 return imb_save_openexr_half(ibuf, name, flags);
342         else {
343                 /* when no float rect, we save as half (16 bits is sufficient) */
344                 if (ibuf->rect_float==NULL)
345                         return imb_save_openexr_half(ibuf, name, flags);
346                 else
347                         return imb_save_openexr_float(ibuf, name, flags);
348         }
349 }
350
351 /* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */
352
353 /* naming rules:
354    - parse name from right to left
355    - last character is channel ID, 1 char like 'A' 'R' 'G' 'B' 'X' 'Y' 'Z' 'W' 'U' 'V'
356    - separated with a dot; the Pass name (like "Depth", "Color", "Diffuse" or "Combined")
357    - separated with a dot: the Layer name (like "Lamp1" or "Walls" or "Characters")
358 */
359
360 static ListBase exrhandles= {NULL, NULL};
361
362 typedef struct ExrHandle {
363         struct ExrHandle *next, *prev;
364         
365         InputFile *ifile;
366         TiledOutputFile *tofile;
367         OutputFile *ofile;
368         int tilex, tiley;
369         int width, height;
370         int mipmap;
371         
372         ListBase channels;      /* flattened out, ExrChannel */
373         ListBase layers;        /* hierarchical, pointing in end to ExrChannel */
374 } ExrHandle;
375
376 /* flattened out channel */
377 typedef struct ExrChannel {
378         struct ExrChannel *next, *prev;
379         
380         char name[EXR_TOT_MAXNAME+1];   /* full name of layer+pass */
381         int xstride, ystride;           /* step to next pixel, to next scanline */
382         float *rect;                            /* first pointer to write in */
383         char chan_id;                           /* quick lookup of channel char */
384 } ExrChannel;
385
386
387 /* hierarchical; layers -> passes -> channels[] */
388 typedef struct ExrPass {
389         struct ExrPass *next, *prev;
390         char name[EXR_PASS_MAXNAME];
391         int totchan;
392         float *rect;
393         struct ExrChannel *chan[EXR_PASS_MAXCHAN];
394         char chan_id[EXR_PASS_MAXCHAN];
395 } ExrPass;
396
397 typedef struct ExrLayer {
398         struct ExrLayer *next, *prev;
399         char name[EXR_LAY_MAXNAME+1];
400         ListBase passes;
401 } ExrLayer;
402
403 /* ********************** */
404
405 void *IMB_exr_get_handle(void)
406 {
407         ExrHandle *data= (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
408         BLI_addtail(&exrhandles, data);
409         return data;
410 }
411
412 /* adds flattened ExrChannels */
413 /* xstride, ystride and rect can be done in set_channel too, for tile writing */
414 void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
415 {
416         ExrHandle *data= (ExrHandle *)handle;
417         ExrChannel *echan;
418         
419         echan= (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel");
420         
421         if(layname) {
422                 char lay[EXR_LAY_MAXNAME+1], pass[EXR_PASS_MAXNAME+1];
423                 BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
424                 BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
425
426                 sprintf(echan->name, "%s.%s", lay, pass);
427         }
428         else
429                 BLI_strncpy(echan->name, passname, EXR_TOT_MAXNAME-1);
430         
431         echan->xstride= xstride;
432         echan->ystride= ystride;
433         echan->rect= rect;
434         
435         // printf("added channel %s\n", echan->name);
436         BLI_addtail(&data->channels, echan);
437 }
438
439 void IMB_exr_begin_write(void *handle, char *filename, int width, int height, int compress)
440 {
441         ExrHandle *data= (ExrHandle *)handle;
442         Header header (width, height);
443         ExrChannel *echan;
444         
445         data->width= width;
446         data->height= height;
447         
448         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
449                 header.channels().insert (echan->name, Channel (FLOAT));
450         
451         openexr_header_compression(&header, compress);
452         /* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */
453         
454         header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43"));
455         
456         data->ofile = new OutputFile(filename, header);
457 }
458
459 void IMB_exrtile_begin_write(void *handle, char *filename, int mipmap, int width, int height, int tilex, int tiley)
460 {
461         ExrHandle *data= (ExrHandle *)handle;
462         Header header (width, height);
463         ExrChannel *echan;
464         
465         data->tilex= tilex;
466         data->tiley= tiley;
467         data->width= width;
468         data->height= height;
469         data->mipmap= mipmap;
470         
471         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
472                 header.channels().insert (echan->name, Channel (FLOAT));
473         
474         header.setTileDescription (TileDescription (tilex, tiley, (mipmap)? MIPMAP_LEVELS: ONE_LEVEL));
475         header.lineOrder() = RANDOM_Y;
476         header.compression() = RLE_COMPRESSION;
477         
478         header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43"));
479         
480         data->tofile = new TiledOutputFile(filename, header);
481 }
482
483 /* read from file */
484 int IMB_exr_begin_read(void *handle, char *filename, int *width, int *height)
485 {
486         ExrHandle *data= (ExrHandle *)handle;
487         
488         if(BLI_exists(filename) && BLI_filepathsize(filename)>32) {     /* 32 is arbitrary, but zero length files crashes exr */
489                 data->ifile = new InputFile(filename);
490                 if(data->ifile) {
491                         Box2i dw = data->ifile->header().dataWindow();
492                         data->width= *width  = dw.max.x - dw.min.x + 1;
493                         data->height= *height = dw.max.y - dw.min.y + 1;
494                         
495                         const ChannelList &channels = data->ifile->header().channels();
496                         
497                         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
498                                 IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
499                         
500                         return 1;
501                 }
502         }
503         return 0;
504 }
505
506 /* still clumsy name handling, layers/channels can be ordered as list in list later */
507 void IMB_exr_set_channel(void *handle, char *layname, char *passname, int xstride, int ystride, float *rect)
508 {
509         ExrHandle *data= (ExrHandle *)handle;
510         ExrChannel *echan;
511         char name[EXR_TOT_MAXNAME + 1];
512         
513         if(layname) {
514                 char lay[EXR_LAY_MAXNAME+1], pass[EXR_PASS_MAXNAME+1];
515                 BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
516                 BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
517                 
518                 sprintf(name, "%s.%s", lay, pass);
519         }
520         else
521                 BLI_strncpy(name, passname, EXR_TOT_MAXNAME-1);
522         
523         
524         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
525                 if(strcmp(echan->name, name)==0)
526                         break;
527         
528         if(echan) {
529                 echan->xstride= xstride;
530                 echan->ystride= ystride;
531                 echan->rect= rect;
532         }
533         else
534                 printf("IMB_exrtile_set_channel error %s\n", name);
535 }
536
537 void IMB_exrtile_clear_channels(void *handle)
538 {
539         ExrHandle *data= (ExrHandle *)handle;
540         BLI_freelistN(&data->channels);
541 }
542
543 void IMB_exrtile_write_channels(void *handle, int partx, int party, int level)
544 {
545         ExrHandle *data= (ExrHandle *)handle;
546         FrameBuffer frameBuffer;
547         ExrChannel *echan;
548         
549         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
550                 float *rect= echan->rect - echan->xstride*partx - echan->ystride*party;
551
552                 frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)rect, 
553                                                         echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
554         }
555         
556         data->tofile->setFrameBuffer (frameBuffer);
557
558         try {
559                 // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
560                 data->tofile->writeTile (partx/data->tilex, party/data->tiley, level);
561         }
562         catch (const std::exception &exc) {
563                 std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
564         }
565 }
566
567 void IMB_exr_write_channels(void *handle)
568 {
569         ExrHandle *data= (ExrHandle *)handle;
570         FrameBuffer frameBuffer;
571         ExrChannel *echan;
572         
573         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
574                 frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)echan->rect, 
575                                                                                                 echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
576         
577         data->ofile->setFrameBuffer (frameBuffer);
578         data->ofile->writePixels (data->height);        
579         
580 }
581
582 void IMB_exr_read_channels(void *handle)
583 {
584         ExrHandle *data= (ExrHandle *)handle;
585         FrameBuffer frameBuffer;
586         ExrChannel *echan;
587         
588         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
589                 /* no datawindow correction needed */
590                 if(echan->rect)
591                         frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)echan->rect, 
592                                                                                                 echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
593                 else 
594                         printf("warning, channel with no rect set %s\n", echan->name);
595         }
596         
597         data->ifile->setFrameBuffer (frameBuffer);
598         data->ifile->readPixels (0, data->height-1);    
599 }
600
601 void IMB_exr_multilayer_convert(void *handle, void *base,  
602                                                                 void * (*addlayer)(void *base, char *str), 
603                                                                 void (*addpass)(void *base, void *lay, char *str, 
604                                                                                                 float *rect, int totchan, char *chan_id))
605 {
606         ExrHandle *data= (ExrHandle *)handle;
607         ExrLayer *lay;
608         ExrPass *pass;
609
610         if(data->layers.first==NULL) {
611                 printf("cannot convert multilayer, no layers in handle\n");
612                 return;
613         }
614
615         for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) {
616                 void *laybase= addlayer(base, lay->name);
617                 if(laybase) {
618                         for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) {
619                                 addpass(base, laybase, pass->name, pass->rect, pass->totchan, pass->chan_id);
620                                 pass->rect= NULL;
621                         }
622                 }
623         }
624 }
625
626
627 void IMB_exr_close(void *handle)
628 {
629         ExrHandle *data= (ExrHandle *)handle;
630         ExrLayer *lay;
631         ExrPass *pass;
632         
633         if(data->ifile)
634                 delete data->ifile;
635         else if(data->ofile)
636                 delete data->ofile;
637         else if(data->tofile)
638                 delete data->tofile;
639         
640         data->ifile= NULL;
641         data->ofile= NULL;
642         data->tofile= NULL;
643         
644         BLI_freelistN(&data->channels);
645         
646         for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) {
647                 for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next)
648                         if(pass->rect)
649                                 MEM_freeN(pass->rect);
650                 BLI_freelistN(&lay->passes);
651         }
652         BLI_freelistN(&data->layers);
653         
654         BLI_remlink(&exrhandles, data);
655         MEM_freeN(data);
656 }
657
658 /* ********* */
659
660 static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
661 {
662         int plen, len= strlen(echan->name);
663         
664         if(len < 4) {
665                 printf("multilayer read: name too short: %s\n", echan->name);
666                 return 0;
667         }
668         if(echan->name[len-2]!='.') {
669                 printf("multilayer read: name has no Channel: %s\n", echan->name);
670                 return 0;
671         }
672         echan->chan_id= echan->name[len-1];
673         
674         len-= 3;
675         while(len>=0) {
676                 if(echan->name[len]=='.')
677                         break;
678                 len--;
679         }
680         BLI_strncpy(passname, echan->name+len+1, EXR_PASS_MAXNAME);
681         plen= strlen(passname);
682         if(plen < 3) {
683                 printf("multilayer read: should not happen: %s\n", echan->name);
684                 return 0;
685         }
686         passname[plen-2]= 0;
687         
688         if(len<1)
689                 layname[0]= 0;
690         else {
691                 BLI_strncpy(layname, echan->name, EXR_LAY_MAXNAME);
692                 layname[len]= 0;
693         }
694         // printf("found lay %s pass %s chan %c\n", layname, passname, echan->chan_id);
695         return 1;
696 }
697
698 static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
699 {
700         ExrLayer *lay;
701         
702         for(lay= (ExrLayer *)lb->first; lay; lay= lay->next) {
703                 if( strcmp(lay->name, layname)==0 )
704                         return lay;
705         }
706         lay= (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
707         BLI_addtail(lb, lay);
708         BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
709         
710         return lay;
711 }
712
713 static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
714 {
715         ExrPass *pass;
716         
717         for(pass= (ExrPass *)lb->first; pass; pass= pass->next) {
718                 if( strcmp(pass->name, passname)==0 )
719                         return pass;
720         }
721         
722         pass= (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
723
724         if(strcmp(passname, "Combined")==0)
725                 BLI_addhead(lb, pass);
726         else
727                 BLI_addtail(lb, pass);
728         
729         BLI_strncpy(pass->name, passname, EXR_LAY_MAXNAME);
730         
731         return pass;
732 }
733
734 /* creates channels, makes a hierarchy and assigns memory to channels */
735 static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
736 {
737         ExrLayer *lay;
738         ExrPass *pass;
739         ExrChannel *echan;
740         ExrHandle *data= (ExrHandle *)IMB_exr_get_handle();
741         int a;
742         char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
743         
744         data->ifile= file;
745         data->width= width;
746         data->height= height;
747         
748         const ChannelList &channels = data->ifile->header().channels();
749
750         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
751                 IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
752         
753         /* now try to sort out how to assign memory to the channels */
754         /* first build hierarchical layer list */
755         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
756                 if( imb_exr_split_channel_name(echan, layname, passname) ) {
757                         ExrLayer *lay= imb_exr_get_layer(&data->layers, layname);
758                         ExrPass *pass= imb_exr_get_pass(&lay->passes, passname);
759                         
760                         pass->chan[pass->totchan]= echan;
761                         pass->totchan++;
762                         if(pass->totchan>=EXR_PASS_MAXCHAN)
763                                 break;
764                 }
765         }
766         if(echan) {
767                 printf("error, too many channels in one pass: %s\n", echan->name);
768                 IMB_exr_close(data);
769                 return NULL;
770         }
771         
772         /* with some heuristics, try to merge the channels in buffers */
773         for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) {
774                 for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) {
775                         if(pass->totchan) {
776                                 pass->rect= (float *)MEM_mapallocN(width*height*pass->totchan*sizeof(float), "pass rect");
777                                 if(pass->totchan==1) {
778                                         echan= pass->chan[0];
779                                         echan->rect= pass->rect;
780                                         echan->xstride= 1;
781                                         echan->ystride= width;
782                                         pass->chan_id[0]= echan->chan_id;
783                                 }
784                                 else {
785                                         char lookup[256];
786                                         
787                                         memset(lookup, 0, sizeof(lookup));
788                                                    
789                                         /* we can have RGB(A), XYZ(W), UVA */
790                                         if(pass->totchan==3 || pass->totchan==4) {
791                                                 if(pass->chan[0]->chan_id=='B' || pass->chan[1]->chan_id=='B' ||  pass->chan[2]->chan_id=='B') {
792                                                         lookup[(unsigned int)'R']= 0;
793                                                         lookup[(unsigned int)'G']= 1;
794                                                         lookup[(unsigned int)'B']= 2;
795                                                         lookup[(unsigned int)'A']= 3;
796                                                 }
797                                                 else if(pass->chan[0]->chan_id=='Y' || pass->chan[1]->chan_id=='Y' ||  pass->chan[2]->chan_id=='Y') {
798                                                         lookup[(unsigned int)'X']= 0;
799                                                         lookup[(unsigned int)'Y']= 1;
800                                                         lookup[(unsigned int)'Z']= 2;
801                                                         lookup[(unsigned int)'W']= 3;
802                                                 }
803                                                 else {
804                                                         lookup[(unsigned int)'U']= 0;
805                                                         lookup[(unsigned int)'V']= 1;
806                                                         lookup[(unsigned int)'A']= 2;
807                                                 }
808                                                 for(a=0; a<pass->totchan; a++) {
809                                                         echan= pass->chan[a];
810                                                         echan->rect= pass->rect + lookup[(unsigned int)echan->chan_id];
811                                                         echan->xstride= pass->totchan;
812                                                         echan->ystride= width*pass->totchan;
813                                                         pass->chan_id[ (unsigned int)lookup[(unsigned int)echan->chan_id] ]= echan->chan_id;
814                                                 }
815                                         }
816                                         else { /* unknown */
817                                                 for(a=0; a<pass->totchan; a++) {
818                                                         echan= pass->chan[a];
819                                                         echan->rect= pass->rect + a;
820                                                         echan->xstride= pass->totchan;
821                                                         echan->ystride= width*pass->totchan;
822                                                         pass->chan_id[a]= echan->chan_id;
823                                                 }
824                                         }
825                                 }
826                         }
827                 }
828         }
829         
830         return data;
831 }
832
833
834 /* ********************************************************* */
835
836 typedef struct RGBA
837 {
838         float r;
839         float g;
840         float b;
841         float a;
842 } RGBA;
843
844
845 /* debug only */
846 static void exr_print_filecontents(InputFile *file)
847 {
848         const ChannelList &channels = file->header().channels();
849         
850         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
851         {
852                 const Channel &channel = i.channel();
853                 printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
854         }
855 }
856
857 /* for non-multilayer, map  R G B A channel names to something that's in this file */
858 static const char *exr_rgba_channelname(InputFile *file, const char *chan)
859 {
860         const ChannelList &channels = file->header().channels();
861         
862         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
863         {
864                 const Channel &channel = i.channel();
865                 const char *str= i.name();
866                 int len= strlen(str);
867                 if(len) {
868                         if(BLI_strcasecmp(chan, str+len-1)==0) {
869                                 return str;
870                         }
871                 }
872         }
873         return chan;
874 }
875
876
877
878 static int exr_has_zbuffer(InputFile *file)
879 {
880         const ChannelList &channels = file->header().channels();
881         
882         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
883         {
884                 if(strcmp("Z", i.name())==0)
885                         return 1;
886         }
887         return 0;
888 }
889
890 static int exr_is_renderresult(InputFile *file)
891 {
892         const StringAttribute *comments= file->header().findTypedAttribute<StringAttribute>("BlenderMultiChannel");
893         if(comments)
894 //              if(comments->value() == "Blender MultiChannel")
895                         return 1;
896         return 0;
897 }
898
899 struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags)
900 {
901         struct ImBuf *ibuf = NULL;
902         InputFile *file = NULL;
903         
904         if (imb_is_a_openexr(mem) == 0) return(NULL);
905         
906         try
907         {
908                 Mem_IStream *membuf = new Mem_IStream(mem, size); 
909                 int is_multi;
910                 file = new InputFile(*membuf);
911                 
912                 Box2i dw = file->header().dataWindow();
913                 int width  = dw.max.x - dw.min.x + 1;
914                 int height = dw.max.y - dw.min.y + 1;
915                 
916                 //printf("OpenEXR-load: image data window %d %d %d %d\n", 
917                 //         dw.min.x, dw.min.y, dw.max.x, dw.max.y);
918
919                 if(0) // debug
920                         exr_print_filecontents(file);
921                 
922                 is_multi= exr_is_renderresult(file);
923                 
924                 /* do not make an ibuf when */
925                 if(is_multi && !(flags & IB_test) && !(flags & IB_multilayer)) 
926                 {
927                         printf("Error: can't process EXR multilayer file\n");
928                 }
929                 else {
930                 
931                         ibuf = IMB_allocImBuf(width, height, 32, 0, 0);
932                         ibuf->ftype = OPENEXR;
933                         
934                         if (!(flags & IB_test))
935                         {
936                                 if(is_multi) /* only enters with IB_multilayer flag set */
937                                 {
938                                         /* constructs channels for reading, allocates memory in channels */
939                                         ExrHandle *handle= imb_exr_begin_read_mem(file, width, height);
940                                         if(handle) {
941                                                 IMB_exr_read_channels(handle);
942                                                 ibuf->userdata= handle;                 /* potential danger, the caller has to check for this! */
943                                                 return ibuf;
944                                         }
945                                 }
946                                 else {
947                                         FrameBuffer frameBuffer;
948                                         float *first;
949                                         int xstride = sizeof(float) * 4;
950                                         int ystride = - xstride*width;
951                                         
952                                         imb_addrectfloatImBuf(ibuf);
953                                         
954                                         /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */
955                                         first= ibuf->rect_float - 4*(dw.min.x - dw.min.y*width);
956                                         /* but, since we read y-flipped (negative y stride) we move to last scanline */
957                                         first+= 4*(height-1)*width;
958                                         
959                                         frameBuffer.insert ( exr_rgba_channelname(file, "R"), 
960                                                                                 Slice (FLOAT,  (char *) first, xstride, ystride));
961                                         frameBuffer.insert ( exr_rgba_channelname(file, "G"), 
962                                                                                 Slice (FLOAT,  (char *) (first+1), xstride, ystride));
963                                         frameBuffer.insert ( exr_rgba_channelname(file, "B"), 
964                                                                                 Slice (FLOAT,  (char *) (first+2), xstride, ystride));
965                                                                                                                                                         
966                                         frameBuffer.insert ( exr_rgba_channelname(file, "A"), 
967                                                                                 Slice (FLOAT,  (char *) (first+3), xstride, ystride, 1, 1, 1.0f)); /* 1.0 is fill value */
968
969                                         if(exr_has_zbuffer(file)) 
970                                         {
971                                                 float *firstz;
972                                                 
973                                                 addzbuffloatImBuf(ibuf);
974                                                 firstz= ibuf->zbuf_float - (dw.min.x - dw.min.y*width);
975                                                 firstz+= (height-1)*width;
976                                                 frameBuffer.insert ("Z", Slice (FLOAT,  (char *)firstz , sizeof(float), -width*sizeof(float)));
977                                         }
978                                         
979                                         file->setFrameBuffer (frameBuffer);
980                                         file->readPixels (dw.min.y, dw.max.y);
981                                         
982                                         IMB_rect_from_float(ibuf);
983                                 }
984                         }
985                         
986                 }
987                 delete file;
988                 
989                 return(ibuf);
990                                 
991         }
992         catch (const std::exception &exc)
993         {
994                 std::cerr << exc.what() << std::endl;
995                 if (ibuf) IMB_freeImBuf(ibuf);
996                 delete file;
997                 
998                 return (0);
999         }
1000         
1001 }
1002
1003
1004 } // export "C"