--- /dev/null
+
+/*] 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 <cstdio> // FILE
+#include <cstring> // strncmp
+
+#include <boost/algorithm/string.hpp>
+
+#include <png.h>
+#include <SDL/SDL.h>
+
+#include "backend.hh"
+#include "image.hh"
+#include "log.hh"
+#include "manager.hh"
+
+
+namespace moof {
+
+
+class image::impl : public manager<impl>
+{
+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 = image::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();
+}
+
+
+bool image::find_path(std::string& name)
+{
+ return resource::find_path(name, "images/", "png");
+}
+
+FILE* image::open_file(std::string& name)
+{
+ return resource::open_file(name, "images/", "png");
+}
+
+
+} // namespace moof
+