cade lab fixes
[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 <SDL/SDL.h>
33 #include <png.h>
34
35 #include "Core.hh"
36 #include "Error.hh"
37 #include "Image.hh"
38 #include "Library.hh"
39 #include "Log.hh"
40
41
42 namespace Mf {
43
44
45 class Image::Impl : public Library<Impl>
46 {
47 public:
48
49 explicit Impl(const std::string& name, bool flipped = false) :
50 Library<Impl>(name),
51 mContext(0),
52 mPixels(0)
53 {
54 init(getName(), flipped);
55 }
56
57 ~Impl()
58 {
59 SDL_FreeSurface(mContext);
60 delete[] mPixels;
61 }
62
63
64 void flip()
65 {
66 unsigned char* pixels = (Uint8*)(mContext->pixels);
67
68 unsigned pitch = mContext->pitch;
69 unsigned char line[pitch];
70
71 int yBegin = 0;
72 int yEnd = mContext->h - 1;
73
74 if (SDL_MUSTLOCK(mContext)) SDL_LockSurface(mContext);
75 while (yBegin < yEnd)
76 {
77 memcpy(line, pixels + pitch * yBegin, pitch);
78 memcpy(pixels + pitch * yBegin, pixels + pitch * yEnd, pitch);
79 memcpy(pixels + pitch * yEnd, line, pitch);
80 yBegin++;
81 yEnd--;
82 }
83 if (SDL_MUSTLOCK(mContext)) SDL_UnlockSurface(mContext);
84 }
85
86 void setAsIcon() const
87 {
88 SDL_WM_SetIcon(mContext, 0);
89 }
90
91
92 SDL_Surface* mContext;
93 char* mPixels;
94
95 unsigned mDepth;
96 GLuint mColorMode;
97
98 std::string mComment;
99
100
101 private:
102
103 Backend mBackend;
104
105 bool init(const std::string& filePath, bool flipped)
106 {
107 logInfo("opening image file...");
108 FILE* fp = fopen(filePath.c_str(), "rb");
109 if (!fp) return false;
110
111 png_byte signature[8];
112 size_t bytesRead;
113
114 png_infop pngInfo = 0;
115 png_infop pngInfoEnd = 0;
116 png_structp pngObj = 0;
117
118 int width;
119 int height;
120 int pitch;
121 int bpp;
122 int channels;
123
124 png_byte colors;
125 png_bytepp rows = 0;
126
127 png_textp texts = 0;
128 int numTexts;
129
130 logInfo("checking signature...");
131 bytesRead = fread(signature, 1, sizeof(signature), fp);
132 logInfo << "reading " << bytesRead << " bytes of signature" << std::endl;
133 if (bytesRead < sizeof(signature) ||
134 png_sig_cmp(signature, 0, sizeof(signature)) != 0) goto cleanup;
135
136 logInfo("creating png structures...");
137 pngObj = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
138 if (!pngObj) goto cleanup;
139
140 pngInfo = png_create_info_struct(pngObj);
141 if (!pngInfo) goto cleanup;
142
143 pngInfoEnd = png_create_info_struct(pngObj);
144 if (!pngInfoEnd) goto cleanup;
145
146 logInfo("setting up long jump...");
147 if (setjmp(png_jmpbuf(pngObj))) goto cleanup;
148
149 png_init_io(pngObj, fp);
150 png_set_sig_bytes(pngObj, sizeof(signature));
151 png_read_info(pngObj, pngInfo);
152
153 bpp = png_get_bit_depth(pngObj, pngInfo);
154 logInfo << "texture bpp: " << bpp << std::endl;
155 colors = png_get_color_type(pngObj, pngInfo);
156 switch (colors)
157 {
158 case PNG_COLOR_TYPE_PALETTE:
159 png_set_palette_to_rgb(pngObj);
160 break;
161
162 case PNG_COLOR_TYPE_GRAY:
163 if (bpp < 8) png_set_expand(pngObj);
164 break;
165
166 case PNG_COLOR_TYPE_GRAY_ALPHA:
167 png_set_gray_to_rgb(pngObj);
168 break;
169 }
170
171 if (bpp == 16) png_set_strip_16(pngObj);
172
173 png_read_update_info(pngObj, pngInfo);
174
175 bpp = png_get_bit_depth(pngObj, pngInfo);
176 channels = png_get_channels(pngObj, pngInfo);
177 mDepth = bpp * channels;
178
179 logInfo << "texture channels: " << channels << std::endl;
180 if (channels == 3) mColorMode = GL_RGB;
181 else mColorMode = GL_RGBA;
182
183 // read comments
184 png_get_text(pngObj, pngInfo, &texts, &numTexts);
185 logInfo << "num texts: " << numTexts << std::endl;
186 for (int i = 0; i < numTexts; ++i)
187 {
188 if (strncmp(texts[i].key, "Comment", 7) == 0)
189 {
190 mComment = texts[i].text;
191 break;
192 }
193 }
194
195 width = png_get_image_width(pngObj, pngInfo);
196 height = png_get_image_height(pngObj, pngInfo);
197
198 pitch = png_get_rowbytes(pngObj, pngInfo);
199 mPixels = new char[width * pitch];
200
201 rows = new png_bytep[height];
202 if (flipped)
203 {
204 for (int i = 0; i < height; ++i)
205 {
206 rows[height - 1 - i] = (png_bytep)(mPixels + i * channels * width);
207 }
208 }
209 else
210 {
211 for (int i = 0; i < height; ++i)
212 {
213 rows[i] = (png_bytep)(mPixels + i * channels * width);
214 }
215 }
216
217 png_read_image(pngObj, rows);
218 png_read_end(pngObj, 0);
219
220 mContext = SDL_CreateRGBSurfaceFrom
221 (
222 mPixels,
223 width,
224 height,
225 bpp * channels,
226 pitch,
227 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
228 0x000000FF,
229 0x0000FF00,
230 0x00FF0000,
231 0xFF000000
232 #else
233 0xFF000000,
234 0x00FF0000,
235 0x0000FF00,
236 0x000000FF
237 #endif
238 );
239
240 cleanup:
241
242 logInfo("cleaning up...");
243 delete[] rows;
244 png_destroy_read_struct(pngObj ? &pngObj : 0,
245 pngInfo ? &pngInfo : 0,
246 pngInfoEnd ? &pngInfoEnd : 0);
247 fclose(fp);
248
249 return mContext;
250 }
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::getColorMode() 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
319 std::string Image::getPath(const std::string& name)
320 {
321 std::string path = Resource::getPath("images/" + name + ".png");
322 return path;
323 }
324
325
326 } // namespace Mf
327
328 /** vim: set ts=4 sw=4 tw=80: *************************************************/
329
This page took 0.043503 seconds and 4 git commands to generate.