Commit ecbe0c85 authored by Robert Menzel's avatar Robert Menzel

added ppm loading to new texture loading functions

parent ea1be458
......@@ -47,14 +47,19 @@ inline bool saveScreenshot( const std::string _fileEnding = "png" ) {
SharedTextureData loadTextureDataFromLodepng(const std::string &_filename);
#ifdef ACGL_COMPILE_WITH_QT
//! loads from the QT library
//! loads various formats from the QT library
SharedTextureData loadTextureDataFromQT(const std::string &_filename);
#endif
//! loads RGBE aka Radiance files
SharedTextureData loadTextureDataFromRGBE(const std::string &_filename);
//! loads EXR / OpenEXR files iff the library is present AT RUNTIME (linux only)
SharedTextureData loadTextureDataFromEXR(const std::string &_filename);
//! loads PNM / PPM files:
SharedTextureData loadTextureDataFromPNM(const std::string &_filename);
///////////////////////////////////////////////////////////////////////////////////////////////////
// library specific save
///////////////////////////////////////////////////////////////////////////////////////////////////
......
......@@ -31,7 +31,7 @@ SharedGeometryData loadGeometryData(const std::string& _filename)
}
else
{
error() << "file format of " << _filename << " not supported" << std::endl;
error() << "geometry file format of " << _filename << " not supported" << std::endl;
}
return SharedGeometryData();
......
......@@ -63,6 +63,8 @@ SharedTextureData loadTextureData(const std::string &_filename)
return loadTextureDataFromRGBE( _filename );
} else if (fileEnding == "exr") {
return loadTextureDataFromEXR( _filename );
} else if (fileEnding == "ppm") {
return loadTextureDataFromPNM( _filename );
}
#ifdef ACGL_COMPILE_WITH_QT
else if ( fileEnding == "bmp" || fileEnding == "jpg" || fileEnding == "jpeg"
......@@ -73,7 +75,7 @@ SharedTextureData loadTextureData(const std::string &_filename)
}
#endif
else {
error() << "file format of " << _filename << " not supported" << std::endl;
error() << "texture file format of " << _filename << " not supported" << std::endl;
}
return SharedTextureData();
......@@ -98,7 +100,7 @@ bool saveTextureData(const SharedTextureData &_textureData, const std::string &_
else if (fileEnding == "ppm") {
return saveTextureDataToPPM( _textureData, _filename );
} else {
error() << "file format of " << _filename << " not supported" << std::endl;
error() << "texture file format of " << _filename << " not supported" << std::endl;
}
return false;
......@@ -289,6 +291,204 @@ SharedTextureData loadTextureDataFromEXR(const std::string &_filename)
#endif
}
enum loadTextureDataFromPNM_InputDataFormat
{
PLAIN_TEXT_BITMAP, // used by P1
PLAIN_TEXT_DECIMAL, // used by P2 and P3
BINARY_PACKED, // used by P4
BINARY_BYTES, // used by P5 and P6
BINARY_WORDS // used by P5 and P6
};
void loadTextureDataFromPNM_skipWhitespace(std::istream& _in, uint_t _max = std::numeric_limits<std::streamsize>::max())
{
uint_t skipped = 0;
while(isspace(_in.peek()) && skipped < _max)
{
_in.ignore(1);
skipped++;
}
}
std::istream& loadTextureDataFromPNM_filterPNMComments(std::istream& _in)
{
loadTextureDataFromPNM_skipWhitespace(_in);
// When the stream starts with a #, throw away all following characters until the next newline
// TODO: this does not entirely conform to the PNM specs, where # characters may appear anywhere, not just at the beginning of fields
while(_in.peek() == '#')
{
_in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
loadTextureDataFromPNM_skipWhitespace(_in);
}
return _in;
}
SharedTextureData loadTextureDataFromPNM(const std::string &_filename)
{
std::ifstream fileStream( _filename, std::ifstream::in );
if (!fileStream.good()) {
error() << "could not open file " << _filename << std::endl;
return SharedTextureData();
}
SharedTextureData texture = SharedTextureData( new TextureData() );
// Read the PNM header
std::string header;
loadTextureDataFromPNM_filterPNMComments(fileStream) >> header;
// The header version determines the format of the data
loadTextureDataFromPNM_InputDataFormat inputDataFormat = BINARY_BYTES; // set it to something to prevent 'may be uninitialized' warnings (which can't occur here)
uint_t components;
if (header == "P1") { components = 1; inputDataFormat = PLAIN_TEXT_BITMAP; }
else if(header == "P2") { components = 1; inputDataFormat = PLAIN_TEXT_DECIMAL; }
else if(header == "P3") { components = 3; inputDataFormat = PLAIN_TEXT_DECIMAL; }
else if(header == "P4") { components = 1; inputDataFormat = BINARY_PACKED; }
else if(header == "P5") { components = 1; /* the data format will be determined later */ }
else if(header == "P6") { components = 3; /* the data format will be determined later */ }
else
{
error() << "could not load " << _filename << ": invalid header" << std::endl;
fileStream.close();
return SharedTextureData();
}
// Read the width and height of the image
uint_t width, height;
loadTextureDataFromPNM_filterPNMComments(fileStream) >> width;
loadTextureDataFromPNM_filterPNMComments(fileStream) >> height;
if(!fileStream.good() || width == 0 || height == 0)
{
error() << "could not load " << _filename << ": invalid image size" << std::endl;
fileStream.close();
return SharedTextureData();
}
// The max value is only present in the P2, P3, P5, P6 versions of the PNM format
uint_t maxValue = 1;
if(header == "P2" || header == "P3" || header == "P5" || header == "P6")
{
loadTextureDataFromPNM_filterPNMComments(fileStream) >> maxValue;
if(!fileStream.good() || maxValue == 0)
{
error() << "could not load " << _filename << ": invalid value range" << std::endl;
fileStream.close();
return SharedTextureData();
}
}
// The binary formats P5 and P6 use either bytes or words of data for each element, depending on the maxValue
if(header == "P5" || header == "P6")
{
if (maxValue < 256) { inputDataFormat = BINARY_BYTES; }
else if(maxValue < 65536) { inputDataFormat = BINARY_WORDS; }
else
{
error() << "could not load " << _filename << ": max value out of bounds" << std::endl;
fileStream.close();
return SharedTextureData();
}
}
// If the image data has maxValue of 255 or 1, we return a GL_UNSIGNED_BYTE texture,
// otherwise the values are normalized and returned as a GL_FLOAT texture
GLenum outputDataType = GL_FLOAT;
if(maxValue == 255 || maxValue == 1)
outputDataType = GL_UNSIGNED_BYTE;
// The data section is separated by a single whitespace
loadTextureDataFromPNM_skipWhitespace(fileStream, 1);
// Now, read in the data
// No comments (#) are expected during this section
unsigned char* data = new unsigned char[width * height * components * getGLTypeSize(outputDataType)];
uint_t elementsRead = 0;
while (fileStream.good() && elementsRead < (width * height * components))
{
// Read in one element
// The exact procedure is based on the input data format
uint_t elem;
if(inputDataFormat == PLAIN_TEXT_DECIMAL)
{
fileStream >> elem;
}
else if(inputDataFormat == BINARY_BYTES)
{
uint8_t byte;
fileStream.read((char*)&byte, 1);
elem = byte;
}
else if(inputDataFormat == BINARY_WORDS)
{
uint8_t word;
fileStream.read((char*)&word, 2);
elem = word;
}
else if(inputDataFormat == PLAIN_TEXT_BITMAP)
{
loadTextureDataFromPNM_skipWhitespace(fileStream);
char c;
fileStream.read(&c, 1);
if (c == '0') elem = 0;
else if(c == '1') elem = 1;
else break;
}
else if(inputDataFormat == BINARY_PACKED)
{
uint_t offset = elementsRead % 8;
uint8_t byte = fileStream.peek();
if(byte & 1<<(7-offset)) elem = 1;
else elem = 0;
if(offset == 7)
fileStream.ignore(1);
}
if(!fileStream.good()) break;
// Store the element in the data array
if(outputDataType == GL_UNSIGNED_BYTE)
{
if(maxValue == 1) elem *= 255; // Bitmap values are normalized to 0..255
data[elementsRead * getGLTypeSize(outputDataType)] = (GLubyte)elem;
}
else if(outputDataType == GL_FLOAT)
{
// Float values are normalized to 0..1
GLfloat normalized = (GLfloat)elem / (GLfloat)maxValue;
GLfloat* position = (GLfloat*)&data[elementsRead * getGLTypeSize(outputDataType)];
*position = normalized;
}
elementsRead++;
}
fileStream.close();
if(elementsRead != width * height * components)
{
error() << "could not load " << _filename << ": unexpected EOF" << std::endl;
return SharedTextureData();
}
texture->setData(data); // data will get deleted by the TextureData destructor!
texture->setDepth(1); // 2D so, depth is 1
texture->setHeight(height);
texture->setWidth(width);
#ifdef ACGL_OPENGL_ES
texture->setFormat(GL_RGB);
#else
texture->setFormat(components == 3 ? GL_RGB : GL_RED);
#endif
texture->setType(outputDataType);
return texture;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// library specific save
///////////////////////////////////////////////////////////////////////////////////////////////////
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment