forked from Mirrorlandia_minetest/irrlicht
275 lines
5.9 KiB
C++
275 lines
5.9 KiB
C++
|
// Copyright (C) 2007-2012 Christian Stehno
|
||
|
// This file is part of the "Irrlicht Engine".
|
||
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||
|
|
||
|
#include "CImageLoaderPPM.h"
|
||
|
|
||
|
#ifdef _IRR_COMPILE_WITH_PPM_LOADER_
|
||
|
|
||
|
#include "IReadFile.h"
|
||
|
#include "CColorConverter.h"
|
||
|
#include "CImage.h"
|
||
|
#include "os.h"
|
||
|
#include "fast_atof.h"
|
||
|
#include "coreutil.h"
|
||
|
|
||
|
namespace irr
|
||
|
{
|
||
|
namespace video
|
||
|
{
|
||
|
|
||
|
|
||
|
//! constructor
|
||
|
CImageLoaderPPM::CImageLoaderPPM()
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
setDebugName("CImageLoaderPPM");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
//! returns true if the file maybe is able to be loaded by this class
|
||
|
//! based on the file extension (e.g. ".tga")
|
||
|
bool CImageLoaderPPM::isALoadableFileExtension(const io::path& filename) const
|
||
|
{
|
||
|
return core::hasFileExtension ( filename, "ppm", "pgm", "pbm" );
|
||
|
}
|
||
|
|
||
|
|
||
|
//! returns true if the file maybe is able to be loaded by this class
|
||
|
bool CImageLoaderPPM::isALoadableFileFormat(io::IReadFile* file) const
|
||
|
{
|
||
|
c8 id[2]={0};
|
||
|
file->read(&id, 2);
|
||
|
return (id[0]=='P' && id[1]>'0' && id[1]<'7');
|
||
|
}
|
||
|
|
||
|
|
||
|
//! creates a surface from the file
|
||
|
IImage* CImageLoaderPPM::loadImage(io::IReadFile* file) const
|
||
|
{
|
||
|
IImage* image;
|
||
|
|
||
|
if (file->getSize() < 12)
|
||
|
return 0;
|
||
|
|
||
|
c8 id[2];
|
||
|
file->read(&id, 2);
|
||
|
|
||
|
if (id[0]!='P' || id[1]<'1' || id[1]>'6')
|
||
|
return 0;
|
||
|
|
||
|
const u8 format = id[1] - '0';
|
||
|
const bool binary = format>3;
|
||
|
|
||
|
core::stringc token;
|
||
|
getNextToken(file, token);
|
||
|
const u32 width = core::strtoul10(token.c_str());
|
||
|
|
||
|
getNextToken(file, token);
|
||
|
const u32 height = core::strtoul10(token.c_str());
|
||
|
|
||
|
u8* data = 0;
|
||
|
const u32 size = width*height;
|
||
|
if (format==1 || format==4)
|
||
|
{
|
||
|
skipToNextToken(file); // go to start of data
|
||
|
|
||
|
const u32 bytesize = size/8+(size & 3)?1:0;
|
||
|
if (binary)
|
||
|
{
|
||
|
if (file->getSize()-file->getPos() < (long)bytesize)
|
||
|
return 0;
|
||
|
data = new u8[bytesize];
|
||
|
file->read(data, bytesize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (file->getSize()-file->getPos() < (long)(2*size)) // optimistic test
|
||
|
return 0;
|
||
|
data = new u8[bytesize];
|
||
|
memset(data, 0, bytesize);
|
||
|
u32 shift=0;
|
||
|
for (u32 i=0; i<size; ++i)
|
||
|
{
|
||
|
getNextToken(file, token);
|
||
|
if (token == "1")
|
||
|
data[i/8] |= (0x01 << shift);
|
||
|
if (++shift == 8)
|
||
|
shift=0;
|
||
|
}
|
||
|
}
|
||
|
image = new CImage(ECF_A1R5G5B5, core::dimension2d<u32>(width, height));
|
||
|
if (image)
|
||
|
CColorConverter::convert1BitTo16Bit(data, (s16*)image->getData(), width, height);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
getNextToken(file, token);
|
||
|
const u32 maxDepth = core::strtoul10(token.c_str());
|
||
|
if (maxDepth > 255) // no double bytes yet
|
||
|
return 0;
|
||
|
|
||
|
skipToNextToken(file); // go to start of data
|
||
|
|
||
|
if (format==2 || format==5)
|
||
|
{
|
||
|
if (binary)
|
||
|
{
|
||
|
if (file->getSize()-file->getPos() < (long)size)
|
||
|
return 0;
|
||
|
data = new u8[size];
|
||
|
file->read(data, size);
|
||
|
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
|
||
|
if (image)
|
||
|
{
|
||
|
u8* ptr = (u8*)image->getData();
|
||
|
for (u32 i=0; i<size; ++i)
|
||
|
{
|
||
|
*ptr++ = data[i];
|
||
|
*ptr++ = data[i];
|
||
|
*ptr++ = data[i];
|
||
|
*ptr++ = 255;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (file->getSize()-file->getPos() < (long)(2*size)) // optimistic test
|
||
|
return 0;
|
||
|
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
|
||
|
if (image)
|
||
|
{
|
||
|
u8* ptr = (u8*)image->getData();
|
||
|
for (u32 i=0; i<size; ++i)
|
||
|
{
|
||
|
getNextToken(file, token);
|
||
|
const u8 num = (u8)core::strtoul10(token.c_str());
|
||
|
*ptr++ = num;
|
||
|
*ptr++ = num;
|
||
|
*ptr++ = num;
|
||
|
*ptr++ = 255;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const u32 bytesize = 3*size;
|
||
|
if (binary)
|
||
|
{
|
||
|
if (file->getSize()-file->getPos() < (long)bytesize)
|
||
|
return 0;
|
||
|
data = new u8[bytesize];
|
||
|
file->read(data, bytesize);
|
||
|
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
|
||
|
if (image)
|
||
|
{
|
||
|
u8* ptr = (u8*)image->getData();
|
||
|
for (u32 i=0; i<size; ++i)
|
||
|
{
|
||
|
*ptr++ = data[3*i];
|
||
|
*ptr++ = data[3*i+1];
|
||
|
*ptr++ = data[3*i+2];
|
||
|
*ptr++ = 255;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (file->getSize()-file->getPos() < (long)(2*bytesize)) // optimistic test
|
||
|
return 0;
|
||
|
image = new CImage(ECF_A8R8G8B8, core::dimension2d<u32>(width, height));
|
||
|
if (image)
|
||
|
{
|
||
|
u8* ptr = (u8*)image->getData();
|
||
|
for (u32 i=0; i<size; ++i)
|
||
|
{
|
||
|
getNextToken(file, token);
|
||
|
*ptr++ = (u8)core::strtoul10(token.c_str());
|
||
|
getNextToken(file, token);
|
||
|
*ptr++ = (u8)core::strtoul10(token.c_str());
|
||
|
getNextToken(file, token);
|
||
|
*ptr++ = (u8)core::strtoul10(token.c_str());
|
||
|
*ptr++ = 255;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete [] data;
|
||
|
|
||
|
return image;
|
||
|
}
|
||
|
|
||
|
|
||
|
//! read the next token from file
|
||
|
void CImageLoaderPPM::getNextToken(io::IReadFile* file, core::stringc& token) const
|
||
|
{
|
||
|
token = "";
|
||
|
c8 c;
|
||
|
while(file->getPos()<file->getSize())
|
||
|
{
|
||
|
file->read(&c, 1);
|
||
|
if (c=='#')
|
||
|
{
|
||
|
while (c!='\n' && c!='\r' && (file->getPos()<file->getSize()))
|
||
|
file->read(&c, 1);
|
||
|
}
|
||
|
else if (!core::isspace(c))
|
||
|
{
|
||
|
token.append(c);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
while(file->getPos()<file->getSize())
|
||
|
{
|
||
|
file->read(&c, 1);
|
||
|
if (c=='#')
|
||
|
{
|
||
|
while (c!='\n' && c!='\r' && (file->getPos()<file->getSize()))
|
||
|
file->read(&c, 1);
|
||
|
}
|
||
|
else if (!core::isspace(c))
|
||
|
token.append(c);
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//! skip to next token (skip whitespace)
|
||
|
void CImageLoaderPPM::skipToNextToken(io::IReadFile* file) const
|
||
|
{
|
||
|
c8 c;
|
||
|
while(file->getPos()<file->getSize())
|
||
|
{
|
||
|
file->read(&c, 1);
|
||
|
if (c=='#')
|
||
|
{
|
||
|
while (c!='\n' && c!='\r' && (file->getPos()<file->getSize()))
|
||
|
file->read(&c, 1);
|
||
|
}
|
||
|
else if (!core::isspace(c))
|
||
|
{
|
||
|
file->seek(-1, true); // put back
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//! creates a loader which is able to load windows bitmaps
|
||
|
IImageLoader* createImageLoaderPPM()
|
||
|
{
|
||
|
return new CImageLoaderPPM;
|
||
|
}
|
||
|
|
||
|
|
||
|
} // end namespace video
|
||
|
} // end namespace irr
|
||
|
|
||
|
#endif
|
||
|
|