bitmapMng.cpp 12 KB

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