#include <algorithm>
+#include <msp/strings/format.h>
#include <IL/il.h>
#include "devilloader.h"
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<IOContext *>(handle)->io->eof();
+ return reinterpret_cast<Msp::IO::Seekable *>(handle)->eof();
}
int get(void *handle)
{
- IOContext *ctx = reinterpret_cast<IOContext *>(handle);
- if(ctx->position<ctx->buf_fill)
- return ctx->buffer[ctx->position++];
- else
- {
- char c = ctx->io->get();
- if(ctx->position<ctx->buf_max)
- ctx->buffer[ctx->position] = c;
- ++ctx->position;
- return c;
- }
+ return reinterpret_cast<Msp::IO::Seekable *>(handle)->get();
}
int read(void *buf, unsigned size, unsigned count, void *handle)
{
- IOContext *ctx = reinterpret_cast<IOContext *>(handle);
+ Msp::IO::Seekable *io = reinterpret_cast<Msp::IO::Seekable *>(handle);
char *cbuf = reinterpret_cast<char *>(buf);
- unsigned len = size*count;
- unsigned ret = 0;
-
- if(ctx->position<ctx->buf_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 i = 0;
+ for(; i<count; ++i)
{
- unsigned read_len = ctx->io->read(cbuf, len);
- if(ctx->position<ctx->buf_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;
+ unsigned len = io->read(cbuf, size);
+ cbuf += size;
+ if(len<size)
+ break;
}
-
- return ret;
+ return i;
}
-int seek(void *handle, int offset, int type)
+int seek(void *handle, int offset, int il_type)
{
- IOContext *ctx = reinterpret_cast<IOContext *>(handle);
-
- unsigned new_pos = ctx->position;
- if(type==IL_SEEK_SET)
- new_pos = offset;
- else if(type==IL_SEEK_CUR)
- new_pos += offset;
+ Msp::IO::SeekType type;
+ if(il_type==IL_SEEK_SET)
+ type = Msp::IO::S_BEG;
+ else if(il_type==IL_SEEK_CUR)
+ type = Msp::IO::S_CUR;
+ else if(il_type==IL_SEEK_END)
+ type = Msp::IO::S_END;
else
return -1;
- if(new_pos>ctx->buf_fill)
- new_pos = ctx->buf_fill;
- ctx->position = new_pos;
+ reinterpret_cast<Msp::IO::Seekable *>(handle)->seek(offset, type);
return 0;
}
int tell(void *handle)
{
- return reinterpret_cast<IOContext *>(handle)->position;
+ return reinterpret_cast<Msp::IO::Seekable *>(handle)->tell();
+}
+
+std::string error_string(ILenum err)
+{
+ switch(err)
+ {
+ case IL_FORMAT_NOT_SUPPORTED: return "Format not supported";
+ case IL_INTERNAL_ERROR: return "DevIL internal error";
+ case IL_INVALID_FILE_HEADER: return "Invalid file header";
+ case IL_FILE_READ_ERROR: return "File read error";
+ case IL_LIB_PNG_ERROR: return "LibPNG error";
+ case IL_LIB_JPEG_ERROR: return "LibJPEG error";
+ default: return Msp::format("Unknown error (%04X)", err);
+ }
}
} // namespace
namespace Msp {
namespace Graphics {
-DevilLoader::DevilLoader(IO::Base &i, const string &s):
- io(i),
- signature(s)
+DevilLoader::DevilLoader(IO::Seekable &i):
+ io(i)
{
static bool il_init_done = false;
return type!=IL_TYPE_UNKNOWN;
}
-void DevilLoader::load(Image::Data &data)
+void DevilLoader::load_headers_(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);
+
+ ilGetError();
+ if(!ilLoadF(IL_TYPE_UNKNOWN, &io))
+ throw bad_image_data(error_string(ilGetError()));
switch(ilGetInteger(IL_IMAGE_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);
+ data.stride = data.width*ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
ilBindImage(0);
ilResetRead();
}
+void DevilLoader::load_pixels_(Image::Data &data)
+{
+ ilBindImage(id);
+
+ unsigned data_size = data.stride*data.height;
+ ILubyte *il_data = ilGetData();
+ copy(il_data, il_data+data_size, data.pixels);
+
+ ilBindImage(0);
+}
+
} // namespace Graphics
} // namespace Msp