Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1001 lines
27 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include <stdio.h>
  7. #include "bitmap/tgaloader.h"
  8. #include "tier0/dbg.h"
  9. #include "basetypes.h"
  10. #include <math.h>
  11. #include "tier1/utlvector.h"
  12. #include "tier1/utlbuffer.h"
  13. #include "filesystem.h"
  14. #include "tier2/tier2.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. namespace TGALoader
  18. {
  19. //-----------------------------------------------------------------------------
  20. // Format of the TGA header on disk
  21. //-----------------------------------------------------------------------------
  22. #pragma pack (1)
  23. struct TGAHeader_t
  24. {
  25. unsigned char id_length;
  26. unsigned char colormap_type;
  27. unsigned char image_type;
  28. unsigned short colormap_index;
  29. unsigned short colormap_length;
  30. unsigned char colormap_size;
  31. unsigned short x_origin;
  32. unsigned short y_origin;
  33. unsigned short width;
  34. unsigned short height;
  35. unsigned char pixel_size;
  36. unsigned char attributes;
  37. };
  38. //-----------------------------------------------------------------------------
  39. // read a row into an RGBA8888 array.
  40. //-----------------------------------------------------------------------------
  41. typedef void (*ReadRowFunc_t)( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDstMemory );
  42. //-----------------------------------------------------------------------------
  43. // output a RGBA8888 row into the destination format.
  44. //-----------------------------------------------------------------------------
  45. typedef void (*OutputRowFunc_t)( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDstMemory );
  46. //-----------------------------------------------------------------------------
  47. // Important constants
  48. //-----------------------------------------------------------------------------
  49. #define TGA_MAX_COLORMAP_SIZE ( 256 * 4 )
  50. #define TGA_MAX_ROW_LENGTH_IN_PIXELS IMAGE_MAX_DIM
  51. //-----------------------------------------------------------------------------
  52. // Globals... blech
  53. //-----------------------------------------------------------------------------
  54. static unsigned char g_ColorMap[TGA_MAX_COLORMAP_SIZE];
  55. // run-length state from row to row for RLE images
  56. static bool g_IsRunLengthPacket;
  57. static int g_PixelsLeftInPacket;
  58. static unsigned char g_SrcGammaTable[256];
  59. static unsigned char g_DstGammaTable[256];
  60. typedef CUtlMemory<unsigned char> CTempImage;
  61. //-----------------------------------------------------------------------------
  62. // Reads in a file, sticks it into a UtlVector
  63. //-----------------------------------------------------------------------------
  64. static bool ReadFile( char const* pFileName, CTempImage& image, int maxbytes = -1 )
  65. {
  66. Assert( pFileName );
  67. Assert( g_pFullFileSystem );
  68. if( !g_pFullFileSystem )
  69. {
  70. return false;
  71. }
  72. FileHandle_t fileHandle;
  73. fileHandle = g_pFullFileSystem->Open( pFileName, "rb" );
  74. if( !fileHandle )
  75. return false;
  76. // How big is the file?
  77. long pos;
  78. if (maxbytes < 0)
  79. {
  80. pos = g_pFullFileSystem->Size( fileHandle );
  81. }
  82. else
  83. {
  84. pos = maxbytes;
  85. }
  86. // Allocate enough space
  87. image.EnsureCapacity( pos );
  88. // Back to the start of the file
  89. g_pFullFileSystem->Seek( fileHandle, 0, FILESYSTEM_SEEK_HEAD );
  90. // Read the file into the vector memory
  91. int len = g_pFullFileSystem->Read( image.Base(), pos, fileHandle );
  92. // Close the file
  93. g_pFullFileSystem->Close( fileHandle );
  94. // It's an error if we didn't read in enough goodies
  95. return len == pos;
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Reads in the TGA Header
  99. //-----------------------------------------------------------------------------
  100. static void ReadHeader( CUtlBuffer& buf, TGAHeader_t& header )
  101. {
  102. buf.Get( &header, sizeof(TGAHeader_t) );
  103. }
  104. //-----------------------------------------------------------------------------
  105. // Figures out TGA information
  106. //-----------------------------------------------------------------------------
  107. bool GetInfo( CUtlBuffer& buf, int *width, int *height,
  108. ImageFormat *imageFormat, float *sourceGamma )
  109. {
  110. TGAHeader_t header;
  111. ReadHeader( buf, header );
  112. switch( header.image_type )
  113. {
  114. case 1: // 8 bit uncompressed TGA image
  115. case 3: // 8 bit monochrome uncompressed TGA image
  116. case 9: // 8 bit compressed TGA image
  117. *imageFormat = IMAGE_FORMAT_I8;
  118. break;
  119. case 2: // 24/32 bit uncompressed TGA image
  120. case 10: // 24/32 bit compressed TGA image
  121. if( header.pixel_size == 32 )
  122. {
  123. *imageFormat = IMAGE_FORMAT_ABGR8888;
  124. }
  125. else if( header.pixel_size == 24 )
  126. {
  127. *imageFormat = IMAGE_FORMAT_BGR888;
  128. }
  129. else
  130. {
  131. return false;
  132. }
  133. break;
  134. default:
  135. return false;
  136. break;
  137. }
  138. *width = header.width;
  139. *height = header.height;
  140. *sourceGamma = ARTWORK_GAMMA;
  141. return true;
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Returns the minimum amount you have to load to get information about the TGA file
  145. //-----------------------------------------------------------------------------
  146. int TGAHeaderSize()
  147. {
  148. return sizeof( TGAHeader_t );
  149. }
  150. //-----------------------------------------------------------------------------
  151. // Gets info about a TGA file
  152. //-----------------------------------------------------------------------------
  153. bool GetInfo( char const* pFileName, int *width, int *height,
  154. ImageFormat *imageFormat, float *sourceGamma )
  155. {
  156. // temporary memory
  157. CTempImage image;
  158. // try to read in the file
  159. if (!ReadFile( pFileName, image, sizeof(TGAHeader_t) ))
  160. return false;
  161. // Serialization buffer
  162. CUtlBuffer buf( image.Base(), image.NumAllocated(), CUtlBuffer::READ_ONLY );
  163. return GetInfo( buf, width, height, imageFormat, sourceGamma );
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Various output methods
  167. //-----------------------------------------------------------------------------
  168. void OutputRowRGBA8888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  169. {
  170. for( int i = 0; i < header.width; ++i, pDst += 4 )
  171. {
  172. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  173. pDst[0] = pSrc[0];
  174. pDst[1] = pSrc[1];
  175. pDst[2] = pSrc[2];
  176. pDst[3] = pSrc[3];
  177. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  178. }
  179. }
  180. void OutputRowABGR8888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  181. {
  182. for( int i = 0; i < header.width; ++i, pDst += 4 )
  183. {
  184. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  185. pDst[3] = pSrc[0];
  186. pDst[2] = pSrc[1];
  187. pDst[1] = pSrc[2];
  188. pDst[0] = pSrc[3];
  189. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  190. }
  191. }
  192. void OutputRowRGB888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  193. {
  194. for( int i = 0; i < header.width; ++i, pDst += 3 )
  195. {
  196. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  197. pDst[0] = pSrc[0];
  198. pDst[1] = pSrc[1];
  199. pDst[2] = pSrc[2];
  200. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  201. }
  202. }
  203. void OutputRowBGR888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  204. {
  205. for( int i = 0; i < header.width; ++i, pDst += 3 )
  206. {
  207. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  208. pDst[2] = pSrc[0];
  209. pDst[1] = pSrc[1];
  210. pDst[0] = pSrc[2];
  211. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  212. }
  213. }
  214. void OutputRowRGB565( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  215. {
  216. Assert( 0 );
  217. }
  218. void OutputRowI8( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  219. {
  220. for( int i = 0; i < header.width; ++i, ++pDst )
  221. {
  222. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  223. if( ( pSrc[0] == pSrc[1] ) && ( pSrc[1] == pSrc[2] ) )
  224. {
  225. pDst[0] = pSrc[0];
  226. }
  227. else
  228. {
  229. pDst[0] = ( unsigned char )( 0.299f * pSrc[0] + 0.587f * pSrc[1] + 0.114f * pSrc[2] );
  230. }
  231. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  232. }
  233. }
  234. void OutputRowIA88( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  235. {
  236. for( int i = 0; i < header.width; ++i, pDst += 2 )
  237. {
  238. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  239. if( ( pSrc[0] == pSrc[1] ) && ( pSrc[1] == pSrc[2] ) )
  240. {
  241. pDst[0] = pSrc[0];
  242. }
  243. else
  244. {
  245. pDst[0] = ( unsigned char )( 0.299f * pSrc[0] + 0.587f * pSrc[1] + 0.114f * pSrc[2] );
  246. }
  247. pDst[1] = pSrc[3];
  248. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  249. }
  250. }
  251. void OutputRowA8( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  252. {
  253. for( int i = 0; i < header.width; ++i, ++pDst )
  254. {
  255. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  256. pDst[0] = pSrc[3];
  257. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  258. }
  259. }
  260. void OutputRowRGB888BlueScreen( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  261. {
  262. for( int i = 0; i < header.width; ++i, pDst += 3 )
  263. {
  264. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  265. pDst[0] = (unsigned char)(( ( int )pSrc[0] * ( int )pSrc[3] ) >> 8);
  266. pDst[1] = (unsigned char)(( ( int )pSrc[1] * ( int )pSrc[3] ) >> 8);
  267. pDst[2] = (( ( ( ( int )pSrc[2] * ( int )pSrc[3] ) ) >> 8 ) + ( 255 - pSrc[3] ));
  268. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  269. }
  270. }
  271. void OutputRowBGR888BlueScreen( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  272. {
  273. for( int i = 0; i < header.width; ++i, pDst += 3 )
  274. {
  275. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  276. pDst[2] = (unsigned char)(( ( int )pSrc[0] * ( int )pSrc[3] ) >> 8);
  277. pDst[1] = (unsigned char)(( ( int )pSrc[1] * ( int )pSrc[3] ) >> 8);
  278. pDst[0] = (unsigned char)(( ( ( ( int )pSrc[2] * ( int )pSrc[3] ) ) >> 8 ) + ( 255 - pSrc[3] ));
  279. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  280. }
  281. }
  282. void OutputRowARGB8888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  283. {
  284. for( int i = 0; i < header.width; ++i, pDst += 4 )
  285. {
  286. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  287. pDst[0] = pSrc[3];
  288. pDst[1] = pSrc[0];
  289. pDst[2] = pSrc[1];
  290. pDst[3] = pSrc[2];
  291. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  292. }
  293. }
  294. void OutputRowBGRA8888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  295. {
  296. for( int i = 0; i < header.width; ++i, pDst += 4 )
  297. {
  298. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  299. pDst[0] = pSrc[2];
  300. pDst[1] = pSrc[1];
  301. pDst[2] = pSrc[0];
  302. pDst[3] = pSrc[3];
  303. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  304. }
  305. }
  306. void OutputRowBGRX8888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  307. {
  308. for( int i = 0; i < header.width; ++i, pDst += 4 )
  309. {
  310. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  311. pDst[0] = pSrc[2];
  312. pDst[1] = pSrc[1];
  313. pDst[2] = pSrc[0];
  314. pDst[3] = 255;
  315. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  316. }
  317. }
  318. void OutputRowBGR565( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  319. {
  320. for( int i = 0; i < header.width; ++i, pDst += 2 )
  321. {
  322. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  323. unsigned short rgba = (pSrc[2] & 0x1F) | ((pSrc[1] & 0x3F) << 5) |
  324. ((pSrc[0] & 0x1F) << 11);
  325. pDst[0] = rgba & 0xFF;
  326. pDst[1] = rgba >> 8;
  327. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  328. }
  329. }
  330. void OutputRowBGRX5551( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  331. {
  332. for( int i = 0; i < header.width; ++i, pDst += 2 )
  333. {
  334. unsigned char* pSrc = (unsigned char*)buf.PeekGet();
  335. unsigned short rgba = (pSrc[2] & 0x1F) | ((pSrc[1] & 0x1F) << 5) |
  336. ((pSrc[0] & 0x1F) << 10) | 0x8000;
  337. pDst[0] = rgba & 0xFF;
  338. pDst[1] = rgba >> 8;
  339. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
  340. }
  341. }
  342. static OutputRowFunc_t GetOutputRowFunc( ImageFormat imageFormat )
  343. {
  344. switch( imageFormat )
  345. {
  346. case IMAGE_FORMAT_RGBA8888:
  347. return &OutputRowRGBA8888;
  348. case IMAGE_FORMAT_ABGR8888:
  349. return &OutputRowABGR8888;
  350. case IMAGE_FORMAT_RGB888:
  351. return &OutputRowRGB888;
  352. case IMAGE_FORMAT_BGR888:
  353. return &OutputRowBGR888;
  354. case IMAGE_FORMAT_RGB565:
  355. return &OutputRowRGB565;
  356. case IMAGE_FORMAT_I8:
  357. return &OutputRowI8;
  358. case IMAGE_FORMAT_IA88:
  359. return &OutputRowIA88;
  360. case IMAGE_FORMAT_A8:
  361. return &OutputRowA8;
  362. case IMAGE_FORMAT_RGB888_BLUESCREEN:
  363. return &OutputRowRGB888BlueScreen;
  364. case IMAGE_FORMAT_BGR888_BLUESCREEN:
  365. return &OutputRowBGR888BlueScreen;
  366. case IMAGE_FORMAT_ARGB8888:
  367. return &OutputRowARGB8888;
  368. case IMAGE_FORMAT_BGRA8888:
  369. return &OutputRowBGRA8888;
  370. case IMAGE_FORMAT_BGRX8888:
  371. return &OutputRowBGRX8888;
  372. case IMAGE_FORMAT_BGR565:
  373. return &OutputRowBGR565;
  374. case IMAGE_FORMAT_BGRX5551:
  375. return &OutputRowBGRX5551;
  376. #ifdef _X360
  377. case IMAGE_FORMAT_LINEAR_RGB888:
  378. return &OutputRowRGB888;
  379. case IMAGE_FORMAT_LINEAR_BGR888:
  380. return &OutputRowBGR888;
  381. #endif
  382. default:
  383. return NULL;
  384. break;
  385. }
  386. }
  387. #if 0
  388. static void InitSourceGammaConversionTable( float srcGamma )
  389. {
  390. static float lastSrcGamma = -1;
  391. if (lastSrcGamma == srcGamma)
  392. return;
  393. lastSrcGamma = srcGamma;
  394. ImageLoader::ConstructGammaTable( g_SrcGammaTable, srcGamma, 1.0f );
  395. }
  396. static void InitDestGammaConversionTable( float dstGamma )
  397. {
  398. static float lastDstGamma = -1;
  399. if (lastDstGamma == dstGamma)
  400. return;
  401. lastDstGamma = dstGamma;
  402. ImageLoader::ConstructGammaTable( g_DstGammaTable, 1.0f, dstGamma );
  403. }
  404. #endif
  405. //-----------------------------------------------------------------------------
  406. // Reads an 8-bit palettized TGA image
  407. //-----------------------------------------------------------------------------
  408. void ReadRow8BitUncompressedWithColormap( CUtlBuffer& buf,
  409. TGAHeader_t const& header, unsigned char* pDst )
  410. {
  411. int i;
  412. unsigned char* colormapEntry;
  413. switch( header.colormap_size )
  414. {
  415. case 8:
  416. for( i = 0; i < header.width; ++i, pDst += 4 )
  417. {
  418. int pal = buf.GetUnsignedChar();
  419. colormapEntry = &g_ColorMap[pal];
  420. pDst[0] = colormapEntry[0];
  421. pDst[1] = colormapEntry[0];
  422. pDst[2] = colormapEntry[0];
  423. pDst[3] = 255;
  424. }
  425. break;
  426. case 24:
  427. for( i = 0; i < header.width; ++i, pDst += 4 )
  428. {
  429. int pal = buf.GetUnsignedChar();
  430. colormapEntry = &g_ColorMap[pal * 3];
  431. pDst[0] = colormapEntry[2];
  432. pDst[1] = colormapEntry[1];
  433. pDst[2] = colormapEntry[0];
  434. pDst[3] = 255;
  435. }
  436. break;
  437. case 32:
  438. for( i = 0; i < header.width; ++i, pDst += 4 )
  439. {
  440. int pal = buf.GetUnsignedChar();
  441. colormapEntry = &g_ColorMap[pal * 4];
  442. pDst[0] = colormapEntry[3];
  443. pDst[1] = colormapEntry[2];
  444. pDst[2] = colormapEntry[1];
  445. pDst[3] = colormapEntry[0];
  446. }
  447. break;
  448. default:
  449. Assert( 0 );
  450. break;
  451. }
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Reads an 8-bit greyscale TGA image
  455. //-----------------------------------------------------------------------------
  456. void ReadRow8BitUncompressedWithoutColormap( CUtlBuffer& buf,
  457. TGAHeader_t const& header, unsigned char* pDst )
  458. {
  459. for( int i = 0; i < header.width; ++i, pDst += 4 )
  460. {
  461. pDst[0] = pDst[1] = pDst[2] = buf.GetUnsignedChar();
  462. pDst[3] = 255;
  463. }
  464. }
  465. //-----------------------------------------------------------------------------
  466. // Reads a 24-bit TGA image
  467. //-----------------------------------------------------------------------------
  468. void ReadRow24BitUncompressedWithoutColormap( CUtlBuffer& buf,
  469. TGAHeader_t const& header, unsigned char* pDst )
  470. {
  471. for( int i = 0; i < header.width; ++i, pDst += 4 )
  472. {
  473. pDst[2] = buf.GetUnsignedChar();
  474. pDst[1] = buf.GetUnsignedChar();
  475. pDst[0] = buf.GetUnsignedChar();
  476. pDst[3] = 255;
  477. }
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Reads a 32-bit TGA image
  481. //-----------------------------------------------------------------------------
  482. void ReadRow32BitUncompressedWithoutColormap( CUtlBuffer& buf,
  483. TGAHeader_t const& header, unsigned char* pDst )
  484. {
  485. for( int i = 0; i < header.width; ++i, pDst += 4 )
  486. {
  487. pDst[2] = buf.GetUnsignedChar();
  488. pDst[1] = buf.GetUnsignedChar();
  489. pDst[0] = buf.GetUnsignedChar();
  490. pDst[3] = buf.GetUnsignedChar();
  491. }
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Decompresses a run-length encoded row of bytes
  495. //-----------------------------------------------------------------------------
  496. static void DecompressRow( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
  497. {
  498. int bytesPerPixel = header.pixel_size >> 3;
  499. int pixelsLeftInRow = header.width;
  500. int numPixelsToProcess;
  501. #ifdef DBGFLAG_ASSERT
  502. unsigned char *pLast = pDst + header.width * bytesPerPixel;
  503. #endif
  504. unsigned char repeat[4] = {};
  505. do
  506. {
  507. if( !g_PixelsLeftInPacket )
  508. {
  509. // start a new packet.
  510. unsigned char packetHeader = buf.GetUnsignedChar();
  511. g_PixelsLeftInPacket = 1 + ( packetHeader & 0x7f );
  512. if( packetHeader & 0x80 )
  513. {
  514. g_IsRunLengthPacket = true;
  515. // Read what I'm supposed to repeat
  516. for (int i = 0; i < bytesPerPixel; ++i)
  517. {
  518. repeat[i] = buf.GetUnsignedChar();
  519. }
  520. }
  521. else
  522. {
  523. g_IsRunLengthPacket = false;
  524. }
  525. }
  526. // already in the middle of a packet of data.
  527. numPixelsToProcess = g_PixelsLeftInPacket;
  528. if( numPixelsToProcess > pixelsLeftInRow )
  529. {
  530. numPixelsToProcess = pixelsLeftInRow;
  531. }
  532. if( g_IsRunLengthPacket )
  533. {
  534. for( int i = numPixelsToProcess; --i >= 0; pDst += bytesPerPixel )
  535. {
  536. for (int j = 0; j < bytesPerPixel; ++j )
  537. {
  538. pDst[j] = repeat[j];
  539. }
  540. }
  541. }
  542. else
  543. {
  544. buf.Get( pDst, numPixelsToProcess * bytesPerPixel );
  545. pDst += numPixelsToProcess * bytesPerPixel;
  546. }
  547. g_PixelsLeftInPacket -= numPixelsToProcess;
  548. pixelsLeftInRow -= numPixelsToProcess;
  549. } while( pixelsLeftInRow );
  550. Assert( pDst == pLast );
  551. }
  552. //-----------------------------------------------------------------------------
  553. // Reads a compressed 8-bit palettized TGA image
  554. //-----------------------------------------------------------------------------
  555. void ReadRow8BitCompressedWithColormap( CUtlBuffer& buf,
  556. TGAHeader_t const& header, unsigned char* pDst )
  557. {
  558. unsigned char rowI_8[TGA_MAX_ROW_LENGTH_IN_PIXELS];
  559. DecompressRow( buf, header, rowI_8 );
  560. CUtlBuffer uncompressedBuf( rowI_8, TGA_MAX_ROW_LENGTH_IN_PIXELS, CUtlBuffer::READ_ONLY );
  561. ReadRow8BitUncompressedWithColormap( uncompressedBuf, header, pDst );
  562. }
  563. //-----------------------------------------------------------------------------
  564. // Reads a compressed 8-bit greyscale TGA image
  565. //-----------------------------------------------------------------------------
  566. void ReadRow8BitCompressedWithoutColormap( CUtlBuffer& buf,
  567. TGAHeader_t const& header, unsigned char* pDst )
  568. {
  569. unsigned char rowI_8[TGA_MAX_ROW_LENGTH_IN_PIXELS];
  570. DecompressRow( buf, header, rowI_8 );
  571. CUtlBuffer uncompressedBuf( rowI_8, TGA_MAX_ROW_LENGTH_IN_PIXELS, CUtlBuffer::READ_ONLY );
  572. ReadRow8BitUncompressedWithoutColormap( uncompressedBuf, header, pDst );
  573. }
  574. //-----------------------------------------------------------------------------
  575. // Reads a compressed 24-bit TGA image
  576. //-----------------------------------------------------------------------------
  577. void ReadRow24BitCompressedWithoutColormap( CUtlBuffer& buf,
  578. TGAHeader_t const& header, unsigned char* pDst )
  579. {
  580. unsigned char rowBGR_888[TGA_MAX_ROW_LENGTH_IN_PIXELS * 3];
  581. DecompressRow( buf, header, rowBGR_888 );
  582. CUtlBuffer uncompressedBuf( rowBGR_888, TGA_MAX_ROW_LENGTH_IN_PIXELS * 3, CUtlBuffer::READ_ONLY );
  583. ReadRow24BitUncompressedWithoutColormap( uncompressedBuf, header, pDst );
  584. }
  585. //-----------------------------------------------------------------------------
  586. // Reads a compressed 32-bit TGA image
  587. //-----------------------------------------------------------------------------
  588. void ReadRow32BitCompressedWithoutColormap( CUtlBuffer& buf,
  589. TGAHeader_t const& header, unsigned char* pDst )
  590. {
  591. unsigned char rowBGRA_8888[TGA_MAX_ROW_LENGTH_IN_PIXELS << 2];
  592. DecompressRow( buf, header, rowBGRA_8888 );
  593. CUtlBuffer uncompressedBuf( rowBGRA_8888, TGA_MAX_ROW_LENGTH_IN_PIXELS << 2, CUtlBuffer::READ_ONLY );
  594. ReadRow32BitUncompressedWithoutColormap( uncompressedBuf, header, pDst );
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Method used to read the TGA
  598. //-----------------------------------------------------------------------------
  599. static ReadRowFunc_t GetReadRowFunc( TGAHeader_t const& header )
  600. {
  601. switch( header.image_type )
  602. {
  603. case 1: // 8 bit uncompressed TGA image
  604. case 3: // 8 bit monochrome uncompressed TGA image
  605. if( header.colormap_length )
  606. {
  607. return &ReadRow8BitUncompressedWithColormap;
  608. }
  609. else
  610. {
  611. return &ReadRow8BitUncompressedWithoutColormap;
  612. }
  613. case 9: // 8 bit compressed TGA image
  614. if( header.colormap_length )
  615. {
  616. return &ReadRow8BitCompressedWithColormap;
  617. }
  618. else
  619. {
  620. return &ReadRow8BitCompressedWithoutColormap;
  621. }
  622. case 2: // 24/32 bit uncompressed TGA image
  623. switch( header.pixel_size )
  624. {
  625. case 24:
  626. return &ReadRow24BitUncompressedWithoutColormap;
  627. break;
  628. case 32:
  629. return &ReadRow32BitUncompressedWithoutColormap;
  630. break;
  631. default:
  632. //Error( "unsupported tga colordepth: %d", TGAHeader_t.pixel_size" );
  633. return 0;
  634. break;
  635. }
  636. case 10: // 24/32 bit compressed TGA image
  637. if( header.colormap_length )
  638. {
  639. // Error( "colormaps not support with 24/32 bit TGAs." );
  640. return 0;
  641. }
  642. else
  643. {
  644. switch( header.pixel_size )
  645. {
  646. case 24:
  647. return &ReadRow24BitCompressedWithoutColormap;
  648. break;
  649. case 32:
  650. return &ReadRow32BitCompressedWithoutColormap;
  651. break;
  652. default:
  653. //Error( "unsupported tga colordepth: %d", TGAHeader_t.pixel_size" );
  654. return NULL;
  655. break;
  656. }
  657. }
  658. default:
  659. // Error( "unsupported tga pixel format" );
  660. return 0;
  661. break;
  662. }
  663. }
  664. //-----------------------------------------------------------------------------
  665. // Reads the color map
  666. //-----------------------------------------------------------------------------
  667. static bool ReadColormap( CUtlBuffer& buf, TGAHeader_t const& header )
  668. {
  669. int numColormapBytes = header.colormap_length * ( header.colormap_size >> 3 );
  670. if( numColormapBytes > TGA_MAX_COLORMAP_SIZE )
  671. {
  672. // Error( "colormap bigger than TGA_MAX_COLORMAP_SIZE" );
  673. return false;
  674. }
  675. // read colormap
  676. buf.Get( g_ColorMap, numColormapBytes );
  677. return true;
  678. }
  679. //-----------------------------------------------------------------------------
  680. // Reads the source image
  681. //-----------------------------------------------------------------------------
  682. static bool ReadSourceImage( CUtlBuffer& buf, TGAHeader_t& header, CTempImage& image )
  683. {
  684. // Figure out our reading and riting
  685. ReadRowFunc_t ReadRowFunc = GetReadRowFunc( header );
  686. if( !ReadRowFunc )
  687. return false;
  688. // HACK: Fixme: We really shouldn't be using globals here
  689. // Init RLE vars
  690. g_PixelsLeftInPacket = 0;
  691. // Only allocate the memory once
  692. int memRequired = ImageLoader::GetMemRequired( header.width, header.height, 1,
  693. IMAGE_FORMAT_RGBA8888, false );
  694. image.EnsureCapacity( memRequired );
  695. // read each row and process it. Note the image is upside-down from
  696. // the way we want it.
  697. unsigned char* pDstBits;
  698. // flip the image vertically if necessary.
  699. if (header.attributes & 0x20)
  700. {
  701. for( int row = 0; row < header.height; ++row )
  702. {
  703. pDstBits = image.Base() +
  704. row * header.width * ImageLoader::SizeInBytes(IMAGE_FORMAT_RGBA8888);
  705. ReadRowFunc( buf, header, pDstBits );
  706. }
  707. }
  708. else
  709. {
  710. for( int row = header.height; --row >= 0; )
  711. {
  712. pDstBits = image.Base() +
  713. row * header.width * ImageLoader::SizeInBytes(IMAGE_FORMAT_RGBA8888);
  714. ReadRowFunc( buf, header, pDstBits );
  715. }
  716. }
  717. return true;
  718. }
  719. #if 0
  720. //-----------------------------------------------------------------------------
  721. // Outputs the final image
  722. //-----------------------------------------------------------------------------
  723. static bool OutputImage( CTempImage& image, TGAHeader_t& header,
  724. ImageFormat imageFormat, unsigned char* pDst )
  725. {
  726. // How do we write?
  727. OutputRowFunc_t OutputRowFunc = GetOutputRowFunc( imageFormat );
  728. if( !OutputRowFunc )
  729. return false;
  730. CUtlBuffer buf( image.Base(), image.NumAllocated(), CUtlBuffer::READ_ONLY );
  731. unsigned char* pDstBits;
  732. for( int row = 0; row < header.height; ++row )
  733. {
  734. pDstBits = pDst +
  735. row * header.width * ImageLoader::SizeInBytes(imageFormat);
  736. OutputRowFunc( buf, header, pDstBits );
  737. }
  738. return true;
  739. }
  740. #endif
  741. //-----------------------------------------------------------------------------
  742. // Parses the lovely bits previously read from disk
  743. //-----------------------------------------------------------------------------
  744. bool Load( unsigned char *pOutputImage, CUtlBuffer& buf, int width,
  745. int height, ImageFormat imageFormat, float targetGamma, bool mipmap )
  746. {
  747. TGAHeader_t header;
  748. // Read the TGA header
  749. ReadHeader( buf, header );
  750. // skip TARGA image comment
  751. if( header.id_length != 0 )
  752. {
  753. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, header.id_length );
  754. }
  755. // Read the color map for palettized images
  756. if( header.colormap_length != 0 )
  757. {
  758. if (!ReadColormap( buf, header ))
  759. return false;
  760. }
  761. // Stores the RGBA8888 temp version of the image which we'll use to
  762. // to do mipmapping...
  763. CTempImage tmpImage;
  764. if (!ReadSourceImage( buf, header, tmpImage ))
  765. return false;
  766. // Erg... what if header.width * header.height > width * height?
  767. // Then don't do anything, this is an error condition...
  768. if ((width * height) < (header.width * header.height))
  769. return false;
  770. // Now that we've got the source image, generate the mip-map levels
  771. ImageLoader::GenerateMipmapLevels( tmpImage.Base(), pOutputImage,
  772. header.width, header.height, 1, imageFormat, ARTWORK_GAMMA, targetGamma,
  773. mipmap ? 0 : 1 );
  774. return true;
  775. }
  776. //-----------------------------------------------------------------------------
  777. // Reads a TGA image from a file
  778. //-----------------------------------------------------------------------------
  779. bool Load( unsigned char *pOutputImage, const char *pFileName, int width, int height,
  780. ImageFormat imageFormat, float targetGamma, bool mipmap )
  781. {
  782. Assert( pOutputImage && pFileName );
  783. // memory for the file
  784. CTempImage vec;
  785. // Read that puppy in!
  786. if (!ReadFile( pFileName, vec ))
  787. return false;
  788. // Make an unserialization buffer
  789. CUtlBuffer buf( vec.Base(), vec.NumAllocated(), CUtlBuffer::READ_ONLY );
  790. // Do the dirty deed
  791. return Load( pOutputImage, buf, width, height, imageFormat, targetGamma, mipmap );
  792. }
  793. //-----------------------------------------------------------------------------
  794. // Creates a map in linear space
  795. //-----------------------------------------------------------------------------
  796. bool LoadRGBA8888( CUtlBuffer& buf, CUtlMemory<unsigned char> &outputData, int &outWidth, int &outHeight )
  797. {
  798. TGAHeader_t header;
  799. // Read the TGA header
  800. ReadHeader( buf, header );
  801. // skip TARGA image comment
  802. if( header.id_length != 0 )
  803. {
  804. buf.SeekGet( CUtlBuffer::SEEK_CURRENT, header.id_length );
  805. }
  806. // Read the color map for palettized images
  807. if( header.colormap_length != 0 )
  808. {
  809. if (!ReadColormap( buf, header ))
  810. return false;
  811. }
  812. // Stores the RGBA8888 temp version of the image which we'll use to
  813. // to do mipmapping...
  814. int memSize = ImageLoader::GetMemRequired(
  815. header.width, header.height, 1, IMAGE_FORMAT_RGBA8888, false );
  816. outputData.EnsureCapacity( memSize );
  817. if (!ReadSourceImage( buf, header, outputData ))
  818. return false;
  819. outWidth = header.width;
  820. outHeight = header.height;
  821. return true;
  822. }
  823. //-----------------------------------------------------------------------------
  824. // Reads a TGA, keeps it in RGBA8888
  825. //-----------------------------------------------------------------------------
  826. bool LoadRGBA8888( const char *pFileName, CUtlMemory<unsigned char> &outputData, int &outWidth, int &outHeight )
  827. {
  828. Assert( pFileName );
  829. // memory for the file
  830. CTempImage vec;
  831. // Read that puppy in!
  832. if (!ReadFile( pFileName, vec ))
  833. return false;
  834. // Make an unserialization buffer
  835. CUtlBuffer buf( vec.Base(), vec.NumAllocated(), CUtlBuffer::READ_ONLY );
  836. // Do the dirty deed
  837. return LoadRGBA8888( buf, outputData, outWidth, outHeight );
  838. }
  839. } // end namespace TGALoader