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.

664 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "pch_materialsystem.h"
  7. // NOTE: currently this file is marked as "exclude from build"
  8. //#define _CHECK_MATERIALS_FOR_PROBLEMS 1
  9. #ifdef _CHECK_MATERIALS_FOR_PROBLEMS
  10. #include "vtf/vtf.h"
  11. #include "tier1/utlbuffer.h"
  12. #include "tier1/utlstring.h"
  13. void CheckMateralsInDirectoryRecursive( const char *pRoot, const char *pDirectory );
  14. #endif
  15. #ifdef _CHECK_MATERIALS_FOR_PROBLEMS
  16. //-----------------------------------------------------------------------------
  17. // Does a texture have alpha?
  18. //-----------------------------------------------------------------------------
  19. static bool DoesTextureUseAlpha( const char *pTextureName, const char *pMaterialName )
  20. {
  21. if ( IsX360() )
  22. {
  23. // not supporting
  24. return false;
  25. }
  26. // Special textures start with '_'..
  27. if ( pTextureName[0] == '_' )
  28. return false;
  29. // The texture name doubles as the relative file name
  30. // It's assumed to have already been set by this point
  31. // Compute the cache name
  32. char pCacheFileName[MATERIAL_MAX_PATH];
  33. Q_snprintf( pCacheFileName, sizeof( pCacheFileName ), "materials/%s.vtf", pTextureName );
  34. CUtlBuffer buf;
  35. FileHandle_t fileHandle = g_pFullFileSystem->Open( pCacheFileName, "rb" );
  36. if ( fileHandle == FILESYSTEM_INVALID_HANDLE)
  37. {
  38. Warning( "Material \"%s\": can't open texture \"%s\"\n", pMaterialName, pCacheFileName );
  39. return false;
  40. }
  41. // Check the .vtf for an alpha channel
  42. IVTFTexture *pVTFTexture = CreateVTFTexture();
  43. int nHeaderSize = VTFFileHeaderSize( VTF_MAJOR_VERSION );
  44. buf.EnsureCapacity( nHeaderSize );
  45. // read the header first.. it's faster!!
  46. g_pFullFileSystem->Read( buf.Base(), nHeaderSize, fileHandle );
  47. buf.SeekPut( CUtlBuffer::SEEK_HEAD, nHeaderSize );
  48. // Unserialize the header
  49. bool bUsesAlpha = false;
  50. if (!pVTFTexture->Unserialize( buf, true ))
  51. {
  52. Warning( "Error reading material \"%s\"\n", pCacheFileName );
  53. g_pFullFileSystem->Close(fileHandle);
  54. }
  55. else
  56. {
  57. if ( pVTFTexture->Flags() & (TEXTUREFLAGS_ONEBITALPHA | TEXTUREFLAGS_EIGHTBITALPHA) )
  58. {
  59. bUsesAlpha = true;
  60. }
  61. }
  62. DestroyVTFTexture( pVTFTexture );
  63. g_pFullFileSystem->Close( fileHandle );
  64. return bUsesAlpha;
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Does a texture have alpha?
  68. //-----------------------------------------------------------------------------
  69. static bool DoesTextureUseNormal( const char *pTextureName, const char *pMaterialName, bool &bUsesAlpha, bool &bIsCompressed, int &nSizeInBytes )
  70. {
  71. nSizeInBytes = 0;
  72. bUsesAlpha = false;
  73. if ( IsX360() )
  74. {
  75. // not supporting
  76. return false;
  77. }
  78. // Special textures start with '_'..
  79. if ( !pTextureName || ( pTextureName[0] == '_' ) || ( pTextureName[0] == 0 ) )
  80. return false;
  81. // The texture name doubles as the relative file name
  82. // It's assumed to have already been set by this point
  83. // Compute the cache name
  84. char pCacheFileName[MATERIAL_MAX_PATH];
  85. Q_snprintf( pCacheFileName, sizeof( pCacheFileName ), "materials/%s.vtf", pTextureName );
  86. CUtlBuffer buf;
  87. FileHandle_t fileHandle = g_pFullFileSystem->Open( pCacheFileName, "rb" );
  88. if ( fileHandle == FILESYSTEM_INVALID_HANDLE)
  89. {
  90. // Warning( "Material \"%s\": can't open texture \"%s\"\n", pMaterialName, pCacheFileName );
  91. return false;
  92. }
  93. // Check the .vtf for an alpha channel
  94. IVTFTexture *pVTFTexture = CreateVTFTexture();
  95. int nHeaderSize = VTFFileHeaderSize( VTF_MAJOR_VERSION );
  96. buf.EnsureCapacity( nHeaderSize );
  97. // read the header first.. it's faster!!
  98. g_pFullFileSystem->Read( buf.Base(), nHeaderSize, fileHandle );
  99. buf.SeekPut( CUtlBuffer::SEEK_HEAD, nHeaderSize );
  100. // Unserialize the header
  101. bool bUsesNormal = false;
  102. if ( !pVTFTexture->Unserialize( buf, true ) )
  103. {
  104. Warning( "Error reading material \"%s\"\n", pCacheFileName );
  105. }
  106. else
  107. {
  108. if ( pVTFTexture->Flags() & TEXTUREFLAGS_NORMAL )
  109. {
  110. bUsesAlpha = false;
  111. bUsesNormal = true;
  112. bIsCompressed = ImageLoader::IsCompressed( pVTFTexture->Format() ) || ( pVTFTexture->Format() == IMAGE_FORMAT_A8 );
  113. nSizeInBytes = pVTFTexture->ComputeTotalSize();
  114. if ( pVTFTexture->Flags() & (TEXTUREFLAGS_ONEBITALPHA | TEXTUREFLAGS_EIGHTBITALPHA) )
  115. {
  116. bUsesAlpha = true;
  117. }
  118. }
  119. }
  120. DestroyVTFTexture( pVTFTexture );
  121. g_pFullFileSystem->Close( fileHandle );
  122. return bUsesNormal;
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Is this a real texture
  126. //-----------------------------------------------------------------------------
  127. static bool IsTexture( const char *pTextureName )
  128. {
  129. // Special textures start with '_'..
  130. if ( pTextureName[0] == '_' )
  131. return false;
  132. // The texture name doubles as the relative file name
  133. // It's assumed to have already been set by this point
  134. // Compute the cache name
  135. char pCacheFileName[MATERIAL_MAX_PATH];
  136. Q_snprintf( pCacheFileName, sizeof( pCacheFileName ), "materials/%s.vtf", pTextureName );
  137. FileHandle_t fileHandle = g_pFullFileSystem->Open( pCacheFileName, "rb" );
  138. if ( fileHandle == FILESYSTEM_INVALID_HANDLE)
  139. return false;
  140. g_pFullFileSystem->Close( fileHandle );
  141. return true;
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Scan material + all subsections for key
  145. //-----------------------------------------------------------------------------
  146. static float MaterialFloatKeyValue( KeyValues *pKeyValues, const char *pKeyName, float flDefault )
  147. {
  148. float flValue = pKeyValues->GetFloat( pKeyName, flDefault );
  149. if ( flValue != flDefault )
  150. return flValue;
  151. for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
  152. {
  153. float flValue = MaterialFloatKeyValue( pSubKey, pKeyName, flDefault );
  154. if ( flValue != flDefault )
  155. return flValue;
  156. }
  157. return flDefault;
  158. }
  159. int ParseVectorFromKeyValueString( KeyValues *pKeyValue, const char *pMaterialName, float vecVal[4] );
  160. static bool AsVectorsEqual( int nDim1, float *pVector1, int nDim2, float *pVector2 )
  161. {
  162. if ( nDim1 != nDim2 )
  163. return false;
  164. for ( int i = 0; i < nDim1; ++i )
  165. {
  166. if ( fabs( pVector1[i] - pVector2[i] ) > 1e-3 )
  167. return false;
  168. }
  169. return true;
  170. }
  171. static bool MaterialVectorKeyValue( KeyValues *pKeyValues, const char *pKeyName, int nDefaultDim, float *pDefault, int *pDim, float *pVector )
  172. {
  173. int nDim;
  174. float retVal[4];
  175. KeyValues *pValue = pKeyValues->FindKey( pKeyName );
  176. if ( pValue )
  177. {
  178. switch( pValue->GetDataType() )
  179. {
  180. case KeyValues::TYPE_INT:
  181. {
  182. int nInt = pValue->GetInt();
  183. for ( int i = 0; i < 4; ++i )
  184. {
  185. retVal[i] = nInt;
  186. }
  187. if ( !AsVectorsEqual( nDefaultDim, pDefault, nDefaultDim, retVal ) )
  188. {
  189. *pDim = nDefaultDim;
  190. memcpy( pVector, retVal, nDefaultDim * sizeof(float) );
  191. return true;
  192. }
  193. }
  194. break;
  195. case KeyValues::TYPE_FLOAT:
  196. {
  197. float flFloat = pValue->GetFloat();
  198. for ( int i = 0; i < 4; ++i )
  199. {
  200. retVal[i] = flFloat;
  201. }
  202. if ( !AsVectorsEqual( nDefaultDim, pDefault, nDefaultDim, retVal ) )
  203. {
  204. *pDim = nDefaultDim;
  205. memcpy( pVector, retVal, nDefaultDim * sizeof(float) );
  206. return true;
  207. }
  208. }
  209. break;
  210. case KeyValues::TYPE_STRING:
  211. {
  212. nDim = ParseVectorFromKeyValueString( pValue, "", retVal );
  213. if ( !AsVectorsEqual( nDefaultDim, pDefault, nDim, retVal ) )
  214. {
  215. *pDim = nDim;
  216. memcpy( pVector, retVal, nDim * sizeof(float) );
  217. return true;
  218. }
  219. }
  220. break;
  221. }
  222. }
  223. for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
  224. {
  225. if ( MaterialVectorKeyValue( pSubKey, pKeyName, nDefaultDim, pDefault, &nDim, retVal ) )
  226. {
  227. *pDim = nDim;
  228. memcpy( pVector, retVal, nDim * sizeof(float) );
  229. return true;
  230. }
  231. }
  232. *pDim = nDefaultDim;
  233. memcpy( pVector, pDefault, nDefaultDim * sizeof(float) );
  234. return false;
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Scan material + all subsections for key
  238. //-----------------------------------------------------------------------------
  239. static bool DoesMaterialHaveKey( KeyValues *pKeyValues, const char *pKeyName )
  240. {
  241. if ( pKeyValues->GetString( pKeyName, NULL ) != NULL )
  242. return true;
  243. for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
  244. {
  245. if ( DoesMaterialHaveKey( pSubKey, pKeyName ) )
  246. return true;
  247. }
  248. return false;
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Scan all materials for errors
  252. //-----------------------------------------------------------------------------
  253. static int s_nNormalBytes;
  254. static int s_nNormalCompressedBytes;
  255. static int s_nNormalPalettizedBytes;
  256. static int s_nNormalWithAlphaBytes;
  257. static int s_nNormalWithAlphaCompressedBytes;
  258. struct VTFInfo_t
  259. {
  260. CUtlString m_VTFName;
  261. bool m_bFoundInVMT;
  262. };
  263. void CheckKeyValues( KeyValues *pKeyValues, CUtlVector<VTFInfo_t> &vtf )
  264. {
  265. for ( KeyValues *pSubKey = pKeyValues->GetFirstValue(); pSubKey; pSubKey = pSubKey->GetNextValue() )
  266. {
  267. if ( pSubKey->GetDataType() != KeyValues::TYPE_STRING )
  268. continue;
  269. if ( IsTexture( pSubKey->GetString() ) )
  270. {
  271. int nLen = Q_strlen( pSubKey->GetString() ) + 1;
  272. char *pTemp = (char*)_alloca( nLen );
  273. memcpy( pTemp, pSubKey->GetString(), nLen );
  274. Q_FixSlashes( pTemp );
  275. int nCount = vtf.Count();
  276. for ( int i = 0; i < nCount; ++i )
  277. {
  278. if ( Q_stricmp( vtf[i].m_VTFName, pTemp ) )
  279. continue;
  280. vtf[i].m_bFoundInVMT = true;
  281. break;
  282. }
  283. }
  284. }
  285. for ( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
  286. {
  287. CheckKeyValues( pSubKey, vtf );
  288. }
  289. }
  290. void CheckMaterial( KeyValues *pKeyValues, const char *pRoot, const char *pFileName, CUtlVector<VTFInfo_t> &vtf )
  291. {
  292. const char *pShaderName = pKeyValues->GetName();
  293. /*
  294. if ( Q_stristr( pShaderName, "Water" ) ||
  295. Q_stristr( pShaderName, "Eyeball" ) ||
  296. Q_stristr( pShaderName, "Shadow" ) ||
  297. Q_stristr( pShaderName, "Refract" ) ||
  298. Q_stristr( pShaderName, "Predator" ) ||
  299. Q_stristr( pShaderName, "ParticleSphere" ) ||
  300. Q_stristr( pShaderName, "DebugLuxels" ) ||
  301. Q_stristr( pShaderName, "GooInGlass" ) ||
  302. Q_stristr( pShaderName, "Modulate" ) ||
  303. Q_stristr( pShaderName, "UnlitTwoTexture" ) ||
  304. Q_stristr( pShaderName, "Cloud" ) ||
  305. Q_stristr( pShaderName, "WorldVertexTransition" ) ||
  306. Q_stristr( pShaderName, "DecalModulate" ) ||
  307. Q_stristr( pShaderName, "DecalBaseTimesLightmapAlphaBlendSelfIllum" ) ||
  308. Q_stristr( pShaderName, "Sprite" ) )
  309. {
  310. return;
  311. }
  312. // Check for alpha channels
  313. const char *pBaseTextureName = pKeyValues->GetString( "$basetexture", NULL );
  314. if ( pBaseTextureName != NULL )
  315. {
  316. if ( DoesTextureUseAlpha( pBaseTextureName, pFileName ) )
  317. {
  318. float flAlpha = MaterialFloatKeyValue( pKeyValues, "$alpha", 1.0f );
  319. bool bHasVertexAlpha = DoesMaterialHaveKey( pKeyValues, "$vertexalpha" ); // Modulation always happens here whether we want it to or not
  320. bool bHasAlphaTest = DoesMaterialHaveKey( pKeyValues, "$alphatest" );
  321. bool bHasTranslucent = DoesMaterialHaveKey( pKeyValues, "$translucent" );
  322. bool bHasSelfIllum = DoesMaterialHaveKey( pKeyValues, "$selfillum" );
  323. bool bHasBaseAlphaEnvMapMask = DoesMaterialHaveKey( pKeyValues, "$basealphaenvmapmask" );
  324. if ( (flAlpha == 1.0f) && !bHasVertexAlpha && !bHasAlphaTest && !bHasTranslucent && !bHasSelfIllum && !bHasBaseAlphaEnvMapMask )
  325. {
  326. Warning("Material \"%s\": BASETEXTURE \"%s\"\n", pFileName, pBaseTextureName );
  327. }
  328. }
  329. }
  330. */
  331. /*
  332. // Check for bump, spec, and no normalmapalphaenvmapmask
  333. const char *pBumpmapName = pKeyValues->GetString( "$bumpmap", NULL );
  334. if ( pBumpmapName != NULL )
  335. {
  336. if ( DoesTextureUseAlpha( pBumpmapName, pFileName ) )
  337. {
  338. bool bHasEnvmap = DoesMaterialHaveKey( pKeyValues, "$envmap" );
  339. bool bHasNormalMapAlphaEnvMapMask = DoesMaterialHaveKey( pKeyValues, "$normalmapalphaenvmapmask" );
  340. if ( !bHasEnvmap || !bHasNormalMapAlphaEnvMapMask )
  341. {
  342. Warning("Material \"%s\": BUMPMAP \"%s\"\n", pFileName, pBumpmapName );
  343. }
  344. }
  345. }
  346. */
  347. /*
  348. if ( !Q_stristr( pShaderName, "LightmappedGeneric" ) &&
  349. !Q_stristr( pShaderName, "VertexLitGeneric" ) )
  350. {
  351. return;
  352. }
  353. if ( DoesMaterialHaveKey( pKeyValues, "$envmap" ) && DoesMaterialHaveKey( pKeyValues, "$bumpmap" ) )
  354. {
  355. int nDim;
  356. float retVal[4];
  357. float defaultVal[4] = { 1, 1, 1, 1 };
  358. if ( MaterialVectorKeyValue( pKeyValues, "$envmaptint", 3, defaultVal, &nDim, retVal ) )
  359. {
  360. Warning("ENVMAP + ENVMAPTINT : Material \"%s\"\n", pFileName );
  361. }
  362. // else
  363. // {
  364. // Warning("ENVMAP only: Material \"%s\"\n", pFileName );
  365. // }
  366. }
  367. */
  368. /*
  369. if ( !Q_stristr( pShaderName, "Refract" ) )
  370. {
  371. return;
  372. }
  373. if ( !DoesMaterialHaveKey( pKeyValues, "$envmap" ) )
  374. {
  375. bool bUsesAlpha, bIsCompressed, bIsPalettized;
  376. int nSizeInBytes;
  377. if ( DoesTextureUseNormal( pKeyValues->GetString( "$normalmap" ),
  378. pFileName, bUsesAlpha, bIsCompressed, bIsPalettized, nSizeInBytes ) )
  379. {
  380. if ( bIsCompressed )
  381. {
  382. Warning("Bad : Material compressed \"%s\"\n", pFileName );
  383. }
  384. else
  385. {
  386. Warning("Bad : Material \"%s\"\n", pFileName );
  387. }
  388. }
  389. }
  390. */
  391. /*
  392. if ( !Q_stristr( pShaderName, "WorldTwoTextureBlend" ) )
  393. {
  394. return;
  395. }
  396. if ( DoesMaterialHaveKey( pKeyValues, "$envmap" ) ||
  397. DoesMaterialHaveKey( pKeyValues, "$parallaxmap" ) ||
  398. DoesMaterialHaveKey( pKeyValues, "$bumpmap" ) ||
  399. DoesMaterialHaveKey( pKeyValues, "$vertexcolor" ) ||
  400. DoesMaterialHaveKey( pKeyValues, "$basetexture2" )
  401. )
  402. {
  403. Warning("Bad : Material \"%s\"\n", pFileName );
  404. }
  405. */
  406. for ( KeyValues *pSubKey = pKeyValues->GetFirstValue(); pSubKey; pSubKey = pSubKey->GetNextValue() )
  407. {
  408. // Msg( " Checking %s\n", pSubKey->GetString() );
  409. if ( pSubKey->GetDataType() != KeyValues::TYPE_STRING )
  410. continue;
  411. bool bUsesAlpha, bIsCompressed;
  412. int nSizeInBytes;
  413. if ( DoesTextureUseNormal( pSubKey->GetString(), pFileName, bUsesAlpha, bIsCompressed, nSizeInBytes ) )
  414. {
  415. if ( bUsesAlpha )
  416. {
  417. if ( bIsCompressed )
  418. {
  419. s_nNormalWithAlphaCompressedBytes += nSizeInBytes;
  420. }
  421. else
  422. {
  423. s_nNormalWithAlphaBytes += nSizeInBytes;
  424. Msg( "Normal texture w alpha uncompressed %s\n", pSubKey->GetString() );
  425. }
  426. }
  427. else
  428. {
  429. if ( bIsCompressed )
  430. {
  431. s_nNormalCompressedBytes += nSizeInBytes;
  432. }
  433. else
  434. {
  435. s_nNormalBytes += nSizeInBytes;
  436. }
  437. }
  438. }
  439. }
  440. /*
  441. if ( !Q_stristr( pShaderName, "VertexLitGeneric" ) )
  442. return;
  443. if ( !DoesMaterialHaveKey( pKeyValues, "$envmap" ) && DoesMaterialHaveKey( pKeyValues, "$bumpmap" ) )
  444. {
  445. Warning("BUMPMAP + no ENVMAP : Material \"%s\"\n", pFileName );
  446. }
  447. */
  448. // CheckKeyValues( pKeyValues, vtf );
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Build list of all VTFs
  452. //-----------------------------------------------------------------------------
  453. void CheckVTFInDirectoryRecursive( const char *pRoot, const char *pDirectory, CUtlVector< VTFInfo_t > &vtf )
  454. {
  455. #define BUF_SIZE 1024
  456. char buf[BUF_SIZE];
  457. WIN32_FIND_DATA wfd;
  458. HANDLE findHandle;
  459. sprintf( buf, "%s/%s/*.vtf", pRoot, pDirectory );
  460. findHandle = FindFirstFile( buf, &wfd );
  461. if ( findHandle != INVALID_HANDLE_VALUE )
  462. {
  463. do
  464. {
  465. int i = vtf.AddToTail( );
  466. char buf[MAX_PATH];
  467. char buf2[MAX_PATH];
  468. Q_snprintf( buf, MAX_PATH, "%s/%s", pDirectory, wfd.cFileName );
  469. Q_FixSlashes( buf );
  470. Q_StripExtension( buf, buf2, sizeof(buf2) );
  471. Assert( !Q_strnicmp( buf2, "materials\\", 10 ) );
  472. vtf[i].m_VTFName = &buf2[10];
  473. vtf[i].m_bFoundInVMT = false;
  474. } while ( FindNextFile ( findHandle, &wfd ) );
  475. FindClose ( findHandle );
  476. }
  477. // do subdirectories
  478. sprintf( buf, "%s/%s/*.*", pRoot, pDirectory );
  479. findHandle = FindFirstFile( buf, &wfd );
  480. if ( findHandle != INVALID_HANDLE_VALUE )
  481. {
  482. do
  483. {
  484. if( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  485. {
  486. if( ( strcmp( wfd.cFileName, ".." ) == 0 ) ||
  487. ( strcmp( wfd.cFileName, "." ) == 0 ) )
  488. {
  489. continue;
  490. }
  491. char buf[MAX_PATH];
  492. Q_snprintf( buf, MAX_PATH, "%s/%s", pDirectory, wfd.cFileName );
  493. CheckVTFInDirectoryRecursive( pRoot, buf, vtf );
  494. }
  495. } while ( FindNextFile ( findHandle, &wfd ) );
  496. FindClose ( findHandle );
  497. }
  498. #undef BUF_SIZE
  499. }
  500. //-----------------------------------------------------------------------------
  501. // Scan all materials for errors
  502. //-----------------------------------------------------------------------------
  503. void _CheckMateralsInDirectoryRecursive( const char *pRoot, const char *pDirectory, CUtlVector< VTFInfo_t > &vtf )
  504. {
  505. #define BUF_SIZE 1024
  506. char buf[BUF_SIZE];
  507. WIN32_FIND_DATA wfd;
  508. HANDLE findHandle;
  509. sprintf( buf, "%s/%s/*.vmt", pRoot, pDirectory );
  510. findHandle = FindFirstFile( buf, &wfd );
  511. if ( findHandle != INVALID_HANDLE_VALUE )
  512. {
  513. do
  514. {
  515. KeyValues * vmtKeyValues = new KeyValues("vmt");
  516. char pFileName[MAX_PATH];
  517. Q_snprintf( pFileName, sizeof( pFileName ), "%s/%s", pDirectory, wfd.cFileName );
  518. if ( !vmtKeyValues->LoadFromFile( g_pFullFileSystem, pFileName, "GAME" ) )
  519. {
  520. Warning( "CheckMateralsInDirectoryRecursive: can't open \"%s\"\n", pFileName );
  521. continue;
  522. }
  523. CheckMaterial( vmtKeyValues, pRoot, pFileName, vtf );
  524. vmtKeyValues->deleteThis();
  525. } while ( FindNextFile ( findHandle, &wfd ) );
  526. FindClose ( findHandle );
  527. }
  528. // do subdirectories
  529. sprintf( buf, "%s/%s/*.*", pRoot, pDirectory );
  530. findHandle = FindFirstFile( buf, &wfd );
  531. if ( findHandle != INVALID_HANDLE_VALUE )
  532. {
  533. do
  534. {
  535. if( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  536. {
  537. if( ( strcmp( wfd.cFileName, ".." ) == 0 ) ||
  538. ( strcmp( wfd.cFileName, "." ) == 0 ) )
  539. {
  540. continue;
  541. }
  542. char buf[MAX_PATH];
  543. Q_snprintf( buf, MAX_PATH, "%s/%s", pDirectory, wfd.cFileName );
  544. _CheckMateralsInDirectoryRecursive( pRoot, buf, vtf );
  545. }
  546. } while ( FindNextFile ( findHandle, &wfd ) );
  547. FindClose ( findHandle );
  548. }
  549. // Msg( "Normal only %d/%d/%d Normal w alpha %d/%d\n", s_nNormalBytes, s_nNormalPalettizedBytes, s_nNormalCompressedBytes, s_nNormalWithAlphaBytes, s_nNormalWithAlphaCompressedBytes );
  550. #undef BUF_SIZE
  551. }
  552. void CheckMateralsInDirectoryRecursive( const char *pRoot, const char *pDirectory )
  553. {
  554. CUtlVector< VTFInfo_t > vtfNames;
  555. // CheckVTFInDirectoryRecursive( pRoot, pDirectory, vtfNames );
  556. _CheckMateralsInDirectoryRecursive( pRoot, pDirectory, vtfNames );
  557. /*
  558. int nCount = vtfNames.Count();
  559. for ( int i = 0; i < nCount; ++i )
  560. {
  561. if ( !vtfNames[i].m_bFoundInVMT )
  562. {
  563. Msg( "Unused VTF %s\n", vtfNames[i].m_VTFName );
  564. }
  565. }
  566. */
  567. }
  568. #endif // _CHECK_MATERIALS_FOR_PROBLEMS