478 lines
14 KiB
C++
478 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
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_WINDOWS_H
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#if defined (SG_MAC)
|
|
#include <OpenGL/gl.h>
|
|
#include <GLUT/glut.h>
|
|
#elif defined (_GLES2)
|
|
#include <GLES2/gl2.h>
|
|
#else
|
|
#include <GL/glew.h> // Must be included before <GL/gl.h>
|
|
#include <GL/gl.h>
|
|
#include <GL/glut.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
#include "FGRGBTextureLoader.hxx"
|
|
|
|
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;
|
|
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 ((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 ((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 (istream& fin) {
|
|
union {
|
|
int testWord;
|
|
char testByte[4];
|
|
} endianTest;
|
|
|
|
rawImageRec *raw = new rawImageRec;
|
|
if (raw == NULL) {
|
|
// notify(WARN)<< "Out of memory!"<< 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!"<< 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!"<< 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!"<< 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!"<< 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!"<< 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!"<< endl;
|
|
RawImageClose (raw);
|
|
return NULL;
|
|
}
|
|
|
|
if ((raw->rowSize = new GLint[ybyz]) == NULL) {
|
|
// notify(FATAL)<< "Out of memory!"<< endl;
|
|
RawImageClose (raw);
|
|
return NULL;
|
|
}
|
|
int x (ybyz * sizeof (GLuint));
|
|
raw->rleEnd = 512 + (2 * x);
|
|
fin.seekg (512, 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, const int y, const int z) {
|
|
unsigned short pixel;
|
|
int done = 0;
|
|
unsigned short *tempShort;
|
|
|
|
if ((raw->type & 0xFF00) == 0x0100) {
|
|
raw->file->seekg (long (raw->rowStart[y + z * raw->sizeY]), ios::beg);
|
|
raw->file->read ((char*) raw->tmp, (unsigned int) (raw->rowSize[y + z * raw->sizeY]));
|
|
|
|
unsigned char *iPtr = raw->tmp;
|
|
unsigned char *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);
|
|
}
|
|
int 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), 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) {
|
|
|
|
// // 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<<endl;
|
|
// osg::notify(osg::INFO)<<"raw->sizeY = "<<raw->sizeY<<endl;
|
|
// osg::notify(osg::INFO)<<"raw->sizeZ = "<<raw->sizeZ<<endl;
|
|
// osg::notify(osg::INFO)<<"raw->bpc = "<<raw->bpc<<endl;
|
|
|
|
*data = new unsigned char [(raw->sizeX) * (raw->sizeY) * (raw->sizeZ) * (raw->bpc)];
|
|
|
|
unsigned char *ptr (*data);
|
|
for (int 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 (int 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 {
|
|
unsigned short *tempShort;
|
|
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 (istream &fin) {
|
|
rawImageRec * const raw (RawImageOpen (fin));
|
|
|
|
if (raw == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
const int s (raw->sizeX);
|
|
const 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
|
|
const 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);
|
|
|
|
const 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);
|
|
glTexImage2D (GL_TEXTURE_2D, 0, pixelFormat, s, t, 0, pixelFormat, dataType, (GLvoid*) data);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
delete []data;
|
|
return texture;
|
|
}
|
|
|
|
GLuint
|
|
FGRGBTextureLoader::loadTexture (const string &filename) {
|
|
GLuint texture = NOTEXTURE;
|
|
ifstream istream (filename.c_str (), ios::in | ios::binary);
|
|
texture = readRGBStream (istream);
|
|
istream.close ();
|
|
return texture;
|
|
}
|