123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- //-----------------------------------------------------------------------------
- // 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 "core/stream/stream.h"
- #include "gfx/bitmap/gBitmap.h"
- #include "core/color.h"
- #define MNG_NO_CMS
- #define MNG_SUPPORT_READ
- #define MNG_SUPPORT_WRITE
- #define MNG_SUPPORT_DISPLAY
- #define MNG_STORE_CHUNKS
- #define MNG_ACCESS_CHUNKS
- #include "lmng/libmng.h"
- static bool sReadMNG(Stream &stream, GBitmap *bitmap);
- static bool sWriteMNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel);
- static struct _privateRegisterMNG
- {
- _privateRegisterMNG()
- {
- GBitmap::Registration reg;
- reg.extensions.push_back( "jng" );
- reg.extensions.push_back( "mng" );
- reg.readFunc = sReadMNG;
- reg.writeFunc = sWriteMNG;
- GBitmap::sRegisterFormat( reg );
- }
- } sStaticRegisterMNG;
- typedef struct
- {
- GBitmap* image;
- Stream* stream;
- } mngstuff;
- static mng_ptr mngMallocFn(mng_size_t size)
- {
- mng_ptr data = dMalloc(size);
- return dMemset(data, 0, size);
- }
- static void mngFreeFn(mng_ptr p, mng_size_t size)
- {
- dFree(p);
- }
- static mng_bool mngOpenDataFn(mng_handle mng)
- {
- return MNG_TRUE;
- }
- static mng_bool mngCloseDataFn(mng_handle mng)
- {
- return MNG_TRUE;
- }
- static mng_bool mngReadDataFn(mng_handle mng, mng_ptr data, mng_uint32 length, mng_uint32 *bytesread)
- {
- mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
- AssertFatal(mymng->stream != NULL, "No stream?");
- bool success = mymng->stream->read(length, data);
- *bytesread = length; // stupid hack
-
- AssertFatal(success, "MNG read catastrophic error!");
- if(success)
- return MNG_TRUE;
- else
- return MNG_FALSE;
- }
- #if 0
- // CodeReview - until we can write these, get rid of warning by disabling method.
- static mng_bool mngWriteDataFn(mng_handle mng, mng_ptr data, mng_uint32 length, mng_uint32 *iWritten)
- {
- mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
- AssertFatal(mymng->stream != NULL, "No stream?");
- bool success = mymng->stream->write(length, data);
- *iWritten = length; // stupid hack
-
- AssertFatal(success, "MNG write catastrophic error!");
- if(success)
- return MNG_TRUE;
- else
- return MNG_FALSE;
- }
- #endif
- static mng_bool mngProcessHeaderFn(mng_handle mng, mng_uint32 width, mng_uint32 height)
- {
- mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
- GFXFormat format;
- mng_uint8 colorType = mng_get_colortype(mng);
- mng_uint8 alphaDepth = mng_get_alphadepth(mng);
- switch(colorType)
- {
- case MNG_COLORTYPE_GRAY:
- case MNG_COLORTYPE_JPEGGRAY:
- format = GFXFormatR8G8B8;
- mng_set_canvasstyle(mng, MNG_CANVAS_RGB8);
- break;
- case MNG_COLORTYPE_INDEXED:
- if(alphaDepth >= 1)
- {
- format = GFXFormatR8G8B8A8;
- mng_set_canvasstyle(mng, MNG_CANVAS_RGBA8);
- }
- else
- {
- format = GFXFormatR8G8B8;
- mng_set_canvasstyle(mng, MNG_CANVAS_RGB8);
- }
- case MNG_COLORTYPE_RGB:
- case MNG_COLORTYPE_JPEGCOLOR:
- if(alphaDepth >= 1)
- {
- format = GFXFormatR8G8B8A8;
- mng_set_canvasstyle(mng, MNG_CANVAS_RGBA8);
- }
- else
- {
- format = GFXFormatR8G8B8;
- mng_set_canvasstyle(mng, MNG_CANVAS_RGB8);
- }
- break;
- case MNG_COLORTYPE_RGBA:
- case MNG_COLORTYPE_JPEGCOLORA:
- format = GFXFormatR8G8B8A8;
- mng_set_canvasstyle(mng, MNG_CANVAS_RGBA8);
- break;
- default:
- // This case should never get hit, however it resolves a compiler
- // warning
- format = GFXFormat_FIRST;
- AssertISV( false, "Unknown color format in bitmap MNG Loading" );
- }
- mymng->image->allocateBitmap(width, height, false, format);
- return MNG_TRUE;
- }
- static mng_ptr mngCanvasLineFn(mng_handle mng, mng_uint32 line)
- {
- mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
- return (mng_ptr) mymng->image->getAddress(0, line);
- }
- static mng_bool mngRefreshFn(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h)
- {
- return MNG_TRUE;
- }
- static mng_uint32 mngGetTicksFn(mng_handle mng)
- {
- return 0;
- }
- static mng_bool mngSetTimerFn(mng_handle mng, mng_uint32 msecs)
- {
- return MNG_TRUE;
- }
- static mng_bool mngFatalErrorFn(mng_handle mng, mng_int32 code, mng_int8 severity, mng_chunkid chunktype, mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar text)
- {
- mng_cleanup(&mng);
-
- AssertISV(false, avar("Error reading MNG file:\n %s", (const char*)text));
- return MNG_FALSE;
- }
- static bool sReadMNG(Stream &stream, GBitmap *bitmap)
- {
- mngstuff mnginfo;
- dMemset(&mnginfo, 0, sizeof(mngstuff));
- mng_handle mng = mng_initialize(&mnginfo, mngMallocFn, mngFreeFn, MNG_NULL);
- if(mng == NULL)
- return false;
-
- // setup the callbacks
- mng_setcb_errorproc(mng, mngFatalErrorFn);
- mng_setcb_openstream(mng, mngOpenDataFn);
- mng_setcb_closestream(mng, mngCloseDataFn);
- mng_setcb_readdata(mng, mngReadDataFn);
- mng_setcb_processheader(mng, mngProcessHeaderFn);
- mng_setcb_getcanvasline(mng, mngCanvasLineFn);
- mng_setcb_refresh(mng, mngRefreshFn);
- mng_setcb_gettickcount(mng, mngGetTicksFn);
- mng_setcb_settimer(mng, mngSetTimerFn);
-
- mnginfo.image = bitmap;
- mnginfo.stream = &stream;
-
- mng_read(mng);
- mng_display(mng);
- // hacks :(
- // libmng doesn't support returning data in gray/gray alpha format,
- // so we grab as RGB/RGBA and just cut off the g and b
- mng_uint8 colorType = mng_get_colortype(mng);
- switch(colorType)
- {
- case MNG_COLORTYPE_GRAY:
- case MNG_COLORTYPE_JPEGGRAY:
- {
- GBitmap temp(*bitmap);
- bitmap->deleteImage();
- bitmap->allocateBitmap(temp.getWidth(), temp.getHeight(), false, GFXFormatA8);
-
- // force getColor to read in in the same color value for each channel
- // since the gray colortype has the real alpha in the first channel
- temp.setFormat( GFXFormatA8 );
- ColorI color;
- for(U32 row = 0; row < bitmap->getHeight(); row++)
- {
- for(U32 col = 0; col < bitmap->getWidth(); col++)
- {
- temp.getColor(col, row, color);
- bitmap->setColor(col, row, color);
- }
- }
- }
- break;
- }
- mng_cleanup(&mng);
- // Check this bitmap for transparency
- bitmap->checkForTransparency();
- return true;
- }
- static bool sWriteMNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel)
- {
- TORQUE_UNUSED( bitmap );
- TORQUE_UNUSED( stream );
- TORQUE_UNUSED( compressionLevel );
- return false;
- #if 0
- // ONLY RGB bitmap writing supported at this time!
- AssertFatal(getFormat() == GFXFormatR8G8B8 || getFormat() == GFXFormatR8G8B8A8 || getFormat() == GFXFormatA8, "GBitmap::writeMNG: ONLY RGB bitmap writing supported at this time.");
- if(getFormat() != GFXFormatR8G8B8 && getFormat() != GFXFormatR8G8B8A8 && getFormat() != GFXFormatA8)
- return (false);
-
- // maximum image size allowed
- #define MAX_HEIGHT 4096
- if(getHeight() >= MAX_HEIGHT)
- return false;
-
- mngstuff mnginfo;
- dMemset(&mnginfo, 0, sizeof(mngstuff));
- mng_handle mng = mng_initialize(&mnginfo, mngMallocFn, mngFreeFn, MNG_NULL);
- if(mng == NULL) {
- return false;
- }
-
- // setup the callbacks
- mng_setcb_openstream(mng, mngOpenDataFn);
- mng_setcb_closestream(mng, mngCloseDataFn);
- mng_setcb_writedata(mng, mngWriteDataFn);
-
- // create the file in memory
- mng_create(mng);
-
- mng_putchunk_defi(mng, 0, 0, 0, MNG_FALSE, 0, 0, MNG_FALSE, 0, getWidth(), 0, getHeight());
-
- mnginfo.image = (GBitmap*)this;
- mnginfo.stream = &stream;
-
- switch(getFormat()) {
- case GFXFormatA8:
- mng_putchunk_ihdr(mng, getWidth(), getHeight(),
- MNG_BITDEPTH_8,
- MNG_COLORTYPE_GRAY,
- MNG_COMPRESSION_DEFLATE,
- MNG_FILTER_ADAPTIVE,
- MNG_INTERLACE_NONE);
-
- // not implemented in lib yet
- //mng_putimgdata_ihdr(mng, getWidth(), getHeight(),
- // MNG_COLORTYPE_GRAY,
- // MNG_BITDEPTH_8,
- // MNG_COMPRESSION_DEFLATE,
- // MNG_FILTER_ADAPTIVE,
- // MNG_INTERLACE_NONE,
- // MNG_CANVAS_GRAY8, mngCanvasLineFn);
- break;
- case GFXFormatR8G8B8:
- mng_putchunk_ihdr(mng, getWidth(), getHeight(),
- MNG_BITDEPTH_8,
- MNG_COLORTYPE_RGB,
- MNG_COMPRESSION_DEFLATE,
- MNG_FILTER_ADAPTIVE,
- MNG_INTERLACE_NONE);
-
- // not implemented in lib yet
- //mng_putimgdata_ihdr(mng, getWidth(), getHeight(),
- // MNG_COLORTYPE_RGB,
- // MNG_BITDEPTH_8,
- // MNG_COMPRESSION_DEFLATE,
- // MNG_FILTER_ADAPTIVE,
- // MNG_INTERLACE_NONE,
- // MNG_CANVAS_RGB8, mngCanvasLineFn);
- break;
- case GFXFormatR8G8B8A8:
- mng_putchunk_ihdr(mng, getWidth(), getHeight(),
- MNG_BITDEPTH_8,
- MNG_COLORTYPE_RGBA,
- MNG_COMPRESSION_DEFLATE,
- MNG_FILTER_ADAPTIVE,
- MNG_INTERLACE_NONE);
-
- // not implemented in lib yet
- //mng_putimgdata_ihdr(mng, getWidth(), getHeight(),
- // MNG_COLORTYPE_RGBA,
- // MNG_BITDEPTH_8,
- // MNG_COMPRESSION_DEFLATE,
- // MNG_FILTER_ADAPTIVE,
- // MNG_INTERLACE_NONE,
- // MNG_CANVAS_RGBA8, mngCanvasLineFn);
- break;
- }
-
-
- // below is a hack until libmng is mature enough to handle this itself
- //-----------------------------------------------------------------------------
-
-
- U8 *tmpbuffer = new U8[this->byteSize + getHeight()];
- if(tmpbuffer == 0)
- {
- mng_cleanup(&mng);
- return false;
- }
-
- // transfer data, add filterbyte
- U32 effwdt = getWidth() * this->bytesPerPixel;
- for(U32 Row = 0; Row < getHeight(); Row++)
- {
- // first Byte in each scanline is filterbyte: currently 0 -> no filter
- tmpbuffer[Row * (effwdt + 1)] = 0;
-
- // copy the scanline
- dMemcpy(tmpbuffer + Row * (effwdt + 1) + 1, getAddress(0, Row), effwdt);
- }
-
- // compress data with zlib
- U8 *dstbuffer = new U8[this->byteSize + getHeight()];
- if(dstbuffer == 0)
- {
- delete [] tmpbuffer;
- mng_cleanup(&mng);
- return false;
- }
- U32 dstbufferSize = this->byteSize + getHeight();
- if(Z_OK != compress2((Bytef*)dstbuffer,(uLongf*)&dstbufferSize, (const Bytef*)tmpbuffer, dstbufferSize, 9))
- {
- delete [] tmpbuffer;
- delete [] dstbuffer;
- mng_cleanup(&mng);
- return false;
- }
-
- mng_putchunk_idat(mng, dstbufferSize, (mng_ptr*)dstbuffer);
-
-
- //-----------------------------------------------------------------------------
-
-
- mng_putchunk_iend(mng);
-
- delete [] tmpbuffer;
- delete [] dstbuffer;
-
- mng_write(mng);
- mng_cleanup(&mng);
-
- return true;
- #endif
- }
|