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.

3729 lines
103 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Implementation of a material
  4. //
  5. //===========================================================================//
  6. #include "imaterialinternal.h"
  7. #include "bitmap/tgaloader.h"
  8. #include "colorspace.h"
  9. #include "materialsystem/imaterialvar.h"
  10. #include "materialsystem/itexture.h"
  11. #include <string.h>
  12. #include "materialsystem_global.h"
  13. #include "shaderapi/ishaderapi.h"
  14. #include "materialsystem/imaterialproxy.h"
  15. #include "shadersystem.h"
  16. #include "materialsystem/imaterialproxyfactory.h"
  17. #include "IHardwareConfigInternal.h"
  18. #include "utlsymbol.h"
  19. #if !defined( _PS3 )
  20. #include <malloc.h>
  21. #endif //!_PS3
  22. #include "filesystem.h"
  23. #include <keyvalues.h>
  24. #include "mempool.h"
  25. #include "shaderapi/ishaderutil.h"
  26. #include "vtf/vtf.h"
  27. #include "tier1/strtools.h"
  28. #include <ctype.h>
  29. #include "utlbuffer.h"
  30. #include "mathlib/vmatrix.h"
  31. #include "texturemanager.h"
  32. #include "itextureinternal.h"
  33. #include "mempool.h"
  34. #include "tier1/callqueue.h"
  35. #include "cmaterial_queuefriendly.h"
  36. #include "ifilelist.h"
  37. #include "tier0/icommandline.h"
  38. #ifndef M_PI
  39. #define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
  40. #endif
  41. //static ConVar mat_debug_material_reference_name( "mat_debug_material_reference_name", "/eq_grenades/smoke_grenade", FCVAR_RELEASE, "Substring to debug material references" );
  42. //-----------------------------------------------------------------------------
  43. // Material implementation
  44. //-----------------------------------------------------------------------------
  45. class CMaterial : public IMaterialInternal
  46. {
  47. public:
  48. // Members of the IMaterial interface
  49. const char *GetName() const;
  50. IMaterialVar** GetVars() { return m_pShaderParams; }
  51. const char *GetTextureGroupName() const;
  52. inline bool IsPrecached_Inline( ) const
  53. {
  54. return (m_Flags & MATERIAL_IS_PRECACHED) != 0;
  55. }
  56. bool IsPrecached( ) const { return IsPrecached_Inline(); }
  57. inline bool IsPrecachedVars_Inline( ) const
  58. {
  59. return (m_Flags & MATERIAL_VARS_IS_PRECACHED) != 0;
  60. }
  61. bool IsPrecachedVars( ) const { return IsPrecachedVars_Inline(); }
  62. PreviewImageRetVal_t GetPreviewImageProperties( int *width, int *height,
  63. ImageFormat *imageFormat, bool* isTranslucent ) const;
  64. PreviewImageRetVal_t GetPreviewImage( unsigned char *data, int width, int height,
  65. ImageFormat imageFormat ) const;
  66. int GetMappingWidth( );
  67. int GetMappingHeight( );
  68. int GetNumAnimationFrames( );
  69. bool InMaterialPage( void ) { return false; }
  70. void GetMaterialOffset( float *pOffset );
  71. void GetMaterialScale( float *pOffset );
  72. IMaterial *GetMaterialPage( void ) { return NULL; }
  73. void IncrementReferenceCount( );
  74. void DecrementReferenceCount( );
  75. int GetEnumerationID( ) const;
  76. void GetLowResColorSample( float s, float t, float *color ) const;
  77. IMaterialVar * FindVar( char const *varName, bool *found, bool complain = true );
  78. IMaterialVar * FindVarFast( char const *pVarName, unsigned int *pToken );
  79. // Sets new VMT shader parameters for the material
  80. virtual void SetShaderAndParams( KeyValues *pKeyValues );
  81. bool UsesEnvCubemap( void );
  82. bool NeedsSoftwareSkinning( void );
  83. virtual bool NeedsSoftwareLighting( void );
  84. bool NeedsTangentSpace( void );
  85. bool NeedsPowerOfTwoFrameBufferTexture( bool bCheckSpecificToThisFrame = true );
  86. bool NeedsFullFrameBufferTexture( bool bCheckSpecificToThisFrame = true );
  87. virtual bool IsUsingVertexID( ) const;
  88. // GR - Is lightmap alpha needed?
  89. bool NeedsLightmapBlendAlpha( void );
  90. virtual void AlphaModulate( float alpha );
  91. virtual void ColorModulate( float r, float g, float b );
  92. virtual float GetAlphaModulation();
  93. virtual void GetColorModulation( float *r, float *g, float *b );
  94. void SetMaterialVarFlag( MaterialVarFlags_t flag, bool on );
  95. bool GetMaterialVarFlag( MaterialVarFlags_t flag ) const;
  96. bool IsTranslucent();
  97. bool IsTranslucentInternal( float fAlphaModulation ) const; //need to centralize the logic without relying on the *current* alpha modulation being that which is stored in m_pShaderParams[ALPHA].
  98. virtual bool IsTranslucentUnderModulation( float fAlphaModulation ) const;
  99. bool IsAlphaTested();
  100. bool IsVertexLit();
  101. virtual bool IsSpriteCard();
  102. void GetReflectivity( Vector& reflect );
  103. bool GetPropertyFlag( MaterialPropertyTypes_t type );
  104. // Is the material visible from both sides?
  105. bool IsTwoSided();
  106. int GetNumPasses( void );
  107. int GetTextureMemoryBytes( void );
  108. public:
  109. // stuff that is visible only from within the material system
  110. // constructor, destructor
  111. CMaterial( char const* materialName, const char *pTextureGroupName, KeyValues *pVMTKeyValues );
  112. virtual ~CMaterial();
  113. CBasePerMaterialContextData **GetContextData( int modulationFlags )
  114. {
  115. return &(m_ShaderRenderState.m_pSnapshots[modulationFlags].m_pContextData[0]);
  116. }
  117. StateSnapshot_t GetSnapshotId( int modulation, int renderPass );
  118. unsigned char* GetInstanceCommandBuffer( int modulation );
  119. void DrawMesh( VertexCompressionType_t vertexCompression, bool bIsAlphaModulating, bool bRenderingPreTessPatchMesh );
  120. void Uncache( bool bPreserveVars = false );
  121. void ReloadTextures( void );
  122. private:
  123. void Precache_Internal();
  124. bool PrecacheVars_Internal( KeyValues *pKeyValues, KeyValues *pPatchKeyValues, CUtlVector<FileNameHandle_t> *pIncludes );
  125. public:
  126. // If provided, pKeyValues and pPatchKeyValues should come from LoadVMTFile()
  127. inline bool PrecacheVars_Inline( KeyValues *pKeyValues = NULL, KeyValues *pPatchKeyValues = NULL, CUtlVector<FileNameHandle_t> *pIncludes = NULL )
  128. {
  129. // We should get both parameters or neither
  130. Assert( !!pKeyValues == !!pPatchKeyValues );
  131. // Don't bother if we're already precached
  132. if( IsPrecachedVars_Inline() )
  133. return true;
  134. return PrecacheVars_Internal( pKeyValues, pPatchKeyValues, pIncludes );
  135. }
  136. inline void Precache_Inline()
  137. {
  138. // Don't bother if we're already precached
  139. if ( IsPrecached_Inline() )
  140. return;
  141. // load data from the vmt file
  142. if ( !PrecacheVars_Inline() )
  143. return;
  144. Precache_Internal();
  145. }
  146. void Precache()
  147. {
  148. Precache_Inline();
  149. }
  150. bool PrecacheVars( KeyValues *pKeyValues = NULL, KeyValues *pPatchKeyValues = NULL, CUtlVector<FileNameHandle_t> *pIncludes = NULL )
  151. {
  152. return PrecacheVars_Inline( pKeyValues, pPatchKeyValues, pIncludes );
  153. }
  154. void SetMinLightmapPageID( int pageID );
  155. void SetMaxLightmapPageID( int pageID );
  156. int GetMinLightmapPageID( ) const;
  157. int GetMaxLightmapPageID( ) const;
  158. void SetNeedsWhiteLightmap( bool val );
  159. bool GetNeedsWhiteLightmap( ) const;
  160. IShader * GetShader() const;
  161. const char *GetShaderName() const;
  162. virtual void DeleteIfUnreferenced();
  163. void SetEnumerationID( int id );
  164. void CallBindProxy( void *proxyData, ICallQueue *pCallQueue );
  165. bool HasProxy( void ) const;
  166. // Sets the shader associated with the material
  167. void SetShader( const char *pShaderName );
  168. // Can we override this material in debug?
  169. bool NoDebugOverride() const;
  170. // Gets the vertex format
  171. VertexFormat_t GetVertexFormat() const;
  172. // diffuse bump lightmap?
  173. bool IsUsingDiffuseBumpedLighting() const;
  174. // lightmap?
  175. bool IsUsingLightmap() const;
  176. // Gets the vertex usage flags
  177. VertexFormat_t GetVertexUsage() const;
  178. // Debugs this material
  179. bool PerformDebugTrace() const;
  180. // Are we suppressed?
  181. bool IsSuppressed() const;
  182. // Do we use fog?
  183. bool UseFog( void ) const;
  184. // Should we draw?
  185. void ToggleSuppression();
  186. void ToggleDebugTrace();
  187. // Refresh material based on current var values
  188. void Refresh();
  189. void RefreshPreservingMaterialVars();
  190. // This computes the state snapshots for this material
  191. void RecomputeStateSnapshots();
  192. // Gets at the shader parameters
  193. virtual int ShaderParamCount() const;
  194. virtual IMaterialVar **GetShaderParams( void );
  195. virtual void AddMaterialVar( IMaterialVar *pMaterialVar );
  196. virtual bool IsErrorMaterial() const;
  197. // Was this manually created (not read from a file?)
  198. virtual bool IsManuallyCreated() const;
  199. virtual bool NeedsFixedFunctionFlashlight() const;
  200. virtual void MarkAsPreloaded( bool bSet );
  201. virtual bool IsPreloaded() const;
  202. virtual void ArtificialAddRef( void );
  203. virtual void ArtificialRelease( void );
  204. virtual void ReportVarChanged( IMaterialVar *pVar )
  205. {
  206. m_ChangeID++;
  207. }
  208. virtual void ClearContextData( void );
  209. virtual uint32 GetChangeID() const { return m_ChangeID; }
  210. virtual uint32 GetChangeTimestamp() const { return m_ChangeID ^ g_nDebugVarsSignature; }
  211. virtual bool IsRealTimeVersion( void ) const { return true; }
  212. virtual IMaterialInternal *GetRealTimeVersion( void ) { return this; }
  213. virtual IMaterialInternal *GetQueueFriendlyVersion( void ) { return &m_QueueFriendlyVersion; }
  214. void DecideShouldReloadFromWhitelist( IFileList *pFilesToReload );
  215. void ReloadFromWhitelistIfMarked();
  216. bool WasReloadedFromWhitelist();
  217. virtual void CompactMaterialVars();
  218. // Are any of the proxies attached to this material callable from the queued thread?
  219. virtual bool HasQueueFriendlyProxies() const OVERRIDE;
  220. virtual bool SetTempExcluded( bool bSet, int nExcludedDimensionLimit );
  221. virtual int GetReferenceCount() const;
  222. private:
  223. // Initializes, cleans up the shader params
  224. void CleanUpShaderParams();
  225. // Sets up an error shader when we run into problems.
  226. void SetupErrorShader();
  227. // Does this material have a UNC-file name?
  228. bool UsesUNCFileName() const;
  229. // Prints material flags.
  230. void PrintMaterialFlags( int flags, int flagsDefined );
  231. // Parses material flags
  232. bool ParseMaterialFlag( KeyValues* pParseValue, IMaterialVar* pFlagVar,
  233. IMaterialVar* pFlagDefinedVar, bool parsingOverrides, int& flagMask, int& overrideMask );
  234. // Computes the material vars for the shader
  235. int ParseMaterialVars( IShader* pShader, KeyValues& keyValues,
  236. KeyValues* pOverride, bool modelDefault, IMaterialVar** ppVars );
  237. // Figures out the preview image for worldcraft
  238. char const* GetPreviewImageName( );
  239. char const* GetPreviewImageFileName( void ) const;
  240. // Hooks up the shader, returns keyvalues of fallback that was used
  241. KeyValues* InitializeShader( KeyValues &keyValues, KeyValues &patchKeyValues );
  242. // Finds the flag associated with a particular flag name
  243. int FindMaterialVarFlag( char const* pFlagName ) const;
  244. // Initializes, cleans up the state snapshots
  245. bool InitializeStateSnapshots();
  246. void CleanUpStateSnapshots();
  247. // Initializes, cleans up the material proxy
  248. void InitializeMaterialProxy( KeyValues* pFallbackKeyValues );
  249. void CleanUpMaterialProxy();
  250. // Creates, destroys snapshots
  251. RenderPassList_t *CreateRenderPassList();
  252. void DestroyRenderPassList( RenderPassList_t *pPassList );
  253. // Grabs the texture width and height from the var list for faster access
  254. void PrecacheMappingDimensions( );
  255. // Gets the renderstate
  256. virtual ShaderRenderState_t *GetRenderState();
  257. // Do we have a valid renderstate?
  258. bool IsValidRenderState() const;
  259. // Get the material var flags
  260. int GetMaterialVarFlags() const;
  261. void SetMaterialVarFlags( int flags, bool on );
  262. int GetMaterialVarFlags2() const;
  263. void SetMaterialVarFlags2( int flags, bool on );
  264. // Returns a dummy material variable
  265. IMaterialVar* GetDummyVariable();
  266. IMaterialVar* GetShaderParam( int id );
  267. void FindRepresentativeTexture( void );
  268. bool ShouldSkipVar( KeyValues *pMaterialVar, bool * pWasConditional );
  269. // Fixed-size allocator
  270. DECLARE_FIXEDSIZE_ALLOCATOR( CMaterial );
  271. private:
  272. enum
  273. {
  274. MATERIAL_NEEDS_WHITE_LIGHTMAP = 0x1,
  275. MATERIAL_IS_PRECACHED = 0x2,
  276. MATERIAL_VARS_IS_PRECACHED = 0x4,
  277. MATERIAL_VALID_RENDERSTATE = 0x8,
  278. MATERIAL_IS_MANUALLY_CREATED = 0x10,
  279. MATERIAL_USES_UNC_FILENAME = 0x20,
  280. MATERIAL_IS_PRELOADED = 0x40,
  281. MATERIAL_ARTIFICIAL_REFCOUNT = 0x80,
  282. };
  283. int m_iEnumerationID;
  284. int m_minLightmapPageID;
  285. int m_maxLightmapPageID;
  286. unsigned short m_MappingWidth;
  287. unsigned short m_MappingHeight;
  288. IShader *m_pShader;
  289. CUtlSymbol m_Name;
  290. // Any textures created for this material go under this texture group.
  291. CUtlSymbol m_TextureGroupName;
  292. CInterlockedInt m_RefCount;
  293. unsigned short m_Flags;
  294. unsigned char m_VarCount;
  295. unsigned char m_ProxyCount;
  296. IMaterialVar** m_pShaderParams;
  297. IMaterialProxy** m_ppProxies;
  298. ShaderRenderState_t m_ShaderRenderState;
  299. // This remembers filenames of VMTs that we included so we can sv_pure/flush ourselves if any of them need to be reloaded.
  300. CUtlVector<FileNameHandle_t> m_VMTIncludes;
  301. bool m_bShouldReloadFromWhitelist; // Tells us if the material decided it should be reloaded due to sv_pure whitelist changes.
  302. ITextureInternal *m_representativeTexture;
  303. Vector m_Reflectivity;
  304. uint32 m_ChangeID;
  305. // Used only by procedural materials; it essentially is an in-memory .VMT file
  306. KeyValues *m_pVMTKeyValues;
  307. #ifdef _DEBUG
  308. // Makes it easier to see what's going on
  309. char *m_pDebugName;
  310. #endif
  311. protected:
  312. CMaterial_QueueFriendly m_QueueFriendlyVersion;
  313. };
  314. // NOTE: This must be the last file included
  315. // Has to exist *after* fixed size allocator declaration
  316. #include "tier0/memdbgon.h"
  317. static ConVar mat_processtoolvars( "mat_processtoolvars", "0" ); // 0 = Ignore tool material variables (e.g. %foo) at runtime (default)
  318. // 1 = Process tool material variables at runtime (required for dynamic level builds via VBSP2LIB)
  319. // Forward decls of helper functions for dealing with patch vmts.
  320. static void ApplyPatchKeyValues( KeyValues &keyValues, KeyValues &patchKeyValues );
  321. static bool AccumulateRecursiveVmtPatches( KeyValues &patchKeyValuesOut, KeyValues **ppBaseKeyValuesOut,
  322. const KeyValues& keyValues, const char *pPathID, CUtlVector<FileNameHandle_t> *pIncludes );
  323. //-----------------------------------------------------------------------------
  324. // Parser utilities
  325. //-----------------------------------------------------------------------------
  326. static inline bool IsWhitespace( char c )
  327. {
  328. return c == ' ' || c == '\t';
  329. }
  330. static inline bool IsEndline( char c )
  331. {
  332. return c == '\n' || c == '\0';
  333. }
  334. static inline bool IsVector( char const* v )
  335. {
  336. while (IsWhitespace(*v))
  337. {
  338. ++v;
  339. if (IsEndline(*v))
  340. return false;
  341. }
  342. return *v == '[' || *v == '{';
  343. }
  344. //-----------------------------------------------------------------------------
  345. // Methods to create state snapshots
  346. //-----------------------------------------------------------------------------
  347. #include "tier0/memdbgoff.h"
  348. #ifndef _GAMECONSOLE
  349. struct EditorRenderStateList_t
  350. {
  351. // Store combo of alpha, color, fixed-function baked lighting, flashlight, editor mode
  352. RenderPassList_t m_Snapshots[SNAPSHOT_COUNT_GBUFFER];
  353. DECLARE_FIXEDSIZE_ALLOCATOR( EditorRenderStateList_t );
  354. };
  355. #endif
  356. struct StandardRenderStateList_t
  357. {
  358. // Store combo of alpha, color, fixed-function baked lighting, flashlight
  359. RenderPassList_t m_Snapshots[SNAPSHOT_COUNT_NORMAL];
  360. DECLARE_FIXEDSIZE_ALLOCATOR( StandardRenderStateList_t );
  361. };
  362. #include "tier0/memdbgon.h"
  363. #ifndef _GAMECONSOLE
  364. DEFINE_FIXEDSIZE_ALLOCATOR( EditorRenderStateList_t, 256, true );
  365. #endif
  366. DEFINE_FIXEDSIZE_ALLOCATOR( StandardRenderStateList_t, 256, true );
  367. //-----------------------------------------------------------------------------
  368. // class factory methods
  369. //-----------------------------------------------------------------------------
  370. DEFINE_FIXEDSIZE_ALLOCATOR( CMaterial, 256, true );
  371. IMaterialInternal* IMaterialInternal::CreateMaterial( char const* pMaterialName, const char *pTextureGroupName, KeyValues *pVMTKeyValues )
  372. {
  373. MaterialLock_t hMaterialLock = MaterialSystem()->Lock();
  374. IMaterialInternal *pResult = new CMaterial( pMaterialName, pTextureGroupName, pVMTKeyValues );
  375. MaterialSystem()->Unlock( hMaterialLock );
  376. return pResult;
  377. }
  378. void IMaterialInternal::DestroyMaterial( IMaterialInternal* pMaterial )
  379. {
  380. MaterialLock_t hMaterialLock = MaterialSystem()->Lock();
  381. if (pMaterial)
  382. {
  383. Assert( pMaterial->IsRealTimeVersion() );
  384. CMaterial* pMatImp = static_cast<CMaterial*>(pMaterial);
  385. // deletion of the error material is deferred until after all other materials have been deleted.
  386. if ( !pMatImp->IsErrorMaterial() )
  387. {
  388. delete pMatImp;
  389. }
  390. }
  391. MaterialSystem()->Unlock( hMaterialLock );
  392. }
  393. //-----------------------------------------------------------------------------
  394. // constructor, destructor
  395. //-----------------------------------------------------------------------------
  396. CMaterial::CMaterial( char const* materialName, const char *pTextureGroupName, KeyValues *pKeyValues )
  397. {
  398. m_Reflectivity.Init( 0.2f, 0.2f, 0.2f );
  399. int len = Q_strlen(materialName);
  400. char* pTemp = (char*)stackalloc( len + 1 );
  401. // Strip off the extension
  402. Q_StripExtension( materialName, pTemp, len+1 );
  403. Q_strlower( pTemp );
  404. #if defined( _X360 )
  405. // material names are expected to be forward slashed for correct sort and find behavior!
  406. // assert now to track alternate or regressed path that is source of inconsistency
  407. Assert( strchr( pTemp, '\\' ) == NULL );
  408. #endif
  409. // Convert it to a symbol
  410. m_Name = pTemp;
  411. #ifdef _DEBUG
  412. m_pDebugName = new char[strlen(pTemp) + 1];
  413. Q_strncpy( m_pDebugName, pTemp, strlen(pTemp) + 1 );
  414. #endif
  415. m_bShouldReloadFromWhitelist = false;
  416. m_Flags = 0;
  417. m_pShader = NULL;
  418. m_pShaderParams = NULL;
  419. m_RefCount = 0;
  420. m_representativeTexture = NULL;
  421. m_ppProxies = NULL;
  422. m_ProxyCount = 0;
  423. m_VarCount = 0;
  424. m_MappingWidth = m_MappingHeight = 0;
  425. m_iEnumerationID = 0;
  426. m_minLightmapPageID = m_maxLightmapPageID = 0;
  427. m_TextureGroupName = pTextureGroupName;
  428. m_pVMTKeyValues = pKeyValues;
  429. if (m_pVMTKeyValues)
  430. {
  431. m_Flags |= MATERIAL_IS_MANUALLY_CREATED;
  432. }
  433. if ( pTemp[0] == '/' && pTemp[1] == '/' && pTemp[2] != '/' )
  434. {
  435. m_Flags |= MATERIAL_USES_UNC_FILENAME;
  436. }
  437. // Initialize the renderstate to something indicating nothing should be drawn
  438. m_ShaderRenderState.m_Flags = 0;
  439. m_ShaderRenderState.m_VertexFormat = m_ShaderRenderState.m_VertexUsage = 0;
  440. m_ShaderRenderState.m_pSnapshots = CreateRenderPassList();
  441. m_ChangeID = 0;
  442. m_QueueFriendlyVersion.SetRealTimeVersion( this );
  443. }
  444. CMaterial::~CMaterial()
  445. {
  446. MaterialSystem()->UnbindMaterial( this );
  447. Uncache();
  448. #if defined( DEVELOPMENT_ONLY ) || defined( ALLOW_TEXT_MODE )
  449. static bool s_bTextMode = CommandLine()->HasParm( "-textmode" );
  450. #else
  451. const bool s_bTextMode = false;
  452. #endif
  453. if ( m_RefCount != 0 && !s_bTextMode )
  454. {
  455. Warning( "Reference Count for Material %s (%d) != 0\n", GetName(), (int) m_RefCount );
  456. }
  457. if ( m_pVMTKeyValues )
  458. {
  459. m_pVMTKeyValues->deleteThis();
  460. m_pVMTKeyValues = NULL;
  461. }
  462. DestroyRenderPassList( m_ShaderRenderState.m_pSnapshots );
  463. m_QueueFriendlyVersion.SetRealTimeVersion( NULL );
  464. m_representativeTexture = NULL;
  465. #ifdef _DEBUG
  466. delete[] m_pDebugName;
  467. #endif
  468. // Deliberately stomp our VTable so that we can detect cases where code tries to access freed materials.
  469. int *p = (int *)this;
  470. *p = 0xc0dedbad;
  471. }
  472. void CMaterial::ClearContextData( void )
  473. {
  474. int nSnapshotCount = SnapshotTypeCount();
  475. for( int i = 0 ; i < nSnapshotCount ; i++ )
  476. {
  477. RenderPassList_t &renderPassList = m_ShaderRenderState.m_pSnapshots[i];
  478. for( int j = 0 ; j < renderPassList.m_nPassCount; j++ )
  479. {
  480. if ( renderPassList.m_pContextData[j] )
  481. {
  482. delete renderPassList.m_pContextData[j];
  483. renderPassList.m_pContextData[j] = NULL;
  484. }
  485. }
  486. }
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Sets new VMT shader parameters for the material
  490. //-----------------------------------------------------------------------------
  491. void CMaterial::SetShaderAndParams( KeyValues *pKeyValues )
  492. {
  493. Uncache();
  494. if ( m_pVMTKeyValues )
  495. {
  496. m_pVMTKeyValues->deleteThis();
  497. m_pVMTKeyValues = NULL;
  498. }
  499. m_pVMTKeyValues = pKeyValues ? pKeyValues->MakeCopy() : NULL;
  500. if ( m_pVMTKeyValues )
  501. {
  502. m_Flags |= MATERIAL_IS_MANUALLY_CREATED;
  503. }
  504. // Apply patches
  505. const char *pMaterialName = GetName();
  506. char pFileName[MAX_PATH];
  507. const char *pPathID = "GAME";
  508. if ( !UsesUNCFileName() )
  509. {
  510. Q_snprintf( pFileName, sizeof( pFileName ), "materials/%s.vmt", pMaterialName );
  511. }
  512. else
  513. {
  514. Q_snprintf( pFileName, sizeof( pFileName ), "%s.vmt", pMaterialName );
  515. if ( pMaterialName[0] == '/' && pMaterialName[1] == '/' && pMaterialName[2] != '/' )
  516. {
  517. // UNC, do full search
  518. pPathID = NULL;
  519. }
  520. }
  521. KeyValues *pLoadedKeyValues = new KeyValues( "vmt" );
  522. if ( pLoadedKeyValues->LoadFromFile( g_pFullFileSystem, pFileName, pPathID ) )
  523. {
  524. // Load succeeded, check if it's a patch file
  525. if ( V_stricmp( pLoadedKeyValues->GetName(), "patch" ) == 0 )
  526. {
  527. // it's a patch file, recursively build up patch keyvalues
  528. KeyValues *pPatchKeyValues = new KeyValues( "vmt_patch" );
  529. bool bSuccess = AccumulateRecursiveVmtPatches( *pPatchKeyValues, NULL, *pLoadedKeyValues, pPathID, NULL );
  530. if ( bSuccess )
  531. {
  532. // Apply accumulated patches to final vmt
  533. ApplyPatchKeyValues( *m_pVMTKeyValues, *pPatchKeyValues );
  534. }
  535. pPatchKeyValues->deleteThis();
  536. }
  537. }
  538. pLoadedKeyValues->deleteThis();
  539. if ( g_pShaderDevice->IsUsingGraphics() )
  540. {
  541. Precache();
  542. }
  543. }
  544. //-----------------------------------------------------------------------------
  545. // Creates, destroys snapshots
  546. //-----------------------------------------------------------------------------
  547. RenderPassList_t *CMaterial::CreateRenderPassList()
  548. {
  549. RenderPassList_t *pRenderPassList;
  550. if ( IsGameConsole() ||
  551. !( MaterialSystem()->GetConfigurationFlags() &
  552. ( MATCONFIG_FLAGS_SUPPORT_GBUFFER | MATCONFIG_FLAGS_SUPPORT_EDITOR ) ) )
  553. {
  554. StandardRenderStateList_t *pList = new StandardRenderStateList_t;
  555. pRenderPassList = (RenderPassList_t*)pList->m_Snapshots;
  556. }
  557. #ifndef _GAMECONSOLE
  558. else
  559. {
  560. EditorRenderStateList_t *pList = new EditorRenderStateList_t;
  561. pRenderPassList = (RenderPassList_t*)pList->m_Snapshots;
  562. }
  563. #endif
  564. int nSnapshotCount = SnapshotTypeCount();
  565. memset( pRenderPassList, 0, nSnapshotCount * sizeof(RenderPassList_t) );
  566. return pRenderPassList;
  567. }
  568. void CMaterial::DestroyRenderPassList( RenderPassList_t *pPassList )
  569. {
  570. if ( !pPassList )
  571. return;
  572. int nSnapshotCount = SnapshotTypeCount();
  573. for( int i = 0 ; i < nSnapshotCount ; i++ )
  574. {
  575. for( int j = 0 ; j < pPassList[i].m_nPassCount; j++ )
  576. {
  577. if ( pPassList[i].m_pContextData[j] )
  578. {
  579. delete pPassList[i].m_pContextData[j];
  580. pPassList[i].m_pContextData[j] = NULL;
  581. }
  582. if ( pPassList[i].m_pInstanceData[j] )
  583. {
  584. delete pPassList[i].m_pInstanceData[j];
  585. pPassList[i].m_pInstanceData[j] = NULL;
  586. }
  587. }
  588. }
  589. if ( IsGameConsole() ||
  590. !( MaterialSystem()->GetConfigurationFlags() &
  591. ( MATCONFIG_FLAGS_SUPPORT_GBUFFER | MATCONFIG_FLAGS_SUPPORT_EDITOR ) ) )
  592. {
  593. StandardRenderStateList_t *pList = (StandardRenderStateList_t*)pPassList;
  594. delete pList;
  595. }
  596. #ifndef _GAMECONSOLE
  597. else
  598. {
  599. EditorRenderStateList_t *pList = (EditorRenderStateList_t*)pPassList;
  600. delete pList;
  601. }
  602. #endif
  603. }
  604. //-----------------------------------------------------------------------------
  605. // Gets the renderstate
  606. //-----------------------------------------------------------------------------
  607. ShaderRenderState_t *CMaterial::GetRenderState()
  608. {
  609. Precache_Inline();
  610. return &m_ShaderRenderState;
  611. }
  612. //-----------------------------------------------------------------------------
  613. // Returns a dummy material variable
  614. //-----------------------------------------------------------------------------
  615. IMaterialVar* CMaterial::GetDummyVariable()
  616. {
  617. static IMaterialVar* pDummyVar = 0;
  618. if (!pDummyVar)
  619. pDummyVar = IMaterialVar::Create( 0, "$dummyVar", 0 );
  620. return pDummyVar;
  621. }
  622. //-----------------------------------------------------------------------------
  623. // Cleans up shader parameters
  624. //-----------------------------------------------------------------------------
  625. void CMaterial::CleanUpShaderParams()
  626. {
  627. if( m_pShaderParams )
  628. {
  629. for (int i = 0; i < m_VarCount; ++i)
  630. {
  631. IMaterialVar::Destroy( m_pShaderParams[i] );
  632. }
  633. free( m_pShaderParams );
  634. m_pShaderParams = 0;
  635. }
  636. m_VarCount = 0;
  637. }
  638. //-----------------------------------------------------------------------------
  639. // Initializes the material proxy
  640. //-----------------------------------------------------------------------------
  641. void CMaterial::InitializeMaterialProxy( KeyValues* pFallbackKeyValues )
  642. {
  643. IMaterialProxyFactory *pMaterialProxyFactory;
  644. pMaterialProxyFactory = MaterialSystem()->GetMaterialProxyFactory();
  645. if( !pMaterialProxyFactory )
  646. return;
  647. // See if we've got a proxy section; obey fallbacks
  648. KeyValues* pProxySection = pFallbackKeyValues->FindKey("Proxies");
  649. if (!pProxySection)
  650. return;
  651. // Iterate through the section + create all of the proxies
  652. int proxyCount = 0;
  653. IMaterialProxy* ppProxies[256];
  654. KeyValues* pProxyKey = pProxySection->GetFirstSubKey();
  655. for ( ; pProxyKey; pProxyKey = pProxyKey->GetNextKey() )
  656. {
  657. // Each of the proxies should themselves be databases
  658. IMaterialProxy* pProxy = pMaterialProxyFactory->CreateProxy( pProxyKey->GetName() );
  659. if (!pProxy)
  660. {
  661. Warning( "Error: Material \"%s\" : proxy \"%s\" not found!\n", GetName(), pProxyKey->GetName() );
  662. continue;
  663. }
  664. if (!pProxy->Init( this->GetQueueFriendlyVersion(), pProxyKey ))
  665. {
  666. pMaterialProxyFactory->DeleteProxy( pProxy );
  667. Warning( "Error: Material \"%s\" : proxy \"%s\" unable to initialize!\n", GetName(), pProxyKey->GetName() );
  668. }
  669. else
  670. {
  671. ppProxies[proxyCount] = pProxy;
  672. ++proxyCount;
  673. if ( proxyCount >= ARRAYSIZE( ppProxies ) )
  674. {
  675. Warning( "Error: Material \"%s\" has more than %lu proxies!\n", GetName(), ( unsigned long )ARRAYSIZE( ppProxies ) );
  676. break;
  677. }
  678. }
  679. }
  680. // Allocate space for the number of proxies we successfully made...
  681. m_ProxyCount = proxyCount;
  682. if (proxyCount)
  683. {
  684. m_ppProxies = (IMaterialProxy**)malloc( proxyCount * sizeof(IMaterialProxy*) );
  685. memcpy( m_ppProxies, ppProxies, proxyCount * sizeof(IMaterialProxy*) );
  686. }
  687. else
  688. {
  689. m_ppProxies = 0;
  690. }
  691. }
  692. //-----------------------------------------------------------------------------
  693. // Cleans up the material proxy
  694. //-----------------------------------------------------------------------------
  695. void CMaterial::CleanUpMaterialProxy()
  696. {
  697. if ( !m_ProxyCount )
  698. return;
  699. IMaterialProxyFactory *pMaterialProxyFactory;
  700. pMaterialProxyFactory = MaterialSystem()->GetMaterialProxyFactory();
  701. if ( !pMaterialProxyFactory )
  702. return;
  703. // Clean up material proxies
  704. for ( int i = m_ProxyCount; --i >= 0; )
  705. {
  706. pMaterialProxyFactory->DeleteProxy( m_ppProxies[i] );
  707. }
  708. free( m_ppProxies );
  709. m_ppProxies = NULL;
  710. m_ProxyCount = 0;
  711. }
  712. static char const *GetVarName( KeyValues *pVar )
  713. {
  714. char const *pVarName = pVar->GetName();
  715. char const *pQuestion = strchr( pVarName, '?' );
  716. if (! pQuestion )
  717. return pVarName;
  718. else
  719. return pQuestion + 1;
  720. }
  721. //-----------------------------------------------------------------------------
  722. // Finds the index of the material var associated with a var
  723. //-----------------------------------------------------------------------------
  724. static int FindMaterialVar( IShader* pShader, char const* pVarName )
  725. {
  726. if ( !pShader )
  727. return -1;
  728. // Strip preceeding spaces
  729. pVarName += strspn( pVarName, " \t" );
  730. for (int i = pShader->GetParamCount(); --i >= 0; )
  731. {
  732. // Makes the parser a little more lenient.. strips off bogus spaces in the var name.
  733. const char *pParamName = pShader->GetParamInfo(i).m_pName;
  734. const char *pFound = Q_stristr( pVarName, pParamName );
  735. // The found string had better start with the first non-whitespace character
  736. if ( pFound != pVarName )
  737. continue;
  738. // Strip spaces at the end
  739. int nLen = Q_strlen( pParamName );
  740. pFound += nLen;
  741. while ( true )
  742. {
  743. if ( !pFound[0] )
  744. return i;
  745. if ( !IsWhitespace( pFound[0] ) )
  746. break;
  747. ++pFound;
  748. }
  749. }
  750. return -1;
  751. }
  752. //-----------------------------------------------------------------------------
  753. // Creates a vector material var
  754. //-----------------------------------------------------------------------------
  755. int ParseVectorFromKeyValueString( KeyValues *pKeyValue, const char *pMaterialName, float vecVal[4] )
  756. {
  757. char const* pScan = pKeyValue->GetString();
  758. bool divideBy255 = false;
  759. // skip whitespace
  760. while( IsWhitespace(*pScan) )
  761. {
  762. ++pScan;
  763. }
  764. if( *pScan == '{' )
  765. {
  766. divideBy255 = true;
  767. }
  768. else
  769. {
  770. Assert( *pScan == '[' );
  771. }
  772. // skip the '['
  773. ++pScan;
  774. int i;
  775. for( i = 0; i < 4; i++ )
  776. {
  777. // skip whitespace
  778. while( IsWhitespace(*pScan) )
  779. {
  780. ++pScan;
  781. }
  782. if( IsEndline(*pScan) || *pScan == ']' || *pScan == '}' )
  783. {
  784. if (*pScan != ']' && *pScan != '}')
  785. {
  786. Warning( "Warning in .VMT file (%s): no ']' or '}' found in vector key \"%s\".\n"
  787. "Did you forget to surround the vector with \"s?\n", pMaterialName, pKeyValue->GetName() );
  788. }
  789. // allow for vec2's, etc.
  790. vecVal[i] = 0.0f;
  791. break;
  792. }
  793. char* pEnd;
  794. vecVal[i] = strtod( pScan, &pEnd );
  795. if (pScan == pEnd)
  796. {
  797. Warning( "Error in .VMT file: error parsing vector element \"%s\" in \"%s\"\n", pKeyValue->GetName(), pMaterialName );
  798. return 0;
  799. }
  800. pScan = pEnd;
  801. }
  802. if( divideBy255 )
  803. {
  804. vecVal[0] *= ( 1.0f / 255.0f );
  805. vecVal[1] *= ( 1.0f / 255.0f );
  806. vecVal[2] *= ( 1.0f / 255.0f );
  807. vecVal[3] *= ( 1.0f / 255.0f );
  808. }
  809. return i;
  810. }
  811. static IMaterialVar* CreateVectorMaterialVarFromKeyValue( IMaterial* pMaterial, KeyValues* pKeyValue )
  812. {
  813. char const *pszName = GetVarName( pKeyValue );
  814. float vecVal[4];
  815. int nDim = ParseVectorFromKeyValueString( pKeyValue, pszName, vecVal );
  816. if ( nDim == 0 )
  817. return NULL;
  818. // Create the variable!
  819. return IMaterialVar::Create( pMaterial, pszName, vecVal, nDim );
  820. }
  821. //-----------------------------------------------------------------------------
  822. // Creates a vector material var
  823. //-----------------------------------------------------------------------------
  824. static IMaterialVar* CreateMatrixMaterialVarFromKeyValue( IMaterial* pMaterial, KeyValues* pKeyValue )
  825. {
  826. char const* pScan = pKeyValue->GetString();
  827. char const *pszName = GetVarName( pKeyValue );
  828. // Matrices can be specified one of two ways:
  829. // [ # # # # # # # # # # # # # # # # ]
  830. // or
  831. // center # # scale # # rotate # translate # #
  832. VMatrix mat;
  833. int count = sscanf( pScan, " [ %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f ]",
  834. &mat.m[0][0], &mat.m[0][1], &mat.m[0][2], &mat.m[0][3],
  835. &mat.m[1][0], &mat.m[1][1], &mat.m[1][2], &mat.m[1][3],
  836. &mat.m[2][0], &mat.m[2][1], &mat.m[2][2], &mat.m[2][3],
  837. &mat.m[3][0], &mat.m[3][1], &mat.m[3][2], &mat.m[3][3] );
  838. if (count == 16)
  839. {
  840. return IMaterialVar::Create( pMaterial, pszName, mat );
  841. }
  842. Vector2D scale, center;
  843. float angle;
  844. Vector2D translation;
  845. //scan for pre-rotation scale and translation with assumed center syntax
  846. count = sscanf( pScan, " scale %f %f translate %f %f rotate %f",
  847. &scale.x, &scale.y, &translation.x, &translation.y, &angle );
  848. if (count == 5)
  849. {
  850. VMatrix temp;
  851. MatrixBuildTranslation( mat, translation.x - 0.5, translation.y - 0.5, 0.0f );
  852. MatrixBuildScale( temp, scale.x, scale.y, 1.0f );
  853. MatrixMultiply( mat, temp, mat );
  854. MatrixBuildRotateZ( temp, angle );
  855. MatrixMultiply( mat, temp, mat );
  856. Vector2D vOffset;
  857. vOffset.Init( 0.5f / ( scale.x != 0 ? scale.x : 1.0 ), 0.5f / ( scale.y != 0 ? scale.y : 1.0 ) );
  858. Vector2DRotate( vOffset, -angle, vOffset );
  859. MatrixBuildTranslation( temp, vOffset.x, vOffset.y, 0.0f );
  860. MatrixMultiply( mat, temp, mat );
  861. return IMaterialVar::Create( pMaterial, pszName, mat );
  862. }
  863. count = sscanf( pScan, " center %f %f scale %f %f rotate %f translate %f %f",
  864. &center.x, &center.y, &scale.x, &scale.y, &angle, &translation.x, &translation.y );
  865. if (count != 7)
  866. return NULL;
  867. VMatrix temp;
  868. MatrixBuildTranslation( mat, -center.x, -center.y, 0.0f );
  869. MatrixBuildScale( temp, scale.x, scale.y, 1.0f );
  870. MatrixMultiply( temp, mat, mat );
  871. MatrixBuildRotateZ( temp, angle );
  872. MatrixMultiply( temp, mat, mat );
  873. MatrixBuildTranslation( temp, center.x + translation.x, center.y + translation.y, 0.0f );
  874. MatrixMultiply( temp, mat, mat );
  875. // Create the variable!
  876. return IMaterialVar::Create( pMaterial, pszName, mat );
  877. }
  878. //-----------------------------------------------------------------------------
  879. // Creates a material var from a key value
  880. //-----------------------------------------------------------------------------
  881. static IMaterialVar* CreateMaterialVarFromKeyValue( IMaterial* pMaterial, KeyValues* pKeyValue )
  882. {
  883. char const *pszName = GetVarName( pKeyValue );
  884. switch( pKeyValue->GetDataType() )
  885. {
  886. case KeyValues::TYPE_INT:
  887. return IMaterialVar::Create( pMaterial, pszName, pKeyValue->GetInt() );
  888. case KeyValues::TYPE_FLOAT:
  889. return IMaterialVar::Create( pMaterial, pszName, pKeyValue->GetFloat() );
  890. case KeyValues::TYPE_STRING:
  891. {
  892. char const* pString = pKeyValue->GetString();
  893. if (!pString || !pString[0])
  894. return 0;
  895. // Look for matrices
  896. IMaterialVar *pMatrixVar = CreateMatrixMaterialVarFromKeyValue( pMaterial, pKeyValue );
  897. if (pMatrixVar)
  898. return pMatrixVar;
  899. // Look for vectors
  900. if (!IsVector(pString))
  901. return IMaterialVar::Create( pMaterial, pszName, pString );
  902. // Parse the string as a vector...
  903. return CreateVectorMaterialVarFromKeyValue( pMaterial, pKeyValue );
  904. }
  905. }
  906. return 0;
  907. }
  908. //-----------------------------------------------------------------------------
  909. // Reads out common flags, prevents them from becoming material vars
  910. //-----------------------------------------------------------------------------
  911. int CMaterial::FindMaterialVarFlag( char const* pFlagName ) const
  912. {
  913. // Strip preceeding spaces
  914. while ( pFlagName[0] )
  915. {
  916. if ( !IsWhitespace( pFlagName[0] ) )
  917. break;
  918. ++pFlagName;
  919. }
  920. for( int i = 0; *ShaderSystem()->ShaderStateString(i); ++i )
  921. {
  922. const char *pStateString = ShaderSystem()->ShaderStateString(i);
  923. const char *pFound = Q_stristr( pFlagName, pStateString );
  924. // The found string had better start with the first non-whitespace character
  925. if ( pFound != pFlagName )
  926. continue;
  927. // Strip spaces at the end
  928. int nLen = Q_strlen( pStateString );
  929. pFound += nLen;
  930. while ( true )
  931. {
  932. if ( !pFound[0] )
  933. return (1 << i);
  934. if ( !IsWhitespace( pFound[0] ) )
  935. break;
  936. ++pFound;
  937. }
  938. }
  939. return 0;
  940. }
  941. //-----------------------------------------------------------------------------
  942. // Print material flags
  943. //-----------------------------------------------------------------------------
  944. void CMaterial::PrintMaterialFlags( int flags, int flagsDefined )
  945. {
  946. int i;
  947. for( i = 0; *ShaderSystem()->ShaderStateString(i); i++ )
  948. {
  949. if( flags & ( 1<<i ) )
  950. {
  951. Warning( "%s|", ShaderSystem()->ShaderStateString(i) );
  952. }
  953. }
  954. Warning( "\n" );
  955. }
  956. //-----------------------------------------------------------------------------
  957. // Parses material flags
  958. //-----------------------------------------------------------------------------
  959. bool CMaterial::ParseMaterialFlag( KeyValues* pParseValue, IMaterialVar* pFlagVar,
  960. IMaterialVar* pFlagDefinedVar, bool parsingOverrides, int& flagMask, int& overrideMask )
  961. {
  962. // See if the var is a flag...
  963. int flagbit = FindMaterialVarFlag( GetVarName( pParseValue ) );
  964. if (!flagbit)
  965. return false;
  966. // Allow for flag override
  967. int testMask = parsingOverrides ? overrideMask : flagMask;
  968. if (testMask & flagbit)
  969. {
  970. Warning("Error! Flag \"%s\" is multiply defined in material \"%s\"!\n", pParseValue->GetName(), GetName() );
  971. return true;
  972. }
  973. // Make sure overrides win
  974. if (overrideMask & flagbit)
  975. return true;
  976. if (parsingOverrides)
  977. overrideMask |= flagbit;
  978. else
  979. flagMask |= flagbit;
  980. // If so, then set the flag bit
  981. if (pParseValue->GetInt())
  982. pFlagVar->SetIntValue( pFlagVar->GetIntValue() | flagbit );
  983. else
  984. pFlagVar->SetIntValue( pFlagVar->GetIntValue() & (~flagbit) );
  985. // Mark the flag as being defined
  986. pFlagDefinedVar->SetIntValue( pFlagDefinedVar->GetIntValue() | flagbit );
  987. /*
  988. if( stristr( m_pDebugName, "glasswindow064a" ) )
  989. {
  990. Warning( "flags\n" );
  991. PrintMaterialFlags( pFlagVar->GetIntValue(), pFlagDefinedVar->GetIntValue() );
  992. }
  993. */
  994. return true;
  995. }
  996. ConVar mat_reduceparticles( "mat_reduceparticles", "0" );
  997. extern ConVar gpu_level;
  998. bool CMaterial::ShouldSkipVar( KeyValues *pVar, bool *pWasConditional )
  999. {
  1000. char const *pVarName = pVar->GetName();
  1001. char const *pQuestion = strchr( pVarName, '?' );
  1002. if ( ( ! pQuestion ) || (pQuestion == pVarName ) )
  1003. {
  1004. *pWasConditional = false; // unconditional var
  1005. return false;
  1006. }
  1007. else
  1008. {
  1009. bool bShouldSkip = true;
  1010. *pWasConditional = true;
  1011. // parse the conditional part
  1012. char pszConditionName[256];
  1013. V_strncpy( pszConditionName, pVarName, 1+pQuestion-pVarName );
  1014. char const *pCond = pszConditionName;
  1015. bool bToggle = false;
  1016. if ( pCond[0] == '!' )
  1017. {
  1018. pCond++;
  1019. bToggle = true;
  1020. }
  1021. if ( ! stricmp( pCond, "lowfill" ) )
  1022. {
  1023. bShouldSkip = !mat_reduceparticles.GetBool();
  1024. }
  1025. else if ( ! stricmp( pCond, "hdr" ) )
  1026. {
  1027. bShouldSkip = ( HardwareConfig()->GetHDRType() == HDR_TYPE_NONE );
  1028. }
  1029. else if ( ! stricmp( pCond, "srgb" ) )
  1030. {
  1031. bShouldSkip = ( !HardwareConfig()->UsesSRGBCorrectBlending() );
  1032. }
  1033. else if ( ! stricmp( pCond, "srgb_gameconsole" ) )
  1034. {
  1035. bShouldSkip = !( HardwareConfig()->UsesSRGBCorrectBlending() && IsGameConsole() );
  1036. }
  1037. else if ( ! stricmp( pCond, "srgb_pc" ) )
  1038. {
  1039. bShouldSkip = !( HardwareConfig()->UsesSRGBCorrectBlending() && IsPC() );
  1040. }
  1041. else if ( ! stricmp( pCond, "ldr" ) )
  1042. {
  1043. bShouldSkip = ( HardwareConfig()->GetHDRType() != HDR_TYPE_NONE );
  1044. }
  1045. else if ( ! stricmp( pCond, "GPU>=3" ) )
  1046. {
  1047. bShouldSkip = gpu_level.GetInt() < 3;
  1048. }
  1049. else if ( ! stricmp( pCond, "GPU>=2" ) )
  1050. {
  1051. bShouldSkip = gpu_level.GetInt() < 2;
  1052. }
  1053. else if ( ! stricmp( pCond, "GPU>=1" ) )
  1054. {
  1055. bShouldSkip = gpu_level.GetInt() < 1;
  1056. }
  1057. else if ( ! stricmp( pCond, "GPU<2" ) )
  1058. {
  1059. bShouldSkip = gpu_level.GetInt() >= 2;
  1060. }
  1061. else if ( ! stricmp( pCond, "GPU<3" ) )
  1062. {
  1063. bShouldSkip = gpu_level.GetInt() >= 3;
  1064. }
  1065. else if ( ! stricmp( pCond, "GPU<1" ) )
  1066. {
  1067. bShouldSkip = gpu_level.GetInt() >= 1;
  1068. }
  1069. else if ( ! stricmp( pCond, "360" ) )
  1070. {
  1071. bShouldSkip = !IsX360();
  1072. }
  1073. else if ( ! stricmp( pCond, "SonyPS3" ) )
  1074. {
  1075. bShouldSkip = !IsPS3();
  1076. }
  1077. else if ( ! stricmp( pCond, "gameconsole" ) )
  1078. {
  1079. bShouldSkip = !IsGameConsole();
  1080. }
  1081. else if ( ! stricmp( pCond, "LowQualityCSM" ) )
  1082. {
  1083. bShouldSkip = HardwareConfig()->SupportsBilinearPCFSampling() && ( materials->GetCurrentConfigForVideoCard().GetCSMQualityMode() > CSMQUALITY_LOW );
  1084. }
  1085. else if ( ! stricmp( pCond, "HighQualityCSM" ) )
  1086. {
  1087. bShouldSkip = !HardwareConfig()->SupportsBilinearPCFSampling() || ( materials->GetCurrentConfigForVideoCard().GetCSMQualityMode() < CSMQUALITY_HIGH );
  1088. }
  1089. else
  1090. {
  1091. Warning( "unrecognized conditional test %s in %s\n", pVarName, GetName() );
  1092. }
  1093. return bShouldSkip ^ bToggle;
  1094. }
  1095. }
  1096. //-----------------------------------------------------------------------------
  1097. // Computes the material vars for the shader
  1098. //-----------------------------------------------------------------------------
  1099. int CMaterial::ParseMaterialVars( IShader* pShader, KeyValues& keyValues,
  1100. KeyValues* pOverrideKeyValues, bool modelDefault, IMaterialVar** ppVars )
  1101. {
  1102. IMaterialVar* pNewVar;
  1103. bool pOverride[256];
  1104. bool bWasConditional[256];
  1105. int overrideMask = 0;
  1106. int flagMask = 0;
  1107. memset( ppVars, 0, 256 * sizeof(IMaterialVar*) );
  1108. memset( pOverride, 0, sizeof( pOverride ) );
  1109. memset( bWasConditional, 0, sizeof( bWasConditional ) );
  1110. // Create the flag var...
  1111. // Set model mode if we fell back from a model mode shader
  1112. int modelFlag = modelDefault ? MATERIAL_VAR_MODEL : 0;
  1113. ppVars[FLAGS] = IMaterialVar::Create( this, "$flags", modelFlag );
  1114. ppVars[FLAGS_DEFINED] = IMaterialVar::Create( this, "$flags_defined", modelFlag );
  1115. ppVars[FLAGS2] = IMaterialVar::Create( this, "$flags2", 0 );
  1116. ppVars[FLAGS_DEFINED2] = IMaterialVar::Create( this, "$flags_defined2", 0 );
  1117. int numParams = pShader ? pShader->GetParamCount() : 0;
  1118. int varCount = numParams;
  1119. bool parsingOverrides = (pOverrideKeyValues != 0);
  1120. KeyValues* pVar = pOverrideKeyValues ? pOverrideKeyValues->GetFirstSubKey() : keyValues.GetFirstSubKey();
  1121. while( pVar )
  1122. {
  1123. bool bProcessThisOne = true;
  1124. bool bIsConditionalVar;
  1125. // See if the var is a flag...
  1126. if (
  1127. ShouldSkipVar( pVar, &bIsConditionalVar ) || // should skip?
  1128. ( ( pVar->GetName()[0] == '%' ) && ( g_pShaderDevice->IsUsingGraphics() ) && ( !MaterialSystem()->CanUseEditorMaterials() ) && !mat_processtoolvars.GetInt() ) || // is an editor var?
  1129. ParseMaterialFlag( pVar, ppVars[FLAGS], ppVars[FLAGS_DEFINED], parsingOverrides, flagMask, overrideMask ) || // is a flag?
  1130. ParseMaterialFlag( pVar, ppVars[FLAGS2], ppVars[FLAGS_DEFINED2], parsingOverrides, flagMask, overrideMask )
  1131. )
  1132. bProcessThisOne = false;
  1133. if ( bProcessThisOne )
  1134. {
  1135. // See if the var is one of the shader params
  1136. int varIdx = FindMaterialVar( pShader, GetVarName( pVar ) );
  1137. // Check for multiply defined or overridden
  1138. if (varIdx >= 0)
  1139. {
  1140. if (ppVars[varIdx] && (! bIsConditionalVar ) )
  1141. {
  1142. if ( !pOverride[varIdx] || parsingOverrides )
  1143. {
  1144. Warning("Error! Variable \"%s\" is multiply defined in material \"%s\"!\n", pVar->GetName(), GetName() );
  1145. }
  1146. goto nextVar;
  1147. }
  1148. }
  1149. else
  1150. {
  1151. int i;
  1152. for ( i = numParams; i < varCount; ++i)
  1153. {
  1154. Assert( ppVars[i] );
  1155. if (!stricmp( ppVars[i]->GetName(), pVar->GetName() ))
  1156. break;
  1157. }
  1158. if (i != varCount)
  1159. {
  1160. if ( !pOverride[i] || parsingOverrides )
  1161. {
  1162. Warning("Error! Variable \"%s\" is multiply defined in material \"%s\"!\n", pVar->GetName(), GetName() );
  1163. }
  1164. goto nextVar;
  1165. }
  1166. }
  1167. // Create a material var for this dudely dude; could be zero...
  1168. pNewVar = CreateMaterialVarFromKeyValue( this, pVar );
  1169. if (!pNewVar)
  1170. goto nextVar;
  1171. if (varIdx < 0)
  1172. {
  1173. varIdx = varCount++;
  1174. }
  1175. if ( ppVars[varIdx] )
  1176. {
  1177. IMaterialVar::Destroy( ppVars[varIdx] );
  1178. }
  1179. ppVars[varIdx] = pNewVar;
  1180. if (parsingOverrides)
  1181. pOverride[varIdx] = true;
  1182. bWasConditional[varIdx] = bIsConditionalVar;
  1183. }
  1184. nextVar:
  1185. pVar = pVar->GetNextKey();
  1186. if (!pVar && parsingOverrides)
  1187. {
  1188. pVar = keyValues.GetFirstSubKey();
  1189. parsingOverrides = false;
  1190. }
  1191. }
  1192. // Create undefined vars for all the actual material vars
  1193. for (int i = 0; i < numParams; ++i)
  1194. {
  1195. if (!ppVars[i])
  1196. ppVars[i] = IMaterialVar::Create( this, pShader->GetParamInfo(i).m_pName );
  1197. }
  1198. return varCount;
  1199. }
  1200. static KeyValues *CheckConditionalFakeShaderName( char const *pShaderName, char const *pSuffixName,
  1201. KeyValues *pKeyValues )
  1202. {
  1203. KeyValues *pFallbackSection = pKeyValues->FindKey( pSuffixName );
  1204. if (pFallbackSection)
  1205. return pFallbackSection;
  1206. char nameBuf[256];
  1207. V_snprintf( nameBuf, sizeof(nameBuf), "%s_%s", pShaderName, pSuffixName );
  1208. pFallbackSection = pKeyValues->FindKey( nameBuf );
  1209. if (pFallbackSection)
  1210. return pFallbackSection;
  1211. return NULL;
  1212. }
  1213. static KeyValues *FindBuiltinFallbackBlock( char const *pShaderName, KeyValues *pKeyValues )
  1214. {
  1215. // handle "fake" shader fallbacks which are conditional upon mode. like _hdr_dx9, etc
  1216. int nGPULevel = gpu_level.GetInt();
  1217. if ( nGPULevel < 1 )
  1218. {
  1219. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"GPU<1", pKeyValues );
  1220. if ( pRet )
  1221. return pRet;
  1222. }
  1223. if ( nGPULevel < 2 )
  1224. {
  1225. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"GPU<2", pKeyValues );
  1226. if ( pRet )
  1227. return pRet;
  1228. }
  1229. if ( nGPULevel >= 1 )
  1230. {
  1231. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"GPU>=1", pKeyValues );
  1232. if ( pRet )
  1233. return pRet;
  1234. }
  1235. if ( nGPULevel >= 2 )
  1236. {
  1237. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"GPU>=2", pKeyValues );
  1238. if ( pRet )
  1239. return pRet;
  1240. }
  1241. if ( HardwareConfig()->GetDXSupportLevel() < 90 )
  1242. {
  1243. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"<DX90", pKeyValues );
  1244. if ( pRet )
  1245. return pRet;
  1246. }
  1247. if ( HardwareConfig()->GetDXSupportLevel() < 95 )
  1248. {
  1249. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"<DX95", pKeyValues );
  1250. if ( pRet )
  1251. return pRet;
  1252. }
  1253. if ( HardwareConfig()->GetDXSupportLevel() < 92 )
  1254. {
  1255. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"<DX90_20b", pKeyValues );
  1256. if ( pRet )
  1257. return pRet;
  1258. }
  1259. if ( HardwareConfig()->GetDXSupportLevel() >= 92 )
  1260. {
  1261. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,">=DX90_20b", pKeyValues );
  1262. if ( pRet )
  1263. return pRet;
  1264. }
  1265. if ( HardwareConfig()->GetDXSupportLevel() <= 90 )
  1266. {
  1267. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"<=DX90", pKeyValues );
  1268. if ( pRet )
  1269. return pRet;
  1270. }
  1271. if ( HardwareConfig()->GetDXSupportLevel() >= 90 )
  1272. {
  1273. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,">=DX90", pKeyValues );
  1274. if ( pRet )
  1275. return pRet;
  1276. }
  1277. if ( HardwareConfig()->GetDXSupportLevel() > 90 )
  1278. {
  1279. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,">DX90", pKeyValues );
  1280. if ( pRet )
  1281. return pRet;
  1282. }
  1283. if ( HardwareConfig()->GetHDRType() != HDR_TYPE_NONE )
  1284. {
  1285. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"hdr_dx9", pKeyValues );
  1286. if ( pRet )
  1287. return pRet;
  1288. pRet = CheckConditionalFakeShaderName( pShaderName,"hdr", pKeyValues );
  1289. if ( pRet )
  1290. return pRet;
  1291. }
  1292. else
  1293. {
  1294. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"ldr", pKeyValues );
  1295. if ( pRet )
  1296. return pRet;
  1297. }
  1298. if ( HardwareConfig()->UsesSRGBCorrectBlending() )
  1299. {
  1300. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"srgb", pKeyValues );
  1301. if ( pRet )
  1302. return pRet;
  1303. }
  1304. if ( HardwareConfig()->GetDXSupportLevel() >= 90 )
  1305. {
  1306. KeyValues *pRet = CheckConditionalFakeShaderName( pShaderName,"dx9", pKeyValues );
  1307. if ( pRet )
  1308. return pRet;
  1309. }
  1310. return NULL;
  1311. }
  1312. //-----------------------------------------------------------------------------
  1313. // Hooks up the shader
  1314. //-----------------------------------------------------------------------------
  1315. KeyValues* CMaterial::InitializeShader( KeyValues &keyValues, KeyValues &patchKeyValues )
  1316. {
  1317. MaterialLock_t hMaterialLock = MaterialSystem()->Lock();
  1318. KeyValues* pCurrentFallback = &keyValues;
  1319. KeyValues* pFallbackSection = 0;
  1320. char szShaderName[MAX_PATH];
  1321. char const* pShaderName = pCurrentFallback->GetName();
  1322. if ( !pShaderName )
  1323. {
  1324. // I'm not quite sure how this can happen, but we'll see...
  1325. Warning( "Shader not specified in material %s\nUsing wireframe instead...\n", GetName() );
  1326. Assert( 0 );
  1327. pShaderName = "Wireframe_DX9";
  1328. }
  1329. else
  1330. {
  1331. // can't pass a stable reference to the key values name around
  1332. // naive leaf functions can cause KV system to re-alloc
  1333. V_strncpy( szShaderName, pShaderName, sizeof( szShaderName ) );
  1334. pShaderName = szShaderName;
  1335. }
  1336. IShader* pShader;
  1337. IMaterialVar* ppVars[256];
  1338. char pFallbackShaderNameBuf[256];
  1339. char pFallbackMaterialNameBuf[256];
  1340. int varCount = 0;
  1341. bool modelDefault = false;
  1342. // Keep going until there's no more fallbacks...
  1343. while( true )
  1344. {
  1345. // Find the shader for this material. Note that this may not be
  1346. // the actual shader we use due to fallbacks...
  1347. pShader = ShaderSystem()->FindShader( pShaderName );
  1348. if ( !pShader )
  1349. {
  1350. if ( g_pShaderDevice->IsUsingGraphics() )
  1351. {
  1352. Warning( "Error: Material \"%s\" uses unknown shader \"%s\"\n", GetName(), pShaderName );
  1353. //hushed Assert( 0 );
  1354. }
  1355. pShaderName = "Wireframe_DX9";
  1356. pShader = ShaderSystem()->FindShader( pShaderName );
  1357. AssertOnce( pShader );
  1358. }
  1359. #ifndef DEDICATED
  1360. if ( !pShader )
  1361. {
  1362. MaterialSystem()->Unlock( hMaterialLock );
  1363. return NULL;
  1364. }
  1365. #endif
  1366. bool bHasBuiltinFallbackBlock = false;
  1367. if ( !pFallbackSection )
  1368. {
  1369. pFallbackSection = FindBuiltinFallbackBlock( pShaderName, &keyValues );
  1370. if( pFallbackSection )
  1371. {
  1372. bHasBuiltinFallbackBlock = true;
  1373. pFallbackSection->ChainKeyValue( &keyValues );
  1374. pCurrentFallback = pFallbackSection;
  1375. }
  1376. }
  1377. // Here we must set up all flags + material vars that the shader needs
  1378. // because it may look at them when choosing shader fallback.
  1379. varCount = ParseMaterialVars( pShader, keyValues, pFallbackSection, modelDefault, ppVars );
  1380. if ( !pShader )
  1381. break;
  1382. // Make sure we set default values before the fallback is looked for
  1383. ShaderSystem()->InitShaderParameters( pShader, ppVars, GetName() );
  1384. // Now that the material vars are parsed, see if there's a fallback
  1385. // But only if we're not in the tools
  1386. /*
  1387. if (!g_pShaderAPI->IsUsingGraphics())
  1388. break;
  1389. */
  1390. // Check for a fallback; if not, we're done
  1391. pShaderName = pShader->GetFallbackShader( ppVars );
  1392. if (!pShaderName)
  1393. {
  1394. break;
  1395. }
  1396. // Copy off the shader name, as it may be in a materialvar in the shader
  1397. // because we're about to delete all materialvars
  1398. Q_strncpy( pFallbackShaderNameBuf, pShaderName, 256 );
  1399. pShaderName = pFallbackShaderNameBuf;
  1400. // Remember the model flag if we're on dx7 or higher...
  1401. modelDefault = ( ppVars[FLAGS]->GetIntValue() & MATERIAL_VAR_MODEL ) != 0;
  1402. // Try to get the section associated with the fallback shader
  1403. // Then chain it to the base data so it can override the
  1404. // values if it wants to
  1405. if( !bHasBuiltinFallbackBlock )
  1406. {
  1407. pFallbackSection = keyValues.FindKey( pShaderName );
  1408. if (pFallbackSection)
  1409. {
  1410. pFallbackSection->ChainKeyValue( &keyValues );
  1411. pCurrentFallback = pFallbackSection;
  1412. }
  1413. }
  1414. // Now, blow away all of the material vars + try again...
  1415. for (int i = 0; i < varCount; ++i)
  1416. {
  1417. Assert( ppVars[i] );
  1418. IMaterialVar::Destroy( ppVars[i] );
  1419. }
  1420. // Check the KeyValues for '$fallbackmaterial'
  1421. // Note we have to do this *after* we chain the keyvalues
  1422. // based on the fallback shader since the names of the fallback material
  1423. // must lie within the shader-specific block usually.
  1424. const char *pFallbackMaterial = pCurrentFallback->GetString( "$fallbackmaterial" );
  1425. if ( pFallbackMaterial[0] )
  1426. {
  1427. // Don't fallback to ourselves
  1428. if ( Q_stricmp( GetName(), pFallbackMaterial ) )
  1429. {
  1430. // Gotta copy it off; clearing the keyvalues will blow the string away
  1431. Q_strncpy( pFallbackMaterialNameBuf, pFallbackMaterial, 256 );
  1432. keyValues.Clear();
  1433. if( !LoadVMTFile( keyValues, patchKeyValues, pFallbackMaterialNameBuf, UsesUNCFileName(), NULL ) )
  1434. {
  1435. Warning( "CMaterial::PrecacheVars: error loading vmt file %s for %s\n", pFallbackMaterialNameBuf, GetName() );
  1436. keyValues = *(((CMaterial *)g_pErrorMaterial)->m_pVMTKeyValues);
  1437. }
  1438. }
  1439. else
  1440. {
  1441. Warning( "CMaterial::PrecacheVars: fallback material for vmt file %s is itself!\n", GetName() );
  1442. keyValues = *(((CMaterial *)g_pErrorMaterial)->m_pVMTKeyValues);
  1443. }
  1444. pCurrentFallback = &keyValues;
  1445. pFallbackSection = NULL;
  1446. // I'm not quite sure how this can happen, but we'll see...
  1447. pShaderName = pCurrentFallback->GetName();
  1448. if (!pShaderName)
  1449. {
  1450. Warning("Shader not specified in material %s (fallback %s)\nUsing wireframe instead...\n", GetName(), pFallbackMaterialNameBuf );
  1451. pShaderName = "Wireframe_DX9";
  1452. }
  1453. }
  1454. }
  1455. // Store off the shader
  1456. m_pShader = pShader;
  1457. // Store off the material vars + flags
  1458. m_VarCount = varCount;
  1459. m_pShaderParams = (IMaterialVar**)malloc( varCount * sizeof(IMaterialVar*) );
  1460. memcpy( m_pShaderParams, ppVars, varCount * sizeof(IMaterialVar*) );
  1461. #ifdef _DEBUG
  1462. for (int i = 0; i < varCount; ++i)
  1463. {
  1464. Assert( ppVars[i] );
  1465. }
  1466. #endif
  1467. MaterialSystem()->Unlock( hMaterialLock );
  1468. return pCurrentFallback;
  1469. }
  1470. //-----------------------------------------------------------------------------
  1471. // Gets the texturemap size
  1472. //-----------------------------------------------------------------------------
  1473. void CMaterial::PrecacheMappingDimensions( )
  1474. {
  1475. // Adding support for mapping width override. To be used sparingly.
  1476. bool bFound;
  1477. IMaterialVar *pMappingWidthVar = FindVar( "$mappingwidth", &bFound, false );
  1478. if ( bFound && pMappingWidthVar->GetIntValue() > 0 )
  1479. {
  1480. IMaterialVar *pMappingHeightVar = FindVar( "$mappingheight", &bFound, false );
  1481. if ( bFound && pMappingHeightVar->GetIntValue() > 0 )
  1482. {
  1483. m_MappingWidth = pMappingWidthVar->GetIntValue();
  1484. m_MappingHeight = pMappingHeightVar->GetIntValue();
  1485. return;
  1486. }
  1487. }
  1488. // Cache mapping width and mapping height
  1489. if (!m_representativeTexture)
  1490. {
  1491. #ifdef PARANOID
  1492. Warning( "No representative texture on material: \"%s\"\n", GetName() );
  1493. #endif
  1494. m_MappingWidth = 64;
  1495. m_MappingHeight = 64;
  1496. }
  1497. else
  1498. {
  1499. m_MappingWidth = m_representativeTexture->GetMappingWidth();
  1500. m_MappingHeight = m_representativeTexture->GetMappingHeight();
  1501. }
  1502. }
  1503. //-----------------------------------------------------------------------------
  1504. // Initialize the state snapshot
  1505. //-----------------------------------------------------------------------------
  1506. bool CMaterial::InitializeStateSnapshots()
  1507. {
  1508. if (IsPrecached())
  1509. {
  1510. // Default state
  1511. CleanUpStateSnapshots();
  1512. if ( m_pShader && !ShaderSystem()->InitRenderState( m_pShader, m_VarCount, m_pShaderParams, &m_ShaderRenderState, GetName() ))
  1513. {
  1514. m_Flags &= ~MATERIAL_VALID_RENDERSTATE;
  1515. return false;
  1516. }
  1517. m_Flags |= MATERIAL_VALID_RENDERSTATE;
  1518. }
  1519. return true;
  1520. }
  1521. void CMaterial::CleanUpStateSnapshots()
  1522. {
  1523. if (IsValidRenderState())
  1524. {
  1525. ShaderSystem()->CleanupRenderState(&m_ShaderRenderState);
  1526. // -- THIS CANNOT BE HERE: m_Flags &= ~MATERIAL_VALID_RENDERSTATE;
  1527. // -- because it will cause a crash when main thread asks for material
  1528. // -- sort group it can temporarily see material in invalid render state
  1529. // -- and crash in DecalSurfaceAdd(msurface2_t*, int)
  1530. }
  1531. }
  1532. //-----------------------------------------------------------------------------
  1533. // This sets up a debugging/error shader...
  1534. //-----------------------------------------------------------------------------
  1535. void CMaterial::SetupErrorShader()
  1536. {
  1537. // Preserve the model flags
  1538. int flags = 0;
  1539. if ( m_pShaderParams && m_pShaderParams[FLAGS] )
  1540. {
  1541. flags = (m_pShaderParams[FLAGS]->GetIntValue() & MATERIAL_VAR_MODEL);
  1542. }
  1543. CleanUpShaderParams();
  1544. CleanUpMaterialProxy();
  1545. // We had a failure; replace it with a valid shader...
  1546. m_pShader = ShaderSystem()->FindShader( "Wireframe_DX9" );
  1547. Assert( m_pShader );
  1548. // Create undefined vars for all the actual material vars
  1549. m_VarCount = m_pShader->GetParamCount();
  1550. m_pShaderParams = (IMaterialVar**)malloc( m_VarCount * sizeof(IMaterialVar*) );
  1551. for (int i = 0; i < m_VarCount; ++i)
  1552. {
  1553. m_pShaderParams[i] = IMaterialVar::Create( this, m_pShader->GetParamInfo(i).m_pName );
  1554. }
  1555. // Store the model flags
  1556. SetMaterialVarFlags( flags, true );
  1557. // Set the default values
  1558. ShaderSystem()->InitShaderParameters( m_pShader, m_pShaderParams, "Error" );
  1559. // Invokes the SHADER_INIT block in the various shaders,
  1560. ShaderSystem()->InitShaderInstance( m_pShader, m_pShaderParams, "Error", GetTextureGroupName() );
  1561. #ifdef DBGFLAG_ASSERT
  1562. bool ok =
  1563. #endif
  1564. InitializeStateSnapshots();
  1565. m_QueueFriendlyVersion.UpdateToRealTime();
  1566. Assert(ok);
  1567. }
  1568. //-----------------------------------------------------------------------------
  1569. // This computes the state snapshots for this material
  1570. //-----------------------------------------------------------------------------
  1571. void CMaterial::RecomputeStateSnapshots()
  1572. {
  1573. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1574. if ( pCallQueue )
  1575. {
  1576. pCallQueue->QueueCall( this, &CMaterial::RecomputeStateSnapshots );
  1577. return;
  1578. }
  1579. bool ok = InitializeStateSnapshots();
  1580. // compute the state snapshots
  1581. if (!ok)
  1582. {
  1583. SetupErrorShader();
  1584. }
  1585. }
  1586. //-----------------------------------------------------------------------------
  1587. // Are we valid
  1588. //-----------------------------------------------------------------------------
  1589. inline bool CMaterial::IsValidRenderState() const
  1590. {
  1591. return (m_Flags & MATERIAL_VALID_RENDERSTATE) != 0;
  1592. }
  1593. //-----------------------------------------------------------------------------
  1594. // Gets/sets material var flags
  1595. //-----------------------------------------------------------------------------
  1596. inline int CMaterial::GetMaterialVarFlags() const
  1597. {
  1598. if ( m_pShaderParams && m_pShaderParams[FLAGS] )
  1599. {
  1600. return m_pShaderParams[FLAGS]->GetIntValueFast();
  1601. }
  1602. else
  1603. {
  1604. return 0;
  1605. }
  1606. }
  1607. inline void CMaterial::SetMaterialVarFlags( int flags, bool on )
  1608. {
  1609. if (on)
  1610. m_pShaderParams[FLAGS]->SetIntValue( GetMaterialVarFlags() | flags );
  1611. else
  1612. m_pShaderParams[FLAGS]->SetIntValue( GetMaterialVarFlags() & (~flags) );
  1613. // Mark it as being defined...
  1614. m_pShaderParams[FLAGS_DEFINED]->SetIntValue(
  1615. m_pShaderParams[FLAGS_DEFINED]->GetIntValueFast() | flags );
  1616. }
  1617. inline int CMaterial::GetMaterialVarFlags2() const
  1618. {
  1619. if ( m_pShaderParams && m_VarCount > FLAGS2 && m_pShaderParams[FLAGS2] )
  1620. {
  1621. return m_pShaderParams[FLAGS2]->GetIntValueFast();
  1622. }
  1623. else
  1624. {
  1625. return 0;
  1626. }
  1627. }
  1628. inline void CMaterial::SetMaterialVarFlags2( int flags, bool on )
  1629. {
  1630. if ( m_pShaderParams && m_VarCount > FLAGS2 && m_pShaderParams[FLAGS2] )
  1631. {
  1632. if (on)
  1633. m_pShaderParams[FLAGS2]->SetIntValue( GetMaterialVarFlags2() | flags );
  1634. else
  1635. m_pShaderParams[FLAGS2]->SetIntValue( GetMaterialVarFlags2() & (~flags) );
  1636. }
  1637. if ( m_pShaderParams && m_VarCount > FLAGS_DEFINED2 && m_pShaderParams[FLAGS_DEFINED2] )
  1638. {
  1639. // Mark it as being defined...
  1640. m_pShaderParams[FLAGS_DEFINED2]->SetIntValue(
  1641. m_pShaderParams[FLAGS_DEFINED2]->GetIntValueFast() | flags );
  1642. }
  1643. }
  1644. //-----------------------------------------------------------------------------
  1645. // Gets the vertex format
  1646. //-----------------------------------------------------------------------------
  1647. VertexFormat_t CMaterial::GetVertexFormat() const
  1648. {
  1649. Assert( IsValidRenderState() );
  1650. return m_ShaderRenderState.m_VertexFormat;
  1651. }
  1652. VertexFormat_t CMaterial::GetVertexUsage() const
  1653. {
  1654. Assert( IsValidRenderState() );
  1655. return m_ShaderRenderState.m_VertexUsage;
  1656. }
  1657. bool CMaterial::PerformDebugTrace() const
  1658. {
  1659. return IsValidRenderState() && ((GetMaterialVarFlags() & MATERIAL_VAR_DEBUG ) != 0);
  1660. }
  1661. //-----------------------------------------------------------------------------
  1662. // Are we suppressed?
  1663. //-----------------------------------------------------------------------------
  1664. bool CMaterial::IsSuppressed() const
  1665. {
  1666. if ( !IsValidRenderState() )
  1667. return true;
  1668. return ((GetMaterialVarFlags() & MATERIAL_VAR_NO_DRAW) != 0);
  1669. }
  1670. void CMaterial::ToggleSuppression()
  1671. {
  1672. if (IsValidRenderState())
  1673. {
  1674. if ((GetMaterialVarFlags() & MATERIAL_VAR_NO_DEBUG_OVERRIDE) != 0)
  1675. return;
  1676. SetMaterialVarFlags( MATERIAL_VAR_NO_DRAW,
  1677. (GetMaterialVarFlags() & MATERIAL_VAR_NO_DRAW) == 0 );
  1678. }
  1679. }
  1680. void CMaterial::ToggleDebugTrace()
  1681. {
  1682. if (IsValidRenderState())
  1683. {
  1684. SetMaterialVarFlags( MATERIAL_VAR_DEBUG,
  1685. (GetMaterialVarFlags() & MATERIAL_VAR_DEBUG) == 0 );
  1686. }
  1687. }
  1688. //-----------------------------------------------------------------------------
  1689. // Can we override this material in debug?
  1690. //-----------------------------------------------------------------------------
  1691. bool CMaterial::NoDebugOverride() const
  1692. {
  1693. return IsValidRenderState() && (GetMaterialVarFlags() & MATERIAL_VAR_NO_DEBUG_OVERRIDE) != 0;
  1694. }
  1695. //-----------------------------------------------------------------------------
  1696. // Material Var flags
  1697. //-----------------------------------------------------------------------------
  1698. void CMaterial::SetMaterialVarFlag( MaterialVarFlags_t flag, bool on )
  1699. {
  1700. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1701. if ( pCallQueue )
  1702. {
  1703. pCallQueue->QueueCall( this, &CMaterial::SetMaterialVarFlag, flag, on );
  1704. return;
  1705. }
  1706. bool oldOn = (GetMaterialVarFlags( ) & flag) != 0;
  1707. if (oldOn != on)
  1708. {
  1709. SetMaterialVarFlags( flag, on );
  1710. // This is going to be called from client code; recompute snapshots!
  1711. RecomputeStateSnapshots();
  1712. }
  1713. }
  1714. bool CMaterial::GetMaterialVarFlag( MaterialVarFlags_t flag ) const
  1715. {
  1716. return (GetMaterialVarFlags() & flag) != 0;
  1717. }
  1718. //-----------------------------------------------------------------------------
  1719. // Do we use the env_cubemap entity to get cubemaps from the level?
  1720. //-----------------------------------------------------------------------------
  1721. bool CMaterial::UsesEnvCubemap( void )
  1722. {
  1723. Precache_Inline();
  1724. AssertOnce( m_pShader );
  1725. if( !m_pShader )
  1726. {
  1727. return false;
  1728. }
  1729. Assert( m_pShaderParams );
  1730. return IsFlag2Set( m_pShaderParams, MATERIAL_VAR2_USES_ENV_CUBEMAP );
  1731. }
  1732. //-----------------------------------------------------------------------------
  1733. // Do we need a tangent space at the vertex level?
  1734. //-----------------------------------------------------------------------------
  1735. bool CMaterial::NeedsTangentSpace( void )
  1736. {
  1737. Precache_Inline();
  1738. AssertOnce( m_pShader );
  1739. if( !m_pShader )
  1740. {
  1741. return false;
  1742. }
  1743. Assert( m_pShaderParams );
  1744. return IsFlag2Set( m_pShaderParams, MATERIAL_VAR2_NEEDS_TANGENT_SPACES );
  1745. }
  1746. bool CMaterial::NeedsPowerOfTwoFrameBufferTexture( bool bCheckSpecificToThisFrame )
  1747. {
  1748. Precache_Inline();
  1749. AssertOnce( m_pShader );
  1750. if( !m_pShader )
  1751. {
  1752. return false;
  1753. }
  1754. Assert( m_pShaderParams );
  1755. return m_pShader->NeedsPowerOfTwoFrameBufferTexture( m_pShaderParams, bCheckSpecificToThisFrame );
  1756. }
  1757. bool CMaterial::NeedsFullFrameBufferTexture( bool bCheckSpecificToThisFrame )
  1758. {
  1759. Precache_Inline();
  1760. Assert( m_pShader );
  1761. if( !m_pShader )
  1762. {
  1763. return false;
  1764. }
  1765. Assert( m_pShaderParams );
  1766. return m_pShader->NeedsFullFrameBufferTexture( m_pShaderParams, bCheckSpecificToThisFrame );
  1767. }
  1768. // GR - Is lightmap alpha needed?
  1769. bool CMaterial::NeedsLightmapBlendAlpha( void )
  1770. {
  1771. Precache_Inline();
  1772. return (GetMaterialVarFlags2() & MATERIAL_VAR2_BLEND_WITH_LIGHTMAP_ALPHA ) != 0;
  1773. }
  1774. //-----------------------------------------------------------------------------
  1775. // Do we need software skinning?
  1776. //-----------------------------------------------------------------------------
  1777. bool CMaterial::NeedsSoftwareSkinning( void )
  1778. {
  1779. Precache_Inline();
  1780. Assert( m_pShader );
  1781. if( !m_pShader )
  1782. {
  1783. return false;
  1784. }
  1785. Assert( m_pShaderParams );
  1786. return IsFlagSet( m_pShaderParams, MATERIAL_VAR_NEEDS_SOFTWARE_SKINNING );
  1787. }
  1788. //-----------------------------------------------------------------------------
  1789. // Do we need software lighting?
  1790. //-----------------------------------------------------------------------------
  1791. bool CMaterial::NeedsSoftwareLighting( void )
  1792. {
  1793. Precache_Inline();
  1794. Assert( m_pShader );
  1795. if( !m_pShader )
  1796. {
  1797. return false;
  1798. }
  1799. Assert( m_pShaderParams );
  1800. return IsFlag2Set( m_pShaderParams, MATERIAL_VAR2_NEEDS_SOFTWARE_LIGHTING );
  1801. }
  1802. //-----------------------------------------------------------------------------
  1803. // Alpha/color modulation
  1804. //-----------------------------------------------------------------------------
  1805. void CMaterial::AlphaModulate( float alpha )
  1806. {
  1807. PrecacheVars_Inline();
  1808. if ( m_VarCount > ALPHA )
  1809. m_pShaderParams[ALPHA]->SetFloatValue(alpha);
  1810. }
  1811. void CMaterial::ColorModulate( float r, float g, float b )
  1812. {
  1813. PrecacheVars_Inline();
  1814. if ( m_VarCount > COLOR )
  1815. m_pShaderParams[COLOR]->SetVecValue( r, g, b );
  1816. }
  1817. float CMaterial::GetAlphaModulation()
  1818. {
  1819. PrecacheVars_Inline();
  1820. if ( m_VarCount > ALPHA )
  1821. return m_pShaderParams[ALPHA]->GetFloatValue();
  1822. return 0.0f;
  1823. }
  1824. void CMaterial::GetColorModulation( float *r, float *g, float *b )
  1825. {
  1826. PrecacheVars_Inline();
  1827. float pColor[3] = { 0.0f, 0.0f, 0.0f };
  1828. if ( m_VarCount > COLOR )
  1829. m_pShaderParams[COLOR]->GetVecValue( pColor, 3 );
  1830. *r = pColor[0];
  1831. *g = pColor[1];
  1832. *b = pColor[2];
  1833. }
  1834. //-----------------------------------------------------------------------------
  1835. // Do we use fog?
  1836. //-----------------------------------------------------------------------------
  1837. bool CMaterial::UseFog() const
  1838. {
  1839. Assert( m_VarCount > 0 );
  1840. return IsValidRenderState() && ((GetMaterialVarFlags() & MATERIAL_VAR_NOFOG) == 0);
  1841. }
  1842. //-----------------------------------------------------------------------------
  1843. // diffuse bump?
  1844. //-----------------------------------------------------------------------------
  1845. bool CMaterial::IsUsingDiffuseBumpedLighting() const
  1846. {
  1847. return (GetMaterialVarFlags2() & MATERIAL_VAR2_LIGHTING_BUMPED_LIGHTMAP ) != 0;
  1848. }
  1849. //-----------------------------------------------------------------------------
  1850. // lightmap?
  1851. //-----------------------------------------------------------------------------
  1852. bool CMaterial::IsUsingLightmap() const
  1853. {
  1854. return (GetMaterialVarFlags2() & MATERIAL_VAR2_LIGHTING_LIGHTMAP ) != 0;
  1855. }
  1856. bool CMaterial::IsManuallyCreated() const
  1857. {
  1858. return (m_Flags & MATERIAL_IS_MANUALLY_CREATED) != 0;
  1859. }
  1860. bool CMaterial::UsesUNCFileName() const
  1861. {
  1862. return (m_Flags & MATERIAL_USES_UNC_FILENAME) != 0;
  1863. }
  1864. void CMaterial::DecideShouldReloadFromWhitelist( IFileList *pFilesToReload )
  1865. {
  1866. m_bShouldReloadFromWhitelist = false;
  1867. if ( IsManuallyCreated() || !IsPrecached() )
  1868. return;
  1869. // Materials loaded with an absolute pathname are usually debug materials.
  1870. if ( V_IsAbsolutePath( GetName() ) )
  1871. return;
  1872. char vmtFilename[MAX_PATH];
  1873. V_ComposeFileName( "materials", GetName(), vmtFilename, sizeof( vmtFilename ) );
  1874. V_strncat( vmtFilename, ".vmt", sizeof( vmtFilename ) );
  1875. // Check if either this file or any of the files it included need to be reloaded.
  1876. bool bShouldReload = pFilesToReload->IsFileInList( vmtFilename );
  1877. if ( !bShouldReload )
  1878. {
  1879. for ( int i=0; i < m_VMTIncludes.Count(); i++ )
  1880. {
  1881. g_pFullFileSystem->String( m_VMTIncludes[i], vmtFilename, sizeof( vmtFilename ) );
  1882. bShouldReload = pFilesToReload->IsFileInList( vmtFilename );
  1883. if ( bShouldReload )
  1884. break;
  1885. }
  1886. }
  1887. m_bShouldReloadFromWhitelist = bShouldReload;
  1888. }
  1889. void CMaterial::ReloadFromWhitelistIfMarked()
  1890. {
  1891. if ( !m_bShouldReloadFromWhitelist )
  1892. return;
  1893. Uncache();
  1894. Precache_Inline();
  1895. if ( !GetShader() )
  1896. {
  1897. // We can get in here if we previously loaded this material off disk and now the whitelist
  1898. // says to get it out of Steam but it's not in Steam. So just setup a wireframe thingy
  1899. // to draw the material with.
  1900. m_Flags |= MATERIAL_IS_PRECACHED | MATERIAL_VARS_IS_PRECACHED;
  1901. #if DEBUG
  1902. if (IsOSX())
  1903. {
  1904. printf("\n ##### CMaterial::ReloadFromWhitelistIfMarked: GetShader failed on %s, calling SetupErrorShader", m_pDebugName );
  1905. }
  1906. #endif
  1907. SetupErrorShader();
  1908. }
  1909. }
  1910. bool CMaterial::WasReloadedFromWhitelist()
  1911. {
  1912. return m_bShouldReloadFromWhitelist;
  1913. }
  1914. //-----------------------------------------------------------------------------
  1915. // Loads the material vars
  1916. //-----------------------------------------------------------------------------
  1917. bool CMaterial::PrecacheVars_Internal( KeyValues *pVMTKeyValues, KeyValues *pPatchKeyValues, CUtlVector<FileNameHandle_t> *pIncludes )
  1918. {
  1919. if ( pIncludes )
  1920. m_VMTIncludes = *pIncludes;
  1921. else
  1922. m_VMTIncludes.Purge();
  1923. MaterialLock_t hMaterialLock = MaterialSystem()->Lock();
  1924. bool bOk = false;
  1925. bool bError = false;
  1926. KeyValues *vmtKeyValues = NULL;
  1927. KeyValues *patchKeyValues = NULL;
  1928. if ( m_pVMTKeyValues )
  1929. {
  1930. // Use the procedural KeyValues
  1931. vmtKeyValues = m_pVMTKeyValues;
  1932. patchKeyValues = new KeyValues( "vmt_patches" );
  1933. // The caller should not be passing in KeyValues if we have procedural ones
  1934. Assert( ( pVMTKeyValues == NULL ) && ( pPatchKeyValues == NULL ) );
  1935. }
  1936. else if ( pVMTKeyValues )
  1937. {
  1938. // Use the passed-in (already-loaded) KeyValues
  1939. vmtKeyValues = pVMTKeyValues;
  1940. patchKeyValues = pPatchKeyValues;
  1941. }
  1942. else
  1943. {
  1944. m_VMTIncludes.Purge();
  1945. // load data from the vmt file
  1946. vmtKeyValues = new KeyValues( "vmt" );
  1947. patchKeyValues = new KeyValues( "vmt_patches" );
  1948. if( !LoadVMTFile( *vmtKeyValues, *patchKeyValues, GetName(), UsesUNCFileName(), &m_VMTIncludes ) )
  1949. {
  1950. Warning( "CMaterial::PrecacheVars: error loading vmt file for %s\n", GetName() );
  1951. bError = true;
  1952. }
  1953. }
  1954. if ( ! bError )
  1955. {
  1956. // Needed to prevent re-entrancy
  1957. m_Flags |= MATERIAL_VARS_IS_PRECACHED;
  1958. // Create shader and the material vars...
  1959. KeyValues *pFallbackKeyValues = InitializeShader( *vmtKeyValues, *patchKeyValues );
  1960. if ( pFallbackKeyValues )
  1961. {
  1962. // Gotta initialize the proxies too, using the fallback proxies
  1963. InitializeMaterialProxy(pFallbackKeyValues);
  1964. bOk = true;
  1965. }
  1966. }
  1967. // Clean up
  1968. if ( ( vmtKeyValues != m_pVMTKeyValues ) && ( vmtKeyValues != pVMTKeyValues ) )
  1969. {
  1970. vmtKeyValues->deleteThis();
  1971. }
  1972. if ( patchKeyValues != pPatchKeyValues )
  1973. {
  1974. patchKeyValues->deleteThis();
  1975. }
  1976. if ( m_pShaderParams )
  1977. {
  1978. m_QueueFriendlyVersion.UpdateToRealTime();
  1979. }
  1980. MaterialSystem()->Unlock( hMaterialLock );
  1981. return bOk;
  1982. }
  1983. //-----------------------------------------------------------------------------
  1984. // Loads the material info from the VMT file
  1985. //-----------------------------------------------------------------------------
  1986. void CMaterial::Precache_Internal()
  1987. {
  1988. MaterialLock_t hMaterialLock = MaterialSystem()->Lock();
  1989. m_Flags |= MATERIAL_IS_PRECACHED;
  1990. // Invokes the SHADER_INIT block in the various shaders,
  1991. if ( m_pShader )
  1992. {
  1993. #ifdef _DEBUG
  1994. if ( GetMaterialVarFlags() & MATERIAL_VAR_DEBUG )
  1995. {
  1996. // Putcher breakpoint here to catch the rendering of a material
  1997. // marked for debugging ($debug = 1 in a .vmt file) SHADER_INIT version
  1998. int x = 0;
  1999. NOTE_UNUSED( x );
  2000. }
  2001. #endif
  2002. ShaderSystem()->InitShaderInstance( m_pShader, m_pShaderParams, GetName(), GetTextureGroupName() );
  2003. }
  2004. // compute the state snapshots
  2005. RecomputeStateSnapshots();
  2006. FindRepresentativeTexture();
  2007. // Reads in the texture width and height from the material var
  2008. PrecacheMappingDimensions();
  2009. Assert( IsValidRenderState() );
  2010. MaterialSystem()->Unlock( hMaterialLock );
  2011. }
  2012. //-----------------------------------------------------------------------------
  2013. // Unloads the material data from memory
  2014. //-----------------------------------------------------------------------------
  2015. void CMaterial::Uncache( bool bPreserveVars )
  2016. {
  2017. MaterialLock_t hMaterialLock = MaterialSystem()->Lock();
  2018. // Don't bother if we're not cached
  2019. if ( IsPrecached() )
  2020. {
  2021. // Clean up the state snapshots
  2022. CleanUpStateSnapshots();
  2023. m_Flags &= ~MATERIAL_VALID_RENDERSTATE;
  2024. m_Flags &= ~MATERIAL_IS_PRECACHED;
  2025. }
  2026. if ( !bPreserveVars )
  2027. {
  2028. if ( IsPrecachedVars() )
  2029. {
  2030. // Clean up the shader + params
  2031. CleanUpShaderParams();
  2032. m_pShader = 0;
  2033. // Clean up the material proxy
  2034. CleanUpMaterialProxy();
  2035. m_Flags &= ~MATERIAL_VARS_IS_PRECACHED;
  2036. }
  2037. }
  2038. MaterialSystem()->Unlock( hMaterialLock );
  2039. }
  2040. //-----------------------------------------------------------------------------
  2041. // reload all textures used by this materals
  2042. //-----------------------------------------------------------------------------
  2043. void CMaterial::ReloadTextures( void )
  2044. {
  2045. Precache_Inline();
  2046. int i;
  2047. int nParams = ShaderParamCount();
  2048. IMaterialVar **ppVars = GetShaderParams();
  2049. for( i = 0; i < nParams; i++ )
  2050. {
  2051. if( ppVars[i] )
  2052. {
  2053. if( ppVars[i]->IsTexture() )
  2054. {
  2055. ITextureInternal *pTexture = ( ITextureInternal * )ppVars[i]->GetTextureValue();
  2056. if( !IsTextureInternalEnvCubemap( pTexture ) )
  2057. {
  2058. pTexture->Download();
  2059. }
  2060. }
  2061. }
  2062. }
  2063. }
  2064. //-----------------------------------------------------------------------------
  2065. // Meant to be used with materials created using CreateMaterial
  2066. // It updates the materials to reflect the current values stored in the material vars
  2067. //-----------------------------------------------------------------------------
  2068. void CMaterial::Refresh()
  2069. {
  2070. if ( g_pShaderDevice->IsUsingGraphics() )
  2071. {
  2072. Uncache();
  2073. Precache();
  2074. }
  2075. }
  2076. void CMaterial::RefreshPreservingMaterialVars()
  2077. {
  2078. if ( g_pShaderDevice->IsUsingGraphics() )
  2079. {
  2080. Uncache( true );
  2081. Precache();
  2082. }
  2083. }
  2084. //-----------------------------------------------------------------------------
  2085. // Gets the material name
  2086. //-----------------------------------------------------------------------------
  2087. char const* CMaterial::GetName() const
  2088. {
  2089. return m_Name.String();
  2090. }
  2091. char const* CMaterial::GetTextureGroupName() const
  2092. {
  2093. return m_TextureGroupName.String();
  2094. }
  2095. //-----------------------------------------------------------------------------
  2096. // Material dimensions
  2097. //-----------------------------------------------------------------------------
  2098. int CMaterial::GetMappingWidth( )
  2099. {
  2100. Precache_Inline();
  2101. return m_MappingWidth;
  2102. }
  2103. int CMaterial::GetMappingHeight( )
  2104. {
  2105. Precache_Inline();
  2106. return m_MappingHeight;
  2107. }
  2108. //-----------------------------------------------------------------------------
  2109. // Animated material info
  2110. //-----------------------------------------------------------------------------
  2111. int CMaterial::GetNumAnimationFrames( )
  2112. {
  2113. Precache_Inline();
  2114. if( m_representativeTexture )
  2115. {
  2116. return m_representativeTexture->GetNumAnimationFrames();
  2117. }
  2118. else
  2119. {
  2120. #ifndef POSIX
  2121. Warning( "CMaterial::GetNumAnimationFrames:\nno representative texture for material %s\n", GetName() );
  2122. #endif
  2123. return 1;
  2124. }
  2125. }
  2126. //-----------------------------------------------------------------------------
  2127. // Purpose:
  2128. //-----------------------------------------------------------------------------
  2129. void CMaterial::GetMaterialOffset( float *pOffset )
  2130. {
  2131. // Identity.
  2132. pOffset[0] = 0.0f;
  2133. pOffset[1] = 0.0f;
  2134. }
  2135. //-----------------------------------------------------------------------------
  2136. // Purpose:
  2137. //-----------------------------------------------------------------------------
  2138. void CMaterial::GetMaterialScale( float *pScale )
  2139. {
  2140. // Identity.
  2141. pScale[0] = 1.0f;
  2142. pScale[1] = 1.0f;
  2143. }
  2144. //-----------------------------------------------------------------------------
  2145. // Reference count
  2146. //-----------------------------------------------------------------------------
  2147. void CMaterial::IncrementReferenceCount()
  2148. {
  2149. // if ( *mat_debug_material_reference_name.GetString() && Q_stristr( m_Name.String(), mat_debug_material_reference_name.GetString() ) )
  2150. // {
  2151. // Msg("%s ++REF(%d)\n", m_Name.String(), m_RefCount );
  2152. // }
  2153. ++m_RefCount;
  2154. }
  2155. void CMaterial::DecrementReferenceCount()
  2156. {
  2157. // if ( *mat_debug_material_reference_name.GetString() && Q_stristr( m_Name.String(), mat_debug_material_reference_name.GetString() ) )
  2158. // {
  2159. // Msg("%s --REF(%d)\n", m_Name.String(), m_RefCount );
  2160. // }
  2161. --m_RefCount;
  2162. }
  2163. int CMaterial::GetReferenceCount( ) const
  2164. {
  2165. return m_RefCount;
  2166. }
  2167. //-----------------------------------------------------------------------------
  2168. // Sets the shader associated with the material
  2169. //-----------------------------------------------------------------------------
  2170. void CMaterial::SetShader( const char *pShaderName )
  2171. {
  2172. Assert( pShaderName );
  2173. int i;
  2174. IShader* pShader;
  2175. IMaterialVar* ppVars[256];
  2176. int iVarCount = 0;
  2177. // Clean up existing state
  2178. Uncache();
  2179. // Keep going until there's no more fallbacks...
  2180. while( true )
  2181. {
  2182. // Find the shader for this material. Note that this may not be
  2183. // the actual shader we use due to fallbacks...
  2184. pShader = ShaderSystem()->FindShader( pShaderName );
  2185. if (!pShader)
  2186. {
  2187. // Couldn't find the shader we wanted to use; it's not defined...
  2188. Warning( "SetShader: Couldn't find shader %s for material %s!\n", pShaderName, GetName() );
  2189. pShaderName = "Wireframe_DX9";
  2190. pShader = ShaderSystem()->FindShader( pShaderName );
  2191. Assert( pShader );
  2192. }
  2193. // Create undefined vars for all the actual material vars
  2194. iVarCount = pShader->GetParamCount();
  2195. for (i = 0; i < iVarCount; ++i)
  2196. {
  2197. ppVars[i] = IMaterialVar::Create( this, pShader->GetParamInfo(i).m_pName );
  2198. }
  2199. // Make sure we set default values before the fallback is looked for
  2200. ShaderSystem()->InitShaderParameters( pShader, ppVars, pShaderName );
  2201. // Now that the material vars are parsed, see if there's a fallback
  2202. // But only if we're not in the tools
  2203. if (!g_pShaderDevice->IsUsingGraphics())
  2204. break;
  2205. // Check for a fallback; if not, we're done
  2206. pShaderName = pShader->GetFallbackShader( ppVars );
  2207. if (!pShaderName)
  2208. break;
  2209. // Now, blow away all of the material vars + try again...
  2210. for (i = 0; i < iVarCount; ++i)
  2211. {
  2212. Assert( ppVars[i] );
  2213. IMaterialVar::Destroy( ppVars[i] );
  2214. }
  2215. }
  2216. // Store off the shader
  2217. m_pShader = pShader;
  2218. // Store off the material vars + flags
  2219. m_VarCount = iVarCount;
  2220. m_pShaderParams = (IMaterialVar**)malloc( iVarCount * sizeof(IMaterialVar*) );
  2221. memcpy( m_pShaderParams, ppVars, iVarCount * sizeof(IMaterialVar*) );
  2222. // Invokes the SHADER_INIT block in the various shaders,
  2223. ShaderSystem()->InitShaderInstance( m_pShader, m_pShaderParams, GetName(), GetTextureGroupName() );
  2224. // Precache our initial state...
  2225. // NOTE: What happens here for textures???
  2226. // Pretend that we precached our material vars; we certainly don't have any!
  2227. m_Flags |= MATERIAL_VARS_IS_PRECACHED;
  2228. // NOTE: The caller has to call 'Refresh' for the shader to be ready...
  2229. }
  2230. const char *CMaterial::GetShaderName() const
  2231. {
  2232. return (m_pShader) ? m_pShader->GetName() : "";
  2233. }
  2234. //-----------------------------------------------------------------------------
  2235. // Enumeration ID
  2236. //-----------------------------------------------------------------------------
  2237. int CMaterial::GetEnumerationID( ) const
  2238. {
  2239. return m_iEnumerationID;
  2240. }
  2241. void CMaterial::SetEnumerationID( int id )
  2242. {
  2243. m_iEnumerationID = id;
  2244. }
  2245. //-----------------------------------------------------------------------------
  2246. // Preview image
  2247. //-----------------------------------------------------------------------------
  2248. char const* CMaterial::GetPreviewImageName( void )
  2249. {
  2250. if ( IsGameConsole() )
  2251. {
  2252. // not supporting
  2253. return NULL;
  2254. }
  2255. PrecacheVars_Inline();
  2256. bool found;
  2257. IMaterialVar *pRepresentativeTextureVar;
  2258. FindVar( "%noToolTexture", &found, false );
  2259. if (found)
  2260. return NULL;
  2261. pRepresentativeTextureVar = FindVar( "%toolTexture", &found, false );
  2262. if( found )
  2263. {
  2264. if (pRepresentativeTextureVar->GetType() == MATERIAL_VAR_TYPE_STRING )
  2265. return pRepresentativeTextureVar->GetStringValue();
  2266. if (pRepresentativeTextureVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE )
  2267. return pRepresentativeTextureVar->GetTextureValue()->GetName();
  2268. }
  2269. pRepresentativeTextureVar = FindVar( "$baseTexture", &found, false );
  2270. if( found )
  2271. {
  2272. if (pRepresentativeTextureVar->GetType() == MATERIAL_VAR_TYPE_STRING )
  2273. return pRepresentativeTextureVar->GetStringValue();
  2274. if (pRepresentativeTextureVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE )
  2275. return pRepresentativeTextureVar->GetTextureValue()->GetName();
  2276. }
  2277. return GetName();
  2278. }
  2279. char const* CMaterial::GetPreviewImageFileName( void ) const
  2280. {
  2281. char const* pName = const_cast<CMaterial*>(this)->GetPreviewImageName();
  2282. if( !pName )
  2283. return NULL;
  2284. static char vtfFilename[MATERIAL_MAX_PATH];
  2285. if( Q_strlen( pName ) >= MATERIAL_MAX_PATH - 5 )
  2286. {
  2287. Warning( "MATERIAL_MAX_PATH to short for %s.vtf\n", pName );
  2288. return NULL;
  2289. }
  2290. if ( !UsesUNCFileName() )
  2291. {
  2292. Q_snprintf( vtfFilename, sizeof( vtfFilename ), "materials/%s.vtf", pName );
  2293. }
  2294. else
  2295. {
  2296. Q_snprintf( vtfFilename, sizeof( vtfFilename ), "%s.vtf", pName );
  2297. }
  2298. return vtfFilename;
  2299. }
  2300. PreviewImageRetVal_t CMaterial::GetPreviewImageProperties( int *width, int *height,
  2301. ImageFormat *imageFormat, bool* isTranslucent ) const
  2302. {
  2303. char const* pFileName = GetPreviewImageFileName();
  2304. if ( IsGameConsole() || !pFileName )
  2305. {
  2306. *width = *height = 0;
  2307. *imageFormat = IMAGE_FORMAT_RGBA8888;
  2308. *isTranslucent = false;
  2309. return MATERIAL_NO_PREVIEW_IMAGE;
  2310. }
  2311. int nHeaderSize = VTFFileHeaderSize( VTF_MAJOR_VERSION );
  2312. unsigned char *pMem = (unsigned char *)stackalloc( nHeaderSize );
  2313. CUtlBuffer buf( pMem, nHeaderSize );
  2314. if( !g_pFullFileSystem->ReadFile( pFileName, NULL, buf, nHeaderSize ) )
  2315. {
  2316. Warning( "\"%s\" - \"%s\": cached version doesn't exist\n", GetName(), pFileName );
  2317. return MATERIAL_PREVIEW_IMAGE_BAD;
  2318. }
  2319. IVTFTexture *pVTFTexture = CreateVTFTexture();
  2320. if (!pVTFTexture->Unserialize( buf, true ))
  2321. {
  2322. Warning( "Error reading material \"%s\"\n", pFileName );
  2323. DestroyVTFTexture( pVTFTexture );
  2324. return MATERIAL_PREVIEW_IMAGE_BAD;
  2325. }
  2326. *width = pVTFTexture->Width();
  2327. *height = pVTFTexture->Height();
  2328. *imageFormat = pVTFTexture->Format();
  2329. *isTranslucent = (pVTFTexture->Flags() & (TEXTUREFLAGS_ONEBITALPHA | TEXTUREFLAGS_EIGHTBITALPHA)) != 0;
  2330. DestroyVTFTexture( pVTFTexture );
  2331. return MATERIAL_PREVIEW_IMAGE_OK;
  2332. }
  2333. PreviewImageRetVal_t CMaterial::GetPreviewImage( unsigned char *pData, int width, int height,
  2334. ImageFormat imageFormat ) const
  2335. {
  2336. CUtlBuffer buf;
  2337. int nHeaderSize;
  2338. int nImageOffset, nImageSize;
  2339. char const* pFileName = GetPreviewImageFileName();
  2340. if ( IsGameConsole() || !pFileName )
  2341. {
  2342. return MATERIAL_NO_PREVIEW_IMAGE;
  2343. }
  2344. IVTFTexture *pVTFTexture = CreateVTFTexture();
  2345. FileHandle_t fileHandle = g_pFullFileSystem->Open( pFileName, "rb" );
  2346. if( !fileHandle )
  2347. {
  2348. Warning( "\"%s\": cached version doesn't exist\n", pFileName );
  2349. goto fail;
  2350. }
  2351. nHeaderSize = VTFFileHeaderSize( VTF_MAJOR_VERSION );
  2352. buf.EnsureCapacity( nHeaderSize );
  2353. // read the header first.. it's faster!!
  2354. int nBytesRead; // GCC won't let this be initialized right away
  2355. nBytesRead = g_pFullFileSystem->Read( buf.Base(), nHeaderSize, fileHandle );
  2356. buf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead );
  2357. // Unserialize the header
  2358. if (!pVTFTexture->Unserialize( buf, true ))
  2359. {
  2360. Warning( "Error reading material \"%s\"\n", pFileName );
  2361. goto fail;
  2362. }
  2363. // FIXME: Make sure the preview image size requested is the same
  2364. // size as mip level 0 of the texture
  2365. Assert( (width == pVTFTexture->Width()) && (height == pVTFTexture->Height()) );
  2366. // Determine where in the file to start reading (frame 0, face 0, mip 0)
  2367. pVTFTexture->ImageFileInfo( 0, 0, 0, &nImageOffset, &nImageSize );
  2368. if ( nImageSize == 0 )
  2369. {
  2370. Warning( "Couldn't determine offset and size of material \"%s\"\n", pFileName );
  2371. goto fail;
  2372. }
  2373. // Prep the utlbuffer for reading
  2374. buf.EnsureCapacity( nImageSize );
  2375. buf.SeekPut( CUtlBuffer::SEEK_HEAD, 0 );
  2376. // Read in the bits at the specified location
  2377. g_pFullFileSystem->Seek( fileHandle, nImageOffset, FILESYSTEM_SEEK_HEAD );
  2378. g_pFullFileSystem->Read( buf.Base(), nImageSize, fileHandle );
  2379. g_pFullFileSystem->Close( fileHandle );
  2380. // Convert from the format read in to the requested format
  2381. ImageLoader::ConvertImageFormat( (unsigned char*)buf.Base(), pVTFTexture->Format(),
  2382. pData, imageFormat, width, height );
  2383. DestroyVTFTexture( pVTFTexture );
  2384. return MATERIAL_PREVIEW_IMAGE_OK;
  2385. fail:
  2386. if( fileHandle )
  2387. {
  2388. g_pFullFileSystem->Close( fileHandle );
  2389. }
  2390. int nSize = ImageLoader::GetMemRequired( width, height, 1, imageFormat, false );
  2391. memset( pData, 0xff, nSize );
  2392. DestroyVTFTexture( pVTFTexture );
  2393. return MATERIAL_PREVIEW_IMAGE_BAD;
  2394. }
  2395. //-----------------------------------------------------------------------------
  2396. // Material variables
  2397. //-----------------------------------------------------------------------------
  2398. IMaterialVar *CMaterial::FindVar( char const *pVarName, bool *pFound, bool complain )
  2399. {
  2400. PrecacheVars_Inline();
  2401. // FIXME: Could look for flags here too...
  2402. MaterialVarSym_t sym = IMaterialVar::FindSymbol(pVarName);
  2403. if ( sym != UTL_INVAL_SYMBOL )
  2404. {
  2405. for (int i = m_VarCount; --i >= 0; )
  2406. {
  2407. if (m_pShaderParams[i]->GetNameAsSymbol() == sym)
  2408. {
  2409. if( pFound )
  2410. *pFound = true;
  2411. return m_pShaderParams[i];
  2412. }
  2413. }
  2414. }
  2415. if( pFound )
  2416. *pFound = false;
  2417. if( complain )
  2418. {
  2419. static int complainCount = 0;
  2420. if( complainCount < 100 )
  2421. {
  2422. Warning( "No such variable \"%s\" for material \"%s\"\n", pVarName, GetName() );
  2423. complainCount++;
  2424. }
  2425. }
  2426. return GetDummyVariable();
  2427. }
  2428. IMaterialVar *CMaterial::FindVarFast( char const *pVarName, unsigned int *pCacheData )
  2429. {
  2430. tokencache_t *pToken = reinterpret_cast<tokencache_t *>(pCacheData);
  2431. PrecacheVars_Inline();
  2432. if ( pToken->cached )
  2433. {
  2434. if ( !pToken->subrect && ( pToken->varIndex < m_VarCount ) && ( m_pShaderParams[pToken->varIndex]->GetNameAsSymbol() == pToken->symbol ) )
  2435. return m_pShaderParams[pToken->varIndex];
  2436. // FIXME: Could look for flags here too...
  2437. if ( !IMaterialVar::SymbolMatches(pVarName, pToken->symbol) )
  2438. {
  2439. pToken->symbol = IMaterialVar::FindSymbol(pVarName);
  2440. }
  2441. }
  2442. else
  2443. {
  2444. pToken->cached = true;
  2445. pToken->symbol = IMaterialVar::FindSymbol(pVarName);
  2446. }
  2447. if ( pToken->symbol != UTL_INVAL_SYMBOL )
  2448. {
  2449. for (int i = m_VarCount; --i >= 0; )
  2450. {
  2451. if (m_pShaderParams[i]->GetNameAsSymbol() == pToken->symbol)
  2452. {
  2453. pToken->varIndex = i;
  2454. pToken->subrect = false;
  2455. return m_pShaderParams[i];
  2456. }
  2457. }
  2458. }
  2459. return NULL;
  2460. }
  2461. //-----------------------------------------------------------------------------
  2462. // Lovely material properties
  2463. //-----------------------------------------------------------------------------
  2464. void CMaterial::GetReflectivity( Vector& reflect )
  2465. {
  2466. Precache_Inline();
  2467. reflect = m_Reflectivity;
  2468. }
  2469. bool CMaterial::GetPropertyFlag( MaterialPropertyTypes_t type )
  2470. {
  2471. Precache_Inline();
  2472. if (!IsValidRenderState())
  2473. return false;
  2474. switch( type )
  2475. {
  2476. case MATERIAL_PROPERTY_NEEDS_LIGHTMAP:
  2477. return IsUsingLightmap();
  2478. case MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS:
  2479. return IsUsingDiffuseBumpedLighting();
  2480. }
  2481. return false;
  2482. }
  2483. //-----------------------------------------------------------------------------
  2484. // Is the material visible from both sides?
  2485. //-----------------------------------------------------------------------------
  2486. bool CMaterial::IsTwoSided()
  2487. {
  2488. PrecacheVars_Inline();
  2489. return GetMaterialVarFlag(MATERIAL_VAR_NOCULL);
  2490. }
  2491. //-----------------------------------------------------------------------------
  2492. // Are we translucent?
  2493. //-----------------------------------------------------------------------------
  2494. bool CMaterial::IsTranslucent()
  2495. {
  2496. Precache_Inline();
  2497. if ( m_VarCount > ALPHA )
  2498. return IsTranslucentInternal( m_pShaderParams? m_pShaderParams[ALPHA]->GetFloatValue() : 0.0 );
  2499. return false;
  2500. }
  2501. bool CMaterial::IsTranslucentInternal( float fAlphaModulation ) const
  2502. {
  2503. if (m_pShader && IsValidRenderState())
  2504. {
  2505. // If alpha is modified by the proxy, then we are translucent
  2506. // Dramatically simplifies game code to make this assumption
  2507. int nMyMaterialVarFlags = GetMaterialVarFlags();
  2508. if ( nMyMaterialVarFlags & MATERIAL_VAR_ALPHA_MODIFIED_BY_PROXY )
  2509. return true;
  2510. const int nPseudoTranslucentMaterialRenderingInOpaquePass = MATERIAL_VAR_TRANSLUCENT | MATERIAL_VAR_PSEUDO_TRANSLUCENT;
  2511. if ( (nMyMaterialVarFlags & nPseudoTranslucentMaterialRenderingInOpaquePass) == nPseudoTranslucentMaterialRenderingInOpaquePass )
  2512. return false;
  2513. // I have to check for alpha modulation here because it isn't
  2514. // factored into the shader's notion of whether or not it's transparent
  2515. return ::IsTranslucent(&m_ShaderRenderState) ||
  2516. (fAlphaModulation < 1.0f) ||
  2517. m_pShader->IsTranslucent( m_pShaderParams );
  2518. }
  2519. return false;
  2520. }
  2521. // Is this translucent even without alpha modulation?
  2522. bool CMaterial::IsTranslucentUnderModulation( float fAlphaModulation ) const
  2523. {
  2524. const_cast< CMaterial* >( this )->Precache_Inline();
  2525. return IsTranslucentInternal( fAlphaModulation );
  2526. }
  2527. //-----------------------------------------------------------------------------
  2528. // Are we alphatested?
  2529. //-----------------------------------------------------------------------------
  2530. bool CMaterial::IsAlphaTested()
  2531. {
  2532. Precache_Inline();
  2533. if (m_pShader && IsValidRenderState())
  2534. {
  2535. return ::IsAlphaTested(&m_ShaderRenderState) ||
  2536. GetMaterialVarFlag( MATERIAL_VAR_ALPHATEST );
  2537. }
  2538. return false;
  2539. }
  2540. //-----------------------------------------------------------------------------
  2541. // Are we vertex lit?
  2542. //-----------------------------------------------------------------------------
  2543. bool CMaterial::IsVertexLit()
  2544. {
  2545. Precache_Inline();
  2546. if (IsValidRenderState())
  2547. {
  2548. return ( GetMaterialVarFlags2() & MATERIAL_VAR2_LIGHTING_VERTEX_LIT ) != 0;
  2549. }
  2550. return false;
  2551. }
  2552. //-----------------------------------------------------------------------------
  2553. // Is the shader a sprite card shader?
  2554. //-----------------------------------------------------------------------------
  2555. bool CMaterial::IsSpriteCard()
  2556. {
  2557. Precache_Inline();
  2558. if (IsValidRenderState())
  2559. {
  2560. return ( GetMaterialVarFlags2() & MATERIAL_VAR2_IS_SPRITECARD ) != 0;
  2561. }
  2562. return false;
  2563. }
  2564. //-----------------------------------------------------------------------------
  2565. // Proxies
  2566. //-----------------------------------------------------------------------------
  2567. void CMaterial::CallBindProxy( void *proxyData, ICallQueue *pCallQueue )
  2568. {
  2569. bool bIsThreaded = ( pCallQueue != NULL );
  2570. switch (g_config.proxiesTestMode)
  2571. {
  2572. case 0:
  2573. {
  2574. // Make sure we call the proxies in the order in which they show up
  2575. // in the .vmt file
  2576. if ( m_ProxyCount )
  2577. {
  2578. if ( bIsThreaded )
  2579. {
  2580. EnableThreadedMaterialVarAccess( true, m_pShaderParams, m_VarCount );
  2581. }
  2582. IClientMaterialSystem *pClientMaterialSystem = MaterialSystem()->GetClientMaterialSystemInterface();
  2583. if( pClientMaterialSystem )
  2584. {
  2585. pClientMaterialSystem->SetMaterialProxyData( proxyData );
  2586. }
  2587. for( int i = 0; i < m_ProxyCount; ++i )
  2588. {
  2589. m_ppProxies[i]->OnBind( proxyData );
  2590. }
  2591. if( pClientMaterialSystem )
  2592. {
  2593. pClientMaterialSystem->SetMaterialProxyData( NULL );
  2594. }
  2595. if ( bIsThreaded )
  2596. {
  2597. EnableThreadedMaterialVarAccess( false, m_pShaderParams, m_VarCount );
  2598. }
  2599. }
  2600. }
  2601. break;
  2602. case 2:
  2603. // alpha mod all....
  2604. {
  2605. float value = ( sin( 2.0f * M_PI * Plat_FloatTime() / 10.0f ) * 0.5f ) + 0.5f;
  2606. m_pShaderParams[ALPHA]->SetFloatValue( value );
  2607. }
  2608. break;
  2609. case 3:
  2610. // color mod all...
  2611. {
  2612. float value = ( sin( 2.0f * M_PI * Plat_FloatTime() / 10.0f ) * 0.5f ) + 0.5f;
  2613. m_pShaderParams[COLOR]->SetVecValue( value, 1.0f, 1.0f );
  2614. }
  2615. break;
  2616. }
  2617. }
  2618. bool CMaterial::HasProxy( ) const
  2619. {
  2620. const_cast< CMaterial* >( this )->PrecacheVars_Inline();
  2621. return (m_ProxyCount > 0);
  2622. }
  2623. //-----------------------------------------------------------------------------
  2624. // Main draw method
  2625. //-----------------------------------------------------------------------------
  2626. #ifdef _WIN32
  2627. #pragma warning (disable: 4189)
  2628. #endif
  2629. StateSnapshot_t CMaterial::GetSnapshotId( int modulation, int renderPass )
  2630. {
  2631. return m_ShaderRenderState.m_pSnapshots[modulation].m_Snapshot[renderPass];
  2632. }
  2633. unsigned char* CMaterial::GetInstanceCommandBuffer( int modulation )
  2634. {
  2635. CBasePerInstanceContextData *pInstanceData = m_ShaderRenderState.m_pSnapshots[modulation].m_pInstanceData[0];
  2636. return pInstanceData->GetInstanceCommandBuffer();
  2637. }
  2638. void CMaterial::DrawMesh( VertexCompressionType_t vertexCompression, bool bIsAlphaModulating, bool bRenderingPreTessPatchMesh )
  2639. {
  2640. if ( m_pShader )
  2641. {
  2642. #ifdef _DEBUG
  2643. if ( GetMaterialVarFlags() & MATERIAL_VAR_DEBUG )
  2644. {
  2645. // Putcher breakpoint here to catch the rendering of a material
  2646. // marked for debugging ($debug = 1 in a .vmt file) dynamic state version
  2647. int x = 0;
  2648. }
  2649. #endif
  2650. if ((GetMaterialVarFlags() & MATERIAL_VAR_NO_DRAW) == 0)
  2651. {
  2652. ShaderSystem()->DrawElements( m_pShader, m_pShaderParams, &m_ShaderRenderState, vertexCompression,
  2653. m_ChangeID ^ g_nDebugVarsSignature, bIsAlphaModulating ? SHADER_USING_ALPHA_MODULATION : 0, bRenderingPreTessPatchMesh );
  2654. }
  2655. }
  2656. else
  2657. {
  2658. Warning( "CMaterial::DrawElements: No bound shader\n" );
  2659. }
  2660. }
  2661. #ifdef _WIN32
  2662. #pragma warning (default: 4189)
  2663. #endif
  2664. IShader *CMaterial::GetShader( ) const
  2665. {
  2666. return m_pShader;
  2667. }
  2668. IMaterialVar *CMaterial::GetShaderParam( int id )
  2669. {
  2670. return m_pShaderParams[id];
  2671. }
  2672. //-----------------------------------------------------------------------------
  2673. // Adds a material variable to the material
  2674. //-----------------------------------------------------------------------------
  2675. void CMaterial::AddMaterialVar( IMaterialVar *pMaterialVar )
  2676. {
  2677. ++m_VarCount;
  2678. m_pShaderParams = (IMaterialVar**)realloc( m_pShaderParams, m_VarCount * sizeof( IMaterialVar*) );
  2679. m_pShaderParams[m_VarCount-1] = pMaterialVar;
  2680. }
  2681. bool CMaterial::IsErrorMaterial() const
  2682. {
  2683. extern IMaterialInternal *g_pErrorMaterial;
  2684. const IMaterialInternal *pThis = this;
  2685. return g_pErrorMaterial == pThis;
  2686. }
  2687. void CMaterial::FindRepresentativeTexture( void )
  2688. {
  2689. Precache_Inline();
  2690. // First try to find the base texture...
  2691. bool found;
  2692. IMaterialVar *textureVar = FindVar( "$baseTexture", &found, false );
  2693. if( found && textureVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE )
  2694. {
  2695. ITextureInternal *pTexture = ( ITextureInternal * )textureVar->GetTextureValue();
  2696. if( pTexture )
  2697. {
  2698. pTexture->GetReflectivity( m_Reflectivity );
  2699. }
  2700. }
  2701. if( !found || textureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
  2702. {
  2703. // Try the flowmap for water
  2704. textureVar = FindVar( "$flowmap", &found, false );
  2705. if( !found || textureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
  2706. {
  2707. // Try the env map mask if the base texture doesn't work...
  2708. // this is needed for specular decals
  2709. textureVar = FindVar( "$envmapmask", &found, false );
  2710. if( !found || textureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
  2711. {
  2712. // Try the bumpmap
  2713. textureVar = FindVar( "$bumpmap", &found, false );
  2714. if( !found || textureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
  2715. {
  2716. textureVar = FindVar( "$dudvmap", &found, false );
  2717. if( !found || textureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
  2718. {
  2719. textureVar = FindVar( "$normalmap", &found, false );
  2720. if( !found || textureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
  2721. {
  2722. // Warning( "Can't find representative texture for material \"%s\"\n", GetName() );
  2723. m_representativeTexture = TextureManager()->ErrorTexture();
  2724. return;
  2725. }
  2726. }
  2727. }
  2728. }
  2729. }
  2730. }
  2731. m_representativeTexture = static_cast<ITextureInternal *>( textureVar->GetTextureValue() );
  2732. if (m_representativeTexture)
  2733. {
  2734. m_representativeTexture->Precache();
  2735. }
  2736. else
  2737. {
  2738. m_representativeTexture = TextureManager()->ErrorTexture();
  2739. Assert( m_representativeTexture );
  2740. }
  2741. }
  2742. void CMaterial::GetLowResColorSample( float s, float t, float *color ) const
  2743. {
  2744. if( !m_representativeTexture )
  2745. {
  2746. return;
  2747. }
  2748. m_representativeTexture->GetLowResColorSample( s, t, color);
  2749. }
  2750. //-----------------------------------------------------------------------------
  2751. // Lightmap-related methods
  2752. //-----------------------------------------------------------------------------
  2753. void CMaterial::SetMinLightmapPageID( int pageID )
  2754. {
  2755. m_minLightmapPageID = pageID;
  2756. }
  2757. void CMaterial::SetMaxLightmapPageID( int pageID )
  2758. {
  2759. m_maxLightmapPageID = pageID;
  2760. }
  2761. int CMaterial::GetMinLightmapPageID( ) const
  2762. {
  2763. return m_minLightmapPageID;
  2764. }
  2765. int CMaterial::GetMaxLightmapPageID( ) const
  2766. {
  2767. return m_maxLightmapPageID;
  2768. }
  2769. void CMaterial::SetNeedsWhiteLightmap( bool val )
  2770. {
  2771. if ( val )
  2772. m_Flags |= MATERIAL_NEEDS_WHITE_LIGHTMAP;
  2773. else
  2774. m_Flags &= ~MATERIAL_NEEDS_WHITE_LIGHTMAP;
  2775. }
  2776. bool CMaterial::GetNeedsWhiteLightmap( ) const
  2777. {
  2778. return (m_Flags & MATERIAL_NEEDS_WHITE_LIGHTMAP) != 0;
  2779. }
  2780. void CMaterial::MarkAsPreloaded( bool bSet )
  2781. {
  2782. if ( bSet )
  2783. {
  2784. m_Flags |= MATERIAL_IS_PRELOADED;
  2785. }
  2786. else
  2787. {
  2788. m_Flags &= ~MATERIAL_IS_PRELOADED;
  2789. }
  2790. }
  2791. bool CMaterial::IsPreloaded() const
  2792. {
  2793. return ( m_Flags & MATERIAL_IS_PRELOADED ) != 0;
  2794. }
  2795. void CMaterial::ArtificialAddRef( void )
  2796. {
  2797. if ( m_Flags & MATERIAL_ARTIFICIAL_REFCOUNT )
  2798. {
  2799. // already done
  2800. return;
  2801. }
  2802. m_Flags |= MATERIAL_ARTIFICIAL_REFCOUNT;
  2803. m_RefCount++;
  2804. }
  2805. void CMaterial::ArtificialRelease( void )
  2806. {
  2807. if ( !( m_Flags & MATERIAL_ARTIFICIAL_REFCOUNT ) )
  2808. {
  2809. return;
  2810. }
  2811. m_Flags &= ~MATERIAL_ARTIFICIAL_REFCOUNT;
  2812. m_RefCount--;
  2813. }
  2814. //-----------------------------------------------------------------------------
  2815. // Return the shader params
  2816. //-----------------------------------------------------------------------------
  2817. IMaterialVar **CMaterial::GetShaderParams( void )
  2818. {
  2819. return m_pShaderParams;
  2820. }
  2821. int CMaterial::ShaderParamCount() const
  2822. {
  2823. return m_VarCount;
  2824. }
  2825. //-----------------------------------------------------------------------------
  2826. // VMT parser
  2827. //-----------------------------------------------------------------------------
  2828. void InsertKeyValues( KeyValues& dst, KeyValues& src, bool bCheckForExistence )
  2829. {
  2830. KeyValues *pSrcVar = src.GetFirstSubKey();
  2831. while( pSrcVar )
  2832. {
  2833. if ( !bCheckForExistence || dst.FindKey( pSrcVar->GetName() ) )
  2834. {
  2835. switch( pSrcVar->GetDataType() )
  2836. {
  2837. case KeyValues::TYPE_STRING:
  2838. dst.SetString( pSrcVar->GetName(), pSrcVar->GetString() );
  2839. break;
  2840. case KeyValues::TYPE_INT:
  2841. dst.SetInt( pSrcVar->GetName(), pSrcVar->GetInt() );
  2842. break;
  2843. case KeyValues::TYPE_FLOAT:
  2844. dst.SetFloat( pSrcVar->GetName(), pSrcVar->GetFloat() );
  2845. break;
  2846. case KeyValues::TYPE_PTR:
  2847. dst.SetPtr( pSrcVar->GetName(), pSrcVar->GetPtr() );
  2848. break;
  2849. }
  2850. }
  2851. pSrcVar = pSrcVar->GetNextKey();
  2852. }
  2853. if( bCheckForExistence )
  2854. {
  2855. for( KeyValues *pScan = dst.GetFirstTrueSubKey(); pScan; pScan = pScan->GetNextTrueSubKey() )
  2856. {
  2857. KeyValues *pTmp = src.FindKey( pScan->GetName() );
  2858. if( !pTmp )
  2859. continue;
  2860. // make sure that this is a subkey.
  2861. if( pTmp->GetDataType() != KeyValues::TYPE_NONE )
  2862. continue;
  2863. InsertKeyValues( *pScan, *pTmp, bCheckForExistence );
  2864. }
  2865. }
  2866. }
  2867. void WriteKeyValuesToFile( const char *pFileName, KeyValues& keyValues )
  2868. {
  2869. keyValues.SaveToFile( g_pFullFileSystem, pFileName );
  2870. }
  2871. void ApplyPatchKeyValues( KeyValues &keyValues, KeyValues &patchKeyValues )
  2872. {
  2873. KeyValues *pInsertSection = patchKeyValues.FindKey( "insert" );
  2874. KeyValues *pReplaceSection = patchKeyValues.FindKey( "replace" );
  2875. if ( pInsertSection )
  2876. {
  2877. InsertKeyValues( keyValues, *pInsertSection, false );
  2878. }
  2879. if ( pReplaceSection )
  2880. {
  2881. InsertKeyValues( keyValues, *pReplaceSection, true );
  2882. }
  2883. // Could add other commands here, like "delete", "rename", etc.
  2884. }
  2885. //-----------------------------------------------------------------------------
  2886. // Adds keys from srcKeys to destKeys, overwriting any keys that are already
  2887. // there. Doesn't work recursively.
  2888. //-----------------------------------------------------------------------------
  2889. void MergeKeyValues( KeyValues &srcKeys, KeyValues &destKeys )
  2890. {
  2891. for( KeyValues *pKV = srcKeys.GetFirstValue(); pKV; pKV = pKV->GetNextValue() )
  2892. {
  2893. switch( pKV->GetDataType() )
  2894. {
  2895. case KeyValues::TYPE_STRING:
  2896. destKeys.SetString( pKV->GetName(), pKV->GetString() );
  2897. break;
  2898. case KeyValues::TYPE_INT:
  2899. destKeys.SetInt( pKV->GetName(), pKV->GetInt() );
  2900. break;
  2901. case KeyValues::TYPE_FLOAT:
  2902. destKeys.SetFloat( pKV->GetName(), pKV->GetFloat() );
  2903. break;
  2904. case KeyValues::TYPE_PTR:
  2905. destKeys.SetPtr( pKV->GetName(), pKV->GetPtr() );
  2906. break;
  2907. }
  2908. }
  2909. }
  2910. //-----------------------------------------------------------------------------
  2911. //-----------------------------------------------------------------------------
  2912. void AccumulatePatchKeyValues( KeyValues &srcKeyValues, KeyValues &patchKeyValues )
  2913. {
  2914. KeyValues *pDestInsertSection = patchKeyValues.FindKey( "insert" );
  2915. if ( pDestInsertSection == NULL )
  2916. {
  2917. pDestInsertSection = new KeyValues( "insert" );
  2918. patchKeyValues.AddSubKey( pDestInsertSection );
  2919. }
  2920. KeyValues *pDestReplaceSection = patchKeyValues.FindKey( "replace" );
  2921. if ( pDestReplaceSection == NULL )
  2922. {
  2923. pDestReplaceSection = new KeyValues( "replace" );
  2924. patchKeyValues.AddSubKey( pDestReplaceSection );
  2925. }
  2926. KeyValues *pSrcInsertSection = srcKeyValues.FindKey( "insert" );
  2927. if ( pSrcInsertSection )
  2928. {
  2929. MergeKeyValues( *pSrcInsertSection, *pDestInsertSection );
  2930. }
  2931. KeyValues *pSrcReplaceSection = srcKeyValues.FindKey( "replace" );
  2932. if ( pSrcReplaceSection )
  2933. {
  2934. MergeKeyValues( *pSrcReplaceSection, *pDestReplaceSection );
  2935. }
  2936. }
  2937. //-----------------------------------------------------------------------------
  2938. //-----------------------------------------------------------------------------
  2939. bool AccumulateRecursiveVmtPatches( KeyValues &patchKeyValuesOut, KeyValues **ppBaseKeyValuesOut, const KeyValues& keyValues, const char *pPathID, CUtlVector<FileNameHandle_t> *pIncludes )
  2940. {
  2941. if ( pIncludes )
  2942. {
  2943. pIncludes->Purge();
  2944. }
  2945. patchKeyValuesOut.Clear();
  2946. if ( V_stricmp( keyValues.GetName(), "patch" ) != 0 )
  2947. {
  2948. // Not a patch file, nothing to do
  2949. if ( ppBaseKeyValuesOut )
  2950. {
  2951. // flag to the caller that the passed in keyValues are in fact final non-patch values
  2952. *ppBaseKeyValuesOut = NULL;
  2953. }
  2954. return true;
  2955. }
  2956. KeyValues *pCurrentKeyValues = keyValues.MakeCopy();
  2957. // Recurse down through all patch files:
  2958. int nCount = 0;
  2959. while( ( nCount < 10 ) && ( V_stricmp( pCurrentKeyValues->GetName(), "patch" ) == 0 ) )
  2960. {
  2961. // Accumulate the new patch keys from this file
  2962. AccumulatePatchKeyValues( *pCurrentKeyValues, patchKeyValuesOut );
  2963. // Load the included file
  2964. const char *pIncludeFileName = pCurrentKeyValues->GetString( "include" );
  2965. if ( pIncludeFileName == NULL )
  2966. {
  2967. // A patch file without an $include key? Not good...
  2968. Warning( "VMT patch file has no $include key - invalid!\n" );
  2969. Assert( pIncludeFileName );
  2970. break;
  2971. }
  2972. CUtlString includeFileName( pIncludeFileName ); // copy off the string before we clear the keyvalues it lives in
  2973. pCurrentKeyValues->Clear();
  2974. bool bSuccess = pCurrentKeyValues->LoadFromFile( g_pFullFileSystem, includeFileName, pPathID );
  2975. if( bSuccess )
  2976. {
  2977. if ( pIncludes )
  2978. {
  2979. // Remember that we included this file for the pure server stuff.
  2980. pIncludes->AddToTail( g_pFullFileSystem->FindOrAddFileName( includeFileName ) );
  2981. }
  2982. }
  2983. else
  2984. {
  2985. pCurrentKeyValues->deleteThis();
  2986. #ifndef DEDICATED
  2987. {
  2988. Warning( "Failed to load $include VMT file (%s)\n", includeFileName.Get() );
  2989. }
  2990. #endif
  2991. Assert( bSuccess );
  2992. return false;
  2993. }
  2994. nCount++;
  2995. }
  2996. if ( ppBaseKeyValuesOut )
  2997. {
  2998. *ppBaseKeyValuesOut = pCurrentKeyValues;
  2999. }
  3000. else
  3001. {
  3002. pCurrentKeyValues->deleteThis();
  3003. }
  3004. if( nCount >= 10 )
  3005. {
  3006. Warning( "Infinite recursion in patch file?\n" );
  3007. }
  3008. return true;
  3009. }
  3010. //-----------------------------------------------------------------------------
  3011. //-----------------------------------------------------------------------------
  3012. void ExpandPatchFile( KeyValues& keyValues, KeyValues &patchKeyValues, const char *pPathID, CUtlVector<FileNameHandle_t> *pIncludes )
  3013. {
  3014. KeyValues *pNonPatchKeyValues = NULL;
  3015. bool bSuccess = AccumulateRecursiveVmtPatches( patchKeyValues, &pNonPatchKeyValues, keyValues, pPathID, pIncludes );
  3016. if ( !bSuccess )
  3017. {
  3018. return;
  3019. }
  3020. if ( pNonPatchKeyValues != NULL )
  3021. {
  3022. // We're dealing with a patch file. Apply accumulated patches to final vmt
  3023. ApplyPatchKeyValues( *pNonPatchKeyValues, patchKeyValues );
  3024. keyValues = *pNonPatchKeyValues;
  3025. pNonPatchKeyValues->deleteThis();
  3026. }
  3027. }
  3028. //-----------------------------------------------------------------------------
  3029. //-----------------------------------------------------------------------------
  3030. bool LoadVMTFile( KeyValues &vmtKeyValues, KeyValues &patchKeyValues, const char *pMaterialName, bool bAbsolutePath, CUtlVector<FileNameHandle_t> *pIncludes )
  3031. {
  3032. MEM_ALLOC_CREDIT();
  3033. char pFileName[MAX_PATH];
  3034. const char *pPathID = "GAME";
  3035. if ( !bAbsolutePath )
  3036. {
  3037. Q_snprintf( pFileName, sizeof( pFileName ), "materials/%s.vmt", pMaterialName );
  3038. }
  3039. else
  3040. {
  3041. Q_snprintf( pFileName, sizeof( pFileName ), "%s.vmt", pMaterialName );
  3042. if ( pMaterialName[0] == '/' && pMaterialName[1] == '/' && pMaterialName[2] != '/' )
  3043. {
  3044. // UNC, do full search
  3045. pPathID = NULL;
  3046. }
  3047. }
  3048. if ( !vmtKeyValues.LoadFromFile( g_pFullFileSystem, pFileName, pPathID ) )
  3049. {
  3050. return false;
  3051. }
  3052. ExpandPatchFile( vmtKeyValues, patchKeyValues, pPathID, pIncludes );
  3053. return true;
  3054. }
  3055. int CMaterial::GetNumPasses( void )
  3056. {
  3057. Precache_Inline();
  3058. // int mod = m_ShaderRenderState.m_Modulation;
  3059. int mod = 0;
  3060. return m_ShaderRenderState.m_pSnapshots[mod].m_nPassCount;
  3061. }
  3062. int CMaterial::GetTextureMemoryBytes( void )
  3063. {
  3064. Precache_Inline();
  3065. int bytes = 0;
  3066. int i;
  3067. for( i = 0; i < m_VarCount; i++ )
  3068. {
  3069. IMaterialVar *pVar = m_pShaderParams[i];
  3070. if( pVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE )
  3071. {
  3072. ITexture *pTexture = pVar->GetTextureValue();
  3073. if( pTexture && pTexture != ( ITexture * )0xffffffff )
  3074. {
  3075. bytes += pTexture->GetApproximateVidMemBytes();
  3076. }
  3077. }
  3078. }
  3079. return bytes;
  3080. }
  3081. bool CMaterial::NeedsFixedFunctionFlashlight() const
  3082. {
  3083. return ( GetMaterialVarFlags2() & MATERIAL_VAR2_NEEDS_FIXED_FUNCTION_FLASHLIGHT ) &&
  3084. MaterialSystem()->InFlashlightMode();
  3085. }
  3086. bool CMaterial::IsUsingVertexID( ) const
  3087. {
  3088. return ( GetMaterialVarFlags2() & MATERIAL_VAR2_USES_VERTEXID ) != 0;
  3089. }
  3090. void CMaterial::DeleteIfUnreferenced()
  3091. {
  3092. if ( m_RefCount > 0 )
  3093. return;
  3094. IMaterialVar::DeleteUnreferencedTextures( true );
  3095. MaterialSystem()->RemoveMaterial( this );
  3096. IMaterialVar::DeleteUnreferencedTextures( false );
  3097. }
  3098. void CMaterial::CompactMaterialVars()
  3099. {
  3100. if ( m_ProxyCount == 0)
  3101. {
  3102. ::CompactMaterialVars( GetShaderParams(), ShaderParamCount() );
  3103. }
  3104. }
  3105. bool CMaterial::HasQueueFriendlyProxies() const
  3106. {
  3107. if ( !HasProxy() )
  3108. return false;
  3109. bool anyAsync = false;
  3110. bool allAsync = true;
  3111. for ( int i = 0; i < m_ProxyCount; ++i )
  3112. {
  3113. const bool isAsync = m_ppProxies[ i ]->CanBeCalledAsync();
  3114. anyAsync = anyAsync || isAsync;
  3115. allAsync = allAsync && isAsync;
  3116. }
  3117. // The code doesn't currently handle this, it would need to be updated.
  3118. Assert( anyAsync == allAsync );
  3119. return anyAsync;
  3120. }
  3121. bool CMaterial::SetTempExcluded( bool bSet, int nExcludedDimensionLimit )
  3122. {
  3123. // iterate all texture variables
  3124. for ( int i = 0; i < m_VarCount; i++ )
  3125. {
  3126. // there are some texture which we will absolutely not temp exclude
  3127. if ( i == FLASHLIGHTTEXTURE )
  3128. continue;
  3129. IMaterialVar *pVar = m_pShaderParams[i];
  3130. if ( !pVar ||
  3131. pVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE ||
  3132. pVar->IsTextureValueInternalEnvCubemap() )
  3133. {
  3134. // not possible to temp exclude these
  3135. continue;
  3136. }
  3137. ITexture *pTexture = pVar->GetTextureValue();
  3138. if ( pTexture && ((ITextureInternal*)pTexture)->MarkAsTempExcluded( bSet, nExcludedDimensionLimit ) )
  3139. {
  3140. DevMsg( "SetTempExcluded: %s: %s (%d)\n", bSet ? "Excluding" : "Restoring", pTexture->GetName(), ((ITextureInternal*)pTexture)->GetReferenceCount() );
  3141. ((ITextureInternal*)pTexture)->UpdateExcludedState();
  3142. }
  3143. }
  3144. return true;
  3145. }