Orange fix: Lamp ipos were also not duplicated when indicated... old stuff
[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 #include "IMB_imbuf_types.h"
39 #include "IMB_imbuf.h"
40         
41 #include "IMB_allocimbuf.h"
42 }
43
44 #include <iostream>
45
46 #include <OpenEXR/half.h>
47 #include <OpenEXR/ImfVersion.h>
48 #include <OpenEXR/ImathBox.h>
49 #include <OpenEXR/ImfArray.h>
50 #include <OpenEXR/ImfIO.h>
51 #include <OpenEXR/ImfChannelList.h>
52 #include <OpenEXR/ImfPixelType.h>
53 #include <OpenEXR/ImfInputFile.h>
54 #include <OpenEXR/ImfOutputFile.h>
55 #include <OpenEXR/ImfCompression.h>
56 #include <OpenEXR/ImfCompressionAttribute.h>
57
58 using namespace Imf;
59 using namespace Imath;
60
61 class Mem_IStream: public IStream
62 {
63 public:
64         
65         Mem_IStream (unsigned char *exrbuf, int exrsize):
66     IStream("dummy"), _exrpos (0), _exrsize(exrsize)  { _exrbuf = exrbuf; }
67         
68         virtual bool    read (char c[], int n);
69         virtual Int64   tellg ();
70         virtual void    seekg (Int64 pos);
71         virtual void    clear ();
72         //virtual ~Mem_IStream() {}; // unused
73         
74 private:
75                 
76                 Int64 _exrpos;
77         Int64 _exrsize;
78         unsigned char *_exrbuf;
79 };
80
81 bool Mem_IStream::read (char c[], int n)
82 {
83         if (n + _exrpos <= _exrsize)
84     {
85                 memcpy(c, (void *)(&_exrbuf[_exrpos]), n);
86                 _exrpos += n;
87                 return true;
88     }
89         else
90                 return false;
91 }
92
93 Int64 Mem_IStream::tellg ()
94 {
95         return _exrpos;
96 }
97
98 void Mem_IStream::seekg (Int64 pos)
99 {
100         _exrpos = pos;
101 }
102
103 void Mem_IStream::clear () 
104
105 }
106
107 struct _RGBAZ
108 {
109         half r;
110         half g;
111         half b;
112         half a;
113         half z;
114 };
115
116 typedef struct _RGBAZ RGBAZ;
117
118 extern "C"
119 {
120         
121 int imb_is_a_openexr(unsigned char *mem)
122 {
123         return Imf::isImfMagic ((const char *)mem);
124 }
125
126 static void openexr_header_compression(Header *header, int compression)
127 {
128         switch(compression)
129         {
130                 case 0:
131                         header->compression() = NO_COMPRESSION;
132                         break;
133                 case 1:
134                         header->compression() = PXR24_COMPRESSION;
135                         break;
136                 case 2:
137                         header->compression() = ZIP_COMPRESSION;
138                         break;
139                 case 3:
140                         header->compression() = PIZ_COMPRESSION;
141                         break;
142                 case 4:
143                         header->compression() = RLE_COMPRESSION;
144                         break;
145                 default:
146                         header->compression() = NO_COMPRESSION;
147                         break; 
148         }
149 }
150
151 static short imb_save_openexr_half(struct ImBuf *ibuf, char *name, int flags)
152 {
153         
154         int width = ibuf->x;
155         int height = ibuf->y;
156         int write_zbuf = (flags & IB_zbuf) && ibuf->zbuf != NULL;   // summarize
157         
158         try
159         {
160                 Header header (width, height);
161                 
162                 openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
163                 
164                 header.channels().insert ("R", Channel (HALF));
165                 header.channels().insert ("G", Channel (HALF));
166                 header.channels().insert ("B", Channel (HALF));
167                 header.channels().insert ("A", Channel (HALF));
168                 if (write_zbuf)         // z we do as uint always
169                         header.channels().insert ("Z", Channel (UINT));
170                 
171                 FrameBuffer frameBuffer;                        
172                 OutputFile *file = new OutputFile(name, header);                        
173                 
174                 /* we store first everything in half array */
175                 RGBAZ *pixels = new RGBAZ[height * width];
176                 RGBAZ *to = pixels;
177                 int xstride= sizeof (RGBAZ);
178                 int ystride= xstride*width;
179                 
180                 /* indicate used buffers */
181                 frameBuffer.insert ("R", Slice (HALF,  (char *) &pixels[0].r, xstride, ystride));       
182                 frameBuffer.insert ("G", Slice (HALF,  (char *) &pixels[0].g, xstride, ystride));
183                 frameBuffer.insert ("B", Slice (HALF,  (char *) &pixels[0].b, xstride, ystride));
184                 frameBuffer.insert ("A", Slice (HALF, (char *) &pixels[0].a, xstride, ystride));
185         
186                 if (write_zbuf)
187                         frameBuffer.insert ("Z", Slice (UINT, (char *) ibuf->zbuf + 4*(height-1)*width,
188                                                                                         sizeof(int), sizeof(int) * -width));
189                 if(ibuf->rect_float) {
190                         float *from;
191                         
192                         for (int i = ibuf->y-1; i >= 0; i--) 
193                         {
194                                 from= ibuf->rect_float + 4*i*width;
195                                 
196                                 for (int j = ibuf->x; j > 0; j--) 
197                                 {
198                                         to->r = from[0];
199                                         to->g = from[1];
200                                         to->b = from[2];
201                                         to->a = from[3];
202                                         to++; from += 4;
203                                 }
204                         }
205                 }
206                 else {
207                         unsigned char *from;
208                         
209                         for (int i = ibuf->y-1; i >= 0; i--) 
210                         {
211                                 from= (unsigned char *)(ibuf->rect + i*width);
212                                 
213                                 for (int j = ibuf->x; j > 0; j--) 
214                                 {
215                                         to->r = (float)(from[0])/255.0;
216                                         to->g = (float)(from[1])/255.0;
217                                         to->b = (float)(from[2])/255.0;
218                                         to->a = (float)(from[3])/255.0;
219                                         to++; from += 4;
220                                 }
221                         }
222                 }
223                 
224 //              printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
225                 
226                 file->setFrameBuffer (frameBuffer);                               
227                 file->writePixels (height);                                       
228                 delete file;
229         }
230         catch (const std::exception &exc)
231         {      
232                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
233                 if (ibuf) IMB_freeImBuf(ibuf);
234                 
235                 return (0);
236         }
237         
238         return (1);
239 }
240
241 static short imb_save_openexr_float(struct ImBuf *ibuf, char *name, int flags)
242 {
243         
244         int width = ibuf->x;
245         int height = ibuf->y;
246         int write_zbuf = (flags & IB_zbuf) && ibuf->zbuf != NULL;   // summarize
247         
248         try
249         {
250                 Header header (width, height);
251                 
252                 openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
253                 
254                 header.channels().insert ("R", Channel (FLOAT));
255                 header.channels().insert ("G", Channel (FLOAT));
256                 header.channels().insert ("B", Channel (FLOAT));
257                 header.channels().insert ("A", Channel (FLOAT));
258                 if (write_zbuf)
259                         header.channels().insert ("Z", Channel (UINT));
260                 
261                 FrameBuffer frameBuffer;                        
262                 OutputFile *file = new OutputFile(name, header);                        
263                 float *first= ibuf->rect_float + 4*(height-1)*width;
264                 int xstride = sizeof(float) * 4;
265                 int ystride = - xstride*width;
266
267                 frameBuffer.insert ("R", Slice (FLOAT,  (char *) first, xstride, ystride));
268                 frameBuffer.insert ("G", Slice (FLOAT,  (char *) (first+1), xstride, ystride));
269                 frameBuffer.insert ("B", Slice (FLOAT,  (char *) (first+2), xstride, ystride));
270                 frameBuffer.insert ("A", Slice (FLOAT,  (char *) (first+3), xstride, ystride));
271
272                 if (write_zbuf)
273                         frameBuffer.insert ("Z", Slice (UINT, (char *) ibuf->zbuf + 4*(height-1)*width,
274                                                                                         sizeof(int), sizeof(int) * -width));
275                 
276                 file->setFrameBuffer (frameBuffer);                               
277                 file->writePixels (height);                                       
278                 delete file;
279         }
280         catch (const std::exception &exc)
281         {      
282                 printf("OpenEXR-save: ERROR: %s\n", exc.what());
283                 if (ibuf) IMB_freeImBuf(ibuf);
284                 
285                 return (0);
286         }
287         
288         return (1);
289         //      printf("OpenEXR-save: Done.\n");
290 }
291
292
293 short imb_save_openexr(struct ImBuf *ibuf, char *name, int flags)
294 {
295         if (flags & IB_mem) 
296         {
297                 printf("OpenEXR-save: Create EXR in memory CURRENTLY NOT SUPPORTED !\n");
298                 imb_addencodedbufferImBuf(ibuf);
299                 ibuf->encodedsize = 0;    
300                 return(0);
301         } 
302         
303         if (ibuf->ftype & OPENEXR_HALF) 
304                 return imb_save_openexr_half(ibuf, name, flags);
305         else {
306                 /* when no float rect, we save as half (16 bits is sufficient) */
307                 if (ibuf->rect_float==NULL)
308                         return imb_save_openexr_half(ibuf, name, flags);
309                 else
310                         return imb_save_openexr_float(ibuf, name, flags);
311         }
312 }
313
314 struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags)
315 {
316         struct ImBuf *ibuf = 0;
317         InputFile *file = NULL;
318         
319 //      printf("OpenEXR-load: testing input, size is %d\n", size);
320         if (imb_is_a_openexr(mem) == 0) return(NULL);
321         
322         try
323         {
324 //              printf("OpenEXR-load: Creating InputFile from mem source\n");
325                 Mem_IStream membuf(mem, size); 
326                 file = new InputFile(membuf);
327                 
328                 Box2i dw = file->header().dataWindow();
329                 int width  = dw.max.x - dw.min.x + 1;
330                 int height = dw.max.y - dw.min.y + 1;
331                 
332 //              printf("OpenEXR-load: image data window %d %d %d %d\n", 
333 //                         dw.min.x, dw.min.y, dw.max.x, dw.max.y);
334                 
335                 const ChannelList &channels = file->header().channels();
336                 
337                 for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
338                 {
339                         const Channel &channel = i.channel();
340 //                      printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
341                         if (channel.type != 1)
342                         {
343                                 printf("OpenEXR-load: Can only process HALF input !!\n");
344                                 return(NULL);
345                         }
346                 }
347                 
348                 RGBAZ *pixels = new RGBAZ[height * width];
349                 
350                 FrameBuffer frameBuffer;
351                 
352                 frameBuffer.insert ("R",
353                                                         Slice (HALF,
354                                                                    (char *) &pixels[0].r,
355                                                                    sizeof (pixels[0]) * 1,
356                                                                    sizeof (pixels[0]) * width));
357                 
358                 frameBuffer.insert ("G",
359                                                         Slice (HALF,
360                                                                    (char *) &pixels[0].g,
361                                                                    sizeof (pixels[0]) * 1,
362                                                                    sizeof (pixels[0]) * width));
363                 
364                 frameBuffer.insert ("B",
365                                                         Slice (HALF,
366                                                                    (char *) &pixels[0].b,
367                                                                    sizeof (pixels[0]) * 1,
368                                                                    sizeof (pixels[0]) * width));
369                 
370                 frameBuffer.insert ("A",
371                                                         Slice (HALF,
372                                                                    (char *) &pixels[0].a,
373                                                                    sizeof (pixels[0]) * 1,
374                                                                    sizeof (pixels[0]) * width));
375                 
376                 // FIXME ? Would be able to read Z data or other channels here ! 
377                 
378 //              printf("OpenEXR-load: Reading pixel data\n");
379                 file->setFrameBuffer (frameBuffer);
380                 file->readPixels (dw.min.y, dw.max.y);
381                 
382 //              printf("OpenEXR-load: Converting to Blender float ibuf\n");
383                 
384                 int bytesperpixel = 4; // since OpenEXR fills in unknown channels
385                 ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0, 0);
386                 
387                 if (ibuf) 
388                 {
389                         ibuf->ftype = OPENEXR;
390                         
391                         imb_addrectImBuf(ibuf);
392                         imb_addrectfloatImBuf(ibuf);
393                         
394                         if (!(flags & IB_test))
395                         {
396                                 unsigned char *to = (unsigned char *) ibuf->rect;
397                                 float *tof = ibuf->rect_float;
398                                 RGBAZ *from = pixels;
399                                 RGBAZ prescale;
400                                 
401                                 for (int i = ibuf->x * ibuf->y; i > 0; i--) 
402                                 {
403                                         to[0] = (unsigned char)(from->r > 1.0 ? 1.0 : (float)from->r)  * 255;
404                                         to[1] = (unsigned char)(from->g > 1.0 ? 1.0 : (float)from->g)  * 255;
405                                         to[2] = (unsigned char)(from->b > 1.0 ? 1.0 : (float)from->b)  * 255;
406                                         to[3] = (unsigned char)(from->a > 1.0 ? 1.0 : (float)from->a)  * 255;
407                                         to += 4; 
408                                         
409                                         tof[0] = from->r;
410                                         tof[1] = from->g;
411                                         tof[2] = from->b;
412                                         tof[3] = from->a;
413                                         
414                                         from++;
415                                 }
416                         }
417                         
418                         IMB_flipy(ibuf);
419                         
420                 } 
421                 else 
422                         printf("Couldn't allocate memory for OpenEXR image\n");
423                 
424 //              printf("OpenEXR-load: Done\n");
425                 
426                 return(ibuf);
427         }
428         catch (const std::exception &exc)
429         {
430                 std::cerr << exc.what() << std::endl;
431                 if (ibuf) IMB_freeImBuf(ibuf);
432                 
433                 return (0);
434         }
435         
436 }
437
438
439 } // export "C"