]> Dogcows Code - chaz/yoink/blobdiff - src/Moof/Image.cc
simplified win32 installer build script
[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..31d6b02
--- /dev/null
@@ -0,0 +1,325 @@
+
+/*******************************************************************************
+
+ Copyright (c) 2009, Charles McGarvey
+ All rights reserved.
+ Redistribution   and   use  in  source  and  binary  forms,  with  or  without
+ modification, are permitted provided that the following conditions are met:
+   * Redistributions  of  source  code  must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   * Redistributions  in binary form must reproduce the above copyright notice,
+     this  list of conditions and the following disclaimer in the documentation
+     and/or other materials provided with the distribution.
+ THIS  SOFTWARE  IS  PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND  ANY  EXPRESS  OR  IMPLIED  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED.  IN  NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES  (INCLUDING,  BUT  NOT  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES;  LOSS  OF  USE,  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include <cstdio>              // FILE
+#include <cstring>             // strncmp
+
+#include <SDL/SDL.h>
+#include <png.h>
+
+#include "Image.hh"
+#include "Library.hh"
+#include "Log.hh"
+
+
+namespace Mf {
+
+
+class Image::Impl : public Library<Impl>
+{
+public:
+
+       explicit Impl(const std::string& name, bool flipped = false) :
+               Library<Impl>(name),
+               mContext(0),
+               mPixels(0)
+       {
+               init(getName(), flipped);
+       }
+
+       ~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);
+       }
+
+
+       SDL_Surface*    mContext;
+       char*                   mPixels;
+
+       unsigned                mDepth;
+       GLuint                  mColorMode;
+
+       std::string             mComment;
+
+
+private:
+
+       bool init(const std::string& filePath, bool flipped)
+       {
+               logInfo("opening image file...");
+               FILE* fp = fopen(filePath.c_str(), "rb");
+               if (!fp) return false;
+
+               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;
+
+               logInfo("checking signature...");
+               bytesRead = fread(signature, 1, sizeof(signature), fp);
+               logInfo << "reading " << bytesRead << " bytes of signature" << std::endl;
+               if (bytesRead < sizeof(signature) ||
+                       png_sig_cmp(signature, 0, sizeof(signature)) != 0) goto cleanup;
+
+               logInfo("creating png structures...");
+               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;
+
+               logInfo("setting up long jump...");
+               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);
+               logInfo << "texture bpp: " << bpp << std::endl;
+               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_gray_1_2_4_to_8(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;
+
+               logInfo << "texture channels: " << channels << std::endl;
+               if (channels == 3) mColorMode = GL_RGB;
+               else               mColorMode = GL_RGBA;
+               
+               // read comments
+               png_get_text(pngObj, pngInfo, &texts, &numTexts);
+               logInfo << "num texts: " << numTexts << std::endl;
+               for (int i = 0; i < numTexts; ++i)
+               {
+                       if (strncmp(texts[i].key, "Comment", 7) == 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:
+
+               logInfo("cleaning up...");
+               delete[] rows;
+               png_destroy_read_struct(pngObj     ? &pngObj     : 0,
+                                                               pngInfo    ? &pngInfo    : 0,
+                                                               pngInfoEnd ? &pngInfoEnd : 0);
+               fclose(fp);
+
+               return mContext;
+       }
+};
+
+
+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::getColorMode() 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();
+}
+
+
+
+std::string Image::getPath(const std::string& name)
+{
+       std::string path = Resource::getPath("images/" + name + ".png");
+       return path;
+}
+
+
+} // namespace Mf
+
+/** vim: set ts=4 sw=4 tw=80: *************************************************/
+
This page took 0.024353 seconds and 4 git commands to generate.