X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2FImage.cc;fp=src%2FMoof%2FImage.cc;h=31d6b0287926e38e35f7fc51c58be55571cfdba5;hp=0000000000000000000000000000000000000000;hb=b357615aba1dbde81e3c6999366604e6001010a7;hpb=246d7d6e4386b686327163d621c7c8b398b7d479 diff --git a/src/Moof/Image.cc b/src/Moof/Image.cc new file mode 100644 index 0000000..31d6b02 --- /dev/null +++ b/src/Moof/Image.cc @@ -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 // FILE +#include // strncmp + +#include +#include + +#include "Image.hh" +#include "Library.hh" +#include "Log.hh" + + +namespace Mf { + + +class Image::Impl : public Library +{ +public: + + explicit Impl(const std::string& name, bool flipped = false) : + Library(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: *************************************************/ +