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.

668 lines
18 KiB

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