2237c88bf1bb059b208907c41e48ca3bb590d12e
[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 "Error.hh"
22 #include "Image.hh"
23 #include "Log.hh"
24 #include "Manager.hh"
25
26
27 namespace Mf {
28
29
30 class Image::Impl : public Manager<Impl>
31 {
32 public:
33
34 explicit Impl() :
35 mContext(0),
36 mPixels(0) {}
37
38 ~Impl()
39 {
40 SDL_FreeSurface(mContext);
41 delete[] mPixels;
42 }
43
44
45 void flip()
46 {
47 unsigned char* pixels = (Uint8*)(mContext->pixels);
48
49 unsigned pitch = mContext->pitch;
50 unsigned char line[pitch];
51
52 int yBegin = 0;
53 int yEnd = mContext->h - 1;
54
55 if (SDL_MUSTLOCK(mContext)) SDL_LockSurface(mContext);
56 while (yBegin < yEnd)
57 {
58 memcpy(line, pixels + pitch * yBegin, pitch);
59 memcpy(pixels + pitch * yBegin, pixels + pitch * yEnd, pitch);
60 memcpy(pixels + pitch * yEnd, line, pitch);
61 yBegin++;
62 yEnd--;
63 }
64 if (SDL_MUSTLOCK(mContext)) SDL_UnlockSurface(mContext);
65 }
66
67 void setAsIcon() const
68 {
69 SDL_WM_SetIcon(mContext, 0);
70 }
71
72
73 void init(const std::string& name, bool flipped = false)
74 {
75 std::string path(name);
76
77 logInfo << "opening image file " << path << std::endl;
78 FILE* fp = Image::openFile(path);
79 if (!fp) return;
80
81 png_byte signature[8];
82 size_t bytesRead;
83
84 png_infop pngInfo = 0;
85 png_infop pngInfoEnd = 0;
86 png_structp pngObj = 0;
87
88 int width;
89 int height;
90 int pitch;
91 int bpp;
92 int channels;
93
94 png_byte colors;
95 png_bytepp rows = 0;
96
97 png_textp texts = 0;
98 int numTexts;
99
100 logInfo("checking signature...");
101 bytesRead = fread(signature, 1, sizeof(signature), fp);
102 logInfo << "reading " << bytesRead << " bytes of signature"
103 << std::endl;
104 if (bytesRead < sizeof(signature) ||
105 png_sig_cmp(signature, 0, sizeof(signature)) != 0) goto cleanup;
106
107 logInfo("creating png structures...");
108 pngObj = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
109 if (!pngObj) goto cleanup;
110
111 pngInfo = png_create_info_struct(pngObj);
112 if (!pngInfo) goto cleanup;
113
114 pngInfoEnd = png_create_info_struct(pngObj);
115 if (!pngInfoEnd) goto cleanup;
116
117 logInfo("setting up long jump...");
118 if (setjmp(png_jmpbuf(pngObj))) goto cleanup;
119
120 png_init_io(pngObj, fp);
121 png_set_sig_bytes(pngObj, sizeof(signature));
122 png_read_info(pngObj, pngInfo);
123
124 bpp = png_get_bit_depth(pngObj, pngInfo);
125 logInfo << "texture bpp: " << bpp << std::endl;
126 colors = png_get_color_type(pngObj, pngInfo);
127 switch (colors)
128 {
129 case PNG_COLOR_TYPE_PALETTE:
130 png_set_palette_to_rgb(pngObj);
131 break;
132
133 case PNG_COLOR_TYPE_GRAY:
134 if (bpp < 8) png_set_expand(pngObj);
135 break;
136
137 case PNG_COLOR_TYPE_GRAY_ALPHA:
138 png_set_gray_to_rgb(pngObj);
139 break;
140 }
141
142 if (bpp == 16) png_set_strip_16(pngObj);
143
144 png_read_update_info(pngObj, pngInfo);
145
146 bpp = png_get_bit_depth(pngObj, pngInfo);
147 channels = png_get_channels(pngObj, pngInfo);
148 mDepth = bpp * channels;
149
150 logInfo << "texture channels: " << channels << std::endl;
151 if (channels == 3) mColorMode = GL_RGB;
152 else mColorMode = GL_RGBA;
153
154 // read comments
155 png_get_text(pngObj, pngInfo, &texts, &numTexts);
156 logInfo << "num texts: " << numTexts << std::endl;
157 for (int i = 0; i < numTexts; ++i)
158 {
159 if (strncmp(texts[i].key, "TextureInfo", 11) == 0)
160 {
161 mComment = texts[i].text;
162 break;
163 }
164 }
165
166 width = png_get_image_width(pngObj, pngInfo);
167 height = png_get_image_height(pngObj, pngInfo);
168
169 pitch = png_get_rowbytes(pngObj, pngInfo);
170 mPixels = new char[width * pitch];
171
172 rows = new png_bytep[height];
173 if (flipped)
174 {
175 for (int i = 0; i < height; ++i)
176 {
177 rows[height - 1 - i] = (png_bytep)(mPixels +
178 i * channels * width);
179 }
180 }
181 else
182 {
183 for (int i = 0; i < height; ++i)
184 {
185 rows[i] = (png_bytep)(mPixels + i * channels * width);
186 }
187 }
188
189 png_read_image(pngObj, rows);
190 png_read_end(pngObj, 0);
191
192 mContext = SDL_CreateRGBSurfaceFrom
193 (
194 mPixels,
195 width,
196 height,
197 bpp * channels,
198 pitch,
199 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
200 0x000000FF,
201 0x0000FF00,
202 0x00FF0000,
203 0xFF000000
204 #else
205 0xFF000000,
206 0x00FF0000,
207 0x0000FF00,
208 0x000000FF
209 #endif
210 );
211
212 cleanup:
213
214 logInfo("cleaning up...");
215 delete[] rows;
216 png_destroy_read_struct(pngObj ? &pngObj : 0,
217 pngInfo ? &pngInfo : 0,
218 pngInfoEnd ? &pngInfoEnd : 0);
219 fclose(fp);
220 }
221
222
223 SDL_Surface* mContext;
224 char* mPixels;
225
226 unsigned mDepth;
227 GLuint mColorMode;
228
229 std::string mComment;
230
231 private:
232
233 Backend mBackend;
234 };
235
236
237 Image::Image(const std::string& name) :
238 // pass through
239 mImpl(Image::Impl::getInstance(name)) {}
240
241
242 bool Image::isValid() const
243 {
244 return mImpl->mContext;
245 }
246
247 int Image::getWidth() const
248 {
249 return mImpl->mContext->w;
250 }
251
252 int Image::getHeight() const
253 {
254 return mImpl->mContext->h;
255 }
256
257 unsigned Image::getDepth() const
258 {
259 return mImpl->mDepth;
260 }
261
262 unsigned Image::getPitch() const
263 {
264 return mImpl->mContext->pitch;
265 }
266
267 GLuint Image::getMode() const
268 {
269 return mImpl->mColorMode;
270 }
271
272 std::string Image::getComment() const
273 {
274 return mImpl->mComment;
275 }
276
277 const char* Image::getPixels() const
278 {
279 return mImpl->mPixels;
280 }
281
282 char* Image::getPixels()
283 {
284 return mImpl->mPixels;
285 }
286
287
288 void Image::flip()
289 {
290 // pass through
291 mImpl->flip();
292 }
293
294 void Image::setAsIcon() const
295 {
296 // pass through
297 mImpl->setAsIcon();
298 }
299
300
301 bool Image::getPath(std::string& name)
302 {
303 return Resource::getPath(name, "images/", "png");
304 }
305
306 FILE* Image::openFile(std::string& name)
307 {
308 return Resource::openFile(name, "images/", "png");
309 }
310
311
312 } // namespace Mf
313
This page took 0.041346 seconds and 3 git commands to generate.