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.

496 lines
14 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include "tier0/dbg.h"
  9. #ifndef _PS3
  10. #include <malloc.h>
  11. #else
  12. #include <stdlib.h>
  13. #endif
  14. #include "filesystem.h"
  15. #include "bitmap/tgawriter.h"
  16. #include "tier1/utlbuffer.h"
  17. #include "bitmap/imageformat.h"
  18. #include "tier2/tier2.h"
  19. #include "tier2/fileutils.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. namespace TGAWriter
  23. {
  24. #pragma pack(1)
  25. struct TGAHeader_t
  26. {
  27. unsigned char id_length;
  28. unsigned char colormap_type;
  29. unsigned char image_type;
  30. unsigned short colormap_index;
  31. unsigned short colormap_length;
  32. unsigned char colormap_size;
  33. unsigned short x_origin;
  34. unsigned short y_origin;
  35. unsigned short width;
  36. unsigned short height;
  37. unsigned char pixel_size;
  38. unsigned char attributes;
  39. };
  40. #pragma pack()
  41. #define fputc myfputc
  42. #define fwrite myfwrite
  43. static void fputLittleShort( unsigned short s, CUtlBuffer &buffer )
  44. {
  45. buffer.PutChar( s & 0xff );
  46. buffer.PutChar( s >> 8 );
  47. }
  48. static inline void myfputc( unsigned char c, FileHandle_t fileHandle )
  49. {
  50. g_pFullFileSystem->Write( &c, 1, fileHandle );
  51. }
  52. static inline void myfwrite( void const *data, int size1, int size2, FileHandle_t fileHandle )
  53. {
  54. g_pFullFileSystem->Write( data, size1 * size2, fileHandle );
  55. }
  56. //-----------------------------------------------------------------------------
  57. // FIXME: assumes that we don't need to do gamma correction.
  58. //-----------------------------------------------------------------------------
  59. bool WriteToBuffer( unsigned char *pImageData, CUtlBuffer &buffer, int width, int height,
  60. ImageFormat srcFormat, ImageFormat dstFormat )
  61. {
  62. TGAHeader_t header;
  63. // Fix the dstFormat to match what actually is going to go into the file
  64. switch( dstFormat )
  65. {
  66. case IMAGE_FORMAT_RGB888:
  67. dstFormat = IMAGE_FORMAT_BGR888;
  68. break;
  69. #if defined( _X360 )
  70. case IMAGE_FORMAT_LINEAR_RGB888:
  71. dstFormat = IMAGE_FORMAT_LINEAR_BGR888;
  72. break;
  73. #endif
  74. case IMAGE_FORMAT_RGBA8888:
  75. dstFormat = IMAGE_FORMAT_BGRA8888;
  76. break;
  77. }
  78. header.id_length = 0; // comment length
  79. header.colormap_type = 0; // ???
  80. switch( dstFormat )
  81. {
  82. case IMAGE_FORMAT_BGR888:
  83. #if defined( _X360 )
  84. case IMAGE_FORMAT_LINEAR_BGR888:
  85. #endif
  86. header.image_type = 2; // 24/32 bit uncompressed TGA
  87. header.pixel_size = 24;
  88. break;
  89. case IMAGE_FORMAT_BGRA8888:
  90. header.image_type = 2; // 24/32 bit uncompressed TGA
  91. header.pixel_size = 32;
  92. break;
  93. case IMAGE_FORMAT_I8:
  94. header.image_type = 1; // 8 bit uncompressed TGA
  95. header.pixel_size = 8;
  96. break;
  97. default:
  98. return false;
  99. break;
  100. }
  101. header.colormap_index = 0;
  102. header.colormap_length = 0;
  103. header.colormap_size = 0;
  104. header.x_origin = 0;
  105. header.y_origin = 0;
  106. header.width = ( unsigned short )width;
  107. header.height = ( unsigned short )height;
  108. header.attributes = 0x20; // Makes it so we don't have to vertically flip the image
  109. buffer.PutChar( header.id_length );
  110. buffer.PutChar( header.colormap_type );
  111. buffer.PutChar( header.image_type );
  112. fputLittleShort( header.colormap_index, buffer );
  113. fputLittleShort( header.colormap_length, buffer );
  114. buffer.PutChar( header.colormap_size );
  115. fputLittleShort( header.x_origin, buffer );
  116. fputLittleShort( header.y_origin, buffer );
  117. fputLittleShort( header.width, buffer );
  118. fputLittleShort( header.height, buffer );
  119. buffer.PutChar( header.pixel_size );
  120. buffer.PutChar( header.attributes );
  121. int nSizeInBytes = width * height * ImageLoader::SizeInBytes( dstFormat );
  122. buffer.EnsureCapacity( buffer.TellPut() + nSizeInBytes );
  123. unsigned char *pDst = (unsigned char*)buffer.PeekPut();
  124. if ( !ImageLoader::ConvertImageFormat( pImageData, srcFormat, pDst, dstFormat, width, height ) )
  125. return false;
  126. buffer.SeekPut( CUtlBuffer::SEEK_CURRENT, nSizeInBytes );
  127. return true;
  128. }
  129. bool WriteDummyFileNoAlloc( const char *fileName, int width, int height, enum ImageFormat dstFormat )
  130. {
  131. TGAHeader_t tgaHeader;
  132. Assert( g_pFullFileSystem );
  133. if( !g_pFullFileSystem )
  134. {
  135. return false;
  136. }
  137. COutputFile fp( fileName );
  138. int nBytesPerPixel, nImageType, nPixelSize;
  139. switch( dstFormat )
  140. {
  141. case IMAGE_FORMAT_BGR888:
  142. #if defined( _X360 )
  143. case IMAGE_FORMAT_LINEAR_BGR888:
  144. #endif
  145. nBytesPerPixel = 3; // 24/32 bit uncompressed TGA
  146. nPixelSize = 24;
  147. nImageType = 2;
  148. break;
  149. case IMAGE_FORMAT_BGRA8888:
  150. nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
  151. nPixelSize = 32;
  152. nImageType = 2;
  153. break;
  154. case IMAGE_FORMAT_I8:
  155. nBytesPerPixel = 1; // 8 bit uncompressed TGA
  156. nPixelSize = 8;
  157. nImageType = 1;
  158. break;
  159. default:
  160. return false;
  161. break;
  162. }
  163. memset( &tgaHeader, 0, sizeof(tgaHeader) );
  164. tgaHeader.id_length = 0;
  165. tgaHeader.image_type = (unsigned char) nImageType;
  166. tgaHeader.width = (unsigned short) width;
  167. tgaHeader.height = (unsigned short) height;
  168. tgaHeader.pixel_size = (unsigned char) nPixelSize;
  169. tgaHeader.attributes = 0x20;
  170. // Write the Targa header
  171. fp.Write( &tgaHeader, sizeof(TGAHeader_t) );
  172. // Write out width * height black pixels
  173. unsigned char black[4] = { 0x00, 0x00, 0x00, 0x00 }; // Valve Orange would be: { 0x1E, 0x9A, 0xFF, 0x00 }
  174. for (int i = 0; i < width * height; i++)
  175. {
  176. fp.Write( black, nBytesPerPixel );
  177. }
  178. return true;
  179. }
  180. bool WriteTGAFile( const char *fileName, int width, int height, enum ImageFormat srcFormat, uint8 const *srcData, int nStride )
  181. {
  182. TGAHeader_t tgaHeader;
  183. COutputFile fp( fileName );
  184. int nBytesPerPixel, nImageType, nPixelSize;
  185. bool bMustConvert = false;
  186. ImageFormat dstFormat = srcFormat;
  187. switch( srcFormat )
  188. {
  189. case IMAGE_FORMAT_BGR888:
  190. #if defined( _X360 )
  191. case IMAGE_FORMAT_LINEAR_BGR888:
  192. #endif
  193. nBytesPerPixel = 3; // 24/32 bit uncompressed TGA
  194. nPixelSize = 24;
  195. nImageType = 2;
  196. break;
  197. case IMAGE_FORMAT_BGRA8888:
  198. nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
  199. nPixelSize = 32;
  200. nImageType = 2;
  201. break;
  202. case IMAGE_FORMAT_RGBA8888:
  203. bMustConvert = true;
  204. dstFormat = IMAGE_FORMAT_BGRA8888;
  205. nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
  206. nPixelSize = 32;
  207. nImageType = 2;
  208. break;
  209. case IMAGE_FORMAT_I8:
  210. nBytesPerPixel = 1; // 8 bit uncompressed TGA
  211. nPixelSize = 8;
  212. nImageType = 1;
  213. break;
  214. default:
  215. return false;
  216. break;
  217. }
  218. memset( &tgaHeader, 0, sizeof(tgaHeader) );
  219. tgaHeader.id_length = 0;
  220. tgaHeader.image_type = (unsigned char) nImageType;
  221. tgaHeader.width = (unsigned short) width;
  222. tgaHeader.height = (unsigned short) height;
  223. tgaHeader.pixel_size = (unsigned char) nPixelSize;
  224. tgaHeader.attributes = 0x20;
  225. // Write the Targa header
  226. fp.Write( &tgaHeader, sizeof(TGAHeader_t) );
  227. // Write out image data
  228. if ( bMustConvert )
  229. {
  230. uint8 *pLineBuf = new uint8[ nBytesPerPixel * width ];
  231. while( height-- )
  232. {
  233. ImageLoader::ConvertImageFormat( srcData, srcFormat, pLineBuf, dstFormat, width, 1 );
  234. fp.Write( pLineBuf, nBytesPerPixel * width );
  235. srcData += nStride;
  236. }
  237. delete[] pLineBuf;
  238. }
  239. else
  240. {
  241. while( height-- )
  242. {
  243. fp.Write( srcData, nBytesPerPixel * width );
  244. srcData += nStride;
  245. }
  246. }
  247. return true;
  248. }
  249. // This routine writes into a width x height subrect of an existing file at the offset ( nXOrigin, nYOrigin ) where the target image has a stride of nStride
  250. bool WriteRectNoAlloc( unsigned char *pImageData, const char *fileName, int nXOrigin, int nYOrigin, int width, int height, int nStride, enum ImageFormat srcFormat )
  251. {
  252. Assert( g_pFullFileSystem );
  253. if( !g_pFullFileSystem )
  254. {
  255. return false;
  256. }
  257. FileHandle_t fp;
  258. fp = g_pFullFileSystem->Open( fileName, "r+b" );
  259. // Read in the targa header
  260. TGAHeader_t tgaHeader;
  261. g_pFullFileSystem->Read( &tgaHeader, sizeof(tgaHeader), fp );
  262. int nBytesPerPixel, nImageType, nPixelSize;
  263. switch( srcFormat )
  264. {
  265. case IMAGE_FORMAT_BGR888:
  266. #if defined( _X360 )
  267. case IMAGE_FORMAT_LINEAR_BGR888:
  268. #endif
  269. nBytesPerPixel = 3; // 24/32 bit uncompressed TGA
  270. nPixelSize = 24;
  271. nImageType = 2;
  272. break;
  273. case IMAGE_FORMAT_BGRA8888:
  274. nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
  275. nPixelSize = 32;
  276. nImageType = 2;
  277. break;
  278. case IMAGE_FORMAT_I8:
  279. nBytesPerPixel = 1; // 8 bit uncompressed TGA
  280. nPixelSize = 8;
  281. nImageType = 1;
  282. break;
  283. default:
  284. return false;
  285. break;
  286. }
  287. // Verify src data matches the targa we're going to write into
  288. if ( nPixelSize != tgaHeader.pixel_size )
  289. {
  290. Warning( "TGA doesn't match source data.\n" );
  291. return false;
  292. }
  293. // Seek to the origin of the target subrect from the beginning of the file
  294. g_pFullFileSystem->Seek( fp, nBytesPerPixel * (tgaHeader.width * nYOrigin + nXOrigin), FILESYSTEM_SEEK_CURRENT );
  295. unsigned char *pSrc = pImageData;
  296. // Run through each scanline of the incoming rect
  297. for (int row=0; row < height; row++ )
  298. {
  299. g_pFullFileSystem->Write( pSrc, nBytesPerPixel * width, fp );
  300. // Advance src pointer to next scanline
  301. pSrc += nBytesPerPixel * nStride;
  302. // Seek ahead in the file
  303. g_pFullFileSystem->Seek( fp, nBytesPerPixel * ( tgaHeader.width - width ), FILESYSTEM_SEEK_CURRENT );
  304. }
  305. g_pFullFileSystem->Close( fp );
  306. return true;
  307. }
  308. // Returns weight for Source pixel based on its position in the guardbanded source tile
  309. static float GetSrcWeight( int nFileY, int nFileX, int nFileHeight, int nFileWidth,
  310. int nRow, int nCol, int nHeight, int nWidth, int nGuardBandHeight, int nGuardBandWidth )
  311. {
  312. float flXWeight = 1.0f;
  313. float flYWeight = 1.0f;
  314. if ( nFileX < nGuardBandWidth ) // Left edge of file doesn't feather in X
  315. {
  316. flXWeight = 1.0f;
  317. }
  318. else if ( nFileX > ( nFileWidth - nGuardBandWidth ) ) // Right edge of file doesn't feather in X
  319. {
  320. flXWeight = 1.0f;
  321. }
  322. else if ( nCol < 2*nGuardBandWidth ) // Left guardband
  323. {
  324. flXWeight = nCol / ( (float) nGuardBandWidth * 2.0f );
  325. }
  326. else if ( nCol > nWidth ) // Right guardband
  327. {
  328. flXWeight = 1.0f - ( ( nCol - nWidth ) / ( (float) nGuardBandWidth * 2.0f ) );
  329. }
  330. if ( nFileY < nGuardBandHeight ) // Top edge of file doesn't feather in Y
  331. {
  332. flYWeight = 1.0f;
  333. }
  334. else if ( nFileY > ( nFileHeight - nGuardBandHeight ) ) // Bottom edge of file doesn't feather in Y
  335. {
  336. flYWeight = 1.0f;
  337. }
  338. else if ( nRow < 2*nGuardBandHeight ) // Top guardband
  339. {
  340. flYWeight = nRow / ( (float) nGuardBandHeight * 2.0f );
  341. }
  342. else if ( nRow > nHeight ) // Bottom guardband
  343. {
  344. flYWeight = 1.0f - ( ( nRow - nHeight ) / ( (float) nGuardBandHeight * 2.0f ) );
  345. }
  346. float flWeight = flXWeight * flYWeight;
  347. Assert( ( flWeight >= 0 ) && ( flWeight <= 1.0f ) );
  348. return flWeight;
  349. }
  350. // This flavor of this routine also writes a subrect into an existing file, but it feathers in a ( nGuardBandWidth, nGuardBandHeight ) border,
  351. bool WriteRectNoAllocFeather( unsigned char *pImageData, const char *fileName, int nXOrigin, int nYOrigin, int width, int height,
  352. int nGuardBandWidth, int nGuardBandHeight, int nStride, enum ImageFormat srcFormat )
  353. {
  354. Assert( g_pFullFileSystem );
  355. if( !g_pFullFileSystem )
  356. return false;
  357. FileHandle_t fp;
  358. fp = g_pFullFileSystem->Open( fileName, "r+b" );
  359. // Read in the targa header
  360. TGAHeader_t tgaHeader;
  361. g_pFullFileSystem->Read( &tgaHeader, sizeof(tgaHeader), fp );
  362. int nBytesPerPixel, nImageType, nPixelSize;
  363. switch( srcFormat )
  364. {
  365. case IMAGE_FORMAT_BGR888:
  366. #if defined( _X360 )
  367. case IMAGE_FORMAT_LINEAR_BGR888:
  368. #endif
  369. nBytesPerPixel = 3; // 24/32 bit uncompressed TGA
  370. nPixelSize = 24;
  371. nImageType = 2;
  372. break;
  373. case IMAGE_FORMAT_BGRA8888:
  374. nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
  375. nPixelSize = 32;
  376. nImageType = 2;
  377. break;
  378. case IMAGE_FORMAT_I8:
  379. nBytesPerPixel = 1; // 8 bit uncompressed TGA
  380. nPixelSize = 8;
  381. nImageType = 1;
  382. break;
  383. default:
  384. return false;
  385. break;
  386. }
  387. // Verify src data matches the targa we're going to write into
  388. if ( nPixelSize != tgaHeader.pixel_size )
  389. {
  390. Warning( "TGA doesn't match source data.\n" );
  391. return false;
  392. }
  393. // Run through each scanline of the incoming tile, including guardbands
  394. for ( int row=0; row < ( height + 2*nGuardBandHeight ) ; row++ )
  395. {
  396. // Point to start of row
  397. unsigned char *pSrc = pImageData + ( row * nBytesPerPixel * nStride );
  398. unsigned char filePixel[4] = { 0, 0, 0, 0 };
  399. // Run through each column of the incoming tile, including guardbands
  400. for ( int col=0; col < ( width + 2*nGuardBandWidth ) ; col++ )
  401. {
  402. // Pixel location in the file
  403. int fileX = nXOrigin - nGuardBandWidth + col;
  404. int fileY = nYOrigin - nGuardBandHeight + row;
  405. // If we're within the limits of the file's image
  406. if ( ( fileX >= 0 ) && ( fileY >= 0 ) && ( fileX < tgaHeader.width ) && ( fileY < tgaHeader.height ) )
  407. {
  408. // Always just seek from the head of the file to the pixel in question and read it in
  409. g_pFullFileSystem->Seek( fp, sizeof(tgaHeader) + nBytesPerPixel * ( tgaHeader.width * fileY + fileX ), FILESYSTEM_SEEK_HEAD );
  410. g_pFullFileSystem->Read( filePixel, 3, fp ); // Just read B, G, R bytes
  411. // Add weighted src pixel to the data from the file (which should be initialized to be black at start of day)
  412. float flWeight = GetSrcWeight( fileY, fileX, tgaHeader.height, tgaHeader.width, row, col, height, width, nGuardBandHeight, nGuardBandWidth );
  413. filePixel[0] = (int) ( flWeight * (float)pSrc[0] + (float)filePixel[0] );
  414. filePixel[1] = (int) ( flWeight * (float)pSrc[1] + (float)filePixel[1] );
  415. filePixel[2] = (int) ( flWeight * (float)pSrc[2] + (float)filePixel[2] );
  416. // Jump back to start of current pixel and write over it
  417. g_pFullFileSystem->Seek( fp, -3, FILESYSTEM_SEEK_CURRENT );
  418. g_pFullFileSystem->Write( filePixel, nBytesPerPixel, fp );
  419. }
  420. // Advance src pointer to next column
  421. pSrc += nBytesPerPixel;
  422. }
  423. }
  424. g_pFullFileSystem->Close( fp );
  425. return true;
  426. }
  427. } // end namespace TGAWriter