]> Dogcows Code - chaz/yoink/blob - src/moof/image.cc
f2f0c09294654145b89e068ebc34a0384c8d8ccf
[chaz/yoink] / src / moof / image.cc
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
9 *
10 **************************************************************************/
11
12 #include <cstdio> // FILE
13 #include <cstring> // strncmp
14
15 #include <boost/algorithm/string.hpp>
16
17 #include <png.h>
18 #include <SDL/SDL.h>
19
20 #include "backend.hh"
21 #include "image.hh"
22 #include "log.hh"
23 #include "manager.hh"
24
25
26 namespace moof {
27
28
29 class image::impl : public manager<impl>
30 {
31 public:
32
33 explicit impl() :
34 context_(0),
35 pixels_(0) {}
36
37 ~impl()
38 {
39 SDL_FreeSurface(context_);
40 delete[] pixels_;
41 }
42
43
44 void flip()
45 {
46 unsigned char* pixels = (Uint8*)(context_->pixels);
47
48 unsigned pitch = context_->pitch;
49 unsigned char line[pitch];
50
51 int yBegin = 0;
52 int yEnd = context_->h - 1;
53
54 if (SDL_MUSTLOCK(context_)) SDL_LockSurface(context_);
55 while (yBegin < yEnd)
56 {
57 memcpy(line, pixels + pitch * yBegin, pitch);
58 memcpy(pixels + pitch * yBegin, pixels + pitch * yEnd, pitch);
59 memcpy(pixels + pitch * yEnd, line, pitch);
60 yBegin++;
61 yEnd--;
62 }
63 if (SDL_MUSTLOCK(context_)) SDL_UnlockSurface(context_);
64 }
65
66 void set_as_icon() const
67 {
68 SDL_WM_SetIcon(context_, 0);
69 }
70
71
72 void init(const std::string& name, bool flipped = false)
73 {
74 std::string path(name);
75
76 FILE* fp = image::open_file(path);
77 if (!fp) return;
78
79 png_byte signature[8];
80 size_t bytesRead;
81
82 png_infop pngInfo = 0;
83 png_infop pngInfoEnd = 0;
84 png_structp pngObj = 0;
85
86 int width;
87 int height;
88 int pitch;
89 int bpp;
90 int channels;
91
92 png_byte colors;
93 png_bytepp rows = 0;
94
95 png_textp texts = 0;
96 int nutext_s;
97
98 bytesRead = fread(signature, 1, sizeof(signature), fp);
99 if (bytesRead < sizeof(signature) ||
100 png_sig_cmp(signature, 0, sizeof(signature)) != 0) goto cleanup;
101
102 pngObj = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
103 if (!pngObj) goto cleanup;
104
105 pngInfo = png_create_info_struct(pngObj);
106 if (!pngInfo) goto cleanup;
107
108 pngInfoEnd = png_create_info_struct(pngObj);
109 if (!pngInfoEnd) goto cleanup;
110
111 if (setjmp(png_jmpbuf(pngObj))) goto cleanup;
112
113 png_init_io(pngObj, fp);
114 png_set_sig_bytes(pngObj, sizeof(signature));
115 png_read_info(pngObj, pngInfo);
116
117 bpp = png_get_bit_depth(pngObj, pngInfo);
118 colors = png_get_color_type(pngObj, pngInfo);
119 switch (colors)
120 {
121 case PNG_COLOR_TYPE_PALETTE:
122 png_set_palette_to_rgb(pngObj);
123 break;
124
125 case PNG_COLOR_TYPE_GRAY:
126 if (bpp < 8) png_set_expand(pngObj);
127 break;
128
129 case PNG_COLOR_TYPE_GRAY_ALPHA:
130 png_set_gray_to_rgb(pngObj);
131 break;
132 }
133
134 if (bpp == 16) png_set_strip_16(pngObj);
135
136 png_read_update_info(pngObj, pngInfo);
137
138 bpp = png_get_bit_depth(pngObj, pngInfo);
139 channels = png_get_channels(pngObj, pngInfo);
140 depth_ = bpp * channels;
141
142 if (channels == 3) color_mode_ = GL_RGB;
143 else color_mode_ = GL_RGBA;
144
145 // read comments
146 png_get_text(pngObj, pngInfo, &texts, &nutext_s);
147 for (int i = 0; i < nutext_s; ++i)
148 {
149 if (strncmp(texts[i].key, "TextureInfo", 11) == 0)
150 {
151 comment_ = texts[i].text;
152 break;
153 }
154 }
155
156 width = png_get_image_width(pngObj, pngInfo);
157 height = png_get_image_height(pngObj, pngInfo);
158
159 pitch = png_get_rowbytes(pngObj, pngInfo);
160 pixels_ = new char[width * pitch];
161
162 rows = new png_bytep[height];
163 if (flipped)
164 {
165 for (int i = 0; i < height; ++i)
166 {
167 rows[height - 1 - i] = (png_bytep)(pixels_ +
168 i * channels * width);
169 }
170 }
171 else
172 {
173 for (int i = 0; i < height; ++i)
174 {
175 rows[i] = (png_bytep)(pixels_ + i * channels * width);
176 }
177 }
178
179 png_read_image(pngObj, rows);
180 png_read_end(pngObj, 0);
181
182 context_ = SDL_CreateRGBSurfaceFrom
183 (
184 pixels_,
185 width,
186 height,
187 bpp * channels,
188 pitch,
189 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
190 0x000000FF,
191 0x0000FF00,
192 0x00FF0000,
193 0xFF000000
194 #else
195 0xFF000000,
196 0x00FF0000,
197 0x0000FF00,
198 0x000000FF
199 #endif
200 );
201
202 cleanup:
203
204 delete[] rows;
205 png_destroy_read_struct(pngObj ? &pngObj : 0,
206 pngInfo ? &pngInfo : 0,
207 pngInfoEnd ? &pngInfoEnd : 0);
208 fclose(fp);
209 }
210
211
212 SDL_Surface* context_;
213 char* pixels_;
214
215 unsigned depth_;
216 GLuint color_mode_;
217
218 std::string comment_;
219
220 private:
221
222 backend backend_;
223 };
224
225
226 image::image(const std::string& name) :
227 // pass through
228 impl_(image::impl::instance(name)) {}
229
230
231 bool image::is_valid() const
232 {
233 return impl_->context_;
234 }
235
236 int image::width() const
237 {
238 return impl_->context_->w;
239 }
240
241 int image::height() const
242 {
243 return impl_->context_->h;
244 }
245
246 unsigned image::depth() const
247 {
248 return impl_->depth_;
249 }
250
251 unsigned image::pitch() const
252 {
253 return impl_->context_->pitch;
254 }
255
256 GLuint image::mode() const
257 {
258 return impl_->color_mode_;
259 }
260
261 std::string image::comment() const
262 {
263 return impl_->comment_;
264 }
265
266 const char* image::pixels() const
267 {
268 return impl_->pixels_;
269 }
270
271 char* image::pixels()
272 {
273 return impl_->pixels_;
274 }
275
276
277 void image::flip()
278 {
279 // pass through
280 impl_->flip();
281 }
282
283 void image::set_as_icon() const
284 {
285 // pass through
286 impl_->set_as_icon();
287 }
288
289
290 bool image::find_path(std::string& name)
291 {
292 return resource::find_path(name, "images/", "png");
293 }
294
295 FILE* image::open_file(std::string& name)
296 {
297 return resource::open_file(name, "images/", "png");
298 }
299
300
301 } // namespace moof
302
This page took 0.040517 seconds and 3 git commands to generate.