]> Dogcows Code - chaz/yoink/blob - src/Moof/Image.cc
ee44dd75dcacb319f331411df02e9c28da92407b
[chaz/yoink] / src / Moof / Image.cc
1
2 /*******************************************************************************
3
4 Copyright (c) 2009, Charles McGarvey
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 *******************************************************************************/
28
29 #include <cstdio> // FILE
30 #include <cstring> // strncmp
31
32 #include <boost/algorithm/string.hpp>
33
34 #include <SDL/SDL.h>
35 #include <png.h>
36
37 #include "Core.hh"
38 #include "Error.hh"
39 #include "Image.hh"
40 #include "Log.hh"
41 #include "Manager.hh"
42
43
44 namespace Mf {
45
46
47 class Image::Impl : public Manager<Impl>
48 {
49 public:
50
51 explicit Impl() :
52 mContext(0),
53 mPixels(0) {}
54
55 ~Impl()
56 {
57 SDL_FreeSurface(mContext);
58 delete[] mPixels;
59 }
60
61
62 void flip()
63 {
64 unsigned char* pixels = (Uint8*)(mContext->pixels);
65
66 unsigned pitch = mContext->pitch;
67 unsigned char line[pitch];
68
69 int yBegin = 0;
70 int yEnd = mContext->h - 1;
71
72 if (SDL_MUSTLOCK(mContext)) SDL_LockSurface(mContext);
73 while (yBegin < yEnd)
74 {
75 memcpy(line, pixels + pitch * yBegin, pitch);
76 memcpy(pixels + pitch * yBegin, pixels + pitch * yEnd, pitch);
77 memcpy(pixels + pitch * yEnd, line, pitch);
78 yBegin++;
79 yEnd--;
80 }
81 if (SDL_MUSTLOCK(mContext)) SDL_UnlockSurface(mContext);
82 }
83
84 void setAsIcon() const
85 {
86 SDL_WM_SetIcon(mContext, 0);
87 }
88
89
90 bool init(const std::string& name, bool flipped = false)
91 {
92 std::string path = Image::getPath(name);
93
94 logInfo << "opening image file " << path << std::endl;
95 FILE* fp = fopen(path.c_str(), "rb");
96 if (!fp) return false;
97
98 png_byte signature[8];
99 size_t bytesRead;
100
101 png_infop pngInfo = 0;
102 png_infop pngInfoEnd = 0;
103 png_structp pngObj = 0;
104
105 int width;
106 int height;
107 int pitch;
108 int bpp;
109 int channels;
110
111 png_byte colors;
112 png_bytepp rows = 0;
113
114 png_textp texts = 0;
115 int numTexts;
116
117 logInfo("checking signature...");
118 bytesRead = fread(signature, 1, sizeof(signature), fp);
119 logInfo << "reading " << bytesRead << " bytes of signature" << std::endl;
120 if (bytesRead < sizeof(signature) ||
121 png_sig_cmp(signature, 0, sizeof(signature)) != 0) goto cleanup;
122
123 logInfo("creating png structures...");
124 pngObj = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
125 if (!pngObj) goto cleanup;
126
127 pngInfo = png_create_info_struct(pngObj);
128 if (!pngInfo) goto cleanup;
129
130 pngInfoEnd = png_create_info_struct(pngObj);
131 if (!pngInfoEnd) goto cleanup;
132
133 logInfo("setting up long jump...");
134 if (setjmp(png_jmpbuf(pngObj))) goto cleanup;
135
136 png_init_io(pngObj, fp);
137 png_set_sig_bytes(pngObj, sizeof(signature));
138 png_read_info(pngObj, pngInfo);
139
140 bpp = png_get_bit_depth(pngObj, pngInfo);
141 logInfo << "texture bpp: " << bpp << std::endl;
142 colors = png_get_color_type(pngObj, pngInfo);
143 switch (colors)
144 {
145 case PNG_COLOR_TYPE_PALETTE:
146 png_set_palette_to_rgb(pngObj);
147 break;
148
149 case PNG_COLOR_TYPE_GRAY:
150 if (bpp < 8) png_set_expand(pngObj);
151 break;
152
153 case PNG_COLOR_TYPE_GRAY_ALPHA:
154 png_set_gray_to_rgb(pngObj);
155 break;
156 }
157
158 if (bpp == 16) png_set_strip_16(pngObj);
159
160 png_read_update_info(pngObj, pngInfo);
161
162 bpp = png_get_bit_depth(pngObj, pngInfo);
163 channels = png_get_channels(pngObj, pngInfo);
164 mDepth = bpp * channels;
165
166 logInfo << "texture channels: " << channels << std::endl;
167 if (channels == 3) mColorMode = GL_RGB;
168 else mColorMode = GL_RGBA;
169
170 // read comments
171 png_get_text(pngObj, pngInfo, &texts, &numTexts);
172 logInfo << "num texts: " << numTexts << std::endl;
173 for (int i = 0; i < numTexts; ++i)
174 {
175 if (strncmp(texts[i].key, "TextureInfo", 11) == 0)
176 {
177 mComment = texts[i].text;
178 break;
179 }
180 }
181
182 width = png_get_image_width(pngObj, pngInfo);
183 height = png_get_image_height(pngObj, pngInfo);
184
185 pitch = png_get_rowbytes(pngObj, pngInfo);
186 mPixels = new char[width * pitch];
187
188 rows = new png_bytep[height];
189 if (flipped)
190 {
191 for (int i = 0; i < height; ++i)
192 {
193 rows[height - 1 - i] = (png_bytep)(mPixels + i * channels * width);
194 }
195 }
196 else
197 {
198 for (int i = 0; i < height; ++i)
199 {
200 rows[i] = (png_bytep)(mPixels + i * channels * width);
201 }
202 }
203
204 png_read_image(pngObj, rows);
205 png_read_end(pngObj, 0);
206
207 mContext = SDL_CreateRGBSurfaceFrom
208 (
209 mPixels,
210 width,
211 height,
212 bpp * channels,
213 pitch,
214 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
215 0x000000FF,
216 0x0000FF00,
217 0x00FF0000,
218 0xFF000000
219 #else
220 0xFF000000,
221 0x00FF0000,
222 0x0000FF00,
223 0x000000FF
224 #endif
225 );
226
227 cleanup:
228
229 logInfo("cleaning up...");
230 delete[] rows;
231 png_destroy_read_struct(pngObj ? &pngObj : 0,
232 pngInfo ? &pngInfo : 0,
233 pngInfoEnd ? &pngInfoEnd : 0);
234 fclose(fp);
235
236 return mContext;
237 }
238
239
240 SDL_Surface* mContext;
241 char* mPixels;
242
243 unsigned mDepth;
244 GLuint mColorMode;
245
246 std::string mComment;
247
248 private:
249
250 Backend mBackend;
251 };
252
253
254 Image::Image(const std::string& name) :
255 // pass through
256 mImpl(Image::Impl::getInstance(name)) {}
257
258
259 bool Image::isValid() const
260 {
261 return mImpl->mContext;
262 }
263
264 int Image::getWidth() const
265 {
266 return mImpl->mContext->w;
267 }
268
269 int Image::getHeight() const
270 {
271 return mImpl->mContext->h;
272 }
273
274 unsigned Image::getDepth() const
275 {
276 return mImpl->mDepth;
277 }
278
279 unsigned Image::getPitch() const
280 {
281 return mImpl->mContext->pitch;
282 }
283
284 GLuint Image::getMode() const
285 {
286 return mImpl->mColorMode;
287 }
288
289 std::string Image::getComment() const
290 {
291 return mImpl->mComment;
292 }
293
294 const char* Image::getPixels() const
295 {
296 return mImpl->mPixels;
297 }
298
299 char* Image::getPixels()
300 {
301 return mImpl->mPixels;
302 }
303
304
305 void Image::flip()
306 {
307 // pass through
308 mImpl->flip();
309 }
310
311 void Image::setAsIcon() const
312 {
313 // pass through
314 mImpl->setAsIcon();
315 }
316
317
318 std::string Image::getPath(const std::string& name)
319 {
320 if (boost::find_last(name, ".png"))
321 {
322 return Resource::getPath(name);
323 }
324 else
325 {
326 std::string path("images/");
327 path += name;
328 path += ".png";
329 return Resource::getPath(path);
330 }
331 }
332
333
334 } // namespace Mf
335
336 /** vim: set ts=4 sw=4 tw=80: *************************************************/
337
This page took 0.041755 seconds and 3 git commands to generate.