2 /*******************************************************************************
4 Copyright (c) 2009, Charles McGarvey
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
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.
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.
27 *******************************************************************************/
29 #include <cstdio> // FILE
30 #include <cstring> // strncmp
32 #include <boost/algorithm/string.hpp>
47 class Image::Impl
: public Manager
<Impl
>
57 SDL_FreeSurface(mContext
);
64 unsigned char* pixels
= (Uint8
*)(mContext
->pixels
);
66 unsigned pitch
= mContext
->pitch
;
67 unsigned char line
[pitch
];
70 int yEnd
= mContext
->h
- 1;
72 if (SDL_MUSTLOCK(mContext
)) SDL_LockSurface(mContext
);
75 memcpy(line
, pixels
+ pitch
* yBegin
, pitch
);
76 memcpy(pixels
+ pitch
* yBegin
, pixels
+ pitch
* yEnd
, pitch
);
77 memcpy(pixels
+ pitch
* yEnd
, line
, pitch
);
81 if (SDL_MUSTLOCK(mContext
)) SDL_UnlockSurface(mContext
);
84 void setAsIcon() const
86 SDL_WM_SetIcon(mContext
, 0);
90 bool init(const std::string
& name
, bool flipped
= false)
92 std::string path
= Image::getPath(name
);
94 logInfo
<< "opening image file " << path
<< std::endl
;
95 FILE* fp
= fopen(path
.c_str(), "rb");
96 if (!fp
) return false;
98 png_byte signature
[8];
101 png_infop pngInfo
= 0;
102 png_infop pngInfoEnd
= 0;
103 png_structp pngObj
= 0;
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
;
123 logInfo("creating png structures...");
124 pngObj
= png_create_read_struct(PNG_LIBPNG_VER_STRING
, 0, 0, 0);
125 if (!pngObj
) goto cleanup
;
127 pngInfo
= png_create_info_struct(pngObj
);
128 if (!pngInfo
) goto cleanup
;
130 pngInfoEnd
= png_create_info_struct(pngObj
);
131 if (!pngInfoEnd
) goto cleanup
;
133 logInfo("setting up long jump...");
134 if (setjmp(png_jmpbuf(pngObj
))) goto cleanup
;
136 png_init_io(pngObj
, fp
);
137 png_set_sig_bytes(pngObj
, sizeof(signature
));
138 png_read_info(pngObj
, pngInfo
);
140 bpp
= png_get_bit_depth(pngObj
, pngInfo
);
141 logInfo
<< "texture bpp: " << bpp
<< std::endl
;
142 colors
= png_get_color_type(pngObj
, pngInfo
);
145 case PNG_COLOR_TYPE_PALETTE
:
146 png_set_palette_to_rgb(pngObj
);
149 case PNG_COLOR_TYPE_GRAY
:
150 if (bpp
< 8) png_set_expand(pngObj
);
153 case PNG_COLOR_TYPE_GRAY_ALPHA
:
154 png_set_gray_to_rgb(pngObj
);
158 if (bpp
== 16) png_set_strip_16(pngObj
);
160 png_read_update_info(pngObj
, pngInfo
);
162 bpp
= png_get_bit_depth(pngObj
, pngInfo
);
163 channels
= png_get_channels(pngObj
, pngInfo
);
164 mDepth
= bpp
* channels
;
166 logInfo
<< "texture channels: " << channels
<< std::endl
;
167 if (channels
== 3) mColorMode
= GL_RGB
;
168 else mColorMode
= GL_RGBA
;
171 png_get_text(pngObj
, pngInfo
, &texts
, &numTexts
);
172 logInfo
<< "num texts: " << numTexts
<< std::endl
;
173 for (int i
= 0; i
< numTexts
; ++i
)
175 if (strncmp(texts
[i
].key
, "TextureInfo", 11) == 0)
177 mComment
= texts
[i
].text
;
182 width
= png_get_image_width(pngObj
, pngInfo
);
183 height
= png_get_image_height(pngObj
, pngInfo
);
185 pitch
= png_get_rowbytes(pngObj
, pngInfo
);
186 mPixels
= new char[width
* pitch
];
188 rows
= new png_bytep
[height
];
191 for (int i
= 0; i
< height
; ++i
)
193 rows
[height
- 1 - i
] = (png_bytep
)(mPixels
+ i
* channels
* width
);
198 for (int i
= 0; i
< height
; ++i
)
200 rows
[i
] = (png_bytep
)(mPixels
+ i
* channels
* width
);
204 png_read_image(pngObj
, rows
);
205 png_read_end(pngObj
, 0);
207 mContext
= SDL_CreateRGBSurfaceFrom
214 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
229 logInfo("cleaning up...");
231 png_destroy_read_struct(pngObj
? &pngObj
: 0,
232 pngInfo
? &pngInfo
: 0,
233 pngInfoEnd
? &pngInfoEnd
: 0);
240 SDL_Surface
* mContext
;
246 std::string mComment
;
254 Image::Image(const std::string
& name
) :
256 mImpl(Image::Impl::getInstance(name
)) {}
259 bool Image::isValid() const
261 return mImpl
->mContext
;
264 int Image::getWidth() const
266 return mImpl
->mContext
->w
;
269 int Image::getHeight() const
271 return mImpl
->mContext
->h
;
274 unsigned Image::getDepth() const
276 return mImpl
->mDepth
;
279 unsigned Image::getPitch() const
281 return mImpl
->mContext
->pitch
;
284 GLuint
Image::getMode() const
286 return mImpl
->mColorMode
;
289 std::string
Image::getComment() const
291 return mImpl
->mComment
;
294 const char* Image::getPixels() const
296 return mImpl
->mPixels
;
299 char* Image::getPixels()
301 return mImpl
->mPixels
;
311 void Image::setAsIcon() const
318 std::string
Image::getPath(const std::string
& name
)
320 if (boost::find_last(name
, ".png"))
322 return Resource::getPath(name
);
326 std::string
path("images/");
329 return Resource::getPath(path
);
336 /** vim: set ts=4 sw=4 tw=80: *************************************************/