Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2057 lines
64 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "shadersystem.h"
  7. #include <stdlib.h>
  8. #include "materialsystem_global.h"
  9. #include "filesystem.h"
  10. #include "tier1/utldict.h"
  11. #include "shaderlib/ShaderDLL.h"
  12. #include "texturemanager.h"
  13. #include "itextureinternal.h"
  14. #include "IHardwareConfigInternal.h"
  15. #include "tier1/utlstack.h"
  16. #include "tier1/utlbuffer.h"
  17. #include "mathlib/vmatrix.h"
  18. #include "imaterialinternal.h"
  19. #include "tier1/strtools.h"
  20. #include "tier0/icommandline.h"
  21. #include "shaderlib/cshader.h"
  22. #include "tier1/convar.h"
  23. #include "tier1/KeyValues.h"
  24. #include "shader_dll_verify.h"
  25. #include "tier0/vprof.h"
  26. // NOTE: This must be the last file included!
  27. #include "tier0/memdbgon.h"
  28. //#define DEBUG_DEPTH 1
  29. //-----------------------------------------------------------------------------
  30. // Lovely convars
  31. //-----------------------------------------------------------------------------
  32. static ConVar mat_showenvmapmask( "mat_showenvmapmask", "0" );
  33. static ConVar mat_debugdepth( "mat_debugdepth", "0" );
  34. extern ConVar mat_supportflashlight;
  35. //-----------------------------------------------------------------------------
  36. // Implementation of the shader system
  37. //-----------------------------------------------------------------------------
  38. class CShaderSystem : public IShaderSystemInternal
  39. {
  40. public:
  41. CShaderSystem();
  42. // Methods of IShaderSystem
  43. virtual ShaderAPITextureHandle_t GetShaderAPITextureBindHandle( ITexture *pTexture, int nFrameVar, int nTextureChannel = 0 );
  44. virtual void BindTexture( Sampler_t sampler1, ITexture *pTexture, int nFrame = 0 );
  45. virtual void BindTexture( Sampler_t sampler1, Sampler_t sampler2, ITexture *pTexture, int nFrame = 0 );
  46. virtual void TakeSnapshot( );
  47. virtual void DrawSnapshot( bool bMakeActualDrawCall = true );
  48. virtual bool IsUsingGraphics() const;
  49. virtual bool CanUseEditorMaterials() const;
  50. // Methods of IShaderSystemInternal
  51. virtual void Init();
  52. virtual void Shutdown();
  53. virtual void ModInit();
  54. virtual void ModShutdown();
  55. virtual bool LoadShaderDLL( const char *pFullPath );
  56. virtual bool LoadShaderDLL( const char *pFullPath, const char *pPathID, bool bModShaderDLL );
  57. virtual void UnloadShaderDLL( const char *pFullPath );
  58. virtual IShader* FindShader( char const* pShaderName );
  59. virtual void CreateDebugMaterials();
  60. virtual void CleanUpDebugMaterials();
  61. virtual char const* ShaderStateString( int i ) const;
  62. virtual int ShaderStateCount( ) const;
  63. virtual void InitShaderParameters( IShader *pShader, IMaterialVar **params, const char *pMaterialName );
  64. virtual void InitShaderInstance( IShader *pShader, IMaterialVar **params, const char *pMaterialName, const char *pTextureGroupName );
  65. virtual bool InitRenderState( IShader *pShader, int numParams, IMaterialVar **params, ShaderRenderState_t* pRenderState, char const* pMaterialName );
  66. virtual void CleanupRenderState( ShaderRenderState_t* pRenderState );
  67. virtual void DrawElements( IShader *pShader, IMaterialVar **params, ShaderRenderState_t* pShaderState, VertexCompressionType_t vertexCompression, uint32 nVarChangeID );
  68. // Used to iterate over all shaders for editing purposes
  69. virtual int ShaderCount() const;
  70. virtual int GetShaders( int nFirstShader, int nMaxCount, IShader **ppShaderList ) const;
  71. // Methods of IShaderInit
  72. virtual void LoadTexture( IMaterialVar *pTextureVar, const char *pTextureGroupName, int nAdditionalCreationFlags = 0 );
  73. virtual void LoadBumpMap( IMaterialVar *pTextureVar, const char *pTextureGroupName );
  74. virtual void LoadCubeMap( IMaterialVar **ppParams, IMaterialVar *pTextureVar, int nAdditionalCreationFlags = 0 );
  75. // Used to prevent re-entrant rendering from warning messages
  76. void BufferSpew( SpewType_t spewType, const Color &c, const char *pMsg );
  77. private:
  78. struct ShaderDLLInfo_t
  79. {
  80. char *m_pFileName;
  81. CSysModule *m_hInstance;
  82. IShaderDLLInternal *m_pShaderDLL;
  83. ShaderDLL_t m_hShaderDLL;
  84. // True if this is a mod's shader DLL, in which case it's not allowed to
  85. // override any existing shader names.
  86. bool m_bModShaderDLL;
  87. CUtlDict< IShader *, unsigned short > m_ShaderDict;
  88. };
  89. private:
  90. // hackhack: remove this when VAC2 is online.
  91. void VerifyBaseShaderDLL( CSysModule *pModule );
  92. // Load up the shader DLLs...
  93. void LoadAllShaderDLLs();
  94. // Load the "mshader_" DLLs.
  95. void LoadModShaderDLLs( int dxSupportLevel );
  96. // Unload all the shader DLLs...
  97. void UnloadAllShaderDLLs();
  98. // Sets up the shader dictionary.
  99. void SetupShaderDictionary( int nShaderDLLIndex );
  100. // Cleans up the shader dictionary.
  101. void CleanupShaderDictionary( int nShaderDLLIndex );
  102. // Finds an already loaded shader DLL
  103. int FindShaderDLL( const char *pFullPath );
  104. // Unloads a particular shader DLL
  105. void UnloadShaderDLL( int nShaderDLLIndex );
  106. // Sets up the current ShaderState_t for rendering
  107. void PrepForShaderDraw( IShader *pShader, IMaterialVar** ppParams,
  108. ShaderRenderState_t* pRenderState, int modulation );
  109. void DoneWithShaderDraw();
  110. // Initializes state snapshots
  111. void InitStateSnapshots( IShader *pShader, IMaterialVar **params, ShaderRenderState_t* pRenderState );
  112. // Compute snapshots for all combinations of alpha + color modulation
  113. void InitRenderStateFlags( ShaderRenderState_t* pRenderState, int numParams, IMaterialVar **params );
  114. // Computes flags from a particular snapshot
  115. void ComputeRenderStateFlagsFromSnapshot( ShaderRenderState_t* pRenderState );
  116. // Computes vertex format + usage from a particular snapshot
  117. bool ComputeVertexFormatFromSnapshot( IMaterialVar **params, ShaderRenderState_t* pRenderState );
  118. // Used to prevent re-entrant rendering from warning messages
  119. void PrintBufferedSpew( void );
  120. // Gets at the current snapshot
  121. StateSnapshot_t CurrentStateSnapshot();
  122. // Draws using a particular material..
  123. void DrawUsingMaterial( IMaterialInternal *pMaterial, VertexCompressionType_t vertexCompression );
  124. // Copies material vars
  125. void CopyMaterialVarToDebugShader( IMaterialInternal *pDebugMaterial, IShader *pShader, IMaterialVar **ppParams, const char *pSrcVarName, const char *pDstVarName = NULL );
  126. // Debugging draw methods...
  127. void DrawMeasureFillRate( ShaderRenderState_t* pRenderState, int mod, VertexCompressionType_t vertexCompression );
  128. void DrawNormalMap( IShader *pShader, IMaterialVar **ppParams, VertexCompressionType_t vertexCompression );
  129. bool DrawEnvmapMask( IShader *pShader, IMaterialVar **ppParams, ShaderRenderState_t* pRenderState, VertexCompressionType_t vertexCompression );
  130. int GetModulationSnapshotCount( IMaterialVar **params );
  131. private:
  132. // List of all DLLs containing shaders
  133. CUtlVector< ShaderDLLInfo_t > m_ShaderDLLs;
  134. // Used to prevent re-entrant rendering from warning messages
  135. SpewOutputFunc_t m_SaveSpewOutput;
  136. CUtlBuffer m_StoredSpew;
  137. // Render state we're drawing with
  138. ShaderRenderState_t* m_pRenderState;
  139. unsigned short m_hShaderDLL;
  140. unsigned char m_nModulation;
  141. unsigned char m_nRenderPass;
  142. // Debugging materials
  143. // If you add to this, add to the list of debug shader names (s_pDebugShaderName) below
  144. enum
  145. {
  146. MATERIAL_FILL_RATE = 0,
  147. MATERIAL_DEBUG_NORMALMAP,
  148. MATERIAL_DEBUG_ENVMAPMASK,
  149. MATERIAL_DEBUG_DEPTH,
  150. MATERIAL_DEBUG_DEPTH_DECAL,
  151. MATERIAL_DEBUG_WIREFRAME,
  152. MATERIAL_DEBUG_COUNT,
  153. };
  154. IMaterialInternal* m_pDebugMaterials[MATERIAL_DEBUG_COUNT];
  155. static const char *s_pDebugShaderName[MATERIAL_DEBUG_COUNT];
  156. bool m_bForceUsingGraphicsReturnTrue;
  157. };
  158. //-----------------------------------------------------------------------------
  159. // Singleton
  160. //-----------------------------------------------------------------------------
  161. static CShaderSystem s_ShaderSystem;
  162. IShaderSystemInternal *g_pShaderSystem = &s_ShaderSystem;
  163. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CShaderSystem, IShaderSystem,
  164. SHADERSYSTEM_INTERFACE_VERSION, s_ShaderSystem );
  165. //-----------------------------------------------------------------------------
  166. // Debugging shader names
  167. //-----------------------------------------------------------------------------
  168. const char *CShaderSystem::s_pDebugShaderName[MATERIAL_DEBUG_COUNT] =
  169. {
  170. "FillRate",
  171. "DebugNormalMap",
  172. "DebugDrawEnvmapMask",
  173. "DebugDepth",
  174. "DebugDepth",
  175. "Wireframe_DX9"
  176. };
  177. //-----------------------------------------------------------------------------
  178. // Constructor
  179. //-----------------------------------------------------------------------------
  180. CShaderSystem::CShaderSystem() : m_StoredSpew( 0, 512, 0 ), m_bForceUsingGraphicsReturnTrue( false )
  181. {
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Initialization, shutdown
  185. //-----------------------------------------------------------------------------
  186. void CShaderSystem::Init()
  187. {
  188. m_SaveSpewOutput = NULL;
  189. m_bForceUsingGraphicsReturnTrue = false;
  190. if ( CommandLine()->FindParm( "-noshaderapi" ) ||
  191. CommandLine()->FindParm( "-makereslists" ) )
  192. {
  193. m_bForceUsingGraphicsReturnTrue = true;
  194. }
  195. for ( int i = 0; i < MATERIAL_DEBUG_COUNT; ++i )
  196. {
  197. m_pDebugMaterials[i] = NULL;
  198. }
  199. LoadAllShaderDLLs();
  200. }
  201. void CShaderSystem::Shutdown()
  202. {
  203. UnloadAllShaderDLLs();
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Load/unload mod-specific shader DLLs
  207. //-----------------------------------------------------------------------------
  208. void CShaderSystem::ModInit()
  209. {
  210. // Load up standard shader DLLs...
  211. int dxSupportLevel = HardwareConfig()->GetMaxDXSupportLevel();
  212. Assert( dxSupportLevel >= 60 );
  213. dxSupportLevel /= 10;
  214. LoadModShaderDLLs( dxSupportLevel );
  215. }
  216. void CShaderSystem::ModShutdown()
  217. {
  218. // Unload only MOD dlls
  219. for ( int i = m_ShaderDLLs.Count(); --i >= 0; )
  220. {
  221. if ( m_ShaderDLLs[i].m_bModShaderDLL )
  222. {
  223. UnloadShaderDLL(i);
  224. delete[] m_ShaderDLLs[i].m_pFileName;
  225. m_ShaderDLLs.Remove( i );
  226. }
  227. }
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Load up the shader DLLs...
  231. //-----------------------------------------------------------------------------
  232. void CShaderSystem::LoadAllShaderDLLs( )
  233. {
  234. UnloadAllShaderDLLs();
  235. GetShaderDLLInternal()->Connect( Sys_GetFactoryThis(), true );
  236. // Loads local defined or statically linked shaders
  237. int i = m_ShaderDLLs.AddToHead();
  238. m_ShaderDLLs[i].m_pFileName = new char[1];
  239. m_ShaderDLLs[i].m_pFileName[0] = 0;
  240. m_ShaderDLLs[i].m_hInstance = NULL;
  241. m_ShaderDLLs[i].m_pShaderDLL = GetShaderDLLInternal();
  242. m_ShaderDLLs[i].m_bModShaderDLL = false;
  243. // Add the shaders to the dictionary of shaders...
  244. SetupShaderDictionary( i );
  245. // 360 has the the debug shaders in its dx9 dll
  246. if ( IsPC() || !IsX360() )
  247. {
  248. // Always need the debug shaders
  249. LoadShaderDLL( "stdshader_dbg" DLL_EXT_STRING );
  250. }
  251. // Load up standard shader DLLs...
  252. int dxSupportLevel = HardwareConfig()->GetMaxDXSupportLevel();
  253. Assert( dxSupportLevel >= 60 );
  254. dxSupportLevel /= 10;
  255. // 360 only supports its dx9 dll
  256. int dxStart = IsX360() ? 9 : 6;
  257. char buf[32];
  258. for ( i = dxStart; i <= dxSupportLevel; ++i )
  259. {
  260. Q_snprintf( buf, sizeof( buf ), "stdshader_dx%d%s", i, DLL_EXT_STRING );
  261. LoadShaderDLL( buf );
  262. }
  263. const char *pShaderName = NULL;
  264. #ifdef _DEBUG
  265. pShaderName = CommandLine()->ParmValue( "-shader" );
  266. #endif
  267. if ( !pShaderName )
  268. {
  269. pShaderName = HardwareConfig()->GetHWSpecificShaderDLLName();
  270. }
  271. if ( pShaderName )
  272. {
  273. LoadShaderDLL( pShaderName );
  274. }
  275. #ifdef _DEBUG
  276. // For fast-iteration debugging
  277. if ( CommandLine()->FindParm( "-testshaders" ) )
  278. {
  279. LoadShaderDLL( "shader_test" DLL_EXT_STRING );
  280. }
  281. #endif
  282. }
  283. const char *COM_GetModDirectory()
  284. {
  285. static char modDir[MAX_PATH];
  286. if ( Q_strlen( modDir ) == 0 )
  287. {
  288. const char *gamedir = CommandLine()->ParmValue("-game", CommandLine()->ParmValue( "-defaultgamedir", "hl2" ) );
  289. Q_strncpy( modDir, gamedir, sizeof(modDir) );
  290. if ( strchr( modDir, '/' ) || strchr( modDir, '\\' ) )
  291. {
  292. Q_StripLastDir( modDir, sizeof(modDir) );
  293. int dirlen = Q_strlen( modDir );
  294. Q_strncpy( modDir, gamedir + dirlen, sizeof(modDir) - dirlen );
  295. }
  296. }
  297. return modDir;
  298. }
  299. void CShaderSystem::LoadModShaderDLLs( int dxSupportLevel )
  300. {
  301. if ( IsX360() )
  302. return;
  303. // Don't do this for Valve mods. They don't need them, and attempting to load them is an opportunity for cheaters to get their code into the process
  304. const char *pGameDir = COM_GetModDirectory();
  305. if ( !Q_stricmp( pGameDir, "hl2" ) || !Q_stricmp( pGameDir, "cstrike" ) || !Q_stricmp( pGameDir, "cstrike_beta" ) ||
  306. !Q_stricmp( pGameDir, "hl2mp" ) || !Q_stricmp( pGameDir, "lostcoast" ) || !Q_stricmp( pGameDir, "episodic" ) ||
  307. !Q_stricmp( pGameDir, "portal" ) || !Q_stricmp( pGameDir, "ep2" ) || !Q_stricmp( pGameDir, "dod" ) ||
  308. !Q_stricmp( pGameDir, "tf" ) || !Q_stricmp( pGameDir, "tf_beta" ) || !Q_stricmp( pGameDir, "hl1" ) )
  309. {
  310. return;
  311. }
  312. const char *pModShaderPathID = "GAMEBIN";
  313. // First load the ones with dx_ prefix.
  314. char buf[256];
  315. int dxStart = 6;
  316. for ( int i = dxStart; i <= dxSupportLevel; ++i )
  317. {
  318. Q_snprintf( buf, sizeof( buf ), "game_shader_dx%d%s", i, DLL_EXT_STRING );
  319. LoadShaderDLL( buf, pModShaderPathID, true );
  320. }
  321. // Now load the ones with any dx_ prefix.
  322. FileFindHandle_t findHandle;
  323. const char *pFilename = g_pFullFileSystem->FindFirstEx( "game_shader_generic*", pModShaderPathID, &findHandle );
  324. while ( pFilename )
  325. {
  326. Q_snprintf( buf, sizeof( buf ), "%s%s", pFilename, DLL_EXT_STRING );
  327. LoadShaderDLL( buf, pModShaderPathID, true );
  328. pFilename = g_pFullFileSystem->FindNext( findHandle );
  329. }
  330. }
  331. //-----------------------------------------------------------------------------
  332. // Unload all the shader DLLs...
  333. //-----------------------------------------------------------------------------
  334. void CShaderSystem::UnloadAllShaderDLLs()
  335. {
  336. if ( m_ShaderDLLs.Count() == 0 )
  337. return;
  338. for ( int i = m_ShaderDLLs.Count(); --i >= 0; )
  339. {
  340. UnloadShaderDLL(i);
  341. delete[] m_ShaderDLLs[i].m_pFileName;
  342. }
  343. m_ShaderDLLs.RemoveAll();
  344. }
  345. bool CShaderSystem::LoadShaderDLL( const char *pFullPath )
  346. {
  347. return LoadShaderDLL( pFullPath, NULL, false );
  348. }
  349. // HACKHACK: remove me when VAC2 is online.
  350. #if defined( _WIN32 ) && !defined( _X360 )
  351. // Instead of including windows.h
  352. extern "C"
  353. {
  354. extern void * __stdcall GetProcAddress( void *hModule, const char *pszProcName );
  355. };
  356. #endif
  357. void CShaderSystem::VerifyBaseShaderDLL( CSysModule *pModule )
  358. {
  359. #if defined( _WIN32 ) && !defined( _X360 )
  360. const char *pErrorStr = "Corrupt save data settings.";
  361. unsigned char *testData1 = new unsigned char[SHADER_DLL_VERIFY_DATA_LEN1];
  362. ShaderDLLVerifyFn fn = (ShaderDLLVerifyFn)GetProcAddress( (void *)pModule, SHADER_DLL_FNNAME_1 );
  363. if ( !fn )
  364. Error( pErrorStr );
  365. IShaderDLLVerification *pVerify;
  366. char *pPtr = (char*)(void*)&pVerify;
  367. pPtr -= SHADER_DLL_VERIFY_DATA_PTR_OFFSET;
  368. fn( pPtr );
  369. // Test the first CRC.
  370. CRC32_t testCRC;
  371. CRC32_Init( &testCRC );
  372. CRC32_ProcessBuffer( &testCRC, testData1, SHADER_DLL_VERIFY_DATA_LEN1 );
  373. CRC32_ProcessBuffer( &testCRC, &pModule, 4 );
  374. CRC32_ProcessBuffer( &testCRC, &pVerify, 4 );
  375. CRC32_Final( &testCRC );
  376. if ( testCRC != pVerify->Function1( testData1 - SHADER_DLL_VERIFY_DATA_PTR_OFFSET ) )
  377. Error( pErrorStr );
  378. // Test the next one.
  379. unsigned char digest[MD5_DIGEST_LENGTH];
  380. MD5Context_t md5Context;
  381. MD5Init( &md5Context );
  382. MD5Update( &md5Context, testData1 + SHADER_DLL_VERIFY_DATA_PTR_OFFSET, SHADER_DLL_VERIFY_DATA_LEN1 - SHADER_DLL_VERIFY_DATA_PTR_OFFSET );
  383. MD5Final( digest, &md5Context );
  384. pVerify->Function2( 2, 3, 3 ); // fn2 is supposed to place the result in testData1.
  385. if ( memcmp( digest, testData1, MD5_DIGEST_LENGTH ) != 0 )
  386. Error( pErrorStr );
  387. pVerify->Function5();
  388. delete [] testData1;
  389. #endif
  390. }
  391. //-----------------------------------------------------------------------------
  392. // Methods related to reading in shader DLLs
  393. //-----------------------------------------------------------------------------
  394. bool CShaderSystem::LoadShaderDLL( const char *pFullPath, const char *pPathID, bool bModShaderDLL )
  395. {
  396. if ( !pFullPath && !pFullPath[0] )
  397. return true;
  398. // Load the new shader
  399. bool bValidatedDllOnly = true;
  400. if ( bModShaderDLL )
  401. bValidatedDllOnly = false;
  402. CSysModule *hInstance = g_pFullFileSystem->LoadModule( pFullPath, pPathID, bValidatedDllOnly );
  403. if ( !hInstance )
  404. return false;
  405. // Get at the shader DLL interface
  406. CreateInterfaceFn factory = Sys_GetFactory( hInstance );
  407. if (!factory)
  408. {
  409. g_pFullFileSystem->UnloadModule( hInstance );
  410. return false;
  411. }
  412. IShaderDLLInternal *pShaderDLL = (IShaderDLLInternal*)factory( SHADER_DLL_INTERFACE_VERSION, NULL );
  413. if ( !pShaderDLL )
  414. {
  415. g_pFullFileSystem->UnloadModule( hInstance );
  416. return false;
  417. }
  418. // Make sure it's a valid base shader DLL if necessary.
  419. //HACKHACK get rid of this when VAC2 comes online.
  420. if ( !bModShaderDLL )
  421. {
  422. VerifyBaseShaderDLL( hInstance );
  423. }
  424. // Allow the DLL to try to connect to interfaces it needs
  425. if ( !pShaderDLL->Connect( Sys_GetFactoryThis(), false ) )
  426. {
  427. g_pFullFileSystem->UnloadModule( hInstance );
  428. return false;
  429. }
  430. // FIXME: We need to do some sort of shader validation here for anticheat.
  431. // Now replace any existing shader
  432. int nShaderDLLIndex = FindShaderDLL( pFullPath );
  433. if ( nShaderDLLIndex >= 0 )
  434. {
  435. UnloadShaderDLL( nShaderDLLIndex );
  436. }
  437. else
  438. {
  439. nShaderDLLIndex = m_ShaderDLLs.AddToTail();
  440. int nLen = Q_strlen(pFullPath) + 1;
  441. m_ShaderDLLs[nShaderDLLIndex].m_pFileName = new char[ nLen ];
  442. Q_strncpy( m_ShaderDLLs[nShaderDLLIndex].m_pFileName, pFullPath, nLen );
  443. }
  444. // Ok, the shader DLL's good!
  445. m_ShaderDLLs[nShaderDLLIndex].m_hInstance = hInstance;
  446. m_ShaderDLLs[nShaderDLLIndex].m_pShaderDLL = pShaderDLL;
  447. m_ShaderDLLs[nShaderDLLIndex].m_bModShaderDLL = bModShaderDLL;
  448. // Add the shaders to the dictionary of shaders...
  449. SetupShaderDictionary( nShaderDLLIndex );
  450. // FIXME: Fix up existing materials that were using shaders that have
  451. // been reloaded?
  452. return true;
  453. }
  454. //-----------------------------------------------------------------------------
  455. // Finds an already loaded shader DLL
  456. //-----------------------------------------------------------------------------
  457. int CShaderSystem::FindShaderDLL( const char *pFullPath )
  458. {
  459. for ( int i = m_ShaderDLLs.Count(); --i >= 0; )
  460. {
  461. if ( !Q_stricmp( pFullPath, m_ShaderDLLs[i].m_pFileName ) )
  462. return i;
  463. }
  464. return -1;
  465. }
  466. //-----------------------------------------------------------------------------
  467. // Unloads a particular shader DLL
  468. //-----------------------------------------------------------------------------
  469. void CShaderSystem::UnloadShaderDLL( int nShaderDLLIndex )
  470. {
  471. if ( nShaderDLLIndex < 0 )
  472. return;
  473. // FIXME: Do some sort of fixup of materials to determine which
  474. // materials are referencing shaders in this DLL?
  475. CleanupShaderDictionary( nShaderDLLIndex );
  476. IShaderDLLInternal *pShaderDLL = m_ShaderDLLs[nShaderDLLIndex].m_pShaderDLL;
  477. pShaderDLL->Disconnect( pShaderDLL == GetShaderDLLInternal() );
  478. if ( m_ShaderDLLs[nShaderDLLIndex].m_hInstance )
  479. {
  480. g_pFullFileSystem->UnloadModule( m_ShaderDLLs[nShaderDLLIndex].m_hInstance );
  481. }
  482. }
  483. //-----------------------------------------------------------------------------
  484. // Unloads a particular shader DLL
  485. //-----------------------------------------------------------------------------
  486. void CShaderSystem::UnloadShaderDLL( const char *pFullPath )
  487. {
  488. int nShaderDLLIndex = FindShaderDLL( pFullPath );
  489. if ( nShaderDLLIndex >= 0 )
  490. {
  491. UnloadShaderDLL( nShaderDLLIndex );
  492. delete[] m_ShaderDLLs[nShaderDLLIndex].m_pFileName;
  493. m_ShaderDLLs.Remove( nShaderDLLIndex );
  494. }
  495. }
  496. //-----------------------------------------------------------------------------
  497. // Make sure these match the bits in imaterial.h
  498. //-----------------------------------------------------------------------------
  499. static const char* s_pShaderStateString[] =
  500. {
  501. "$debug",
  502. "$no_fullbright",
  503. "$no_draw",
  504. "$use_in_fillrate_mode",
  505. "$vertexcolor",
  506. "$vertexalpha",
  507. "$selfillum",
  508. "$additive",
  509. "$alphatest",
  510. "$multipass",
  511. "$znearer",
  512. "$model",
  513. "$flat",
  514. "$nocull",
  515. "$nofog",
  516. "$ignorez",
  517. "$decal",
  518. "$envmapsphere",
  519. "$noalphamod",
  520. "$envmapcameraspace",
  521. "$basealphaenvmapmask",
  522. "$translucent",
  523. "$normalmapalphaenvmapmask",
  524. "$softwareskin",
  525. "$opaquetexture",
  526. "$envmapmode",
  527. "$nodecal",
  528. "$halflambert",
  529. "$wireframe",
  530. "$allowalphatocoverage",
  531. "" // last one must be null
  532. };
  533. //-----------------------------------------------------------------------------
  534. // returns strings associated with the shader state flags...
  535. // If you modify this, make sure and modify MaterialVarFlags_t in imaterial.h
  536. //-----------------------------------------------------------------------------
  537. int CShaderSystem::ShaderStateCount( ) const
  538. {
  539. return sizeof( s_pShaderStateString ) / sizeof( char* ) - 1;
  540. }
  541. //-----------------------------------------------------------------------------
  542. // returns strings associated with the shader state flags...
  543. // If you modify this, make sure and modify MaterialVarFlags_t in imaterial.h
  544. //-----------------------------------------------------------------------------
  545. char const* CShaderSystem::ShaderStateString( int i ) const
  546. {
  547. return s_pShaderStateString[i];
  548. }
  549. //-----------------------------------------------------------------------------
  550. // Sets up the shader dictionary.
  551. //-----------------------------------------------------------------------------
  552. void CShaderSystem::SetupShaderDictionary( int nShaderDLLIndex )
  553. {
  554. // We could have put the shader dictionary into each shader DLL
  555. // I'm not sure if that makes this system any less secure than it already is
  556. int i;
  557. ShaderDLLInfo_t &info = m_ShaderDLLs[nShaderDLLIndex];
  558. int nCount = info.m_pShaderDLL->ShaderCount();
  559. for ( i = 0; i < nCount; ++i )
  560. {
  561. IShader *pShader = info.m_pShaderDLL->GetShader( i );
  562. const char *pShaderName = pShader->GetName();
  563. #ifdef POSIX
  564. if (CommandLine()->FindParm("-glmspew"))
  565. printf("CShaderSystem::SetupShaderDictionary: %s", pShaderName );
  566. #endif
  567. // Make sure it doesn't try to override another shader DLL's names.
  568. if ( info.m_bModShaderDLL )
  569. {
  570. for ( int iTestDLL=0; iTestDLL < m_ShaderDLLs.Count(); iTestDLL++ )
  571. {
  572. ShaderDLLInfo_t *pTestDLL = &m_ShaderDLLs[iTestDLL];
  573. if ( !pTestDLL->m_bModShaderDLL )
  574. {
  575. if ( pTestDLL->m_ShaderDict.Find( pShaderName ) != pTestDLL->m_ShaderDict.InvalidIndex() )
  576. {
  577. Error( "Game shader '%s' trying to override a base shader '%s'.", info.m_pFileName, pShaderName );
  578. }
  579. }
  580. }
  581. }
  582. info.m_ShaderDict.Insert( pShaderName, pShader );
  583. }
  584. }
  585. //-----------------------------------------------------------------------------
  586. // Cleans up the shader dictionary.
  587. //-----------------------------------------------------------------------------
  588. void CShaderSystem::CleanupShaderDictionary( int nShaderDLLIndex )
  589. {
  590. }
  591. //-----------------------------------------------------------------------------
  592. // Finds a shader in the shader dictionary
  593. //-----------------------------------------------------------------------------
  594. IShader* CShaderSystem::FindShader( char const* pShaderName )
  595. {
  596. // FIXME: What kind of search order should we use here?
  597. // I'm currently assuming last added, first searched.
  598. for (int i = m_ShaderDLLs.Count(); --i >= 0; )
  599. {
  600. ShaderDLLInfo_t &info = m_ShaderDLLs[i];
  601. unsigned short idx = info.m_ShaderDict.Find( pShaderName );
  602. if ( idx != info.m_ShaderDict.InvalidIndex() )
  603. {
  604. return info.m_ShaderDict[idx];
  605. }
  606. }
  607. return NULL;
  608. }
  609. //-----------------------------------------------------------------------------
  610. // Used to iterate over all shaders for editing purposes
  611. //-----------------------------------------------------------------------------
  612. int CShaderSystem::ShaderCount() const
  613. {
  614. return GetShaders( 0, 65536, NULL );
  615. }
  616. int CShaderSystem::GetShaders( int nFirstShader, int nMaxCount, IShader **ppShaderList ) const
  617. {
  618. CUtlSymbolTable uniqueNames( 0, 512, true );
  619. int nCount = 0;
  620. int nActualCount = 0;
  621. for ( int i = m_ShaderDLLs.Count(); --i >= 0; )
  622. {
  623. const ShaderDLLInfo_t &info = m_ShaderDLLs[i];
  624. for ( unsigned short j = info.m_ShaderDict.First();
  625. j != info.m_ShaderDict.InvalidIndex();
  626. j = info.m_ShaderDict.Next( j ) )
  627. {
  628. // Don't add shaders twice
  629. const char *pShaderName = info.m_ShaderDict.GetElementName( j );
  630. if ( uniqueNames.Find( pShaderName ) != UTL_INVAL_SYMBOL )
  631. continue;
  632. // Indicate we've seen this shader
  633. uniqueNames.AddString( pShaderName );
  634. ++nActualCount;
  635. if ( nActualCount > nFirstShader )
  636. {
  637. if ( ppShaderList )
  638. {
  639. ppShaderList[ nCount ] = info.m_ShaderDict[j];
  640. }
  641. ++nCount;
  642. if ( nCount >= nMaxCount )
  643. return nCount;
  644. }
  645. }
  646. }
  647. return nCount;
  648. }
  649. //-----------------------------------------------------------------------------
  650. //
  651. // Methods of IShaderInit lie below
  652. //
  653. //-----------------------------------------------------------------------------
  654. //-----------------------------------------------------------------------------
  655. // Gets at the render pass info for this pass...
  656. //-----------------------------------------------------------------------------
  657. inline StateSnapshot_t CShaderSystem::CurrentStateSnapshot()
  658. {
  659. Assert( m_pRenderState );
  660. Assert( m_nRenderPass < MAX_RENDER_PASSES );
  661. Assert( m_nRenderPass < m_pRenderState->m_pSnapshots[m_nModulation].m_nPassCount );
  662. return m_pRenderState->m_pSnapshots[m_nModulation].m_Snapshot[m_nRenderPass];
  663. }
  664. //-----------------------------------------------------------------------------
  665. // Create debugging materials
  666. //-----------------------------------------------------------------------------
  667. void CShaderSystem::CreateDebugMaterials()
  668. {
  669. if (m_pDebugMaterials[0])
  670. return;
  671. KeyValues *pVMTKeyValues[MATERIAL_DEBUG_COUNT];
  672. int i;
  673. for ( i = 0; i < MATERIAL_DEBUG_COUNT; ++i )
  674. {
  675. pVMTKeyValues[i] = new KeyValues( s_pDebugShaderName[i] );
  676. }
  677. pVMTKeyValues[MATERIAL_DEBUG_DEPTH_DECAL]->SetInt( "$decal", 1 );
  678. for ( i = 0; i < MATERIAL_DEBUG_COUNT; ++i )
  679. {
  680. char shaderName[64];
  681. Q_snprintf( shaderName, sizeof( shaderName ), "___%s_%d.vmt", s_pDebugShaderName[i], i );
  682. m_pDebugMaterials[i] = static_cast<IMaterialInternal*>(MaterialSystem()->CreateMaterial( shaderName, pVMTKeyValues[i] ));
  683. if( m_pDebugMaterials[i] )
  684. m_pDebugMaterials[i] = m_pDebugMaterials[i]->GetRealTimeVersion();
  685. }
  686. }
  687. //-----------------------------------------------------------------------------
  688. // Cleans up the debugging materials
  689. //-----------------------------------------------------------------------------
  690. void CShaderSystem::CleanUpDebugMaterials()
  691. {
  692. if (m_pDebugMaterials[0])
  693. {
  694. for ( int i = 0; i < MATERIAL_DEBUG_COUNT; ++i )
  695. {
  696. m_pDebugMaterials[i]->DecrementReferenceCount();
  697. if ( m_pDebugMaterials[i]->InMaterialPage() )
  698. {
  699. MaterialSystem()->RemoveMaterialSubRect( m_pDebugMaterials[i] );
  700. }
  701. else
  702. {
  703. MaterialSystem()->RemoveMaterial( m_pDebugMaterials[i] );
  704. }
  705. m_pDebugMaterials[i] = NULL;
  706. }
  707. }
  708. }
  709. //-----------------------------------------------------------------------------
  710. // Deal with buffering of spew while doing shader draw so that we don't get
  711. // recursive spew during precache due to fonts not being loaded, etc.
  712. //-----------------------------------------------------------------------------
  713. CThreadFastMutex g_StgoredSpewMutex;
  714. void CShaderSystem::BufferSpew( SpewType_t spewType, const Color &c, const char *pMsg )
  715. {
  716. AUTO_LOCK( g_StgoredSpewMutex );
  717. m_StoredSpew.PutInt( spewType );
  718. m_StoredSpew.PutChar( c.r() );
  719. m_StoredSpew.PutChar( c.g() );
  720. m_StoredSpew.PutChar( c.b() );
  721. m_StoredSpew.PutChar( c.a() );
  722. m_StoredSpew.PutString( pMsg );
  723. }
  724. void CShaderSystem::PrintBufferedSpew( void )
  725. {
  726. AUTO_LOCK( g_StgoredSpewMutex );
  727. while ( m_StoredSpew.GetBytesRemaining() > 0 )
  728. {
  729. SpewType_t spewType = (SpewType_t)m_StoredSpew.GetInt();
  730. unsigned char r, g, b, a;
  731. r = m_StoredSpew.GetChar();
  732. g = m_StoredSpew.GetChar();
  733. b = m_StoredSpew.GetChar();
  734. a = m_StoredSpew.GetChar();
  735. Color c( r, g, b, a );
  736. int nLen = m_StoredSpew.PeekStringLength();
  737. if ( nLen )
  738. {
  739. char *pBuf = (char*)_alloca( nLen );
  740. m_StoredSpew.GetStringManualCharCount( pBuf, nLen );
  741. ColorSpewMessage( spewType, &c, "%s", pBuf );
  742. }
  743. else
  744. {
  745. break;
  746. }
  747. }
  748. m_StoredSpew.Clear();
  749. }
  750. static SpewRetval_t MySpewOutputFunc( SpewType_t spewType, char const *pMsg )
  751. {
  752. AUTO_LOCK( g_StgoredSpewMutex );
  753. Color c = *GetSpewOutputColor();
  754. s_ShaderSystem.BufferSpew( spewType, c, pMsg );
  755. switch( spewType )
  756. {
  757. case SPEW_MESSAGE:
  758. case SPEW_WARNING:
  759. case SPEW_LOG:
  760. return SPEW_CONTINUE;
  761. case SPEW_ASSERT:
  762. case SPEW_ERROR:
  763. default:
  764. return SPEW_DEBUGGER;
  765. }
  766. }
  767. //-----------------------------------------------------------------------------
  768. // Deals with shader draw
  769. //-----------------------------------------------------------------------------
  770. void CShaderSystem::PrepForShaderDraw( IShader *pShader,
  771. IMaterialVar** ppParams, ShaderRenderState_t* pRenderState, int nModulation )
  772. {
  773. Assert( !m_pRenderState );
  774. // 360 runs the console remotely, spew cannot cause the matsys to be reentrant
  775. // 360 sidesteps the other negative affect that *all* buffered spew redirects as warning text
  776. if ( IsPC() || !IsX360() )
  777. {
  778. Assert( !m_SaveSpewOutput );
  779. m_SaveSpewOutput = GetSpewOutputFunc();
  780. SpewOutputFunc( MySpewOutputFunc );
  781. }
  782. m_pRenderState = pRenderState;
  783. m_nModulation = nModulation;
  784. m_nRenderPass = 0;
  785. }
  786. void CShaderSystem::DoneWithShaderDraw()
  787. {
  788. if ( IsPC() || !IsX360() )
  789. {
  790. SpewOutputFunc( m_SaveSpewOutput );
  791. PrintBufferedSpew();
  792. m_SaveSpewOutput = NULL;
  793. }
  794. m_pRenderState = NULL;
  795. }
  796. //-----------------------------------------------------------------------------
  797. // Call the SHADER_PARAM_INIT block of the shaders
  798. //-----------------------------------------------------------------------------
  799. void CShaderSystem::InitShaderParameters( IShader *pShader, IMaterialVar **params, const char *pMaterialName )
  800. {
  801. // Let the derived class do its thing
  802. PrepForShaderDraw( pShader, params, 0, 0 );
  803. pShader->InitShaderParams( params, pMaterialName );
  804. DoneWithShaderDraw();
  805. // Set up color + alpha defaults
  806. if (!params[COLOR]->IsDefined())
  807. {
  808. params[COLOR]->SetVecValue( 1.0f, 1.0f, 1.0f );
  809. }
  810. if (!params[ALPHA]->IsDefined())
  811. {
  812. params[ALPHA]->SetFloatValue( 1.0f );
  813. }
  814. // Initialize all shader params based on their type...
  815. int i;
  816. for ( i = pShader->GetNumParams(); --i >= 0; )
  817. {
  818. // Don't initialize parameters that are already set up
  819. if (params[i]->IsDefined())
  820. continue;
  821. int type = pShader->GetParamType( i );
  822. switch( type )
  823. {
  824. case SHADER_PARAM_TYPE_TEXTURE:
  825. // Do nothing; we'll be loading in a string later
  826. break;
  827. case SHADER_PARAM_TYPE_STRING:
  828. // Do nothing; we'll be loading in a string later
  829. break;
  830. case SHADER_PARAM_TYPE_MATERIAL:
  831. params[i]->SetMaterialValue( NULL );
  832. break;
  833. case SHADER_PARAM_TYPE_BOOL:
  834. case SHADER_PARAM_TYPE_INTEGER:
  835. params[i]->SetIntValue( 0 );
  836. break;
  837. case SHADER_PARAM_TYPE_COLOR:
  838. params[i]->SetVecValue( 1.0f, 1.0f, 1.0f );
  839. break;
  840. case SHADER_PARAM_TYPE_VEC2:
  841. params[i]->SetVecValue( 0.0f, 0.0f );
  842. break;
  843. case SHADER_PARAM_TYPE_VEC3:
  844. params[i]->SetVecValue( 0.0f, 0.0f, 0.0f );
  845. break;
  846. case SHADER_PARAM_TYPE_VEC4:
  847. params[i]->SetVecValue( 0.0f, 0.0f, 0.0f, 0.0f );
  848. break;
  849. case SHADER_PARAM_TYPE_FLOAT:
  850. params[i]->SetFloatValue( 0 );
  851. break;
  852. case SHADER_PARAM_TYPE_FOURCC:
  853. params[i]->SetFourCCValue( 0, 0 );
  854. break;
  855. case SHADER_PARAM_TYPE_MATRIX:
  856. {
  857. VMatrix identity;
  858. MatrixSetIdentity( identity );
  859. params[i]->SetMatrixValue( identity );
  860. }
  861. break;
  862. case SHADER_PARAM_TYPE_MATRIX4X2:
  863. {
  864. VMatrix identity;
  865. MatrixSetIdentity( identity );
  866. params[i]->SetMatrixValue( identity );
  867. }
  868. break;
  869. default:
  870. Assert(0);
  871. }
  872. }
  873. }
  874. //-----------------------------------------------------------------------------
  875. // Call the SHADER_INIT block of the shaders
  876. //-----------------------------------------------------------------------------
  877. void CShaderSystem::InitShaderInstance( IShader *pShader, IMaterialVar **params, const char *pMaterialName, const char *pTextureGroupName )
  878. {
  879. // Let the derived class do its thing
  880. PrepForShaderDraw( pShader, params, 0, 0 );
  881. pShader->InitShaderInstance( params, ShaderSystem(), pMaterialName, pTextureGroupName );
  882. DoneWithShaderDraw();
  883. }
  884. //-----------------------------------------------------------------------------
  885. // Compute snapshots for all combinations of alpha + color modulation
  886. //-----------------------------------------------------------------------------
  887. void CShaderSystem::InitRenderStateFlags( ShaderRenderState_t* pRenderState, int numParams, IMaterialVar **params )
  888. {
  889. // Compute vertex format and flags
  890. pRenderState->m_Flags = 0;
  891. // Make sure the shader don't force these flags. . they are automatically computed.
  892. Assert( !( pRenderState->m_Flags & SHADER_OPACITY_TRANSLUCENT ) );
  893. Assert( !( pRenderState->m_Flags & SHADER_OPACITY_ALPHATEST ) );
  894. Assert( !( pRenderState->m_Flags & SHADER_OPACITY_OPAQUE ) );
  895. // If we are in release mode, just go ahead and clear in case the above is screwed up.
  896. pRenderState->m_Flags &= ~SHADER_OPACITY_MASK;
  897. /*
  898. // HACK: Also kind of gross; turn off bump lightmapping for low-end
  899. if (g_config.bUseGraphics && !HardwareConfig()->SupportsVertexAndPixelShaders())
  900. {
  901. pRenderState->m_Flags &= ~SHADER_NEEDS_BUMPED_LIGHTMAPS;
  902. }
  903. */
  904. /*
  905. // HACK: more grossness!!! turn off bump lightmapping if we don't have a bumpmap
  906. // Shaders should specify SHADER_NEEDS_BUMPED_LIGHTMAPS if they might need a bumpmap,
  907. // and this'll take care of getting rid of it if it isn't there.
  908. if( pRenderState->m_Flags & SHADER_NEEDS_BUMPED_LIGHTMAPS )
  909. {
  910. pRenderState->m_Flags &= ~SHADER_NEEDS_BUMPED_LIGHTMAPS;
  911. for( int i = 0; i < numParams; i++ )
  912. {
  913. if( stricmp( params[i]->GetName(), "$bumpmap" ) == 0 )
  914. {
  915. if( params[i]->IsDefined() )
  916. {
  917. const char *blah = params[i]->GetStringValue();
  918. pRenderState->m_Flags |= SHADER_NEEDS_BUMPED_LIGHTMAPS;
  919. break;
  920. }
  921. }
  922. }
  923. }
  924. */
  925. }
  926. //-----------------------------------------------------------------------------
  927. // Computes flags from a particular snapshot
  928. //-----------------------------------------------------------------------------
  929. void CShaderSystem::ComputeRenderStateFlagsFromSnapshot( ShaderRenderState_t* pRenderState )
  930. {
  931. // When computing the flags, use the snapshot that has no alpha or color
  932. // modulation. When asking for translucency, we'll have to check for
  933. // alpha modulation in addition to checking the TRANSLUCENT flag.
  934. // I have to do it this way because I'm really wanting to treat alpha
  935. // modulation as a dynamic state, even though it's being used to compute
  936. // shadow state. I still want to use it to compute shadow state though
  937. // because it's somewhat complicated code that I'd rather precache.
  938. StateSnapshot_t snapshot = pRenderState->m_pSnapshots[0].m_Snapshot[0];
  939. // Automatically compute if the snapshot is transparent or not
  940. if ( g_pShaderAPI->IsTranslucent( snapshot ) )
  941. {
  942. pRenderState->m_Flags |= SHADER_OPACITY_TRANSLUCENT;
  943. }
  944. else
  945. {
  946. if ( g_pShaderAPI->IsAlphaTested( snapshot ) )
  947. {
  948. pRenderState->m_Flags |= SHADER_OPACITY_ALPHATEST;
  949. }
  950. else
  951. {
  952. pRenderState->m_Flags |= SHADER_OPACITY_OPAQUE;
  953. }
  954. }
  955. #ifdef _DEBUG
  956. if( pRenderState->m_Flags & SHADER_OPACITY_TRANSLUCENT )
  957. {
  958. Assert( !( pRenderState->m_Flags & SHADER_OPACITY_ALPHATEST ) );
  959. Assert( !( pRenderState->m_Flags & SHADER_OPACITY_OPAQUE ) );
  960. }
  961. if( pRenderState->m_Flags & SHADER_OPACITY_ALPHATEST )
  962. {
  963. Assert( !( pRenderState->m_Flags & SHADER_OPACITY_TRANSLUCENT ) );
  964. Assert( !( pRenderState->m_Flags & SHADER_OPACITY_OPAQUE ) );
  965. }
  966. if( pRenderState->m_Flags & SHADER_OPACITY_OPAQUE )
  967. {
  968. Assert( !( pRenderState->m_Flags & SHADER_OPACITY_ALPHATEST ) );
  969. Assert( !( pRenderState->m_Flags & SHADER_OPACITY_TRANSLUCENT ) );
  970. }
  971. #endif
  972. }
  973. //-----------------------------------------------------------------------------
  974. // Initializes state snapshots
  975. //-----------------------------------------------------------------------------
  976. #ifdef _DEBUG
  977. #pragma warning (disable:4189)
  978. #endif
  979. int CShaderSystem::GetModulationSnapshotCount( IMaterialVar **params )
  980. {
  981. int nSnapshotCount = SnapshotTypeCount();
  982. if ( !MaterialSystem()->CanUseEditorMaterials() )
  983. {
  984. if( !IsFlag2Set( params, MATERIAL_VAR2_NEEDS_BAKED_LIGHTING_SNAPSHOTS ) )
  985. {
  986. nSnapshotCount /= 2;
  987. }
  988. }
  989. return nSnapshotCount;
  990. }
  991. void CShaderSystem::InitStateSnapshots( IShader *pShader, IMaterialVar **params, ShaderRenderState_t* pRenderState )
  992. {
  993. #ifdef _DEBUG
  994. if ( IsFlagSet( params, MATERIAL_VAR_DEBUG ) )
  995. {
  996. // Putcher breakpoint here to catch the rendering of a material
  997. // marked for debugging ($debug = 1 in a .vmt file) shadow state version
  998. int x = 0;
  999. }
  1000. #endif
  1001. // Store off the current alpha + color modulations
  1002. float alpha;
  1003. float color[3];
  1004. params[COLOR]->GetVecValue( color, 3 );
  1005. alpha = params[ALPHA]->GetFloatValue( );
  1006. bool bBakedLighting = IsFlag2Set( params, MATERIAL_VAR2_USE_FIXED_FUNCTION_BAKED_LIGHTING );
  1007. bool bFlashlight = IsFlag2Set( params, MATERIAL_VAR2_USE_FLASHLIGHT );
  1008. bool bEditor = IsFlag2Set( params, MATERIAL_VAR2_USE_EDITOR );
  1009. // bool bSupportsFlashlight = IsFlag2Set( params, MATERIAL_VAR2_SUPPORTS_FLASHLIGHT );
  1010. float white[3] = { 1, 1, 1 };
  1011. float grey[3] = { .5, .5, .5 };
  1012. int nSnapshotCount = GetModulationSnapshotCount( params );
  1013. // If the current mod does not use the flashlight, skip all flashlight snapshots (saves a ton of memory)
  1014. bool bModUsesFlashlight = ( mat_supportflashlight.GetInt() != 0 );
  1015. for (int i = 0; i < nSnapshotCount; ++i)
  1016. {
  1017. if ( ( i & SHADER_USING_FLASHLIGHT ) &&
  1018. !bModUsesFlashlight )
  1019. {
  1020. pRenderState->m_pSnapshots[i].m_nPassCount = 0;
  1021. continue;
  1022. }
  1023. // Set modulation to force particular code paths
  1024. if (i & SHADER_USING_COLOR_MODULATION)
  1025. {
  1026. params[COLOR]->SetVecValue( grey, 3 );
  1027. }
  1028. else
  1029. {
  1030. params[COLOR]->SetVecValue( white, 3 );
  1031. }
  1032. if (i & SHADER_USING_ALPHA_MODULATION)
  1033. {
  1034. params[ALPHA]->SetFloatValue( grey[0] );
  1035. }
  1036. else
  1037. {
  1038. params[ALPHA]->SetFloatValue( white[0] );
  1039. }
  1040. if ( i & SHADER_USING_FLASHLIGHT )
  1041. {
  1042. // if ( !bSupportsFlashlight )
  1043. // {
  1044. // pRenderState->m_pSnapshots[i].m_nPassCount = 0;
  1045. // continue;
  1046. // }
  1047. SET_FLAGS2( MATERIAL_VAR2_USE_FLASHLIGHT );
  1048. }
  1049. else
  1050. {
  1051. CLEAR_FLAGS2( MATERIAL_VAR2_USE_FLASHLIGHT );
  1052. }
  1053. if ( i & SHADER_USING_EDITOR )
  1054. {
  1055. SET_FLAGS2( MATERIAL_VAR2_USE_EDITOR );
  1056. }
  1057. else
  1058. {
  1059. CLEAR_FLAGS2( MATERIAL_VAR2_USE_EDITOR );
  1060. }
  1061. if ( i & SHADER_USING_FIXED_FUNCTION_BAKED_LIGHTING )
  1062. {
  1063. SET_FLAGS2( MATERIAL_VAR2_USE_FIXED_FUNCTION_BAKED_LIGHTING );
  1064. }
  1065. else
  1066. {
  1067. CLEAR_FLAGS2( MATERIAL_VAR2_USE_FIXED_FUNCTION_BAKED_LIGHTING );
  1068. }
  1069. PrepForShaderDraw( pShader, params, pRenderState, i );
  1070. // Now snapshot how we're going to draw
  1071. pRenderState->m_pSnapshots[i].m_nPassCount = 0;
  1072. pShader->DrawElements( params, i, g_pShaderShadow, 0, VERTEX_COMPRESSION_NONE, &(pRenderState->m_pSnapshots[i].m_pContextData[0] ) );
  1073. DoneWithShaderDraw();
  1074. }
  1075. // Restore alpha + color modulation
  1076. params[COLOR]->SetVecValue( color, 3 );
  1077. params[ALPHA]->SetFloatValue( alpha );
  1078. if( bBakedLighting )
  1079. {
  1080. SET_FLAGS2( MATERIAL_VAR2_USE_FIXED_FUNCTION_BAKED_LIGHTING );
  1081. }
  1082. else
  1083. {
  1084. CLEAR_FLAGS2( MATERIAL_VAR2_USE_FIXED_FUNCTION_BAKED_LIGHTING );
  1085. }
  1086. if( bEditor )
  1087. {
  1088. SET_FLAGS2( MATERIAL_VAR2_USE_EDITOR );
  1089. }
  1090. else
  1091. {
  1092. CLEAR_FLAGS2( MATERIAL_VAR2_USE_EDITOR );
  1093. }
  1094. if( bFlashlight )
  1095. {
  1096. SET_FLAGS2( MATERIAL_VAR2_USE_FLASHLIGHT );
  1097. }
  1098. else
  1099. {
  1100. CLEAR_FLAGS2( MATERIAL_VAR2_USE_FLASHLIGHT );
  1101. }
  1102. }
  1103. #ifdef _DEBUG
  1104. #pragma warning (default:4189)
  1105. #endif
  1106. //-----------------------------------------------------------------------------
  1107. // Helper to count texture coordinates
  1108. //-----------------------------------------------------------------------------
  1109. static int NumTextureCoordinates( VertexFormat_t vertexFormat )
  1110. {
  1111. // FIXME: this is a duplicate of the function in meshdx8.cpp
  1112. int nTexCoordCount = 0;
  1113. for ( int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; ++i )
  1114. {
  1115. if ( TexCoordSize( i, vertexFormat ) == 0 )
  1116. continue;
  1117. ++nTexCoordCount;
  1118. }
  1119. return nTexCoordCount;
  1120. }
  1121. //-----------------------------------------------------------------------------
  1122. // Displays the vertex format
  1123. //-----------------------------------------------------------------------------
  1124. static void OutputVertexFormat( VertexFormat_t format )
  1125. {
  1126. // FIXME: this is a duplicate of the function in meshdx8.cpp
  1127. VertexCompressionType_t compressionType = CompressionType( format );
  1128. if( format & VERTEX_POSITION )
  1129. {
  1130. Warning( "VERTEX_POSITION|" );
  1131. }
  1132. if( format & VERTEX_NORMAL )
  1133. {
  1134. if ( compressionType == VERTEX_COMPRESSION_ON )
  1135. Warning( "VERTEX_NORMAL[COMPRESSED]|" );
  1136. else
  1137. Warning( "VERTEX_NORMAL|" );
  1138. }
  1139. if( format & VERTEX_COLOR )
  1140. {
  1141. Warning( "VERTEX_COLOR|" );
  1142. }
  1143. if( format & VERTEX_SPECULAR )
  1144. {
  1145. Warning( "VERTEX_SPECULAR|" );
  1146. }
  1147. if( format & VERTEX_TANGENT_S )
  1148. {
  1149. Warning( "VERTEX_TANGENT_S|" );
  1150. }
  1151. if( format & VERTEX_TANGENT_T )
  1152. {
  1153. Warning( "VERTEX_TANGENT_T|" );
  1154. }
  1155. if( format & VERTEX_BONE_INDEX )
  1156. {
  1157. Warning( "VERTEX_BONE_INDEX|" );
  1158. }
  1159. if( format & VERTEX_FORMAT_VERTEX_SHADER )
  1160. {
  1161. Warning( "VERTEX_FORMAT_VERTEX_SHADER|" );
  1162. }
  1163. Warning( "\nBone weights: %d\n", NumBoneWeights( format ) );
  1164. Warning( "user data size: %d (%s)\n", UserDataSize( format ),
  1165. ( CompressionType( format ) == VERTEX_COMPRESSION_ON ? "compressed" : "uncompressed" ) );
  1166. Warning( "num tex coords: %d\n", NumTextureCoordinates( format ) );
  1167. // NOTE: This doesn't print texcoord sizes.
  1168. }
  1169. #ifdef _DEBUG
  1170. static bool IsVertexFormatSubsetOfVertexformat( VertexFormat_t subset, VertexFormat_t superset )
  1171. {
  1172. subset &= ~VERTEX_FORMAT_USE_EXACT_FORMAT;
  1173. superset &= ~VERTEX_FORMAT_USE_EXACT_FORMAT;
  1174. // Test the flags
  1175. if( VertexFlags( subset ) & VertexFlags( ~superset ) )
  1176. return false;
  1177. // Test bone weights
  1178. if( NumBoneWeights( subset ) > NumBoneWeights( superset ) )
  1179. return false;
  1180. // Test user data size
  1181. if( UserDataSize( subset ) > UserDataSize( superset ) )
  1182. return false;
  1183. // Test the texcoord dimensions
  1184. for( int i = 0; i < VERTEX_MAX_TEXTURE_COORDINATES; i++ )
  1185. {
  1186. if( TexCoordSize( i, subset ) > TexCoordSize( i, superset ) )
  1187. return false;
  1188. }
  1189. return true;
  1190. }
  1191. #endif
  1192. //-----------------------------------------------------------------------------
  1193. // Adds state snapshots to the render list
  1194. //-----------------------------------------------------------------------------
  1195. static void AddSnapshotsToList( RenderPassList_t *pPassList, int &nSnapshotID, StateSnapshot_t *pSnapshots )
  1196. {
  1197. int nNumPassSnapshots = pPassList->m_nPassCount;
  1198. for( int i = 0; i < nNumPassSnapshots; ++i )
  1199. {
  1200. pSnapshots[nSnapshotID] = pPassList->m_Snapshot[i];
  1201. nSnapshotID++;
  1202. }
  1203. }
  1204. //-----------------------------------------------------------------------------
  1205. // Computes vertex format + usage from a particular snapshot
  1206. //-----------------------------------------------------------------------------
  1207. bool CShaderSystem::ComputeVertexFormatFromSnapshot( IMaterialVar **params, ShaderRenderState_t* pRenderState )
  1208. {
  1209. // When computing the usage, use the snapshot that has no alpha or color
  1210. // modulation. We need the usage + format to be the same for all
  1211. // combinations of alpha + color modulation, though, or we are asking for
  1212. // trouble.
  1213. int nModulationSnapshotCount = GetModulationSnapshotCount( params );
  1214. int numSnapshots = pRenderState->m_pSnapshots[0].m_nPassCount;
  1215. if (nModulationSnapshotCount >= SHADER_USING_FLASHLIGHT)
  1216. {
  1217. numSnapshots += pRenderState->m_pSnapshots[SHADER_USING_FLASHLIGHT].m_nPassCount;
  1218. }
  1219. if ( MaterialSystem()->CanUseEditorMaterials() )
  1220. {
  1221. numSnapshots += pRenderState->m_pSnapshots[SHADER_USING_EDITOR].m_nPassCount;
  1222. }
  1223. StateSnapshot_t* pSnapshots = (StateSnapshot_t*)stackalloc(
  1224. numSnapshots * sizeof(StateSnapshot_t) );
  1225. int snapshotID = 0;
  1226. AddSnapshotsToList( &pRenderState->m_pSnapshots[0], snapshotID, pSnapshots );
  1227. if (nModulationSnapshotCount >= SHADER_USING_FLASHLIGHT)
  1228. {
  1229. AddSnapshotsToList( &pRenderState->m_pSnapshots[SHADER_USING_FLASHLIGHT], snapshotID, pSnapshots );
  1230. }
  1231. if ( MaterialSystem()->CanUseEditorMaterials() )
  1232. {
  1233. AddSnapshotsToList( &pRenderState->m_pSnapshots[SHADER_USING_EDITOR], snapshotID, pSnapshots );
  1234. }
  1235. Assert( snapshotID == numSnapshots );
  1236. pRenderState->m_VertexUsage = g_pShaderAPI->ComputeVertexUsage( numSnapshots, pSnapshots );
  1237. pRenderState->m_MorphFormat = g_pShaderAPI->ComputeMorphFormat( numSnapshots, pSnapshots );
  1238. #ifdef _DEBUG
  1239. // Make sure all modulation combinations match vertex usage
  1240. for ( int mod = 1; mod < nModulationSnapshotCount; ++mod )
  1241. {
  1242. int numSnapshotsTest = pRenderState->m_pSnapshots[mod].m_nPassCount;
  1243. StateSnapshot_t* pSnapshotsTest = (StateSnapshot_t*)_alloca(
  1244. numSnapshotsTest * sizeof(StateSnapshot_t) );
  1245. for (int i = 0; i < numSnapshotsTest; ++i)
  1246. {
  1247. pSnapshotsTest[i] = pRenderState->m_pSnapshots[mod].m_Snapshot[i];
  1248. }
  1249. VertexFormat_t usageTest = g_pShaderAPI->ComputeVertexUsage( numSnapshotsTest, pSnapshotsTest );
  1250. Assert( IsVertexFormatSubsetOfVertexformat( usageTest, pRenderState->m_VertexUsage ) );
  1251. }
  1252. #endif
  1253. if ( IsPC() )
  1254. {
  1255. pRenderState->m_VertexFormat = g_pShaderAPI->ComputeVertexFormat( numSnapshots, pSnapshots );
  1256. }
  1257. else
  1258. {
  1259. pRenderState->m_VertexFormat = pRenderState->m_VertexUsage;
  1260. }
  1261. return true;
  1262. }
  1263. //-----------------------------------------------------------------------------
  1264. // go through each param and make sure it is the right type, load textures,
  1265. // compute state snapshots and vertex types, etc.
  1266. //-----------------------------------------------------------------------------
  1267. bool CShaderSystem::InitRenderState( IShader *pShader, int numParams, IMaterialVar **params, ShaderRenderState_t* pRenderState, char const* pMaterialName )
  1268. {
  1269. Assert( !m_pRenderState );
  1270. // Initialize render state flags
  1271. InitRenderStateFlags( pRenderState, numParams, params );
  1272. // Compute state snapshots for each combination of alpha + color
  1273. InitStateSnapshots( pShader, params, pRenderState );
  1274. // Compute other infomation for the render state based on snapshots
  1275. if (pRenderState->m_pSnapshots[0].m_nPassCount == 0)
  1276. {
  1277. Warning( "Material \"%s\":\n No render states in shader \"%s\"\n", pMaterialName, pShader->GetName() );
  1278. return false;
  1279. }
  1280. // Set a couple additional flags based on the render state
  1281. ComputeRenderStateFlagsFromSnapshot( pRenderState );
  1282. // Compute the vertex format + usage from the snapshot
  1283. if ( !ComputeVertexFormatFromSnapshot( params, pRenderState ) )
  1284. {
  1285. // warn.. return a null render state...
  1286. Warning("Material \"%s\":\n Shader \"%s\" can't be used with models!\n", pMaterialName, pShader->GetName() );
  1287. CleanupRenderState( pRenderState );
  1288. return false;
  1289. }
  1290. return true;
  1291. }
  1292. // When you're done with the shader, be sure to call this to clean up
  1293. void CShaderSystem::CleanupRenderState( ShaderRenderState_t* pRenderState )
  1294. {
  1295. if (pRenderState)
  1296. {
  1297. int nSnapshotCount = SnapshotTypeCount();
  1298. // kill context data
  1299. // Indicate no passes for any of the snapshot lists
  1300. RenderPassList_t *pTemp = pRenderState->m_pSnapshots;
  1301. for(int i = 0; i < nSnapshotCount; i++ )
  1302. {
  1303. for(int j = 0 ; j < pRenderState->m_pSnapshots[i].m_nPassCount; j++ )
  1304. if ( pTemp[i].m_pContextData[j] )
  1305. {
  1306. delete pTemp[i].m_pContextData[j];
  1307. pTemp[i].m_pContextData[j] = NULL;
  1308. }
  1309. pRenderState->m_pSnapshots[i].m_nPassCount = 0;
  1310. }
  1311. }
  1312. }
  1313. //-----------------------------------------------------------------------------
  1314. // Does the rendering!
  1315. //-----------------------------------------------------------------------------
  1316. void CShaderSystem::DrawElements( IShader *pShader, IMaterialVar **params,
  1317. ShaderRenderState_t* pRenderState,
  1318. VertexCompressionType_t vertexCompression,
  1319. uint32 nMaterialVarChangeTimeStamp )
  1320. {
  1321. VPROF("CShaderSystem::DrawElements");
  1322. g_pShaderAPI->InvalidateDelayedShaderConstants();
  1323. // Compute modulation...
  1324. int mod = pShader->ComputeModulationFlags( params, g_pShaderAPI );
  1325. // No snapshots? do nothing.
  1326. if ( pRenderState->m_pSnapshots[mod].m_nPassCount == 0 )
  1327. return;
  1328. // If we're rendering a model, gotta have skinning matrices
  1329. int materialVarFlags = params[FLAGS]->GetIntValue();
  1330. if ( (( materialVarFlags & MATERIAL_VAR_MODEL ) != 0) ||
  1331. ( IsFlag2Set( params, MATERIAL_VAR2_SUPPORTS_HW_SKINNING ) && ( g_pShaderAPI->GetCurrentNumBones() > 0 )) )
  1332. {
  1333. g_pShaderAPI->SetSkinningMatrices( );
  1334. }
  1335. // FIXME: need one conditional that we calculate once a frame for debug or not with everything debug under that.
  1336. #ifndef DX_TO_GL_ABSTRACTION
  1337. if ( ( ( g_config.bMeasureFillRate || g_config.bVisualizeFillRate ) &&
  1338. ( ( materialVarFlags & MATERIAL_VAR_USE_IN_FILLRATE_MODE ) == 0 ) ) )
  1339. {
  1340. DrawMeasureFillRate( pRenderState, mod, vertexCompression );
  1341. }
  1342. else
  1343. #endif
  1344. if( ( g_config.bShowNormalMap || g_config.nShowMipLevels == 2 ) &&
  1345. ( IsFlag2Set( params, MATERIAL_VAR2_LIGHTING_BUMPED_LIGHTMAP ) ||
  1346. IsFlag2Set( params, MATERIAL_VAR2_DIFFUSE_BUMPMAPPED_MODEL ) ) )
  1347. {
  1348. DrawNormalMap( pShader, params, vertexCompression );
  1349. }
  1350. #if defined(DEBUG_DEPTH)
  1351. else if ( mat_debugdepth.GetInt() && ((materialVarFlags & MATERIAL_VAR_NO_DEBUG_OVERRIDE) == 0) )
  1352. {
  1353. int nIndex = 0;
  1354. if ( IsFlagSet( params, MATERIAL_VAR_DECAL ) )
  1355. {
  1356. nIndex |= 0x1;
  1357. }
  1358. IMaterialInternal *pDebugMaterial = m_pDebugMaterials[ MATERIAL_DEBUG_DEPTH + nIndex ];
  1359. if ( !g_pShaderAPI->IsDepthWriteEnabled( pRenderState->m_Snapshots[mod].m_Snapshot[0] ) )
  1360. {
  1361. pDebugMaterial = m_pDebugMaterials[MATERIAL_DEBUG_WIREFRAME];
  1362. }
  1363. DrawUsingMaterial( pDebugMaterial, vertexCompression );
  1364. }
  1365. #endif
  1366. else
  1367. {
  1368. g_pShaderAPI->SetDefaultState();
  1369. // If we're rendering flat, turn on flat mode...
  1370. if (materialVarFlags & MATERIAL_VAR_FLAT)
  1371. {
  1372. g_pShaderAPI->ShadeMode( SHADER_FLAT );
  1373. }
  1374. PrepForShaderDraw( pShader, params, pRenderState, mod );
  1375. g_pShaderAPI->BeginPass( CurrentStateSnapshot() );
  1376. CBasePerMaterialContextData ** pContextDataPtr =
  1377. &( m_pRenderState->m_pSnapshots[m_nModulation].m_pContextData[m_nRenderPass] );
  1378. if ( *pContextDataPtr && ( (*pContextDataPtr)->m_nVarChangeID != nMaterialVarChangeTimeStamp ) )
  1379. {
  1380. (*pContextDataPtr)->m_bMaterialVarsChanged = true;
  1381. (*pContextDataPtr)->m_nVarChangeID = nMaterialVarChangeTimeStamp;
  1382. }
  1383. pShader->DrawElements(
  1384. params, mod, 0, g_pShaderAPI, vertexCompression,
  1385. &( m_pRenderState->m_pSnapshots[m_nModulation].m_pContextData[m_nRenderPass] ) );
  1386. DoneWithShaderDraw();
  1387. }
  1388. MaterialSystem()->ForceDepthFuncEquals( false );
  1389. }
  1390. //-----------------------------------------------------------------------------
  1391. // Are we using graphics?
  1392. //-----------------------------------------------------------------------------
  1393. bool CShaderSystem::IsUsingGraphics() const
  1394. {
  1395. // YWB Hack if running with -noshaderapi/-makereslists this forces materials to "precache" which means they will resolve their .vtf files for
  1396. // things like normal/height/dudv maps...
  1397. if ( m_bForceUsingGraphicsReturnTrue )
  1398. return true;
  1399. return g_pShaderDevice->IsUsingGraphics();
  1400. }
  1401. //-----------------------------------------------------------------------------
  1402. // Are we using the editor materials?
  1403. //-----------------------------------------------------------------------------
  1404. bool CShaderSystem::CanUseEditorMaterials() const
  1405. {
  1406. return MaterialSystem()->CanUseEditorMaterials();
  1407. }
  1408. //-----------------------------------------------------------------------------
  1409. // Takes a snapshot
  1410. //-----------------------------------------------------------------------------
  1411. void CShaderSystem::TakeSnapshot( )
  1412. {
  1413. Assert( m_pRenderState );
  1414. Assert( m_nModulation < SnapshotTypeCount() );
  1415. if( g_pHardwareConfig->SupportsPixelShaders_2_b() )
  1416. {
  1417. //enable linear->gamma srgb conversion lookup texture
  1418. g_pShaderShadow->EnableTexture( SHADER_SAMPLER15, true );
  1419. g_pShaderShadow->EnableSRGBRead( SHADER_SAMPLER15, true );
  1420. }
  1421. RenderPassList_t& snapshotList = m_pRenderState->m_pSnapshots[m_nModulation];
  1422. // Take a snapshot...
  1423. snapshotList.m_Snapshot[snapshotList.m_nPassCount] = g_pShaderAPI->TakeSnapshot();
  1424. ++snapshotList.m_nPassCount;
  1425. }
  1426. //-----------------------------------------------------------------------------
  1427. // Draws a snapshot
  1428. //-----------------------------------------------------------------------------
  1429. void CShaderSystem::DrawSnapshot( bool bMakeActualDrawCall )
  1430. {
  1431. Assert( m_pRenderState );
  1432. RenderPassList_t& snapshotList = m_pRenderState->m_pSnapshots[m_nModulation];
  1433. int nPassCount = snapshotList.m_nPassCount;
  1434. Assert( m_nRenderPass < nPassCount );
  1435. if ( bMakeActualDrawCall )
  1436. {
  1437. g_pShaderAPI->RenderPass( m_nRenderPass, nPassCount );
  1438. }
  1439. g_pShaderAPI->InvalidateDelayedShaderConstants();
  1440. if (++m_nRenderPass < nPassCount)
  1441. {
  1442. g_pShaderAPI->BeginPass( CurrentStateSnapshot() );
  1443. }
  1444. }
  1445. //-----------------------------------------------------------------------------
  1446. //
  1447. // Debugging material methods below
  1448. //
  1449. //-----------------------------------------------------------------------------
  1450. //-----------------------------------------------------------------------------
  1451. // Draws a using a particular material..
  1452. //-----------------------------------------------------------------------------
  1453. void CShaderSystem::DrawUsingMaterial( IMaterialInternal *pMaterial, VertexCompressionType_t vertexCompression )
  1454. {
  1455. ShaderRenderState_t *pRenderState = pMaterial->GetRenderState();
  1456. g_pShaderAPI->SetDefaultState( );
  1457. IShader *pShader = pMaterial->GetShader();
  1458. int nMod = pShader->ComputeModulationFlags( pMaterial->GetShaderParams(), g_pShaderAPI );
  1459. PrepForShaderDraw( pShader, pMaterial->GetShaderParams(), pRenderState, nMod );
  1460. g_pShaderAPI->BeginPass( pRenderState->m_pSnapshots[nMod].m_Snapshot[0] );
  1461. pShader->DrawElements( pMaterial->GetShaderParams(), nMod, 0, g_pShaderAPI, vertexCompression,
  1462. &( pRenderState->m_pSnapshots[nMod].m_pContextData[0] ) );
  1463. DoneWithShaderDraw( );
  1464. }
  1465. //-----------------------------------------------------------------------------
  1466. // Copies material vars
  1467. //-----------------------------------------------------------------------------
  1468. void CShaderSystem::CopyMaterialVarToDebugShader( IMaterialInternal *pDebugMaterial, IShader *pShader, IMaterialVar **ppParams, const char *pSrcVarName, const char *pDstVarName )
  1469. {
  1470. bool bFound;
  1471. IMaterialVar *pMaterialVar = pDebugMaterial->FindVar( pDstVarName ? pDstVarName : pSrcVarName, &bFound );
  1472. Assert( bFound );
  1473. for( int i = pShader->GetNumParams(); --i >= 0; )
  1474. {
  1475. if( !Q_stricmp( ppParams[i]->GetName( ), pSrcVarName ) )
  1476. {
  1477. pMaterialVar->CopyFrom( ppParams[i] );
  1478. return;
  1479. }
  1480. }
  1481. pMaterialVar->SetUndefined();
  1482. }
  1483. //-----------------------------------------------------------------------------
  1484. // Draws the puppy in fill rate mode...
  1485. //-----------------------------------------------------------------------------
  1486. void CShaderSystem::DrawMeasureFillRate( ShaderRenderState_t* pRenderState, int mod, VertexCompressionType_t vertexCompression )
  1487. {
  1488. int nPassCount = pRenderState->m_pSnapshots[mod].m_nPassCount;
  1489. // We require the use of a vertex shader rather than fixed function transforms
  1490. Assert( (VertexFlags(pRenderState->m_VertexFormat) & VERTEX_FORMAT_VERTEX_SHADER) != 0 );
  1491. IMaterialInternal *pMaterial = m_pDebugMaterials[ MATERIAL_FILL_RATE ];
  1492. bool bFound;
  1493. IMaterialVar *pMaterialVar = pMaterial->FindVar( "$passcount", &bFound );
  1494. pMaterialVar->SetIntValue( nPassCount );
  1495. DrawUsingMaterial( pMaterial, vertexCompression );
  1496. }
  1497. //-----------------------------------------------------------------------------
  1498. // Draws normalmaps
  1499. //-----------------------------------------------------------------------------
  1500. void CShaderSystem::DrawNormalMap( IShader *pShader, IMaterialVar **ppParams, VertexCompressionType_t vertexCompression )
  1501. {
  1502. IMaterialInternal *pDebugMaterial = m_pDebugMaterials[MATERIAL_DEBUG_NORMALMAP];
  1503. if( !g_config.m_bFastNoBump )
  1504. {
  1505. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$bumpmap" );
  1506. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$bumpframe" );
  1507. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$bumptransform" );
  1508. }
  1509. else
  1510. {
  1511. bool bFound;
  1512. IMaterialVar *pMaterialVar = pDebugMaterial->FindVar( "$bumpmap", &bFound );
  1513. Assert( bFound );
  1514. pMaterialVar->SetUndefined();
  1515. }
  1516. DrawUsingMaterial( pDebugMaterial, vertexCompression );
  1517. }
  1518. //-----------------------------------------------------------------------------
  1519. // Draws envmapmask
  1520. //-----------------------------------------------------------------------------
  1521. bool CShaderSystem::DrawEnvmapMask( IShader *pShader, IMaterialVar **ppParams,
  1522. ShaderRenderState_t* pRenderState, VertexCompressionType_t vertexCompression )
  1523. {
  1524. // FIXME! Make this work with fixed function.
  1525. int vertexFormat = pRenderState->m_VertexFormat;
  1526. bool bUsesVertexShader = (VertexFlags(vertexFormat) & VERTEX_FORMAT_VERTEX_SHADER) != 0;
  1527. if( !bUsesVertexShader )
  1528. {
  1529. Assert( 0 );
  1530. return false;
  1531. }
  1532. IMaterialInternal *pDebugMaterial = m_pDebugMaterials[ MATERIAL_DEBUG_ENVMAPMASK ];
  1533. bool bFound;
  1534. IMaterialVar *pMaterialVar = pDebugMaterial->FindVar( "$showalpha", &bFound );
  1535. Assert( bFound );
  1536. if( IsFlagSet( ppParams, MATERIAL_VAR_NORMALMAPALPHAENVMAPMASK ) )
  1537. {
  1538. // $bumpmap
  1539. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$bumpmap", "$basetexture" );
  1540. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$bumpframe", "$frame" );
  1541. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$bumptransform", "$basetexturetransform" );
  1542. pMaterialVar->SetIntValue( 1 );
  1543. }
  1544. else if( IsFlagSet( ppParams, MATERIAL_VAR_BASEALPHAENVMAPMASK ) )
  1545. {
  1546. // $basealphaenvmapmask
  1547. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$basetexture" );
  1548. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$frame" );
  1549. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$basetexturetransform" );
  1550. pMaterialVar->SetIntValue( 1 );
  1551. }
  1552. else
  1553. {
  1554. // $envmapmask
  1555. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$envmapmask", "$basetexture" );
  1556. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$envmapmaskframe", "$frame" );
  1557. CopyMaterialVarToDebugShader( pDebugMaterial, pShader, ppParams, "$envmapmasktransform", "$basetexturetransform" );
  1558. pMaterialVar->SetIntValue( 0 );
  1559. }
  1560. if( pDebugMaterial->FindVar( "$basetexture", NULL )->IsTexture() )
  1561. {
  1562. DrawUsingMaterial( pDebugMaterial, vertexCompression );
  1563. return true;
  1564. }
  1565. else
  1566. {
  1567. return false;
  1568. }
  1569. }
  1570. //-----------------------------------------------------------------------------
  1571. //
  1572. // Methods of IShaderSystem lie below
  1573. //
  1574. //-----------------------------------------------------------------------------
  1575. ShaderAPITextureHandle_t CShaderSystem::GetShaderAPITextureBindHandle( ITexture *pTexture, int nFrame, int nTextureChannel )
  1576. {
  1577. Assert( !IsTextureInternalEnvCubemap( static_cast<ITextureInternal*>(pTexture) ) );
  1578. // Bind away baby
  1579. if( pTexture )
  1580. {
  1581. // This is ugly. Basically, this is yet another way that textures can be bound. They don't get bound here,
  1582. // but the return is only used to bind them for semistatic command buffer building, which doesn't go through
  1583. // CTexture::Bind for whatever reason. So let's request the mipmaps here. If you run into this, in a situation
  1584. // where we shouldn't be doing the request, we could relocate this code to the appropriate callsites instead.
  1585. ITextureInternal* pTex = assert_cast< ITextureInternal* >( pTexture );
  1586. TextureManager()->RequestAllMipmaps( pTex );
  1587. return pTex->GetTextureHandle( nFrame, nTextureChannel );
  1588. }
  1589. else
  1590. return INVALID_SHADERAPI_TEXTURE_HANDLE;
  1591. }
  1592. //-----------------------------------------------------------------------------
  1593. // Binds a texture
  1594. //-----------------------------------------------------------------------------
  1595. void CShaderSystem::BindTexture( Sampler_t sampler1, ITexture *pTexture, int nFrame /* = 0 */ )
  1596. {
  1597. // The call to IMaterialVar::GetTextureValue should have converted this to a real thing
  1598. Assert( !IsTextureInternalEnvCubemap( static_cast<ITextureInternal*>(pTexture) ) );
  1599. // Bind away baby
  1600. if( pTexture )
  1601. {
  1602. static_cast<ITextureInternal*>(pTexture)->Bind( sampler1, nFrame );
  1603. }
  1604. }
  1605. void CShaderSystem::BindTexture( Sampler_t sampler1, Sampler_t sampler2, ITexture *pTexture, int nFrame /* = 0 */ )
  1606. {
  1607. // The call to IMaterialVar::GetTextureValue should have converted this to a real thing
  1608. Assert( !IsTextureInternalEnvCubemap( static_cast<ITextureInternal*>(pTexture) ) );
  1609. // Bind away baby
  1610. if( pTexture )
  1611. {
  1612. if ( sampler2 == Sampler_t(-1) )
  1613. {
  1614. static_cast<ITextureInternal*>(pTexture)->Bind( sampler1, nFrame );
  1615. }
  1616. else
  1617. {
  1618. static_cast<ITextureInternal*>(pTexture)->Bind( sampler1, nFrame, sampler2 );
  1619. }
  1620. }
  1621. }
  1622. //-----------------------------------------------------------------------------
  1623. //
  1624. // Methods of IShaderInit lie below
  1625. //
  1626. //-----------------------------------------------------------------------------
  1627. //-----------------------------------------------------------------------------
  1628. // Loads a texture
  1629. //-----------------------------------------------------------------------------
  1630. void CShaderSystem::LoadTexture( IMaterialVar *pTextureVar, const char *pTextureGroupName, int nAdditionalCreationFlags /* = 0 */ )
  1631. {
  1632. if (pTextureVar->GetType() != MATERIAL_VAR_TYPE_STRING)
  1633. {
  1634. // This here will cause 'UNDEFINED' material vars
  1635. if (pTextureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE)
  1636. {
  1637. pTextureVar->SetTextureValue( TextureManager()->ErrorTexture() );
  1638. }
  1639. return;
  1640. }
  1641. // In this case, we have to convert the string into a texture value
  1642. const char *pName = pTextureVar->GetStringValue();
  1643. // Fix cases where people stupidly put a slash at the front of the vtf filename in a vmt. Causes trouble elsewhere.
  1644. if ( pName[0] == CORRECT_PATH_SEPARATOR || pName[1] == CORRECT_PATH_SEPARATOR )
  1645. ++pName;
  1646. ITextureInternal *pTexture;
  1647. // Force local cubemaps when using the editor
  1648. if ( MaterialSystem()->CanUseEditorMaterials() && ( stricmp( pName, "env_cubemap" ) == 0 ) )
  1649. {
  1650. pTexture = (ITextureInternal*)-1;
  1651. }
  1652. else
  1653. {
  1654. pTexture = static_cast< ITextureInternal * >( MaterialSystem()->FindTexture( pName, pTextureGroupName, false, nAdditionalCreationFlags ) );
  1655. }
  1656. if( !pTexture )
  1657. {
  1658. if( !g_pShaderDevice->IsUsingGraphics() && ( stricmp( pName, "env_cubemap" ) != 0 ) )
  1659. {
  1660. Warning( "Shader_t::LoadTexture: texture \"%s.vtf\" doesn't exist\n", pName );
  1661. }
  1662. pTexture = TextureManager()->ErrorTexture();
  1663. }
  1664. pTextureVar->SetTextureValue( pTexture );
  1665. }
  1666. //-----------------------------------------------------------------------------
  1667. // Loads a bumpmap
  1668. //-----------------------------------------------------------------------------
  1669. void CShaderSystem::LoadBumpMap( IMaterialVar *pTextureVar, const char *pTextureGroupName )
  1670. {
  1671. Assert( pTextureVar );
  1672. if (pTextureVar->GetType() != MATERIAL_VAR_TYPE_STRING)
  1673. {
  1674. // This here will cause 'UNDEFINED' material vars
  1675. if (pTextureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE)
  1676. {
  1677. pTextureVar->SetTextureValue( TextureManager()->ErrorTexture() );
  1678. }
  1679. return;
  1680. }
  1681. // Convert a string to the actual texture
  1682. ITexture *pTexture;
  1683. pTexture = MaterialSystem()->FindTexture( pTextureVar->GetStringValue(), pTextureGroupName, false, 0 );
  1684. // FIXME: Make a bumpmap error texture
  1685. if (!pTexture)
  1686. {
  1687. pTexture = TextureManager()->ErrorTexture();
  1688. }
  1689. pTextureVar->SetTextureValue( pTexture );
  1690. }
  1691. //-----------------------------------------------------------------------------
  1692. // Loads a cubemap
  1693. //-----------------------------------------------------------------------------
  1694. void CShaderSystem::LoadCubeMap( IMaterialVar **ppParams, IMaterialVar *pTextureVar, int nAdditionalCreationFlags /* = 0 */ )
  1695. {
  1696. if ( !HardwareConfig()->SupportsCubeMaps() )
  1697. return;
  1698. if ( pTextureVar->GetType() != MATERIAL_VAR_TYPE_STRING )
  1699. {
  1700. // This here will cause 'UNDEFINED' material vars
  1701. if (pTextureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE)
  1702. {
  1703. pTextureVar->SetTextureValue( TextureManager()->ErrorTexture() );
  1704. }
  1705. return;
  1706. }
  1707. if ( stricmp( pTextureVar->GetStringValue(), "env_cubemap" ) == 0 )
  1708. {
  1709. // garymcthack
  1710. // don't have to load anything here. . just set the texture value to something
  1711. // special that says to use the cubemap entity.
  1712. pTextureVar->SetTextureValue( ( ITexture * )-1 );
  1713. SetFlags2( ppParams, MATERIAL_VAR2_USES_ENV_CUBEMAP );
  1714. }
  1715. else
  1716. {
  1717. ITexture *pTexture;
  1718. char textureName[MAX_PATH];
  1719. Q_strncpy( textureName, pTextureVar->GetStringValue(), MAX_PATH );
  1720. if ( HardwareConfig()->GetHDRType() != HDR_TYPE_NONE )
  1721. {
  1722. // Overload the texture name to ".hdr.vtf" (instead of .vtf) if we are running with
  1723. // HDR enabled.
  1724. Q_strncat( textureName, ".hdr", MAX_PATH, COPY_ALL_CHARACTERS );
  1725. }
  1726. pTexture = MaterialSystem()->FindTexture( textureName, TEXTURE_GROUP_CUBE_MAP, false, nAdditionalCreationFlags );
  1727. // FIXME: Make a cubemap error texture
  1728. if ( !pTexture )
  1729. {
  1730. pTexture = TextureManager()->ErrorTexture();
  1731. }
  1732. pTextureVar->SetTextureValue( pTexture );
  1733. }
  1734. }