]> git.tdb.fi Git - libs/gui.git/blob - source/graphics/devil/devilloader.cpp
Make the image loading code more modular
[libs/gui.git] / source / graphics / devil / devilloader.cpp
1 #include <algorithm>
2 #include <IL/il.h>
3 #include "devilloader.h"
4
5 using namespace std;
6
7 namespace {
8
9 struct IOContext
10 {
11         Msp::IO::Base *io;
12         char *buffer;
13         unsigned buf_fill;
14         unsigned buf_max;
15         unsigned position;
16 };
17
18 unsigned char eof(void *handle)
19 {
20         return reinterpret_cast<IOContext *>(handle)->io->eof();
21 }
22
23 int get(void *handle)
24 {
25         IOContext *ctx = reinterpret_cast<IOContext *>(handle);
26         if(ctx->position<ctx->buf_fill)
27                 return ctx->buffer[ctx->position++];
28         else
29         {
30                 char c = ctx->io->get();
31                 if(ctx->position<ctx->buf_max)
32                         ctx->buffer[ctx->position] = c;
33                 ++ctx->position;
34                 return c;
35         }
36 }
37
38 int read(void *buf, unsigned size, unsigned count, void *handle)
39 {
40         IOContext *ctx = reinterpret_cast<IOContext *>(handle);
41         char *cbuf = reinterpret_cast<char *>(buf);
42         unsigned len = size*count;
43         unsigned ret = 0;
44
45         if(ctx->position<ctx->buf_fill)
46         {
47                 unsigned copy_len = min(ctx->buf_fill-ctx->position, len);
48                 copy(ctx->buffer+ctx->position, ctx->buffer+ctx->position+copy_len, cbuf);
49                 ctx->position += copy_len;
50                 ret += copy_len;
51                 cbuf += copy_len;
52                 len -= copy_len;
53         }
54
55         if(len)
56         {
57                 unsigned read_len = ctx->io->read(cbuf, len);
58                 if(ctx->position<ctx->buf_max)
59                 {
60                         unsigned copy_len = min(ctx->buf_max-ctx->position, read_len);
61                         copy(cbuf, cbuf+copy_len, ctx->buffer+ctx->position);
62                         ctx->buf_fill += copy_len;
63                 }
64                 ret += read_len;
65                 ctx->position += read_len;
66         }
67
68         return ret;
69 }
70
71 int seek(void *handle, int offset, int type)
72 {
73         IOContext *ctx = reinterpret_cast<IOContext *>(handle);
74
75         unsigned new_pos = ctx->position;
76         if(type==IL_SEEK_SET)
77                 new_pos = offset;
78         else if(type==IL_SEEK_CUR)
79                 new_pos += offset;
80         else
81                 return -1;
82
83         if(new_pos>ctx->buf_fill)
84                 new_pos = ctx->buf_fill;
85         ctx->position = new_pos;
86
87         return 0;
88 }
89
90 int tell(void *handle)
91 {
92         return reinterpret_cast<IOContext *>(handle)->position;
93 }
94
95 } // namespace
96
97
98 namespace Msp {
99 namespace Graphics {
100
101 DevilLoader::DevilLoader(IO::Base &i, const string &s):
102         io(i),
103         signature(s)
104 {
105         static bool il_init_done = false;
106
107         if(!il_init_done)
108         {
109                 ilInit();
110                 ilEnable(IL_ORIGIN_SET);
111                 ilOriginFunc(IL_ORIGIN_LOWER_LEFT);
112                 il_init_done = true;
113         }
114
115         ilGenImages(1, &id);
116 }
117
118 DevilLoader::~DevilLoader()
119 {
120         ilDeleteImages(1, &id);
121 }
122
123 bool DevilLoader::detect(const string &sig)
124 {
125         unsigned type = ilDetermineTypeL(sig.data(), sig.size());
126         return type!=IL_TYPE_UNKNOWN;
127 }
128
129 void DevilLoader::load(Image::Data &data)
130 {
131         IOContext ctx;
132         ctx.io = &io;
133         char buffer[4096];
134         ctx.buffer = buffer;
135         ctx.buf_max = sizeof(buffer);
136         copy(signature.begin(), signature.end(), buffer);
137         ctx.buf_fill = signature.size();
138         ctx.position = 0;
139
140         ilSetRead(0, 0, eof, get, read, seek, tell);
141         ilBindImage(id);
142         ilLoadF(IL_TYPE_UNKNOWN, &ctx);
143
144         switch(ilGetInteger(IL_IMAGE_FORMAT))
145         {
146         case IL_COLOR_INDEX:     data.fmt = COLOR_INDEX; break;
147         case IL_LUMINANCE:       data.fmt = LUMINANCE; break;
148         case IL_LUMINANCE_ALPHA: data.fmt = LUMINANCE_ALPHA; break;
149         case IL_RGB:             data.fmt = RGB; break;
150         case IL_RGBA:            data.fmt = RGBA; break;
151         case IL_BGR:             data.fmt = BGR; break;
152         case IL_BGRA:            data.fmt = BGRA; break;
153         default: throw unsupported_image_format("unknown pixel format");
154         }
155
156         data.width = ilGetInteger(IL_IMAGE_WIDTH);
157         data.height = ilGetInteger(IL_IMAGE_HEIGHT);
158         unsigned data_size = data.width*data.height*ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
159         data.data = new char[data_size];
160         ILubyte *il_data = ilGetData();
161         copy(il_data, il_data+data_size, data.data);
162
163         ilBindImage(0);
164         ilResetRead();
165 }
166
167 } // namespace Graphics
168 } // namespace Msp