~ubuntu-branches/ubuntu/maverick/blender/maverick

« back to all changes in this revision

Viewing changes to extern/qdune/imgio/exr_io.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Khashayar Naderehvandi, Khashayar Naderehvandi, Alessio Treglia
  • Date: 2009-01-22 16:53:59 UTC
  • mfrom: (14.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20090122165359-v0996tn7fbit64ni
Tags: 2.48a+dfsg-1ubuntu1
[ Khashayar Naderehvandi ]
* Merge from debian experimental (LP: #320045), Ubuntu remaining changes:
  - Add patch correcting header file locations.
  - Add libvorbis-dev and libgsm1-dev to Build-Depends.
  - Use avcodec_decode_audio2() in source/blender/src/hddaudio.c

[ Alessio Treglia ]
* Add missing previous changelog entries.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
///-----------------------------------------
2
 
///  OpenEXR file read & write
3
 
///-----------------------------------------
4
 
 
5
 
#include "exr_io.h"
6
 
 
7
 
#include <ImfTiledOutputFile.h>
8
 
#include <ImfChannelList.h>
9
 
#include <ImfMatrixAttribute.h>
10
 
#include <ImfIntAttribute.h>
11
 
#include <ImfBoxAttribute.h>
12
 
// for rgba image loader
13
 
#include <ImfRgbaFile.h>
14
 
#include <ImfArray.h>
15
 
// same, using general interface
16
 
#include <ImfInputFile.h>
17
 
 
18
 
#include <iostream>
19
 
 
20
 
using namespace std;
21
 
using namespace Imf;
22
 
using namespace Imath;
23
 
 
24
 
__BEGIN_QDRENDER
25
 
 
26
 
// fixed tilesize value for now, but probably will leave it like that anyway, seems good average value
27
 
// WARNING, duplicate! also defined in maketexture.cpp
28
 
#define TILESIZE 64
29
 
void writeTiledZ(const char fileName[], float* Zbuf, int width, int height,
30
 
                 int ortho, const float w2c[4][4], const float c2r[4][4])
31
 
{
32
 
        try
33
 
        {
34
 
                Header header(width, height);
35
 
                // default zip is best probably, lossles too, pxr24 is possible (though lossy) alternative, seems to work well for Z
36
 
                //header.compression() = PXR24_COMPRESSION;
37
 
                //header.compression() = NO_COMPRESSION;
38
 
                header.channels().insert("Z", Channel(FLOAT));
39
 
                header.setTileDescription(TileDescription(TILESIZE, TILESIZE, ONE_LEVEL));
40
 
                // this is used as ID, value not used, text itself is the id
41
 
                header.insert("QD_shadowmap", IntAttribute(0));
42
 
                header.insert("w2c", M44fAttribute(M44f(w2c)));
43
 
                header.insert("c2r", M44fAttribute(M44f(c2r)));
44
 
                header.insert("ortho", IntAttribute(ortho));
45
 
                TiledOutputFile out(fileName, header);
46
 
                FrameBuffer frameBuffer;
47
 
                frameBuffer.insert("Z", Slice(FLOAT, (char*)Zbuf, sizeof(float), sizeof(float)*width));
48
 
                out.setFrameBuffer(frameBuffer);
49
 
                for (int tileY=0; tileY<out.numYTiles(); ++tileY)
50
 
                        for (int tileX=0; tileX<out.numXTiles(); ++tileX)
51
 
                                out.writeTile(tileX, tileY);
52
 
        }
53
 
        catch (const std::exception &exc)
54
 
        {
55
 
                cout << "writeTiledZ() -> " << exc.what() << endl;
56
 
        }
57
 
}
58
 
#undef TILESIZE
59
 
 
60
 
float* readTiledZ(const char fileName[], int& width, int& height,
61
 
                  int& ortho, float w2c[4][4], float c2r[4][4])
62
 
{
63
 
        float* zmap = NULL;
64
 
        try
65
 
        {
66
 
                TiledInputFile in(fileName);
67
 
                const Header& h = in.header();
68
 
                const M44fAttribute& ma1 = h.typedAttribute<M44fAttribute>("w2c").value();
69
 
                const M44fAttribute& ma2 = h.typedAttribute<M44fAttribute>("c2r").value();
70
 
                const IntAttribute& ia1 = h.typedAttribute<IntAttribute>("ortho").value();
71
 
                memcpy(w2c, &(ma1.value()[0][0]), sizeof(float)*16);
72
 
                memcpy(c2r, &(ma2.value()[0][0]), sizeof(float)*16);
73
 
                ortho = ia1.value();
74
 
                const Box2i dw = h.dataWindow();
75
 
                width =  dw.max.x - dw.min.x + 1;
76
 
                height = dw.max.y - dw.min.y + 1;
77
 
                const int dx = dw.min.x, dy = dw.min.y;
78
 
                zmap = new float[width*height];
79
 
                FrameBuffer frameBuffer;
80
 
                frameBuffer.insert("Z", Slice(FLOAT, (char*)&zmap[-dy*width - dx], sizeof(float), sizeof(float)*width));
81
 
                in.setFrameBuffer(frameBuffer);
82
 
                for (int tileY=0; tileY<in.numYTiles(); ++tileY)
83
 
                        for (int tileX=0; tileX<in.numXTiles(); ++tileX)
84
 
                                in.readTile(tileX, tileY);
85
 
                return zmap;
86
 
        }
87
 
        catch (const std::exception &exc)
88
 
        {
89
 
                cout << "readTiledZ() -> " << exc.what() << endl;
90
 
                if (zmap) { delete[] zmap;  zmap = NULL; }
91
 
                width = height = 0;
92
 
                return NULL;
93
 
        }
94
 
}
95
 
 
96
 
//----------------------------------------------------------------------------------------------------------------
97
 
// EXRbuf_t
98
 
 
99
 
// yet another stupid error was here, used TILESIZE in the loading routines,
100
 
// but of course the image does not have necessarily that tilesize, must get from file
101
 
EXRbuf_t::EXRbuf_t(const char fname[]) : in(NULL), tmp_tile(NULL), tdsize(0), numchan(0), have_alpha(false)
102
 
{
103
 
        try
104
 
        {
105
 
                in = new TiledInputFile(fname);
106
 
                const Header& h = in->header();
107
 
                if (h.findTypedAttribute<IntAttribute>("QD_shadowmap")) {
108
 
                        // regular shadowmap, Z only
109
 
                        const M44fAttribute& ma1 = h.typedAttribute<M44fAttribute>("w2c").value();
110
 
                        memcpy(w2c, &(ma1.value()[0][0]), sizeof(float)*16);
111
 
                        const M44fAttribute& ma2 = h.typedAttribute<M44fAttribute>("c2r").value();
112
 
                        memcpy(c2r, &(ma2.value()[0][0]), sizeof(float)*16);
113
 
                        const IntAttribute& ia1 = h.typedAttribute<IntAttribute>("ortho").value();
114
 
                        ortho = ia1.value();
115
 
                        imgtype = IT_SHADOWMAP;
116
 
                        dttype = IT_FLOAT;
117
 
                        numchan = 1;
118
 
                        // no temporary tile needed in this case
119
 
                }
120
 
                else {
121
 
                        // must be texmap, value not used, just here to trigger exception if not found
122
 
                        h.typedAttribute<IntAttribute>("QD_texturemap");
123
 
                        imgtype = IT_TEXTUREMAP;
124
 
                        const Channel* Ychan = in->header().channels().findChannel("Y");
125
 
                        // get image data type
126
 
                        PixelType tp;
127
 
                        if (Ychan) {
128
 
                                tp = Ychan->type;
129
 
                                numchan = 1;
130
 
                        }
131
 
                        else {
132
 
                                const Channel* rchan = in->header().channels().findChannel("R");
133
 
                                if ((rchan == NULL) || (in->header().channels().findChannel("G") == NULL) || (in->header().channels().findChannel("B") == NULL))
134
 
                                        throw Iex::InputExc("Image has some or all required RGB channels missing?");
135
 
                                tp = rchan->type;
136
 
                                have_alpha = (in->header().channels().findChannel("A") != NULL);
137
 
                                numchan += have_alpha ? 4 : 3;
138
 
                        }
139
 
                        const int tilesize = in->tileXSize() * in->tileYSize() * numchan;
140
 
                        if (tp == UINT) {
141
 
                                dttype = IT_UINT;
142
 
                                tmp_tile = new unsigned int [tilesize];
143
 
                        }
144
 
                        else if (tp == HALF) {
145
 
                                dttype = IT_HALF;
146
 
                                tmp_tile = new half [tilesize];
147
 
                        }
148
 
                        else if (tp == FLOAT) {
149
 
                                dttype = IT_FLOAT;
150
 
                                tmp_tile = new float [tilesize];
151
 
                        }
152
 
                        else    // unless a new type gets added, this should never happen
153
 
                                throw Iex::InputExc("EXRbuf_t() -> Unknown image data type?");
154
 
                }
155
 
        }
156
 
        catch (const std::exception &exc)
157
 
        {
158
 
                cout << "EXRbuf_t() -> " << exc.what() << endl;
159
 
                delete in;
160
 
                in = NULL;
161
 
        }
162
 
}
163
 
 
164
 
EXRbuf_t::~EXRbuf_t()
165
 
{
166
 
        if (in) { delete in;  in = NULL; }
167
 
        if (tmp_tile) { delete[] (int*)tmp_tile;  tmp_tile = NULL; }    // cast only to make compiler happy (delete void undefined)
168
 
}
169
 
 
170
 
template<typename cpptype, PixelType exrtype>
171
 
bool getTile(TiledInputFile* in, const tileID_t& tileID,
172
 
        cpptype* Rtile, cpptype* Gtile, cpptype *Btile, cpptype* Atile,
173
 
        cpptype* Ztile = NULL, cpptype* Ytile = NULL)
174
 
{
175
 
        try
176
 
        {
177
 
                const Box2i b = in->dataWindowForTile(tileID.tileX, tileID.tileY, tileID.levelX, tileID.levelY);
178
 
                FrameBuffer fb;
179
 
                const int tx = in->tileXSize(), p = -b.min.y*tx - b.min.x;      // must be int, negative offset possible
180
 
                if (Rtile) fb.insert("R", Slice(exrtype, (char*)&Rtile[p], sizeof( cpptype ), sizeof( cpptype )*tx));
181
 
                if (Btile) fb.insert("G", Slice(exrtype, (char*)&Gtile[p], sizeof( cpptype ), sizeof( cpptype )*tx));
182
 
                if (Gtile) fb.insert("B", Slice(exrtype, (char*)&Btile[p], sizeof( cpptype ), sizeof( cpptype )*tx));
183
 
                if (Atile) fb.insert("A", Slice(exrtype, (char*)&Atile[p], sizeof( cpptype ), sizeof( cpptype )*tx));
184
 
                if (Ztile) fb.insert("Z", Slice(exrtype, (char*)&Ztile[p], sizeof( cpptype ), sizeof( cpptype )*tx));
185
 
                if (Ytile) fb.insert("Y", Slice(exrtype, (char*)&Ytile[p], sizeof( cpptype ), sizeof( cpptype )*tx));
186
 
                in->setFrameBuffer(fb);
187
 
                in->readTile(tileID.tileX, tileID.tileY, tileID.levelX, tileID.levelY);
188
 
        }
189
 
        catch (const std::exception &exc)
190
 
        {
191
 
                cout << "getTile<>() -> " << exc.what() << endl;
192
 
                return false;
193
 
        }
194
 
        return true;
195
 
}
196
 
 
197
 
 
198
 
// Currently this converts the exr data to interleaved form,
199
 
// so it uses an intermediate tile, copying data, which is all completely unnecessary overhead.
200
 
// It really should be simplified to either save the tiles in the required interleaved format
201
 
// (which as far as I know is possible, but would not be compatible anymore with exrmaketiled)
202
 
// or let the texture cache code handle it all when a color is requested, which probably is best TODO
203
 
RtColor* EXRbuf_t::getColorTile(const tileID_t& tileID) const
204
 
{
205
 
        if (in) {
206
 
                const int tx = in->tileXSize(), ty = in->tileYSize();
207
 
                const unsigned int colofs = tx*ty;
208
 
                tdsize = colofs*sizeof(RtColor);        // tile data size in bytes
209
 
                if (dttype == IT_UINT) {
210
 
                        unsigned int* icoltile = reinterpret_cast<unsigned int*>(tmp_tile);
211
 
                        RtColor* coltile = NULL;
212
 
                        if (getTile<unsigned int, UINT>(in, tileID, icoltile, icoltile + colofs,
213
 
                                                        icoltile + colofs*2, (have_alpha ? (icoltile + colofs*3) : NULL)))
214
 
                        {
215
 
                                // UINT -> RtColor
216
 
                                const float c2f = 1.f/255.f;
217
 
                                coltile = new RtColor[colofs];
218
 
                                for (unsigned int i=0; i<colofs; ++i)
219
 
                                        coltile[i][0] = c2f*icoltile[i], coltile[i][1] = c2f*icoltile[i + colofs], coltile[i][2] = c2f*icoltile[i + colofs*2];
220
 
                        }
221
 
                        return coltile;
222
 
                }
223
 
                else if (dttype == IT_HALF) {
224
 
                        half* hcoltile = reinterpret_cast<half*>(tmp_tile);
225
 
                        RtColor* coltile = NULL;
226
 
                        if (getTile<half, HALF>(in, tileID, hcoltile, hcoltile + colofs,
227
 
                                                hcoltile + colofs*2, (have_alpha ? (hcoltile + colofs*3) : NULL)))
228
 
                        {
229
 
                                // half r/g/b/a -> RtColor
230
 
                                coltile = new RtColor[colofs];
231
 
                                for (unsigned int i=0; i<colofs; ++i)
232
 
                                        coltile[i][0] = hcoltile[i], coltile[i][1] = hcoltile[i + colofs], coltile[i][2] = hcoltile[i + colofs*2];
233
 
                        }
234
 
                        return coltile;
235
 
                }
236
 
                else {  // float
237
 
                        float* fcoltile = reinterpret_cast<float*>(tmp_tile);
238
 
                        RtColor* coltile = NULL;
239
 
                        if (getTile<float, FLOAT>(in, tileID, fcoltile, fcoltile + colofs,
240
 
                                                  fcoltile + colofs*2, (have_alpha ? (fcoltile + colofs*3) : NULL)))
241
 
                        {
242
 
                                // float r/g/b/a -> RtColor
243
 
                                coltile = new RtColor[colofs];
244
 
                                for (unsigned int i=0; i<colofs; ++i)
245
 
                                        coltile[i][0] = fcoltile[i], coltile[i][1] = fcoltile[i + colofs], coltile[i][2] = fcoltile[i + colofs*2];
246
 
                        }
247
 
                        return coltile;
248
 
                }
249
 
        }
250
 
        return NULL;
251
 
}
252
 
 
253
 
 
254
 
// used for Z depth shadowmap or Y grayscale displacementmap
255
 
float* EXRbuf_t::getFloatTile(const tileID_t& tileID) const
256
 
{
257
 
        if (in && ((imgtype == IT_SHADOWMAP) || (numchan == 1))) {
258
 
                const unsigned int tilesize = in->tileXSize() * in->tileYSize();
259
 
                tdsize = tilesize*sizeof(float);        // tile data size in bytes
260
 
                float* Ftile = new float[tilesize];
261
 
                if (imgtype == IT_SHADOWMAP)    // Z
262
 
                        getTile<float, FLOAT>(in, tileID, NULL, NULL, NULL, NULL, Ftile);
263
 
                else    // probably single channel luminance (possibly displacementmap)
264
 
                        getTile<float, FLOAT>(in, tileID, NULL, NULL, NULL, NULL, NULL, Ftile);
265
 
                return Ftile;
266
 
        }
267
 
        return NULL;
268
 
}
269
 
 
270
 
inline void* makeTmpBuf(PixelType pt, unsigned int sz, unsigned int& tpsize)
271
 
{
272
 
        switch (pt) {
273
 
                case UINT:
274
 
                        tpsize = sizeof(unsigned int);
275
 
                        return new unsigned int[sz];
276
 
                case HALF:
277
 
                        tpsize = sizeof(half);
278
 
                        return new half[sz];
279
 
                default:
280
 
                case FLOAT:
281
 
                        tpsize = sizeof(float);
282
 
                        return new float[sz];
283
 
        }
284
 
}
285
 
 
286
 
imgbuf_t* loadEXR(const char filename[], bool force_grayscale)
287
 
{
288
 
        try
289
 
        {
290
 
                InputFile file(filename);
291
 
                Box2i dw = file.header().dataWindow();
292
 
                const int width = dw.max.x - dw.min.x + 1;
293
 
                const int height = dw.max.y - dw.min.y + 1;
294
 
                const unsigned int sz = width*height;
295
 
                const ChannelList &chans = file.header().channels();
296
 
                const Channel* Ychan = chans.findChannel("Y");
297
 
                if (Ychan) {
298
 
                        // assume luminance channel only (strangely, channellist does not seem to have a size() type of function ??)
299
 
                        unsigned int tpsize;
300
 
                        void* tmpbuf = makeTmpBuf(Ychan->type, sz, tpsize);
301
 
                        FrameBuffer fb;
302
 
                        fb.insert("Y", Slice(Ychan->type, (char*)tmpbuf - (dw.min.x - dw.min.y*width)*tpsize, tpsize, tpsize*width));
303
 
                        file.setFrameBuffer(fb);
304
 
                        file.readPixels(dw.min.y, dw.max.y);
305
 
                        // convert
306
 
                        imgbuf_t* img = new imgbuf_t(width, height, 1, (Ychan->type == UINT) ? IMG_BYTE : IMG_FLOAT);
307
 
                        if (Ychan->type == HALF) {
308
 
                                half* tbufp = reinterpret_cast<half*>(tmpbuf);
309
 
                                float* fbufp = reinterpret_cast<float*>(img->getData());
310
 
                                for (unsigned int i=0; i<sz; ++i)
311
 
                                        *fbufp++ = *tbufp++;
312
 
                        }
313
 
                        else if (Ychan->type == UINT) { // assume uint in range of char
314
 
                                unsigned int* tbufp = reinterpret_cast<unsigned int*>(tmpbuf);
315
 
                                unsigned char* cbufp = reinterpret_cast<unsigned char*>(img->getData());
316
 
                                for (unsigned int i=0; i<sz; ++i)
317
 
                                        *cbufp++ = (unsigned char)*tbufp++;
318
 
                        }
319
 
                        else    // float
320
 
                                memcpy(img->getData(), tmpbuf, sizeof(float)*sz);
321
 
                        delete[] (unsigned long*)tmpbuf;        // cast only needed to make compiler happy
322
 
                        return img;
323
 
                }
324
 
                // RGB[A]
325
 
                const Channel* Rchan = chans.findChannel("R");
326
 
                const Channel* Gchan = chans.findChannel("G");
327
 
                const Channel* Bchan = chans.findChannel("B");
328
 
                const Channel* Achan = chans.findChannel("A");
329
 
                if ((Rchan == NULL) || (Gchan == NULL) || (Bchan == NULL))
330
 
                        throw Iex::InputExc("Image must have at least all RGB color channels!");
331
 
                // all channels must be the same pixeltype
332
 
                if ((Rchan->type != Gchan->type) || (Rchan->type != Bchan->type) || (Achan ? (Rchan->type != Achan->type) : false))
333
 
                        throw Iex::InputExc("All image channels must be of the same type!");
334
 
                unsigned int tpsize;
335
 
                void *Gtmpbuf = NULL, *Btmpbuf = NULL, *Atmpbuf = NULL;
336
 
                void* Rtmpbuf = makeTmpBuf(Rchan->type, sz, tpsize);
337
 
                if (!force_grayscale) {
338
 
                        Gtmpbuf = makeTmpBuf(Gchan->type, sz, tpsize);
339
 
                        Btmpbuf = makeTmpBuf(Bchan->type, sz, tpsize);
340
 
                        Atmpbuf = Achan ? makeTmpBuf(Achan->type, sz, tpsize) : NULL;
341
 
                }
342
 
                FrameBuffer fb;
343
 
                fb.insert("R", Slice(Rchan->type, (char*)Rtmpbuf - (dw.min.x - dw.min.y*width)*tpsize, tpsize, tpsize*width));
344
 
                if (!force_grayscale) {
345
 
                        fb.insert("G", Slice(Gchan->type, (char*)Gtmpbuf - (dw.min.x - dw.min.y*width)*tpsize, tpsize, tpsize*width));
346
 
                        fb.insert("B", Slice(Bchan->type, (char*)Btmpbuf - (dw.min.x - dw.min.y*width)*tpsize, tpsize, tpsize*width));
347
 
                        if (Achan)
348
 
                                fb.insert("A", Slice(Achan->type, (char*)Atmpbuf - (dw.min.x - dw.min.y*width)*tpsize, tpsize, tpsize*width));
349
 
                }
350
 
                file.setFrameBuffer(fb);
351
 
                file.readPixels(dw.min.y, dw.max.y);
352
 
                // convert
353
 
                imgbuf_t* img = new imgbuf_t(width, height, (force_grayscale ? 1 : (Achan ? 4 : 3)), (Rchan->type == UINT) ? IMG_BYTE : IMG_FLOAT);
354
 
                if (Rchan->type == HALF) {
355
 
                        half *Gtbufp = NULL, *Btbufp = NULL, *Atbufp = NULL;
356
 
                        half* Rtbufp = reinterpret_cast<half*>(Rtmpbuf);
357
 
                        if (!force_grayscale) {
358
 
                                Gtbufp = reinterpret_cast<half*>(Gtmpbuf);
359
 
                                Btbufp = reinterpret_cast<half*>(Btmpbuf);
360
 
                                Atbufp = Atmpbuf ? NULL : reinterpret_cast<half*>(Atmpbuf);
361
 
                        }
362
 
                        float* fbufp = reinterpret_cast<float*>(img->getData());
363
 
                        for (unsigned int i=0; i<sz; ++i) {
364
 
                                *fbufp++ = *Rtbufp++;
365
 
                                if (!force_grayscale) {
366
 
                                        *fbufp++ = *Gtbufp++;
367
 
                                        *fbufp++ = *Btbufp++;
368
 
                                        if (Atbufp) *fbufp++ = *Atbufp++;
369
 
                                }
370
 
                        }
371
 
                }
372
 
                else if (Rchan->type == UINT) { // assume uint in range of char
373
 
                        unsigned int *Gtbufp = NULL, *Btbufp = NULL, *Atbufp = NULL;
374
 
                        unsigned int* Rtbufp = reinterpret_cast<unsigned int*>(Rtmpbuf);
375
 
                        if (!force_grayscale) {
376
 
                                Gtbufp = reinterpret_cast<unsigned int*>(Gtmpbuf);
377
 
                                Btbufp = reinterpret_cast<unsigned int*>(Btmpbuf);
378
 
                                Atbufp = Atmpbuf ? reinterpret_cast<unsigned int*>(Atmpbuf) : NULL;
379
 
                        }
380
 
                        unsigned char* cbufp = reinterpret_cast<unsigned char*>(img->getData());
381
 
                        for (unsigned int i=0; i<sz; ++i) {
382
 
                                *cbufp++ = (unsigned char)*Rtbufp++;
383
 
                                if (!force_grayscale) {
384
 
                                        *cbufp++ = (unsigned char)*Gtbufp++;
385
 
                                        *cbufp++ = (unsigned char)*Btbufp++;
386
 
                                        if (Atbufp) *cbufp++ = (unsigned char)*Atbufp++;
387
 
                                }
388
 
                        }
389
 
                }
390
 
                else {  // float
391
 
                        float *Gtbufp = NULL, *Btbufp = NULL, *Atbufp = NULL;
392
 
                        float* Rtbufp = reinterpret_cast<float*>(Rtmpbuf);
393
 
                        if (!force_grayscale) {
394
 
                                Gtbufp = reinterpret_cast<float*>(Gtmpbuf);
395
 
                                Btbufp = reinterpret_cast<float*>(Btmpbuf);
396
 
                                Atbufp = Atmpbuf ? NULL : reinterpret_cast<float*>(Atmpbuf);
397
 
                        }
398
 
                        float* fbufp = reinterpret_cast<float*>(img->getData());
399
 
                        for (unsigned int i=0; i<sz; ++i) {
400
 
                                *fbufp++ = *Rtbufp++;
401
 
                                if (!force_grayscale) {
402
 
                                        *fbufp++ = *Gtbufp++;
403
 
                                        *fbufp++ = *Btbufp++;
404
 
                                        if (Atbufp) *fbufp++ = *Atbufp++;
405
 
                                }
406
 
                        }
407
 
                }
408
 
                delete[] (unsigned long*)Rtmpbuf;
409
 
                if (Gtmpbuf) delete[] (unsigned long*)Gtmpbuf;
410
 
                if (Btmpbuf) delete[] (unsigned long*)Btmpbuf;
411
 
                if (Atmpbuf) delete[] (unsigned long*)Atmpbuf;
412
 
                return img;
413
 
        }
414
 
        catch (const exception &exc)
415
 
        {
416
 
                cerr << "[ERROR] -> loadEXR(): " << exc.what() << endl;
417
 
                return NULL;
418
 
        }
419
 
}
420
 
 
421
 
__END_QDRENDER