505 lines
14 KiB
C++
505 lines
14 KiB
C++
|
//
|
||
|
// This program is free software; you can redistribute it and/or
|
||
|
// modify it under the terms of the GNU General Public License as
|
||
|
// published by the Free Software Foundation; either version 2 of the
|
||
|
// License, or (at your option) any later version.
|
||
|
//
|
||
|
// This program 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
|
||
|
// General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU General Public License
|
||
|
// along with this program; if not, write to the Free Software
|
||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
//
|
||
|
// From the OpenSceneGraph distribution ReaderWriterRGB.cpp
|
||
|
// Reader for sgi's .rgb format.
|
||
|
// specification can be found at http://local.wasp.uwa.edu.au/~pbourke/dataformats/sgirgb/sgiversion.html
|
||
|
|
||
|
#include "FGRGBTextureLoader.hxx"
|
||
|
#include <GL/gl.h>
|
||
|
#include <GL/glu.h>
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <iostream>
|
||
|
#include <fstream>
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
// notify(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 )
|
||
|
{
|
||
|
// notify(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 )
|
||
|
{
|
||
|
// notify(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 )
|
||
|
{
|
||
|
// notify(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 )
|
||
|
{
|
||
|
// notify(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 )
|
||
|
{
|
||
|
// notify(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 )
|
||
|
{
|
||
|
// notify(FATAL)<< "Out of memory!"<< std::endl;
|
||
|
RawImageClose(raw);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if ( (raw->rowSize = new GLint [ybyz]) == NULL )
|
||
|
{
|
||
|
// notify(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 (oPtr + count*raw->bpc > buf + raw->sizeX*raw->bpc)
|
||
|
{
|
||
|
count = ( (buf + raw->sizeX*raw->bpc) - oPtr ) / 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::notify(osg::INFO)<<"raw->sizeX = "<<raw->sizeX<<std::endl;
|
||
|
// osg::notify(osg::INFO)<<"raw->sizeY = "<<raw->sizeY<<std::endl;
|
||
|
// osg::notify(osg::INFO)<<"raw->sizeZ = "<<raw->sizeZ<<std::endl;
|
||
|
// osg::notify(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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// 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");
|
||
|
|
||
|
GLuint readRGBStream(std::istream& fin)
|
||
|
{
|
||
|
rawImageRec *raw;
|
||
|
|
||
|
if( (raw = RawImageOpen(fin)) == NULL )
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
GLint component = raw->sizeZ;
|
||
|
|
||
|
unsigned int dataType = raw->bpc == 1 ? GL_UNSIGNED_BYTE :
|
||
|
GL_UNSIGNED_SHORT;
|
||
|
|
||
|
unsigned char *data;
|
||
|
RawImageGetData(raw, &data);
|
||
|
RawImageClose(raw);
|
||
|
|
||
|
GLuint texture;
|
||
|
glGenTextures(1, &texture);
|
||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||
|
gluBuild2DMipmaps( GL_TEXTURE_2D, component, s, t, pixelFormat, dataType, (GLvoid*)data );
|
||
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
|
||
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );
|
||
|
|
||
|
delete []data;
|
||
|
return texture;
|
||
|
}
|
||
|
|
||
|
GLuint FGRGBTextureLoader::loadTexture( const std::string & filename )
|
||
|
{
|
||
|
GLuint texture = NOTEXTURE;
|
||
|
std::ifstream istream(filename.c_str(), std::ios::in | std::ios::binary );
|
||
|
texture = readRGBStream(istream);
|
||
|
istream.close();
|
||
|
return texture;
|
||
|
}
|
||
|
|