Counter Strike : Global Offensive Source Code
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.

1023 lines
28 KiB

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