]> Dogcows Code - chaz/yoink/blobdiff - src/moof/image.cc
the massive refactoring effort
[chaz/yoink] / src / moof / image.cc
diff --git a/src/moof/image.cc b/src/moof/image.cc
new file mode 100644 (file)
index 0000000..f2f0c09
--- /dev/null
@@ -0,0 +1,302 @@
+
+/*]  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
+
This page took 0.023952 seconds and 4 git commands to generate.