]> git.tdb.fi Git - libs/gui.git/blobdiff - source/graphics/devil/devilloader.cpp
Make the image loading code more modular
[libs/gui.git] / source / graphics / devil / devilloader.cpp
diff --git a/source/graphics/devil/devilloader.cpp b/source/graphics/devil/devilloader.cpp
new file mode 100644 (file)
index 0000000..23b04b3
--- /dev/null
@@ -0,0 +1,168 @@
+#include <algorithm>
+#include <IL/il.h>
+#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<IOContext *>(handle)->io->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;
+       }
+}
+
+int read(void *buf, unsigned size, unsigned count, void *handle)
+{
+       IOContext *ctx = reinterpret_cast<IOContext *>(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 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;
+       }
+
+       return ret;
+}
+
+int seek(void *handle, int offset, int 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;
+       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<IOContext *>(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