From Ragnar Hammarqvist, "I wrote an EXR image plug-in to osg, I would like to contribute this plug-in to the osg project if you find it useful.
The plug-in is a wrapper around open-exr (http://www.openexr.com) that consists of two projects, ilmbase-1.0.1 and openexr-1.6.1. I have only tested it on windows XP 32 machine. So there might be some work making it work on other platforms. The plug-in supports writing and reading EXR files. When writing it can use the data type GL_HALF_FLOAT_ARB(se ilmbase-1.0.1) and GL_FLOAT. When reading the data type always becomes GL_HALF_FLOAT_ARB. It supports textures with three and four channels. When reading an exr file it automatically removes Alfa channel if it didn't store any information." -- From Robert Osfield, started work on ported it to other platforms, but could fix some problems relating to error: ?Imf::OStream::OStream(const Imf::OStream&)? is private I'm checking in now so that others can have a bash at completing the port.
This commit is contained in:
parent
e02ae68aa9
commit
51fee6f75c
@ -86,6 +86,9 @@ ENDIF(JPEG_FOUND)
|
||||
IF(JASPER_FOUND)
|
||||
ADD_SUBDIRECTORY(jp2)
|
||||
ENDIF(JASPER_FOUND)
|
||||
IF(OPENEXR_FOUND)
|
||||
# ADD_SUBDIRECTORY(exr)
|
||||
ENDIF(OPENEXR_FOUND)
|
||||
IF(GIFLIB_FOUND)
|
||||
ADD_SUBDIRECTORY(gif)
|
||||
ENDIF(GIFLIB_FOUND)
|
||||
|
8
src/osgPlugins/exr/CMakeLists.txt
Normal file
8
src/osgPlugins/exr/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
INCLUDE_DIRECTORIES( ${OPENEXR_INCLUDE_DIR}/OpenEXR )
|
||||
|
||||
SET(TARGET_SRC ReaderWriterEXR.cpp )
|
||||
|
||||
SET(TARGET_LIBRARIES_VARS OPENEXR_LIBRARY )
|
||||
|
||||
#### end var setup ###
|
||||
SETUP_PLUGIN(exr)
|
403
src/osgPlugins/exr/ReaderWriterEXR.cpp
Normal file
403
src/osgPlugins/exr/ReaderWriterEXR.cpp
Normal file
@ -0,0 +1,403 @@
|
||||
#include <osg/Image>
|
||||
#include <osg/Notify>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Image>
|
||||
#include <osg/GL>
|
||||
|
||||
//Make the half format work against openEXR libs
|
||||
// #define OPENEXR_DLL
|
||||
|
||||
#include <osgDB/Registry>
|
||||
#include <osgDB/FileNameUtils>
|
||||
#include <osgDB/FileUtils>
|
||||
|
||||
#include <ImfRgbaFile.h>
|
||||
#include <ImfIO.h>
|
||||
#include <ImfArray.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace Imf;
|
||||
using namespace Imath;
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Follows is code written by FOI (www.foi.se)
|
||||
* it is a wraper of openEXR(www.openexr.com)
|
||||
* to add suport of exr images into osg
|
||||
*
|
||||
* Ported to a OSG-plugin, Ragnar Hammarqvist.
|
||||
* For patches, bugs and new features
|
||||
* please send them direct to the OSG dev team.
|
||||
**********************************************************************/
|
||||
class C_IStream: public Imf::IStream
|
||||
{
|
||||
public:
|
||||
C_IStream (istream *fin) :
|
||||
IStream(""),_inStream(fin){}
|
||||
|
||||
virtual bool read (char c[/*n*/], int n)
|
||||
{
|
||||
return _inStream->read(c,n).good();
|
||||
};
|
||||
virtual Int64 tellg ()
|
||||
{
|
||||
return _inStream->tellg();
|
||||
};
|
||||
virtual void seekg (Int64 pos)
|
||||
{
|
||||
_inStream->seekg(pos);
|
||||
};
|
||||
virtual void clear ()
|
||||
{
|
||||
_inStream->clear();
|
||||
};
|
||||
|
||||
private:
|
||||
std::istream * _inStream;
|
||||
};
|
||||
|
||||
class C_OStream: public Imf::OStream
|
||||
{
|
||||
public:
|
||||
C_OStream (ostream *fin) :
|
||||
OStream(""),_outStream(fin)
|
||||
{};
|
||||
|
||||
virtual void write (const char c[/*n*/], int n)
|
||||
{
|
||||
_outStream->write(c,n);
|
||||
};
|
||||
virtual Int64 tellp ()
|
||||
{
|
||||
return _outStream->tellp();
|
||||
};
|
||||
virtual void seekp (Int64 pos)
|
||||
{
|
||||
_outStream->seekp(pos);
|
||||
};
|
||||
|
||||
private:
|
||||
std::ostream * _outStream;
|
||||
};
|
||||
|
||||
|
||||
unsigned char *exr_load(std::istream& fin,
|
||||
int *width_ret,
|
||||
int *height_ret,
|
||||
int *numComponents_ret,
|
||||
unsigned int *dataType_ret)
|
||||
{
|
||||
unsigned char *buffer=NULL; // returned to sender & as read from the disk
|
||||
bool inputError = false;
|
||||
Array2D<Rgba> pixels;
|
||||
int width,height,numComponents;
|
||||
|
||||
try
|
||||
{
|
||||
C_IStream inStream = C_IStream(&fin);
|
||||
RgbaInputFile rgbafile(inStream);
|
||||
|
||||
Box2i dw = rgbafile.dataWindow();
|
||||
RgbaChannels channels = rgbafile.channels();
|
||||
(*width_ret) = width = dw.max.x - dw.min.x + 1;
|
||||
(*height_ret)=height = dw.max.y - dw.min.y + 1;
|
||||
(*dataType_ret) = GL_HALF_FLOAT_ARB;
|
||||
|
||||
pixels.resizeErase (height, width);
|
||||
|
||||
rgbafile.setFrameBuffer((&pixels)[0][0] - dw.min.x - dw.min.y * width, 1, width);
|
||||
rgbafile.readPixels(dw.min.y, dw.max.y);
|
||||
}
|
||||
catch( char * str ) {
|
||||
inputError = true;
|
||||
}
|
||||
|
||||
//If error during stream read return a empty pointer
|
||||
if (inputError)
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//If there is no information in alpha channel do not store the alpha channel
|
||||
numComponents = 3;
|
||||
for (long i = height-1; i >= 0; i--)
|
||||
{
|
||||
for (long j = 0 ; j < width; j++)
|
||||
{
|
||||
if (pixels[i][j].a != half(1.0f) )
|
||||
{
|
||||
numComponents = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
(*numComponents_ret) = numComponents;
|
||||
|
||||
if (!( numComponents == 3 ||
|
||||
numComponents == 4))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Copy and allocate data to a unsigned char array that OSG can use for texturing
|
||||
unsigned dataSize = (sizeof(half) * height * width * numComponents);
|
||||
//buffer = new unsigned char[dataSize];
|
||||
buffer = (unsigned char*)malloc(dataSize);
|
||||
half* pOut = (half*) buffer;
|
||||
|
||||
for (long i = height-1; i >= 0; i--)
|
||||
{
|
||||
for (long j = 0 ; j < width; j++)
|
||||
{
|
||||
(*pOut) = pixels[i][j].r;
|
||||
pOut++;
|
||||
(*pOut) = pixels[i][j].g;
|
||||
pOut++;
|
||||
(*pOut) = pixels[i][j].b;
|
||||
pOut++;
|
||||
if (numComponents >= 4)
|
||||
{
|
||||
(*pOut) = pixels[i][j].a;
|
||||
pOut++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
class ReaderWriterEXR : public osgDB::ReaderWriter
|
||||
{
|
||||
public:
|
||||
ReaderWriterEXR()
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool acceptsExtension(const std::string& extension) const { return osgDB::equalCaseInsensitive(extension,"exr"); }
|
||||
|
||||
virtual const char* className() const { return "EXR Image Reader"; }
|
||||
|
||||
virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const
|
||||
{
|
||||
return readImage(fin, options);
|
||||
}
|
||||
|
||||
virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const
|
||||
{
|
||||
return readImage(file, options);
|
||||
}
|
||||
|
||||
virtual ReadResult readImage(std::istream& fin,const Options* =NULL) const
|
||||
{
|
||||
return readEXRStream(fin);
|
||||
}
|
||||
|
||||
virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
|
||||
{
|
||||
std::string ext = osgDB::getLowerCaseFileExtension(file);
|
||||
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
|
||||
|
||||
std::string fileName = osgDB::findDataFile( file, options );
|
||||
if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
|
||||
|
||||
std::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary);
|
||||
if(!istream) return ReadResult::FILE_NOT_HANDLED;
|
||||
|
||||
ReadResult rr = readEXRStream(istream);
|
||||
if(rr.validImage())
|
||||
{
|
||||
rr.getImage()->setFileName(fileName);
|
||||
}
|
||||
return rr;
|
||||
}
|
||||
|
||||
virtual WriteResult writeImage(const osg::Image& image,std::ostream& fout,const Options*) const
|
||||
{
|
||||
bool success = writeEXRStream(image, fout, "<output stream>");
|
||||
|
||||
if(success)
|
||||
return WriteResult::FILE_SAVED;
|
||||
else
|
||||
return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
}
|
||||
|
||||
virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options*) const
|
||||
{
|
||||
std::string ext = osgDB::getFileExtension(fileName);
|
||||
if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
|
||||
|
||||
std::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
|
||||
if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
|
||||
bool success = writeEXRStream(img, fout, fileName);
|
||||
|
||||
fout.close();
|
||||
|
||||
if(success)
|
||||
return WriteResult::FILE_SAVED;
|
||||
else
|
||||
return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
}
|
||||
protected:
|
||||
bool writeEXRStream(const osg::Image &img, std::ostream& fout, const std::string &fileName) const
|
||||
{
|
||||
bool writeOK = true;
|
||||
|
||||
//Obtain data from texture
|
||||
int width = img.s();
|
||||
int height = img.t();
|
||||
unsigned int intenalTextureFormat = img.getInternalTextureFormat();
|
||||
unsigned int pixelFormat = img.getPixelFormat();
|
||||
int numComponents = img.computeNumComponents(pixelFormat);
|
||||
unsigned int dataType = img.getDataType();
|
||||
|
||||
//Validates image data
|
||||
//if numbers of components matches
|
||||
if (!( numComponents == 3 ||
|
||||
numComponents == 4))
|
||||
{
|
||||
writeOK = false;
|
||||
return false;
|
||||
}
|
||||
if (!( dataType == GL_HALF_FLOAT_ARB ||
|
||||
dataType == GL_FLOAT))
|
||||
{
|
||||
writeOK = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
//Create a stream to save to
|
||||
C_OStream outStream = C_OStream(&fout);
|
||||
|
||||
//Copy data from texture to rgba pixel format
|
||||
Array2D<Rgba> outPixels(height,width);
|
||||
//If texture is half format
|
||||
if (dataType == GL_HALF_FLOAT_ARB)
|
||||
{
|
||||
half* pOut = (half*) img.data();
|
||||
for (long i = height-1; i >= 0; i--)
|
||||
{
|
||||
for (long j = 0 ; j < width; j++)
|
||||
{
|
||||
outPixels[i][j].r = (*pOut);
|
||||
pOut++;
|
||||
outPixels[i][j].g = (*pOut);
|
||||
pOut++;
|
||||
outPixels[i][j].b = (*pOut);
|
||||
pOut++;
|
||||
if (numComponents >= 4)
|
||||
{
|
||||
outPixels[i][j].a = (*pOut);
|
||||
pOut++;
|
||||
}
|
||||
else{outPixels[i][j].a = 1.0f;}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dataType == GL_FLOAT)
|
||||
{
|
||||
float* pOut = (float*) img.data();
|
||||
for (long i = height-1; i >= 0; i--)
|
||||
{
|
||||
for (long j = 0 ; j < width; j++)
|
||||
{
|
||||
outPixels[i][j].r = half(*pOut);
|
||||
pOut++;
|
||||
outPixels[i][j].g = half(*pOut);
|
||||
pOut++;
|
||||
outPixels[i][j].b = half(*pOut);
|
||||
pOut++;
|
||||
if (numComponents >= 4)
|
||||
{
|
||||
outPixels[i][j].a = half(*pOut);
|
||||
pOut++;
|
||||
}
|
||||
else
|
||||
{outPixels[i][j].a = 1.0f;}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//If texture format not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//Write to stream
|
||||
Header outHeader(width, height);
|
||||
RgbaOutputFile rgbaFile (outStream, outHeader, WRITE_RGBA);
|
||||
rgbaFile.setFrameBuffer ((&outPixels)[0][0], 1, width);
|
||||
rgbaFile.writePixels (height);
|
||||
}
|
||||
catch( char * str )
|
||||
{
|
||||
writeOK = false;
|
||||
}
|
||||
|
||||
|
||||
return writeOK;
|
||||
}
|
||||
|
||||
ReadResult readEXRStream(std::istream& fin) const
|
||||
{
|
||||
unsigned char *imageData = NULL;
|
||||
int width_ret = 0;
|
||||
int height_ret = 0;
|
||||
int numComponents_ret = 4;
|
||||
unsigned int dataType_ret = GL_UNSIGNED_BYTE;
|
||||
unsigned int pixelFormat = GL_RGB;
|
||||
unsigned int interNalTextureFormat = GL_RGB;
|
||||
|
||||
imageData = exr_load(fin,&width_ret,&height_ret,&numComponents_ret,&dataType_ret);
|
||||
|
||||
if (imageData==NULL)
|
||||
return ReadResult::FILE_NOT_HANDLED;
|
||||
|
||||
int s = width_ret;
|
||||
int t = height_ret;
|
||||
int r = 1;
|
||||
|
||||
int internalFormat = numComponents_ret;
|
||||
|
||||
if (dataType_ret == GL_HALF_FLOAT_ARB)
|
||||
{
|
||||
interNalTextureFormat =
|
||||
numComponents_ret == 1 ? GL_LUMINANCE16F_ARB :
|
||||
numComponents_ret == 2 ? GL_LUMINANCE_ALPHA16F_ARB :
|
||||
numComponents_ret == 3 ? GL_RGB16F_ARB :
|
||||
numComponents_ret == 4 ? GL_RGBA16F_ARB : (GLenum)-1;
|
||||
}
|
||||
else if (dataType_ret == GL_FLOAT)
|
||||
{
|
||||
interNalTextureFormat =
|
||||
numComponents_ret == 1 ? GL_LUMINANCE32F_ARB :
|
||||
numComponents_ret == 2 ? GL_LUMINANCE_ALPHA32F_ARB :
|
||||
numComponents_ret == 3 ? GL_RGB32F_ARB :
|
||||
numComponents_ret == 4 ? GL_RGBA32F_ARB : (GLenum)-1;
|
||||
}
|
||||
pixelFormat =
|
||||
numComponents_ret == 1 ? GL_LUMINANCE :
|
||||
numComponents_ret == 2 ? GL_LUMINANCE_ALPHA :
|
||||
numComponents_ret == 3 ? GL_RGB :
|
||||
numComponents_ret == 4 ? GL_RGBA : (GLenum)-1;
|
||||
|
||||
unsigned int dataType = dataType_ret;
|
||||
|
||||
osg::Image* pOsgImage = new osg::Image;
|
||||
pOsgImage->setImage(s,t,r,
|
||||
interNalTextureFormat,
|
||||
pixelFormat,
|
||||
dataType,
|
||||
imageData,
|
||||
osg::Image::USE_MALLOC_FREE);
|
||||
|
||||
return pOsgImage;
|
||||
}
|
||||
};
|
||||
|
||||
// now register with Registry to instantiate the exr suport
|
||||
// reader/writer.
|
||||
REGISTER_OSGPLUGIN(exr, ReaderWriterEXR)
|
Loading…
Reference in New Issue
Block a user