/*] 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 "image.hh" #include "log.hh" #include "manager.hh" namespace moof { class image::impl : public manager { public: explicit impl() : context_(0), pixels_(0) {} ~impl() { SDL_FreeSurface(context_); delete[] pixels_; } void flip() { unsigned char* pixels = (Uint8*)(context_->pixels); unsigned pitch = context_->pitch; unsigned char line[pitch]; int yBegin = 0; int yEnd = context_->h - 1; if (SDL_MUSTLOCK(context_)) SDL_LockSurface(context_); 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(context_)) SDL_UnlockSurface(context_); } void set_as_icon() const { SDL_WM_SetIcon(context_, 0); } void init(const std::string& name, bool flipped = false) { std::string path(name); FILE* fp = resource::open_file(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 nutext_s; 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); depth_ = bpp * channels; if (channels == 3) color_mode_ = GL_RGB; else color_mode_ = GL_RGBA; // read comments png_get_text(pngObj, pngInfo, &texts, &nutext_s); for (int i = 0; i < nutext_s; ++i) { if (strncmp(texts[i].key, "TextureInfo", 11) == 0) { comment_ = texts[i].text; break; } } width = png_get_image_width(pngObj, pngInfo); height = png_get_image_height(pngObj, pngInfo); pitch = png_get_rowbytes(pngObj, pngInfo); pixels_ = new char[width * pitch]; rows = new png_bytep[height]; if (flipped) { for (int i = 0; i < height; ++i) { rows[height - 1 - i] = (png_bytep)(pixels_ + i * channels * width); } } else { for (int i = 0; i < height; ++i) { rows[i] = (png_bytep)(pixels_ + i * channels * width); } } png_read_image(pngObj, rows); png_read_end(pngObj, 0); context_ = SDL_CreateRGBSurfaceFrom ( pixels_, 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* context_; char* pixels_; unsigned depth_; GLuint color_mode_; std::string comment_; private: backend backend_; }; image::image(const std::string& name) : // pass through impl_(image::impl::instance(name)) {} bool image::is_valid() const { return impl_->context_; } int image::width() const { return impl_->context_->w; } int image::height() const { return impl_->context_->h; } unsigned image::depth() const { return impl_->depth_; } unsigned image::pitch() const { return impl_->context_->pitch; } GLuint image::mode() const { return impl_->color_mode_; } std::string image::comment() const { return impl_->comment_; } const char* image::pixels() const { return impl_->pixels_; } char* image::pixels() { return impl_->pixels_; } void image::flip() { // pass through impl_->flip(); } void image::set_as_icon() const { // pass through impl_->set_as_icon(); } } // namespace moof