X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fgraphics%2Fdevil%2Fdevilloader.cpp;fp=source%2Fgraphics%2Fdevil%2Fdevilloader.cpp;h=23b04b32d64819bd839bc317ad3c81995c866d53;hb=cfd3548464e6424fc9decf0539d6cd04b031ba10;hp=0000000000000000000000000000000000000000;hpb=12df88ecf9787f4ed59051646775165b74301cf0;p=libs%2Fgui.git diff --git a/source/graphics/devil/devilloader.cpp b/source/graphics/devil/devilloader.cpp new file mode 100644 index 0000000..23b04b3 --- /dev/null +++ b/source/graphics/devil/devilloader.cpp @@ -0,0 +1,168 @@ +#include +#include +#include "devilloader.h" + +using namespace std; + +namespace { + +struct IOContext +{ + Msp::IO::Base *io; + char *buffer; + unsigned buf_fill; + unsigned buf_max; + unsigned position; +}; + +unsigned char eof(void *handle) +{ + return reinterpret_cast(handle)->io->eof(); +} + +int get(void *handle) +{ + IOContext *ctx = reinterpret_cast(handle); + if(ctx->positionbuf_fill) + return ctx->buffer[ctx->position++]; + else + { + char c = ctx->io->get(); + if(ctx->positionbuf_max) + ctx->buffer[ctx->position] = c; + ++ctx->position; + return c; + } +} + +int read(void *buf, unsigned size, unsigned count, void *handle) +{ + IOContext *ctx = reinterpret_cast(handle); + char *cbuf = reinterpret_cast(buf); + unsigned len = size*count; + unsigned ret = 0; + + if(ctx->positionbuf_fill) + { + unsigned copy_len = min(ctx->buf_fill-ctx->position, len); + copy(ctx->buffer+ctx->position, ctx->buffer+ctx->position+copy_len, cbuf); + ctx->position += copy_len; + ret += copy_len; + cbuf += copy_len; + len -= copy_len; + } + + if(len) + { + unsigned read_len = ctx->io->read(cbuf, len); + if(ctx->positionbuf_max) + { + unsigned copy_len = min(ctx->buf_max-ctx->position, read_len); + copy(cbuf, cbuf+copy_len, ctx->buffer+ctx->position); + ctx->buf_fill += copy_len; + } + ret += read_len; + ctx->position += read_len; + } + + return ret; +} + +int seek(void *handle, int offset, int type) +{ + IOContext *ctx = reinterpret_cast(handle); + + unsigned new_pos = ctx->position; + if(type==IL_SEEK_SET) + new_pos = offset; + else if(type==IL_SEEK_CUR) + new_pos += offset; + else + return -1; + + if(new_pos>ctx->buf_fill) + new_pos = ctx->buf_fill; + ctx->position = new_pos; + + return 0; +} + +int tell(void *handle) +{ + return reinterpret_cast(handle)->position; +} + +} // namespace + + +namespace Msp { +namespace Graphics { + +DevilLoader::DevilLoader(IO::Base &i, const string &s): + io(i), + signature(s) +{ + static bool il_init_done = false; + + if(!il_init_done) + { + ilInit(); + ilEnable(IL_ORIGIN_SET); + ilOriginFunc(IL_ORIGIN_LOWER_LEFT); + il_init_done = true; + } + + ilGenImages(1, &id); +} + +DevilLoader::~DevilLoader() +{ + ilDeleteImages(1, &id); +} + +bool DevilLoader::detect(const string &sig) +{ + unsigned type = ilDetermineTypeL(sig.data(), sig.size()); + return type!=IL_TYPE_UNKNOWN; +} + +void DevilLoader::load(Image::Data &data) +{ + IOContext ctx; + ctx.io = &io; + char buffer[4096]; + ctx.buffer = buffer; + ctx.buf_max = sizeof(buffer); + copy(signature.begin(), signature.end(), buffer); + ctx.buf_fill = signature.size(); + ctx.position = 0; + + ilSetRead(0, 0, eof, get, read, seek, tell); + ilBindImage(id); + ilLoadF(IL_TYPE_UNKNOWN, &ctx); + + switch(ilGetInteger(IL_IMAGE_FORMAT)) + { + case IL_COLOR_INDEX: data.fmt = COLOR_INDEX; break; + case IL_LUMINANCE: data.fmt = LUMINANCE; break; + case IL_LUMINANCE_ALPHA: data.fmt = LUMINANCE_ALPHA; break; + case IL_RGB: data.fmt = RGB; break; + case IL_RGBA: data.fmt = RGBA; break; + case IL_BGR: data.fmt = BGR; break; + case IL_BGRA: data.fmt = BGRA; break; + default: throw unsupported_image_format("unknown pixel format"); + } + + data.width = ilGetInteger(IL_IMAGE_WIDTH); + data.height = ilGetInteger(IL_IMAGE_HEIGHT); + unsigned data_size = data.width*data.height*ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL); + data.data = new char[data_size]; + ILubyte *il_data = ilGetData(); + copy(il_data, il_data+data_size, data.data); + + ilBindImage(0); + ilResetRead(); +} + +} // namespace Graphics +} // namespace Msp