/*] Copyright (c) 2009-2010, Charles McGarvey [************************** **] All rights reserved. * * vi:ts=4 sw=4 tw=75 * * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * **************************************************************************/ #include // FILE #include // strncmp #include #include #include #include "Backend.hh" #include "Error.hh" #include "Image.hh" #include "Log.hh" #include "Manager.hh" namespace Mf { class Image::Impl : public Manager { public: explicit Impl() : mContext(0), mPixels(0) {} ~Impl() { SDL_FreeSurface(mContext); delete[] mPixels; } void flip() { unsigned char* pixels = (Uint8*)(mContext->pixels); unsigned pitch = mContext->pitch; unsigned char line[pitch]; int yBegin = 0; int yEnd = mContext->h - 1; if (SDL_MUSTLOCK(mContext)) SDL_LockSurface(mContext); while (yBegin < yEnd) { memcpy(line, pixels + pitch * yBegin, pitch); memcpy(pixels + pitch * yBegin, pixels + pitch * yEnd, pitch); memcpy(pixels + pitch * yEnd, line, pitch); yBegin++; yEnd--; } if (SDL_MUSTLOCK(mContext)) SDL_UnlockSurface(mContext); } void setAsIcon() const { SDL_WM_SetIcon(mContext, 0); } void init(const std::string& name, bool flipped = false) { std::string path(name); FILE* fp = Image::openFile(path); if (!fp) return; png_byte signature[8]; size_t bytesRead; png_infop pngInfo = 0; png_infop pngInfoEnd = 0; png_structp pngObj = 0; int width; int height; int pitch; int bpp; int channels; png_byte colors; png_bytepp rows = 0; png_textp texts = 0; int numTexts; bytesRead = fread(signature, 1, sizeof(signature), fp); if (bytesRead < sizeof(signature) || png_sig_cmp(signature, 0, sizeof(signature)) != 0) goto cleanup; pngObj = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (!pngObj) goto cleanup; pngInfo = png_create_info_struct(pngObj); if (!pngInfo) goto cleanup; pngInfoEnd = png_create_info_struct(pngObj); if (!pngInfoEnd) goto cleanup; if (setjmp(png_jmpbuf(pngObj))) goto cleanup; png_init_io(pngObj, fp); png_set_sig_bytes(pngObj, sizeof(signature)); png_read_info(pngObj, pngInfo); bpp = png_get_bit_depth(pngObj, pngInfo); colors = png_get_color_type(pngObj, pngInfo); switch (colors) { case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(pngObj); break; case PNG_COLOR_TYPE_GRAY: if (bpp < 8) png_set_expand(pngObj); break; case PNG_COLOR_TYPE_GRAY_ALPHA: png_set_gray_to_rgb(pngObj); break; } if (bpp == 16) png_set_strip_16(pngObj); png_read_update_info(pngObj, pngInfo); bpp = png_get_bit_depth(pngObj, pngInfo); channels = png_get_channels(pngObj, pngInfo); mDepth = bpp * channels; if (channels == 3) mColorMode = GL_RGB; else mColorMode = GL_RGBA; // read comments png_get_text(pngObj, pngInfo, &texts, &numTexts); for (int i = 0; i < numTexts; ++i) { if (strncmp(texts[i].key, "TextureInfo", 11) == 0) { mComment = texts[i].text; break; } } width = png_get_image_width(pngObj, pngInfo); height = png_get_image_height(pngObj, pngInfo); pitch = png_get_rowbytes(pngObj, pngInfo); mPixels = new char[width * pitch]; rows = new png_bytep[height]; if (flipped) { for (int i = 0; i < height; ++i) { rows[height - 1 - i] = (png_bytep)(mPixels + i * channels * width); } } else { for (int i = 0; i < height; ++i) { rows[i] = (png_bytep)(mPixels + i * channels * width); } } png_read_image(pngObj, rows); png_read_end(pngObj, 0); mContext = SDL_CreateRGBSurfaceFrom ( mPixels, width, height, bpp * channels, pitch, #if SDL_BYTEORDER == SDL_LIL_ENDIAN 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 #else 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF #endif ); cleanup: delete[] rows; png_destroy_read_struct(pngObj ? &pngObj : 0, pngInfo ? &pngInfo : 0, pngInfoEnd ? &pngInfoEnd : 0); fclose(fp); } SDL_Surface* mContext; char* mPixels; unsigned mDepth; GLuint mColorMode; std::string mComment; private: Backend mBackend; }; Image::Image(const std::string& name) : // pass through mImpl(Image::Impl::getInstance(name)) {} bool Image::isValid() const { return mImpl->mContext; } int Image::getWidth() const { return mImpl->mContext->w; } int Image::getHeight() const { return mImpl->mContext->h; } unsigned Image::getDepth() const { return mImpl->mDepth; } unsigned Image::getPitch() const { return mImpl->mContext->pitch; } GLuint Image::getMode() const { return mImpl->mColorMode; } std::string Image::getComment() const { return mImpl->mComment; } const char* Image::getPixels() const { return mImpl->mPixels; } char* Image::getPixels() { return mImpl->mPixels; } void Image::flip() { // pass through mImpl->flip(); } void Image::setAsIcon() const { // pass through mImpl->setAsIcon(); } bool Image::getPath(std::string& name) { return Resource::getPath(name, "images/", "png"); } FILE* Image::openFile(std::string& name) { return Resource::openFile(name, "images/", "png"); } } // namespace Mf