Files
OpenSceneGraph/src/osgPlugins/rgb/ReaderWriterRGB.cpp
Robert Osfield 6d66e1abaa Added support for using GL_UNPACK_ROW_LENGTH in conjunction with texture's + osg::Image via new RowLength
parameter in osg::Image.  To support this Image::setData(..) now has a new optional rowLength parameter which
defaults to 0, which provides the original behaviour, Image::setRowLength(int) and int Image::getRowLength() are also provided.

With the introduction of RowLength support in osg::Image it is now possible to create a sub image where
the t size of the image are smaller than the row length, useful for when you have a large image on the CPU
and which to use a small portion of it on the GPU.  However, when these sub images are created the data
within the image is no longer contiguous so data access can no longer assume that all the data is in
one block.  The new method Image::isDataContiguous() enables the user to check whether the data is contiguous,
and if not one can either access the data row by row using Image::data(column,row,image) accessor, or use the
new Image::DataIterator for stepping through each block on memory assocatied with the image.

To support the possibility of non contiguous osg::Image usage of image objects has had to be updated to
check DataContiguous and handle the case or use access via the DataIerator or by row by row.  To achieve
this a relatively large number of files has had to be modified, in particular the texture classes and
image plugins that doing writing.
2012-01-24 14:34:02 +00:00

704 lines
21 KiB
C++

// Released under the OSGPL license, as part of the OpenSceneGraph distribution.
//
// ReaderWriter for sgi's .rgb format.
// specification can be found at http://local.wasp.uwa.edu.au/~pbourke/dataformats/sgirgb/sgiversion.html
#include <osg/Image>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/GL>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/Registry>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef SEEK_SET
# define SEEK_SET 0
#endif
#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
#define GL_BITMAP 0x1A00
#define GL_RED 0x1903
#define GL_GREEN 0x1904
#define GL_BLUE 0x1905
#define GL_COLOR_INDEX 0x1900
#endif
#if defined(OSG_GL3_AVAILABLE)
#define GL_BITMAP 0x1A00
#define GL_COLOR_INDEX 0x1900
#endif
using namespace osg;
typedef struct _rawImageRec
{
unsigned short imagic;
unsigned short type;
unsigned short dim;
unsigned short sizeX, sizeY, sizeZ;
unsigned long min, max;
unsigned long wasteBytes;
char name[80];
unsigned long colorMap;
std::istream *file;
unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
unsigned long rleEnd;
GLuint *rowStart;
GLint *rowSize;
GLenum swapFlag;
short bpc;
typedef unsigned char * BytePtr;
bool needsBytesSwapped()
{
union {
int testWord;
char testByte[sizeof(int)];
}endianTest;
endianTest.testWord = 1;
if( endianTest.testByte[0] == 1 )
return true;
else
return false;
}
template <class T>
inline void swapBytes( T &s )
{
if( sizeof( T ) == 1 )
return;
T d = s;
BytePtr sptr = (BytePtr)&s;
BytePtr dptr = &(((BytePtr)&d)[sizeof(T)-1]);
for( unsigned int i = 0; i < sizeof(T); i++ )
*(sptr++) = *(dptr--);
}
void swapBytes()
{
swapBytes( imagic );
swapBytes( type );
swapBytes( dim );
swapBytes( sizeX );
swapBytes( sizeY );
swapBytes( sizeZ );
swapBytes( wasteBytes );
swapBytes( min );
swapBytes( max );
swapBytes( colorMap );
}
} rawImageRec;
static void ConvertShort(unsigned short *array, long length)
{
unsigned long b1, b2;
unsigned char *ptr;
ptr = (unsigned char *)array;
while (length--)
{
b1 = *ptr++;
b2 = *ptr++;
*array++ = (unsigned short) ((b1 << 8) | (b2));
}
}
static void ConvertLong(GLuint *array, long length)
{
unsigned long b1, b2, b3, b4;
unsigned char *ptr;
ptr = (unsigned char *)array;
while (length--)
{
b1 = *ptr++;
b2 = *ptr++;
b3 = *ptr++;
b4 = *ptr++;
*array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
}
}
static void RawImageClose(rawImageRec *raw)
{
if (raw)
{
if (raw->tmp) delete [] raw->tmp;
if (raw->tmpR) delete [] raw->tmpR;
if (raw->tmpG) delete [] raw->tmpG;
if (raw->tmpB) delete [] raw->tmpB;
if (raw->tmpA) delete [] raw->tmpA;
if (raw->rowStart) delete [] raw->rowStart;
if (raw->rowSize) delete [] raw->rowSize;
delete raw;
}
}
static rawImageRec *RawImageOpen(std::istream& fin)
{
union
{
int testWord;
char testByte[4];
} endianTest;
rawImageRec *raw;
int x;
raw = new rawImageRec;
if (raw == NULL)
{
OSG_WARN<< "Out of memory!"<< std::endl;
return NULL;
}
//Set istream pointer
raw->file = &fin;
endianTest.testWord = 1;
if (endianTest.testByte[0] == 1)
{
raw->swapFlag = GL_TRUE;
}
else
{
raw->swapFlag = GL_FALSE;
}
fin.read((char*)raw,12);
if (!fin.good())
return NULL;
if (raw->swapFlag)
{
ConvertShort(&raw->imagic, 6);
}
raw->tmp = raw->tmpR = raw->tmpG = raw->tmpB = raw->tmpA = 0L;
raw->rowStart = 0;
raw->rowSize = 0;
raw->bpc = (raw->type & 0x00FF);
raw->tmp = new unsigned char [raw->sizeX*256*raw->bpc];
if (raw->tmp == NULL )
{
OSG_FATAL<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
if( raw->sizeZ >= 1 )
{
if( (raw->tmpR = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
{
OSG_FATAL<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
}
if( raw->sizeZ >= 2 )
{
if( (raw->tmpG = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
{
OSG_FATAL<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
}
if( raw->sizeZ >= 3 )
{
if( (raw->tmpB = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
{
OSG_FATAL<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
}
if (raw->sizeZ >= 4)
{
if( (raw->tmpA = new unsigned char [raw->sizeX*raw->bpc]) == NULL )
{
OSG_FATAL<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
}
if ((raw->type & 0xFF00) == 0x0100)
{
unsigned int ybyz = raw->sizeY * raw->sizeZ;
if ( (raw->rowStart = new GLuint [ybyz]) == NULL )
{
OSG_FATAL<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
if ( (raw->rowSize = new GLint [ybyz]) == NULL )
{
OSG_FATAL<< "Out of memory!"<< std::endl;
RawImageClose(raw);
return NULL;
}
x = ybyz * sizeof(GLuint);
raw->rleEnd = 512 + (2 * x);
fin.seekg(512,std::ios::beg);
fin.read((char*)raw->rowStart,x);
fin.read((char*)raw->rowSize,x);
if (raw->swapFlag)
{
ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint)));
ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint)));
}
}
return raw;
}
static void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z)
{
unsigned char *iPtr, *oPtr;
unsigned short pixel;
int count, done = 0;
unsigned short *tempShort;
if ((raw->type & 0xFF00) == 0x0100)
{
raw->file->seekg((long) raw->rowStart[y+z*raw->sizeY], std::ios::beg);
raw->file->read((char*)raw->tmp, (unsigned int)raw->rowSize[y+z*raw->sizeY]);
iPtr = raw->tmp;
oPtr = buf;
while (!done)
{
if (raw->bpc == 1)
pixel = *iPtr++;
else
{
tempShort = reinterpret_cast<unsigned short*>(iPtr);
pixel = *tempShort;
tempShort++;
iPtr = reinterpret_cast<unsigned char *>(tempShort);
}
if(raw->bpc != 1)
ConvertShort(&pixel, 1);
count = (int)(pixel & 0x7F);
// limit the count value to the remiaing row size
if (raw->sizeX*raw->bpc <= (oPtr - buf))
{
count = raw->sizeX - (oPtr - buf) / raw->bpc;
}
if (count<=0)
{
done = 1;
return;
}
if (pixel & 0x80)
{
while (count--)
{
if(raw->bpc == 1)
*oPtr++ = *iPtr++;
else{
tempShort = reinterpret_cast<unsigned short*>(iPtr);
pixel = *tempShort;
tempShort++;
iPtr = reinterpret_cast<unsigned char *>(tempShort);
ConvertShort(&pixel, 1);
tempShort = reinterpret_cast<unsigned short*>(oPtr);
*tempShort = pixel;
tempShort++;
oPtr = reinterpret_cast<unsigned char *>(tempShort);
}
}
}
else
{
if (raw->bpc == 1)
{
pixel = *iPtr++;
}
else
{
tempShort = reinterpret_cast<unsigned short*>(iPtr);
pixel = *tempShort;
tempShort++;
iPtr = reinterpret_cast<unsigned char *>(tempShort);
}
if(raw->bpc != 1)
ConvertShort(&pixel, 1);
while (count--)
{
if(raw->bpc == 1)
*oPtr++ = pixel;
else
{
tempShort = reinterpret_cast<unsigned short*>(oPtr);
*tempShort = pixel;
tempShort++;
oPtr = reinterpret_cast<unsigned char *>(tempShort);
}
}
}
}
}
else
{
raw->file->seekg(512+(y*raw->sizeX*raw->bpc)+(z*raw->sizeX*raw->sizeY*raw->bpc),std::ios::beg);
raw->file->read((char*)buf, raw->sizeX*raw->bpc);
if(raw->swapFlag && raw->bpc != 1){
ConvertShort(reinterpret_cast<unsigned short*>(buf), raw->sizeX);
}
}
}
static void RawImageGetData(rawImageRec *raw, unsigned char **data )
{
unsigned char *ptr;
int i, j;
unsigned short *tempShort;
// // round the width to a factor 4
// int width = (int)(floorf((float)raw->sizeX/4.0f)*4.0f);
// if (width!=raw->sizeX) width += 4;
// byte aligned.
OSG_INFO<<"raw->sizeX = "<<raw->sizeX<<std::endl;
OSG_INFO<<"raw->sizeY = "<<raw->sizeY<<std::endl;
OSG_INFO<<"raw->sizeZ = "<<raw->sizeZ<<std::endl;
OSG_INFO<<"raw->bpc = "<<raw->bpc<<std::endl;
*data = new unsigned char [(raw->sizeX)*(raw->sizeY)*(raw->sizeZ)*(raw->bpc)];
ptr = *data;
for (i = 0; i < (int)(raw->sizeY); i++)
{
if( raw->sizeZ >= 1 )
RawImageGetRow(raw, raw->tmpR, i, 0);
if( raw->sizeZ >= 2 )
RawImageGetRow(raw, raw->tmpG, i, 1);
if( raw->sizeZ >= 3 )
RawImageGetRow(raw, raw->tmpB, i, 2);
if( raw->sizeZ >= 4 )
RawImageGetRow(raw, raw->tmpA, i, 3);
for (j = 0; j < (int)(raw->sizeX); j++)
{
if(raw->bpc == 1){
if( raw->sizeZ >= 1 )
*ptr++ = *(raw->tmpR + j);
if( raw->sizeZ >= 2 )
*ptr++ = *(raw->tmpG + j);
if( raw->sizeZ >= 3 )
*ptr++ = *(raw->tmpB + j);
if( raw->sizeZ >= 4 )
*ptr++ = *(raw->tmpA + j);
}else{
if( raw->sizeZ >= 1 )
{
tempShort = reinterpret_cast<unsigned short*>(ptr);
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpR) + j);
tempShort++;
ptr = reinterpret_cast<unsigned char *>(tempShort);
}
if( raw->sizeZ >= 2 )
{
tempShort = reinterpret_cast<unsigned short*>(ptr);
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpG) + j);
tempShort++;
ptr = reinterpret_cast<unsigned char *>(tempShort);
}
if( raw->sizeZ >= 3 )
{
tempShort = reinterpret_cast<unsigned short*>(ptr);
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpB) + j);
tempShort++;
ptr = reinterpret_cast<unsigned char *>(tempShort);
}
if( raw->sizeZ >= 4 )
{
tempShort = reinterpret_cast<unsigned short*>(ptr);
*tempShort = *(reinterpret_cast<unsigned short*>(raw->tmpA) + j);
tempShort++;
ptr = reinterpret_cast<unsigned char *>(tempShort);
}
}
}
// // pad the image width with blanks to bring it up to the rounded width.
// for(;j<width;++j) *ptr++ = 0;
}
}
class ReaderWriterRGB : public osgDB::ReaderWriter
{
public:
ReaderWriterRGB()
{
supportsExtension("rgb","rgb image format");
supportsExtension("rgba","rgba image format");
supportsExtension("sgi","sgi image format");
supportsExtension("int","int image format");
supportsExtension("inta","inta image format");
supportsExtension("bw","bw image format");
}
virtual const char* className() const { return "RGB Image Reader/Writer"; }
ReadResult readRGBStream(std::istream& fin) const
{
rawImageRec *raw;
if( (raw = RawImageOpen(fin)) == NULL )
{
return ReadResult::ERROR_IN_READING_FILE;
}
int s = raw->sizeX;
int t = raw->sizeY;
int r = 1;
#if 0
int internalFormat = raw->sizeZ == 3 ? GL_RGB5 :
raw->sizeZ == 4 ? GL_RGB5_A1 : GL_RGB;
#else
int internalFormat = raw->sizeZ;
#endif
unsigned int pixelFormat =
raw->sizeZ == 1 ? GL_LUMINANCE :
raw->sizeZ == 2 ? GL_LUMINANCE_ALPHA :
raw->sizeZ == 3 ? GL_RGB :
raw->sizeZ == 4 ? GL_RGBA : (GLenum)-1;
unsigned int dataType = raw->bpc == 1 ? GL_UNSIGNED_BYTE :
GL_UNSIGNED_SHORT;
unsigned char *data;
RawImageGetData(raw, &data);
RawImageClose(raw);
Image* image = new Image();
image->setImage(s,t,r,
internalFormat,
pixelFormat,
dataType,
data,
osg::Image::USE_NEW_DELETE);
OSG_INFO << "image read ok "<<s<<" "<<t<< std::endl;
return image;
}
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* =NULL) const
{
return readRGBStream(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;
osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary);
if(!istream) return ReadResult::FILE_NOT_HANDLED;
ReadResult rr = readRGBStream(istream);
if(rr.validImage()) rr.getImage()->setFileName(file);
return rr;
}
WriteResult writeRGBStream(const osg::Image& img, std::ostream &fout, const std::string& name) const
{
rawImageRec raw;
raw.imagic = 0732;
GLenum dataType = img.getDataType();
raw.type = dataType == GL_UNSIGNED_BYTE ? 1 :
dataType == GL_BYTE ? 1 :
dataType == GL_BITMAP ? 1 :
dataType == GL_UNSIGNED_SHORT ? 2 :
dataType == GL_SHORT ? 2 :
dataType == GL_UNSIGNED_INT ? 4 :
dataType == GL_INT ? 4 :
dataType == GL_FLOAT ? 4 :
dataType == GL_UNSIGNED_BYTE_3_3_2 ? 1 :
dataType == GL_UNSIGNED_BYTE_2_3_3_REV ? 1 :
dataType == GL_UNSIGNED_SHORT_5_6_5 ? 2 :
dataType == GL_UNSIGNED_SHORT_5_6_5_REV ? 2 :
dataType == GL_UNSIGNED_SHORT_4_4_4_4 ? 2 :
dataType == GL_UNSIGNED_SHORT_4_4_4_4_REV ? 2 :
dataType == GL_UNSIGNED_SHORT_5_5_5_1 ? 2 :
dataType == GL_UNSIGNED_SHORT_1_5_5_5_REV ? 2 :
dataType == GL_UNSIGNED_INT_8_8_8_8 ? 4 :
dataType == GL_UNSIGNED_INT_8_8_8_8_REV ? 4 :
dataType == GL_UNSIGNED_INT_10_10_10_2 ? 4 :
dataType == GL_UNSIGNED_INT_2_10_10_10_REV ? 4 : 4;
GLenum pixelFormat = img.getPixelFormat();
raw.dim = 3;
raw.sizeX = img.s();
raw.sizeY = img.t();
raw.sizeZ =
pixelFormat == GL_COLOR_INDEX? 1 :
pixelFormat == GL_RED? 1 :
pixelFormat == GL_GREEN? 1 :
pixelFormat == GL_BLUE? 1 :
pixelFormat == GL_ALPHA? 1 :
pixelFormat == GL_RGB? 3 :
pixelFormat == GL_BGR ? 3 :
pixelFormat == GL_RGBA? 4 :
pixelFormat == GL_BGRA? 4 :
pixelFormat == GL_LUMINANCE? 1 :
pixelFormat == GL_LUMINANCE_ALPHA ? 2 : 1;
raw.min = 0;
raw.max = 0xFF;
raw.wasteBytes = 0;
strncpy( raw.name, name.c_str(), 80);
raw.colorMap = 0;
raw.bpc = (img.getPixelSizeInBits()/raw.sizeZ)/8;
int isize = img.getImageSizeInBytes();
unsigned char *buffer = new unsigned char[isize];
if(raw.bpc == 1)
{
unsigned char *dptr = buffer;
int i, j;
for( i = 0; i < raw.sizeZ; ++i )
{
const unsigned char *ptr = img.data();
ptr += i;
for( j = 0; j < isize/raw.sizeZ; ++j )
{
*(dptr++) = *ptr;
ptr += raw.sizeZ;
}
}
}
else
{ // bpc == 2
unsigned short *dptr = reinterpret_cast<unsigned short*>(buffer);
int i, j;
for( i = 0; i < raw.sizeZ; ++i )
{
const unsigned short *ptr = reinterpret_cast<const unsigned short*>(img.data());
ptr += i;
for( j = 0; j < isize/(raw.sizeZ*2); ++j )
{
*dptr = *ptr;
ConvertShort(dptr++, 1);
ptr += raw.sizeZ;
}
}
}
if( raw.needsBytesSwapped() )
raw.swapBytes();
/*
swapBytes( raw.imagic );
swapBytes( raw.type );
swapBytes( raw.dim );
swapBytes( raw.sizeX );
swapBytes( raw.sizeY );
swapBytes( raw.sizeZ );
swapBytes( raw.min );
swapBytes( raw.max );
swapBytes( raw.colorMap );
*/
char pad[512 - sizeof(rawImageRec)];
memset( pad, 0, sizeof(pad));
fout.write((const char*)&raw,sizeof(rawImageRec));
fout.write((const char*)pad,sizeof(pad));
fout.write((const char*)buffer,isize);
delete [] buffer;
return WriteResult::FILE_SAVED;
}
virtual WriteResult writeImage(const osg::Image& img,std::ostream& fout,const osgDB::ReaderWriter::Options*) const
{
if (img.isCompressed())
{
OSG_NOTICE<<"Warning: RGB plugin does not supporting writing compressed imagery."<<std::endl;
return WriteResult::ERROR_IN_WRITING_FILE;
}
if (!img.isDataContiguous())
{
OSG_NOTICE<<"Warning: RGB plugin does not supporting writing non contiguous imagery."<<std::endl;
return WriteResult::ERROR_IN_WRITING_FILE;
}
return writeRGBStream(img,fout,"");
}
virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options*) const
{
if (img.isCompressed())
{
OSG_NOTICE<<"Warning: RGB plugin does not supporting writing compressed imagery."<<std::endl;
return WriteResult::ERROR_IN_WRITING_FILE;
}
if (!img.isDataContiguous())
{
OSG_NOTICE<<"Warning: RGB plugin does not supporting writing non contiguous imagery."<<std::endl;
return WriteResult::ERROR_IN_WRITING_FILE;
}
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 writeRGBStream(img,fout,fileName);
}
};
// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(rgb, ReaderWriterRGB)