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.

1675 lines
50 KiB

  1. //===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include <stdlib.h>
  7. #ifndef _PS3
  8. #include <malloc.h>
  9. #endif
  10. #include "materialsystem_global.h"
  11. #include "string.h"
  12. #include "shaderapi/ishaderapi.h"
  13. #include "materialsystem/materialsystem_config.h"
  14. #include "IHardwareConfigInternal.h"
  15. #include "texturemanager.h"
  16. #include "materialsystem/imaterialvar.h"
  17. #include "materialsystem/IColorCorrection.h"
  18. #include "tier1/strtools.h"
  19. #include "utlvector.h"
  20. #include "utldict.h"
  21. #include "itextureinternal.h"
  22. #include "vtf/vtf.h"
  23. #include "pixelwriter.h"
  24. #include "basetypes.h"
  25. #include "utlbuffer.h"
  26. #include "filesystem.h"
  27. #include "materialsystem/imesh.h"
  28. #include "materialsystem/ishaderapi.h"
  29. #include "vstdlib/random.h"
  30. #include "imorphinternal.h"
  31. #include "isubdinternal.h"
  32. #include "tier1/utlrbtree.h"
  33. #include "ctype.h"
  34. #include "tier0/icommandline.h"
  35. #include "filesystem/IQueuedLoader.h"
  36. // Need lightmaps access here
  37. #ifndef _PS3
  38. #define MATSYS_INTERNAL
  39. #endif
  40. #include "cmatlightmaps.h"
  41. #include "cmaterialsystem.h"
  42. #ifndef _PS3
  43. #undef MATSYS_INTERNAL
  44. #endif
  45. #include "tier0/memdbgon.h"
  46. #define ERROR_TEXTURE_SIZE 32
  47. #define WHITE_TEXTURE_SIZE 1
  48. #define BLACK_TEXTURE_SIZE 1
  49. #define GREY_TEXTURE_SIZE 1
  50. #define NORMALIZATION_CUBEMAP_SIZE 32
  51. #define SSAO_NOISE_TEXTURE_SIZE 32
  52. #define ERROR_TEXTURE_IS_SOLID
  53. //-----------------------------------------------------------------------------
  54. //
  55. // Various procedural texture regeneration classes
  56. //
  57. //-----------------------------------------------------------------------------
  58. //-----------------------------------------------------------------------------
  59. // Creates a checkerboard texture
  60. //-----------------------------------------------------------------------------
  61. class CCheckerboardTexture : public ITextureRegenerator
  62. {
  63. public:
  64. CCheckerboardTexture( int nCheckerSize, color32 color1, color32 color2 ) :
  65. m_nCheckerSize( nCheckerSize ), m_Color1(color1), m_Color2(color2)
  66. {
  67. }
  68. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
  69. {
  70. for (int iFrame = 0; iFrame < pVTFTexture->FrameCount(); ++iFrame )
  71. {
  72. for (int iFace = 0; iFace < pVTFTexture->FaceCount(); ++iFace )
  73. {
  74. int nWidth = pVTFTexture->Width();
  75. int nHeight = pVTFTexture->Height();
  76. int nDepth = pVTFTexture->Depth();
  77. for (int z = 0; z < nDepth; ++z)
  78. {
  79. // Fill mip 0 with a checkerboard
  80. CPixelWriter pixelWriter;
  81. pixelWriter.SetPixelMemory( pVTFTexture->Format(),
  82. pVTFTexture->ImageData( iFrame, iFace, 0, 0, 0, z ), pVTFTexture->RowSizeInBytes( 0 ) );
  83. for (int y = 0; y < nHeight; ++y)
  84. {
  85. pixelWriter.Seek( 0, y );
  86. for (int x = 0; x < nWidth; ++x)
  87. {
  88. if ( ((x & m_nCheckerSize) ^ (y & m_nCheckerSize)) ^ (z & m_nCheckerSize) )
  89. {
  90. pixelWriter.WritePixel( m_Color1.r, m_Color1.g, m_Color1.b, m_Color1.a );
  91. }
  92. else
  93. {
  94. pixelWriter.WritePixel( m_Color2.r, m_Color2.g, m_Color2.b, m_Color2.a );
  95. }
  96. }
  97. }
  98. }
  99. }
  100. }
  101. }
  102. virtual void Release()
  103. {
  104. delete this;
  105. }
  106. private:
  107. int m_nCheckerSize;
  108. color32 m_Color1;
  109. color32 m_Color2;
  110. };
  111. static void CreateCheckerboardTexture( ITextureInternal *pTexture, int nCheckerSize, color32 color1, color32 color2 )
  112. {
  113. ITextureRegenerator *pRegen = new CCheckerboardTexture( nCheckerSize, color1, color2 );
  114. pTexture->SetTextureRegenerator( pRegen );
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Creates a solid texture
  118. //-----------------------------------------------------------------------------
  119. class CSolidTexture : public ITextureRegenerator
  120. {
  121. public:
  122. CSolidTexture( color32 color ) : m_Color(color)
  123. {
  124. }
  125. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
  126. {
  127. int nMipCount = pTexture->IsMipmapped() ? pVTFTexture->MipCount() : 1;
  128. for (int iFrame = 0; iFrame < pVTFTexture->FrameCount(); ++iFrame )
  129. {
  130. for (int iFace = 0; iFace < pVTFTexture->FaceCount(); ++iFace )
  131. {
  132. for (int iMip = 0; iMip < nMipCount; ++iMip )
  133. {
  134. int nWidth, nHeight, nDepth;
  135. pVTFTexture->ComputeMipLevelDimensions( iMip, &nWidth, &nHeight, &nDepth );
  136. for (int z = 0; z < nDepth; ++z)
  137. {
  138. CPixelWriter pixelWriter;
  139. pixelWriter.SetPixelMemory( pVTFTexture->Format(),
  140. pVTFTexture->ImageData( iFrame, iFace, iMip, 0, 0, z ), pVTFTexture->RowSizeInBytes( iMip ) );
  141. for (int y = 0; y < nHeight; ++y)
  142. {
  143. pixelWriter.Seek( 0, y );
  144. for (int x = 0; x < nWidth; ++x)
  145. {
  146. pixelWriter.WritePixel( m_Color.r, m_Color.g, m_Color.b, m_Color.a );
  147. }
  148. }
  149. }
  150. }
  151. }
  152. }
  153. }
  154. virtual void Release()
  155. {
  156. delete this;
  157. }
  158. private:
  159. color32 m_Color;
  160. };
  161. static void CreateSolidTexture( ITextureInternal *pTexture, color32 color )
  162. {
  163. ITextureRegenerator *pRegen = new CSolidTexture( color );
  164. pTexture->SetTextureRegenerator( pRegen );
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Creates a normalization cubemap texture
  168. //-----------------------------------------------------------------------------
  169. class CNormalizationCubemap : public ITextureRegenerator
  170. {
  171. public:
  172. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
  173. {
  174. // Normalization cubemap doesn't make sense on low-end hardware
  175. // So we won't construct a spheremap out of this
  176. CPixelWriter pixelWriter;
  177. Vector direction;
  178. for (int iFace = 0; iFace < 6; ++iFace)
  179. {
  180. pixelWriter.SetPixelMemory( pVTFTexture->Format(),
  181. pVTFTexture->ImageData( 0, iFace, 0 ), pVTFTexture->RowSizeInBytes( 0 ) );
  182. int nWidth = pVTFTexture->Width();
  183. int nHeight = pVTFTexture->Height();
  184. float flInvWidth = 2.0f / (float)(nWidth-1);
  185. float flInvHeight = 2.0f / (float)(nHeight-1);
  186. for (int y = 0; y < nHeight; ++y)
  187. {
  188. float v = y * flInvHeight - 1.0f;
  189. pixelWriter.Seek( 0, y );
  190. for (int x = 0; x < nWidth; ++x)
  191. {
  192. float u = x * flInvWidth - 1.0f;
  193. float oow = 1.0f / sqrt( 1.0f + u*u + v*v );
  194. int ix = (int)(255.0f * 0.5f * (u*oow + 1.0f) + 0.5f);
  195. ix = clamp( ix, 0, 255 );
  196. int iy = (int)(255.0f * 0.5f * (v*oow + 1.0f) + 0.5f);
  197. iy = clamp( iy, 0, 255 );
  198. int iz = (int)(255.0f * 0.5f * (oow + 1.0f) + 0.5f);
  199. iz = clamp( iz, 0, 255 );
  200. switch (iFace)
  201. {
  202. case CUBEMAP_FACE_RIGHT:
  203. pixelWriter.WritePixel( iz, 255 - iy, 255 - ix, 255 );
  204. break;
  205. case CUBEMAP_FACE_LEFT:
  206. pixelWriter.WritePixel( 255 - iz, 255 - iy, ix, 255 );
  207. break;
  208. case CUBEMAP_FACE_BACK:
  209. pixelWriter.WritePixel( ix, iz, iy, 255 );
  210. break;
  211. case CUBEMAP_FACE_FRONT:
  212. pixelWriter.WritePixel( ix, 255 - iz, 255 - iy, 255 );
  213. break;
  214. case CUBEMAP_FACE_UP:
  215. pixelWriter.WritePixel( ix, 255 - iy, iz, 255 );
  216. break;
  217. case CUBEMAP_FACE_DOWN:
  218. pixelWriter.WritePixel( 255 - ix, 255 - iy, 255 - iz, 255 );
  219. break;
  220. default:
  221. break;
  222. }
  223. }
  224. }
  225. }
  226. }
  227. // NOTE: The normalization cubemap regenerator is stateless
  228. // so there's no need to allocate + deallocate them
  229. virtual void Release() {}
  230. };
  231. //-----------------------------------------------------------------------------
  232. // Creates a normalization cubemap texture
  233. //-----------------------------------------------------------------------------
  234. class CSignedNormalizationCubemap : public ITextureRegenerator
  235. {
  236. public:
  237. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
  238. {
  239. // Normalization cubemap doesn't make sense on low-end hardware
  240. // So we won't construct a spheremap out of this
  241. CPixelWriter pixelWriter;
  242. Vector direction;
  243. for (int iFace = 0; iFace < 6; ++iFace)
  244. {
  245. pixelWriter.SetPixelMemory( pVTFTexture->Format(),
  246. pVTFTexture->ImageData( 0, iFace, 0 ), pVTFTexture->RowSizeInBytes( 0 ) );
  247. int nWidth = pVTFTexture->Width();
  248. int nHeight = pVTFTexture->Height();
  249. float flInvWidth = 2.0f / (float)(nWidth-1);
  250. float flInvHeight = 2.0f / (float)(nHeight-1);
  251. for (int y = 0; y < nHeight; ++y)
  252. {
  253. float v = y * flInvHeight - 1.0f;
  254. pixelWriter.Seek( 0, y );
  255. for (int x = 0; x < nWidth; ++x)
  256. {
  257. float u = x * flInvWidth - 1.0f;
  258. float oow = 1.0f / sqrt( 1.0f + u*u + v*v );
  259. #if defined( DX_TO_GL_ABSTRACTION ) && !defined( _PS3 )
  260. float flX = (255.0f * 0.5 * (u*oow + 1.0f) + 0.5f);
  261. float flY = (255.0f * 0.5 * (v*oow + 1.0f) + 0.5f);
  262. float flZ = (255.0f * 0.5 * (oow + 1.0f) + 0.5f);
  263. switch (iFace)
  264. {
  265. case CUBEMAP_FACE_RIGHT:
  266. flX = 255.0f - flX;
  267. flY = 255.0f - flY;
  268. break;
  269. case CUBEMAP_FACE_LEFT:
  270. flY = 255.0f - flY;
  271. flZ = 255.0f - flZ;
  272. break;
  273. case CUBEMAP_FACE_BACK:
  274. break;
  275. case CUBEMAP_FACE_FRONT:
  276. flY = 255.0f - flY;
  277. flZ = 255.0f - flZ;
  278. break;
  279. case CUBEMAP_FACE_UP:
  280. flY = 255.0f - flY;
  281. break;
  282. case CUBEMAP_FACE_DOWN:
  283. flX = 255.0f - flX;
  284. flY = 255.0f - flY;
  285. flZ = 255.0f - flZ;
  286. break;
  287. default:
  288. break;
  289. }
  290. flX -= 128.0f;
  291. flY -= 128.0f;
  292. flZ -= 128.0f;
  293. flX /= 128.0f;
  294. flY /= 128.0f;
  295. flZ /= 128.0f;
  296. switch ( iFace )
  297. {
  298. case CUBEMAP_FACE_RIGHT:
  299. pixelWriter.WritePixelF( flZ, flY, flX, 0.0f );
  300. break;
  301. case CUBEMAP_FACE_LEFT:
  302. pixelWriter.WritePixelF( flZ, flY, flX, 0.0f );
  303. break;
  304. case CUBEMAP_FACE_BACK:
  305. pixelWriter.WritePixelF( flX, flZ, flY, 0.0f );
  306. break;
  307. case CUBEMAP_FACE_FRONT:
  308. pixelWriter.WritePixelF( flX, flZ, flY, 0.0f );
  309. break;
  310. case CUBEMAP_FACE_UP:
  311. pixelWriter.WritePixelF( flX, flY, flZ, 0.0f );
  312. break;
  313. case CUBEMAP_FACE_DOWN:
  314. pixelWriter.WritePixelF( flX, flY, flZ, 0.0f );
  315. break;
  316. default:
  317. break;
  318. }
  319. #else
  320. int ix = (int)(255 * 0.5 * (u*oow + 1.0f) + 0.5f);
  321. ix = clamp( ix, 0, 255 );
  322. int iy = (int)(255 * 0.5 * (v*oow + 1.0f) + 0.5f);
  323. iy = clamp( iy, 0, 255 );
  324. int iz = (int)(255 * 0.5 * (oow + 1.0f) + 0.5f);
  325. iz = clamp( iz, 0, 255 );
  326. switch (iFace)
  327. {
  328. case CUBEMAP_FACE_RIGHT:
  329. ix = 255 - ix;
  330. iy = 255 - iy;
  331. break;
  332. case CUBEMAP_FACE_LEFT:
  333. iy = 255 - iy;
  334. iz = 255 - iz;
  335. break;
  336. case CUBEMAP_FACE_BACK:
  337. break;
  338. case CUBEMAP_FACE_FRONT:
  339. iy = 255 - iy;
  340. iz = 255 - iz;
  341. break;
  342. case CUBEMAP_FACE_UP:
  343. iy = 255 - iy;
  344. break;
  345. case CUBEMAP_FACE_DOWN:
  346. ix = 255 - ix;
  347. iy = 255 - iy;
  348. iz = 255 - iz;
  349. break;
  350. default:
  351. break;
  352. }
  353. ix -= 128;
  354. iy -= 128;
  355. iz -= 128;
  356. Assert( ix >= -128 && ix <= 127 );
  357. Assert( iy >= -128 && iy <= 127 );
  358. Assert( iz >= -128 && iz <= 127 );
  359. switch (iFace)
  360. {
  361. case CUBEMAP_FACE_RIGHT:
  362. // correct
  363. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  364. pixelWriter.WritePixelSigned( iz, iy, ix, 0 );
  365. break;
  366. case CUBEMAP_FACE_LEFT:
  367. // correct
  368. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  369. pixelWriter.WritePixelSigned( iz, iy, ix, 0 );
  370. break;
  371. case CUBEMAP_FACE_BACK:
  372. // wrong
  373. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  374. pixelWriter.WritePixelSigned( ix, iz, iy, 0 );
  375. // pixelWriter.WritePixelSigned( -127, -127, 127, 0 );
  376. break;
  377. case CUBEMAP_FACE_FRONT:
  378. // wrong
  379. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  380. pixelWriter.WritePixelSigned( ix, iz, iy, 0 );
  381. break;
  382. case CUBEMAP_FACE_UP:
  383. // correct
  384. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  385. pixelWriter.WritePixelSigned( ix, iy, iz, 0 );
  386. break;
  387. case CUBEMAP_FACE_DOWN:
  388. // correct
  389. // pixelWriter.WritePixelSigned( -128, -128, -128, 0 );
  390. pixelWriter.WritePixelSigned( ix, iy, iz, 0 );
  391. break;
  392. default:
  393. break;
  394. }
  395. #endif
  396. } // x
  397. } // y
  398. } // iFace
  399. }
  400. // NOTE: The normalization cubemap regenerator is stateless
  401. // so there's no need to allocate + deallocate them
  402. virtual void Release() {}
  403. };
  404. static void CreateNormalizationCubemap( ITextureInternal *pTexture )
  405. {
  406. // NOTE: The normalization cubemap regenerator is stateless
  407. // so there's no need to allocate + deallocate them
  408. static CNormalizationCubemap s_NormalizationCubemap;
  409. pTexture->SetTextureRegenerator( &s_NormalizationCubemap );
  410. }
  411. static void CreateSignedNormalizationCubemap( ITextureInternal *pTexture )
  412. {
  413. // NOTE: The normalization cubemap regenerator is stateless
  414. // so there's no need to allocate + deallocate them
  415. static CSignedNormalizationCubemap s_SignedNormalizationCubemap;
  416. pTexture->SetTextureRegenerator( &s_SignedNormalizationCubemap );
  417. }
  418. /*
  419. static void CreateSSAONoiseTexture( ITextureInternal *pTexture )
  420. {
  421. // NOTE: This texture regenerator is stateless so there's no need to allocate + deallocate
  422. static CSSAONoiseMap s_SSAONoiseMap;
  423. pTexture->SetTextureRegenerator( &s_SSAONoiseMap );
  424. }
  425. */
  426. //-----------------------------------------------------------------------------
  427. // Implementation of the texture manager
  428. //-----------------------------------------------------------------------------
  429. class CTextureManager : public ITextureManager
  430. {
  431. public:
  432. CTextureManager( void );
  433. // Initialization + shutdown
  434. virtual void Init( int nFlags );
  435. virtual void Shutdown();
  436. virtual void AllocateStandardRenderTargets( );
  437. virtual void FreeStandardRenderTargets();
  438. virtual void CacheExternalStandardRenderTargets();
  439. virtual ITextureInternal *CreateProceduralTexture( const char *pTextureName, const char *pTextureGroupName, int w, int h, int d, ImageFormat fmt, int nFlags );
  440. virtual ITextureInternal *FindOrLoadTexture( const char *textureName, const char *pTextureGroupName, int nAdditionalCreationFlags = 0 );
  441. virtual bool IsTextureLoaded( const char *pTextureName );
  442. virtual bool GetTextureInformation( char const *szTextureName, MaterialTextureInfo_t &info );
  443. virtual void AddTextureAlias( const char *pAlias, const char *pRealName );
  444. virtual void RemoveTextureAlias( const char *pAlias );
  445. virtual void SetExcludedTextures( const char *pScriptName, bool bUsingWeaponModelCache );
  446. virtual void UpdateExcludedTextures();
  447. virtual void ClearForceExcludes();
  448. virtual void ResetTextureFilteringState();
  449. void ReloadTextures( void );
  450. // These are used when we lose our video memory due to a mode switch etc
  451. void ReleaseTextures( bool bReleaseManaged = true );
  452. void RestoreNonRenderTargetTextures( void );
  453. void RestoreRenderTargets( void );
  454. // delete any texture that has a refcount <= 0
  455. void RemoveUnusedTextures( void );
  456. void DebugPrintUsedTextures( void );
  457. // Request a texture ID
  458. virtual int RequestNextTextureID();
  459. // Get at a couple standard textures
  460. virtual ITextureInternal *ErrorTexture();
  461. virtual ITextureInternal *NormalizationCubemap();
  462. virtual ITextureInternal *SignedNormalizationCubemap();
  463. virtual ITextureInternal *ShadowNoise2D();
  464. virtual ITextureInternal *SSAONoise2D();
  465. virtual ITextureInternal *IdentityLightWarp();
  466. virtual ITextureInternal *ColorCorrectionTexture( int i );
  467. virtual ITextureInternal *FullFrameDepthTexture();
  468. virtual ITextureInternal *StereoParamTexture();
  469. // Generates an error texture pattern
  470. virtual void GenerateErrorTexture( ITexture *pTexture, IVTFTexture *pVTFTexture );
  471. // Updates the color correction state
  472. virtual void SetColorCorrectionTexture( int i, ITextureInternal *pTexture );
  473. virtual void ForceAllTexturesIntoHardware( void );
  474. virtual ITextureInternal *CreateRenderTargetTexture(
  475. const char *pRTName, // NULL for auto-generated name
  476. int w,
  477. int h,
  478. RenderTargetSizeMode_t sizeMode,
  479. ImageFormat fmt,
  480. RenderTargetType_t type,
  481. unsigned int textureFlags,
  482. unsigned int renderTargetFlags,
  483. bool bMultipleTargets );
  484. virtual void RemoveTexture( ITextureInternal *pTexture );
  485. virtual void ReloadFilesInList( IFileList *pFilesToReload );
  486. // start with -1, list terminates with -1
  487. virtual int FindNext( int iIndex, ITextureInternal **ppTexture );
  488. virtual void ReleaseTempRenderTargetBits( void );
  489. protected:
  490. ITextureInternal *FindTexture( const char *textureName );
  491. ITextureInternal *LoadTexture( const char *textureName, const char *pTextureGroupName, int nAdditionalCreationFlags = 0 );
  492. // Restores a single texture
  493. void RestoreTexture( ITextureInternal* pTex );
  494. CUtlDict< ITextureInternal *, unsigned short > m_TextureList;
  495. CUtlDict< const char *, unsigned short > m_TextureAliases;
  496. CUtlDict< int, unsigned short > m_TextureExcludes;
  497. bool m_bUsingWeaponModelCache;
  498. int m_iNextTexID;
  499. int m_nFlags;
  500. ITextureInternal *m_pErrorTexture;
  501. ITextureInternal *m_pBlackTexture;
  502. ITextureInternal *m_pWhiteTexture;
  503. ITextureInternal *m_pGreyTexture;
  504. ITextureInternal *m_pGreyAlphaZeroTexture;
  505. ITextureInternal *m_pNormalizationCubemap;
  506. ITextureInternal *m_pFullScreenTexture;
  507. ITextureInternal *m_pSignedNormalizationCubemap;
  508. ITextureInternal *m_pShadowNoise2D;
  509. ITextureInternal *m_pSSAONoise2D;
  510. ITextureInternal *m_pIdentityLightWarp;
  511. ITextureInternal *m_pColorCorrectionTextures[ COLOR_CORRECTION_MAX_TEXTURES ];
  512. ITextureInternal *m_pFullScreenDepthTexture;
  513. ITextureInternal *m_pStereoParamTexture;
  514. // Used to generate various error texture patterns when necessary
  515. #ifdef ERROR_TEXTURE_IS_SOLID
  516. CSolidTexture *m_pErrorRegen;
  517. #else
  518. CCheckerboardTexture *m_pErrorRegen;
  519. #endif
  520. private:
  521. bool ParseTextureExcludeScript( const char *pScriptName );
  522. };
  523. //-----------------------------------------------------------------------------
  524. // Singleton instance
  525. //-----------------------------------------------------------------------------
  526. static CTextureManager s_TextureManager;
  527. ITextureManager *g_pTextureManager = &s_TextureManager;
  528. //-----------------------------------------------------------------------------
  529. // Texture manager
  530. //-----------------------------------------------------------------------------
  531. CTextureManager::CTextureManager( void ) : m_TextureList( true ), m_TextureAliases( true ), m_TextureExcludes( true )
  532. {
  533. m_pErrorTexture = NULL;
  534. m_pBlackTexture = NULL;
  535. m_pWhiteTexture = NULL;
  536. m_pGreyTexture = NULL;
  537. m_pGreyAlphaZeroTexture = NULL;
  538. m_pNormalizationCubemap = NULL;
  539. m_pErrorRegen = NULL;
  540. m_pFullScreenTexture = NULL;
  541. m_pSignedNormalizationCubemap = NULL;
  542. m_pShadowNoise2D = NULL;
  543. m_pSSAONoise2D = NULL;
  544. m_pIdentityLightWarp = NULL;
  545. m_pFullScreenDepthTexture = NULL;
  546. m_pStereoParamTexture = NULL;
  547. m_bUsingWeaponModelCache = false;
  548. }
  549. //-----------------------------------------------------------------------------
  550. // Initialization + shutdown
  551. //-----------------------------------------------------------------------------
  552. void CTextureManager::Init( int nFlags )
  553. {
  554. m_nFlags = nFlags;
  555. color32 color, color2;
  556. m_iNextTexID = 4096;
  557. // setup the checkerboard generator for failed texture loading
  558. color.r = color.g = color.b = 0; color.a = 128;
  559. color2.r = color2.b = color2.a = 255; color2.g = 0;
  560. #ifdef ERROR_TEXTURE_IS_SOLID
  561. color32 color_black; color_black.r = color_black.g = color_black.b = 0; color_black.a = 255;
  562. m_pErrorRegen = new CSolidTexture( color_black );
  563. #else
  564. m_pErrorRegen = new CCheckerboardTexture( 4, color, color2 );
  565. #endif
  566. // Create an error texture
  567. m_pErrorTexture = CreateProceduralTexture( "error", TEXTURE_GROUP_OTHER,
  568. ERROR_TEXTURE_SIZE, ERROR_TEXTURE_SIZE, 1, IMAGE_FORMAT_BGRA8888, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_SRGB );
  569. #ifdef ERROR_TEXTURE_IS_SOLID
  570. CreateSolidTexture( m_pErrorTexture, color_black );
  571. #else
  572. CreateCheckerboardTexture( m_pErrorTexture, 4, color, color2 );
  573. #endif
  574. // Create a white texture
  575. m_pWhiteTexture = CreateProceduralTexture( "white", TEXTURE_GROUP_OTHER,
  576. WHITE_TEXTURE_SIZE, WHITE_TEXTURE_SIZE, 1, IMAGE_FORMAT_BGRX8888, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_SRGB );
  577. color.r = color.g = color.b = color.a = 255;
  578. CreateSolidTexture( m_pWhiteTexture, color );
  579. // Create a black texture
  580. m_pBlackTexture = CreateProceduralTexture( "black", TEXTURE_GROUP_OTHER,
  581. BLACK_TEXTURE_SIZE, BLACK_TEXTURE_SIZE, 1, IMAGE_FORMAT_BGRX8888, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_SRGB );
  582. color.r = color.g = color.b = 0;
  583. CreateSolidTexture( m_pBlackTexture, color );
  584. // Create a grey texture
  585. m_pGreyTexture = CreateProceduralTexture( "grey", TEXTURE_GROUP_OTHER,
  586. GREY_TEXTURE_SIZE, GREY_TEXTURE_SIZE, 1, IMAGE_FORMAT_BGRA8888, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_SRGB );
  587. color.r = color.g = color.b = 128;
  588. color.a = 255;
  589. CreateSolidTexture( m_pGreyTexture, color );
  590. // Create a grey texture
  591. m_pGreyAlphaZeroTexture = CreateProceduralTexture( "greyalphazero", TEXTURE_GROUP_OTHER,
  592. GREY_TEXTURE_SIZE, GREY_TEXTURE_SIZE, 1, IMAGE_FORMAT_BGRA8888, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_SRGB );
  593. color.r = color.g = color.b = 128;
  594. color.a = 0;
  595. CreateSolidTexture( m_pGreyAlphaZeroTexture, color );
  596. #ifdef IS_WINDOWS_PC
  597. if ( g_pShaderAPI->IsStereoSupported() )
  598. {
  599. // TODO: Call CreateStereoTexture, which should make a similar call onto the ShaderAPI
  600. int stereoWidth = 8;
  601. int stereoHeight = 1;
  602. m_pStereoParamTexture = CreateProceduralTexture( "stereoparam", TEXTURE_GROUP_OTHER,
  603. stereoWidth, stereoHeight, 1, IMAGE_FORMAT_R32F, TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_POINTSAMPLE | TEXTUREFLAGS_DEFAULT_POOL);
  604. }
  605. #endif
  606. if ( HardwareConfig()->GetMaxDXSupportLevel() >= 80 )
  607. {
  608. // Create a normalization cubemap
  609. m_pNormalizationCubemap = CreateProceduralTexture( "normalize", TEXTURE_GROUP_CUBE_MAP,
  610. NORMALIZATION_CUBEMAP_SIZE, NORMALIZATION_CUBEMAP_SIZE, 1, IMAGE_FORMAT_BGRX8888,
  611. TEXTUREFLAGS_ENVMAP | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_SINGLECOPY |
  612. TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_CLAMPU );
  613. CreateNormalizationCubemap( m_pNormalizationCubemap );
  614. }
  615. if ( HardwareConfig()->GetMaxDXSupportLevel() >= 90 )
  616. {
  617. // On MacOS, we have poor format support, so we ask for signed float
  618. ImageFormat fmt = IsOpenGL() ? IMAGE_FORMAT_RGBA16161616F : IMAGE_FORMAT_UVWQ8888;
  619. int nFlags = TEXTUREFLAGS_ENVMAP | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_CLAMPU;
  620. nFlags |= IsOSXOpenGL() ? TEXTUREFLAGS_POINTSAMPLE : 0; // JasonM - ridiculous hack around R500 lameness...we never use this texture on MacOS anyways (right?)
  621. // Create a normalization cubemap
  622. m_pSignedNormalizationCubemap = CreateProceduralTexture( "normalizesigned", TEXTURE_GROUP_CUBE_MAP,
  623. NORMALIZATION_CUBEMAP_SIZE, NORMALIZATION_CUBEMAP_SIZE, 1, fmt, nFlags );
  624. CreateSignedNormalizationCubemap( m_pSignedNormalizationCubemap );
  625. m_pIdentityLightWarp = FindOrLoadTexture( "dev/IdentityLightWarp", TEXTURE_GROUP_OTHER );
  626. m_pIdentityLightWarp->IncrementReferenceCount();
  627. }
  628. // For safety, always load the shadow noise 2D texture even on 9.0 hardware. (It's not needed in Portal2's flashlight shaders, but I'm leaving it in
  629. // because it's referenced all over the place and so the older L4D-style flashlight shadows can be easily re-enabled if needed.)
  630. m_pShadowNoise2D = FindOrLoadTexture( "engine/NormalizedRandomDirections2D", TEXTURE_GROUP_OTHER );
  631. m_pShadowNoise2D->IncrementReferenceCount();
  632. if ( HardwareConfig()->GetMaxDXSupportLevel() >= 92 )
  633. {
  634. m_pSSAONoise2D = FindOrLoadTexture( "engine/SSAOReflectionVectors", TEXTURE_GROUP_OTHER );
  635. m_pSSAONoise2D->IncrementReferenceCount();
  636. }
  637. }
  638. void CTextureManager::Shutdown()
  639. {
  640. FreeStandardRenderTargets();
  641. // These checks added because it's possible for shutdown to be called before the material system is
  642. // fully initialized.
  643. if ( m_pWhiteTexture )
  644. {
  645. m_pWhiteTexture->DecrementReferenceCount();
  646. m_pWhiteTexture = NULL;
  647. }
  648. if ( m_pBlackTexture )
  649. {
  650. m_pBlackTexture->DecrementReferenceCount();
  651. m_pBlackTexture = NULL;
  652. }
  653. if ( m_pGreyTexture )
  654. {
  655. m_pGreyTexture->DecrementReferenceCount();
  656. m_pGreyTexture = NULL;
  657. }
  658. if ( m_pGreyAlphaZeroTexture )
  659. {
  660. m_pGreyAlphaZeroTexture->DecrementReferenceCount();
  661. m_pGreyAlphaZeroTexture = NULL;
  662. }
  663. if ( m_pNormalizationCubemap )
  664. {
  665. m_pNormalizationCubemap->DecrementReferenceCount();
  666. m_pNormalizationCubemap = NULL;
  667. }
  668. if ( m_pSignedNormalizationCubemap )
  669. {
  670. m_pSignedNormalizationCubemap->DecrementReferenceCount();
  671. m_pSignedNormalizationCubemap = NULL;
  672. }
  673. if ( m_pShadowNoise2D )
  674. {
  675. m_pShadowNoise2D->DecrementReferenceCount();
  676. m_pShadowNoise2D = NULL;
  677. }
  678. if ( m_pSSAONoise2D )
  679. {
  680. m_pSSAONoise2D->DecrementReferenceCount();
  681. m_pSSAONoise2D = NULL;
  682. }
  683. if ( m_pIdentityLightWarp )
  684. {
  685. m_pIdentityLightWarp->DecrementReferenceCount();
  686. m_pIdentityLightWarp = NULL;
  687. }
  688. if ( m_pErrorTexture )
  689. {
  690. m_pErrorTexture->DecrementReferenceCount();
  691. m_pErrorTexture = NULL;
  692. }
  693. if ( m_pStereoParamTexture )
  694. {
  695. m_pStereoParamTexture->DecrementReferenceCount();
  696. m_pStereoParamTexture = NULL;
  697. }
  698. ReleaseTextures();
  699. if ( m_pErrorRegen )
  700. {
  701. m_pErrorRegen->Release();
  702. m_pErrorRegen = NULL;
  703. }
  704. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  705. {
  706. ITextureInternal::Destroy( m_TextureList[i] );
  707. }
  708. m_TextureList.RemoveAll();
  709. for( int i = m_TextureAliases.First(); i != m_TextureAliases.InvalidIndex(); i = m_TextureAliases.Next( i ) )
  710. {
  711. delete []m_TextureAliases[i];
  712. }
  713. m_TextureAliases.RemoveAll();
  714. m_TextureExcludes.RemoveAll();
  715. }
  716. //-----------------------------------------------------------------------------
  717. // Allocate, free standard render target textures
  718. //-----------------------------------------------------------------------------
  719. void CTextureManager::AllocateStandardRenderTargets( )
  720. {
  721. bool bAllocateFullscreenTexture = ( m_nFlags & MATERIAL_INIT_ALLOCATE_FULLSCREEN_TEXTURE ) != 0;
  722. bool bAllocateMorphAccumTexture = g_pMorphMgr->ShouldAllocateScratchTextures();
  723. if ( IsPC() && ( bAllocateFullscreenTexture || bAllocateMorphAccumTexture ) )
  724. {
  725. MaterialSystem()->BeginRenderTargetAllocation();
  726. // A offscreen render target which is the size + format of the back buffer (*not* HDR format!)
  727. if ( bAllocateFullscreenTexture )
  728. {
  729. // Ensure the _rt_FullScreen RT is given its own depth-stencil surface (RENDER_TARGET_WITH_DEPTH vs. RENDER_TARGET) on the PC/Mac to work around store rendering glitches between the bot panel and the rest of the store UI.
  730. m_pFullScreenTexture = CreateRenderTargetTexture( "_rt_FullScreen", 1, 1, RT_SIZE_FULL_FRAME_BUFFER_ROUNDED_UP, MaterialSystem()->GetBackBufferFormat(), RENDER_TARGET_WITH_DEPTH, TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT, 0, false );
  731. m_pFullScreenTexture->IncrementReferenceCount();
  732. }
  733. // This texture is the one we accumulate morph deltas into
  734. if ( bAllocateMorphAccumTexture )
  735. {
  736. g_pMorphMgr->AllocateScratchTextures();
  737. g_pMorphMgr->AllocateMaterials();
  738. }
  739. MaterialSystem()->EndRenderTargetAllocation();
  740. }
  741. }
  742. void CTextureManager::FreeStandardRenderTargets()
  743. {
  744. if ( m_pFullScreenTexture )
  745. {
  746. m_pFullScreenTexture->DecrementReferenceCount();
  747. m_pFullScreenTexture = NULL;
  748. }
  749. g_pMorphMgr->FreeMaterials();
  750. g_pMorphMgr->FreeScratchTextures();
  751. #if defined( FEATURE_SUBD_SUPPORT )
  752. g_pSubDMgr->FreeTextures();
  753. #endif
  754. }
  755. void CTextureManager::CacheExternalStandardRenderTargets()
  756. {
  757. m_pFullScreenDepthTexture = FindTexture( "_rt_FullFrameDepth" ); //created/destroyed in engine/matsys_interface.cpp to properly track hdr changes
  758. }
  759. //-----------------------------------------------------------------------------
  760. // Generates an error texture pattern
  761. //-----------------------------------------------------------------------------
  762. void CTextureManager::GenerateErrorTexture( ITexture *pTexture, IVTFTexture *pVTFTexture )
  763. {
  764. m_pErrorRegen->RegenerateTextureBits( pTexture, pVTFTexture, NULL );
  765. }
  766. //-----------------------------------------------------------------------------
  767. // Updates the color correction state
  768. //-----------------------------------------------------------------------------
  769. ITextureInternal *CTextureManager::ColorCorrectionTexture( int i )
  770. {
  771. Assert( i<COLOR_CORRECTION_MAX_TEXTURES );
  772. return m_pColorCorrectionTextures[ i ];
  773. }
  774. void CTextureManager::SetColorCorrectionTexture( int i, ITextureInternal *pTexture )
  775. {
  776. Assert( i<COLOR_CORRECTION_MAX_TEXTURES );
  777. if( m_pColorCorrectionTextures[i] )
  778. {
  779. m_pColorCorrectionTextures[i]->DecrementReferenceCount();
  780. }
  781. m_pColorCorrectionTextures[i] = pTexture;
  782. if( pTexture )
  783. pTexture->IncrementReferenceCount();
  784. }
  785. //-----------------------------------------------------------------------------
  786. // Releases all textures (cause we've lost video memory)
  787. //-----------------------------------------------------------------------------
  788. void CTextureManager::ReleaseTextures( bool bReleaseManaged /*= true*/ )
  789. {
  790. g_pShaderAPI->SetFullScreenTextureHandle( INVALID_SHADERAPI_TEXTURE_HANDLE );
  791. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  792. {
  793. if ( bReleaseManaged || m_TextureList[i]->IsRenderTarget() || m_TextureList[i]->IsDefaultPool() )
  794. {
  795. // Release the texture...
  796. m_TextureList[i]->Release();
  797. }
  798. }
  799. }
  800. //-----------------------------------------------------------------------------
  801. // Request a texture ID
  802. //-----------------------------------------------------------------------------
  803. int CTextureManager::RequestNextTextureID()
  804. {
  805. // FIXME: Deal better with texture ids
  806. // The range between 19000 and 21000 are used for standard textures + lightmaps
  807. if (m_iNextTexID == 19000)
  808. {
  809. m_iNextTexID = 21000;
  810. }
  811. return m_iNextTexID++;
  812. }
  813. //-----------------------------------------------------------------------------
  814. // Restores a single texture
  815. //-----------------------------------------------------------------------------
  816. void CTextureManager::RestoreTexture( ITextureInternal* pTexture )
  817. {
  818. // Put the texture back onto the board
  819. pTexture->OnRestore(); // Give render targets a chance to reinitialize themselves if necessary (due to AA changes).
  820. pTexture->Download();
  821. }
  822. //-----------------------------------------------------------------------------
  823. // Restore all textures (cause we've got video memory again)
  824. //-----------------------------------------------------------------------------
  825. void CTextureManager::RestoreNonRenderTargetTextures()
  826. {
  827. // 360 should not have gotten here
  828. Assert( !IsX360() );
  829. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  830. {
  831. if ( !m_TextureList[i]->IsRenderTarget() )
  832. {
  833. RestoreTexture( m_TextureList[i] );
  834. }
  835. }
  836. }
  837. //-----------------------------------------------------------------------------
  838. // Restore just the render targets (cause we've got video memory again)
  839. //-----------------------------------------------------------------------------
  840. void CTextureManager::RestoreRenderTargets()
  841. {
  842. // 360 should not have gotten here
  843. Assert( !IsX360() );
  844. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  845. {
  846. if ( m_TextureList[i]->IsRenderTarget() )
  847. {
  848. RestoreTexture( m_TextureList[i] );
  849. }
  850. }
  851. if ( m_pFullScreenTexture )
  852. {
  853. g_pShaderAPI->SetFullScreenTextureHandle( m_pFullScreenTexture->GetTextureHandle( 0 ) );
  854. }
  855. CacheExternalStandardRenderTargets();
  856. }
  857. //-----------------------------------------------------------------------------
  858. // Reloads all textures
  859. //-----------------------------------------------------------------------------
  860. void CTextureManager::ReloadTextures()
  861. {
  862. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  863. {
  864. // Put the texture back onto the board
  865. m_TextureList[i]->Download();
  866. }
  867. }
  868. static void ForceTextureIntoHardware( ITexture *pTexture, IMaterial *pMaterial, IMaterialVar *pBaseTextureVar )
  869. {
  870. if ( IsGameConsole() )
  871. return;
  872. pBaseTextureVar->SetTextureValue( pTexture );
  873. CMatRenderContextPtr pRenderContext( MaterialSystem()->GetRenderContext() );
  874. pRenderContext->Bind( pMaterial );
  875. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  876. CMeshBuilder meshBuilder;
  877. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 1 );
  878. meshBuilder.Position3f( 0.0f, 0.0f, 0.0f );
  879. meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  880. meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  881. meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  882. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  883. meshBuilder.AdvanceVertex();
  884. meshBuilder.Position3f( 0.0f, 0.0f, 0.0f );
  885. meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  886. meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  887. meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  888. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  889. meshBuilder.AdvanceVertex();
  890. meshBuilder.Position3f( 0.0f, 0.0f, 0.0f );
  891. meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  892. meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  893. meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  894. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  895. meshBuilder.AdvanceVertex();
  896. meshBuilder.End();
  897. pMesh->Draw();
  898. }
  899. //-----------------------------------------------------------------------------
  900. // Reloads all textures
  901. //-----------------------------------------------------------------------------
  902. void CTextureManager::ForceAllTexturesIntoHardware( void )
  903. {
  904. if ( IsGameConsole() )
  905. return;
  906. IMaterial *pMaterial = MaterialSystem()->FindMaterial( "engine/preloadtexture", "texture preload" );
  907. pMaterial = ((IMaterialInternal *)pMaterial)->GetRealTimeVersion(); //always work with the realtime material internally
  908. bool bFound;
  909. IMaterialVar *pBaseTextureVar = pMaterial->FindVar( "$basetexture", &bFound );
  910. if( !bFound )
  911. {
  912. return;
  913. }
  914. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  915. {
  916. // Put the texture back onto the board
  917. ForceTextureIntoHardware( m_TextureList[i], pMaterial, pBaseTextureVar );
  918. }
  919. }
  920. //-----------------------------------------------------------------------------
  921. // Get at a couple standard textures
  922. //-----------------------------------------------------------------------------
  923. ITextureInternal *CTextureManager::ErrorTexture()
  924. {
  925. return m_pErrorTexture;
  926. }
  927. ITextureInternal *CTextureManager::NormalizationCubemap()
  928. {
  929. return m_pNormalizationCubemap;
  930. }
  931. ITextureInternal *CTextureManager::SignedNormalizationCubemap()
  932. {
  933. return m_pSignedNormalizationCubemap;
  934. }
  935. ITextureInternal *CTextureManager::ShadowNoise2D()
  936. {
  937. return m_pShadowNoise2D;
  938. }
  939. ITextureInternal *CTextureManager::SSAONoise2D()
  940. {
  941. return m_pSSAONoise2D;
  942. }
  943. ITextureInternal *CTextureManager::IdentityLightWarp()
  944. {
  945. return m_pIdentityLightWarp;
  946. }
  947. ITextureInternal *CTextureManager::FullFrameDepthTexture()
  948. {
  949. return m_pFullScreenDepthTexture;
  950. }
  951. ITextureInternal *CTextureManager::StereoParamTexture()
  952. {
  953. return m_pStereoParamTexture ? m_pStereoParamTexture : m_pErrorTexture;
  954. }
  955. //-----------------------------------------------------------------------------
  956. // Creates a procedural texture
  957. //-----------------------------------------------------------------------------
  958. ITextureInternal *CTextureManager::CreateProceduralTexture(
  959. const char *pTextureName,
  960. const char *pTextureGroupName,
  961. int w,
  962. int h,
  963. int d,
  964. ImageFormat fmt,
  965. int nFlags )
  966. {
  967. ITextureInternal *pNewTexture = ITextureInternal::CreateProceduralTexture( pTextureName, pTextureGroupName, w, h, d, fmt, nFlags );
  968. if ( !pNewTexture )
  969. return NULL;
  970. // Add it to the list of textures so it can be restored, etc.
  971. m_TextureList.Insert( pNewTexture->GetName(), pNewTexture );
  972. if ( ( nFlags & TEXTUREFLAGS_SKIP_INITIAL_DOWNLOAD ) != TEXTUREFLAGS_SKIP_INITIAL_DOWNLOAD )
  973. {
  974. // NOTE: This will download the texture only if the shader api is ready
  975. pNewTexture->Download();
  976. }
  977. return pNewTexture;
  978. }
  979. //-----------------------------------------------------------------------------
  980. // FIXME: Need some better understanding of when textures should be added to
  981. // the texture dictionary here. Is it only for files, for example?
  982. // Texture dictionary...
  983. //-----------------------------------------------------------------------------
  984. ITextureInternal *CTextureManager::LoadTexture( const char *pTextureName, const char *pTextureGroupName, int nAdditionalCreationFlags /* = 0 */ )
  985. {
  986. ITextureInternal *pNewTexture = ITextureInternal::CreateFileTexture( pTextureName, pTextureGroupName );
  987. if ( pNewTexture )
  988. {
  989. int iIndex = m_TextureExcludes.Find( pNewTexture->GetName() );
  990. if ( m_TextureExcludes.IsValidIndex( iIndex ) )
  991. {
  992. // mark the new texture as excluded
  993. int nDimensionsLimit = m_TextureExcludes[iIndex];
  994. pNewTexture->MarkAsExcluded( ( nDimensionsLimit == 0 ), nDimensionsLimit );
  995. }
  996. else if ( m_bUsingWeaponModelCache && g_pQueuedLoader->IsMapLoading() )
  997. {
  998. // Unfortunate, but the weapon textures get automatically subverted
  999. // to avoid ensuring that scripts do not need to be maintained as new weapons occur.
  1000. // When a weapon texture in not explicitly excluded (which trumps), ensure the exclusion.
  1001. if ( V_stristr( pNewTexture->GetName(), "weapons/v_models" ) ||
  1002. V_stristr( pNewTexture->GetName(), "weapons/w_models" ) ||
  1003. V_stristr( pNewTexture->GetName(), "weapons/shared" ) )
  1004. {
  1005. // ALL weapon textures (subject to temp exclusion) are getting pre-excluded down to 16, which matches the weapon model cache
  1006. // exclusion expectation during loading.
  1007. //
  1008. // This is necessary to avoid a horrible memory load pattern where the QL would otherwise load the texture at full-res and then
  1009. // the weapon model cache would then evict causing a reload as it evicts down to 16.
  1010. //
  1011. // This hack is because the QL is blasting these in BEFORE the weapon model cache has any chance to know what are the actual dependent
  1012. // weapon materials that are subject to initial eviction.
  1013. //
  1014. // Instead this gets in front of the QL which will bring in ALL weapon based textures in at the desired reduced state with a single load/free.
  1015. // Then, there is a fixup by weapon model cache that has then discovered which texture are the REAL dependents and restores the ones
  1016. // that got broadly classified here (i.e. shared textures that can't be subject to temp evictions). Temp Exclusion abilities cannot
  1017. // be determined this early, thus the broad classification, and the unfortunate minor fixup
  1018. pNewTexture->MarkAsExcluded( false, 16, true );
  1019. }
  1020. }
  1021. // Stick the texture onto the board
  1022. pNewTexture->Download( NULL, nAdditionalCreationFlags );
  1023. // FIXME: If there's been an error loading, we don't also want this error...
  1024. }
  1025. return pNewTexture;
  1026. }
  1027. ITextureInternal *CTextureManager::FindTexture( const char *pTextureName )
  1028. {
  1029. if ( !pTextureName || pTextureName[0] == 0 )
  1030. return NULL;
  1031. char szCleanName[MAX_PATH];
  1032. NormalizeTextureName( pTextureName, szCleanName, sizeof( szCleanName ) );
  1033. int i = m_TextureList.Find( szCleanName );
  1034. if ( i != m_TextureList.InvalidIndex() )
  1035. {
  1036. return m_TextureList[i];
  1037. }
  1038. i = m_TextureAliases.Find( szCleanName );
  1039. if ( i != m_TextureAliases.InvalidIndex() )
  1040. {
  1041. return FindTexture( m_TextureAliases[i] );
  1042. }
  1043. // Special handling: lightmaps
  1044. if ( char const *szLightMapNum = StringAfterPrefix( szCleanName, "[lightmap" ) )
  1045. {
  1046. int iLightMapNum = atoi( szLightMapNum );
  1047. extern CMaterialSystem g_MaterialSystem;
  1048. CMatLightmaps *plm = g_MaterialSystem.GetLightmaps();
  1049. if ( iLightMapNum >= 0 &&
  1050. iLightMapNum < plm->GetNumLightmapPages() )
  1051. {
  1052. ShaderAPITextureHandle_t hTex = plm->GetLightmapPageTextureHandle( iLightMapNum );
  1053. if ( hTex != INVALID_SHADERAPI_TEXTURE_HANDLE )
  1054. {
  1055. // Establish the lookup linking in the dictionary
  1056. ITextureInternal *pTxInt = ITextureInternal::CreateReferenceTextureFromHandle( pTextureName, TEXTURE_GROUP_LIGHTMAP, hTex );
  1057. m_TextureList.Insert( pTextureName, pTxInt );
  1058. return pTxInt;
  1059. }
  1060. }
  1061. }
  1062. // scaleform textures bypass the texture manager
  1063. if ( !V_strncmp( szCleanName, "scaleform", 9 ) )
  1064. {
  1065. ShaderAPITextureHandle_t hTex = g_pShaderAPI->FindTexture( szCleanName );
  1066. if ( hTex != INVALID_SHADERAPI_TEXTURE_HANDLE )
  1067. {
  1068. // Establish the lookup linking in the dictionary
  1069. ITextureInternal *pTxInt = ITextureInternal::CreateReferenceTextureFromHandle( szCleanName, TEXTURE_GROUP_SCALEFORM, hTex );
  1070. m_TextureList.Insert( szCleanName, pTxInt );
  1071. return pTxInt;
  1072. }
  1073. }
  1074. return NULL;
  1075. }
  1076. void CTextureManager::AddTextureAlias( const char *pAlias, const char *pRealName )
  1077. {
  1078. if ( (pAlias == NULL) || (pRealName == NULL) )
  1079. return; //invalid alias
  1080. char szCleanName[MAX_PATH];
  1081. int index = m_TextureAliases.Find( NormalizeTextureName( pAlias, szCleanName, sizeof( szCleanName ) ) );
  1082. if ( index != m_TextureAliases.InvalidIndex() )
  1083. {
  1084. AssertMsg( Q_stricmp( pRealName, m_TextureAliases[index] ) == 0, "Trying to use one name to alias two different textures." );
  1085. RemoveTextureAlias( pAlias ); //remove the old alias to make room for the new one.
  1086. }
  1087. size_t iRealNameLength = strlen( pRealName ) + 1;
  1088. char *pRealNameCopy = new char [iRealNameLength];
  1089. memcpy( pRealNameCopy, pRealName, iRealNameLength );
  1090. m_TextureAliases.Insert( szCleanName, pRealNameCopy );
  1091. }
  1092. void CTextureManager::RemoveTextureAlias( const char *pAlias )
  1093. {
  1094. if ( pAlias == NULL )
  1095. return;
  1096. char szCleanName[MAX_PATH];
  1097. int index = m_TextureAliases.Find( NormalizeTextureName( pAlias, szCleanName, sizeof( szCleanName ) ) );
  1098. if ( index == m_TextureAliases.InvalidIndex() )
  1099. return; //not found
  1100. delete []m_TextureAliases[index];
  1101. m_TextureAliases.RemoveAt( index );
  1102. }
  1103. bool CTextureManager::ParseTextureExcludeScript( const char *pScriptName )
  1104. {
  1105. // get optional script
  1106. if ( !pScriptName || !pScriptName[0] )
  1107. return false;
  1108. CUtlBuffer excludeBuffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1109. if ( !g_pFullFileSystem->ReadFile( pScriptName, NULL, excludeBuffer ) )
  1110. return false;
  1111. char szToken[MAX_PATH];
  1112. while ( 1 )
  1113. {
  1114. // must support spaces in names without quotes
  1115. // have to brute force parse up to a valid line
  1116. while ( 1 )
  1117. {
  1118. excludeBuffer.EatWhiteSpace();
  1119. if ( !excludeBuffer.EatCPPComment() )
  1120. {
  1121. // not a comment
  1122. break;
  1123. }
  1124. }
  1125. excludeBuffer.GetLine( szToken, sizeof( szToken ) );
  1126. int tokenLength = strlen( szToken );
  1127. if ( !tokenLength )
  1128. {
  1129. // end of list
  1130. break;
  1131. }
  1132. // remove all trailing whitespace
  1133. while ( tokenLength > 0 )
  1134. {
  1135. tokenLength--;
  1136. if ( V_isgraph( szToken[tokenLength] ) )
  1137. {
  1138. break;
  1139. }
  1140. szToken[tokenLength] = '\0';
  1141. }
  1142. // first optional token may be a dimension limit hint
  1143. int nDimensionsLimit = 0;
  1144. char *pTextureName = szToken;
  1145. if ( pTextureName[0] != 0 && V_isdigit( pTextureName[0] ) )
  1146. {
  1147. nDimensionsLimit = atoi( pTextureName );
  1148. // skip forward to name
  1149. for ( ;; )
  1150. {
  1151. char ch = *pTextureName;
  1152. if ( !ch || ( !V_isdigit( ch ) && !V_isspace( ch ) ) )
  1153. {
  1154. break;
  1155. }
  1156. pTextureName++;
  1157. }
  1158. }
  1159. char szCleanName[MAX_PATH];
  1160. NormalizeTextureName( pTextureName, szCleanName, sizeof( szCleanName ) );
  1161. int iIndex = m_TextureExcludes.Find( szCleanName );
  1162. if ( m_TextureExcludes.IsValidIndex( iIndex ) )
  1163. {
  1164. // do not duplicate, override existing entry
  1165. m_TextureExcludes[iIndex] = nDimensionsLimit;
  1166. }
  1167. else
  1168. {
  1169. m_TextureExcludes.Insert( szCleanName, nDimensionsLimit );
  1170. }
  1171. }
  1172. return true;
  1173. }
  1174. void CTextureManager::SetExcludedTextures( const char *pScriptName, bool bUsingWeaponModelCache )
  1175. {
  1176. MEM_ALLOC_CREDIT();
  1177. m_bUsingWeaponModelCache = IsGameConsole() && bUsingWeaponModelCache;
  1178. // clear all existing texture's exclusion
  1179. for ( int i = m_TextureExcludes.First(); i != m_TextureExcludes.InvalidIndex(); i = m_TextureExcludes.Next( i ) )
  1180. {
  1181. ITextureInternal *pTexture = FindTexture( m_TextureExcludes.GetElementName( i ) );
  1182. if ( pTexture )
  1183. {
  1184. pTexture->MarkAsExcluded( false, 0 );
  1185. }
  1186. }
  1187. m_TextureExcludes.RemoveAll();
  1188. // run through exclusions, build final aggregate list
  1189. // optional global script first
  1190. ParseTextureExcludeScript( "//MOD/maps/_exclude.lst" );
  1191. // optional spec'd script further refines
  1192. ParseTextureExcludeScript( pScriptName );
  1193. // perform exclusions
  1194. for ( int i = m_TextureExcludes.First(); i != m_TextureExcludes.InvalidIndex(); i = m_TextureExcludes.Next( i ) )
  1195. {
  1196. // set any existing texture's exclusion
  1197. // textures that don't exist yet will get caught during their creation path
  1198. ITextureInternal *pTexture = FindTexture( m_TextureExcludes.GetElementName( i ) );
  1199. if ( pTexture )
  1200. {
  1201. int nDimensionsLimit = m_TextureExcludes[i];
  1202. pTexture->MarkAsExcluded( ( nDimensionsLimit == 0 ), nDimensionsLimit );
  1203. }
  1204. }
  1205. }
  1206. void CTextureManager::UpdateExcludedTextures( void )
  1207. {
  1208. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1209. {
  1210. m_TextureList[i]->UpdateExcludedState();
  1211. }
  1212. }
  1213. void CTextureManager::ClearForceExcludes( void )
  1214. {
  1215. if ( !m_bUsingWeaponModelCache )
  1216. {
  1217. // forced excludes are a temp state promoted by the weapon model cache
  1218. return;
  1219. }
  1220. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1221. {
  1222. if ( m_TextureList[i]->IsForceExcluded() )
  1223. {
  1224. m_TextureList[i]->ClearForceExclusion();
  1225. }
  1226. }
  1227. }
  1228. ITextureInternal *CTextureManager::FindOrLoadTexture( const char *pTextureName, const char *pTextureGroupName, int nAdditionalCreationFlags /* = 0 */ )
  1229. {
  1230. ITextureInternal *pTexture = FindTexture( pTextureName );
  1231. if ( !pTexture )
  1232. {
  1233. #if defined( DEVELOPMENT_ONLY ) || defined( ALLOW_TEXT_MODE )
  1234. static bool s_bTextMode = CommandLine()->HasParm( "-textmode" );
  1235. if ( s_bTextMode )
  1236. {
  1237. return m_pErrorTexture;
  1238. }
  1239. #endif
  1240. pTexture = LoadTexture( pTextureName, pTextureGroupName, nAdditionalCreationFlags );
  1241. if ( pTexture )
  1242. {
  1243. // insert into the dictionary using the processed texture name
  1244. m_TextureList.Insert( pTexture->GetName(), pTexture );
  1245. }
  1246. }
  1247. return pTexture;
  1248. }
  1249. bool CTextureManager::IsTextureLoaded( const char *pTextureName )
  1250. {
  1251. ITextureInternal *pTexture = FindTexture( pTextureName );
  1252. return ( pTexture != NULL );
  1253. }
  1254. bool CTextureManager::GetTextureInformation( char const *szTextureName, MaterialTextureInfo_t &info )
  1255. {
  1256. extern bool CTextureImpl_GetTextureInformation( char const *szTextureName, MaterialTextureInfo_t &info );
  1257. return CTextureImpl_GetTextureInformation( szTextureName, info );
  1258. }
  1259. //-----------------------------------------------------------------------------
  1260. // Creates a texture that's a render target
  1261. //-----------------------------------------------------------------------------
  1262. ITextureInternal *CTextureManager::CreateRenderTargetTexture(
  1263. const char *pRTName, // NULL for auto-generated name
  1264. int w,
  1265. int h,
  1266. RenderTargetSizeMode_t sizeMode,
  1267. ImageFormat fmt,
  1268. RenderTargetType_t type,
  1269. unsigned int textureFlags,
  1270. unsigned int renderTargetFlags,
  1271. bool bMultipleTargets )
  1272. {
  1273. MEM_ALLOC_CREDIT_( __FILE__ ": Render target" );
  1274. ITextureInternal *pTexture;
  1275. if ( pRTName )
  1276. {
  1277. // caller is re-initing or changing
  1278. pTexture = FindTexture( pRTName );
  1279. if ( pTexture )
  1280. {
  1281. // Changing the underlying render target, but leaving the pointer and refcount
  1282. // alone fixes callers that have exisiting references to this object.
  1283. ITextureInternal::ChangeRenderTarget( pTexture, w, h, sizeMode, fmt, type,
  1284. textureFlags, renderTargetFlags );
  1285. #ifdef _PS3
  1286. if ( pRTName[0] == '^' )
  1287. {
  1288. // Alias raw buffer
  1289. pTexture->Ps3gcmRawBufferAlias( pRTName );
  1290. return pTexture;
  1291. }
  1292. #endif
  1293. // download if ready
  1294. pTexture->Download();
  1295. return pTexture;
  1296. }
  1297. }
  1298. pTexture = ITextureInternal::CreateRenderTarget( pRTName, w, h, sizeMode, fmt, type,
  1299. textureFlags, renderTargetFlags, bMultipleTargets );
  1300. if ( !pTexture )
  1301. return NULL;
  1302. // Add the render target to the list of textures
  1303. // that way it'll get cleaned up correctly in case of a task switch
  1304. m_TextureList.Insert( pTexture->GetName(), pTexture );
  1305. // NOTE: This will download the texture only if the shader api is ready
  1306. #ifdef _PS3
  1307. if ( pRTName && pRTName[0] == '^' )
  1308. {
  1309. // Alias raw buffer
  1310. pTexture->Ps3gcmRawBufferAlias( pRTName );
  1311. }
  1312. else
  1313. #endif
  1314. {
  1315. pTexture->Download();
  1316. }
  1317. return pTexture;
  1318. }
  1319. void CTextureManager::ResetTextureFilteringState( )
  1320. {
  1321. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1322. {
  1323. m_TextureList[i]->SetFilteringAndClampingMode();
  1324. }
  1325. }
  1326. void CTextureManager::RemoveUnusedTextures( void )
  1327. {
  1328. int iNext;
  1329. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = iNext )
  1330. {
  1331. iNext = m_TextureList.Next( i );
  1332. #ifdef _DEBUG
  1333. if ( m_TextureList[i]->GetReferenceCount() < 0 )
  1334. {
  1335. Warning( "RemoveUnusedTextures: pTexture->m_referenceCount < 0 for %s\n", m_TextureList[i]->GetName() );
  1336. }
  1337. #endif
  1338. if ( m_TextureList[i]->GetReferenceCount() <= 0 )
  1339. {
  1340. ITextureInternal::Destroy( m_TextureList[i] );
  1341. m_TextureList.RemoveAt( i );
  1342. }
  1343. }
  1344. }
  1345. void CTextureManager::RemoveTexture( ITextureInternal *pTexture )
  1346. {
  1347. Assert( pTexture->GetReferenceCount() <= 0 );
  1348. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1349. {
  1350. // search by object
  1351. if ( m_TextureList[i] == pTexture )
  1352. {
  1353. ITextureInternal::Destroy( m_TextureList[i] );
  1354. m_TextureList.RemoveAt( i );
  1355. break;
  1356. }
  1357. }
  1358. }
  1359. void CTextureManager::ReloadFilesInList( IFileList *pFilesToReload )
  1360. {
  1361. if ( IsPC() )
  1362. {
  1363. for ( int i=m_TextureList.First(); i != m_TextureList.InvalidIndex(); i=m_TextureList.Next( i ) )
  1364. {
  1365. ITextureInternal *pTex = m_TextureList[i];
  1366. pTex->ReloadFilesInList( pFilesToReload );
  1367. }
  1368. }
  1369. }
  1370. void CTextureManager::ReleaseTempRenderTargetBits( void )
  1371. {
  1372. if( IsX360() ) //only sane on 360
  1373. {
  1374. int iNext;
  1375. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = iNext )
  1376. {
  1377. iNext = m_TextureList.Next( i );
  1378. if ( m_TextureList[i]->IsTempRenderTarget() )
  1379. {
  1380. m_TextureList[i]->Release();
  1381. }
  1382. }
  1383. }
  1384. }
  1385. void CTextureManager::DebugPrintUsedTextures( void )
  1386. {
  1387. for ( int i = m_TextureList.First(); i != m_TextureList.InvalidIndex(); i = m_TextureList.Next( i ) )
  1388. {
  1389. ITextureInternal *pTexture;
  1390. pTexture = m_TextureList[i];
  1391. Msg( "Texture: '%s' RefCount: %d\n", pTexture->GetName(), pTexture->GetReferenceCount() );
  1392. }
  1393. if ( m_TextureExcludes.Count() )
  1394. {
  1395. Msg( "\nExcluded Textures: (%d)\n", m_TextureExcludes.Count() );
  1396. for ( int i = m_TextureExcludes.First(); i != m_TextureExcludes.InvalidIndex(); i = m_TextureExcludes.Next( i ) )
  1397. {
  1398. char buff[256];
  1399. const char *pName = m_TextureExcludes.GetElementName( i );
  1400. V_snprintf( buff, sizeof( buff ), "Excluded: %d '%s' \n", m_TextureExcludes[i], pName );
  1401. // an excluded texture is valid, but forced tiny
  1402. if ( IsTextureLoaded( pName ) )
  1403. {
  1404. Msg( "%s\n", buff );
  1405. }
  1406. else
  1407. {
  1408. // warn as unknown, could be a spelling error
  1409. Warning( "%s", buff );
  1410. }
  1411. }
  1412. }
  1413. }
  1414. int CTextureManager::FindNext( int iIndex, ITextureInternal **pTexInternal )
  1415. {
  1416. if ( iIndex == -1 && m_TextureList.Count() )
  1417. {
  1418. iIndex = m_TextureList.First();
  1419. }
  1420. else if ( !m_TextureList.Count() || !m_TextureList.IsValidIndex( iIndex ) )
  1421. {
  1422. *pTexInternal = NULL;
  1423. return -1;
  1424. }
  1425. *pTexInternal = m_TextureList[iIndex];
  1426. iIndex = m_TextureList.Next( iIndex );
  1427. if ( iIndex == m_TextureList.InvalidIndex() )
  1428. {
  1429. // end of list
  1430. iIndex = -1;
  1431. }
  1432. return iIndex;
  1433. }