CMake: Fix FFMPeg/OpenEXR issues in CMake system and possibly the others. OpenEXR...
[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() = NO_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 /* ********************* Tile file support ************************************ */
347
348 typedef struct ExrHandle {
349         InputFile *ifile;
350         TiledOutputFile *tofile;
351         OutputFile *ofile;
352         int tilex, tiley;
353         int width, height;
354         ListBase channels;
355 } ExrHandle;
356
357 #define CHANMAXNAME 64
358 typedef struct ExrChannel {
359         struct ExrChannel *next, *prev;
360         char name[2*CHANMAXNAME + 1];
361         int xstride, ystride;
362         float *rect;
363 } ExrChannel;
364
365 /* not threaded! write one tiled file at a time */
366 void *IMB_exr_get_handle(void)
367 {
368         static ExrHandle data;
369         
370         memset(&data, sizeof(ExrHandle), 0);
371         
372         return &data;
373 }
374
375 /* still clumsy name handling, layers/channels can be ordered as list in list later */
376 void IMB_exr_add_channel(void *handle, const char *layname, const char *channame)
377 {
378         ExrHandle *data= (ExrHandle *)handle;
379         ExrChannel *echan;
380         
381         echan= (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel");
382         
383         if(layname) {
384                 char lay[CHANMAXNAME], chan[CHANMAXNAME];
385                 strncpy(lay, layname, CHANMAXNAME-1);
386                 strncpy(chan, channame, CHANMAXNAME-1);
387
388                 sprintf(echan->name, "%s.%s", lay, chan);
389         }
390         else
391                 strncpy(echan->name, channame, 2*CHANMAXNAME);
392         // printf("added channel %s\n", echan->name);
393         BLI_addtail(&data->channels, echan);
394 }
395
396 void IMB_exr_begin_write(void *handle, char *filename, int width, int height)
397 {
398         ExrHandle *data= (ExrHandle *)handle;
399         Header header (width, height);
400         ExrChannel *echan;
401         
402         data->width= width;
403         data->height= height;
404         
405         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
406                 header.channels().insert (echan->name, Channel (FLOAT));
407         
408         header.insert ("comments", StringAttribute ("Blender MultiChannel"));
409         
410         data->ofile = new OutputFile(filename, header);
411 }
412
413 void IMB_exrtile_begin_write(void *handle, char *filename, int width, int height, int tilex, int tiley)
414 {
415         ExrHandle *data= (ExrHandle *)handle;
416         Header header (width, height);
417         ExrChannel *echan;
418         
419         data->tilex= tilex;
420         data->tiley= tiley;
421         data->width= width;
422         data->height= height;
423         
424         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
425                 header.channels().insert (echan->name, Channel (FLOAT));
426         
427         header.setTileDescription (TileDescription (tilex, tiley, ONE_LEVEL));
428         header.lineOrder() = RANDOM_Y,
429         header.compression() = NO_COMPRESSION;
430         
431         header.insert ("comments", StringAttribute ("Blender MultiChannel"));
432         
433         data->tofile = new TiledOutputFile(filename, header);
434 }
435
436 int IMB_exr_begin_read(void *handle, char *filename, int *width, int *height)
437 {
438         ExrHandle *data= (ExrHandle *)handle;
439         
440         if(BLI_exists(filename)) {
441                 data->ifile = new InputFile(filename);
442                 if(data->ifile) {
443                         Box2i dw = data->ifile->header().dataWindow();
444                         data->width= *width  = dw.max.x - dw.min.x + 1;
445                         data->height= *height = dw.max.y - dw.min.y + 1;
446                         
447                         const ChannelList &channels = data->ifile->header().channels();
448                         
449                         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
450                                 IMB_exr_add_channel(data, NULL, i.name());
451                         
452                         return 1;
453                 }
454         }
455         return 0;
456 }
457
458 /* still clumsy name handling, layers/channels can be ordered as list in list later */
459 void IMB_exr_set_channel(void *handle, char *layname, char *channame, int xstride, int ystride, float *rect)
460 {
461         ExrHandle *data= (ExrHandle *)handle;
462         ExrChannel *echan;
463         char name[2*CHANMAXNAME + 1];
464         
465         if(layname) {
466                 char lay[CHANMAXNAME], chan[CHANMAXNAME];
467                 strncpy(lay, layname, CHANMAXNAME-1);
468                 strncpy(chan, channame, CHANMAXNAME-1);
469                 
470                 sprintf(name, "%s.%s", lay, chan);
471         }
472         else
473                 strncpy(name, channame, 2*CHANMAXNAME);
474         
475         
476         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
477                 if(strcmp(echan->name, name)==0)
478                         break;
479         
480         if(echan) {
481                 echan->xstride= xstride;
482                 echan->ystride= ystride;
483                 echan->rect= rect;
484         }
485         else
486                 printf("IMB_exrtile_set_channel error %s\n", name);
487 }
488
489
490 void IMB_exrtile_write_channels(void *handle, int partx, int party)
491 {
492         ExrHandle *data= (ExrHandle *)handle;
493         FrameBuffer frameBuffer;
494         ExrChannel *echan;
495         
496         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
497                 float *rect= echan->rect - echan->xstride*partx - echan->ystride*party;
498
499                 frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)rect, 
500                                                         echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
501         }
502         
503         data->tofile->setFrameBuffer (frameBuffer);
504         // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
505         data->tofile->writeTile (partx/data->tilex, party/data->tiley); 
506         
507 }
508
509 void IMB_exr_write_channels(void *handle)
510 {
511         ExrHandle *data= (ExrHandle *)handle;
512         FrameBuffer frameBuffer;
513         ExrChannel *echan;
514         
515         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
516                 frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)echan->rect, 
517                                                                                                 echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
518         
519         data->ofile->setFrameBuffer (frameBuffer);
520         data->ofile->writePixels (data->height);        
521         
522 }
523
524 void IMB_exr_read_channels(void *handle)
525 {
526         ExrHandle *data= (ExrHandle *)handle;
527         FrameBuffer frameBuffer;
528         ExrChannel *echan;
529         
530         for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
531                 /* no datawindow correction needed */
532                 if(echan->rect)
533                         frameBuffer.insert (echan->name, Slice (FLOAT,  (char *)echan->rect, 
534                                                                                                 echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
535                 else 
536                         printf("warning, channel with no rect set %s\n", echan->name);
537         }
538         
539         data->ifile->setFrameBuffer (frameBuffer);
540         data->ifile->readPixels (0, data->height-1);    
541 }
542
543
544 void IMB_exr_close(void *handle)
545 {
546         ExrHandle *data= (ExrHandle *)handle;
547         ExrChannel *echan;
548         
549         if(data->ifile)
550                 delete data->ifile;
551         else if(data->ofile)
552                 delete data->ofile;
553         else if(data->tofile)
554                 delete data->tofile;
555         
556         data->ifile= NULL;
557         data->ofile= NULL;
558         data->tofile= NULL;
559         
560         BLI_freelistN(&data->channels);
561 }
562
563
564 /* ********************************************************* */
565
566 typedef struct RGBA
567 {
568         float r;
569         float g;
570         float b;
571         float a;
572 } RGBA;
573
574
575 static void exr_print_filecontents(InputFile *file)
576 {
577         const ChannelList &channels = file->header().channels();
578         
579         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
580         {
581                 const Channel &channel = i.channel();
582                 printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
583         }
584 }
585
586 static int exr_has_zbuffer(InputFile *file)
587 {
588         const ChannelList &channels = file->header().channels();
589         
590         for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
591         {
592                 const Channel &channel = i.channel();
593                 if(strcmp("Z", i.name())==0)
594                         return 1;
595         }
596         return 0;
597 }
598
599 static int exr_is_renderresult(InputFile *file)
600 {
601         const StringAttribute *comments= file->header().findTypedAttribute<StringAttribute>("comments");
602         if(comments)
603                 if(comments->value() == "Blender MultiChannel")
604                         return 1;
605         return 0;
606 }
607
608 struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags)
609 {
610         struct ImBuf *ibuf = NULL;
611         InputFile *file = NULL;
612         
613         if (imb_is_a_openexr(mem) == 0) return(NULL);
614         
615         try
616         {
617                 Mem_IStream membuf(mem, size); 
618                 file = new InputFile(membuf);
619                 
620                 Box2i dw = file->header().dataWindow();
621                 int width  = dw.max.x - dw.min.x + 1;
622                 int height = dw.max.y - dw.min.y + 1;
623                 
624                 //printf("OpenEXR-load: image data window %d %d %d %d\n", 
625                 //         dw.min.x, dw.min.y, dw.max.x, dw.max.y);
626
627                 //exr_print_filecontents(file);
628                 int flipped= exr_is_renderresult(file);
629                 
630                 ibuf = IMB_allocImBuf(width, height, 32, 0, 0);
631                 
632                 if (ibuf) 
633                 {
634                         ibuf->ftype = OPENEXR;
635                         
636                         if (!(flags & IB_test))
637                         {
638                                 FrameBuffer frameBuffer;
639                                 float *first;
640                                 int xstride = sizeof(float) * 4;
641                                 int ystride = flipped ? xstride*width : - xstride*width;
642                                 
643                                 imb_addrectfloatImBuf(ibuf);
644                                 
645                                 /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */
646                                 first= ibuf->rect_float - 4*(dw.min.x - dw.min.y*width);
647                                 /* but, since we read y-flipped (negative y stride) we move to last scanline */
648                                 if(!flipped) first+= 4*(height-1)*width;
649                                 
650                                 frameBuffer.insert ("R", Slice (FLOAT,  (char *) first, xstride, ystride));
651                                 frameBuffer.insert ("G", Slice (FLOAT,  (char *) (first+1), xstride, ystride));
652                                 frameBuffer.insert ("B", Slice (FLOAT,  (char *) (first+2), xstride, ystride));
653                                                                                                                                                 /* 1.0 is fill value */
654                                 frameBuffer.insert ("A", Slice (FLOAT,  (char *) (first+3), xstride, ystride, 1, 1, 1.0f));
655
656                                 if(exr_has_zbuffer(file)) 
657                                 {
658                                         float *firstz;
659                                         
660                                         addzbuffloatImBuf(ibuf);
661                                         firstz= ibuf->zbuf_float - (dw.min.x - dw.min.y*width);
662                                         if(!flipped) firstz+= (height-1)*width;
663                                         frameBuffer.insert ("Z", Slice (FLOAT,  (char *)firstz , sizeof(float), -width*sizeof(float)));
664                                 }
665                                 
666                                 file->setFrameBuffer (frameBuffer);
667                                 file->readPixels (dw.min.y, dw.max.y);
668                                 
669                                 IMB_rect_from_float(ibuf);
670                         }
671                 }
672                 
673                 delete file;
674                 
675                 return(ibuf);
676                                 
677         }
678         catch (const std::exception &exc)
679         {
680                 std::cerr << exc.what() << std::endl;
681                 if (ibuf) IMB_freeImBuf(ibuf);
682                 
683                 return (0);
684         }
685         
686 }
687
688
689 } // export "C"