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.

1419 lines
38 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implementation of IEditorTexture interface for materials.
  4. //
  5. // Materials are kept in a directory tree containing pairs of VMT
  6. // and VTF files. Each pair of files represents a material.
  7. //
  8. //=============================================================================//
  9. #include "stdafx.h"
  10. #include <process.h>
  11. #include <afxtempl.h>
  12. #include <io.h>
  13. #include <sys\stat.h>
  14. #include <fcntl.h>
  15. #include "hammer.h"
  16. #include "MapDoc.h"
  17. #include "Material.h"
  18. #include "Options.h"
  19. #include "MainFrm.h"
  20. #include "GlobalFunctions.h"
  21. #include "WADTypes.h"
  22. #include "BSPFile.h"
  23. #include "materialsystem/imaterialsystem.h"
  24. #include "materialsystem/IMaterialSystemHardwareConfig.h"
  25. #include "materialsystem/MaterialSystem_Config.h"
  26. #include "materialsystem/MaterialSystemUtil.h"
  27. #include "materialsystem/itexture.h"
  28. #include "materialsystem/imaterial.h"
  29. #include "bitmap/imageformat.h" // hack : don't want to include this just for ImageFormat
  30. #include "filesystem.h"
  31. #include "StudioModel.h"
  32. #include "tier1/strtools.h"
  33. #include "tier0/dbg.h"
  34. #include "TextureSystem.h"
  35. #include "materialproxyfactory_wc.h"
  36. #include "vstdlib/cvar.h"
  37. #include "interface.h"
  38. // memdbgon must be the last include file in a .cpp file!!!
  39. #include <tier0/memdbgon.h>
  40. #pragma warning(disable:4244)
  41. #define _GraphicCacheAllocate(n) malloc(n)
  42. MaterialSystem_Config_t g_materialSystemConfig;
  43. static MaterialHandle_t g_CurrMaterial;
  44. extern void ScaleBitmap(CSize sizeSrc, CSize sizeDest, char *src, char *dest);
  45. struct MaterialCacheEntry_t
  46. {
  47. char szName[MAX_PATH]; //
  48. CMaterial *pMaterial; //
  49. int nRefCount; //
  50. };
  51. //-----------------------------------------------------------------------------
  52. // Purpose:
  53. // This class speeds up the call to IMaterial::GetPreviewImageProperties because
  54. // we call it thousands of times per level load when there are detail props.
  55. //-----------------------------------------------------------------------------
  56. class CPreviewImagePropertiesCache
  57. {
  58. public:
  59. //-----------------------------------------------------------------------------
  60. // Purpose: Anyone can call this instead of IMaterial::GetPreviewImageProperties
  61. // and it'll be a lot faster if there are redundant calls to it.
  62. //-----------------------------------------------------------------------------
  63. static PreviewImageRetVal_t GetPreviewImageProperties( IMaterial *pMaterial, int *width, int *height, ImageFormat *imageFormat, bool* isTranslucent )
  64. {
  65. int i = s_PreviewImagePropertiesCache.Find( pMaterial );
  66. if ( i == s_PreviewImagePropertiesCache.InvalidIndex() )
  67. {
  68. // Add an entry to the cache.
  69. CPreviewImagePropertiesCache::CEntry entry;
  70. entry.m_RetVal = pMaterial->GetPreviewImageProperties( &entry.m_Width, &entry.m_Height, &entry.m_ImageFormat, &entry.m_bIsTranslucent );
  71. i = s_PreviewImagePropertiesCache.Insert( pMaterial, entry );
  72. }
  73. CPreviewImagePropertiesCache::CEntry &entry = s_PreviewImagePropertiesCache[i];
  74. *width = entry.m_Width;
  75. *height = entry.m_Height;
  76. *imageFormat = entry.m_ImageFormat;
  77. *isTranslucent = entry.m_bIsTranslucent;
  78. return entry.m_RetVal;
  79. }
  80. private:
  81. class CEntry
  82. {
  83. public:
  84. int m_Width;
  85. int m_Height;
  86. ImageFormat m_ImageFormat;
  87. bool m_bIsTranslucent;
  88. PreviewImageRetVal_t m_RetVal;
  89. };
  90. static bool PreviewImageLessFunc( IMaterial* const &a, IMaterial* const &b )
  91. {
  92. return a < b;
  93. }
  94. static CUtlMap<IMaterial*, CPreviewImagePropertiesCache::CEntry> s_PreviewImagePropertiesCache;
  95. };
  96. CUtlMap<IMaterial*, CPreviewImagePropertiesCache::CEntry> CPreviewImagePropertiesCache::s_PreviewImagePropertiesCache( 64, 64, &CPreviewImagePropertiesCache::PreviewImageLessFunc );
  97. //-----------------------------------------------------------------------------
  98. // Purpose: stuff for caching textures in memory.
  99. //-----------------------------------------------------------------------------
  100. class CMaterialImageCache
  101. {
  102. public:
  103. CMaterialImageCache(int maxNumGraphicsLoaded);
  104. ~CMaterialImageCache(void);
  105. void EnCache( CMaterial *pMaterial );
  106. protected:
  107. CMaterial **pool;
  108. int cacheSize;
  109. int currentID; // next one to get killed.
  110. };
  111. //-----------------------------------------------------------------------------
  112. // Purpose: Constructor. Allocates a pool of material pointers.
  113. // Input : maxNumGraphicsLoaded -
  114. //-----------------------------------------------------------------------------
  115. CMaterialImageCache::CMaterialImageCache(int maxNumGraphicsLoaded)
  116. {
  117. cacheSize = maxNumGraphicsLoaded;
  118. pool = new CMaterialPtr[cacheSize];
  119. if (pool != NULL)
  120. {
  121. memset(pool, 0, sizeof(CMaterialPtr) * cacheSize);
  122. }
  123. currentID = 0;
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose: Destructor. Frees the pool memory.
  127. //-----------------------------------------------------------------------------
  128. CMaterialImageCache::~CMaterialImageCache(void)
  129. {
  130. if (pool != NULL)
  131. {
  132. delete [] pool;
  133. }
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Purpose:
  137. // Input : *pMaterial -
  138. //-----------------------------------------------------------------------------
  139. void CMaterialImageCache::EnCache( CMaterial *pMaterial )
  140. {
  141. if (pMaterial->m_pData != NULL)
  142. {
  143. // Already cached.
  144. return;
  145. }
  146. // kill currentID
  147. if ((pool[currentID]) && (pool[currentID]->HasData()))
  148. {
  149. pool[currentID]->FreeData();
  150. }
  151. pool[currentID] = pMaterial;
  152. pMaterial->LoadMaterialImage();
  153. currentID = ( currentID + 1 ) % cacheSize;
  154. #if 0
  155. OutputDebugString( "CMaterialCache::Encache: " );
  156. OutputDebugString( pMaterial->m_szName );
  157. OutputDebugString( "\n" );
  158. #endif
  159. }
  160. static CMaterialImageCache *g_pMaterialImageCache = NULL;
  161. //-----------------------------------------------------------------------------
  162. // Purpose:
  163. //-----------------------------------------------------------------------------
  164. CMaterialCache::CMaterialCache(void)
  165. {
  166. m_pCache = NULL;
  167. m_nMaxEntries = 0;
  168. }
  169. //-----------------------------------------------------------------------------
  170. // Purpose:
  171. //-----------------------------------------------------------------------------
  172. CMaterialCache::~CMaterialCache(void)
  173. {
  174. if (m_pCache != NULL)
  175. {
  176. delete m_pCache;
  177. }
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose: Allocates cache memory for a given number of materials.
  181. // Input : nMaxEntries - Maximum number of materials in the cache.
  182. // Output : Returns true on success, false on failure.
  183. //-----------------------------------------------------------------------------
  184. bool CMaterialCache::Create(int nMaxEntries)
  185. {
  186. Assert((m_pCache == NULL) && (m_nMaxEntries == 0));
  187. if (m_pCache != NULL)
  188. {
  189. delete m_pCache;
  190. m_pCache = NULL;
  191. m_nMaxEntries = 0;
  192. }
  193. if (nMaxEntries <= 0)
  194. {
  195. nMaxEntries = 500;
  196. }
  197. m_pCache = new MaterialCacheEntry_t[nMaxEntries];
  198. if (m_pCache != NULL)
  199. {
  200. memset(m_pCache, 0, sizeof(m_pCache[0]) * nMaxEntries);
  201. m_nMaxEntries = nMaxEntries;
  202. }
  203. return(m_pCache != NULL);
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Purpose: Factory. Creates a material by name, first looking in the cache.
  207. // Input : pszMaterialName - Name of material, ie "brick/brickfloor01".
  208. // Output : Returns a pointer to the new material object, NULL if the given
  209. // material did not exist.
  210. //-----------------------------------------------------------------------------
  211. CMaterial *CMaterialCache::CreateMaterial(const char *pszMaterialName)
  212. {
  213. CMaterial *pMaterial = NULL;
  214. if (pszMaterialName != NULL)
  215. {
  216. //
  217. // Find this material in the cache. If it is here, return it.
  218. //
  219. pMaterial = FindMaterial(pszMaterialName);
  220. if (pMaterial == NULL)
  221. {
  222. //
  223. // Not found in the cache, try to create it.
  224. //
  225. pMaterial = CMaterial::CreateMaterial(pszMaterialName, true);
  226. if (pMaterial != NULL)
  227. {
  228. //
  229. // Success. Add the newly created material to the cache.
  230. //
  231. AddMaterial(pMaterial);
  232. return(pMaterial);
  233. }
  234. }
  235. else
  236. {
  237. //
  238. // Found in the cache, bump the reference count.
  239. //
  240. AddRef(pMaterial);
  241. }
  242. }
  243. return(pMaterial);
  244. }
  245. //-----------------------------------------------------------------------------
  246. // Purpose: Finds a material in the cache.
  247. // Input : char *pszMaterialName -
  248. // Output : CMaterial
  249. //-----------------------------------------------------------------------------
  250. void CMaterialCache::AddMaterial(CMaterial *pMaterial)
  251. {
  252. if (pMaterial != NULL)
  253. {
  254. Assert(m_nEntries < m_nMaxEntries);
  255. if (m_nEntries < m_nMaxEntries)
  256. {
  257. m_pCache[m_nEntries].pMaterial = pMaterial;
  258. m_pCache[m_nEntries].nRefCount = 1;
  259. m_nEntries++;
  260. }
  261. }
  262. }
  263. //-----------------------------------------------------------------------------
  264. // Purpose: Increments the reference count on a material in the cache. Called by
  265. // client code when a pointer to the model is copied, making that
  266. // reference independent.
  267. // Input : pModel - Model for which to increment the reference count.
  268. //-----------------------------------------------------------------------------
  269. void CMaterialCache::AddRef(CMaterial *pMaterial)
  270. {
  271. for (int i = 0; i < m_nEntries; i++)
  272. {
  273. if (m_pCache[i].pMaterial == pMaterial)
  274. {
  275. m_pCache[i].nRefCount++;
  276. return;
  277. }
  278. }
  279. }
  280. //-----------------------------------------------------------------------------
  281. // Purpose: Finds a material in the cache by name.
  282. // Input : char *pszMaterialName -
  283. // Output : CMaterial
  284. //-----------------------------------------------------------------------------
  285. CMaterial *CMaterialCache::FindMaterial(const char *pszMaterialName)
  286. {
  287. if (pszMaterialName != NULL)
  288. {
  289. for (int i = 0; i < m_nEntries; i++)
  290. {
  291. if (!stricmp(m_pCache[i].pMaterial->GetName(), pszMaterialName))
  292. {
  293. return(m_pCache[i].pMaterial);
  294. }
  295. }
  296. }
  297. return(NULL);
  298. }
  299. //-----------------------------------------------------------------------------
  300. // Purpose: Decrements the reference count of a material, deleting it and
  301. // removing it from the cache if its reference count becomes zero.
  302. // Input : pMaterial - Material to release.
  303. //-----------------------------------------------------------------------------
  304. void CMaterialCache::Release(CMaterial *pMaterial)
  305. {
  306. if (pMaterial != NULL)
  307. {
  308. for (int i = 0; i < m_nEntries; i++)
  309. {
  310. if (m_pCache[i].pMaterial == pMaterial)
  311. {
  312. m_pCache[i].nRefCount--;
  313. if (m_pCache[i].nRefCount == 0)
  314. {
  315. delete m_pCache[i].pMaterial;
  316. m_nEntries--;
  317. m_pCache[i] = m_pCache[m_nEntries];
  318. memset(&m_pCache[m_nEntries], 0, sizeof(m_pCache[0]));
  319. }
  320. break;
  321. }
  322. }
  323. }
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Purpose: Constructor. Initializes data members.
  327. //-----------------------------------------------------------------------------
  328. CMaterial::CMaterial(void)
  329. {
  330. memset(m_szName, 0, sizeof(m_szName));
  331. memset(m_szFileName, 0, sizeof(m_szFileName));
  332. memset(m_szKeywords, 0, sizeof(m_szKeywords));
  333. m_nWidth = 0;
  334. m_nHeight = 0;
  335. m_nTextureID = 0;
  336. m_pData = NULL;
  337. m_bLoaded = false;
  338. m_pMaterial = NULL;
  339. m_TranslucentBaseTexture = false;
  340. }
  341. //-----------------------------------------------------------------------------
  342. // Purpose: Destructor. Frees texture image data and palette.
  343. //-----------------------------------------------------------------------------
  344. CMaterial::~CMaterial(void)
  345. {
  346. //
  347. // Free image data.
  348. //
  349. if (m_pData != NULL)
  350. {
  351. free(m_pData);
  352. m_pData = NULL;
  353. }
  354. /* FIXME: Texture manager shuts down after the material system
  355. if (m_pMaterial)
  356. {
  357. m_pMaterial->DecrementReferenceCount();
  358. m_pMaterial = NULL;
  359. }
  360. */
  361. }
  362. #define MATERIAL_PREFIX_LEN 10
  363. //-----------------------------------------------------------------------------
  364. // Finds all .VMT files in a particular directory
  365. //-----------------------------------------------------------------------------
  366. bool CMaterial::LoadMaterialsInDirectory( char const* pDirectoryName, int nDirectoryNameLen,
  367. IMaterialEnumerator *pEnum, int nContext, int nFlags )
  368. {
  369. //Assert( Q_strnicmp( pDirectoryName, "materials", 9 ) == 0 );
  370. char *pWildCard;
  371. pWildCard = ( char * )stackalloc( nDirectoryNameLen + 7 );
  372. Q_snprintf( pWildCard, nDirectoryNameLen + 7, "%s/*.vmt", pDirectoryName );
  373. if ( !g_pFileSystem )
  374. {
  375. return false;
  376. }
  377. FileFindHandle_t findHandle;
  378. const char *pFileName = g_pFullFileSystem->FindFirstEx( pWildCard, "GAME", &findHandle );
  379. while( pFileName )
  380. {
  381. if (IsIgnoredMaterial(pFileName))
  382. {
  383. pFileName = g_pFullFileSystem->FindNext( findHandle );
  384. continue;
  385. }
  386. if( !g_pFullFileSystem->FindIsDirectory( findHandle ) )
  387. {
  388. // Strip off the 'materials/' part of the material name.
  389. char *pFileNameWithPath;
  390. int nAllocSize = nDirectoryNameLen + Q_strlen(pFileName) + 2;
  391. pFileNameWithPath = (char *)stackalloc( nAllocSize );
  392. Q_snprintf( pFileNameWithPath, nAllocSize, "%s/%s", &pDirectoryName[MATERIAL_PREFIX_LEN], pFileName );
  393. Q_strnlwr( pFileNameWithPath, nAllocSize );
  394. // Strip off the extension...
  395. char *pExt = Q_strrchr( pFileNameWithPath, '.');
  396. if (pExt)
  397. *pExt = 0;
  398. if (!pEnum->EnumMaterial( pFileNameWithPath, nContext ))
  399. {
  400. return false;
  401. }
  402. }
  403. pFileName = g_pFullFileSystem->FindNext( findHandle );
  404. }
  405. g_pFullFileSystem->FindClose( findHandle );
  406. return true;
  407. }
  408. //-----------------------------------------------------------------------------
  409. // Discovers all .VMT files lying under a particular directory
  410. // It only finds their names so we can generate shell materials for them
  411. // that we can load up at a later time
  412. //-----------------------------------------------------------------------------
  413. bool CMaterial::InitDirectoryRecursive( char const* pDirectoryName,
  414. IMaterialEnumerator *pEnum, int nContext, int nFlags )
  415. {
  416. // Make sure this is an ok directory, otherwise don't bother
  417. if (ShouldSkipMaterial( pDirectoryName + MATERIAL_PREFIX_LEN, nFlags ))
  418. return true;
  419. // Compute directory name length
  420. int nDirectoryNameLen = Q_strlen( pDirectoryName );
  421. if (!LoadMaterialsInDirectory( pDirectoryName, nDirectoryNameLen, pEnum, nContext, nFlags ))
  422. return false;
  423. char *pWildCard = ( char * )stackalloc( nDirectoryNameLen + 5 );
  424. strcpy(pWildCard, pDirectoryName);
  425. strcat(pWildCard, "/*.*");
  426. int nPathStrLen = nDirectoryNameLen + 1;
  427. FileFindHandle_t findHandle;
  428. const char *pFileName = g_pFullFileSystem->FindFirstEx( pWildCard, "GAME", &findHandle );
  429. while( pFileName )
  430. {
  431. if (!IsIgnoredMaterial(pFileName))
  432. {
  433. if ((pFileName[0] != '.') || (pFileName[1] != '.' && pFileName[1] != 0))
  434. {
  435. if( g_pFullFileSystem->FindIsDirectory( findHandle ) )
  436. {
  437. int fileNameStrLen = Q_strlen( pFileName );
  438. char *pFileNameWithPath = ( char * )stackalloc( nPathStrLen + fileNameStrLen + 1 );
  439. memcpy( pFileNameWithPath, pWildCard, nPathStrLen );
  440. pFileNameWithPath[nPathStrLen] = '\0';
  441. Q_strncat( pFileNameWithPath, pFileName, nPathStrLen + fileNameStrLen + 1 );
  442. if (!InitDirectoryRecursive( pFileNameWithPath, pEnum, nContext, nFlags ))
  443. return false;
  444. }
  445. }
  446. }
  447. pFileName = g_pFullFileSystem->FindNext( findHandle );
  448. }
  449. return true;
  450. }
  451. //-----------------------------------------------------------------------------
  452. // Discovers all .VMT files lying under a particular directory
  453. // It only finds their names so we can generate shell materials for them
  454. // that we can load up at a later time
  455. //-----------------------------------------------------------------------------
  456. void CMaterial::EnumerateMaterials( IMaterialEnumerator *pEnum, const char *szRoot, int nContext, int nFlags )
  457. {
  458. InitDirectoryRecursive( szRoot, pEnum, nContext, nFlags );
  459. }
  460. //-----------------------------------------------------------------------------
  461. // Purpose: Called from GetFirst/GetNextMaterialName to skip unwanted materials.
  462. // Input : pszName - Name of material to evaluate.
  463. // nFlags - One or more of the following:
  464. // INCLUDE_ALL_MATERIALS
  465. // INCLUDE_WORLD_MATERIALS
  466. // INCLUDE_MODEL_MATERIALS
  467. // Output : Returns true to skip, false to not skip this material.
  468. //-----------------------------------------------------------------------------
  469. bool CMaterial::ShouldSkipMaterial(const char *pszName, int nFlags)
  470. {
  471. static char szStrippedName[MAX_PATH];
  472. // if NULL skip it
  473. if( !pszName )
  474. return true;
  475. //
  476. // check against the list of user-defined exclusion directories
  477. //
  478. for( int i = 0; i < g_pGameConfig->m_MaterialExcludeCount; i++ )
  479. {
  480. // This will guarantee the match is at the start of the string
  481. const char *pMatchFound = Q_stristr( pszName, g_pGameConfig->m_MaterialExclusions[i].szDirectory );
  482. if( pMatchFound == pszName )
  483. return true;
  484. }
  485. // also check against any FGD-defined exclusions
  486. if (pGD != NULL)
  487. {
  488. for( int i = 0; i < pGD->m_FGDMaterialExclusions.Count(); i++ )
  489. {
  490. const char *pMatchFound = Q_stristr( pszName, pGD->m_FGDMaterialExclusions[i].szDirectory );
  491. if( pMatchFound == pszName )
  492. return true;
  493. }
  494. }
  495. return false;
  496. #if 0
  497. bool bSkip = false;
  498. if (pszName != NULL)
  499. {
  500. if (!(nFlags & INCLUDE_MODEL_MATERIALS))
  501. {
  502. if (_strnicmp(pszName, "models/", 7) == 0)
  503. {
  504. bSkip = true;
  505. }
  506. }
  507. if (!(nFlags & INCLUDE_WORLD_MATERIALS))
  508. {
  509. if (_strnicmp(pszName, "models/", 7) != 0)
  510. {
  511. bSkip = true;
  512. }
  513. }
  514. }
  515. else
  516. {
  517. bSkip = true;
  518. }
  519. return(bSkip);
  520. #endif
  521. }
  522. //-----------------------------------------------------------------------------
  523. // Purpose: Factory. Creates a material by name.
  524. // Input : pszMaterialName - Name of material, ie "brick/brickfloor01".
  525. // Output : Returns a pointer to the new material object, NULL if the given
  526. // material did not exist.
  527. //-----------------------------------------------------------------------------
  528. CMaterial *CMaterial::CreateMaterial(const char *pszMaterialName, bool bLoadImmediately, bool* pFound)
  529. {
  530. Assert (pszMaterialName);
  531. CMaterial *pMaterial = new CMaterial;
  532. Assert( pMaterial );
  533. // Store off the material name so we can load it later if we need to
  534. Q_snprintf( pMaterial->m_szFileName, MAX_PATH, pszMaterialName );
  535. Q_snprintf( pMaterial->m_szName, MAX_PATH, pszMaterialName );
  536. //
  537. // Find the material by name and load it.
  538. //
  539. if (bLoadImmediately)
  540. {
  541. bool bFound = pMaterial->LoadMaterial();
  542. // Returns if the material was found or not
  543. if (pFound)
  544. *pFound = bFound;
  545. }
  546. return pMaterial;
  547. }
  548. bool CMaterial::IsIgnoredMaterial( const char *pName )
  549. {
  550. //TODO: make this a customizable user option?
  551. if ( !Q_strnicmp(pName, ".svn", 4) || strstr (pName, ".svn") ||
  552. !Q_strnicmp(pName, "models", 6) || strstr (pName, "models") )
  553. return true;
  554. return false;
  555. }
  556. //-----------------------------------------------------------------------------
  557. // Will actually load the material bits
  558. // We don't want to load them all at once because it takes way too long
  559. //-----------------------------------------------------------------------------
  560. bool CMaterial::LoadMaterial()
  561. {
  562. bool bFound = true;
  563. if (!m_bLoaded)
  564. {
  565. if (IsIgnoredMaterial(m_szFileName))
  566. {
  567. return false;
  568. }
  569. m_bLoaded = true;
  570. IMaterial *pMat = materials->FindMaterial(m_szFileName, TEXTURE_GROUP_OTHER);
  571. if ( IsErrorMaterial( pMat ) )
  572. bFound = false;
  573. Assert( pMat );
  574. if (!pMat)
  575. {
  576. return false;
  577. }
  578. if (!LoadMaterialHeader(pMat))
  579. {
  580. // dvs: yeaaaaaaaaah, we're gonna disable this until the spew can be reduced
  581. //Msg( mwError,"Load material header failed: %s", m_szFileName );
  582. bFound = false;
  583. pMat = materials->FindMaterial("debug/debugempty", TEXTURE_GROUP_OTHER);
  584. if (pMat)
  585. {
  586. LoadMaterialHeader(pMat);
  587. }
  588. }
  589. }
  590. return bFound;
  591. }
  592. //-----------------------------------------------------------------------------
  593. // Reloads owing to a material change
  594. //-----------------------------------------------------------------------------
  595. void CMaterial::Reload( bool bFullReload )
  596. {
  597. // Don't bother if we're not loaded yet
  598. if (!m_bLoaded)
  599. return;
  600. FreeData();
  601. if ( m_pMaterial )
  602. {
  603. m_pMaterial->DecrementReferenceCount();
  604. }
  605. m_pMaterial = materials->FindMaterial(m_szFileName, TEXTURE_GROUP_OTHER);
  606. Assert( m_pMaterial );
  607. if ( bFullReload )
  608. m_pMaterial->Refresh();
  609. PreviewImageRetVal_t retVal;
  610. bool translucentBaseTexture;
  611. ImageFormat eImageFormat;
  612. int width, height;
  613. retVal = m_pMaterial->GetPreviewImageProperties(&width, &height, &eImageFormat, &translucentBaseTexture);
  614. if (retVal == MATERIAL_PREVIEW_IMAGE_BAD)
  615. return;
  616. m_nWidth = width;
  617. m_nHeight = height;
  618. m_TranslucentBaseTexture = translucentBaseTexture;
  619. // Find the keywords for this material from the vmt file.
  620. bool bFound;
  621. IMaterialVar *pVar = m_pMaterial->FindVar("%keywords", &bFound, false);
  622. if (bFound)
  623. {
  624. V_strcpy_safe( m_szKeywords, pVar->GetStringValue() );
  625. // Register the keywords
  626. g_Textures.RegisterTextureKeywords( this );
  627. }
  628. // Make sure to bump the refcount again. Not sure why this wasn't always done (check for leaks).
  629. if (m_pMaterial)
  630. {
  631. m_pMaterial->IncrementReferenceCount();
  632. }
  633. }
  634. //-----------------------------------------------------------------------------
  635. // Returns the material
  636. //-----------------------------------------------------------------------------
  637. IMaterial* CMaterial::GetMaterial( bool bForceLoad )
  638. {
  639. if ( bForceLoad )
  640. LoadMaterial();
  641. return m_pMaterial;
  642. }
  643. //-----------------------------------------------------------------------------
  644. // Purpose:
  645. //-----------------------------------------------------------------------------
  646. void CMaterial::DrawIcon( CDC *pDC, CMaterial* pIcon, RECT& dstRect )
  647. {
  648. if (!pIcon)
  649. return;
  650. g_pMaterialImageCache->EnCache(pIcon);
  651. RECT rect, dst;
  652. rect.left = 0; rect.right = pIcon->GetWidth();
  653. // FIXME: Workaround the fact that materials must be power of 2, I want 12 bite
  654. rect.top = 2; rect.bottom = pIcon->GetHeight() - 2;
  655. dst = dstRect;
  656. float dstHeight = dstRect.bottom - dstRect.top;
  657. float srcAspect = (float)(rect.right - rect.left) / (float)(rect.bottom - rect.top);
  658. dst.right = dst.left + (dstHeight * srcAspect);
  659. pIcon->DrawBitmap( pDC, rect, dst );
  660. dstRect.left += dst.right - dst.left;
  661. }
  662. //-----------------------------------------------------------------------------
  663. // Purpose:
  664. // Input : pDC -
  665. // dstRect -
  666. // detectErrors -
  667. //-----------------------------------------------------------------------------
  668. void CMaterial::DrawBrowserIcons( CDC *pDC, RECT& dstRect, bool detectErrors )
  669. {
  670. static CMaterial* pTranslucentIcon = 0;
  671. static CMaterial* pOpaqueIcon = 0;
  672. static CMaterial* pSelfIllumIcon = 0;
  673. static CMaterial* pBaseAlphaEnvMapMaskIcon = 0;
  674. static CMaterial* pErrorIcon = 0;
  675. if (!pTranslucentIcon)
  676. {
  677. pTranslucentIcon = CreateMaterial("editor/translucenticon", true);
  678. pOpaqueIcon = CreateMaterial("editor/opaqueicon", true);
  679. pSelfIllumIcon = CreateMaterial("editor/selfillumicon", true);
  680. pBaseAlphaEnvMapMaskIcon = CreateMaterial("editor/basealphaenvmapmaskicon", true);
  681. pErrorIcon = CreateMaterial("editor/erroricon", true);
  682. Assert( pTranslucentIcon && pOpaqueIcon && pSelfIllumIcon && pBaseAlphaEnvMapMaskIcon && pErrorIcon );
  683. }
  684. bool error = false;
  685. IMaterial* pMaterial = GetMaterial();
  686. if ( pMaterial->GetMaterialVarFlag( MATERIAL_VAR_TRANSLUCENT ) )
  687. {
  688. DrawIcon( pDC, pTranslucentIcon, dstRect );
  689. if (detectErrors)
  690. {
  691. error = error || !m_TranslucentBaseTexture;
  692. }
  693. }
  694. else
  695. {
  696. DrawIcon( pDC, pOpaqueIcon, dstRect );
  697. }
  698. if ( pMaterial->GetMaterialVarFlag( MATERIAL_VAR_SELFILLUM ))
  699. {
  700. DrawIcon( pDC, pSelfIllumIcon, dstRect );
  701. if (detectErrors)
  702. {
  703. error = error || !m_TranslucentBaseTexture;
  704. }
  705. }
  706. if ( pMaterial->GetMaterialVarFlag( MATERIAL_VAR_BASEALPHAENVMAPMASK ))
  707. {
  708. DrawIcon( pDC, pBaseAlphaEnvMapMaskIcon, dstRect );
  709. if (detectErrors)
  710. {
  711. error = error || !m_TranslucentBaseTexture;
  712. }
  713. }
  714. if (error)
  715. {
  716. DrawIcon( pDC, pErrorIcon, dstRect );
  717. }
  718. }
  719. //-----------------------------------------------------------------------------
  720. // Purpose:
  721. // Input : pDC -
  722. // srcRect -
  723. // dstRect -
  724. //-----------------------------------------------------------------------------
  725. void CMaterial::DrawBitmap( CDC *pDC, RECT& srcRect, RECT& dstRect )
  726. {
  727. static struct
  728. {
  729. BITMAPINFOHEADER bmih;
  730. unsigned short colorindex[256];
  731. } bmi;
  732. int srcWidth = srcRect.right - srcRect.left;
  733. int srcHeight = srcRect.bottom - srcRect.top;
  734. BITMAPINFOHEADER &bmih = bmi.bmih;
  735. memset(&bmih, 0, sizeof(bmih));
  736. bmih.biSize = sizeof(bmih);
  737. bmih.biWidth = srcWidth;
  738. bmih.biHeight = -srcHeight;
  739. bmih.biCompression = BI_RGB;
  740. bmih.biBitCount = 24;
  741. bmih.biPlanes = 1;
  742. static BOOL bInit = false;
  743. if (!bInit)
  744. {
  745. bInit = true;
  746. for (int i = 0; i < 256; i++)
  747. {
  748. bmi.colorindex[i] = i;
  749. }
  750. }
  751. int dest_width = dstRect.right - dstRect.left;
  752. int dest_height = dstRect.bottom - dstRect.top;
  753. // ** bits **
  754. SetStretchBltMode(pDC->m_hDC, COLORONCOLOR);
  755. if (StretchDIBits(pDC->m_hDC, dstRect.left, dstRect.top, dest_width, dest_height,
  756. srcRect.left, -srcRect.top, srcWidth, srcHeight, m_pData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR)
  757. {
  758. Msg(mwError, "CMaterial::Draw(): StretchDIBits failed.");
  759. }
  760. }
  761. //-----------------------------------------------------------------------------
  762. // Purpose:
  763. // Input : *pDC -
  764. // rect -
  765. // iFontHeight -
  766. // dwFlags -
  767. //-----------------------------------------------------------------------------
  768. void CMaterial::Draw(CDC *pDC, RECT& rect, int iFontHeight, int iIconHeight, DrawTexData_t &DrawTexData)//, BrowserData_t *pBrowserData)
  769. {
  770. g_pMaterialImageCache->EnCache(this);
  771. if (!this->HasData())
  772. {
  773. return;
  774. }
  775. if (m_nWidth <= 0)
  776. {
  777. NoData:
  778. // draw "no data"
  779. CFont *pOldFont = (CFont*) pDC->SelectStockObject(ANSI_VAR_FONT);
  780. COLORREF cr = pDC->SetTextColor(RGB(0xff, 0xff, 0xff));
  781. COLORREF cr2 = pDC->SetBkColor(RGB(0, 0, 0));
  782. // draw black rect first
  783. pDC->FillRect(&rect, CBrush::FromHandle(HBRUSH(GetStockObject(BLACK_BRUSH))));
  784. // then text
  785. pDC->TextOut(rect.left+2, rect.top+2, "No Image", 8);
  786. pDC->SelectObject(pOldFont);
  787. pDC->SetTextColor(cr);
  788. pDC->SetBkColor(cr2);
  789. return;
  790. }
  791. // no data -
  792. if (!m_pData)
  793. {
  794. // try to load -
  795. if (!Load())
  796. {
  797. // can't load -
  798. goto NoData;
  799. }
  800. }
  801. // Draw the material image
  802. RECT srcRect, dstRect;
  803. srcRect.left = 0;
  804. srcRect.top = 0;
  805. srcRect.right = m_nWidth;
  806. srcRect.bottom = m_nHeight;
  807. dstRect = rect;
  808. if (DrawTexData.nFlags & drawCaption)
  809. {
  810. dstRect.bottom -= iFontHeight + 4;
  811. }
  812. if (DrawTexData.nFlags & drawIcons)
  813. {
  814. dstRect.bottom -= iIconHeight;
  815. }
  816. if (!(DrawTexData.nFlags & drawResizeAlways))
  817. {
  818. if (m_nWidth < dstRect.right - dstRect.left )
  819. {
  820. dstRect.right = dstRect.left + m_nWidth;
  821. }
  822. if (m_nHeight < dstRect.bottom - dstRect.top )
  823. {
  824. dstRect.bottom = dstRect.top + m_nHeight;
  825. }
  826. }
  827. DrawBitmap( pDC, srcRect, dstRect );
  828. // Draw the icons
  829. if (DrawTexData.nFlags & drawIcons)
  830. {
  831. dstRect = rect;
  832. if (DrawTexData.nFlags & drawCaption)
  833. {
  834. dstRect.bottom -= iFontHeight + 5;
  835. }
  836. dstRect.top = dstRect.bottom - iIconHeight;
  837. DrawBrowserIcons(pDC, dstRect, (DrawTexData.nFlags & drawErrors) != 0 );
  838. }
  839. // ** caption **
  840. if (DrawTexData.nFlags & drawCaption)
  841. {
  842. // draw background for name
  843. CBrush brCaption(RGB(0, 0, 255));
  844. CRect rcCaption(rect);
  845. rcCaption.top = rcCaption.bottom - (iFontHeight + 5);
  846. pDC->FillRect(rcCaption, &brCaption);
  847. // draw name
  848. char szShortName[MAX_PATH];
  849. int iLen = GetShortName(szShortName);
  850. pDC->TextOut(rect.left, rect.bottom - (iFontHeight + 4), szShortName, iLen);
  851. // draw usage count
  852. if (DrawTexData.nFlags & drawUsageCount)
  853. {
  854. CString str;
  855. str.Format("%d", DrawTexData.nUsageCount);
  856. CSize size = pDC->GetTextExtent(str);
  857. pDC->TextOut(rect.right - size.cx, rect.bottom - (iFontHeight + 4), str);
  858. }
  859. }
  860. }
  861. //-----------------------------------------------------------------------------
  862. // Purpose:
  863. //-----------------------------------------------------------------------------
  864. void CMaterial::FreeData( void )
  865. {
  866. free( m_pData );
  867. m_pData = NULL;
  868. }
  869. //-----------------------------------------------------------------------------
  870. // Purpose: Returns a string of comma delimited keywords associated with this
  871. // material.
  872. // Input : pszKeywords - Buffer to receive keywords, NULL to query string length.
  873. // Output : Returns the number of characters in the keyword string.
  874. //-----------------------------------------------------------------------------
  875. int CMaterial::GetKeywords(char *pszKeywords) const
  876. {
  877. // To access keywords, we have to have the header loaded
  878. const_cast<CMaterial*>(this)->Load();
  879. if (pszKeywords != NULL)
  880. {
  881. strcpy(pszKeywords, m_szKeywords);
  882. }
  883. return(strlen(m_szKeywords));
  884. }
  885. //-----------------------------------------------------------------------------
  886. // Purpose:
  887. // Input : *pszName -
  888. // Output : int
  889. //-----------------------------------------------------------------------------
  890. int CMaterial::GetShortName(char *pszName) const
  891. {
  892. if (pszName != NULL)
  893. {
  894. strcpy(pszName, m_szName);
  895. }
  896. return(strlen(m_szName));
  897. }
  898. //-----------------------------------------------------------------------------
  899. // Purpose:
  900. // Input : material -
  901. // Output : Returns true on success, false on failure.
  902. //-----------------------------------------------------------------------------
  903. bool CMaterial::LoadMaterialHeader( IMaterial *pMat )
  904. {
  905. PreviewImageRetVal_t retVal;
  906. bool translucentBaseTexture;
  907. ImageFormat eImageFormat;
  908. int width, height;
  909. retVal = CPreviewImagePropertiesCache::GetPreviewImageProperties( pMat, &width, &height, &eImageFormat, &translucentBaseTexture);
  910. if (retVal == MATERIAL_PREVIEW_IMAGE_BAD)
  911. return false;
  912. m_pMaterial = pMat;
  913. m_pMaterial->IncrementReferenceCount();
  914. m_nWidth = width;
  915. m_nHeight = height;
  916. m_TranslucentBaseTexture = translucentBaseTexture;
  917. // Find the keywords for this material from the vmt file.
  918. bool bFound;
  919. IMaterialVar *pVar = pMat->FindVar("%keywords", &bFound, false);
  920. if (bFound)
  921. {
  922. V_strcpy_safe( m_szKeywords, pVar->GetStringValue() );
  923. // Register the keywords
  924. g_Textures.RegisterTextureKeywords( this );
  925. }
  926. return(true);
  927. }
  928. //-----------------------------------------------------------------------------
  929. // Purpose: Returns the full path of the file from which this material was loaded.
  930. //-----------------------------------------------------------------------------
  931. const char *CMaterial::GetFileName( void ) const
  932. {
  933. return(m_szFileName);
  934. }
  935. //-----------------------------------------------------------------------------
  936. // Purpose:
  937. //-----------------------------------------------------------------------------
  938. bool CMaterial::IsWater( void ) const
  939. {
  940. bool bFound;
  941. IMaterialVar *pVar = m_pMaterial->FindVar( "$surfaceprop", &bFound, false );
  942. if ( bFound )
  943. {
  944. if ( !strcmp( "water", pVar->GetStringValue() ) )
  945. return true;
  946. }
  947. return false;
  948. }
  949. //-----------------------------------------------------------------------------
  950. // Purpose: If the buffer pointer passed in is not NULL, copies the image data
  951. // in RGB format to the buffer
  952. // Input : pImageRGB - Pointer to buffer that receives the image data. If the
  953. // pointer is NULL, no data is copied, only the data size is returned.
  954. // Output : Returns a the size of the RGB image in bytes.
  955. //-----------------------------------------------------------------------------
  956. int CMaterial::GetImageDataRGB( void *pImageRGB )
  957. {
  958. Assert( m_nWidth > 0 );
  959. if ( pImageRGB != NULL )
  960. {
  961. Load();
  962. g_pMaterialImageCache->EnCache( this );
  963. if (!this->HasData())
  964. {
  965. return(NULL);
  966. }
  967. unsigned char *src, *dst;
  968. src = ( unsigned char * )m_pData;
  969. dst = (unsigned char *)pImageRGB;
  970. for( ; src < ( unsigned char * )m_pData + m_nWidth * m_nHeight * 3; src += 3, dst += 3 )
  971. {
  972. dst[0] = src[2];
  973. dst[1] = src[1];
  974. dst[2] = src[0];
  975. }
  976. return( m_nWidth * m_nHeight * 3 );
  977. }
  978. return( m_nWidth * m_nHeight * 3 );
  979. }
  980. //-----------------------------------------------------------------------------
  981. // Purpose: If the buffer pointer passed in is not NULL, copies the image data
  982. // in RGBA format to the buffer
  983. // Input : pImageRGBA - Pointer to buffer that receives the image data. If the
  984. // pointer is NULL, no data is copied, only the data size is returned.
  985. // Output : Returns a the size of the RGBA image in bytes.
  986. //-----------------------------------------------------------------------------
  987. int CMaterial::GetImageDataRGBA(void *pImageRGBA)
  988. {
  989. Assert( m_nWidth > 0 );
  990. if (pImageRGBA != NULL)
  991. {
  992. Load();
  993. g_pMaterialImageCache->EnCache(this);
  994. if (!this->HasData())
  995. {
  996. return(NULL);
  997. }
  998. unsigned char *src, *dst;
  999. src = (unsigned char *)m_pData;
  1000. dst = (unsigned char *)pImageRGBA;
  1001. while (src < (unsigned char *)m_pData + m_nWidth * m_nHeight * 4);
  1002. {
  1003. dst[0] = src[2];
  1004. dst[1] = src[1];
  1005. dst[2] = src[0];
  1006. dst[3] = 0;
  1007. src += 4;
  1008. dst += 4;
  1009. }
  1010. }
  1011. return(m_nWidth * m_nHeight * 4);
  1012. }
  1013. //-----------------------------------------------------------------------------
  1014. // Purpose:
  1015. // Input : size -
  1016. //-----------------------------------------------------------------------------
  1017. void CMaterial::GetSize(SIZE &size) const
  1018. {
  1019. const_cast<CMaterial*>(this)->Load();
  1020. Assert( m_nWidth >= 0 );
  1021. size.cx = m_nWidth;
  1022. size.cy = m_nHeight;
  1023. }
  1024. //-----------------------------------------------------------------------------
  1025. // Purpose: Loads this material's image from disk if it is not already loaded.
  1026. // Output : Returns true on success, false on failure.
  1027. //-----------------------------------------------------------------------------
  1028. bool CMaterial::Load( void )
  1029. {
  1030. LoadMaterial();
  1031. return true;
  1032. }
  1033. //-----------------------------------------------------------------------------
  1034. // cache in the image size only when we need to
  1035. //-----------------------------------------------------------------------------
  1036. int CMaterial::GetImageWidth(void) const
  1037. {
  1038. const_cast<CMaterial*>(this)->Load();
  1039. return(m_nWidth);
  1040. }
  1041. int CMaterial::GetImageHeight(void) const
  1042. {
  1043. const_cast<CMaterial*>(this)->Load();
  1044. return(m_nHeight);
  1045. }
  1046. int CMaterial::GetWidth(void) const
  1047. {
  1048. const_cast<CMaterial*>(this)->Load();
  1049. return(m_nWidth);
  1050. }
  1051. int CMaterial::GetHeight(void) const
  1052. {
  1053. const_cast<CMaterial*>(this)->Load();
  1054. return(m_nHeight);
  1055. }
  1056. float CMaterial::GetDecalScale(void) const
  1057. {
  1058. const_cast<CMaterial*>(this)->Load();
  1059. IMaterialVar *decalScaleVar;
  1060. bool found;
  1061. decalScaleVar = m_pMaterial->FindVar( "$decalScale", &found, false );
  1062. if( !found )
  1063. {
  1064. return 1.0f;
  1065. }
  1066. else
  1067. {
  1068. return decalScaleVar->GetFloatValue();
  1069. }
  1070. }
  1071. //-----------------------------------------------------------------------------
  1072. // Purpose:
  1073. // Output : Returns true on success, false on failure.
  1074. //-----------------------------------------------------------------------------
  1075. bool CMaterial::LoadMaterialImage( void )
  1076. {
  1077. Load();
  1078. if ((!m_nWidth) || (!m_nHeight))
  1079. return(false);
  1080. m_pData = malloc(m_nWidth * m_nHeight * 3);
  1081. Assert(m_pData);
  1082. ImageFormat imageFormat;
  1083. // if( _strnicmp( m_pMaterial->GetName(), "decals", 6 ) == 0 )
  1084. // {
  1085. // imageFormat = IMAGE_FORMAT_BGR888_BLUESCREEN;
  1086. // }
  1087. // else
  1088. {
  1089. imageFormat = IMAGE_FORMAT_BGR888;
  1090. }
  1091. PreviewImageRetVal_t retVal;
  1092. retVal = m_pMaterial->GetPreviewImage( (unsigned char *)m_pData, m_nWidth, m_nHeight, imageFormat );
  1093. return (retVal != MATERIAL_PREVIEW_IMAGE_BAD);
  1094. }
  1095. static void InitMaterialSystemConfig(MaterialSystem_Config_t *pConfig)
  1096. {
  1097. pConfig->bEditMode = true;
  1098. pConfig->m_nAASamples = 0;
  1099. pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_DISABLE_BUMPMAP, true);
  1100. // When I do this the model browser layout is horked...
  1101. // pConfig->SetFlag( MATSYS_VIDCFG_FLAGS_USING_MULTIPLE_WINDOWS, true );
  1102. }
  1103. static char const *s_rt_names[]={"_rt_albedo","_rt_normal","_rt_position","_rt_flags",
  1104. "_rt_accbuf_0","_rt_accbuf_1"};
  1105. ImageFormat s_rt_formats[]={ IMAGE_FORMAT_RGBA32323232F, IMAGE_FORMAT_RGBA32323232F,
  1106. IMAGE_FORMAT_RGBA32323232F, IMAGE_FORMAT_RGBA32323232F,
  1107. IMAGE_FORMAT_RGBA16161616F, IMAGE_FORMAT_RGBA16161616F };
  1108. // ImageFormat s_rt_formats[]={
  1109. // IMAGE_FORMAT_RGBA16161616F, IMAGE_FORMAT_RGBA16161616F,
  1110. // IMAGE_FORMAT_RGBA16161616F, IMAGE_FORMAT_RGBA16161616F,
  1111. // IMAGE_FORMAT_RGBA16161616F, IMAGE_FORMAT_RGBA16161616F,
  1112. // IMAGE_FORMAT_RGBA16161616F, IMAGE_FORMAT_RGBA16161616F };
  1113. static CTextureReference sg_ExtraFP16Targets[NELEMS(s_rt_names)];
  1114. void AllocateLightingPreviewtextures(void)
  1115. {
  1116. static bool bHaveAllocated=false;
  1117. if (! bHaveAllocated )
  1118. {
  1119. bHaveAllocated = true;
  1120. MaterialSystemInterface()->BeginRenderTargetAllocation();
  1121. for(int idx=0;idx<NELEMS(sg_ExtraFP16Targets);idx++)
  1122. sg_ExtraFP16Targets[idx].Init(
  1123. materials->CreateNamedRenderTargetTextureEx2(
  1124. s_rt_names[idx],
  1125. 512, 512, RT_SIZE_DEFAULT, s_rt_formats[idx],
  1126. MATERIAL_RT_DEPTH_SHARED,
  1127. TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT,
  1128. CREATERENDERTARGETFLAGS_HDR )
  1129. );
  1130. // End block in which all render targets should be allocated (kicking off an Alt-Tab type
  1131. // behavior)
  1132. MaterialSystemInterface()->EndRenderTargetAllocation();
  1133. }
  1134. }
  1135. //-----------------------------------------------------------------------------
  1136. // Purpose:
  1137. // Output : Returns true on success, false on failure.
  1138. //-----------------------------------------------------------------------------
  1139. bool CMaterial::Initialize( HWND hwnd )
  1140. {
  1141. // NOTE: This gets set to true later upon creating a 3d view.
  1142. g_materialSystemConfig = materials->GetCurrentConfigForVideoCard();
  1143. InitMaterialSystemConfig( &g_materialSystemConfig );
  1144. // Create a cache for material images (for browsing and uploading to the driver).
  1145. if (g_pMaterialImageCache == NULL)
  1146. {
  1147. g_pMaterialImageCache = new CMaterialImageCache(500);
  1148. if (g_pMaterialImageCache == NULL)
  1149. return false ;
  1150. }
  1151. materials->OverrideConfig( g_materialSystemConfig, false );
  1152. // Set the mode
  1153. // When setting the mode, we need to grab the parent window
  1154. // since that's going to enclose all our little render windows
  1155. g_materialSystemConfig.m_VideoMode.m_Width = g_materialSystemConfig.m_VideoMode.m_Height = 0;
  1156. g_materialSystemConfig.m_VideoMode.m_Format = IMAGE_FORMAT_BGRA8888;
  1157. g_materialSystemConfig.m_VideoMode.m_RefreshRate = 0;
  1158. g_materialSystemConfig.SetFlag( MATSYS_VIDCFG_FLAGS_WINDOWED, true );
  1159. g_materialSystemConfig.SetFlag( MATSYS_VIDCFG_FLAGS_RESIZING, true );
  1160. if (!MaterialSystemInterface()->SetMode( hwnd, g_materialSystemConfig ) )
  1161. return false;
  1162. return true;
  1163. }
  1164. //-----------------------------------------------------------------------------
  1165. // Purpose: Restores the material system to an uninitialized state.
  1166. //-----------------------------------------------------------------------------
  1167. void CMaterial::ShutDown(void)
  1168. {
  1169. for ( int i = 0; i < NELEMS(sg_ExtraFP16Targets); ++i )
  1170. {
  1171. sg_ExtraFP16Targets[i].Shutdown();
  1172. }
  1173. if (materials != NULL)
  1174. {
  1175. materials->UncacheAllMaterials();
  1176. }
  1177. delete g_pMaterialImageCache;
  1178. g_pMaterialImageCache = NULL;
  1179. }