flightgear/utils/fgpanel/FGRGBTextureLoader.cxx
2022-10-20 20:29:11 +08:00

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;
}