]> Dogcows Code - chaz/yoink/blob - src/Moof/Image.cc
54e9972d6264be65021286e3e2068340794527f7
[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 bool init(const std::string& name, bool flipped = false)
74 {
75 std::string path = Image::getPath(name);
76
77 logInfo << "opening image file " << path << std::endl;
78 FILE* fp = fopen(path.c_str(), "rb");
79 if (!fp) return false;
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 return mContext;
222 }
223
224
225 SDL_Surface* mContext;
226 char* mPixels;
227
228 unsigned mDepth;
229 GLuint mColorMode;
230
231 std::string mComment;
232
233 private:
234
235 Backend mBackend;
236 };
237
238
239 Image::Image(const std::string& name) :
240 // pass through
241 mImpl(Image::Impl::getInstance(name)) {}
242
243
244 bool Image::isValid() const
245 {
246 return mImpl->mContext;
247 }
248
249 int Image::getWidth() const
250 {
251 return mImpl->mContext->w;
252 }
253
254 int Image::getHeight() const
255 {
256 return mImpl->mContext->h;
257 }
258
259 unsigned Image::getDepth() const
260 {
261 return mImpl->mDepth;
262 }
263
264 unsigned Image::getPitch() const
265 {
266 return mImpl->mContext->pitch;
267 }
268
269 GLuint Image::getMode() const
270 {
271 return mImpl->mColorMode;
272 }
273
274 std::string Image::getComment() const
275 {
276 return mImpl->mComment;
277 }
278
279 const char* Image::getPixels() const
280 {
281 return mImpl->mPixels;
282 }
283
284 char* Image::getPixels()
285 {
286 return mImpl->mPixels;
287 }
288
289
290 void Image::flip()
291 {
292 // pass through
293 mImpl->flip();
294 }
295
296 void Image::setAsIcon() const
297 {
298 // pass through
299 mImpl->setAsIcon();
300 }
301
302
303 std::string Image::getPath(const std::string& name)
304 {
305 if (boost::find_last(name, ".png"))
306 {
307 return Resource::getPath(name);
308 }
309 else
310 {
311 std::string path("images/");
312 path += name;
313 path += ".png";
314 return Resource::getPath(path);
315 }
316 }
317
318
319 } // namespace Mf
320
This page took 0.046238 seconds and 3 git commands to generate.