//----------------------------------------------------------------------------- // Copyright (c) 2012 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- #include "platform/platform.h" #include "core/stream/fileStream.h" #include "core/util/path.h" #include "gfx/bitmap/gBitmap.h" // This must come after our headers due to a conflicting definition of VoidPtr #include "lungif/gif_lib.h" using namespace Torque; static bool sReadGIF(Stream &stream, GBitmap *bitmap); static bool sWriteGIF(GBitmap *bitmap, Stream &stream, U32 compressionLevel); static struct _privateRegisterGIF { _privateRegisterGIF() { GBitmap::Registration reg; reg.extensions.push_back( "gif" ); reg.readFunc = sReadGIF; reg.writeFunc = sWriteGIF; GBitmap::sRegisterFormat( reg ); } } sStaticRegisterGIF; //-------------------------------------- Replacement I/O for standard LIBjpeg // functions. we don't wanna use // FILE*'s... static S32 gifReadDataFn(GifFileType *gifinfo, GifByteType *data, S32 length) { Stream *stream = (Stream*)gifinfo->UserData; AssertFatal(stream != NULL, "gifReadDataFn::No stream."); int pos = stream->getPosition(); if (stream->read(length, data)) return length; if (stream->getStatus() == Stream::EOS) return (stream->getPosition()-pos); else return 0; } //-------------------------------------- #if 0 // CodeReview - until we can write these, get rid of warning by disabling method. static S32 gifWriteDataFn(GifFileType *gifinfo, GifByteType *data, S32 length) { Stream *stream = (Stream*)gifinfo->UserData; AssertFatal(stream != NULL, "gifWriteDataFn::No stream."); if (stream->write(length, data)) return length; else return 0; } #endif //-------------------------------------- static bool sReadGIF( Stream &stream, GBitmap *bitmap ) { GifFileType *gifinfo = DGifOpen( (void*)&stream, gifReadDataFn); if (!gifinfo) return false; GifRecordType recordType; do { if (DGifGetRecordType(gifinfo, &recordType) == GIF_ERROR) break; if (recordType == IMAGE_DESC_RECORD_TYPE) { if (DGifGetImageDesc(gifinfo) == GIF_ERROR) break; GFXFormat format = (gifinfo->SBackGroundColor == 0 ) ? GFXFormatR8G8B8 : GFXFormatR8G8B8A8; bitmap->allocateBitmap(gifinfo->SWidth, gifinfo->SHeight, false, format); // Assume no transparency until proven otherwise bitmap->setHasTransparency(false); U32 gwidth = gifinfo->Image.Width ? gifinfo->Image.Width : bitmap->getWidth(); U32 gheight= gifinfo->Image.Height ? gifinfo->Image.Height : bitmap->getHeight(); U32 gifSize = gwidth * gheight; U8 *data = new U8[gifSize]; if (DGifGetLine(gifinfo, data, gifSize) != GIF_ERROR) { // use the global or local color table ? GifColorType *color = NULL; if (gifinfo->Image.ColorMap) color = gifinfo->Image.ColorMap->Colors; else if (gifinfo->SColorMap) color = gifinfo->SColorMap->Colors; if (color) { U8 *dst = bitmap->getAddress(gifinfo->Image.Left, gifinfo->Image.Top); U8 *src = data; U32 right = gifinfo->Image.Left + gwidth; U32 bottom = gifinfo->Image.Top + gheight; U32 next = (bitmap->getWidth() - gwidth) * bitmap->getBytesPerPixel(); if (format == GFXFormatR8G8B8A8) { for (U32 y=gifinfo->Image.Top; yImage.Left; xSBackGroundColor) { // this is a transparent pixel dst[0] = 0; // red dst[1] = 0; // green dst[2] = 0; // blue dst[3] = 0; // alpha bitmap->setHasTransparency(true); } else { dst[0] = color[*src].Red; dst[1] = color[*src].Green; dst[2] = color[*src].Blue; dst[3] = 0; // alpha } dst += bitmap->getBytesPerPixel(); } dst += next; } } else { for (U32 y=gifinfo->Image.Top; yImage.Left; xgetBytesPerPixel(); } dst += next; } } delete [] data; DGifCloseFile(gifinfo); return true; } } // failure delete [] data; break; } else if (recordType == EXTENSION_RECORD_TYPE) { GifByteType *extension; S32 extCode; // Skip any extension blocks in file if (DGifGetExtension(gifinfo, &extCode, &extension) != GIF_ERROR) { while (extension != NULL) { if (DGifGetExtensionNext(gifinfo, &extension) == GIF_ERROR) { return false; } } } else { return false; } } // There used to be a break right here. This caused the while condition to // never get processed, and so it never looped through all the records in // the GIF. I took a quick peek back at TGB and TGE histories and I am not // sure where this change got made, but I can't figure out why the loading // worked at all, ever, with that break in there. The only case I can think // of is if the first record in the GIF was the bitmap data. // [6/6/2007 Pat] }while (recordType != TERMINATE_RECORD_TYPE); DGifCloseFile(gifinfo); return true; } //-------------------------------------------------------------------------- static bool sWriteGIF(GBitmap *bitmap, Stream &stream, U32 compressionLevel) { TORQUE_UNUSED( bitmap ); TORQUE_UNUSED( stream ); TORQUE_UNUSED( compressionLevel ); return false; }