bitmapMng.cpp

Engine/source/gfx/bitmap/loaders/bitmapMng.cpp

More...

Classes:

Public Defines

Public Variables

struct _privateRegisterMNG

Public Functions

mng_ptr
mngCanvasLineFn(mng_handle mng, mng_uint32 line)
mng_bool
mngCloseDataFn(mng_handle mng)
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)
mngFreeFn(mng_ptr p, mng_size_t size)
mng_uint32
mngGetTicksFn(mng_handle mng)
mng_ptr
mngMallocFn(mng_size_t size)
mng_bool
mngOpenDataFn(mng_handle mng)
mng_bool
mngProcessHeaderFn(mng_handle mng, mng_uint32 width, mng_uint32 height)
mng_bool
mngReadDataFn(mng_handle mng, mng_ptr data, mng_uint32 length, mng_uint32 * bytesread)
mng_bool
mngRefreshFn(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h)
mng_bool
mngSetTimerFn(mng_handle mng, mng_uint32 msecs)
bool
sReadMNG(Stream & stream, GBitmap * bitmap)
bool
sWriteMNG(GBitmap * bitmap, Stream & stream, U32 compressionLevel)

Detailed Description

Public Defines

MNG_ACCESS_CHUNKS() 
MNG_NO_CMS() 
MNG_STORE_CHUNKS() 
MNG_SUPPORT_DISPLAY() 
MNG_SUPPORT_READ() 
MNG_SUPPORT_WRITE() 

Public Variables

struct _privateRegisterMNG sStaticRegisterMNG 

Public Functions

mngCanvasLineFn(mng_handle mng, mng_uint32 line)

mngCloseDataFn(mng_handle mng)

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)

mngFreeFn(mng_ptr p, mng_size_t size)

mngGetTicksFn(mng_handle mng)

mngMallocFn(mng_size_t size)

mngOpenDataFn(mng_handle mng)

mngProcessHeaderFn(mng_handle mng, mng_uint32 width, mng_uint32 height)

mngReadDataFn(mng_handle mng, mng_ptr data, mng_uint32 length, mng_uint32 * bytesread)

mngRefreshFn(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h)

mngSetTimerFn(mng_handle mng, mng_uint32 msecs)

sReadMNG(Stream & stream, GBitmap * bitmap)

sWriteMNG(GBitmap * bitmap, Stream & stream, U32 compressionLevel)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "core/stream/stream.h"
 25
 26#include "gfx/bitmap/gBitmap.h"
 27
 28#include "core/color.h"
 29
 30#define MNG_NO_CMS
 31#define MNG_SUPPORT_READ
 32#define MNG_SUPPORT_WRITE
 33#define MNG_SUPPORT_DISPLAY
 34#define MNG_STORE_CHUNKS
 35#define MNG_ACCESS_CHUNKS
 36
 37#include "lmng/libmng.h"
 38
 39
 40
 41static bool sReadMNG(Stream &stream, GBitmap *bitmap);
 42static bool sWriteMNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel);
 43
 44static struct _privateRegisterMNG
 45{
 46   _privateRegisterMNG()
 47   {
 48      GBitmap::Registration reg;
 49
 50      reg.extensions.push_back( "jng" );
 51      reg.extensions.push_back( "mng" );
 52
 53      reg.readFunc = sReadMNG;
 54      reg.writeFunc = sWriteMNG;
 55
 56      GBitmap::sRegisterFormat( reg );
 57   }
 58} sStaticRegisterMNG;
 59
 60
 61typedef struct 
 62{
 63   GBitmap*    image;
 64   Stream*     stream;
 65} mngstuff;
 66
 67static mng_ptr mngMallocFn(mng_size_t size)
 68{
 69   mng_ptr data = dMalloc(size);
 70   return dMemset(data, 0, size);
 71}
 72
 73static void mngFreeFn(mng_ptr p, mng_size_t size)
 74{
 75   dFree(p);
 76}
 77
 78static mng_bool mngOpenDataFn(mng_handle mng)
 79{
 80   return MNG_TRUE;
 81}
 82
 83static mng_bool mngCloseDataFn(mng_handle mng)
 84{
 85   return MNG_TRUE;
 86}
 87
 88static mng_bool mngReadDataFn(mng_handle mng, mng_ptr data, mng_uint32 length, mng_uint32 *bytesread)
 89{
 90   mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
 91   AssertFatal(mymng->stream != NULL, "No stream?");
 92
 93   bool success = mymng->stream->read(length, data);
 94   *bytesread = length; // stupid hack
 95   
 96   AssertFatal(success, "MNG read catastrophic error!");
 97   if(success)
 98      return MNG_TRUE;
 99   else
100      return MNG_FALSE;
101}
102
103#if 0
104// CodeReview - until we can write these, get rid of warning by disabling method.
105static mng_bool mngWriteDataFn(mng_handle mng, mng_ptr data, mng_uint32 length, mng_uint32 *iWritten)
106{
107   mngstuff *)mng_get_userdata(mng);
108   NULL, "No stream?");
109
110   bool success = mymng->write(length, data);
111   *iWritten = length; // stupid hack
112   
113   AssertFatal(success, "MNG write catastrophic error!");
114   if(success)
115      return MNG_TRUE;
116   else
117      return MNG_FALSE;
118}
119#endif
120
121static mng_bool mngProcessHeaderFn(mng_handle mng, mng_uint32 width, mng_uint32 height)
122{
123   mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
124
125   GFXFormat format;
126   mng_uint8 colorType = mng_get_colortype(mng);
127   mng_uint8 alphaDepth = mng_get_alphadepth(mng);
128   switch(colorType)
129   {
130      case MNG_COLORTYPE_GRAY:
131      case MNG_COLORTYPE_JPEGGRAY:
132         format = GFXFormatR8G8B8;
133         mng_set_canvasstyle(mng, MNG_CANVAS_RGB8);
134         break;
135
136      case MNG_COLORTYPE_INDEXED:
137         if(alphaDepth >= 1)
138         {
139            format = GFXFormatR8G8B8A8;
140            mng_set_canvasstyle(mng, MNG_CANVAS_RGBA8);
141         }
142         else
143         {
144            format = GFXFormatR8G8B8;
145            mng_set_canvasstyle(mng, MNG_CANVAS_RGB8);
146         }
147
148      case MNG_COLORTYPE_RGB:
149      case MNG_COLORTYPE_JPEGCOLOR:
150         if(alphaDepth >= 1)
151         {
152            format = GFXFormatR8G8B8A8;
153            mng_set_canvasstyle(mng, MNG_CANVAS_RGBA8);
154         }
155         else
156         {
157            format = GFXFormatR8G8B8;
158            mng_set_canvasstyle(mng, MNG_CANVAS_RGB8);
159         }
160         break;
161
162      case MNG_COLORTYPE_RGBA:
163      case MNG_COLORTYPE_JPEGCOLORA:
164         format = GFXFormatR8G8B8A8;
165         mng_set_canvasstyle(mng, MNG_CANVAS_RGBA8);
166         break;
167
168      default:
169         // This case should never get hit, however it resolves a compiler
170         // warning
171         format = GFXFormat_FIRST;
172         AssertISV( false, "Unknown color format in bitmap MNG Loading" );
173   }
174
175   mymng->image->allocateBitmap(width, height, false, format);
176   return MNG_TRUE;
177}
178
179static mng_ptr mngCanvasLineFn(mng_handle mng, mng_uint32 line)
180{
181   mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
182   return (mng_ptr) mymng->image->getAddress(0, line);
183}
184
185static mng_bool mngRefreshFn(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h)
186{
187   return MNG_TRUE;
188}
189
190static mng_uint32 mngGetTicksFn(mng_handle mng)
191{
192   return 0;
193}
194
195static mng_bool mngSetTimerFn(mng_handle mng, mng_uint32 msecs)
196{
197   return MNG_TRUE;
198}
199
200static 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)
201{
202   mng_cleanup(&mng);
203   
204   AssertISV(false, avar("Error reading MNG file:\n %s", (const char*)text));
205   return MNG_FALSE;
206}
207
208static bool sReadMNG(Stream &stream, GBitmap *bitmap)
209{
210   mngstuff mnginfo;
211   dMemset(&mnginfo, 0, sizeof(mngstuff));
212
213   mng_handle mng = mng_initialize(&mnginfo, mngMallocFn, mngFreeFn, MNG_NULL);
214   if(mng == NULL)
215      return false;
216   
217   // setup the callbacks
218   mng_setcb_errorproc(mng, mngFatalErrorFn);
219   mng_setcb_openstream(mng, mngOpenDataFn);
220   mng_setcb_closestream(mng, mngCloseDataFn);
221   mng_setcb_readdata(mng, mngReadDataFn);
222   mng_setcb_processheader(mng, mngProcessHeaderFn);
223   mng_setcb_getcanvasline(mng, mngCanvasLineFn);
224   mng_setcb_refresh(mng, mngRefreshFn);
225   mng_setcb_gettickcount(mng, mngGetTicksFn);
226   mng_setcb_settimer(mng, mngSetTimerFn);
227   
228   mnginfo.image = bitmap;
229   mnginfo.stream = &stream;
230   
231   mng_read(mng);
232   mng_display(mng);
233
234   // hacks :(
235   // libmng doesn't support returning data in gray/gray alpha format, 
236   // so we grab as RGB/RGBA and just cut off the g and b
237   mng_uint8 colorType = mng_get_colortype(mng);
238   switch(colorType)
239   {
240      case MNG_COLORTYPE_GRAY:
241      case MNG_COLORTYPE_JPEGGRAY:
242         {
243            GBitmap temp(*bitmap);
244            bitmap->deleteImage();
245            bitmap->allocateBitmap(temp.getWidth(), temp.getHeight(), false, GFXFormatA8);
246            
247            // force getColor to read in in the same color value for each channel
248            // since the gray colortype has the real alpha in the first channel
249            temp.setFormat( GFXFormatA8 );
250
251            ColorI color;
252            for(U32 row = 0; row < bitmap->getHeight(); row++)
253            {
254               for(U32 col = 0; col < bitmap->getWidth(); col++)
255               {
256                  temp.getColor(col, row, color);
257                  bitmap->setColor(col, row, color);
258               }
259            }
260         }
261
262         break;
263   }
264
265   mng_cleanup(&mng);
266
267   // Check this bitmap for transparency
268   bitmap->checkForTransparency();
269
270   return true;
271}
272
273static bool sWriteMNG(GBitmap *bitmap, Stream &stream, U32 compressionLevel)
274{
275   TORQUE_UNUSED( bitmap );
276   TORQUE_UNUSED( stream );
277   TORQUE_UNUSED( compressionLevel );
278
279   return false;
280#if 0
281   // ONLY RGB bitmap writing supported at this time!
282   GFXFormatA8, "GBitmap::writeMNG: ONLY RGB bitmap writing supported at this time.");
283   if(getFormat() != GFXFormatA8)
284      return (false);
285      
286   // maximum image size allowed
287   #define MAX_HEIGHT 4096
288   if(getHeight() >= MAX_HEIGHT)
289      return false;
290      
291   mngstuff mnginfo;
292   mngstuff));
293   mng_handle mng = mng_initialize(&mnginfo, mngMallocFn, mngFreeFn, MNG_NULL);
294   if(mng == NULL) {
295      return false;
296   }
297   
298   // setup the callbacks
299   mng_setcb_openstream(mng, mngOpenDataFn);
300   mng_setcb_closestream(mng, mngCloseDataFn);
301   mng_setcb_writedata(mng, mngWriteDataFn);
302   
303   // create the file in memory
304   mng_create(mng);
305   
306   mng_putchunk_defi(mng, 0, 0, 0, MNG_FALSE, 0, 0, MNG_FALSE, 0, getWidth(), 0, getHeight());
307   
308   mnginfo.GBitmap*)this;
309   mnginfo.stream = &stream;
310   
311   switch(getFormat()) {
312      case GFXFormatA8:
313         mng_putchunk_ihdr(mng, getWidth(), getHeight(), 
314            MNG_BITDEPTH_8, 
315            MNG_COLORTYPE_GRAY, 
316            MNG_COMPRESSION_DEFLATE, 
317            MNG_FILTER_ADAPTIVE, 
318            MNG_INTERLACE_NONE);
319         
320         // not implemented in lib yet
321         //mng_putimgdata_ihdr(mng, getWidth(), getHeight(), 
322         //   MNG_COLORTYPE_GRAY, 
323         //   MNG_BITDEPTH_8, 
324         //   MNG_COMPRESSION_DEFLATE, 
325         //   MNG_FILTER_ADAPTIVE, 
326         //   MNG_INTERLACE_NONE, 
327         //   MNG_CANVAS_GRAY8, mngCanvasLineFn);
328         break;
329     case GFXFormatR8G8B8:
330         mng_putchunk_ihdr(mng, getWidth(), getHeight(), 
331            MNG_BITDEPTH_8, 
332            MNG_COLORTYPE_RGB, 
333            MNG_COMPRESSION_DEFLATE, 
334            MNG_FILTER_ADAPTIVE, 
335            MNG_INTERLACE_NONE);
336            
337         // not implemented in lib yet
338         //mng_putimgdata_ihdr(mng, getWidth(), getHeight(), 
339         //   MNG_COLORTYPE_RGB, 
340         //   MNG_BITDEPTH_8, 
341         //   MNG_COMPRESSION_DEFLATE, 
342         //   MNG_FILTER_ADAPTIVE, 
343         //   MNG_INTERLACE_NONE, 
344         //   MNG_CANVAS_RGB8, mngCanvasLineFn);
345         break;
346     case GFXFormatR8G8B8A8:
347         mng_putchunk_ihdr(mng, getWidth(), getHeight(), 
348            MNG_BITDEPTH_8, 
349            MNG_COLORTYPE_RGBA, 
350            MNG_COMPRESSION_DEFLATE, 
351            MNG_FILTER_ADAPTIVE, 
352            MNG_INTERLACE_NONE);
353            
354         // not implemented in lib yet
355         //mng_putimgdata_ihdr(mng, getWidth(), getHeight(), 
356         //   MNG_COLORTYPE_RGBA, 
357         //   MNG_BITDEPTH_8, 
358         //   MNG_COMPRESSION_DEFLATE, 
359         //   MNG_FILTER_ADAPTIVE, 
360         //   MNG_INTERLACE_NONE, 
361         //   MNG_CANVAS_RGBA8, mngCanvasLineFn);
362         break;
363   }
364   
365   
366   // below is a hack until libmng is mature enough to handle this itself
367   //-----------------------------------------------------------------------------
368   
369  
370   U8[this->byteSize + getHeight()];
371   if(tmpbuffer == 0)
372   {
373      mng_cleanup(&mng);
374      return false;
375   }
376   
377   // transfer data, add filterbyte
378   U32 effwdt = getWidth() * this->bytesPerPixel;
379   for(U32 Row = 0; Row < getHeight(); Row++)
380   {
381      // first Byte in each scanline is filterbyte: currently 0 -> no filter
382      tmpbuffer[Row * (effwdt + 1)] = 0; 
383      
384      // copy the scanline
385      dMemcpy(tmpbuffer + Row * (effwdt + 1) + 1, getAddress(0, Row), effwdt);
386   } 
387   
388   // compress data with zlib
389   U8[this->byteSize + getHeight()];
390   if(dstbuffer == 0)
391   {
392      delete [] tmpbuffer;
393      mng_cleanup(&mng);
394      return false;
395   }
396
397   U32 dstbufferSize = this->byteSize + getHeight();
398   if(Z_OK != compress2((Bytef*)dstbuffer,(uLongf*)&dstbufferSize, (const Bytef*)tmpbuffer, dstbufferSize, 9))
399   {
400      delete [] tmpbuffer;
401      delete [] dstbuffer;
402      mng_cleanup(&mng);
403      return false;
404   }
405   
406   mng_putchunk_idat(mng, dstbufferSize, (mng_ptr*)dstbuffer);
407   
408   
409   //-----------------------------------------------------------------------------
410   
411   
412   mng_putchunk_iend(mng);
413   
414   delete [] tmpbuffer;
415   delete [] dstbuffer;
416   
417   mng_write(mng);
418   mng_cleanup(&mng);
419   
420   return true;
421#endif
422}
423