tga.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. /*
  2. Copyright (C) 2004-2005 Michael Liebscher <johnnycanuck@users.sourceforge.net>
  3. Copyright (C) 1995 Spencer Kimball and Peter Mattis
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. */
  16. /*
  17. * tga.h: Handle Targa file format.
  18. *
  19. * Author: Michael Liebscher <johnnycanuck@users.sourceforge.net>
  20. *
  21. * Acknowledgement:
  22. * Portion of this code was derived from The GIMP -- an image manipulation
  23. * program, and was originally written by Spencer Kimball and Peter Mattis.
  24. *
  25. */
  26. /*
  27. Notes:
  28. */
  29. #include "../wolfiphone.h"
  30. #define TGA_HEADER_SIZE 18
  31. #ifndef IPHONE
  32. PRIVATE W8 *p_buf; // current pointer to tga data block
  33. #endif
  34. /* TRUEVISION-XFILE magic signature string */
  35. static W8 magic[ 18 ] =
  36. {
  37. 0x54, 0x52, 0x55, 0x45, 0x56, 0x49, 0x53, 0x49, 0x4f,
  38. 0x4e, 0x2d, 0x58, 0x46, 0x49, 0x4c, 0x45, 0x2e, 0x0
  39. };
  40. typedef struct _TargaHeader
  41. {
  42. W8 idLength;
  43. W8 colorMapType;
  44. W8 imageType;
  45. /* Known image types. */
  46. #define TGA_TYPE_MAPPED 1
  47. #define TGA_TYPE_COLOR 2
  48. #define TGA_TYPE_GRAY 3
  49. W8 imageCompression;
  50. /* Only known compression is RLE */
  51. #define TGA_COMP_NONE 0
  52. #define TGA_COMP_RLE 1
  53. /* Color Map Specification. */
  54. W16 colorMapIndex;
  55. W16 colorMapLength;
  56. W8 colorMapSize;
  57. /* Image Specification. */
  58. W16 xOrigin;
  59. W16 yOrigin;
  60. W16 width;
  61. W16 height;
  62. W8 bpp;
  63. W8 bytes;
  64. W8 alphaBits;
  65. W8 flipHoriz;
  66. W8 flipVert;
  67. } TargaHeader;
  68. PRIVATE void flip_line( W8 *buffer, TargaHeader *info )
  69. {
  70. W8 temp;
  71. W8 *alt;
  72. SW32 x, s;
  73. alt = buffer + (info->bytes * (info->width - 1));
  74. for( x = 0; x * 2 <= info->width; ++x )
  75. {
  76. for( s = 0; s < info->bytes; ++s )
  77. {
  78. temp = buffer[ s ];
  79. buffer[ s ] = alt[ s ];
  80. alt[ s ] = temp;
  81. }
  82. buffer += info->bytes;
  83. alt -= info->bytes;
  84. }
  85. }
  86. PRIVATE void upsample( W8 *dest, W8 *src,
  87. W32 width, W32 bytes, W8 alphaBits )
  88. {
  89. W32 x;
  90. for( x = 0 ; x < width ; ++x )
  91. {
  92. dest[0] = ((src[1] << 1) & 0xf8);
  93. dest[0] += (dest[0] >> 5);
  94. dest[1] = ((src[0] & 0xe0) >> 2) + ((src[1] & 0x03) << 6);
  95. dest[1] += (dest[1] >> 5);
  96. dest[2] = ((src[0] << 3) & 0xf8);
  97. dest[2] += (dest[2] >> 5);
  98. switch( alphaBits )
  99. {
  100. case 1:
  101. dest[ 3 ] = (src[ 1 ] & 0x80) ? 0 : 255;
  102. dest += 4;
  103. break;
  104. default:
  105. dest += 3;
  106. }
  107. src += bytes;
  108. }
  109. }
  110. PRIVATE void bgr2rgb( W8 *dest, W8 *src,
  111. W32 width, W32 bytes, W32 alpha )
  112. {
  113. W32 x;
  114. if( alpha )
  115. {
  116. for( x = 0 ; x < width ; ++x )
  117. {
  118. *(dest++) = src[2];
  119. *(dest++) = src[1];
  120. *(dest++) = src[0];
  121. *(dest++) = src[3];
  122. src += bytes;
  123. }
  124. }
  125. else
  126. {
  127. for( x = 0 ; x < width ; ++x )
  128. {
  129. *(dest++) = src[2];
  130. *(dest++) = src[1];
  131. *(dest++) = src[0];
  132. src += bytes;
  133. }
  134. }
  135. }
  136. PRIVATE SW32 rle_read( filehandle_t *fp, W8 *buffer,
  137. TargaHeader *info )
  138. {
  139. static SW32 repeat = 0;
  140. static SW32 direct = 0;
  141. static W8 sample[ 4 ];
  142. SW32 head;
  143. W8 temphead;
  144. SW32 x, k;
  145. for( x = 0; x < info->width; ++x )
  146. {
  147. if( repeat == 0 && direct == 0 )
  148. {
  149. FS_ReadFile( &temphead, 1, 1, fp );
  150. head = temphead;
  151. if( head >= 128 )
  152. {
  153. repeat = head - 127;
  154. if( FS_ReadFile( sample, info->bytes, 1, fp ) < 1 )
  155. {
  156. return EOF;
  157. }
  158. }
  159. else
  160. {
  161. direct = head + 1;
  162. }
  163. }
  164. if( repeat > 0 )
  165. {
  166. for( k = 0 ; k < info->bytes ; ++k )
  167. {
  168. buffer[ k ] = sample[ k ];
  169. }
  170. repeat--;
  171. }
  172. else /* direct > 0 */
  173. {
  174. if( FS_ReadFile( buffer, info->bytes, 1, fp ) < 1 )
  175. {
  176. return EOF;
  177. }
  178. direct--;
  179. }
  180. buffer += info->bytes;
  181. }
  182. return 0;
  183. }
  184. PRIVATE void read_line( filehandle_t *fp,
  185. W8 *row,
  186. W8 *buffer,
  187. TargaHeader *info )
  188. {
  189. if( info->imageCompression == TGA_COMP_RLE )
  190. {
  191. if( rle_read( fp, buffer, info ) == EOF )
  192. {
  193. return;
  194. }
  195. }
  196. else
  197. {
  198. FS_ReadFile( buffer, info->bytes, info->width, fp );
  199. }
  200. if( info->flipHoriz )
  201. {
  202. flip_line( buffer, info );
  203. }
  204. if( info->imageType == TGA_TYPE_COLOR )
  205. {
  206. if( info->bpp == 16 || info->bpp == 15 )
  207. {
  208. upsample( row, buffer, info->width, info->bytes, info->alphaBits );
  209. }
  210. else
  211. {
  212. bgr2rgb( row, buffer, info->width, info->bytes, info->bytes == 4 ? 1 : 0 );
  213. }
  214. }
  215. else
  216. {
  217. memcpy( row, buffer, info->width * info->bpp );
  218. }
  219. }
  220. PUBLIC void LoadTGA( const char *filename, W8 **pic, W16 *width, W16 *height, W16 *bytes )
  221. {
  222. TargaHeader targa_header;
  223. W8 header[ 18 ];
  224. W8 footer[ 26 ];
  225. W8 extension[ 495 ];
  226. W32 cmap_bytes;
  227. SW32 offset;
  228. W8 tga_cmap[4 * 256], gimp_cmap[3 * 256];
  229. W8 *buffer, *data, *row;
  230. int i;
  231. SW32 datalength;
  232. filehandle_t *hFile;
  233. *pic = NULL;
  234. //
  235. // Load the file
  236. //
  237. hFile = FS_OpenFile( filename, 0 );
  238. if( ! hFile )
  239. {
  240. Com_DPrintf( "Could not open (%s) for reading\n", filename );
  241. goto TGALOADFAILED;
  242. }
  243. datalength = FS_GetFileSize( hFile );
  244. if( ! FS_FileSeek( hFile, -26L, SEEK_END ) )
  245. {
  246. /* Is file big enough for a footer? */
  247. if( FS_ReadFile( footer, sizeof( footer ), 1, hFile ) != 1 )
  248. {
  249. Com_DPrintf( "Cannot read footer from (%s)\n" , filename );
  250. goto TGALOADFAILED;
  251. }
  252. else if( memcmp( footer + 8, magic, sizeof( magic ) ) == 0 )
  253. {
  254. /* Check the signature. */
  255. offset = footer[ 0 ] + (footer[ 1 ] * 256) + (footer[ 2 ] * 65536)
  256. + (footer[ 3 ] * 16777216);
  257. if( offset != 0 )
  258. {
  259. if( FS_FileSeek( hFile, offset, SEEK_SET ) ||
  260. FS_ReadFile( extension, sizeof( extension ), 1, hFile ) != 1 )
  261. {
  262. Com_DPrintf( "Cannot read extension from '%s'\n", filename );
  263. goto TGALOADFAILED;
  264. }
  265. /* Eventually actually handle version 2 TGA here */
  266. }
  267. }
  268. }
  269. //
  270. // Get header information.
  271. //
  272. if( datalength < TGA_HEADER_SIZE )
  273. {
  274. Com_Printf( "Could not read header from (%s)\n", filename );
  275. goto TGALOADFAILED;
  276. }
  277. if( FS_FileSeek( hFile, 0, SEEK_SET ) ||
  278. FS_ReadFile( header, sizeof( header ), 1, hFile ) != 1 )
  279. {
  280. Com_Printf( "Cannot read header from (%s)\n", filename );
  281. goto TGALOADFAILED;
  282. }
  283. targa_header.idLength = header[ 0 ];
  284. targa_header.colorMapType = header[ 1 ];
  285. switch( header[ 2 ] )
  286. {
  287. case 1:
  288. targa_header.imageType = TGA_TYPE_MAPPED;
  289. targa_header.imageCompression = TGA_COMP_NONE;
  290. break;
  291. case 2:
  292. targa_header.imageType = TGA_TYPE_COLOR;
  293. targa_header.imageCompression = TGA_COMP_NONE;
  294. break;
  295. case 3:
  296. targa_header.imageType = TGA_TYPE_GRAY;
  297. targa_header.imageCompression = TGA_COMP_NONE;
  298. break;
  299. case 9:
  300. targa_header.imageType = TGA_TYPE_MAPPED;
  301. targa_header.imageCompression = TGA_COMP_RLE;
  302. break;
  303. case 10:
  304. targa_header.imageType = TGA_TYPE_COLOR;
  305. targa_header.imageCompression = TGA_COMP_RLE;
  306. break;
  307. case 11:
  308. targa_header.imageType = TGA_TYPE_GRAY;
  309. targa_header.imageCompression = TGA_COMP_RLE;
  310. break;
  311. default:
  312. targa_header.imageType = 0;
  313. }
  314. targa_header.colorMapIndex = header[ 3 ] + header[ 4 ] * 256;
  315. targa_header.colorMapLength = header[ 5 ] + header[ 6 ] * 256;
  316. targa_header.colorMapSize = header[ 7 ];
  317. targa_header.xOrigin = header[ 8 ] + header[ 9 ] * 256;
  318. targa_header.yOrigin = header[ 10 ] + header[ 11 ] * 256;
  319. targa_header.width = header[ 12 ] + header[ 13 ] * 256;
  320. targa_header.height = header[ 14 ] + header[ 15 ] * 256;
  321. targa_header.bpp = header[ 16 ];
  322. targa_header.bytes = (targa_header.bpp + 7) / 8;
  323. targa_header.alphaBits = header[ 17 ] & 0x0f; /* Just the low 4 bits */
  324. targa_header.flipHoriz = (header[ 17 ] & 0x10) ? 1 : 0;
  325. targa_header.flipVert = (header[ 17 ] & 0x20) ? 0 : 1;
  326. //
  327. // Analyze header information.
  328. //
  329. switch( targa_header.imageType )
  330. {
  331. case TGA_TYPE_MAPPED:
  332. if( targa_header.bpp != 8 )
  333. {
  334. Com_DPrintf( "Unhandled sub-format in (%s)\n", filename );
  335. goto TGALOADFAILED;
  336. }
  337. goto TGALOADFAILED;
  338. break;
  339. case TGA_TYPE_COLOR:
  340. if( targa_header.bpp != 15 && targa_header.bpp != 16 && targa_header.bpp != 24
  341. && targa_header.bpp != 32 )
  342. {
  343. Com_DPrintf( "Unhandled sub-format in (%s)\n", filename );
  344. goto TGALOADFAILED;
  345. }
  346. break;
  347. case TGA_TYPE_GRAY:
  348. if( targa_header.bpp != 8 && (targa_header.alphaBits != 8 || (targa_header.bpp != 16 && targa_header.bpp != 15 )))
  349. {
  350. Com_DPrintf( "Unhandled sub-format in (%s)\n", filename );
  351. goto TGALOADFAILED;
  352. }
  353. goto TGALOADFAILED;
  354. break;
  355. default:
  356. Com_DPrintf( "Unknown image type for (%s)\n", filename );
  357. goto TGALOADFAILED;
  358. } /* end of switch targa_header.imageType */
  359. /* Plausible but unhandled formats */
  360. if( targa_header.bytes * 8 != targa_header.bpp && ! (targa_header.bytes == 2 && targa_header.bpp == 15) )
  361. {
  362. Com_DPrintf( "No support yet for TGA with these parameters\n" );
  363. goto TGALOADFAILED;
  364. }
  365. /* Check that we have a color map only when we need it. */
  366. if( targa_header.imageType == TGA_TYPE_MAPPED && targa_header.colorMapType != 1 )
  367. {
  368. Com_DPrintf( "Indexed image has invalid color map type %d\n",
  369. targa_header.colorMapType );
  370. goto TGALOADFAILED;
  371. }
  372. else if( targa_header.imageType != TGA_TYPE_MAPPED && targa_header.colorMapType != 0 )
  373. {
  374. Com_DPrintf( "Non-indexed image has invalid color map type %d\n",
  375. targa_header.colorMapType );
  376. goto TGALOADFAILED;
  377. }
  378. /* Skip the image ID field. */
  379. if( targa_header.idLength && FS_FileSeek( hFile, targa_header.idLength, SEEK_CUR ) )
  380. {
  381. Com_DPrintf( "File (%s) is truncated or corrupted\n", filename );
  382. goto TGALOADFAILED;
  383. }
  384. /* Handle colormap */
  385. if( targa_header.colorMapType == 1 )
  386. {
  387. cmap_bytes = (targa_header.colorMapSize + 7 ) / 8;
  388. if( cmap_bytes <= 4 &&
  389. FS_ReadFile( tga_cmap, targa_header.colorMapLength * cmap_bytes, 1, hFile ) == 1 )
  390. {
  391. if( targa_header.colorMapSize == 32 )
  392. {
  393. bgr2rgb( gimp_cmap, tga_cmap, targa_header.colorMapLength, cmap_bytes, 1);
  394. }
  395. else if( targa_header.colorMapSize == 24 )
  396. {
  397. bgr2rgb( gimp_cmap, tga_cmap, targa_header.colorMapLength, cmap_bytes, 0);
  398. }
  399. else if( targa_header.colorMapSize == 16 || targa_header.colorMapSize == 15 )
  400. {
  401. upsample( gimp_cmap, tga_cmap, targa_header.colorMapLength, cmap_bytes, targa_header.alphaBits);
  402. }
  403. }
  404. else
  405. {
  406. Com_DPrintf( "File (%s) is truncated or corrupted\n", filename );
  407. goto TGALOADFAILED;
  408. }
  409. }
  410. /* Allocate the data. */
  411. data = MM_MALLOC( targa_header.width * targa_header.height * targa_header.bytes );
  412. if( data == NULL )
  413. {
  414. MM_OUTOFMEM( "data" );
  415. }
  416. buffer = (PW8) MM_MALLOC( targa_header.width * targa_header.bytes );
  417. if( buffer == NULL )
  418. {
  419. MM_FREE( data );
  420. MM_OUTOFMEM( "buffer" );
  421. }
  422. if( targa_header.flipVert )
  423. {
  424. for( i = targa_header.height-1 ; i >= 0 ; --i )
  425. {
  426. row = data + (targa_header.width * targa_header.bytes * i);
  427. read_line( hFile, row, buffer, &targa_header );
  428. }
  429. }
  430. else
  431. {
  432. for( i = 0 ; i < targa_header.height ; ++i )
  433. {
  434. row = data + (targa_header.width * targa_header.bytes * i);
  435. read_line( hFile, row, buffer, &targa_header );
  436. }
  437. }
  438. MM_FREE( buffer );
  439. FS_CloseFile( hFile );
  440. *pic = data;
  441. *width = targa_header.width;
  442. *height = targa_header.height;
  443. *bytes = targa_header.bytes;
  444. return;
  445. TGALOADFAILED:
  446. *pic = NULL;
  447. *width = 0;
  448. *height = 0;
  449. *bytes = 0;
  450. if( hFile )
  451. {
  452. FS_CloseFile( hFile );
  453. }
  454. }
  455. /*
  456. -----------------------------------------------------------------------------
  457. Function: rle_write -Run length encode scanline.
  458. Parameters: fp -[in] Pointer to valid FILE structure.
  459. buffer -[in] Scanline data.
  460. width -[in] Image scanline width.
  461. bytes -[in] Bytes per pixel.
  462. Returns: Nothing.
  463. Notes:
  464. -----------------------------------------------------------------------------
  465. */
  466. PRIVATE void rle_write( FILE *fp,
  467. W8 *buffer,
  468. W32 width,
  469. W32 bytes )
  470. {
  471. SW32 repeat = 0;
  472. SW32 direct = 0;
  473. W8 *from = buffer;
  474. W32 x;
  475. for( x = 1 ; x < width ; ++x )
  476. {
  477. if( memcmp( buffer, buffer + bytes, bytes ) )
  478. {
  479. /* next pixel is different */
  480. if( repeat )
  481. {
  482. putc( 128 + repeat, fp );
  483. fwrite( from, bytes, 1, fp );
  484. from = buffer + bytes; /* point to first different pixel */
  485. repeat = 0;
  486. direct = 0;
  487. }
  488. else
  489. {
  490. direct += 1;
  491. }
  492. }
  493. else
  494. {
  495. /* next pixel is the same */
  496. if( direct )
  497. {
  498. putc( direct - 1, fp );
  499. fwrite( from, bytes, direct, fp );
  500. from = buffer; /* point to first identical pixel */
  501. direct = 0;
  502. repeat = 1;
  503. }
  504. else
  505. {
  506. repeat += 1;
  507. }
  508. }
  509. if( repeat == 128 )
  510. {
  511. putc( 255, fp );
  512. fwrite( from, bytes, 1, fp );
  513. from = buffer + bytes;
  514. direct = 0;
  515. repeat = 0;
  516. }
  517. else if( direct == 128 )
  518. {
  519. putc( 127, fp );
  520. fwrite( from, bytes, direct, fp );
  521. from = buffer + bytes;
  522. direct = 0;
  523. repeat = 0;
  524. }
  525. buffer += bytes;
  526. }
  527. if( repeat > 0 )
  528. {
  529. putc( 128 + repeat, fp );
  530. fwrite( from, bytes, 1, fp );
  531. }
  532. else
  533. {
  534. putc( direct, fp );
  535. fwrite( from, bytes, direct + 1, fp );
  536. }
  537. }
  538. /*
  539. -----------------------------------------------------------------------------
  540. Function: WriteTGA -Write targa image file.
  541. Parameters: filename -[in] Name of TGA file to save as.
  542. bpp -[in] Bits per pixel. (16, 24 or 32).
  543. width -[in] Width of image.
  544. height -[in] Height of image.
  545. Data -[in] Raw image data.
  546. upsideDown -[in] Is the data upside down? 1 yes, 0 no.
  547. rle -[in] Run Length encode? 1 yes, 0 no.
  548. Returns: 0 on error, otherwise 1.
  549. Notes:
  550. -----------------------------------------------------------------------------
  551. */
  552. PUBLIC W8 WriteTGA( const char *filename, W16 bpp, W16 width, W16 height,
  553. void *Data, W8 upsideDown, W8 rle )
  554. {
  555. W16 i, x, y, BytesPerPixel;
  556. W8 *scanline;
  557. W8 header[ 18 ];
  558. FILE *filestream;
  559. W8 *ptr = (PW8) Data;
  560. W8 temp;
  561. BytesPerPixel = bpp >> 3;
  562. filestream = fopen( filename, "wb" );
  563. if( filestream == NULL )
  564. {
  565. Com_DPrintf( "Could not open file (%s) for write!\n", filename );
  566. return 0;
  567. }
  568. memset( header, 0, 18 );
  569. header[2] = rle ? 10 : 2;
  570. header[12] = width & 255; // width low
  571. header[13] = width >> 8; // width high
  572. header[14] = height & 255; // height low
  573. header[15] = height >> 8; // height high
  574. header[16] = bpp & 255; // pixel size
  575. if( upsideDown )
  576. {
  577. header[17] |= 1 << 5; // Image Descriptor
  578. }
  579. fwrite( header, sizeof( W8 ), sizeof( header ), filestream );
  580. scanline = (PW8) MM_MALLOC( width * BytesPerPixel );
  581. if( scanline == NULL )
  582. {
  583. fclose( filestream );
  584. return 0;
  585. }
  586. for( y = 0; y < height; ++y )
  587. {
  588. W32 k = 0;
  589. for( i = 0; i < (width * BytesPerPixel); ++i )
  590. {
  591. scanline[ k++ ] = ptr[ (height - y - 1) * width * BytesPerPixel + i ];
  592. }
  593. if( bpp == 24 || bpp == 32 )
  594. {
  595. // swap rgb to bgr
  596. for( x = 0; x < (width * BytesPerPixel); x += BytesPerPixel )
  597. {
  598. temp = scanline[ x ];
  599. scanline[ x ] = scanline[ x + 2 ];
  600. scanline[ x + 2 ] = temp;
  601. }
  602. }
  603. if( rle )
  604. {
  605. rle_write( filestream, scanline, width, BytesPerPixel );
  606. }
  607. else
  608. {
  609. fwrite( scanline, sizeof( W8 ), width * BytesPerPixel, filestream );
  610. }
  611. }
  612. MM_FREE( scanline );
  613. fclose( filestream );
  614. return 1;
  615. }