root/OpenSceneGraph/trunk/src/osgPlugins/exr/ReaderWriterEXR.cpp @ 12292

Revision 12292, 11.4 kB (checked in by robert, 3 years ago)

Ran svn propset -R svn:eol-style native . on the OpenSceneGraph

  • Property svn:eol-style set to native
Line 
1#include <osg/Image>
2#include <osg/Notify>
3#include <osg/Geode>
4#include <osg/Image>
5#include <osg/GL>
6
7#if defined _WIN32 && !defined OSG_LIBRARY_STATIC
8//Make the half format work against openEXR libs
9#define OPENEXR_DLL
10#endif
11
12#include <osgDB/Registry>
13#include <osgDB/FileNameUtils>
14#include <osgDB/FileUtils>
15
16#include <ImfRgbaFile.h>
17#include <ImfIO.h>
18#include <ImfArray.h>
19
20using namespace std;
21using namespace Imf;
22using namespace Imath;
23
24/****************************************************************************
25 *
26 * Follows is code written by FOI (www.foi.se)
27 * it is a wraper of openEXR(www.openexr.com)
28 * to add suport of exr images into osg
29 *
30 * Ported to a OSG-plugin, Ragnar Hammarqvist.
31 * For patches, bugs and new features
32 * please send them direct to the OSG dev team.
33 **********************************************************************/
34class C_IStream: public Imf::IStream
35{
36public:
37    C_IStream (istream *fin) :
38      IStream(""),_inStream(fin){}
39
40      virtual bool    read (char c[/*n*/], int n)
41      {
42        return _inStream->read(c,n).good();
43      };
44      virtual Int64    tellg ()
45      {
46          return _inStream->tellg();
47      };
48      virtual void    seekg (Int64 pos)
49      {
50        _inStream->seekg(pos);
51      };
52      virtual void    clear ()
53      {
54        _inStream->clear();
55      };
56
57private:
58    std::istream * _inStream;
59};
60
61class C_OStream: public Imf::OStream
62{
63public:
64    C_OStream (ostream *fin) :
65      OStream(""),_outStream(fin)
66      {};
67
68      virtual void    write (const char c[/*n*/], int n)
69      {
70        _outStream->write(c,n);
71      };
72      virtual Int64    tellp ()
73      {
74        return _outStream->tellp();
75      };
76      virtual void seekp (Int64 pos)
77      {
78        _outStream->seekp(pos);
79      };
80
81private:
82    std::ostream * _outStream;
83};
84
85
86unsigned char *exr_load(std::istream& fin,
87                        int *width_ret,
88                        int *height_ret,
89                        int *numComponents_ret,
90                        unsigned int *dataType_ret)
91{
92    unsigned char *buffer=NULL; // returned to sender & as read from the disk
93    bool inputError = false;
94    Array2D<Rgba> pixels;
95    int width,height,numComponents;
96   
97    try
98    {   
99        C_IStream inStream(&fin);
100        RgbaInputFile rgbafile(inStream);
101
102        Box2i dw = rgbafile.dataWindow();
103        /*RgbaChannels channels =*/ rgbafile.channels();
104        (*width_ret) = width = dw.max.x - dw.min.x + 1;
105        (*height_ret)=height = dw.max.y - dw.min.y + 1;
106        (*dataType_ret) = GL_HALF_FLOAT_ARB;
107
108        pixels.resizeErase (height, width);
109
110        rgbafile.setFrameBuffer((&pixels)[0][0] - dw.min.x - dw.min.y * width, 1, width);   
111        rgbafile.readPixels(dw.min.y, dw.max.y);
112    }
113    catch( char * str ) {
114        inputError = true;
115    }
116
117    //If error during stream read return a empty pointer
118    if (inputError)
119    {
120        return buffer;
121    }
122   
123    //If there is no information in alpha channel do not store the alpha channel
124    numComponents = 3;
125    for (long i = height-1; i >= 0; i--)
126    {
127        for (long j = 0 ; j < width; j++)
128        {
129            if (pixels[i][j].a != half(1.0f) )
130            {
131                numComponents = 4;
132                break;
133            }
134        }
135    }
136    (*numComponents_ret) = numComponents;
137
138    if (!(    numComponents == 3 ||
139            numComponents == 4))
140    {
141        return NULL;
142    }
143   
144    //Copy and allocate data to a unsigned char array that OSG can use for texturing
145    unsigned dataSize = (sizeof(half) * height * width * numComponents);
146    //buffer = new unsigned char[dataSize];
147    buffer = (unsigned char*)malloc(dataSize);
148    half* pOut = (half*) buffer;
149   
150    for (long i = height-1; i >= 0; i--)
151    {
152        for (long j = 0 ; j < width; j++)
153        {
154            (*pOut) = pixels[i][j].r;
155            pOut++;
156            (*pOut) = pixels[i][j].g;
157            pOut++;
158            (*pOut) = pixels[i][j].b;
159            pOut++;
160            if (numComponents >= 4)
161            {
162                (*pOut) = pixels[i][j].a;
163                pOut++;
164            }
165        }
166    }
167
168    return buffer;
169}
170
171
172 class ReaderWriterEXR : public osgDB::ReaderWriter
173{
174public:
175    ReaderWriterEXR()
176    {
177    }
178
179    virtual bool acceptsExtension(const std::string& extension) const { return osgDB::equalCaseInsensitive(extension,"exr"); }
180   
181    virtual const char* className() const { return "EXR Image Reader"; }
182   
183    virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const
184    {
185        return readImage(fin, options);
186    }
187
188    virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const
189    {
190        return readImage(file, options);
191    }
192
193    virtual ReadResult readImage(std::istream& fin,const Options* =NULL) const
194    {
195        return readEXRStream(fin);
196    }
197
198    virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
199    {
200        std::string ext = osgDB::getLowerCaseFileExtension(file);
201        if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
202
203        std::string fileName = osgDB::findDataFile( file, options );
204        if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
205
206        osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary);
207        if(!istream) return ReadResult::FILE_NOT_HANDLED;
208       
209        ReadResult rr = readEXRStream(istream);
210        if(rr.validImage())
211        {
212            rr.getImage()->setFileName(fileName);
213        }
214        return rr;
215    }
216   
217    virtual WriteResult writeImage(const osg::Image& image,std::ostream& fout,const Options*) const
218    {
219        bool success = writeEXRStream(image, fout, "<output stream>");
220
221        if(success)
222            return WriteResult::FILE_SAVED;
223        else
224            return WriteResult::ERROR_IN_WRITING_FILE;
225    }
226
227    virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options*) const
228     {
229        std::string ext = osgDB::getFileExtension(fileName);
230        if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
231
232        osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
233        if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;
234
235        bool success = writeEXRStream(img, fout, fileName);
236 
237        fout.close();
238
239        if(success)
240            return WriteResult::FILE_SAVED;
241        else
242            return WriteResult::ERROR_IN_WRITING_FILE;
243     }
244protected:
245    bool writeEXRStream(const osg::Image &img, std::ostream& fout, const std::string &fileName) const
246    {
247        bool writeOK = true;
248
249        //Obtain data from texture
250        int width = img.s();
251        int height = img.t();
252        unsigned int pixelFormat = img.getPixelFormat();
253        int numComponents = img.computeNumComponents(pixelFormat);
254        unsigned int dataType = img.getDataType();
255
256        //Validates image data
257        //if numbers of components matches
258        if (!(    numComponents == 3 ||
259                numComponents == 4))
260        {
261            writeOK = false;
262            return false;
263        }
264        if (!(    dataType == GL_HALF_FLOAT_ARB ||
265                dataType == GL_FLOAT))
266        {
267            writeOK = false;
268            return false;
269        }
270
271         //Create a stream to save to
272         C_OStream outStream(&fout);
273
274         //Copy data from texture to rgba pixel format
275        Array2D<Rgba> outPixels(height,width);
276         //If texture is half format
277         if (dataType == GL_HALF_FLOAT_ARB)
278         {   
279             half* pOut = (half*) img.data();
280             for (long i = height-1; i >= 0; i--)
281             {
282                 for (long j = 0 ; j < width; j++)
283                 {
284                     outPixels[i][j].r = (*pOut);
285                     pOut++;
286                     outPixels[i][j].g = (*pOut);
287                     pOut++;
288                     outPixels[i][j].b = (*pOut);
289                     pOut++;
290                    if (numComponents >= 4)
291                    {
292                        outPixels[i][j].a = (*pOut);
293                        pOut++;
294                    }
295                    else{outPixels[i][j].a = 1.0f;}
296                 }
297             }
298         }
299        else if (dataType == GL_FLOAT)
300        {
301            float* pOut = (float*) img.data();
302            for (long i = height-1; i >= 0; i--)
303            {
304                for (long j = 0 ; j < width; j++)
305                {
306                    outPixels[i][j].r = half(*pOut);
307                    pOut++;
308                    outPixels[i][j].g = half(*pOut);
309                    pOut++;
310                    outPixels[i][j].b = half(*pOut);
311                    pOut++;
312                    if (numComponents >= 4)
313                    {
314                        outPixels[i][j].a = half(*pOut);
315                        pOut++;
316                    }
317                    else
318                    {outPixels[i][j].a = 1.0f;}
319                }
320            }       
321        }
322         else
323         {
324             //If texture format not supported
325             return false;
326         }
327 
328         try
329         {
330             //Write to stream
331             Header outHeader(width, height);
332             RgbaOutputFile rgbaFile (outStream, outHeader, WRITE_RGBA);
333             rgbaFile.setFrameBuffer ((&outPixels)[0][0], 1, width);
334             rgbaFile.writePixels (height);
335         }
336         catch( char * str )
337         {
338             writeOK = false;
339         }
340
341
342        return writeOK;
343    }
344
345    ReadResult readEXRStream(std::istream& fin) const
346    {
347        unsigned char *imageData = NULL;
348        int width_ret = 0;
349        int height_ret = 0;
350        int numComponents_ret = 4;
351        unsigned int dataType_ret = GL_UNSIGNED_BYTE;
352        unsigned int pixelFormat = GL_RGB;
353        unsigned int interNalTextureFormat = GL_RGB;
354
355        imageData = exr_load(fin,&width_ret,&height_ret,&numComponents_ret,&dataType_ret);
356
357        if (imageData==NULL)
358            return ReadResult::FILE_NOT_HANDLED;
359
360        int s = width_ret;
361        int t = height_ret;
362        int r = 1;
363
364        if (dataType_ret == GL_HALF_FLOAT_ARB)
365        {
366            interNalTextureFormat =
367                numComponents_ret == 1 ? GL_LUMINANCE16F_ARB :
368                numComponents_ret == 2 ? GL_LUMINANCE_ALPHA16F_ARB :
369                numComponents_ret == 3 ? GL_RGB16F_ARB :
370                numComponents_ret == 4 ? GL_RGBA16F_ARB : (GLenum)-1;
371        }
372        else if (dataType_ret == GL_FLOAT)
373        {
374            interNalTextureFormat =
375                numComponents_ret == 1 ? GL_LUMINANCE32F_ARB :
376                numComponents_ret == 2 ? GL_LUMINANCE_ALPHA32F_ARB :
377                numComponents_ret == 3 ? GL_RGB32F_ARB :
378                numComponents_ret == 4 ? GL_RGBA32F_ARB : (GLenum)-1;
379        }
380        pixelFormat =
381            numComponents_ret == 1 ? GL_LUMINANCE :
382            numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
383            numComponents_ret == 3 ? GL_RGB :
384            numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;
385
386        unsigned int dataType = dataType_ret;
387
388        osg::Image* pOsgImage = new osg::Image;
389        pOsgImage->setImage(s,t,r,
390            interNalTextureFormat,
391            pixelFormat,
392            dataType,
393            imageData,
394            osg::Image::USE_MALLOC_FREE);
395
396        return pOsgImage;
397    }
398};
399
400// now register with Registry to instantiate the exr suport
401// reader/writer.
402REGISTER_OSGPLUGIN(exr, ReaderWriterEXR)
Note: See TracBrowser for help on using the browser.