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.

353 lines
8.7 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include "tier0/dbg.h"
  9. #include <malloc.h>
  10. #include "filesystem.h"
  11. #include "bitmap/tgawriter.h"
  12. #include "tier1/utlbuffer.h"
  13. #include "bitmap/imageformat.h"
  14. #include "tier2/tier2.h"
  15. #include "tier2/fileutils.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. namespace TGAWriter
  19. {
  20. #pragma pack(1)
  21. struct TGAHeader_t
  22. {
  23. unsigned char id_length;
  24. unsigned char colormap_type;
  25. unsigned char image_type;
  26. unsigned short colormap_index;
  27. unsigned short colormap_length;
  28. unsigned char colormap_size;
  29. unsigned short x_origin;
  30. unsigned short y_origin;
  31. unsigned short width;
  32. unsigned short height;
  33. unsigned char pixel_size;
  34. unsigned char attributes;
  35. };
  36. #pragma pack()
  37. #define fputc myfputc
  38. #define fwrite myfwrite
  39. static void fputLittleShort( unsigned short s, CUtlBuffer &buffer )
  40. {
  41. buffer.PutChar( s & 0xff );
  42. buffer.PutChar( s >> 8 );
  43. }
  44. static inline void myfputc( unsigned char c, FileHandle_t fileHandle )
  45. {
  46. g_pFullFileSystem->Write( &c, 1, fileHandle );
  47. }
  48. static inline void myfwrite( void const *data, int size1, int size2, FileHandle_t fileHandle )
  49. {
  50. g_pFullFileSystem->Write( data, size1 * size2, fileHandle );
  51. }
  52. //-----------------------------------------------------------------------------
  53. // FIXME: assumes that we don't need to do gamma correction.
  54. //-----------------------------------------------------------------------------
  55. bool WriteToBuffer( unsigned char *pImageData, CUtlBuffer &buffer, int width, int height,
  56. ImageFormat srcFormat, ImageFormat dstFormat )
  57. {
  58. TGAHeader_t header;
  59. // Fix the dstFormat to match what actually is going to go into the file
  60. switch( dstFormat )
  61. {
  62. case IMAGE_FORMAT_RGB888:
  63. dstFormat = IMAGE_FORMAT_BGR888;
  64. break;
  65. #if defined( _X360 )
  66. case IMAGE_FORMAT_LINEAR_RGB888:
  67. dstFormat = IMAGE_FORMAT_LINEAR_BGR888;
  68. break;
  69. #endif
  70. case IMAGE_FORMAT_RGBA8888:
  71. dstFormat = IMAGE_FORMAT_BGRA8888;
  72. break;
  73. }
  74. header.id_length = 0; // comment length
  75. header.colormap_type = 0; // ???
  76. switch( dstFormat )
  77. {
  78. case IMAGE_FORMAT_BGR888:
  79. #if defined( _X360 )
  80. case IMAGE_FORMAT_LINEAR_BGR888:
  81. #endif
  82. header.image_type = 2; // 24/32 bit uncompressed TGA
  83. header.pixel_size = 24;
  84. break;
  85. case IMAGE_FORMAT_BGRA8888:
  86. header.image_type = 2; // 24/32 bit uncompressed TGA
  87. header.pixel_size = 32;
  88. break;
  89. case IMAGE_FORMAT_I8:
  90. header.image_type = 1; // 8 bit uncompressed TGA
  91. header.pixel_size = 8;
  92. break;
  93. default:
  94. return false;
  95. break;
  96. }
  97. header.colormap_index = 0;
  98. header.colormap_length = 0;
  99. header.colormap_size = 0;
  100. header.x_origin = 0;
  101. header.y_origin = 0;
  102. header.width = ( unsigned short )width;
  103. header.height = ( unsigned short )height;
  104. header.attributes = 0x20; // Makes it so we don't have to vertically flip the image
  105. buffer.PutChar( header.id_length );
  106. buffer.PutChar( header.colormap_type );
  107. buffer.PutChar( header.image_type );
  108. fputLittleShort( header.colormap_index, buffer );
  109. fputLittleShort( header.colormap_length, buffer );
  110. buffer.PutChar( header.colormap_size );
  111. fputLittleShort( header.x_origin, buffer );
  112. fputLittleShort( header.y_origin, buffer );
  113. fputLittleShort( header.width, buffer );
  114. fputLittleShort( header.height, buffer );
  115. buffer.PutChar( header.pixel_size );
  116. buffer.PutChar( header.attributes );
  117. int nSizeInBytes = width * height * ImageLoader::SizeInBytes( dstFormat );
  118. buffer.EnsureCapacity( buffer.TellPut() + nSizeInBytes );
  119. unsigned char *pDst = (unsigned char*)buffer.PeekPut();
  120. if ( !ImageLoader::ConvertImageFormat( pImageData, srcFormat, pDst, dstFormat, width, height ) )
  121. return false;
  122. buffer.SeekPut( CUtlBuffer::SEEK_CURRENT, nSizeInBytes );
  123. return true;
  124. }
  125. bool WriteDummyFileNoAlloc( const char *fileName, int width, int height, enum ImageFormat dstFormat )
  126. {
  127. TGAHeader_t tgaHeader;
  128. Assert( g_pFullFileSystem );
  129. if( !g_pFullFileSystem )
  130. {
  131. return false;
  132. }
  133. COutputFile fp( fileName );
  134. int nBytesPerPixel, nImageType, nPixelSize;
  135. switch( dstFormat )
  136. {
  137. case IMAGE_FORMAT_BGR888:
  138. #if defined( _X360 )
  139. case IMAGE_FORMAT_LINEAR_BGR888:
  140. #endif
  141. nBytesPerPixel = 3; // 24/32 bit uncompressed TGA
  142. nPixelSize = 24;
  143. nImageType = 2;
  144. break;
  145. case IMAGE_FORMAT_BGRA8888:
  146. nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
  147. nPixelSize = 32;
  148. nImageType = 2;
  149. break;
  150. case IMAGE_FORMAT_I8:
  151. nBytesPerPixel = 1; // 8 bit uncompressed TGA
  152. nPixelSize = 8;
  153. nImageType = 1;
  154. break;
  155. default:
  156. return false;
  157. break;
  158. }
  159. memset( &tgaHeader, 0, sizeof(tgaHeader) );
  160. tgaHeader.id_length = 0;
  161. tgaHeader.image_type = (unsigned char) nImageType;
  162. tgaHeader.width = (unsigned short) width;
  163. tgaHeader.height = (unsigned short) height;
  164. tgaHeader.pixel_size = (unsigned char) nPixelSize;
  165. tgaHeader.attributes = 0x20;
  166. // Write the Targa header
  167. fp.Write( &tgaHeader, sizeof(TGAHeader_t) );
  168. // Write out width * height black pixels
  169. unsigned char black[4] = { 0x1E, 0x9A, 0xFF, 0x00 };
  170. for (int i = 0; i < width * height; i++)
  171. {
  172. fp.Write( black, nBytesPerPixel );
  173. }
  174. return true;
  175. }
  176. bool WriteTGAFile( const char *fileName, int width, int height, enum ImageFormat srcFormat, uint8 const *srcData, int nStride )
  177. {
  178. TGAHeader_t tgaHeader;
  179. COutputFile fp( fileName );
  180. int nBytesPerPixel, nImageType, nPixelSize;
  181. bool bMustConvert = false;
  182. ImageFormat dstFormat = srcFormat;
  183. switch( srcFormat )
  184. {
  185. case IMAGE_FORMAT_BGR888:
  186. #if defined( _X360 )
  187. case IMAGE_FORMAT_LINEAR_BGR888:
  188. #endif
  189. nBytesPerPixel = 3; // 24/32 bit uncompressed TGA
  190. nPixelSize = 24;
  191. nImageType = 2;
  192. break;
  193. case IMAGE_FORMAT_BGRA8888:
  194. nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
  195. nPixelSize = 32;
  196. nImageType = 2;
  197. break;
  198. case IMAGE_FORMAT_RGBA8888:
  199. bMustConvert = true;
  200. dstFormat = IMAGE_FORMAT_BGRA8888;
  201. nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
  202. nPixelSize = 32;
  203. nImageType = 2;
  204. break;
  205. case IMAGE_FORMAT_I8:
  206. nBytesPerPixel = 1; // 8 bit uncompressed TGA
  207. nPixelSize = 8;
  208. nImageType = 1;
  209. break;
  210. default:
  211. return false;
  212. break;
  213. }
  214. memset( &tgaHeader, 0, sizeof(tgaHeader) );
  215. tgaHeader.id_length = 0;
  216. tgaHeader.image_type = (unsigned char) nImageType;
  217. tgaHeader.width = (unsigned short) width;
  218. tgaHeader.height = (unsigned short) height;
  219. tgaHeader.pixel_size = (unsigned char) nPixelSize;
  220. tgaHeader.attributes = 0x20;
  221. // Write the Targa header
  222. fp.Write( &tgaHeader, sizeof(TGAHeader_t) );
  223. // Write out image data
  224. if ( bMustConvert )
  225. {
  226. uint8 *pLineBuf = new uint8[ nBytesPerPixel * width ];
  227. while( height-- )
  228. {
  229. ImageLoader::ConvertImageFormat( srcData, srcFormat, pLineBuf, dstFormat, width, 1 );
  230. fp.Write( pLineBuf, nBytesPerPixel * width );
  231. srcData += nStride;
  232. }
  233. delete[] pLineBuf;
  234. }
  235. else
  236. {
  237. while( height-- )
  238. {
  239. fp.Write( srcData, nBytesPerPixel * width );
  240. srcData += nStride;
  241. }
  242. }
  243. return true;
  244. }
  245. bool WriteRectNoAlloc( unsigned char *pImageData, const char *fileName, int nXOrigin, int nYOrigin, int width, int height, int nStride, enum ImageFormat srcFormat )
  246. {
  247. Assert( g_pFullFileSystem );
  248. if( !g_pFullFileSystem )
  249. {
  250. return false;
  251. }
  252. FileHandle_t fp;
  253. fp = g_pFullFileSystem->Open( fileName, "r+b" );
  254. //
  255. // Read in the targa header
  256. //
  257. TGAHeader_t tgaHeader;
  258. g_pFullFileSystem->Read( &tgaHeader, sizeof(tgaHeader), fp );
  259. int nBytesPerPixel, nPixelSize;
  260. switch( srcFormat )
  261. {
  262. case IMAGE_FORMAT_BGR888:
  263. #if defined( _X360 )
  264. case IMAGE_FORMAT_LINEAR_BGR888:
  265. #endif
  266. nBytesPerPixel = 3; // 24/32 bit uncompressed TGA
  267. nPixelSize = 24;
  268. break;
  269. case IMAGE_FORMAT_BGRA8888:
  270. nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
  271. nPixelSize = 32;
  272. break;
  273. case IMAGE_FORMAT_I8:
  274. nBytesPerPixel = 1; // 8 bit uncompressed TGA
  275. nPixelSize = 8;
  276. break;
  277. default:
  278. return false;
  279. break;
  280. }
  281. // Verify src data matches the targa we're going to write into
  282. if ( nPixelSize != tgaHeader.pixel_size )
  283. {
  284. Warning( "TGA doesn't match source data.\n" );
  285. return false;
  286. }
  287. // Seek to the origin of the target subrect from the beginning of the file
  288. g_pFullFileSystem->Seek( fp, nBytesPerPixel * (tgaHeader.width * nYOrigin + nXOrigin), FILESYSTEM_SEEK_CURRENT );
  289. unsigned char *pSrc = pImageData;
  290. // Run through each scanline of the incoming rect
  291. for (int row=0; row < height; row++ )
  292. {
  293. g_pFullFileSystem->Write( pSrc, nBytesPerPixel * width, fp );
  294. // Advance src pointer to next scanline
  295. pSrc += nBytesPerPixel * nStride;
  296. // Seek ahead in the file
  297. g_pFullFileSystem->Seek( fp, nBytesPerPixel * ( tgaHeader.width - width ), FILESYSTEM_SEEK_CURRENT );
  298. }
  299. g_pFullFileSystem->Close( fp );
  300. return true;
  301. }
  302. } // end namespace TGAWriter