bitmapTga.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  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. static bool sReadTGA(Stream &stream, GBitmap *bitmap);
  25. static bool sWriteTGA(GBitmap *bitmap, Stream &stream, U32 compressionLevel);
  26. static struct _privateRegisterTGA
  27. {
  28. _privateRegisterTGA()
  29. {
  30. GBitmap::Registration reg;
  31. reg.extensions.push_back( "tga" );
  32. reg.readFunc = sReadTGA;
  33. reg.writeFunc = sWriteTGA;
  34. GBitmap::sRegisterFormat( reg );
  35. }
  36. } sStaticRegisterTGA;
  37. //------------------------------------------------------------------------------
  38. //-------------------------------------- Supplementary I/O
  39. //
  40. enum eImageType
  41. {
  42. TypeNoData = 0,
  43. TypeUncPaletted = 1,
  44. TypeUncTruecolor = 2,
  45. TypeUncGrayscale = 3,
  46. TypeRlePaletted = 9,
  47. TypeRleTruecolor = 10,
  48. TypeRleGrayscale = 11
  49. };
  50. enum ePixelMap
  51. {
  52. MapLowerLeft = 0,
  53. MapLowerRight = 1,
  54. MapUpperLeft = 2,
  55. MapUpperRight = 3,
  56. };
  57. static void tga_write_pixel_to_mem( U8 * dat, U8 img_spec, U32 number,
  58. U32 w, U32 h, U32 pixel, U32 bppOut )
  59. {
  60. // write the pixel to the data regarding how the
  61. // header says the data is ordered.
  62. U32 x, y;
  63. switch( (img_spec & 0x30) >> 4 )
  64. {
  65. case MapLowerRight:
  66. x = w - 1 - (number % w);
  67. y = h - 1 - (number / w);
  68. break;
  69. case MapUpperLeft:
  70. x = number % w;
  71. y = number / w;
  72. break;
  73. case MapUpperRight:
  74. x = w - 1 - (number % w);
  75. y = number / w;
  76. break;
  77. case MapLowerLeft:
  78. default:
  79. x = number % w;
  80. y = h - 1 - (number / w);
  81. break;
  82. }
  83. U32 addy = (y * w + x) * bppOut;
  84. for ( U32 j = 0; j < bppOut; j++ )
  85. dat[addy + j] = (U8)((pixel >> (j * 8)) & 0xFF);
  86. }
  87. static U32 tga_get_pixel( Stream& stream, U8 bppIn,
  88. U8 * colormap, U8 cmapBytesEntry )
  89. {
  90. /* get the image data value out */
  91. U32 tmp_int32 = 0;
  92. for ( U32 j = 0; j < bppIn; j++ )
  93. {
  94. U8 tmp_byte;
  95. if ( !stream.read( &tmp_byte ) )
  96. tmp_int32 = 0;
  97. else
  98. tmp_int32 += tmp_byte << (j * 8);
  99. }
  100. /* byte-order correct the thing */
  101. switch( bppIn )
  102. {
  103. case 2:
  104. tmp_int32 = convertLEndianToHost( (U16)tmp_int32 );
  105. break;
  106. case 3: /* intentional fall-thru */
  107. case 4:
  108. tmp_int32 = convertLEndianToHost( tmp_int32 );
  109. break;
  110. }
  111. U32 tmp_col;
  112. if ( colormap )
  113. {
  114. /* need to look up value to get real color */
  115. tmp_col = 0;
  116. for ( U32 j = 0; j < cmapBytesEntry; j++ )
  117. tmp_col += colormap[cmapBytesEntry * tmp_int32 + j] << (8 * j);
  118. }
  119. else
  120. {
  121. tmp_col = tmp_int32;
  122. }
  123. return tmp_col;
  124. }
  125. static U32 tga_convert_color( U32 pixel, U32 bppIn, U8 alphabits, U32 bppOut )
  126. {
  127. // this is not only responsible for converting from different depths
  128. // to other depths, it also switches BGR to RGB.
  129. // this thing will also premultiply alpha, on a pixel by pixel basis.
  130. U8 r, g, b, a;
  131. switch( bppIn )
  132. {
  133. case 32:
  134. if ( alphabits == 0 )
  135. goto is_24_bit_in_disguise;
  136. // 32-bit to 32-bit -- nop.
  137. break;
  138. case 24:
  139. is_24_bit_in_disguise:
  140. // 24-bit to 32-bit; (only force alpha to full)
  141. pixel |= 0xFF000000;
  142. break;
  143. case 15:
  144. is_15_bit_in_disguise:
  145. r = (U8)(((F32)((pixel & 0x7C00) >> 10)) * 8.2258f);
  146. g = (U8)(((F32)((pixel & 0x03E0) >> 5 )) * 8.2258f);
  147. b = (U8)(((F32)(pixel & 0x001F)) * 8.2258f);
  148. // 15-bit to 32-bit; (force alpha to full)
  149. pixel = 0xFF000000 + (r << 16) + (g << 8) + b;
  150. break;
  151. case 16:
  152. if ( alphabits == 1 )
  153. goto is_15_bit_in_disguise;
  154. // 16-bit to 32-bit; (force alpha to full)
  155. r = (U8)(((F32)((pixel & 0xF800) >> 11)) * 8.2258f);
  156. g = (U8)(((F32)((pixel & 0x07E0) >> 5 )) * 4.0476f);
  157. b = (U8)(((F32)(pixel & 0x001F)) * 8.2258f);
  158. pixel = 0xFF000000 + (r << 16) + (g << 8) + b;
  159. break;
  160. }
  161. // convert the 32-bit pixel from BGR to RGB.
  162. pixel = (pixel & 0xFF00FF00) + ((pixel & 0xFF) << 16) + ((pixel & 0xFF0000) >> 16);
  163. r = pixel & 0x000000FF;
  164. g = (pixel & 0x0000FF00) >> 8;
  165. b = (pixel & 0x00FF0000) >> 16;
  166. a = (pixel & 0xFF000000) >> 24;
  167. // not premultiplied alpha -- multiply.
  168. r = (U8)(((F32)r / 255.0f) * ((F32)a / 255.0f) * 255.0f);
  169. g = (U8)(((F32)g / 255.0f) * ((F32)a / 255.0f) * 255.0f);
  170. b = (U8)(((F32)b / 255.0f) * ((F32)a / 255.0f) * 255.0f);
  171. pixel = r + (g << 8) + (b << 16) + (a << 24);
  172. /* now convert from 32-bit to whatever they want. */
  173. switch( bppOut )
  174. {
  175. case 4:
  176. // 32 to 32 -- nop.
  177. break;
  178. case 3:
  179. // 32 to 24 -- discard alpha.
  180. pixel &= 0x00FFFFFF;
  181. break;
  182. }
  183. return pixel;
  184. }
  185. static bool sReadTGA(Stream &stream, GBitmap *bitmap)
  186. {
  187. PROFILE_SCOPE(sReadTGA);
  188. struct Header
  189. {
  190. U8 idLength; // length of the image_id string below.
  191. U8 cmapType; // paletted image <=> cmapType
  192. U8 imageType; // can be any of the IMG_TYPE constants above.
  193. U16 cmapFirst; //
  194. U16 cmapLength; // how long the colormap is
  195. U8 cmapEntrySize; // how big a palette entry is.
  196. U16 xOrigin; // the x origin of the image in the image data.
  197. U16 yOrigin; // the y origin of the image in the image data.
  198. U16 width; // the width of the image.
  199. U16 height; // the height of the image.
  200. U8 pixelDepth; // the depth of a pixel in the image.
  201. U8 imageDesc; // the image descriptor.
  202. };
  203. // Read header
  204. Header header;
  205. stream.read( &header.idLength );
  206. stream.read( &header.cmapType );
  207. stream.read( &header.imageType );
  208. stream.read( &header.cmapFirst );
  209. stream.read( &header.cmapLength );
  210. stream.read( &header.cmapEntrySize );
  211. stream.read( &header.xOrigin );
  212. stream.read( &header.yOrigin );
  213. stream.read( &header.width );
  214. stream.read( &header.height );
  215. stream.read( &header.pixelDepth );
  216. stream.read( &header.imageDesc );
  217. U32 numPixels = header.width * header.height;
  218. if ( numPixels == 0 )
  219. {
  220. //Con::errorf( "Texture has width and/or height set to 0" );
  221. return false;
  222. }
  223. U8 alphabits = header.imageDesc & 0x0F;
  224. /* seek past the image id, if there is one */
  225. if ( header.idLength )
  226. {
  227. if ( !stream.setPosition( stream.getPosition() + header.idLength ) )
  228. {
  229. //Con::errorf( "Unexpected end of stream encountered" );
  230. return false;
  231. }
  232. }
  233. /* if this is a 'nodata' image, just jump out. */
  234. if ( header.imageType == TypeNoData )
  235. {
  236. //Con::errorf( "Texture contains no data" );
  237. return false;
  238. }
  239. /* deal with the colormap, if there is one. */
  240. U8* colormap = NULL;
  241. U32 cmapBytes = 0;
  242. U8 cmapBytesEntry = 0;
  243. if ( header.cmapType )
  244. {
  245. switch( header.imageType )
  246. {
  247. case TypeUncPaletted:
  248. case TypeRlePaletted:
  249. break;
  250. case TypeUncTruecolor:
  251. case TypeRleTruecolor:
  252. // this should really be an error, but some really old
  253. // crusty targas might actually be like this (created by TrueVision, no less!)
  254. // so, we'll hack our way through it.
  255. break;
  256. case TypeUncGrayscale:
  257. case TypeRleGrayscale:
  258. //Con::errorf( "Found colormap for a grayscale image" );
  259. return false;
  260. }
  261. /* ensure colormap entry size is something we support */
  262. if ( !(header.cmapEntrySize == 15 ||
  263. header.cmapEntrySize == 16 ||
  264. header.cmapEntrySize == 24 ||
  265. header.cmapEntrySize == 32) )
  266. {
  267. //Con::errorf( "Unsupported colormap entry size" );
  268. return false;
  269. }
  270. /* allocate memory for a colormap */
  271. if ( header.cmapEntrySize & 0x07 )
  272. cmapBytesEntry = (((8 - (header.cmapEntrySize & 0x07)) + header.cmapEntrySize) >> 3);
  273. else
  274. cmapBytesEntry = (header.cmapEntrySize >> 3);
  275. cmapBytes = cmapBytesEntry * header.cmapLength;
  276. colormap = new U8[ cmapBytes ];
  277. for ( U32 i = 0; i < header.cmapLength; i++ )
  278. {
  279. /* seek ahead to first entry used */
  280. if ( header.cmapFirst != 0 )
  281. stream.setPosition( stream.getPosition() + header.cmapFirst * cmapBytesEntry );
  282. U32 tmp_int32 = 0;
  283. for ( U32 j = 0; j < cmapBytesEntry; j++ )
  284. {
  285. U8 tmp_byte;
  286. if ( !stream.read( &tmp_byte ) )
  287. {
  288. delete [] colormap;
  289. //Con::errorf( "Bad colormap" );
  290. return false;
  291. }
  292. tmp_int32 += tmp_byte << (j * 8);
  293. }
  294. // byte order correct.
  295. tmp_int32 = convertLEndianToHost( tmp_int32 );
  296. for ( U32 j = 0; j < cmapBytesEntry; j++ )
  297. colormap[i * cmapBytesEntry + j] = (tmp_int32 >> (8 * j)) & 0xFF;
  298. }
  299. }
  300. // compute number of bytes in an image data unit (either index or BGR triple)
  301. U8 inBytesPerPixel = 0;
  302. if ( header.pixelDepth & 0x07 )
  303. inBytesPerPixel = (((8 - (header.pixelDepth & 0x07)) + header.pixelDepth) >> 3);
  304. else
  305. inBytesPerPixel = (header.pixelDepth >> 3);
  306. /* assume that there's one byte per pixel */
  307. if ( inBytesPerPixel == 0 )
  308. inBytesPerPixel = 1;
  309. GFXFormat gfxFmt;
  310. U32 outBytesPerPixel;
  311. switch ( header.pixelDepth )
  312. {
  313. case 32:
  314. gfxFmt = GFXFormatR8G8B8A8;
  315. outBytesPerPixel = 4;
  316. break;
  317. case 24:
  318. default:
  319. gfxFmt = GFXFormatR8G8B8;
  320. outBytesPerPixel = 3;
  321. break;
  322. }
  323. bitmap->allocateBitmap( header.width, header.height, false, gfxFmt );
  324. // compute the true number of bits per pixel
  325. U8 trueBitsPerPixel = header.cmapType ? header.cmapEntrySize : header.pixelDepth;
  326. // Override the number of alpha bits if necessary
  327. // Some apps generate transparent TGAs with alphabits set to 0 in the image descriptor
  328. if ( ( trueBitsPerPixel == 32 ) && ( alphabits == 0 ) )
  329. alphabits = 8;
  330. switch( header.imageType )
  331. {
  332. case TypeUncTruecolor:
  333. case TypeUncGrayscale:
  334. case TypeUncPaletted:
  335. /* FIXME: support grayscale */
  336. for ( U32 i = 0; i < numPixels; i++ )
  337. {
  338. // get the color value.
  339. U32 tmp_col = tga_get_pixel( stream, inBytesPerPixel, colormap, cmapBytesEntry );
  340. tmp_col = tga_convert_color( tmp_col, trueBitsPerPixel, alphabits, outBytesPerPixel );
  341. // now write the data out.
  342. tga_write_pixel_to_mem( bitmap->getAddress( 0, 0 ), header.imageDesc,
  343. i, header.width, header.height, tmp_col, outBytesPerPixel );
  344. }
  345. break;
  346. case TypeRleTruecolor:
  347. case TypeRleGrayscale:
  348. case TypeRlePaletted:
  349. // FIXME: handle grayscale..
  350. for ( U32 i = 0; i < numPixels; )
  351. {
  352. /* a bit of work to do to read the data.. */
  353. U8 packet_header;
  354. if ( !stream.read( 1, &packet_header ) )
  355. {
  356. // well, just let them fill the rest with null pixels then...
  357. packet_header = 1;
  358. }
  359. if ( packet_header & 0x80 )
  360. {
  361. /* run length packet */
  362. U32 tmp_col = tga_get_pixel( stream, inBytesPerPixel, colormap, cmapBytesEntry );
  363. tmp_col = tga_convert_color( tmp_col, trueBitsPerPixel, alphabits, outBytesPerPixel );
  364. U8 repcount = (packet_header & 0x7F) + 1;
  365. /* write all the data out */
  366. for ( U32 j = 0; j < repcount; j++ )
  367. {
  368. tga_write_pixel_to_mem( bitmap->getAddress( 0, 0 ), header.imageDesc,
  369. i + j, header.width, header.height, tmp_col, outBytesPerPixel );
  370. }
  371. i += repcount;
  372. }
  373. else
  374. {
  375. /* raw packet */
  376. /* get pixel from file */
  377. U8 repcount = (packet_header & 0x7F) + 1;
  378. for ( U32 j = 0; j < repcount; j++ )
  379. {
  380. U32 tmp_col = tga_get_pixel( stream, inBytesPerPixel, colormap, cmapBytesEntry );
  381. tmp_col = tga_convert_color( tmp_col, trueBitsPerPixel, alphabits, outBytesPerPixel );
  382. tga_write_pixel_to_mem( bitmap->getAddress( 0, 0 ), header.imageDesc,
  383. i + j, header.width, header.height, tmp_col, outBytesPerPixel );
  384. }
  385. i += repcount;
  386. }
  387. }
  388. break;
  389. default:
  390. //Con::errorf( "Unknown image type" );
  391. delete[] colormap;
  392. return false;
  393. }
  394. delete [] colormap;
  395. // 32-bit tgas have an alpha channel
  396. bitmap->setHasTransparency( header.pixelDepth == 32 );
  397. return true;
  398. }
  399. static bool sWriteTGA(GBitmap *bitmap, Stream &stream, U32 compressionLevel)
  400. {
  401. AssertISV(false, "GBitmap::writeTGA - doesn't support writing tga files!");
  402. return false;
  403. }