// // 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 #endif #ifdef HAVE_WINDOWS_H #include #endif #if defined (SG_MAC) #include #include #elif defined (_GLES2) #include #else #include // Must be included before #include #include #endif #include #include #include #include #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 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 (iPtr); pixel = *tempShort; tempShort++; iPtr = reinterpret_cast (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 (iPtr); pixel = *tempShort; tempShort++; iPtr = reinterpret_cast (tempShort); ConvertShort (&pixel, 1); tempShort = reinterpret_cast (oPtr); *tempShort = pixel; tempShort++; oPtr = reinterpret_cast (tempShort); } } } else { if (raw->bpc == 1) { pixel = *iPtr++; } else { tempShort = reinterpret_cast (iPtr); pixel = *tempShort; tempShort++; iPtr = reinterpret_cast (tempShort); } if (raw->bpc != 1) { ConvertShort (&pixel, 1); } while (count--) { if (raw->bpc == 1) { *oPtr++ = pixel; } else { tempShort = reinterpret_cast (oPtr); *tempShort = pixel; tempShort++; oPtr = reinterpret_cast (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 (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 = "<sizeX<sizeY = "<sizeY<sizeZ = "<sizeZ<bpc = "<bpc<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 (ptr); *tempShort = *(reinterpret_cast (raw->tmpR) + j); tempShort++; ptr = reinterpret_cast (tempShort); } if (raw->sizeZ >= 2) { tempShort = reinterpret_cast (ptr); *tempShort = *(reinterpret_cast (raw->tmpG) + j); tempShort++; ptr = reinterpret_cast (tempShort); } if (raw->sizeZ >= 3) { tempShort = reinterpret_cast (ptr); *tempShort = *(reinterpret_cast (raw->tmpB) + j); tempShort++; ptr = reinterpret_cast (tempShort); } if (raw->sizeZ >= 4) { tempShort = reinterpret_cast (ptr); *tempShort = *(reinterpret_cast (raw->tmpA) + j); tempShort++; ptr = reinterpret_cast (tempShort); } } } // // pad the image width with blanks to bring it up to the rounded width. // for(;jsizeX); 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; }