277 lines
8.9 KiB
C++
277 lines
8.9 KiB
C++
/*
|
|
*
|
|
* Copyright (C) 2004 Mekensleep
|
|
*
|
|
* Mekensleep
|
|
* 24 rue vieille du temple
|
|
* 75004 Paris
|
|
* licensing@mekensleep.com
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* 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 GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Author:
|
|
* Igor Kravtchenko <igor@obraz.net>
|
|
*
|
|
*/
|
|
|
|
#include <osg/Image>
|
|
#include <osg/Notify>
|
|
#include <osg/Geode>
|
|
#include <osg/GL>
|
|
|
|
#include <osgDB/Registry>
|
|
#include <osgDB/FileNameUtils>
|
|
#include <osgDB/FileUtils>
|
|
#include <osgDB/fstream>
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sstream>
|
|
|
|
#include "hdrloader.h"
|
|
#include "hdrwriter.h"
|
|
|
|
class ReaderWriterHDR : public osgDB::ReaderWriter
|
|
{
|
|
public:
|
|
ReaderWriterHDR()
|
|
{
|
|
supportsExtension("hdr","High Dynamic Range image format");
|
|
supportsOption("RGBMUL","");
|
|
supportsOption("RGB8","");
|
|
supportsOption("RAW","");
|
|
supportsOption("YFLIP","");
|
|
supportsOption("NO_YFLIP","");
|
|
}
|
|
virtual const char* className() { return "HDR Image Reader"; }
|
|
|
|
virtual ReadResult readImage(const std::string &_file, const osgDB::ReaderWriter::Options *_opts) const
|
|
{
|
|
std::string filepath = osgDB::findDataFile(_file, _opts);
|
|
if (filepath.empty())
|
|
return ReadResult::FILE_NOT_FOUND;
|
|
|
|
if (!HDRLoader::isHDRFile(filepath.c_str()))
|
|
return ReadResult::FILE_NOT_HANDLED;
|
|
|
|
float mul = 1.0f;
|
|
bool bYFlip = false;
|
|
bool convertToRGB8 = false;
|
|
bool rawRGBE = false;
|
|
if(_opts)
|
|
{
|
|
std::istringstream iss(_opts->getOptionString());
|
|
std::string opt;
|
|
while (iss >> opt)
|
|
{
|
|
if(opt == "RGBMUL")
|
|
{
|
|
iss >> mul;
|
|
}
|
|
else if(opt == "RGB8")
|
|
{
|
|
convertToRGB8 = true;
|
|
}
|
|
/* RAW: store the RGBE values into a Image, to use this option you
|
|
* need to decode the RGBE value in the fragment shader. Follow
|
|
* the cube map glsl decoder:
|
|
*
|
|
* vec4 textureCubeRGBE( uniform samplerCube sampler, vec3 coords )
|
|
* {
|
|
* ivec4 rgbe = textureCube( sampler, coords ) * 255. + 0.5;
|
|
* float e = rgbe.a - ( 128 + 8 );
|
|
* return vec4( rgbe.rgb * exp2( e ), 1.0 );
|
|
* }
|
|
*
|
|
*/
|
|
else if(opt == "RAW")
|
|
{
|
|
rawRGBE = true;
|
|
}
|
|
else if(opt == "YFLIP")
|
|
{
|
|
bYFlip = true; // Image is flipped later if required
|
|
}
|
|
}
|
|
}
|
|
|
|
HDRLoaderResult res;
|
|
bool ret = HDRLoader::load(filepath.c_str(), rawRGBE, res);
|
|
if (!ret)
|
|
return ReadResult::ERROR_IN_READING_FILE;
|
|
|
|
// create the osg::Image to fill in.
|
|
osg::Image *img = new osg::Image;
|
|
|
|
// copy across the raw data into the osg::Image
|
|
if (convertToRGB8)
|
|
{
|
|
int nbPixs = res.width * res.height;
|
|
int nbElements = nbPixs * 3;
|
|
unsigned char *rgb = new unsigned char[ nbElements ];
|
|
unsigned char *tt = rgb;
|
|
float *cols = res.cols;
|
|
|
|
for (int i = 0; i < nbElements; i++) {
|
|
float element = *cols++;
|
|
element *= mul;
|
|
if (element < 0) element = 0;
|
|
else if (element > 1) element = 1;
|
|
int intElement = (int) (element * 255.0f);
|
|
*tt++ = intElement;
|
|
}
|
|
|
|
delete [] res.cols;
|
|
|
|
int pixelFormat = GL_RGB;
|
|
int dataType = GL_UNSIGNED_BYTE;
|
|
|
|
img->setFileName(filepath.c_str());
|
|
img->setImage( res.width, res.height, 1,
|
|
3, // Why this value are here?
|
|
pixelFormat,
|
|
dataType,
|
|
(unsigned char*) rgb,
|
|
osg::Image::USE_NEW_DELETE);
|
|
}
|
|
else
|
|
{
|
|
int internalFormat;
|
|
int pixelFormat;
|
|
int dataType = GL_FLOAT;
|
|
|
|
if (rawRGBE)
|
|
{
|
|
internalFormat = GL_RGBA8;
|
|
pixelFormat = GL_RGBA;
|
|
} else {
|
|
// In a perfect world it should be GL_RGB32F_ARB,
|
|
// but by default it works fine as GL_RGB8. You
|
|
// can set it as GL_RGB32F_ARB in the method
|
|
// setInternalFormat of osg::Texture{xD, Rectangle
|
|
// and CubeMap} if your GPU support it.
|
|
internalFormat = GL_RGB8;
|
|
pixelFormat = GL_RGB;
|
|
}
|
|
|
|
img->setFileName(filepath.c_str());
|
|
img->setImage( res.width, res.height, 1,
|
|
internalFormat,
|
|
pixelFormat,
|
|
dataType,
|
|
(unsigned char*) res.cols,
|
|
osg::Image::USE_NEW_DELETE);
|
|
}
|
|
|
|
// Y flip
|
|
if(bYFlip==true) img->flipVertical();
|
|
|
|
return img;
|
|
}
|
|
|
|
|
|
// Additional write methods
|
|
virtual WriteResult writeImage(const osg::Image &image,const std::string& file, const osgDB::ReaderWriter::Options* options) const
|
|
{
|
|
std::string ext = osgDB::getFileExtension(file);
|
|
if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
|
|
|
|
osgDB::ofstream fout(file.c_str(), std::ios::out | std::ios::binary);
|
|
if(!fout) return WriteResult::ERROR_IN_WRITING_FILE;
|
|
|
|
return writeImage(image,fout,options);
|
|
}
|
|
|
|
virtual WriteResult writeImage(const osg::Image& image,std::ostream& fout,const Options* options) const
|
|
{
|
|
|
|
bool bYFlip = true; // Whether to flip the vertical
|
|
bool rawRGBE = false; // Whether to write as raw RGBE
|
|
|
|
if(options)
|
|
{
|
|
std::istringstream iss(options->getOptionString());
|
|
std::string opt;
|
|
while (iss >> opt)
|
|
{
|
|
if (opt=="NO_YFLIP")
|
|
{
|
|
// We want to YFLIP because although the file format specification
|
|
// dictates that +Y M +X N is a valid resolution line, no software (including
|
|
// HDRShop!) actually recognises it; hence everything tends to be written upside down
|
|
// So we flip the image first...
|
|
bYFlip = false;
|
|
}
|
|
else if(opt=="RAW")
|
|
{
|
|
rawRGBE = true;
|
|
}
|
|
/* The following are left out for the moment as
|
|
we don't really do anything with them in OSG
|
|
else if(opt=="GAMMA")
|
|
{
|
|
iss >> gamma;
|
|
}
|
|
else if(opt=="EXPOSURE")
|
|
{
|
|
iss >> exposure;
|
|
}
|
|
*/
|
|
|
|
}
|
|
}
|
|
|
|
// Reject unhandled image formats
|
|
if(rawRGBE==false)
|
|
{
|
|
if(image.getInternalTextureFormat()!=GL_RGB32F_ARB) // We only handle RGB (no alpha) with 32F formats
|
|
{
|
|
return WriteResult::FILE_NOT_HANDLED;
|
|
}
|
|
}
|
|
else // Outputting raw RGBE (as interpreted by a shader, for example)
|
|
{
|
|
if(image.getInternalTextureFormat()!=GL_RGBA8) // We need 8 bit bytes including alpha (E)
|
|
{
|
|
return WriteResult::FILE_NOT_HANDLED;
|
|
}
|
|
}
|
|
|
|
// Get a temporary copy to flip if we need to
|
|
osg::ref_ptr<osg::Image> source = new osg::Image(image,osg::CopyOp::DEEP_COPY_ALL);
|
|
|
|
if(bYFlip==true) source->flipVertical();
|
|
|
|
bool success;
|
|
success = HDRWriter::writeHeader(source.get(),fout);
|
|
if(!success)
|
|
{
|
|
source = 0; // delete the temporary image
|
|
return WriteResult::ERROR_IN_WRITING_FILE; // early out
|
|
}
|
|
|
|
success = HDRWriter::writeRLE(source.get(), fout);
|
|
|
|
source = 0; // delete the temporary image
|
|
return (success)? WriteResult::FILE_SAVED : WriteResult::ERROR_IN_WRITING_FILE;
|
|
}
|
|
};
|
|
|
|
// now register with Registry to instantiate the above
|
|
// reader/writer.
|
|
REGISTER_OSGPLUGIN(hdr, ReaderWriterHDR)
|