Files
OpenSceneGraph/src/osgPlugins/gta/ReaderWriterGTA.cpp
2012-03-21 17:36:20 +00:00

379 lines
14 KiB
C++

#include <osg/Image>
#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <string>
#include <sstream>
#include <limits>
#include <gta/gta.hpp>
/* Copyright (C) 2011 Martin Lambers
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
class ReaderWriterGTA : public osgDB::ReaderWriter
{
public:
ReaderWriterGTA()
{
supportsExtension("gta","GTA (Generic Tagged Arrays) file format");
supportsOption("COMPRESSION","Set compression method: NONE, ZLIB (default), ZLIB1,...,ZLIB9, BZIP2, or XZ");
}
virtual const char* className() const { return "GTA Image Reader"; }
virtual bool acceptsExtension(const std::string& extension) const
{
return osgDB::equalCaseInsensitive(extension,"gta");
}
ReadResult local_readImage(std::istream& fin,const osgDB::ReaderWriter::Options* /* options */) const
{
int s,t,r;
int internalFormat;
unsigned int pixelFormat;
unsigned int dataType;
unsigned char* imageData = NULL;
std::string my_errmsg;
try
{
gta::header hdr;
hdr.read_from(fin);
if (hdr.data_size() > static_cast<uintmax_t>(std::numeric_limits<int>::max()))
{
my_errmsg = "GTA too large";
throw std::exception();
}
if (hdr.dimensions() < 1 || hdr.dimensions() > 3)
{
my_errmsg = "GTA has less than 1 or more than 3 dimensions";
throw std::exception();
}
s = t = r = 1;
for (uintmax_t i = 0; i < hdr.dimensions(); i++)
{
if (hdr.dimension_size(i) > static_cast<uintmax_t>(std::numeric_limits<int>::max()))
{
my_errmsg = "GTA dimensions too large";
throw std::exception();
}
if (i == 0)
s = hdr.dimension_size(i);
else if (i == 1)
t = hdr.dimension_size(i);
else
r = hdr.dimension_size(i);
}
if (hdr.components() < 1 || hdr.components() > 4)
{
my_errmsg = "GTA has less than 1 or more than 4 element components";
throw std::exception();
}
pixelFormat =
hdr.components() == 1 ? GL_LUMINANCE :
hdr.components() == 2 ? GL_LUMINANCE_ALPHA :
hdr.components() == 3 ? GL_RGB :
GL_RGBA;
switch (hdr.component_type(0))
{
case gta::int8:
dataType = GL_BYTE;
break;
case gta::uint8:
dataType = GL_UNSIGNED_BYTE;
break;
case gta::int16:
dataType = GL_SHORT;
break;
case gta::uint16:
dataType = GL_UNSIGNED_SHORT;
break;
case gta::int32:
dataType = GL_INT;
break;
case gta::uint32:
dataType = GL_UNSIGNED_INT;
break;
case gta::float32:
dataType = GL_FLOAT;
break;
default:
my_errmsg = "GTA component type(s) not supported";
throw std::exception();
}
for (uintmax_t i = 1; i < hdr.components(); i++)
{
if (hdr.component_type(i) != hdr.component_type(0))
{
my_errmsg = "GTA component types differ";
throw std::exception();
}
}
if (dataType == GL_BYTE || dataType == GL_UNSIGNED_BYTE)
{
internalFormat = hdr.components();
}
else
{
internalFormat =
hdr.components() == 1 ? GL_LUMINANCE32F_ARB :
hdr.components() == 2 ? GL_LUMINANCE_ALPHA32F_ARB :
hdr.components() == 3 ? GL_RGB32F_ARB :
GL_RGBA32F_ARB;
}
imageData = new unsigned char[hdr.data_size()];
hdr.read_data(fin, imageData);
}
catch (std::exception& e)
{
delete[] imageData;
if (!(my_errmsg.empty()))
{
OSG_WARN << my_errmsg << std::endl;
}
else
{
OSG_WARN << e.what() << std::endl;
}
return ReadResult::ERROR_IN_READING_FILE;
}
osg::Image* pOsgImage = new osg::Image;
pOsgImage->setImage(s,t,r,
internalFormat,
pixelFormat,
dataType,
imageData,
osg::Image::USE_NEW_DELETE);
pOsgImage->setOrigin(osg::Image::TOP_LEFT);
return pOsgImage;
}
WriteResult local_writeImage(std::ostream& fout,const osg::Image& img,const osgDB::ReaderWriter::Options* options) const
{
std::string my_errmsg;
try
{
gta::header hdr;
gta::compression compression = gta::zlib;
if (options)
{
std::istringstream iss(options->getOptionString());
std::string opt;
std::string compressionMethod;
while (iss >> opt)
{
if (opt == "COMPRESSION")
{
iss >> compressionMethod;
}
};
if (compressionMethod == "NONE")
compression = gta::none;
else if (compressionMethod == "ZLIB")
compression = gta::zlib;
else if (compressionMethod == "ZLIB1")
compression = gta::zlib1;
else if (compressionMethod == "ZLIB2")
compression = gta::zlib2;
else if (compressionMethod == "ZLIB3")
compression = gta::zlib3;
else if (compressionMethod == "ZLIB4")
compression = gta::zlib4;
else if (compressionMethod == "ZLIB5")
compression = gta::zlib5;
else if (compressionMethod == "ZLIB6")
compression = gta::zlib6;
else if (compressionMethod == "ZLIB7")
compression = gta::zlib7;
else if (compressionMethod == "ZLIB8")
compression = gta::zlib8;
else if (compressionMethod == "ZLIB9")
compression = gta::zlib9;
else if (compressionMethod == "BZIP2")
compression = gta::bzip2;
else if (compressionMethod == "XZ")
compression = gta::xz;
}
hdr.set_compression(compression);
if (img.s() > 0 && img.t() <= 1 && img.r() <= 1)
{
hdr.set_dimensions(img.s());
}
else if (img.s() > 0 && img.t() > 1 && img.r() <= 1)
{
hdr.set_dimensions(img.s(), img.t());
}
else if (img.s() > 0 && img.t() > 1 && img.r() > 1)
{
hdr.set_dimensions(img.s(), img.t(), img.r());
}
else
{
my_errmsg = "Image has unsupported dimensions";
throw std::exception();
}
gta::type type;
switch (img.getDataType())
{
case GL_BYTE:
type = gta::int8;
break;
case GL_UNSIGNED_BYTE:
type = gta::uint8;
break;
case GL_SHORT:
type = gta::int16;
break;
case GL_UNSIGNED_SHORT:
type = gta::uint16;
break;
case GL_INT:
type = gta::int32;
break;
case GL_UNSIGNED_INT:
type = gta::uint32;
break;
case GL_FLOAT:
type = gta::float32;
break;
default:
my_errmsg = "Image has unsupported data type";
throw std::exception();
}
switch (img.getPixelFormat())
{
case 1:
case GL_DEPTH_COMPONENT:
case GL_LUMINANCE:
case GL_ALPHA:
hdr.set_components(type);
break;
case 2:
case GL_LUMINANCE_ALPHA:
hdr.set_components(type, type);
break;
case 3:
case GL_RGB:
hdr.set_components(type, type, type);
break;
case 4:
case GL_RGBA:
hdr.set_components(type, type, type, type);
break;
default:
my_errmsg = "Image has unsupported pixel format";
throw std::exception();
}
if (img.getPacking() != 1)
{
my_errmsg = "Image has unsupported packing";
throw std::exception();
}
hdr.write_to(fout);
#if 0 /* Does not seem to be necessary */
if (img.t() > 1 && img.getOrigin() == osg::Image::BOTTOM_LEFT)
{
int depth = (img.r() >= 1 ? img.r() : 1);
const unsigned char* data = static_cast<const unsigned char*>(img.getDataPointer());
size_t row_size = hdr.element_size() * img.s();
gta::io_state io_state;
for (int k = 0; k < depth; k++)
{
const unsigned char* slice = data + k * (row_size * img.t());
for (int j = 0; j < img.t(); j++)
{
const unsigned char* p = slice + (img.t() - 1 - j) * row_size;
hdr.write_elements(io_state, fout, img.s(), p);
}
}
}
else
{
hdr.write_data(fout, img.getDataPointer());
}
#endif
hdr.write_data(fout, img.getDataPointer());
}
catch (std::exception& e)
{
if (!(my_errmsg.empty()))
{
OSG_WARN << my_errmsg << std::endl;
}
else
{
OSG_WARN << e.what() << std::endl;
}
return WriteResult::ERROR_IN_WRITING_FILE;
}
return WriteResult::FILE_SAVED;
}
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 osgDB::ReaderWriter::Options* options =NULL) const
{
return local_readImage(fin, options);
}
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;
osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary);
if(!istream) return ReadResult::FILE_NOT_HANDLED;
ReadResult rr = local_readImage(istream, options);
if(rr.validImage()) rr.getImage()->setFileName(file);
return rr;
}
virtual WriteResult writeImage(const osg::Image& img,std::ostream& fout,const osgDB::ReaderWriter::Options* options) const
{
return local_writeImage(fout,img,options);
}
virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options *options) const
{
std::string ext = osgDB::getFileExtension(fileName);
if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary);
if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;
return writeImage(img,fout,options);
}
};
// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(gta, ReaderWriterGTA)