diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fb5b6bd6..dd327746b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -467,6 +467,7 @@ ELSE() FIND_PACKAGE(OpenVRML) FIND_PACKAGE(Performer) FIND_PACKAGE(GDAL) + FIND_PACKAGE(GTA) FIND_PACKAGE(CURL) FIND_PACKAGE(LibVNCServer) FIND_PACKAGE(OurDCMTK) diff --git a/CMakeModules/FindGTA.cmake b/CMakeModules/FindGTA.cmake new file mode 100644 index 000000000..56f6b803d --- /dev/null +++ b/CMakeModules/FindGTA.cmake @@ -0,0 +1,56 @@ +# Locate libgta +# This module defines +# GTA_FOUND, if false, do not try to link to libgta +# GTA_INCLUDE_DIRS, where to find the headers +# GTA_LIBRARIES +# +# $GTA_DIR is an environment variable that would +# correspond to the ./configure --prefix=$GTA_DIR +# used in building libgta. + +INCLUDE(FindPkgConfig OPTIONAL) + +IF(PKG_CONFIG_FOUND) + + INCLUDE(FindPkgConfig) + + PKG_CHECK_MODULES(GTA gta) + +ELSE(PKG_CONFIG_FOUND) + +FIND_PATH(GTA_INCLUDE_DIRS gta/gta.hpp + $ENV{GTA_DIR}/include + $ENV{GTA_DIR} + ~/Library/Frameworks + /Library/Frameworks + /usr/local/include + /usr/include + /sw/include # Fink + /opt/local/include # DarwinPorts + /opt/csw/include # Blastwave + /opt/include + /usr/freeware/include +) + +FIND_LIBRARY(GTA_LIBRARIES + NAMES gta libgta + PATHS + $ENV{GTA_DIR}/lib + $ENV{GTA_DIR} + ~/Library/Frameworks + /Library/Frameworks + /usr/local/lib + /usr/lib + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + /usr/freeware/lib64 +) + +SET(GTA_FOUND "NO") +IF(GTA_LIBRARIES AND GTA_INCLUDE_DIRS) + SET(GTA_FOUND "YES") +ENDIF(GTA_LIBRARIES AND GTA_INCLUDE_DIRS) + +ENDIF(PKG_CONFIG_FOUND) diff --git a/src/osgPlugins/CMakeLists.txt b/src/osgPlugins/CMakeLists.txt index 0a6cd987f..9a8453bb7 100644 --- a/src/osgPlugins/CMakeLists.txt +++ b/src/osgPlugins/CMakeLists.txt @@ -100,6 +100,9 @@ IF(GDAL_FOUND) ADD_SUBDIRECTORY(gdal) ADD_SUBDIRECTORY(ogr) ENDIF() +IF(GTA_FOUND AND OSG_CPP_EXCEPTIONS_AVAILABLE) + ADD_SUBDIRECTORY(gta) +ENDIF() ############################################################ diff --git a/src/osgPlugins/gta/CMakeLists.txt b/src/osgPlugins/gta/CMakeLists.txt new file mode 100644 index 000000000..16466fefc --- /dev/null +++ b/src/osgPlugins/gta/CMakeLists.txt @@ -0,0 +1,8 @@ +INCLUDE_DIRECTORIES( ${GTA_INCLUDE_DIRS} ) + +SET(TARGET_SRC ReaderWriterGTA.cpp ) + +SET(TARGET_LIBRARIES_VARS GTA_LIBRARIES) + +#### end var setup ### +SETUP_PLUGIN(gta) diff --git a/src/osgPlugins/gta/ReaderWriterGTA.cpp b/src/osgPlugins/gta/ReaderWriterGTA.cpp new file mode 100644 index 000000000..26ce78a6d --- /dev/null +++ b/src/osgPlugins/gta/ReaderWriterGTA.cpp @@ -0,0 +1,378 @@ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* 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(std::numeric_limits::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(std::numeric_limits::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(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)