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.

320 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifdef _WIN32
  8. #include <direct.h>
  9. #endif
  10. #include "mathlib/mathlib.h"
  11. #include "bitmap/tgawriter.h"
  12. #include "tier1/strtools.h"
  13. #include "vtf/vtf.h"
  14. #include "tier1/utlbuffer.h"
  15. #include "tier0/dbg.h"
  16. #include "tier0/icommandline.h"
  17. #include "tier1/utlbuffer.h"
  18. #include "tier2/tier2.h"
  19. #include "filesystem.h"
  20. //-----------------------------------------------------------------------------
  21. // HDRFIXME: move this somewhere else.
  22. //-----------------------------------------------------------------------------
  23. static void PFMWrite( float *pFloatImage, const char *pFilename, int width, int height )
  24. {
  25. FILE *fp;
  26. fp = fopen( pFilename, "wb" );
  27. fprintf( fp, "PF\n%d %d\n-1.000000\n", width, height );
  28. int i;
  29. for( i = height-1; i >= 0; i-- )
  30. {
  31. float *pRow = &pFloatImage[3 * width * i];
  32. fwrite( pRow, width * sizeof( float ) * 3, 1, fp );
  33. }
  34. fclose( fp );
  35. }
  36. SpewRetval_t VTF2TGAOutputFunc( SpewType_t spewType, char const *pMsg )
  37. {
  38. printf( "%s", pMsg );
  39. fflush( stdout );
  40. if (spewType == SPEW_ERROR)
  41. return SPEW_ABORT;
  42. return (spewType == SPEW_ASSERT) ? SPEW_DEBUGGER : SPEW_CONTINUE;
  43. }
  44. static void Usage( void )
  45. {
  46. Error( "Usage: vtf2tga -i <input vtf> [-o <output tga>] [-mip]\n" );
  47. exit( -1 );
  48. }
  49. int main( int argc, char **argv )
  50. {
  51. SpewOutputFunc( VTF2TGAOutputFunc );
  52. CommandLine()->CreateCmdLine( argc, argv );
  53. MathLib_Init( 2.2f, 2.2f, 0.0f, 1.0f, false, false, false, false );
  54. InitDefaultFileSystem();
  55. const char *pVTFFileName = CommandLine()->ParmValue( "-i" );
  56. const char *pTGAFileName = CommandLine()->ParmValue( "-o" );
  57. bool bGenerateMipLevels = CommandLine()->CheckParm( "-mip" ) != NULL;
  58. if ( !pVTFFileName )
  59. {
  60. Usage();
  61. }
  62. if ( !pTGAFileName )
  63. {
  64. pTGAFileName = pVTFFileName;
  65. }
  66. char pCurrentDirectory[MAX_PATH];
  67. if ( _getcwd( pCurrentDirectory, sizeof(pCurrentDirectory) ) == NULL )
  68. {
  69. fprintf( stderr, "Unable to get the current directory\n" );
  70. return -1;
  71. }
  72. Q_StripTrailingSlash( pCurrentDirectory );
  73. char pBuf[MAX_PATH];
  74. if ( !Q_IsAbsolutePath( pTGAFileName ) )
  75. {
  76. Q_snprintf( pBuf, sizeof(pBuf), "%s\\%s", pCurrentDirectory, pTGAFileName );
  77. }
  78. else
  79. {
  80. Q_strncpy( pBuf, pTGAFileName, sizeof(pBuf) );
  81. }
  82. Q_FixSlashes( pBuf );
  83. char pOutFileNameBase[MAX_PATH];
  84. Q_StripExtension( pBuf, pOutFileNameBase, MAX_PATH );
  85. char pActualVTFFileName[MAX_PATH];
  86. Q_strncpy( pActualVTFFileName, pVTFFileName, MAX_PATH );
  87. if ( !Q_strstr( pActualVTFFileName, ".vtf" ) )
  88. {
  89. Q_strcat( pActualVTFFileName, ".vtf", MAX_PATH );
  90. }
  91. FILE *vtfFp = fopen( pActualVTFFileName, "rb" );
  92. if( !vtfFp )
  93. {
  94. Error( "Can't open %s\n", pActualVTFFileName );
  95. exit( -1 );
  96. }
  97. fseek( vtfFp, 0, SEEK_END );
  98. int srcVTFLength = ftell( vtfFp );
  99. fseek( vtfFp, 0, SEEK_SET );
  100. CUtlBuffer buf;
  101. buf.EnsureCapacity( srcVTFLength );
  102. int nBytesRead = fread( buf.Base(), 1, srcVTFLength, vtfFp );
  103. fclose( vtfFp );
  104. buf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead );
  105. IVTFTexture *pTex = CreateVTFTexture();
  106. if (!pTex->Unserialize( buf ))
  107. {
  108. Error( "*** Error reading in .VTF file %s\n", pActualVTFFileName );
  109. exit(-1);
  110. }
  111. Msg( "vtf width: %d\n", pTex->Width() );
  112. Msg( "vtf height: %d\n", pTex->Height() );
  113. Msg( "vtf numFrames: %d\n", pTex->FrameCount() );
  114. Msg( "TEXTUREFLAGS_POINTSAMPLE=%s\n", ( pTex->Flags() & TEXTUREFLAGS_POINTSAMPLE ) ? "true" : "false" );
  115. Msg( "TEXTUREFLAGS_TRILINEAR=%s\n", ( pTex->Flags() & TEXTUREFLAGS_TRILINEAR ) ? "true" : "false" );
  116. Msg( "TEXTUREFLAGS_CLAMPS=%s\n", ( pTex->Flags() & TEXTUREFLAGS_CLAMPS ) ? "true" : "false" );
  117. Msg( "TEXTUREFLAGS_CLAMPT=%s\n", ( pTex->Flags() & TEXTUREFLAGS_CLAMPT ) ? "true" : "false" );
  118. Msg( "TEXTUREFLAGS_CLAMPU=%s\n", ( pTex->Flags() & TEXTUREFLAGS_CLAMPU ) ? "true" : "false" );
  119. Msg( "TEXTUREFLAGS_BORDER=%s\n", ( pTex->Flags() & TEXTUREFLAGS_BORDER ) ? "true" : "false" );
  120. Msg( "TEXTUREFLAGS_ANISOTROPIC=%s\n", ( pTex->Flags() & TEXTUREFLAGS_ANISOTROPIC ) ? "true" : "false" );
  121. Msg( "TEXTUREFLAGS_HINT_DXT5=%s\n", ( pTex->Flags() & TEXTUREFLAGS_HINT_DXT5 ) ? "true" : "false" );
  122. Msg( "TEXTUREFLAGS_SRGB=%s\n", ( pTex->Flags() & TEXTUREFLAGS_SRGB ) ? "true" : "false" );
  123. Msg( "TEXTUREFLAGS_NORMAL=%s\n", ( pTex->Flags() & TEXTUREFLAGS_NORMAL ) ? "true" : "false" );
  124. Msg( "TEXTUREFLAGS_NOMIP=%s\n", ( pTex->Flags() & TEXTUREFLAGS_NOMIP ) ? "true" : "false" );
  125. Msg( "TEXTUREFLAGS_NOLOD=%s\n", ( pTex->Flags() & TEXTUREFLAGS_NOLOD ) ? "true" : "false" );
  126. Msg( "TEXTUREFLAGS_ALL_MIPS=%s\n", ( pTex->Flags() & TEXTUREFLAGS_ALL_MIPS ) ? "true" : "false" );
  127. Msg( "TEXTUREFLAGS_PROCEDURAL=%s\n", ( pTex->Flags() & TEXTUREFLAGS_PROCEDURAL ) ? "true" : "false" );
  128. Msg( "TEXTUREFLAGS_ONEBITALPHA=%s\n", ( pTex->Flags() & TEXTUREFLAGS_ONEBITALPHA ) ? "true" : "false" );
  129. Msg( "TEXTUREFLAGS_EIGHTBITALPHA=%s\n", ( pTex->Flags() & TEXTUREFLAGS_EIGHTBITALPHA ) ? "true" : "false" );
  130. Msg( "TEXTUREFLAGS_ENVMAP=%s\n", ( pTex->Flags() & TEXTUREFLAGS_ENVMAP ) ? "true" : "false" );
  131. Msg( "TEXTUREFLAGS_RENDERTARGET=%s\n", ( pTex->Flags() & TEXTUREFLAGS_RENDERTARGET ) ? "true" : "false" );
  132. Msg( "TEXTUREFLAGS_DEPTHRENDERTARGET=%s\n", ( pTex->Flags() & TEXTUREFLAGS_DEPTHRENDERTARGET ) ? "true" : "false" );
  133. Msg( "TEXTUREFLAGS_NODEBUGOVERRIDE=%s\n", ( pTex->Flags() & TEXTUREFLAGS_NODEBUGOVERRIDE ) ? "true" : "false" );
  134. Msg( "TEXTUREFLAGS_SINGLECOPY=%s\n", ( pTex->Flags() & TEXTUREFLAGS_SINGLECOPY ) ? "true" : "false" );
  135. Vector vecReflectivity = pTex->Reflectivity();
  136. Msg( "vtf reflectivity: %f %f %f\n", vecReflectivity[0], vecReflectivity[1], vecReflectivity[2] );
  137. Msg( "transparency: " );
  138. if( pTex->Flags() & TEXTUREFLAGS_EIGHTBITALPHA )
  139. {
  140. Msg( "eightbitalpha\n" );
  141. }
  142. else if( pTex->Flags() & TEXTUREFLAGS_ONEBITALPHA )
  143. {
  144. Msg( "onebitalpha\n" );
  145. }
  146. else
  147. {
  148. Msg( "noalpha\n" );
  149. }
  150. ImageFormat srcFormat = pTex->Format();
  151. Msg( "vtf format: %s\n", ImageLoader::GetName( srcFormat ) );
  152. int iTGANameLen = Q_strlen( pOutFileNameBase );
  153. int iFaceCount = pTex->FaceCount();
  154. int nFrameCount = pTex->FrameCount();
  155. bool bIsCubeMap = pTex->IsCubeMap();
  156. int iLastMipLevel = bGenerateMipLevels ? pTex->MipCount() - 1 : 0;
  157. for( int iFrame = 0; iFrame < nFrameCount; ++iFrame )
  158. {
  159. for ( int iMipLevel = 0; iMipLevel <= iLastMipLevel; ++iMipLevel )
  160. {
  161. int iWidth, iHeight, iDepth;
  162. pTex->ComputeMipLevelDimensions( iMipLevel, &iWidth, &iHeight, &iDepth );
  163. for (int iCubeFace = 0; iCubeFace < iFaceCount; ++iCubeFace)
  164. {
  165. for ( int z = 0; z < iDepth; ++z )
  166. {
  167. // Construct output filename
  168. char *pTempNameBuf = new char[iTGANameLen + 13];//(char *)stackalloc( iTGANameLen + 13 );
  169. Q_strncpy( pTempNameBuf, pOutFileNameBase, iTGANameLen + 1 );
  170. char *pExt = Q_strrchr( pTempNameBuf, '.' );
  171. if ( pExt )
  172. {
  173. pExt = 0;
  174. }
  175. if ( bIsCubeMap )
  176. {
  177. Assert( pTex->Depth() == 1 ); // shouldn't this be 1 instead of 0?
  178. static const char *pCubeFaceName[7] = { "rt", "lf", "bk", "ft", "up", "dn", "sph" };
  179. Q_strcat( pTempNameBuf, pCubeFaceName[iCubeFace], iTGANameLen + 13 );
  180. }
  181. if ( nFrameCount > 1 )
  182. {
  183. char pTemp[4];
  184. Q_snprintf( pTemp, 4, "%03d", iFrame );
  185. Q_strcat( pTempNameBuf, pTemp, iTGANameLen + 13 );
  186. }
  187. if ( iLastMipLevel != 0 )
  188. {
  189. char pTemp[8];
  190. Q_snprintf( pTemp, 8, "_mip%d", iMipLevel );
  191. Q_strcat( pTempNameBuf, pTemp, iTGANameLen + 13 );
  192. }
  193. if ( pTex->Depth() > 1 )
  194. {
  195. char pTemp[6];
  196. Q_snprintf( pTemp, 6, "_z%03d", z );
  197. Q_strcat( pTempNameBuf, pTemp, iTGANameLen + 13 );
  198. }
  199. if( srcFormat == IMAGE_FORMAT_RGBA16161616F )
  200. {
  201. Q_strcat( pTempNameBuf, ".pfm", iTGANameLen + 13 );
  202. }
  203. else
  204. {
  205. Q_strcat( pTempNameBuf, ".tga", iTGANameLen + 13 );
  206. }
  207. unsigned char *pSrcImage = pTex->ImageData( iFrame, iCubeFace, iMipLevel, 0, 0, z );
  208. ImageFormat dstFormat;
  209. if( srcFormat == IMAGE_FORMAT_RGBA16161616F )
  210. {
  211. dstFormat = IMAGE_FORMAT_RGB323232F;
  212. }
  213. else
  214. {
  215. if( ImageLoader::IsTransparent( srcFormat ) || (srcFormat == IMAGE_FORMAT_ATI1N ) || (srcFormat == IMAGE_FORMAT_ATI2N ))
  216. {
  217. dstFormat = IMAGE_FORMAT_BGRA8888;
  218. }
  219. else
  220. {
  221. dstFormat = IMAGE_FORMAT_BGR888;
  222. }
  223. }
  224. // dstFormat = IMAGE_FORMAT_RGBA8888;
  225. // dstFormat = IMAGE_FORMAT_RGB888;
  226. // dstFormat = IMAGE_FORMAT_BGRA8888;
  227. // dstFormat = IMAGE_FORMAT_BGR888;
  228. // dstFormat = IMAGE_FORMAT_BGRA5551;
  229. // dstFormat = IMAGE_FORMAT_BGR565;
  230. // dstFormat = IMAGE_FORMAT_BGRA4444;
  231. // printf( "dstFormat: %s\n", ImageLoader::GetName( dstFormat ) );
  232. unsigned char *pDstImage = new unsigned char[ImageLoader::GetMemRequired( iWidth, iHeight, 1, dstFormat, false )];
  233. if( !ImageLoader::ConvertImageFormat( pSrcImage, srcFormat,
  234. pDstImage, dstFormat, iWidth, iHeight, 0, 0 ) )
  235. {
  236. Error( "Error converting from %s to %s\n",
  237. ImageLoader::GetName( srcFormat ), ImageLoader::GetName( dstFormat ) );
  238. exit( -1 );
  239. }
  240. if( dstFormat != IMAGE_FORMAT_RGB323232F )
  241. {
  242. if( ImageLoader::IsTransparent( dstFormat ) && ( dstFormat != IMAGE_FORMAT_RGBA8888 ) )
  243. {
  244. unsigned char *tmpImage = pDstImage;
  245. pDstImage = new unsigned char[ImageLoader::GetMemRequired( iWidth, iHeight, 1, IMAGE_FORMAT_RGBA8888, false )];
  246. if( !ImageLoader::ConvertImageFormat( tmpImage, dstFormat, pDstImage, IMAGE_FORMAT_RGBA8888,
  247. iWidth, iHeight, 0, 0 ) )
  248. {
  249. Error( "Error converting from %s to %s\n",
  250. ImageLoader::GetName( dstFormat ), ImageLoader::GetName( IMAGE_FORMAT_RGBA8888 ) );
  251. }
  252. dstFormat = IMAGE_FORMAT_RGBA8888;
  253. }
  254. else if( !ImageLoader::IsTransparent( dstFormat ) && ( dstFormat != IMAGE_FORMAT_RGB888 ) )
  255. {
  256. unsigned char *tmpImage = pDstImage;
  257. pDstImage = new unsigned char[ImageLoader::GetMemRequired( iWidth, iHeight, 1, IMAGE_FORMAT_RGB888, false )];
  258. if( !ImageLoader::ConvertImageFormat( tmpImage, dstFormat, pDstImage, IMAGE_FORMAT_RGB888,
  259. iWidth, iHeight, 0, 0 ) )
  260. {
  261. Error( "Error converting from %s to %s\n",
  262. ImageLoader::GetName( dstFormat ), ImageLoader::GetName( IMAGE_FORMAT_RGB888 ) );
  263. }
  264. dstFormat = IMAGE_FORMAT_RGB888;
  265. }
  266. CUtlBuffer outBuffer;
  267. TGAWriter::WriteToBuffer( pDstImage, outBuffer, iWidth, iHeight,
  268. dstFormat, dstFormat );
  269. if ( !g_pFullFileSystem->WriteFile( pTempNameBuf, NULL, outBuffer ) )
  270. {
  271. fprintf( stderr, "unable to write %s\n", pTempNameBuf );
  272. }
  273. }
  274. else
  275. {
  276. PFMWrite( ( float * )pDstImage, pTempNameBuf, iWidth, iHeight );
  277. }
  278. delete[] pTempNameBuf;
  279. }
  280. }
  281. }
  282. }
  283. // leak leak leak leak leak, leak leak, leak leak (Blue Danube)
  284. return 0;
  285. }