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.

3157 lines
90 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "pch_materialsystem.h"
  7. #define MATSYS_INTERNAL
  8. #include <math.h>
  9. #include "cmatrendercontext.h"
  10. #include "tier2/renderutils.h"
  11. #include "cmaterialsystem.h"
  12. #include "occlusionquerymgr.h"
  13. #include "texturemanager.h"
  14. #include "IHardwareConfigInternal.h"
  15. #include "ctype.h"
  16. #include "tier1/fmtstr.h"
  17. #include "togl/rendermechanism.h"
  18. // NOTE: This must be the last file included!!!
  19. #include "tier0/memdbgon.h"
  20. //-----------------------------------------------------------------------------
  21. // FIXME: right now, always keeping shader API in sync, because debug overlays don't seem to work 100% with the delayed matrix loading
  22. #define FORCE_MATRIX_SYNC 1
  23. #ifdef VALIDATE_MATRICES
  24. #define ShouldValidateMatrices() true
  25. #else
  26. #define ShouldValidateMatrices() false
  27. #endif
  28. #ifdef VALIDATE_MATRICES
  29. #define AllowLazyMatrixSync() false
  30. #define ForceSync() ((void)(0))
  31. #elif defined(FORCE_MATRIX_SYNC)
  32. #define AllowLazyMatrixSync() false
  33. #define ForceSync() ForceSyncMatrix( m_MatrixMode )
  34. #else
  35. #define AllowLazyMatrixSync() true
  36. #define ForceSync() ((void)(0))
  37. #endif
  38. #ifdef _X360
  39. static bool s_bDirtyDisk = false;
  40. #endif
  41. void ValidateMatrices( const VMatrix &m1, const VMatrix &m2, float eps = .001 )
  42. {
  43. if ( !ShouldValidateMatrices() )
  44. return;
  45. for ( int i = 0; i < 16; i++ )
  46. {
  47. AssertFloatEquals( m1.Base()[i], m1.Base()[i], eps );
  48. }
  49. }
  50. //-----------------------------------------------------------------------------
  51. // The dirty disk error report function (NOTE: Could be called from any thread!)
  52. //-----------------------------------------------------------------------------
  53. #ifdef _X360
  54. unsigned ThreadedDirtyDiskErrorDisplay( void *pParam )
  55. {
  56. XShowDirtyDiscErrorUI( XBX_GetPrimaryUserId() );
  57. }
  58. #endif
  59. void SpinPresent()
  60. {
  61. while ( true )
  62. {
  63. g_pShaderAPI->ClearColor3ub( 0, 0, 0 );
  64. g_pShaderAPI->ClearBuffers( true, true, true, -1, -1 );
  65. g_pShaderDevice->Present();
  66. }
  67. }
  68. void ReportDirtyDisk()
  69. {
  70. #ifdef _X360
  71. s_bDirtyDisk = true;
  72. ThreadHandle_t h = CreateSimpleThread( ThreadedDirtyDiskErrorDisplay, NULL );
  73. ThreadSetPriority( h, THREAD_PRIORITY_HIGHEST );
  74. // If this is being called from the render thread, immediately swap
  75. if ( ( ThreadGetCurrentId() == MaterialSystem()->GetRenderThreadId() ) ||
  76. ( ThreadInMainThread() && g_pMaterialSystem->GetThreadMode() != MATERIAL_QUEUED_THREADED ) )
  77. {
  78. SpinPresent();
  79. }
  80. #endif
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Install dirty disk error reporting function (call after SetMode)
  84. //-----------------------------------------------------------------------------
  85. void SetupDirtyDiskReportFunc()
  86. {
  87. g_pFullFileSystem->InstallDirtyDiskReportFunc( ReportDirtyDisk );
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Globals
  91. //-----------------------------------------------------------------------------
  92. CMemoryStack CMatRenderContextBase::sm_RenderData[2];
  93. int CMatRenderContextBase::sm_nRenderLockCount = 0;
  94. int CMatRenderContextBase::sm_nRenderStack = 0;
  95. int CMatRenderContextBase::sm_nInitializeCount = 0;
  96. //-----------------------------------------------------------------------------
  97. // Constructor
  98. //-----------------------------------------------------------------------------
  99. CMatRenderContextBase::CMatRenderContextBase() :
  100. m_pMaterialSystem( NULL ), m_RenderTargetStack( 16, 32 ), m_MatrixMode( NUM_MATRIX_MODES )
  101. {
  102. int i;
  103. m_bDirtyViewState = true;
  104. // Put a special element at the top of the RT stack (indicating back buffer is current top of stack)
  105. // NULL indicates back buffer, -1 indicates full-size viewport
  106. #if !defined( _X360 )
  107. RenderTargetStackElement_t initialElement = { {NULL, NULL, NULL, NULL}, NULL, 0, 0, -1, -1 };
  108. #else
  109. RenderTargetStackElement_t initialElement = { {NULL}, NULL, 0, 0, -1, -1 };
  110. #endif
  111. m_RenderTargetStack.Push( initialElement );
  112. for ( i = 0; i < MAX_FB_TEXTURES; i++ )
  113. {
  114. m_pCurrentFrameBufferCopyTexture[i] = NULL;
  115. }
  116. m_pCurrentMaterial = NULL;
  117. m_pCurrentProxyData = NULL;
  118. m_pUserDefinedLightmap = NULL;
  119. m_HeightClipMode = MATERIAL_HEIGHTCLIPMODE_DISABLE;
  120. m_HeightClipZ = 0.0f;
  121. m_bEnableClipping = true;
  122. m_bFlashlightEnable = false;
  123. m_bFullFrameDepthIsValid = false;
  124. for ( i = 0; i < NUM_MATRIX_MODES; i++ )
  125. {
  126. m_MatrixStacks[i].Push();
  127. m_MatrixStacks[i].Top().matrix.Identity();
  128. m_MatrixStacks[i].Top().flags |= ( MSF_DIRTY| MSF_IDENTITY );
  129. }
  130. m_pCurMatrixItem = &m_MatrixStacks[0].Top();
  131. m_Viewport.Init( 0, 0, 0, 0 );
  132. m_LastSetToneMapScale=Vector(1,1,1);
  133. m_CurToneMapScale=1.0;
  134. m_GoalToneMapScale = 1.0f;
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Init, shutdown
  138. //-----------------------------------------------------------------------------
  139. InitReturnVal_t CMatRenderContextBase::Init( )
  140. {
  141. MEM_ALLOC_CREDIT();
  142. if ( !sm_nInitializeCount )
  143. {
  144. int nSize = 2200 * 1024;
  145. int nCommitSize = 32 * 1024;
  146. #ifdef SWDS
  147. nSize = nCommitSize = 1024;
  148. #endif
  149. const char *gamedir = CommandLine()->ParmValue("-game", CommandLine()->ParmValue( "-defaultgamedir", "hl2" ) );
  150. if ( gamedir && !Q_stricmp( "garrysmod", gamedir ) )
  151. {
  152. nSize = 4400 * 1024;
  153. }
  154. sm_RenderData[0].Init( nSize, nCommitSize, 0, 32 );
  155. sm_RenderData[1].Init( nSize, nCommitSize, 0, 32 );
  156. sm_nRenderStack = 0;
  157. sm_nRenderLockCount = 0;
  158. }
  159. ++sm_nInitializeCount;
  160. return INIT_OK;
  161. }
  162. void CMatRenderContextBase::Shutdown( )
  163. {
  164. Assert( sm_nInitializeCount >= 0 );
  165. if ( --sm_nInitializeCount == 0 )
  166. {
  167. sm_RenderData[0].Term();
  168. sm_RenderData[1].Term();
  169. }
  170. }
  171. void CMatRenderContextBase::CompactMemory()
  172. {
  173. if ( sm_nRenderLockCount )
  174. {
  175. DevWarning( "CMatRenderContext: Trying to compact with render data still locked!\n" );
  176. sm_nRenderLockCount = 0;
  177. }
  178. sm_RenderData[0].FreeAll();
  179. sm_RenderData[1].FreeAll();
  180. }
  181. void CMatRenderContextBase::MarkRenderDataUnused( bool bFrameBegin )
  182. {
  183. if ( sm_nRenderLockCount )
  184. {
  185. DevWarning( "CMatRenderContext: Trying to clear render data with render data still locked (%d)!\n", sm_nRenderLockCount );
  186. sm_nRenderLockCount = 0;
  187. }
  188. // JAY: DO NOT MERGE FROM TF2 - L4D HAS CHANGED THE UNDERLYING INTERFACE IN A WAY THAT DOESN'T REQUIRE THIS
  189. #if 0
  190. // Switch stacks
  191. if ( bFrameBegin )
  192. {
  193. sm_nRenderStack = 1 - sm_nRenderStack;
  194. }
  195. // Clear the new stack
  196. #ifdef _DEBUG
  197. memset( sm_RenderData[sm_nRenderStack].GetBase(), 0xFF, RenderDataSizeUsed() );
  198. #endif
  199. sm_RenderData[ sm_nRenderStack ].FreeAll( false );
  200. #else
  201. // Just for TF2, don't free the stack until the end of frame. TF2 Allocates render data and holds it over the lock
  202. // period because we haven't revised the studiorender interface yet to change patterns.
  203. // Switch stacks
  204. if ( bFrameBegin )
  205. {
  206. sm_nRenderStack = 1 - sm_nRenderStack;
  207. // Clear the new stack
  208. #ifdef _DEBUG
  209. memset( sm_RenderData[sm_nRenderStack].GetBase(), 0xFF, RenderDataSizeUsed() );
  210. #endif
  211. sm_RenderData[ sm_nRenderStack ].FreeAll( false );
  212. }
  213. #endif
  214. }
  215. int CMatRenderContextBase::RenderDataSizeUsed() const
  216. {
  217. return sm_RenderData[sm_nRenderStack].GetUsed();
  218. }
  219. bool CMatRenderContextBase::IsRenderData( const void *pData ) const
  220. {
  221. intp nData = (intp)pData;
  222. intp nBaseAddress = (intp)sm_RenderData[sm_nRenderStack].GetBase();
  223. intp nLastAddress = nBaseAddress + RenderDataSizeUsed();
  224. return ( nData == 0 ) || ( nData >= nBaseAddress && nData < nLastAddress );
  225. }
  226. //-----------------------------------------------------------------------------
  227. // debug logging - empty in base class
  228. //-----------------------------------------------------------------------------
  229. void CMatRenderContextBase::PrintfVA( char *fmt, va_list vargs )
  230. {
  231. }
  232. void CMatRenderContextBase::Printf( const char *fmt, ... )
  233. {
  234. }
  235. float CMatRenderContextBase::Knob( char *knobname, float *setvalue )
  236. {
  237. return 0.0f;
  238. }
  239. //-----------------------------------------------------------------------------
  240. //
  241. //-----------------------------------------------------------------------------
  242. #define g_pShaderAPI Cannot_use_ShaderAPI_in_CMatRenderContextBase
  243. void CMatRenderContextBase::InitializeFrom( CMatRenderContextBase *pInitialState )
  244. {
  245. int i;
  246. m_pCurrentMaterial = pInitialState->m_pCurrentMaterial;
  247. m_pCurrentProxyData = pInitialState->m_pCurrentProxyData;
  248. m_lightmapPageID = pInitialState->m_lightmapPageID;
  249. m_pUserDefinedLightmap = pInitialState->m_pUserDefinedLightmap;
  250. m_pLocalCubemapTexture = pInitialState->m_pLocalCubemapTexture;
  251. memcpy( m_pCurrentFrameBufferCopyTexture, pInitialState->m_pCurrentFrameBufferCopyTexture, MAX_FB_TEXTURES * sizeof(ITexture *) );
  252. m_bEnableClipping = pInitialState->m_bEnableClipping;
  253. m_HeightClipMode = pInitialState->m_HeightClipMode;
  254. m_HeightClipZ = pInitialState->m_HeightClipZ;
  255. m_pBoundMorph = pInitialState->m_pBoundMorph; // not reference counted?
  256. m_RenderTargetStack.Clear();
  257. m_RenderTargetStack.EnsureCapacity( pInitialState->m_RenderTargetStack.Count() );
  258. for ( i = 0; i < pInitialState->m_RenderTargetStack.Count(); i++ )
  259. {
  260. m_RenderTargetStack.Push( pInitialState->m_RenderTargetStack[i] );
  261. }
  262. m_MatrixMode = pInitialState->m_MatrixMode;
  263. for ( i = 0; i < NUM_MATRIX_MODES; i++ )
  264. {
  265. m_MatrixStacks[i].CopyFrom( pInitialState->m_MatrixStacks[i] );
  266. }
  267. m_bFlashlightEnable = pInitialState->m_bFlashlightEnable;
  268. m_FrameTime = pInitialState->m_FrameTime;
  269. m_GoalToneMapScale = pInitialState->m_GoalToneMapScale;
  270. m_CurToneMapScale = pInitialState->m_CurToneMapScale;
  271. m_LastSetToneMapScale = pInitialState->m_LastSetToneMapScale;
  272. }
  273. void CMatRenderContextBase::Bind( IMaterial *iMaterial, void *proxyData )
  274. {
  275. IMaterialInternal *material = static_cast<IMaterialInternal *>( iMaterial );
  276. if ( !material )
  277. {
  278. Warning( "Programming error: CMatRenderContext::Bind: NULL material\n" );
  279. material = static_cast<IMaterialInternal *>( g_pErrorMaterial );
  280. }
  281. material = material->GetRealTimeVersion(); //always work with the real time versions of materials internally
  282. if ( GetCurrentMaterialInternal() != material )
  283. {
  284. if( !material->IsPrecached() )
  285. {
  286. DevWarning( "Binding uncached material \"%s\", artificially incrementing refcount\n", material->GetName() );
  287. material->ArtificialAddRef();
  288. material->Precache();
  289. }
  290. SetCurrentMaterialInternal(material);
  291. }
  292. SetCurrentProxy( proxyData );
  293. }
  294. void CMatRenderContextBase::BindLightmapPage( int lightmapPageID )
  295. {
  296. m_lightmapPageID = lightmapPageID;
  297. }
  298. void CMatRenderContextBase::SetRenderTargetEx( int nRenderTargetID, ITexture *pNewTarget )
  299. {
  300. // Verify valid top of RT stack
  301. Assert ( m_RenderTargetStack.Count() > 0 );
  302. // Reset the top of stack to the new target with old viewport
  303. RenderTargetStackElement_t newTOS = m_RenderTargetStack.Top();
  304. newTOS.m_pRenderTargets[nRenderTargetID] = pNewTarget;
  305. m_RenderTargetStack.Pop( );
  306. m_RenderTargetStack.Push( newTOS );
  307. }
  308. void CMatRenderContextBase::BindLocalCubemap( ITexture *pTexture )
  309. {
  310. if( pTexture )
  311. {
  312. m_pLocalCubemapTexture = pTexture;
  313. }
  314. else
  315. {
  316. m_pLocalCubemapTexture = TextureManager()->ErrorTexture();
  317. }
  318. }
  319. ITexture *CMatRenderContextBase::GetRenderTarget( void )
  320. {
  321. if (m_RenderTargetStack.Count() > 0)
  322. {
  323. return m_RenderTargetStack.Top().m_pRenderTargets[0];
  324. }
  325. else
  326. {
  327. return NULL; // should this be something else, since NULL indicates back buffer?
  328. }
  329. }
  330. ITexture *CMatRenderContextBase::GetRenderTargetEx( int nRenderTargetID )
  331. {
  332. // Verify valid top of stack
  333. Assert ( m_RenderTargetStack.Count() > 0 );
  334. // Top of render target stack
  335. ITexture *pTexture = m_RenderTargetStack.Top().m_pRenderTargets[ nRenderTargetID ];
  336. return pTexture;
  337. }
  338. void CMatRenderContextBase::SetFrameBufferCopyTexture( ITexture *pTexture, int textureIndex )
  339. {
  340. if( textureIndex < 0 || textureIndex > MAX_FB_TEXTURES )
  341. {
  342. Assert( 0 );
  343. return;
  344. }
  345. // FIXME: Do I need to increment/decrement ref counts here, or assume that the app is going to do it?
  346. m_pCurrentFrameBufferCopyTexture[textureIndex] = pTexture;
  347. }
  348. ITexture *CMatRenderContextBase::GetFrameBufferCopyTexture( int textureIndex )
  349. {
  350. if( textureIndex < 0 || textureIndex > MAX_FB_TEXTURES )
  351. {
  352. Assert( 0 );
  353. return NULL; // FIXME! This should return the error texture.
  354. }
  355. return m_pCurrentFrameBufferCopyTexture[textureIndex];
  356. }
  357. void CMatRenderContextBase::MatrixMode( MaterialMatrixMode_t mode )
  358. {
  359. Assert( m_MatrixStacks[mode].Count() );
  360. m_MatrixMode = mode;
  361. m_pCurMatrixItem = &m_MatrixStacks[mode].Top();
  362. }
  363. void CMatRenderContextBase::CurrentMatrixChanged()
  364. {
  365. if ( m_MatrixMode == MATERIAL_VIEW )
  366. {
  367. m_bDirtyViewState = true;
  368. m_bDirtyViewProjState = true;
  369. }
  370. else if ( m_MatrixMode == MATERIAL_PROJECTION )
  371. {
  372. m_bDirtyViewProjState = true;
  373. }
  374. }
  375. void CMatRenderContextBase::PushMatrix()
  376. {
  377. CUtlStack<MatrixStackItem_t> &curStack = m_MatrixStacks[ m_MatrixMode ];
  378. Assert( curStack.Count() );
  379. int iNew = curStack.Push();
  380. curStack[ iNew ] = curStack[ iNew - 1 ];
  381. m_pCurMatrixItem = &curStack.Top();
  382. CurrentMatrixChanged();
  383. }
  384. void CMatRenderContextBase::PopMatrix()
  385. {
  386. Assert( m_MatrixStacks[m_MatrixMode].Count() > 1 );
  387. m_MatrixStacks[ m_MatrixMode ].Pop();
  388. m_pCurMatrixItem = &m_MatrixStacks[m_MatrixMode].Top();
  389. CurrentMatrixChanged();
  390. }
  391. void CMatRenderContextBase::LoadMatrix( const VMatrix& matrix )
  392. {
  393. m_pCurMatrixItem->matrix = matrix;
  394. m_pCurMatrixItem->flags = MSF_DIRTY; // clearing identity implicitly
  395. CurrentMatrixChanged();
  396. }
  397. void CMatRenderContextBase::LoadMatrix( const matrix3x4_t& matrix )
  398. {
  399. m_pCurMatrixItem->matrix = matrix;
  400. m_pCurMatrixItem->flags = MSF_DIRTY; // clearing identity implicitly
  401. CurrentMatrixChanged();
  402. }
  403. void CMatRenderContextBase::MultMatrix( const VMatrix& matrix )
  404. {
  405. VMatrix result;
  406. MatrixMultiply( matrix, m_pCurMatrixItem->matrix, result );
  407. m_pCurMatrixItem->matrix = result;
  408. m_pCurMatrixItem->flags = MSF_DIRTY; // clearing identity implicitly
  409. CurrentMatrixChanged();
  410. }
  411. void CMatRenderContextBase::MultMatrix( const matrix3x4_t& matrix )
  412. {
  413. CMatRenderContextBase::MultMatrix( VMatrix( matrix ) );
  414. }
  415. void CMatRenderContextBase::MultMatrixLocal( const VMatrix& matrix )
  416. {
  417. VMatrix result;
  418. MatrixMultiply( m_pCurMatrixItem->matrix, matrix, result );
  419. m_pCurMatrixItem->matrix = result;
  420. m_pCurMatrixItem->flags = MSF_DIRTY; // clearing identity implicitly
  421. CurrentMatrixChanged();
  422. }
  423. void CMatRenderContextBase::MultMatrixLocal( const matrix3x4_t& matrix )
  424. {
  425. CMatRenderContextBase::MultMatrixLocal( VMatrix( matrix ) );
  426. }
  427. void CMatRenderContextBase::LoadIdentity()
  428. {
  429. // FIXME: possibly track is identity so can call shader API LoadIdentity() later instead of LoadMatrix()?
  430. m_pCurMatrixItem->matrix.Identity();
  431. m_pCurMatrixItem->flags = ( MSF_DIRTY | MSF_IDENTITY );
  432. CurrentMatrixChanged();
  433. }
  434. void CMatRenderContextBase::Ortho( double left, double top, double right, double bottom, double zNear, double zFar )
  435. {
  436. MatrixOrtho( m_pCurMatrixItem->matrix, left, top, right, bottom, zNear, zFar );
  437. m_pCurMatrixItem->flags = MSF_DIRTY;
  438. }
  439. void CMatRenderContextBase::PerspectiveX( double flFovX, double flAspect, double flZNear, double flZFar )
  440. {
  441. MatrixPerspectiveX( m_pCurMatrixItem->matrix, flFovX, flAspect, flZNear, flZFar );
  442. m_pCurMatrixItem->flags = MSF_DIRTY;
  443. }
  444. void CMatRenderContextBase::PerspectiveOffCenterX( double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right )
  445. {
  446. MatrixPerspectiveOffCenterX( m_pCurMatrixItem->matrix, flFovX, flAspect, flZNear, flZFar, bottom, top, left, right );
  447. m_pCurMatrixItem->flags = MSF_DIRTY;
  448. }
  449. void CMatRenderContextBase::PickMatrix( int x, int y, int nWidth, int nHeight )
  450. {
  451. int vx, vy, vwidth, vheight;
  452. GetViewport( vx, vy, vwidth, vheight );
  453. // Compute the location of the pick region in projection space...
  454. float px = 2.0 * (float)(x - vx) / (float)vwidth - 1;
  455. float py = 2.0 * (float)(y - vy)/ (float)vheight - 1;
  456. float pw = 2.0 * (float)nWidth / (float)vwidth;
  457. float ph = 2.0 * (float)nHeight / (float)vheight;
  458. // we need to translate (px, py) to the origin
  459. // and scale so (pw,ph) -> (2, 2)
  460. VMatrix mat;
  461. MatrixSetIdentity( mat );
  462. mat.m[0][0] = 2.0 / pw;
  463. mat.m[1][1] = 2.0 / ph;
  464. mat.m[0][3] = -2.0 * px / pw;
  465. mat.m[1][3] = -2.0 * py / ph;
  466. CMatRenderContextBase::MultMatrixLocal( mat );
  467. }
  468. void CMatRenderContextBase::Rotate( float flAngle, float x, float y, float z )
  469. {
  470. MatrixRotate( m_pCurMatrixItem->matrix, Vector( x, y, z ), flAngle );
  471. m_pCurMatrixItem->flags = MSF_DIRTY;
  472. }
  473. void CMatRenderContextBase::Translate( float x, float y, float z )
  474. {
  475. MatrixTranslate( m_pCurMatrixItem->matrix, Vector( x, y, z ) );
  476. m_pCurMatrixItem->flags = MSF_DIRTY;
  477. }
  478. void CMatRenderContextBase::Scale( float x, float y, float z )
  479. {
  480. VMatrix mat;
  481. MatrixBuildScale( mat, x, y, z );
  482. CMatRenderContextBase::MultMatrixLocal( mat );
  483. }
  484. void CMatRenderContextBase::GetMatrix( MaterialMatrixMode_t matrixMode, VMatrix *pMatrix )
  485. {
  486. CUtlStack<MatrixStackItem_t> &stack = m_MatrixStacks[ matrixMode ];
  487. if ( !stack.Count() )
  488. {
  489. pMatrix->Identity();
  490. return;
  491. }
  492. *pMatrix = stack.Top().matrix;
  493. }
  494. void CMatRenderContextBase::GetMatrix( MaterialMatrixMode_t matrixMode, matrix3x4_t *pMatrix )
  495. {
  496. CUtlStack<MatrixStackItem_t> &stack = m_MatrixStacks[ matrixMode ];
  497. if ( !stack.Count() )
  498. {
  499. SetIdentityMatrix( *pMatrix );
  500. return;
  501. }
  502. *pMatrix = stack.Top().matrix.As3x4();
  503. }
  504. void CMatRenderContextBase::RecomputeViewState()
  505. {
  506. if ( !m_bDirtyViewState )
  507. return;
  508. m_bDirtyViewState = false;
  509. // FIXME: Cache this off to make it less expensive?
  510. matrix3x4_t viewMatrix;
  511. GetMatrix( MATERIAL_VIEW, &viewMatrix );
  512. m_vecViewOrigin.x =
  513. -( viewMatrix[0][3] * viewMatrix[0][0] +
  514. viewMatrix[1][3] * viewMatrix[1][0] +
  515. viewMatrix[2][3] * viewMatrix[2][0] );
  516. m_vecViewOrigin.y =
  517. -( viewMatrix[0][3] * viewMatrix[0][1] +
  518. viewMatrix[1][3] * viewMatrix[1][1] +
  519. viewMatrix[2][3] * viewMatrix[2][1] );
  520. m_vecViewOrigin.z =
  521. -( viewMatrix[0][3] * viewMatrix[0][2] +
  522. viewMatrix[1][3] * viewMatrix[1][2] +
  523. viewMatrix[2][3] * viewMatrix[2][2] );
  524. // FIXME Implement computation of m_vecViewForward, etc
  525. m_vecViewForward.Init();
  526. m_vecViewRight.Init();
  527. // FIXME: Is this correct?
  528. m_vecViewUp.Init( viewMatrix[1][0], viewMatrix[1][1], viewMatrix[1][2] );
  529. }
  530. void CMatRenderContextBase::GetWorldSpaceCameraPosition( Vector *pCameraPos )
  531. {
  532. RecomputeViewState();
  533. VectorCopy( m_vecViewOrigin, *pCameraPos );
  534. }
  535. void CMatRenderContextBase::GetWorldSpaceCameraVectors( Vector *pVecForward, Vector *pVecRight, Vector *pVecUp )
  536. {
  537. RecomputeViewState();
  538. // FIXME Implement computation of m_vecViewForward
  539. Assert( 0 );
  540. if ( pVecForward )
  541. {
  542. VectorCopy( m_vecViewForward, *pVecForward );
  543. }
  544. if ( pVecRight )
  545. {
  546. VectorCopy( m_vecViewRight, *pVecRight );
  547. }
  548. if ( pVecUp )
  549. {
  550. VectorCopy( m_vecViewUp, *pVecUp );
  551. }
  552. }
  553. void *CMatRenderContextBase::LockRenderData( int nSizeInBytes )
  554. {
  555. MEM_ALLOC_CREDIT();
  556. void *pDest = sm_RenderData[ sm_nRenderStack ].Alloc( nSizeInBytes, false );
  557. if ( !pDest )
  558. {
  559. ExecuteNTimes( 10, Warning("MaterialSystem: Out of memory in render data!\n") );
  560. }
  561. AddRefRenderData();
  562. return pDest;
  563. }
  564. void CMatRenderContextBase::UnlockRenderData( void *pData )
  565. {
  566. ReleaseRenderData();
  567. }
  568. void CMatRenderContextBase::AddRefRenderData()
  569. {
  570. ++sm_nRenderLockCount;
  571. }
  572. void CMatRenderContextBase::ReleaseRenderData()
  573. {
  574. --sm_nRenderLockCount;
  575. Assert( sm_nRenderLockCount >= 0 );
  576. if ( sm_nRenderLockCount == 0 )
  577. {
  578. OnRenderDataUnreferenced();
  579. }
  580. }
  581. void CMatRenderContextBase::SyncMatrices()
  582. {
  583. }
  584. void CMatRenderContextBase::SyncMatrix( MaterialMatrixMode_t mode )
  585. {
  586. }
  587. void CMatRenderContextBase::SetHeightClipMode( enum MaterialHeightClipMode_t heightClipMode )
  588. {
  589. if( m_HeightClipMode != heightClipMode )
  590. {
  591. m_HeightClipMode = heightClipMode;
  592. UpdateHeightClipUserClipPlane();
  593. /*if ( HardwareConfig()->MaxUserClipPlanes() >= 1 && !HardwareConfig()->UseFastClipping())
  594. {
  595. UpdateHeightClipUserClipPlane();
  596. }
  597. else
  598. {
  599. g_pShaderAPI->SetHeightClipMode( heightClipMode );
  600. }*/
  601. }
  602. }
  603. void CMatRenderContextBase::SetHeightClipZ( float z )
  604. {
  605. if( z != m_HeightClipZ )
  606. {
  607. m_HeightClipZ = z;
  608. UpdateHeightClipUserClipPlane();
  609. }
  610. // FIXME! : Need to move user clip plane support back to pre-dx9 cards (all of the pixel shaders
  611. // have texkill in them. . blich.)
  612. /*if ( HardwareConfig()->MaxUserClipPlanes() >= 1 && !HardwareConfig()->UseFastClipping() )
  613. {
  614. UpdateHeightClipUserClipPlane();
  615. }
  616. else
  617. {
  618. g_pShaderAPI->SetHeightClipZ( z );
  619. }*/
  620. }
  621. bool CMatRenderContextBase::EnableClipping( bool bEnable )
  622. {
  623. if( bEnable != m_bEnableClipping )
  624. {
  625. m_bEnableClipping = bEnable;
  626. ApplyCustomClipPlanes();
  627. return !bEnable;
  628. }
  629. return bEnable;
  630. }
  631. void CMatRenderContextBase::Viewport( int x, int y, int width, int height )
  632. {
  633. // Verify valid top of RT stack
  634. Assert ( m_RenderTargetStack.Count() > 0 );
  635. // Reset the top of stack to the new viewport
  636. RenderTargetStackElement_t newTOS;
  637. memcpy(&newTOS,&(m_RenderTargetStack.Top()),sizeof(newTOS));
  638. newTOS.m_nViewX = x;
  639. newTOS.m_nViewY = y;
  640. newTOS.m_nViewW = width;
  641. newTOS.m_nViewH = height;
  642. m_RenderTargetStack.Pop( );
  643. m_RenderTargetStack.Push( newTOS );
  644. }
  645. //-----------------------------------------------------------------------------
  646. // This version will push the current rendertarget + current viewport onto the stack
  647. //-----------------------------------------------------------------------------
  648. void CMatRenderContextBase::PushRenderTargetAndViewport( )
  649. {
  650. // Necessary to push the stack top onto itself; realloc could happen otherwise
  651. m_RenderTargetStack.EnsureCapacity( m_RenderTargetStack.Count() + 1 );
  652. m_RenderTargetStack.Push( m_RenderTargetStack.Top() );
  653. CommitRenderTargetAndViewport();
  654. }
  655. //-----------------------------------------------------------------------------
  656. // Pushes a render target on the render target stack. Without a specific
  657. // viewport also being pushed, this function uses dummy values which indicate
  658. // that the viewport should span the the full render target and pushes
  659. // the RenderTargetStackElement_t onto the stack
  660. //
  661. // The push and pop methods also implicitly set the render target to the new top of stack
  662. //
  663. // NULL for pTexture indicates rendering to the back buffer
  664. //-----------------------------------------------------------------------------
  665. void CMatRenderContextBase::PushRenderTargetAndViewport( ITexture *pTexture )
  666. {
  667. // Just blindly push the data on the stack with flags indicating full bounds
  668. #if !defined( _X360 )
  669. RenderTargetStackElement_t element = { {pTexture, NULL, NULL, NULL}, 0, 0, -1, -1 };
  670. #else
  671. RenderTargetStackElement_t element = { {pTexture}, 0, 0, -1, -1 };
  672. #endif
  673. m_RenderTargetStack.Push( element );
  674. CommitRenderTargetAndViewport();
  675. }
  676. //-----------------------------------------------------------------------------
  677. // Pushes a render target on the render target stack and sets the viewport
  678. //
  679. // NULL for pTexture indicates rendering to the back buffer
  680. //
  681. // The push and pop methods also implicitly set the render target to the new top of stack
  682. //-----------------------------------------------------------------------------
  683. void CMatRenderContextBase::PushRenderTargetAndViewport( ITexture *pTexture, int nViewX, int nViewY, int nViewW, int nViewH )
  684. {
  685. CMatRenderContextBase::PushRenderTargetAndViewport( pTexture, NULL, nViewX, nViewY, nViewW, nViewH );
  686. }
  687. //-----------------------------------------------------------------------------
  688. // Pushes a render target on the render target stack and sets the viewport
  689. // The push and pop methods also implicitly set the render target to the new top of stack
  690. //-----------------------------------------------------------------------------
  691. void CMatRenderContextBase::PushRenderTargetAndViewport( ITexture *pTexture, ITexture *pDepthTexture, int nViewX, int nViewY, int nViewW, int nViewH )
  692. {
  693. // Just blindly push the data on the stack
  694. #if !defined( _X360 )
  695. RenderTargetStackElement_t element = { {pTexture, NULL, NULL, NULL}, pDepthTexture, nViewX, nViewY, nViewW, nViewH };
  696. #else
  697. RenderTargetStackElement_t element = { {pTexture}, pDepthTexture, nViewX, nViewY, nViewW, nViewH };
  698. #endif
  699. m_RenderTargetStack.Push( element );
  700. CommitRenderTargetAndViewport();
  701. }
  702. //-----------------------------------------------------------------------------
  703. // Pops from the render target stack
  704. // Also implicitly sets the render target to the new top of stack
  705. //-----------------------------------------------------------------------------
  706. void CMatRenderContextBase::PopRenderTargetAndViewport( void )
  707. {
  708. // Check for underflow
  709. if ( m_RenderTargetStack.Count() == 0 )
  710. {
  711. Assert( !"CMatRenderContext::PopRenderTargetAndViewport: Stack is empty!!!" );
  712. return;
  713. }
  714. // Changelist #266217 added this to main/src/materialsystem.
  715. Flush();
  716. // Remove the top of stack
  717. m_RenderTargetStack.Pop( );
  718. CommitRenderTargetAndViewport();
  719. }
  720. void CMatRenderContextBase::RecomputeViewProjState()
  721. {
  722. if ( m_bDirtyViewProjState )
  723. {
  724. VMatrix viewMatrix, projMatrix;
  725. // FIXME: Should consider caching this upon change for projection or view matrix.
  726. GetMatrix( MATERIAL_VIEW, &viewMatrix );
  727. GetMatrix( MATERIAL_PROJECTION, &projMatrix );
  728. m_viewProjMatrix = projMatrix * viewMatrix;
  729. m_bDirtyViewProjState = false;
  730. }
  731. }
  732. //-----------------------------------------------------------------------------
  733. // This returns the diameter of the sphere in pixels based on
  734. // the current model, view, + projection matrices and viewport.
  735. //-----------------------------------------------------------------------------
  736. float CMatRenderContextBase::ComputePixelDiameterOfSphere( const Vector& vecAbsOrigin, float flRadius )
  737. {
  738. RecomputeViewState();
  739. RecomputeViewProjState();
  740. // This is sort of faked, but it's faster that way
  741. // FIXME: Also, there's a much faster way to do this with similar triangles
  742. // but I want to make sure it exactly matches the current matrices, so
  743. // for now, I do it this conservative way
  744. Vector4D testPoint1, testPoint2;
  745. VectorMA( vecAbsOrigin, flRadius, m_vecViewUp, testPoint1.AsVector3D() );
  746. VectorMA( vecAbsOrigin, -flRadius, m_vecViewUp, testPoint2.AsVector3D() );
  747. testPoint1.w = testPoint2.w = 1.0f;
  748. Vector4D clipPos1, clipPos2;
  749. Vector4DMultiply( m_viewProjMatrix, testPoint1, clipPos1 );
  750. Vector4DMultiply( m_viewProjMatrix, testPoint2, clipPos2 );
  751. if (clipPos1.w >= 0.001f)
  752. {
  753. clipPos1.y /= clipPos1.w;
  754. }
  755. else
  756. {
  757. clipPos1.y *= 1000;
  758. }
  759. if (clipPos2.w >= 0.001f)
  760. {
  761. clipPos2.y /= clipPos2.w;
  762. }
  763. else
  764. {
  765. clipPos2.y *= 1000;
  766. }
  767. int vx, vy, vwidth, vheight;
  768. GetViewport( vx, vy, vwidth, vheight );
  769. // The divide-by-two here is because y goes from -1 to 1 in projection space
  770. return vheight * fabs( clipPos2.y - clipPos1.y ) / 2.0f;
  771. }
  772. ConVar mat_accelerate_adjust_exposure_down( "mat_accelerate_adjust_exposure_down", "3.0", FCVAR_CHEAT );
  773. ConVar mat_hdr_manual_tonemap_rate( "mat_hdr_manual_tonemap_rate", "1.0" );
  774. ConVar mat_hdr_tonemapscale( "mat_hdr_tonemapscale", "1.0", FCVAR_CHEAT );
  775. ConVar mat_tonemap_algorithm( "mat_tonemap_algorithm", "1", FCVAR_CHEAT, "0 = Original Algorithm 1 = New Algorithm" );
  776. void CMatRenderContextBase::TurnOnToneMapping(void)
  777. {
  778. if ( ( HardwareConfig()->GetHDRType() != HDR_TYPE_NONE ) && ( m_FrameTime > 0.0f ) )
  779. {
  780. float elapsed_time = m_FrameTime;
  781. float goalScale = m_GoalToneMapScale;
  782. float rate = mat_hdr_manual_tonemap_rate.GetFloat();
  783. if ( mat_tonemap_algorithm.GetInt() == 1 )
  784. {
  785. rate *= 2.0f; // Default 2x for the new tone mapping algorithm so it feels the same as the original
  786. }
  787. if ( rate == 0.0f ) // Zero indicates instantaneous tonemap scaling
  788. {
  789. m_CurToneMapScale = goalScale;
  790. }
  791. else
  792. {
  793. if ( goalScale < m_CurToneMapScale )
  794. {
  795. float acc_exposure_adjust = mat_accelerate_adjust_exposure_down.GetFloat();
  796. // Adjust at up to 4x rate when over-exposed.
  797. rate = min( ( acc_exposure_adjust * rate ), FLerp( rate, ( acc_exposure_adjust * rate ), 0.0f, 1.5f, ( m_CurToneMapScale - goalScale ) ) );
  798. }
  799. float flRateTimesTime = rate * elapsed_time;
  800. if ( mat_tonemap_algorithm.GetInt() == 1 )
  801. {
  802. // For the new tone mapping algorithm, limit the rate based on the number of bins to
  803. // help reduce the tone map scalar "riding the wave" of the histogram re-building
  804. //Warning( "flRateTimesTime = %.4f", flRateTimesTime );
  805. flRateTimesTime = min( flRateTimesTime, ( 1.0f / 16.0f ) * 0.25f ); // 16 is number of HDR sample bins defined in viewpostprocess.cpp
  806. //Warning( " --> %.4f\n", flRateTimesTime );
  807. }
  808. float alpha = max( 0.0f, min( 1.0f, flRateTimesTime ) );
  809. m_CurToneMapScale = ( goalScale * alpha ) + ( m_CurToneMapScale * ( 1.0f - alpha ) );
  810. if ( !IsFinite( m_CurToneMapScale ) )
  811. {
  812. Assert( 0 );
  813. m_CurToneMapScale = goalScale;
  814. }
  815. }
  816. SetToneMappingScaleLinear( Vector( m_CurToneMapScale, m_CurToneMapScale, m_CurToneMapScale ) );
  817. m_LastSetToneMapScale = Vector( m_CurToneMapScale, m_CurToneMapScale, m_CurToneMapScale );
  818. }
  819. }
  820. void CMatRenderContextBase::ResetToneMappingScale(float sc)
  821. {
  822. m_CurToneMapScale = sc;
  823. SetToneMappingScaleLinear( Vector( m_CurToneMapScale, m_CurToneMapScale, m_CurToneMapScale ) );
  824. m_LastSetToneMapScale = Vector( m_CurToneMapScale, m_CurToneMapScale, m_CurToneMapScale );
  825. // mat_hdr_tonemapscale.SetValue(1.0f);
  826. m_GoalToneMapScale = 1;
  827. }
  828. void CMatRenderContextBase::SetGoalToneMappingScale( float monoscale)
  829. {
  830. Assert( IsFinite( monoscale ) );
  831. if( IsFinite( monoscale ) )
  832. {
  833. m_GoalToneMapScale = monoscale;
  834. }
  835. }
  836. Vector CMatRenderContextBase::GetToneMappingScaleLinear( void )
  837. {
  838. if ( HardwareConfig()->GetHDRType() == HDR_TYPE_NONE )
  839. return Vector( 1.0f, 1.0f, 1.0f );
  840. else
  841. return m_LastSetToneMapScale;
  842. }
  843. void CMatRenderContextBase::OnAsyncCreateTextureFromRenderTarget( ITexture* pSrcRt, const char** ppDstName, IAsyncTextureOperationReceiver* pRecipient )
  844. {
  845. Assert( pSrcRt != NULL );
  846. Assert( pRecipient != NULL );
  847. Assert( ppDstName != NULL && *ppDstName != NULL);
  848. // Bump the ref count on the recipient before handing it off. This ensures the receiver won't go away before we have completed our work.
  849. pSrcRt->AddRef();
  850. pRecipient->AddRef();
  851. // Also, need to allocate a copy of the string and use that one s.t. the caller doesn't have to worry about it.
  852. char* pDstNameCopy = new char[ V_strlen( *ppDstName ) + 1 ];
  853. V_strcpy( pDstNameCopy, *ppDstName );
  854. ( *ppDstName ) = pDstNameCopy;
  855. }
  856. // Map and unmap a texture. The pRecipient->OnAsyncMapComplete is called when complete.
  857. void CMatRenderContextBase::OnAsyncMap( ITextureInternal* pTexToMap, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs )
  858. {
  859. Assert( pTexToMap != NULL );
  860. Assert( pRecipient != NULL );
  861. pTexToMap->AddRef();
  862. pRecipient->AddRef();
  863. }
  864. void CMatRenderContextBase::OnAsyncUnmap( ITextureInternal* pTexToUnmap )
  865. {
  866. Assert( pTexToUnmap != NULL );
  867. pTexToUnmap->AddRef();
  868. }
  869. void CMatRenderContextBase::OnAsyncCopyRenderTargetToStagingTexture( ITexture* pDst, ITexture* pSrc, IAsyncTextureOperationReceiver* pRecipient )
  870. {
  871. Assert( pDst != NULL );
  872. Assert( pSrc != NULL );
  873. Assert( pRecipient != NULL );
  874. pDst->AddRef();
  875. pSrc->AddRef();
  876. pRecipient->AddRef();
  877. }
  878. #undef g_pShaderAPI
  879. //-----------------------------------------------------------------------------
  880. //
  881. //-----------------------------------------------------------------------------
  882. CMatRenderContext::CMatRenderContext()
  883. {
  884. g_FrameNum = 0;
  885. m_pBatchIndices = NULL;
  886. m_pBatchMesh = NULL;
  887. m_pCurrentIndexBuffer = NULL;
  888. m_pMorphRenderContext = NULL;
  889. m_NonInteractiveMode = MATERIAL_NON_INTERACTIVE_MODE_NONE;
  890. }
  891. InitReturnVal_t CMatRenderContext::Init( CMaterialSystem *pMaterialSystem )
  892. {
  893. InitReturnVal_t nRetVal = BaseClass::Init();
  894. if ( nRetVal != INIT_OK )
  895. return nRetVal;
  896. m_pMaterialSystem = pMaterialSystem;
  897. m_pBoundMorph = NULL;
  898. // Create some lovely textures
  899. m_pLocalCubemapTexture = TextureManager()->ErrorTexture();
  900. m_pMorphRenderContext = g_pMorphMgr->AllocateRenderContext();
  901. return INIT_OK;
  902. }
  903. void CMatRenderContext::Shutdown( )
  904. {
  905. if ( m_pUserDefinedLightmap )
  906. {
  907. m_pUserDefinedLightmap->DecrementReferenceCount();
  908. m_pUserDefinedLightmap = NULL;
  909. }
  910. if ( m_pMorphRenderContext )
  911. {
  912. g_pMorphMgr->FreeRenderContext( m_pMorphRenderContext );
  913. m_pMorphRenderContext = NULL;
  914. }
  915. BaseClass::Shutdown();
  916. }
  917. void CMatRenderContext::OnReleaseShaderObjects()
  918. {
  919. // alt-tab unbinds the morph
  920. m_pBoundMorph = NULL;
  921. }
  922. #ifdef DX_TO_GL_ABSTRACTION
  923. void CMatRenderContext::DoStartupShaderPreloading( void )
  924. {
  925. g_pShaderDevice->DoStartupShaderPreloading();
  926. }
  927. #endif
  928. void CMatRenderContext::TextureManagerUpdate()
  929. {
  930. TextureManager()->Update();
  931. }
  932. inline IMaterialInternal *CMatRenderContext::GetMaterialInternal( MaterialHandle_t h ) const
  933. {
  934. return GetMaterialSystem()->GetMaterialInternal( h );
  935. }
  936. inline IMaterialInternal *CMatRenderContext::GetDrawFlatMaterial()
  937. {
  938. return GetMaterialSystem()->GetDrawFlatMaterial();
  939. }
  940. inline IMaterialInternal *CMatRenderContext::GetBufferClearObeyStencil( int i )
  941. {
  942. return GetMaterialSystem()->GetBufferClearObeyStencil(i );
  943. }
  944. inline ShaderAPITextureHandle_t CMatRenderContext::GetFullbrightLightmapTextureHandle() const
  945. {
  946. return GetMaterialSystem()->GetFullbrightLightmapTextureHandle();
  947. }
  948. inline ShaderAPITextureHandle_t CMatRenderContext::GetFullbrightBumpedLightmapTextureHandle() const
  949. {
  950. return GetMaterialSystem()->GetFullbrightBumpedLightmapTextureHandle();
  951. }
  952. inline ShaderAPITextureHandle_t CMatRenderContext::GetBlackTextureHandle() const
  953. {
  954. return GetMaterialSystem()->GetBlackTextureHandle();
  955. }
  956. inline ShaderAPITextureHandle_t CMatRenderContext::GetFlatNormalTextureHandle() const
  957. {
  958. return GetMaterialSystem()->GetFlatNormalTextureHandle();
  959. }
  960. inline ShaderAPITextureHandle_t CMatRenderContext::GetGreyTextureHandle() const
  961. {
  962. return GetMaterialSystem()->GetGreyTextureHandle();
  963. }
  964. inline ShaderAPITextureHandle_t CMatRenderContext::GetGreyAlphaZeroTextureHandle() const
  965. {
  966. return GetMaterialSystem()->GetGreyAlphaZeroTextureHandle();
  967. }
  968. inline ShaderAPITextureHandle_t CMatRenderContext::GetWhiteTextureHandle() const
  969. {
  970. return GetMaterialSystem()->GetWhiteTextureHandle();
  971. }
  972. inline const CMatLightmaps *CMatRenderContext::GetLightmaps() const
  973. {
  974. return GetMaterialSystem()->GetLightmaps();
  975. }
  976. inline CMatLightmaps *CMatRenderContext::GetLightmaps()
  977. {
  978. return GetMaterialSystem()->GetLightmaps();
  979. }
  980. inline ShaderAPITextureHandle_t CMatRenderContext::GetMaxDepthTextureHandle() const
  981. {
  982. return GetMaterialSystem()->GetMaxDepthTextureHandle();
  983. }
  984. void CMatRenderContext::BeginRender()
  985. {
  986. #if 1 // Rick's optimization: not sure this is needed anymore
  987. if ( GetMaterialSystem()->GetThreadMode() != MATERIAL_SINGLE_THREADED )
  988. {
  989. VPROF_INCREMENT_GROUP_COUNTER( "render/CMatBeginRender", COUNTER_GROUP_TELEMETRY, 1 );
  990. TelemetrySetLockName( TELEMETRY_LEVEL1, (char const *)&g_MatSysMutex, "MatSysMutex" );
  991. tmTryLock( TELEMETRY_LEVEL1, (char const *)&g_MatSysMutex, "BeginRender" );
  992. g_MatSysMutex.Lock();
  993. tmEndTryLock( TELEMETRY_LEVEL1, (char const *)&g_MatSysMutex, TMLR_SUCCESS );
  994. tmSetLockState( TELEMETRY_LEVEL1, (char const *)&g_MatSysMutex, TMLS_LOCKED, "BeginRender" );
  995. }
  996. #endif
  997. }
  998. void CMatRenderContext::EndRender()
  999. {
  1000. #if 1 // Rick's optimization: not sure this is needed anymore
  1001. if ( GetMaterialSystem()->GetThreadMode() != MATERIAL_SINGLE_THREADED )
  1002. {
  1003. g_MatSysMutex.Unlock();
  1004. tmSetLockState( TELEMETRY_LEVEL1, (char const *)&g_MatSysMutex, TMLS_RELEASED, "EndRender" );
  1005. }
  1006. #endif
  1007. }
  1008. void CMatRenderContext::Flush( bool flushHardware )
  1009. {
  1010. VPROF( "CMatRenderContextBase::Flush" );
  1011. g_pShaderAPI->FlushBufferedPrimitives();
  1012. if ( IsPC() && flushHardware )
  1013. {
  1014. g_pShaderAPI->FlushBufferedPrimitives();
  1015. }
  1016. }
  1017. bool CMatRenderContext::TestMatrixSync( MaterialMatrixMode_t mode )
  1018. {
  1019. if ( !ShouldValidateMatrices() )
  1020. {
  1021. return true;
  1022. }
  1023. VMatrix transposeMatrix, matrix;
  1024. g_pShaderAPI->GetMatrix( mode, (float*)transposeMatrix.m );
  1025. MatrixTranspose( transposeMatrix, matrix );
  1026. ValidateMatrices( matrix, m_MatrixStacks[mode].Top().matrix );
  1027. return true;
  1028. }
  1029. void CMatRenderContext::MatrixMode( MaterialMatrixMode_t mode )
  1030. {
  1031. CMatRenderContextBase::MatrixMode( mode );
  1032. g_pShaderAPI->MatrixMode( mode );
  1033. if ( ShouldValidateMatrices() )
  1034. {
  1035. TestMatrixSync( mode );
  1036. }
  1037. }
  1038. void CMatRenderContext::PushMatrix()
  1039. {
  1040. if ( ShouldValidateMatrices() )
  1041. {
  1042. TestMatrixSync( m_MatrixMode );
  1043. }
  1044. CMatRenderContextBase::PushMatrix();
  1045. g_pShaderAPI->PushMatrix();
  1046. if ( ShouldValidateMatrices() )
  1047. {
  1048. TestMatrixSync( m_MatrixMode );
  1049. }
  1050. }
  1051. void CMatRenderContext::PopMatrix()
  1052. {
  1053. if ( ShouldValidateMatrices() )
  1054. {
  1055. TestMatrixSync( m_MatrixMode );
  1056. }
  1057. CMatRenderContextBase::PopMatrix();
  1058. g_pShaderAPI->PopMatrix();
  1059. if ( ShouldValidateMatrices() )
  1060. {
  1061. TestMatrixSync( m_MatrixMode );
  1062. }
  1063. }
  1064. void CMatRenderContext::LoadMatrix( const VMatrix& matrix )
  1065. {
  1066. CMatRenderContextBase::LoadMatrix( matrix );
  1067. ForceSync();
  1068. if ( ShouldValidateMatrices() )
  1069. {
  1070. VMatrix transposeMatrix;
  1071. MatrixTranspose( matrix, transposeMatrix );
  1072. g_pShaderAPI->LoadMatrix( transposeMatrix.Base() );
  1073. TestMatrixSync( m_MatrixMode );
  1074. }
  1075. }
  1076. void CMatRenderContext::LoadMatrix( const matrix3x4_t& matrix )
  1077. {
  1078. CMatRenderContextBase::LoadMatrix( matrix );
  1079. ForceSync();
  1080. if ( ShouldValidateMatrices() )
  1081. {
  1082. VMatrix transposeMatrix;
  1083. MatrixTranspose( VMatrix(matrix), transposeMatrix );
  1084. g_pShaderAPI->LoadMatrix( transposeMatrix.Base() );
  1085. TestMatrixSync( m_MatrixMode );
  1086. }
  1087. }
  1088. void CMatRenderContext::MultMatrix( const VMatrix& matrix )
  1089. {
  1090. CMatRenderContextBase::MultMatrix( matrix );
  1091. ForceSync();
  1092. if ( ShouldValidateMatrices() )
  1093. {
  1094. VMatrix transposeMatrix;
  1095. MatrixTranspose( matrix, transposeMatrix );
  1096. g_pShaderAPI->MultMatrix( transposeMatrix.Base() );
  1097. TestMatrixSync( m_MatrixMode );
  1098. }
  1099. }
  1100. void CMatRenderContext::MultMatrix( const matrix3x4_t& matrix )
  1101. {
  1102. CMatRenderContextBase::MultMatrix( VMatrix( matrix ) );
  1103. ForceSync();
  1104. if ( ShouldValidateMatrices() )
  1105. {
  1106. VMatrix transposeMatrix;
  1107. MatrixTranspose( VMatrix(matrix), transposeMatrix );
  1108. g_pShaderAPI->MultMatrix( transposeMatrix.Base() );
  1109. TestMatrixSync( m_MatrixMode );
  1110. }
  1111. }
  1112. void CMatRenderContext::MultMatrixLocal( const VMatrix& matrix )
  1113. {
  1114. CMatRenderContextBase::MultMatrixLocal( matrix );
  1115. ForceSync();
  1116. if ( ShouldValidateMatrices() )
  1117. {
  1118. VMatrix transposeMatrix;
  1119. MatrixTranspose( matrix, transposeMatrix );
  1120. g_pShaderAPI->MultMatrixLocal( transposeMatrix.Base() );
  1121. TestMatrixSync( m_MatrixMode );
  1122. }
  1123. }
  1124. void CMatRenderContext::MultMatrixLocal( const matrix3x4_t& matrix )
  1125. {
  1126. CMatRenderContextBase::MultMatrixLocal( VMatrix( matrix ) );
  1127. ForceSync();
  1128. if ( ShouldValidateMatrices() )
  1129. {
  1130. VMatrix transposeMatrix;
  1131. MatrixTranspose( VMatrix(matrix), transposeMatrix );
  1132. g_pShaderAPI->MultMatrixLocal( transposeMatrix.Base() );
  1133. TestMatrixSync( m_MatrixMode );
  1134. }
  1135. }
  1136. void CMatRenderContext::LoadIdentity()
  1137. {
  1138. CMatRenderContextBase::LoadIdentity();
  1139. ForceSync();
  1140. if ( ShouldValidateMatrices() )
  1141. {
  1142. g_pShaderAPI->LoadIdentity();
  1143. TestMatrixSync( m_MatrixMode );
  1144. }
  1145. }
  1146. void CMatRenderContext::Ortho( double left, double top, double right, double bottom, double zNear, double zFar )
  1147. {
  1148. CMatRenderContextBase::Ortho( left, top, right, bottom, zNear, zFar );
  1149. ForceSync();
  1150. if ( ShouldValidateMatrices() )
  1151. {
  1152. g_pShaderAPI->Ortho( left, top, right, bottom, zNear, zFar );
  1153. TestMatrixSync( m_MatrixMode );
  1154. }
  1155. }
  1156. void CMatRenderContext::PerspectiveX( double flFovX, double flAspect, double flZNear, double flZFar )
  1157. {
  1158. CMatRenderContextBase::PerspectiveX( flFovX, flAspect, flZNear, flZFar );
  1159. ForceSync();
  1160. if ( ShouldValidateMatrices() )
  1161. {
  1162. g_pShaderAPI->PerspectiveX( flFovX, flAspect, flZNear, flZFar );
  1163. TestMatrixSync( m_MatrixMode );
  1164. }
  1165. }
  1166. void CMatRenderContext::PerspectiveOffCenterX( double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right )
  1167. {
  1168. CMatRenderContextBase::PerspectiveOffCenterX( flFovX, flAspect, flZNear, flZFar, bottom, top, left, right );
  1169. ForceSync();
  1170. if ( ShouldValidateMatrices() )
  1171. {
  1172. g_pShaderAPI->PerspectiveOffCenterX( flFovX, flAspect, flZNear, flZFar, bottom, top, left, right );
  1173. TestMatrixSync( m_MatrixMode );
  1174. }
  1175. }
  1176. void CMatRenderContext::PickMatrix( int x, int y, int nWidth, int nHeight )
  1177. {
  1178. CMatRenderContextBase::PickMatrix( x, y, nWidth, nHeight );
  1179. ForceSync();
  1180. if ( ShouldValidateMatrices() )
  1181. {
  1182. g_pShaderAPI->PickMatrix( x, y, nWidth, nHeight );
  1183. TestMatrixSync( m_MatrixMode );
  1184. }
  1185. }
  1186. void CMatRenderContext::Rotate( float flAngle, float x, float y, float z )
  1187. {
  1188. CMatRenderContextBase::Rotate( flAngle, x, y, z );
  1189. ForceSync();
  1190. if ( ShouldValidateMatrices() )
  1191. {
  1192. g_pShaderAPI->Rotate( flAngle, x, y, z );
  1193. TestMatrixSync( m_MatrixMode );
  1194. }
  1195. }
  1196. void CMatRenderContext::Translate( float x, float y, float z )
  1197. {
  1198. CMatRenderContextBase::Translate( x, y, z );
  1199. ForceSync();
  1200. if ( ShouldValidateMatrices() )
  1201. {
  1202. g_pShaderAPI->Translate( x, y, z );
  1203. TestMatrixSync( m_MatrixMode );
  1204. }
  1205. }
  1206. void CMatRenderContext::Scale( float x, float y, float z )
  1207. {
  1208. CMatRenderContextBase::Scale( x, y, z );
  1209. ForceSync();
  1210. if ( ShouldValidateMatrices() )
  1211. {
  1212. g_pShaderAPI->Scale( x, y, z );
  1213. TestMatrixSync( m_MatrixMode );
  1214. }
  1215. }
  1216. void CMatRenderContext::GetMatrix( MaterialMatrixMode_t matrixMode, VMatrix *pMatrix )
  1217. {
  1218. CMatRenderContextBase::GetMatrix( matrixMode, pMatrix );
  1219. ForceSync();
  1220. if ( ShouldValidateMatrices() )
  1221. {
  1222. VMatrix testMatrix;
  1223. VMatrix transposeMatrix;
  1224. g_pShaderAPI->GetMatrix( matrixMode, (float*)transposeMatrix.m );
  1225. MatrixTranspose( transposeMatrix, testMatrix );
  1226. ValidateMatrices( testMatrix, *pMatrix );
  1227. }
  1228. }
  1229. void CMatRenderContext::GetMatrix( MaterialMatrixMode_t matrixMode, matrix3x4_t *pMatrix )
  1230. {
  1231. if ( !ShouldValidateMatrices() )
  1232. {
  1233. CMatRenderContextBase::GetMatrix( matrixMode, pMatrix );
  1234. }
  1235. else
  1236. {
  1237. VMatrix matrix;
  1238. CMatRenderContext::GetMatrix( matrixMode, &matrix );
  1239. *pMatrix = matrix.As3x4();
  1240. }
  1241. }
  1242. void CMatRenderContext::SyncMatrices()
  1243. {
  1244. if ( !ShouldValidateMatrices() && AllowLazyMatrixSync() )
  1245. {
  1246. for( int i = 0; i < NUM_MATRIX_MODES; i++ )
  1247. {
  1248. MatrixStackItem_t &top = m_MatrixStacks[i].Top();
  1249. if ( top.flags & MSF_DIRTY )
  1250. {
  1251. g_pShaderAPI->MatrixMode( (MaterialMatrixMode_t)i );
  1252. if ( !( top.flags & MSF_IDENTITY ) )
  1253. {
  1254. VMatrix transposeTop;
  1255. MatrixTranspose( top.matrix, transposeTop );
  1256. g_pShaderAPI->LoadMatrix( transposeTop.Base() );
  1257. }
  1258. else
  1259. {
  1260. g_pShaderAPI->LoadIdentity();
  1261. }
  1262. top.flags &= ~MSF_DIRTY;
  1263. }
  1264. }
  1265. }
  1266. }
  1267. void CMatRenderContext::ForceSyncMatrix( MaterialMatrixMode_t mode )
  1268. {
  1269. MatrixStackItem_t &top = m_MatrixStacks[mode].Top();
  1270. if ( top.flags & MSF_DIRTY )
  1271. {
  1272. bool bSetMode = ( m_MatrixMode != mode );
  1273. if ( bSetMode )
  1274. {
  1275. g_pShaderAPI->MatrixMode( (MaterialMatrixMode_t)mode );
  1276. }
  1277. if ( !( top.flags & MSF_IDENTITY ) )
  1278. {
  1279. VMatrix transposeTop;
  1280. MatrixTranspose( top.matrix, transposeTop );
  1281. g_pShaderAPI->LoadMatrix( transposeTop.Base() );
  1282. }
  1283. else
  1284. {
  1285. g_pShaderAPI->LoadIdentity();
  1286. }
  1287. if ( bSetMode )
  1288. {
  1289. g_pShaderAPI->MatrixMode( (MaterialMatrixMode_t)mode );
  1290. }
  1291. top.flags &= ~MSF_DIRTY;
  1292. }
  1293. }
  1294. void CMatRenderContext::SyncMatrix( MaterialMatrixMode_t mode )
  1295. {
  1296. if ( !ShouldValidateMatrices() && AllowLazyMatrixSync() )
  1297. {
  1298. ForceSyncMatrix( mode );
  1299. }
  1300. }
  1301. //-----------------------------------------------------------------------------
  1302. // Swap buffers
  1303. //-----------------------------------------------------------------------------
  1304. void CMatRenderContext::SwapBuffers()
  1305. {
  1306. g_pMorphMgr->AdvanceFrame();
  1307. g_pOcclusionQueryMgr->AdvanceFrame();
  1308. g_pShaderDevice->Present();
  1309. #ifdef _X360
  1310. if ( s_bDirtyDisk )
  1311. {
  1312. SpinPresent();
  1313. }
  1314. #endif
  1315. }
  1316. //-----------------------------------------------------------------------------
  1317. // Clears the render data after we're done with it
  1318. //-----------------------------------------------------------------------------
  1319. void CMatRenderContext::OnRenderDataUnreferenced()
  1320. {
  1321. MarkRenderDataUnused( false );
  1322. }
  1323. //-----------------------------------------------------------------------------
  1324. // Custom clip planes
  1325. //-----------------------------------------------------------------------------
  1326. void CMatRenderContext::PushCustomClipPlane( const float *pPlane )
  1327. {
  1328. PlaneStackElement psePlane;
  1329. memcpy( psePlane.fValues, pPlane, sizeof( float ) * 4 );
  1330. psePlane.bHack_IsHeightClipPlane = false;
  1331. m_CustomClipPlanes.AddToTail( psePlane ); //we're doing this as a UtlVector so height clip planes never change their cached index
  1332. ApplyCustomClipPlanes();
  1333. }
  1334. void CMatRenderContext::PopCustomClipPlane( void )
  1335. {
  1336. Assert( m_CustomClipPlanes.Count() );
  1337. //remove the endmost non-height plane found
  1338. int i;
  1339. for( i = m_CustomClipPlanes.Count(); --i >= 0; )
  1340. {
  1341. if( m_CustomClipPlanes[i].bHack_IsHeightClipPlane == false )
  1342. {
  1343. m_CustomClipPlanes.Remove(i);
  1344. break;
  1345. }
  1346. }
  1347. Assert( i != -1 ); //only the height clip plane was found, which means this pop had no associated push
  1348. ApplyCustomClipPlanes();
  1349. }
  1350. void CMatRenderContext::ApplyCustomClipPlanes( void )
  1351. {
  1352. int iMaxClipPlanes = HardwareConfig()->MaxUserClipPlanes();
  1353. int iCustomPlanes;
  1354. if( m_bEnableClipping )
  1355. iCustomPlanes = m_CustomClipPlanes.Count();
  1356. else
  1357. iCustomPlanes = 0;
  1358. float fFakePlane[4];
  1359. unsigned int iFakePlaneVal = 0xFFFFFFFF;
  1360. fFakePlane[0] = fFakePlane[1] = fFakePlane[2] = fFakePlane[3] = *((float *)&iFakePlaneVal);
  1361. SyncMatrices();
  1362. if( iMaxClipPlanes >= 1 && !HardwareConfig()->UseFastClipping() )
  1363. {
  1364. //yay, we get to be the cool clipping club
  1365. if( iMaxClipPlanes >= iCustomPlanes )
  1366. {
  1367. int i;
  1368. for( i = 0; i < iCustomPlanes; ++i )
  1369. {
  1370. g_pShaderAPI->SetClipPlane( i, m_CustomClipPlanes[i].fValues );
  1371. g_pShaderAPI->EnableClipPlane( i, true );
  1372. }
  1373. for( ; i < iMaxClipPlanes; ++i ) //disable unused planes
  1374. {
  1375. g_pShaderAPI->EnableClipPlane( i, false );
  1376. g_pShaderAPI->SetClipPlane( i, fFakePlane );
  1377. }
  1378. }
  1379. else
  1380. {
  1381. int iCustomPlaneOffset = iCustomPlanes - iMaxClipPlanes;
  1382. //can't enable them all
  1383. for( int i = iCustomPlaneOffset; i < iCustomPlanes; ++i )
  1384. {
  1385. g_pShaderAPI->SetClipPlane( i % iMaxClipPlanes, m_CustomClipPlanes[i].fValues );
  1386. g_pShaderAPI->EnableClipPlane( i % iMaxClipPlanes, true );
  1387. }
  1388. }
  1389. }
  1390. else
  1391. {
  1392. //hmm, at most we can make 1 clip plane work
  1393. if( iCustomPlanes == 0 )
  1394. {
  1395. //no planes at all
  1396. g_pShaderAPI->EnableFastClip( false );
  1397. g_pShaderAPI->SetFastClipPlane( fFakePlane );
  1398. }
  1399. else
  1400. {
  1401. //we have to wire the topmost plane into the fast clipping scheme
  1402. g_pShaderAPI->EnableFastClip( true );
  1403. g_pShaderAPI->SetFastClipPlane( m_CustomClipPlanes[iCustomPlanes - 1].fValues );
  1404. }
  1405. }
  1406. }
  1407. //-----------------------------------------------------------------------------
  1408. // Creates/destroys morph data associated w/ a particular material
  1409. //-----------------------------------------------------------------------------
  1410. IMorph *CMatRenderContext::CreateMorph( MorphFormat_t format, const char *pDebugName )
  1411. {
  1412. Assert( format != 0 );
  1413. IMorphInternal *pMorph = g_pMorphMgr->CreateMorph( );
  1414. pMorph->Init( format, pDebugName );
  1415. return pMorph;
  1416. }
  1417. void CMatRenderContext::DestroyMorph( IMorph *pMorph )
  1418. {
  1419. g_pMorphMgr->DestroyMorph( static_cast<IMorphInternal*>(pMorph) );
  1420. }
  1421. void CMatRenderContext::BindMorph( IMorph *pMorph )
  1422. {
  1423. IMorphInternal *pMorphInternal = static_cast<IMorphInternal*>(pMorph);
  1424. if ( m_pBoundMorph != pMorphInternal )
  1425. {
  1426. g_pShaderAPI->FlushBufferedPrimitives();
  1427. m_pBoundMorph = pMorphInternal;
  1428. bool bEnableHWMorph = false;
  1429. if ( pMorphInternal == MATERIAL_MORPH_DECAL )
  1430. {
  1431. bEnableHWMorph = true;
  1432. }
  1433. else if ( pMorphInternal )
  1434. {
  1435. bEnableHWMorph = true;
  1436. pMorphInternal->Bind( m_pMorphRenderContext );
  1437. }
  1438. g_pShaderAPI->EnableHWMorphing( bEnableHWMorph );
  1439. }
  1440. }
  1441. IMesh* CMatRenderContext::GetDynamicMesh( bool buffered, IMesh* pVertexOverride, IMesh* pIndexOverride, IMaterial *pAutoBind )
  1442. {
  1443. VPROF_ASSERT_ACCOUNTED( "CMatRenderContext::GetDynamicMesh" );
  1444. if( pAutoBind )
  1445. {
  1446. Bind( pAutoBind, NULL );
  1447. }
  1448. if ( pVertexOverride )
  1449. {
  1450. if ( CompressionType( pVertexOverride->GetVertexFormat() ) != VERTEX_COMPRESSION_NONE )
  1451. {
  1452. // UNDONE: support compressed dynamic meshes if needed (pro: less VB memory, con: time spent compressing)
  1453. DebuggerBreak();
  1454. return NULL;
  1455. }
  1456. }
  1457. // For anything more than 1 bone, imply the last weight from the 1 - the sum of the others.
  1458. int nCurrentBoneCount = GetCurrentNumBones();
  1459. Assert( nCurrentBoneCount <= 4 );
  1460. if ( nCurrentBoneCount > 1 )
  1461. {
  1462. --nCurrentBoneCount;
  1463. }
  1464. return g_pShaderAPI->GetDynamicMesh( GetCurrentMaterialInternal(), nCurrentBoneCount,
  1465. buffered, pVertexOverride, pIndexOverride);
  1466. }
  1467. IMesh* CMatRenderContext::GetDynamicMeshEx( VertexFormat_t vertexFormat, bool bBuffered, IMesh* pVertexOverride, IMesh* pIndexOverride, IMaterial *pAutoBind )
  1468. {
  1469. VPROF_ASSERT_ACCOUNTED( "CMatRenderContext::GetDynamicMesh" );
  1470. if( pAutoBind )
  1471. {
  1472. Bind( pAutoBind, NULL );
  1473. }
  1474. if ( pVertexOverride )
  1475. {
  1476. if ( CompressionType( pVertexOverride->GetVertexFormat() ) != VERTEX_COMPRESSION_NONE )
  1477. {
  1478. // UNDONE: support compressed dynamic meshes if needed (pro: less VB memory, con: time spent compressing)
  1479. DebuggerBreak();
  1480. return NULL;
  1481. }
  1482. }
  1483. // For anything more than 1 bone, imply the last weight from the 1 - the sum of the others.
  1484. // FIXME: this seems wrong - in common_vs_fxc.h, we only infer the last weight if we have 3 (not 2)
  1485. int nCurrentBoneCount = GetCurrentNumBones();
  1486. Assert( nCurrentBoneCount <= 4 );
  1487. if ( nCurrentBoneCount > 1 )
  1488. {
  1489. --nCurrentBoneCount;
  1490. }
  1491. return g_pShaderAPI->GetDynamicMeshEx( GetCurrentMaterialInternal(), vertexFormat, nCurrentBoneCount,
  1492. bBuffered, pVertexOverride, pIndexOverride );
  1493. }
  1494. //-----------------------------------------------------------------------------
  1495. // Deals with depth range
  1496. //-----------------------------------------------------------------------------
  1497. void CMatRenderContext::DepthRange( float zNear, float zFar )
  1498. {
  1499. m_Viewport.m_flMinZ = zNear;
  1500. m_Viewport.m_flMaxZ = zFar;
  1501. g_pShaderAPI->SetViewports( 1, &m_Viewport );
  1502. }
  1503. //-----------------------------------------------------------------------------
  1504. // Private utility function to actually commit the top of the RT/Viewport stack
  1505. // to the device. Only called by the push and pop routines above.
  1506. //-----------------------------------------------------------------------------
  1507. void CMatRenderContext::CommitRenderTargetAndViewport( void )
  1508. {
  1509. Assert( m_RenderTargetStack.Count() > 0 );
  1510. const RenderTargetStackElement_t &element = m_RenderTargetStack.Top( );
  1511. for( int rt=0; rt<NELEMS(element.m_pRenderTargets); rt++ )
  1512. {
  1513. // If we're dealing with the back buffer
  1514. if ( element.m_pRenderTargets[rt] == NULL )
  1515. {
  1516. g_pShaderAPI->SetRenderTargetEx(rt); // No texture parameter here indicates back buffer
  1517. if ( IsPC() )
  1518. {
  1519. Assert( ImageLoader::SizeInBytes( g_pShaderDevice->GetBackBufferFormat() ) <= 4 );
  1520. g_pShaderAPI->EnableLinearColorSpaceFrameBuffer( false );
  1521. }
  1522. if (rt == 0) // the first rt sets the viewport
  1523. {
  1524. // If either dimension is negative, set to full bounds of back buffer
  1525. if ( (element.m_nViewW < 0) || (element.m_nViewH < 0) )
  1526. {
  1527. m_Viewport.m_nTopLeftX = 0;
  1528. m_Viewport.m_nTopLeftY = 0;
  1529. g_pShaderAPI->GetBackBufferDimensions( m_Viewport.m_nWidth, m_Viewport.m_nHeight );
  1530. g_pShaderAPI->SetViewports( 1, &m_Viewport );
  1531. }
  1532. else // use the bounds in the element
  1533. {
  1534. m_Viewport.m_nTopLeftX = element.m_nViewX;
  1535. m_Viewport.m_nTopLeftY = element.m_nViewY;
  1536. m_Viewport.m_nWidth = element.m_nViewW;
  1537. m_Viewport.m_nHeight = element.m_nViewH;
  1538. g_pShaderAPI->SetViewports( 1, &m_Viewport );
  1539. }
  1540. }
  1541. }
  1542. else // We're dealing with a texture
  1543. {
  1544. ITextureInternal *pTexInt = static_cast<ITextureInternal*>(element.m_pRenderTargets[rt]);
  1545. pTexInt->SetRenderTarget( rt, element.m_pDepthTexture );
  1546. if (rt == 0)
  1547. {
  1548. if ( IsPC() )
  1549. {
  1550. if( element.m_pRenderTargets[rt]->GetImageFormat() == IMAGE_FORMAT_RGBA16161616F )
  1551. {
  1552. g_pShaderAPI->EnableLinearColorSpaceFrameBuffer( true );
  1553. }
  1554. else
  1555. {
  1556. g_pShaderAPI->EnableLinearColorSpaceFrameBuffer( false );
  1557. }
  1558. }
  1559. // If either dimension is negative, set to full bounds of target
  1560. if ( (element.m_nViewW < 0) || (element.m_nViewH < 0) )
  1561. {
  1562. m_Viewport.m_nTopLeftX = 0;
  1563. m_Viewport.m_nTopLeftY = 0;
  1564. m_Viewport.m_nWidth = element.m_pRenderTargets[rt]->GetActualWidth();
  1565. m_Viewport.m_nHeight = element.m_pRenderTargets[rt]->GetActualHeight();
  1566. g_pShaderAPI->SetViewports( 1, &m_Viewport );
  1567. }
  1568. else // use the bounds passed in
  1569. {
  1570. m_Viewport.m_nTopLeftX = element.m_nViewX;
  1571. m_Viewport.m_nTopLeftY = element.m_nViewY;
  1572. m_Viewport.m_nWidth = element.m_nViewW;
  1573. m_Viewport.m_nHeight = element.m_nViewH;
  1574. g_pShaderAPI->SetViewports( 1, &m_Viewport );
  1575. }
  1576. }
  1577. }
  1578. }
  1579. }
  1580. void CMatRenderContext::SetFrameBufferCopyTexture( ITexture *pTexture, int textureIndex )
  1581. {
  1582. if( textureIndex < 0 || textureIndex > MAX_FB_TEXTURES )
  1583. {
  1584. Assert( 0 );
  1585. return;
  1586. }
  1587. if( m_pCurrentFrameBufferCopyTexture[textureIndex] != pTexture )
  1588. {
  1589. g_pShaderAPI->FlushBufferedPrimitives();
  1590. }
  1591. // FIXME: Do I need to increment/decrement ref counts here, or assume that the app is going to do it?
  1592. m_pCurrentFrameBufferCopyTexture[textureIndex] = pTexture;
  1593. }
  1594. void CMatRenderContext::BindLocalCubemap( ITexture *pTexture )
  1595. {
  1596. ITexture *pPreviousTexture = m_pLocalCubemapTexture;
  1597. CMatRenderContextBase::BindLocalCubemap( pTexture );
  1598. if( m_pLocalCubemapTexture != pPreviousTexture )
  1599. {
  1600. g_pShaderAPI->FlushBufferedPrimitives();
  1601. }
  1602. }
  1603. void CMatRenderContext::SetNonInteractivePacifierTexture( ITexture *pTexture, float flNormalizedX, float flNormalizedY, float flNormalizedSize )
  1604. {
  1605. m_pNonInteractivePacifier.Init( pTexture );
  1606. m_flNormalizedX = flNormalizedX;
  1607. m_flNormalizedY = flNormalizedY;
  1608. m_flNormalizedSize = flNormalizedSize;
  1609. }
  1610. void CMatRenderContext::SetNonInteractiveTempFullscreenBuffer( ITexture *pTexture, MaterialNonInteractiveMode_t mode )
  1611. {
  1612. if ( mode != MATERIAL_NON_INTERACTIVE_MODE_NONE )
  1613. {
  1614. m_pNonInteractiveTempFullscreenBuffer[mode].Init( pTexture );
  1615. }
  1616. }
  1617. void CMatRenderContext::RefreshFrontBufferNonInteractive()
  1618. {
  1619. g_pShaderDevice->RefreshFrontBufferNonInteractive();
  1620. #ifdef _X360
  1621. if ( s_bDirtyDisk )
  1622. {
  1623. if ( m_NonInteractiveMode == MATERIAL_NON_INTERACTIVE_MODE_NONE )
  1624. {
  1625. SpinPresent();
  1626. }
  1627. else
  1628. {
  1629. while ( true )
  1630. {
  1631. g_pShaderDevice->RefreshFrontBufferNonInteractive();
  1632. }
  1633. }
  1634. }
  1635. #endif
  1636. }
  1637. void CMatRenderContext::EnableNonInteractiveMode( MaterialNonInteractiveMode_t mode )
  1638. {
  1639. m_NonInteractiveMode = mode;
  1640. if ( mode == MATERIAL_NON_INTERACTIVE_MODE_NONE )
  1641. {
  1642. g_pShaderDevice->EnableNonInteractiveMode( mode );
  1643. }
  1644. else
  1645. {
  1646. ShaderNonInteractiveInfo_t info;
  1647. info.m_flNormalizedX = m_flNormalizedX;
  1648. info.m_flNormalizedY = m_flNormalizedY;
  1649. info.m_flNormalizedSize = m_flNormalizedSize;
  1650. ITextureInternal *pTexInternal = static_cast<ITextureInternal*>( (ITexture*)m_pNonInteractiveTempFullscreenBuffer[mode] );
  1651. info.m_hTempFullscreenTexture = pTexInternal ?
  1652. pTexInternal->GetTextureHandle(0) : INVALID_SHADERAPI_TEXTURE_HANDLE;
  1653. ITextureInternal *pTexPacifierInternal = static_cast<ITextureInternal*>( (ITexture*)m_pNonInteractivePacifier );
  1654. info.m_nPacifierCount = pTexPacifierInternal ? pTexPacifierInternal->GetNumAnimationFrames() : 0;
  1655. for ( int i = 0; i < info.m_nPacifierCount; ++i )
  1656. {
  1657. info.m_pPacifierTextures[i] = pTexPacifierInternal->GetTextureHandle( i );
  1658. }
  1659. g_pShaderDevice->EnableNonInteractiveMode( mode, &info );
  1660. }
  1661. }
  1662. void CMatRenderContext::SetRenderTargetEx( int nRenderTargetID, ITexture *pNewTarget )
  1663. {
  1664. // Verify valid top of RT stack
  1665. Assert ( m_RenderTargetStack.Count() > 0 );
  1666. // Grab the old target
  1667. ITexture *pOldTarget = m_RenderTargetStack.Top().m_pRenderTargets[nRenderTargetID];
  1668. CMatRenderContextBase::SetRenderTargetEx( nRenderTargetID, pNewTarget );
  1669. // If we're actually changing render targets
  1670. if( pNewTarget != pOldTarget )
  1671. {
  1672. // If we're going to render to the back buffer
  1673. if ( pNewTarget == NULL )
  1674. {
  1675. if ( nRenderTargetID == 0) // reset viewport on set of rt 0
  1676. {
  1677. m_Viewport.m_nTopLeftX = 0;
  1678. m_Viewport.m_nTopLeftY = 0;
  1679. g_pShaderAPI->GetBackBufferDimensions( m_Viewport.m_nWidth, m_Viewport.m_nHeight );
  1680. g_pShaderAPI->SetViewports( 1, &m_Viewport );
  1681. }
  1682. g_pShaderAPI->SetRenderTargetEx( nRenderTargetID ); // No parameter here indicates back buffer
  1683. }
  1684. else
  1685. {
  1686. // If we're going to render to a texture
  1687. // Make sure the texture is a render target...
  1688. bool reset = true;
  1689. if (nRenderTargetID==0)
  1690. {
  1691. // reset vp on change of rt#0
  1692. m_Viewport.m_nTopLeftX = 0;
  1693. m_Viewport.m_nTopLeftY = 0;
  1694. m_Viewport.m_nWidth = pNewTarget->GetActualWidth();
  1695. m_Viewport.m_nHeight = pNewTarget->GetActualHeight();
  1696. g_pShaderAPI->SetViewports( 1, &m_Viewport );
  1697. }
  1698. ITextureInternal *pTexInt = static_cast<ITextureInternal*>(pNewTarget);
  1699. if ( pTexInt )
  1700. {
  1701. reset = !pTexInt->SetRenderTarget( nRenderTargetID );
  1702. if ( reset )
  1703. {
  1704. g_pShaderAPI->SetRenderTargetEx( nRenderTargetID );
  1705. }
  1706. }
  1707. if( pNewTarget && pNewTarget->GetImageFormat() == IMAGE_FORMAT_RGBA16161616F )
  1708. {
  1709. g_pShaderAPI->EnableLinearColorSpaceFrameBuffer( true );
  1710. }
  1711. else
  1712. {
  1713. g_pShaderAPI->EnableLinearColorSpaceFrameBuffer( false );
  1714. }
  1715. }
  1716. }
  1717. CommitRenderTargetAndViewport();
  1718. }
  1719. void CMatRenderContext::GetRenderTargetDimensions( int &width, int &height ) const
  1720. {
  1721. // Target at top of stack
  1722. ITexture *pTOS = m_RenderTargetStack.Top().m_pRenderTargets[0];
  1723. // If top of stack isn't the back buffer, get dimensions from the texture
  1724. if ( pTOS != NULL )
  1725. {
  1726. width = pTOS->GetActualWidth();
  1727. height = pTOS->GetActualHeight();
  1728. }
  1729. else // otherwise, get them from the shader API
  1730. {
  1731. g_pShaderAPI->GetBackBufferDimensions( width, height );
  1732. }
  1733. }
  1734. //-----------------------------------------------------------------------------
  1735. // What are the lightmap dimensions?
  1736. //-----------------------------------------------------------------------------
  1737. void CMatRenderContext::GetLightmapDimensions( int *w, int *h )
  1738. {
  1739. *w = GetMaterialSystem()->GetLightmapWidth( GetLightmapPage() );
  1740. *h = GetMaterialSystem()->GetLightmapHeight( GetLightmapPage() );
  1741. }
  1742. void CMatRenderContext::DrawScreenSpaceQuad( IMaterial* pMaterial )
  1743. {
  1744. // Despite saying we render a full screen quad, this actually renders a single triangle
  1745. // that covers the whole screen.
  1746. int w, h;
  1747. GetRenderTargetDimensions( w, h );
  1748. if ( ( w == 0 ) || ( h == 0 ) )
  1749. return;
  1750. // DX9 disagrees about (0, 0) in a render target and (0, 0) in the texture.
  1751. // Fix that here by doing a half-pixel offset for the pixel.
  1752. // Because we are working in clip space which is 2 units across, the adjustment factor is 1.
  1753. float flOffsetW = 1.0f / w;
  1754. float flOffsetH = 1.0f / h;
  1755. Bind( pMaterial );
  1756. IMesh* pMesh = GetDynamicMesh( true );
  1757. CMeshBuilder meshBuilder;;
  1758. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 1 );
  1759. enum { TL, BL, TR, COORDS_COUNT };
  1760. struct CoordSSQ_t
  1761. {
  1762. float x, y;
  1763. float u, v;
  1764. };
  1765. CoordSSQ_t coords[] = {
  1766. { -1.0f - 1.0f * flOffsetW, 1.0f + 1.0f * flOffsetH, 0.0f, 0.0f }, // TL
  1767. { -1.0f - 1.0f * flOffsetW, -3.0f + 1.0f * flOffsetH, 0.0f, 2.0f }, // BL
  1768. { 3.0f - 1.0f * flOffsetW, 1.0f + 1.0f * flOffsetH, 2.0f, 0.0f }, // TR
  1769. };
  1770. static_assert( ARRAYSIZE( coords ) == COORDS_COUNT, "Unexpected number of coords in triangle, should match enum." );
  1771. MatrixMode( MATERIAL_VIEW );
  1772. PushMatrix();
  1773. LoadIdentity();
  1774. MatrixMode( MATERIAL_PROJECTION );
  1775. PushMatrix();
  1776. LoadIdentity();
  1777. for ( int i = 0; i < COORDS_COUNT; ++i )
  1778. {
  1779. meshBuilder.Position3f( coords[ i ].x, coords[ i ].y, 0.0f );
  1780. meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  1781. meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  1782. meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  1783. meshBuilder.TexCoord2f( 0, coords[ i ].u, coords[ i ].v );
  1784. meshBuilder.AdvanceVertex();
  1785. }
  1786. meshBuilder.End();
  1787. pMesh->Draw();
  1788. MatrixMode( MATERIAL_VIEW );
  1789. PopMatrix();
  1790. MatrixMode( MATERIAL_PROJECTION );
  1791. PopMatrix();
  1792. }
  1793. void CMatRenderContext::DrawScreenSpaceRectangle(
  1794. IMaterial *pMaterial,
  1795. int destx, int desty,
  1796. int width, int height,
  1797. float src_texture_x0, float src_texture_y0, // which texel you want to appear at
  1798. // destx/y
  1799. float src_texture_x1, float src_texture_y1, // which texel you want to appear at
  1800. // destx+width-1, desty+height-1
  1801. int src_texture_width, int src_texture_height, // needed for fixup
  1802. void *pClientRenderable,
  1803. int nXDice, int nYDice ) // Amount to tessellate the quad
  1804. {
  1805. pMaterial = ((IMaterialInternal *)pMaterial)->GetRealTimeVersion();
  1806. ::DrawScreenSpaceRectangle( pMaterial, destx, desty, width, height,
  1807. src_texture_x0, src_texture_y0, src_texture_x1, src_texture_y1,
  1808. src_texture_width, src_texture_height, pClientRenderable, nXDice, nYDice );
  1809. return;
  1810. }
  1811. static int CompareVertexFormats( VertexFormat_t Fmt1, VertexFormat_t Fmt2 )
  1812. {
  1813. if ( Fmt1 != Fmt2 )
  1814. {
  1815. if ( Fmt1 > Fmt2 )
  1816. return 1;
  1817. else
  1818. return -1;
  1819. }
  1820. else
  1821. return 0;
  1822. }
  1823. int CMatRenderContext::CompareMaterialCombos( IMaterial *pMaterial1, IMaterial *pMaterial2, int lightMapID1, int lightMapID2 )
  1824. {
  1825. pMaterial1 = ((IMaterialInternal *)pMaterial1)->GetRealTimeVersion(); //always work with the real time version of materials internally.
  1826. pMaterial2 = ((IMaterialInternal *)pMaterial2)->GetRealTimeVersion(); //always work with the real time version of materials internally.
  1827. IMaterialInternal *pMat1 = (IMaterialInternal *)pMaterial1;
  1828. IMaterialInternal *pMat2 = (IMaterialInternal *)pMaterial2;
  1829. ShaderRenderState_t *pState1 = pMat1->GetRenderState();
  1830. ShaderRenderState_t *pState2 = pMat2->GetRenderState();
  1831. int dPass = pState2->m_pSnapshots->m_nPassCount - pState1->m_pSnapshots->m_nPassCount;
  1832. if ( dPass )
  1833. return dPass;
  1834. if ( pState1->m_pSnapshots->m_nPassCount > 1 )
  1835. {
  1836. int dFormat = CompareVertexFormats( pMat1->GetVertexFormat(), pMat2->GetVertexFormat() );
  1837. if ( dFormat )
  1838. return dFormat;
  1839. }
  1840. for ( int i = 0; i < pState1->m_pSnapshots->m_nPassCount; i++ )
  1841. {
  1842. // UNDONE: Compare snapshots in the shaderapi?
  1843. int dSnapshot = pState1->m_pSnapshots->m_Snapshot[i] - pState2->m_pSnapshots->m_Snapshot[i];
  1844. if ( dSnapshot )
  1845. {
  1846. dSnapshot = g_pShaderAPI->CompareSnapshots( pState1->m_pSnapshots->m_Snapshot[i], pState2->m_pSnapshots->m_Snapshot[i] );
  1847. if ( dSnapshot )
  1848. return dSnapshot;
  1849. }
  1850. }
  1851. int dFormat = CompareVertexFormats( pMat1->GetVertexFormat(), pMat2->GetVertexFormat() );
  1852. if ( dFormat )
  1853. return dFormat;
  1854. IMaterialVar **pParams1 = pMat1->GetShaderParams();
  1855. IMaterialVar **pParams2 = pMat2->GetShaderParams();
  1856. int nParams1 = pMat1->ShaderParamCount();
  1857. int nParams2 = pMat2->ShaderParamCount();
  1858. int nBaseTexParamType1 = pParams1 && nParams1 > BASETEXTURE ? pParams1[BASETEXTURE]->GetType() : -1;
  1859. int nBaseTexParamType2 = pParams2 && nParams2 > BASETEXTURE ? pParams2[BASETEXTURE]->GetType() : -1;
  1860. if( nBaseTexParamType1 == MATERIAL_VAR_TYPE_TEXTURE || nBaseTexParamType2 == MATERIAL_VAR_TYPE_TEXTURE )
  1861. {
  1862. if( nBaseTexParamType1 != nBaseTexParamType2 )
  1863. {
  1864. return nBaseTexParamType2 - nBaseTexParamType1;
  1865. }
  1866. int dBaseTexture = Q_stricmp( pParams1[BASETEXTURE]->GetTextureValue()->GetName(), pParams2[BASETEXTURE]->GetTextureValue()->GetName() );
  1867. if ( dBaseTexture )
  1868. return dBaseTexture;
  1869. }
  1870. int dLightmap = lightMapID1 - lightMapID2;
  1871. if ( dLightmap )
  1872. return dLightmap;
  1873. return (int)pMat1 - (int)pMat2;
  1874. }
  1875. void CMatRenderContext::Bind( IMaterial *iMaterial, void *proxyData )
  1876. {
  1877. if ( !iMaterial )
  1878. {
  1879. if ( !g_pErrorMaterial )
  1880. return;
  1881. Warning( "Programming error: CMatRenderContext::Bind: NULL material\n" );
  1882. iMaterial = g_pErrorMaterial;
  1883. }
  1884. else
  1885. {
  1886. iMaterial = iMaterial->CheckProxyReplacement( proxyData );
  1887. }
  1888. IMaterialInternal *material = static_cast<IMaterialInternal *>( iMaterial );
  1889. material = material->GetRealTimeVersion(); //always work with the real time versions of materials internally
  1890. if ( material->GetReferenceCount() <= 0 )
  1891. {
  1892. static ConVarRef matTextureListConVar( "mat_texture_list" );
  1893. static ConVarRef matShowWaterTextureConVar( "mat_showwatertextures" );
  1894. if ( ( !matTextureListConVar.IsValid() || !matTextureListConVar.GetBool() ) &&
  1895. ( !matShowWaterTextureConVar.IsValid() || !matShowWaterTextureConVar.GetBool() ))
  1896. {
  1897. Warning( "Material %s has bad reference count %d when being bound\n", material->GetName(), material->GetReferenceCount() );
  1898. // The usual solution for this for global materials that really don't need refcounting is to do material->AddRef();
  1899. Assert( 0 );
  1900. iMaterial = g_pErrorMaterial;
  1901. }
  1902. }
  1903. if (g_config.bDrawFlat && !material->NoDebugOverride())
  1904. {
  1905. material = static_cast<IMaterialInternal *>( GetDrawFlatMaterial() );
  1906. }
  1907. CMatRenderContextBase::Bind( iMaterial, proxyData );
  1908. // We've always gotta call the bind proxy
  1909. SyncMatrices();
  1910. if ( GetMaterialSystem()->GetThreadMode() == MATERIAL_SINGLE_THREADED )
  1911. {
  1912. GetCurrentMaterialInternal()->CallBindProxy( proxyData );
  1913. }
  1914. g_pShaderAPI->Bind( GetCurrentMaterialInternal() );
  1915. }
  1916. void CMatRenderContext::CopyRenderTargetToTextureEx( ITexture *pTexture, int nRenderTargetID, Rect_t *pSrcRect, Rect_t *pDstRect )
  1917. {
  1918. if ( !pTexture )
  1919. {
  1920. Assert( 0 );
  1921. return;
  1922. }
  1923. GetMaterialSystem()->Flush( false );
  1924. ITextureInternal *pTextureInternal = (ITextureInternal *)pTexture;
  1925. if ( IsPC() || !IsX360() )
  1926. {
  1927. pTextureInternal->CopyFrameBufferToMe( nRenderTargetID, pSrcRect, pDstRect );
  1928. }
  1929. else
  1930. {
  1931. // X360 only does 1:1 resolves. So we can do full resolves to textures of size
  1932. // equal or greater than the viewport trivially. Downsizing is nasty.
  1933. Rect_t srcRect;
  1934. if ( !pSrcRect )
  1935. {
  1936. // build out source rect
  1937. pSrcRect = &srcRect;
  1938. int x, y, w, h;
  1939. GetViewport( x, y, w, h );
  1940. pSrcRect->x = 0;
  1941. pSrcRect->y = 0;
  1942. pSrcRect->width = w;
  1943. pSrcRect->height = h;
  1944. }
  1945. Rect_t dstRect;
  1946. if ( !pDstRect )
  1947. {
  1948. // build out target rect
  1949. pDstRect = &dstRect;
  1950. pDstRect->x = 0;
  1951. pDstRect->y = 0;
  1952. pDstRect->width = pTexture->GetActualWidth();
  1953. pDstRect->height = pTexture->GetActualHeight();
  1954. }
  1955. if ( pSrcRect->width == pDstRect->width && pSrcRect->height == pDstRect->height )
  1956. {
  1957. // 1:1 mapping, no stretching needed, use direct path
  1958. pTextureInternal->CopyFrameBufferToMe( nRenderTargetID, pSrcRect, pDstRect );
  1959. return;
  1960. }
  1961. if( (pDstRect->x == 0) && (pDstRect->y == 0) &&
  1962. (pDstRect->width == pTexture->GetActualWidth()) && (pDstRect->height == pTexture->GetActualHeight()) &&
  1963. (pDstRect->width >= pSrcRect->width) && (pDstRect->height >= pSrcRect->height) )
  1964. {
  1965. // Resolve takes up the whole texture, and the texture is large enough to hold the resolve.
  1966. // This is turned into a 1:1 resolve within shaderapi by making D3D think the texture is smaller from now on. (Until it resolves from a bigger source)
  1967. pTextureInternal->CopyFrameBufferToMe( nRenderTargetID, pSrcRect, pDstRect );
  1968. return;
  1969. }
  1970. // currently assuming disparate copies are only for FB blits
  1971. // ensure active render target is actually the back buffer
  1972. Assert( m_RenderTargetStack.Top().m_pRenderTargets[0] == NULL );
  1973. // nasty sequence:
  1974. // resolve FB surface to matching clone DDR texture
  1975. // gpu draw from clone DDR FB texture to disparate RT target surface
  1976. // resolve to its matching DDR clone texture
  1977. ITextureInternal *pFullFrameFB = (ITextureInternal*)GetMaterialSystem()->FindTexture( "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET );
  1978. pFullFrameFB->CopyFrameBufferToMe( nRenderTargetID, NULL, NULL );
  1979. // target texture must be a render target
  1980. PushRenderTargetAndViewport( pTexture );
  1981. // blit FB source to render target
  1982. DrawScreenSpaceRectangle(
  1983. GetMaterialSystem()->GetRenderTargetBlitMaterial(),
  1984. pDstRect->x, pDstRect->y, pDstRect->width, pDstRect->height,
  1985. pSrcRect->x, pSrcRect->y, pSrcRect->x+pSrcRect->width-1, pSrcRect->y+pSrcRect->height-1,
  1986. pFullFrameFB->GetActualWidth(), pFullFrameFB->GetActualHeight() );
  1987. // resolve render target to texture
  1988. ((ITextureInternal *)pTexture)->CopyFrameBufferToMe( 0, NULL, NULL );
  1989. // restore render target and viewport
  1990. PopRenderTargetAndViewport();
  1991. }
  1992. }
  1993. void CMatRenderContext::CopyRenderTargetToTexture( ITexture *pTexture )
  1994. {
  1995. CopyRenderTargetToTextureEx( pTexture, NULL, NULL );
  1996. }
  1997. void CMatRenderContext::CopyTextureToRenderTargetEx( int nRenderTargetID, ITexture *pTexture, Rect_t *pSrcRect, Rect_t *pDstRect )
  1998. {
  1999. if ( !pTexture )
  2000. {
  2001. Assert( 0 );
  2002. return;
  2003. }
  2004. GetMaterialSystem()->Flush( false );
  2005. ITextureInternal *pTextureInternal = (ITextureInternal *)pTexture;
  2006. if ( IsPC() || !IsX360() )
  2007. {
  2008. pTextureInternal->CopyMeToFrameBuffer( nRenderTargetID, pSrcRect, pDstRect );
  2009. }
  2010. else
  2011. {
  2012. Assert( 0 );
  2013. }
  2014. }
  2015. void CMatRenderContext::ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil )
  2016. {
  2017. int width, height;
  2018. GetRenderTargetDimensions( width, height );
  2019. g_pShaderAPI->ClearBuffers( bClearColor, bClearDepth, bClearStencil, width, height );
  2020. }
  2021. void CMatRenderContext::DrawClearBufferQuad( unsigned char r, unsigned char g, unsigned char b, unsigned char a, bool bClearColor, bool bClearAlpha, bool bClearDepth )
  2022. {
  2023. IMaterialInternal *pClearMaterial = GetBufferClearObeyStencil( bClearColor + ( bClearAlpha << 1 ) + ( bClearDepth << 2 ) );
  2024. Bind( pClearMaterial );
  2025. IMesh* pMesh = GetDynamicMesh( true );
  2026. MatrixMode( MATERIAL_MODEL );
  2027. PushMatrix();
  2028. LoadIdentity();
  2029. MatrixMode( MATERIAL_VIEW );
  2030. PushMatrix();
  2031. LoadIdentity();
  2032. MatrixMode( MATERIAL_PROJECTION );
  2033. PushMatrix();
  2034. LoadIdentity();
  2035. float flDepth = GetMaterialSystem()->GetConfig().bReverseDepth ? 0.0f : 1.0f;
  2036. CMeshBuilder meshBuilder;
  2037. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  2038. //1.1 instead of 1.0 to fix small borders around the edges in full screen with anti-aliasing enabled
  2039. meshBuilder.Position3f( -1.1f, -1.1f, flDepth );
  2040. meshBuilder.Color4ub( r, g, b, a );
  2041. meshBuilder.AdvanceVertex();
  2042. meshBuilder.Position3f( -1.1f, 1.1f, flDepth );
  2043. meshBuilder.Color4ub( r, g, b, a );
  2044. meshBuilder.AdvanceVertex();
  2045. meshBuilder.Position3f( 1.1f, 1.1f, flDepth );
  2046. meshBuilder.Color4ub( r, g, b, a );
  2047. meshBuilder.AdvanceVertex();
  2048. meshBuilder.Position3f( 1.1f, -1.1f, flDepth );
  2049. meshBuilder.Color4ub( r, g, b, a );
  2050. meshBuilder.AdvanceVertex();
  2051. meshBuilder.End();
  2052. pMesh->Draw();
  2053. MatrixMode( MATERIAL_MODEL );
  2054. PopMatrix();
  2055. MatrixMode( MATERIAL_VIEW );
  2056. PopMatrix();
  2057. MatrixMode( MATERIAL_PROJECTION );
  2058. PopMatrix();
  2059. }
  2060. //-----------------------------------------------------------------------------
  2061. // Should really be called SetViewport
  2062. //-----------------------------------------------------------------------------
  2063. void CMatRenderContext::Viewport( int x, int y, int width, int height )
  2064. {
  2065. CMatRenderContextBase::Viewport( x, y, width, height );
  2066. // If either dimension is negative, set to full bounds of current target
  2067. if ( (width < 0) || (height < 0) )
  2068. {
  2069. ITexture *pTarget = m_RenderTargetStack.Top().m_pRenderTargets[0];
  2070. // If target is the back buffer
  2071. if ( pTarget == NULL )
  2072. {
  2073. m_Viewport.m_nTopLeftX = 0;
  2074. m_Viewport.m_nTopLeftY = 0;
  2075. g_pShaderAPI->GetBackBufferDimensions( m_Viewport.m_nWidth, m_Viewport.m_nHeight );
  2076. g_pShaderAPI->SetViewports( 1, &m_Viewport );
  2077. }
  2078. else // target is a texture
  2079. {
  2080. m_Viewport.m_nTopLeftX = 0;
  2081. m_Viewport.m_nTopLeftY = 0;
  2082. m_Viewport.m_nWidth = pTarget->GetActualWidth();
  2083. m_Viewport.m_nHeight = pTarget->GetActualHeight();
  2084. g_pShaderAPI->SetViewports( 1, &m_Viewport );
  2085. }
  2086. }
  2087. else // use the bounds passed in
  2088. {
  2089. m_Viewport.m_nTopLeftX = x;
  2090. m_Viewport.m_nTopLeftY = y;
  2091. m_Viewport.m_nWidth = width;
  2092. m_Viewport.m_nHeight = height;
  2093. g_pShaderAPI->SetViewports( 1, &m_Viewport );
  2094. }
  2095. }
  2096. void CMatRenderContext::GetViewport( int& x, int& y, int& width, int& height ) const
  2097. {
  2098. // Verify valid top of RT stack
  2099. Assert ( m_RenderTargetStack.Count() > 0 );
  2100. // Grab the top of stack
  2101. const RenderTargetStackElement_t& element = m_RenderTargetStack.Top();
  2102. // If either dimension is not positive, set to full bounds of current target
  2103. if ( (element.m_nViewW <= 0) || (element.m_nViewH <= 0) )
  2104. {
  2105. // Viewport origin at target origin
  2106. x = y = 0;
  2107. // If target is back buffer
  2108. if ( element.m_pRenderTargets[0] == NULL )
  2109. {
  2110. g_pShaderAPI->GetBackBufferDimensions( width, height );
  2111. }
  2112. else // if target is texture
  2113. {
  2114. width = element.m_pRenderTargets[0]->GetActualWidth();
  2115. height = element.m_pRenderTargets[0]->GetActualHeight();
  2116. }
  2117. }
  2118. else // use the bounds from the stack directly
  2119. {
  2120. x = element.m_nViewX;
  2121. y = element.m_nViewY;
  2122. width = element.m_nViewW;
  2123. height = element.m_nViewH;
  2124. }
  2125. }
  2126. //-----------------------------------------------------------------------------
  2127. // Methods related to user clip planes
  2128. //-----------------------------------------------------------------------------
  2129. void CMatRenderContext::UpdateHeightClipUserClipPlane( void )
  2130. {
  2131. PlaneStackElement pse;
  2132. pse.bHack_IsHeightClipPlane = true;
  2133. int iExistingHeightClipPlaneIndex;
  2134. for( iExistingHeightClipPlaneIndex = m_CustomClipPlanes.Count(); --iExistingHeightClipPlaneIndex >= 0; )
  2135. {
  2136. if( m_CustomClipPlanes[iExistingHeightClipPlaneIndex].bHack_IsHeightClipPlane )
  2137. break;
  2138. }
  2139. switch( m_HeightClipMode )
  2140. {
  2141. case MATERIAL_HEIGHTCLIPMODE_DISABLE:
  2142. if( iExistingHeightClipPlaneIndex != -1 )
  2143. m_CustomClipPlanes.Remove( iExistingHeightClipPlaneIndex );
  2144. break;
  2145. case MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT:
  2146. pse.fValues[0] = 0.0f;
  2147. pse.fValues[1] = 0.0f;
  2148. pse.fValues[2] = 1.0f;
  2149. pse.fValues[3] = m_HeightClipZ;
  2150. if( iExistingHeightClipPlaneIndex != -1 )
  2151. {
  2152. memcpy( m_CustomClipPlanes.Base() + iExistingHeightClipPlaneIndex, &pse, sizeof( PlaneStackElement ) );
  2153. }
  2154. else
  2155. {
  2156. m_CustomClipPlanes.AddToTail( pse );
  2157. }
  2158. break;
  2159. case MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT:
  2160. pse.fValues[0] = 0.0f;
  2161. pse.fValues[1] = 0.0f;
  2162. pse.fValues[2] = -1.0f;
  2163. pse.fValues[3] = -m_HeightClipZ;
  2164. if( iExistingHeightClipPlaneIndex != -1 )
  2165. {
  2166. memcpy( m_CustomClipPlanes.Base() + iExistingHeightClipPlaneIndex, &pse, sizeof( PlaneStackElement ) );
  2167. }
  2168. else
  2169. {
  2170. m_CustomClipPlanes.AddToTail( pse );
  2171. }
  2172. break;
  2173. };
  2174. ApplyCustomClipPlanes();
  2175. /*switch( m_HeightClipMode )
  2176. {
  2177. case MATERIAL_HEIGHTCLIPMODE_DISABLE:
  2178. g_pShaderAPI->EnableClipPlane( 0, false );
  2179. break;
  2180. case MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT:
  2181. plane[0] = 0.0f;
  2182. plane[1] = 0.0f;
  2183. plane[2] = 1.0f;
  2184. plane[3] = m_HeightClipZ;
  2185. g_pShaderAPI->SetClipPlane( 0, plane );
  2186. g_pShaderAPI->EnableClipPlane( 0, true );
  2187. break;
  2188. case MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT:
  2189. plane[0] = 0.0f;
  2190. plane[1] = 0.0f;
  2191. plane[2] = -1.0f;
  2192. plane[3] = -m_HeightClipZ;
  2193. g_pShaderAPI->SetClipPlane( 0, plane );
  2194. g_pShaderAPI->EnableClipPlane( 0, true );
  2195. break;
  2196. }*/
  2197. }
  2198. //-----------------------------------------------------------------------------
  2199. // Lightmap stuff
  2200. //-----------------------------------------------------------------------------
  2201. void CMatRenderContext::BindLightmapPage( int lightmapPageID )
  2202. {
  2203. if ( m_lightmapPageID == lightmapPageID )
  2204. return;
  2205. // We gotta make sure there's no buffered primitives 'cause this'll
  2206. // change the render state.
  2207. g_pShaderAPI->FlushBufferedPrimitives();
  2208. CMatRenderContextBase::BindLightmapPage( lightmapPageID );
  2209. }
  2210. void CMatRenderContext::BindLightmapTexture( ITexture *pLightmapTexture )
  2211. {
  2212. if ( ( m_lightmapPageID == MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED ) && ( m_pUserDefinedLightmap == pLightmapTexture ) )
  2213. return;
  2214. // We gotta make sure there's no buffered primitives 'cause this'll
  2215. // change the render state.
  2216. g_pShaderAPI->FlushBufferedPrimitives();
  2217. m_lightmapPageID = MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED;
  2218. if ( pLightmapTexture )
  2219. {
  2220. pLightmapTexture->IncrementReferenceCount();
  2221. }
  2222. if ( m_pUserDefinedLightmap )
  2223. {
  2224. m_pUserDefinedLightmap->DecrementReferenceCount();
  2225. }
  2226. m_pUserDefinedLightmap = static_cast<ITextureInternal*>( pLightmapTexture );
  2227. }
  2228. void CMatRenderContext::BindLightmap( Sampler_t sampler )
  2229. {
  2230. switch ( m_lightmapPageID )
  2231. {
  2232. default:
  2233. Assert( ( m_lightmapPageID == 0 && GetLightmaps()->GetNumLightmapPages() == 0 ) || ( m_lightmapPageID >= 0 && m_lightmapPageID < GetLightmaps()->GetNumLightmapPages() ) );
  2234. if( m_lightmapPageID >= 0 && m_lightmapPageID < GetLightmaps()->GetNumLightmapPages() )
  2235. {
  2236. g_pShaderAPI->BindTexture( sampler, GetLightmaps()->GetLightmapPageTextureHandle( m_lightmapPageID ) );
  2237. }
  2238. break;
  2239. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED:
  2240. AssertOnce( m_pUserDefinedLightmap );
  2241. g_pShaderAPI->BindTexture( sampler, m_pUserDefinedLightmap->GetTextureHandle( 0 ) );
  2242. break;
  2243. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE:
  2244. BindFullbrightLightmap( sampler );
  2245. break;
  2246. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP:
  2247. BindBumpedFullbrightLightmap( sampler );
  2248. break;
  2249. }
  2250. }
  2251. void CMatRenderContext::BindBumpLightmap( Sampler_t sampler )
  2252. {
  2253. switch ( m_lightmapPageID )
  2254. {
  2255. default:
  2256. Assert( m_lightmapPageID >= 0 && m_lightmapPageID < GetLightmaps()->GetNumLightmapPages() );
  2257. if( m_lightmapPageID >= 0 && m_lightmapPageID < GetLightmaps()->GetNumLightmapPages() )
  2258. {
  2259. g_pShaderAPI->BindTexture( sampler, GetLightmaps()->GetLightmapPageTextureHandle( m_lightmapPageID ) );
  2260. g_pShaderAPI->BindTexture( (Sampler_t)(sampler+1), GetLightmaps()->GetLightmapPageTextureHandle( m_lightmapPageID ) );
  2261. g_pShaderAPI->BindTexture( (Sampler_t)(sampler+2), GetLightmaps()->GetLightmapPageTextureHandle( m_lightmapPageID ) );
  2262. }
  2263. break;
  2264. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED:
  2265. AssertOnce( m_pUserDefinedLightmap );
  2266. g_pShaderAPI->BindTexture( sampler, m_pUserDefinedLightmap->GetTextureHandle( 0 ) );
  2267. g_pShaderAPI->BindTexture( (Sampler_t)(sampler+1), m_pUserDefinedLightmap->GetTextureHandle( 0 ) );
  2268. g_pShaderAPI->BindTexture( (Sampler_t)(sampler+2), m_pUserDefinedLightmap->GetTextureHandle( 0 ) );
  2269. break;
  2270. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP:
  2271. BindBumpedFullbrightLightmap( sampler );
  2272. BindBumpedFullbrightLightmap( (Sampler_t)(sampler+1) );
  2273. BindBumpedFullbrightLightmap( (Sampler_t)(sampler+2) );
  2274. break;
  2275. case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE:
  2276. BindBumpedFullbrightLightmap( sampler );
  2277. BindBumpedFullbrightLightmap( (Sampler_t)(sampler+1) );
  2278. BindBumpedFullbrightLightmap( (Sampler_t)(sampler+2) );
  2279. break;
  2280. }
  2281. }
  2282. void CMatRenderContext::BindFullbrightLightmap( Sampler_t sampler )
  2283. {
  2284. g_pShaderAPI->BindTexture( sampler, GetFullbrightLightmapTextureHandle() );
  2285. }
  2286. void CMatRenderContext::BindBumpedFullbrightLightmap( Sampler_t sampler )
  2287. {
  2288. g_pShaderAPI->BindTexture( sampler, GetFullbrightBumpedLightmapTextureHandle() );
  2289. }
  2290. //-----------------------------------------------------------------------------
  2291. // Bind standard textures
  2292. //-----------------------------------------------------------------------------
  2293. void CMatRenderContext::BindStandardTexture( Sampler_t sampler, StandardTextureId_t id )
  2294. {
  2295. switch ( id )
  2296. {
  2297. case TEXTURE_LIGHTMAP:
  2298. BindLightmap( sampler );
  2299. return;
  2300. case TEXTURE_LIGHTMAP_BUMPED:
  2301. BindBumpLightmap( sampler );
  2302. return;
  2303. case TEXTURE_LIGHTMAP_FULLBRIGHT:
  2304. BindFullbrightLightmap( sampler );
  2305. return;
  2306. case TEXTURE_LIGHTMAP_BUMPED_FULLBRIGHT:
  2307. BindBumpedFullbrightLightmap( sampler );
  2308. return;
  2309. case TEXTURE_WHITE:
  2310. g_pShaderAPI->BindTexture( sampler, GetWhiteTextureHandle() );
  2311. return;
  2312. case TEXTURE_BLACK:
  2313. g_pShaderAPI->BindTexture( sampler, GetBlackTextureHandle() );
  2314. return;
  2315. case TEXTURE_GREY:
  2316. g_pShaderAPI->BindTexture( sampler, GetGreyTextureHandle() );
  2317. return;
  2318. case TEXTURE_GREY_ALPHA_ZERO:
  2319. g_pShaderAPI->BindTexture( sampler, GetGreyAlphaZeroTextureHandle() );
  2320. return;
  2321. case TEXTURE_NORMALMAP_FLAT:
  2322. g_pShaderAPI->BindTexture( sampler, GetFlatNormalTextureHandle() );
  2323. return;
  2324. case TEXTURE_NORMALIZATION_CUBEMAP:
  2325. TextureManager()->NormalizationCubemap()->Bind( sampler );
  2326. return;
  2327. case TEXTURE_NORMALIZATION_CUBEMAP_SIGNED:
  2328. TextureManager()->SignedNormalizationCubemap()->Bind( sampler );
  2329. return;
  2330. case TEXTURE_FRAME_BUFFER_FULL_TEXTURE_0:
  2331. case TEXTURE_FRAME_BUFFER_FULL_TEXTURE_1:
  2332. {
  2333. int nTextureIndex = id - TEXTURE_FRAME_BUFFER_FULL_TEXTURE_0;
  2334. if( m_pCurrentFrameBufferCopyTexture[ nTextureIndex ] )
  2335. {
  2336. ( ( ITextureInternal * )m_pCurrentFrameBufferCopyTexture[ nTextureIndex ] )->Bind( sampler );
  2337. }
  2338. }
  2339. return;
  2340. case TEXTURE_COLOR_CORRECTION_VOLUME_0:
  2341. case TEXTURE_COLOR_CORRECTION_VOLUME_1:
  2342. case TEXTURE_COLOR_CORRECTION_VOLUME_2:
  2343. case TEXTURE_COLOR_CORRECTION_VOLUME_3:
  2344. {
  2345. ITextureInternal *pTexture = TextureManager()->ColorCorrectionTexture( id - TEXTURE_COLOR_CORRECTION_VOLUME_0 );
  2346. if( pTexture )
  2347. {
  2348. pTexture->Bind( sampler );
  2349. }
  2350. }
  2351. return;
  2352. case TEXTURE_SHADOW_NOISE_2D:
  2353. TextureManager()->ShadowNoise2D()->Bind( sampler );
  2354. return;
  2355. case TEXTURE_IDENTITY_LIGHTWARP:
  2356. TextureManager()->IdentityLightWarp()->Bind( sampler );
  2357. return;
  2358. case TEXTURE_MORPH_ACCUMULATOR:
  2359. g_pMorphMgr->MorphAccumulator()->Bind( sampler );
  2360. return;
  2361. case TEXTURE_MORPH_WEIGHTS:
  2362. g_pMorphMgr->MorphWeights()->Bind( sampler );
  2363. return;
  2364. case TEXTURE_FRAME_BUFFER_FULL_DEPTH:
  2365. if( m_bFullFrameDepthIsValid )
  2366. TextureManager()->FullFrameDepthTexture()->Bind( sampler );
  2367. else
  2368. g_pShaderAPI->BindTexture( sampler, GetMaxDepthTextureHandle() );
  2369. return;
  2370. case TEXTURE_DEBUG_LUXELS:
  2371. TextureManager()->DebugLuxels2D()->Bind( sampler );
  2372. return;
  2373. default:
  2374. Assert(0);
  2375. }
  2376. }
  2377. void CMatRenderContext::BindStandardVertexTexture( VertexTextureSampler_t sampler, StandardTextureId_t id )
  2378. {
  2379. switch ( id )
  2380. {
  2381. case TEXTURE_MORPH_ACCUMULATOR:
  2382. g_pMorphMgr->MorphAccumulator()->BindVertexTexture( sampler );
  2383. return;
  2384. case TEXTURE_MORPH_WEIGHTS:
  2385. g_pMorphMgr->MorphWeights()->BindVertexTexture( sampler );
  2386. return;
  2387. default:
  2388. Assert(0);
  2389. }
  2390. }
  2391. void CMatRenderContext::GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id )
  2392. {
  2393. ITexture *pTexture = NULL;
  2394. switch ( id )
  2395. {
  2396. case TEXTURE_LIGHTMAP:
  2397. case TEXTURE_LIGHTMAP_BUMPED:
  2398. case TEXTURE_LIGHTMAP_FULLBRIGHT:
  2399. case TEXTURE_LIGHTMAP_BUMPED_FULLBRIGHT:
  2400. // NOTE: Doesn't exactly work since we may be in fullbright mode
  2401. // GetLightmapDimensions( pWidth, pHeight );
  2402. // break;
  2403. case TEXTURE_WHITE:
  2404. case TEXTURE_BLACK:
  2405. case TEXTURE_GREY:
  2406. case TEXTURE_GREY_ALPHA_ZERO:
  2407. case TEXTURE_NORMALMAP_FLAT:
  2408. default:
  2409. Assert( 0 );
  2410. Warning( "GetStandardTextureDimensions: still unimplemented for this type!\n" );
  2411. *pWidth = *pHeight = -1;
  2412. break;
  2413. case TEXTURE_NORMALIZATION_CUBEMAP:
  2414. pTexture = TextureManager()->NormalizationCubemap();
  2415. break;
  2416. case TEXTURE_NORMALIZATION_CUBEMAP_SIGNED:
  2417. pTexture = TextureManager()->SignedNormalizationCubemap();
  2418. break;
  2419. case TEXTURE_FRAME_BUFFER_FULL_TEXTURE_0:
  2420. case TEXTURE_FRAME_BUFFER_FULL_TEXTURE_1:
  2421. {
  2422. int nTextureIndex = id - TEXTURE_FRAME_BUFFER_FULL_TEXTURE_0;
  2423. pTexture = m_pCurrentFrameBufferCopyTexture[ nTextureIndex ];
  2424. }
  2425. break;
  2426. case TEXTURE_COLOR_CORRECTION_VOLUME_0:
  2427. case TEXTURE_COLOR_CORRECTION_VOLUME_1:
  2428. case TEXTURE_COLOR_CORRECTION_VOLUME_2:
  2429. case TEXTURE_COLOR_CORRECTION_VOLUME_3:
  2430. pTexture = TextureManager()->ColorCorrectionTexture( id - TEXTURE_COLOR_CORRECTION_VOLUME_0 );
  2431. break;
  2432. case TEXTURE_SHADOW_NOISE_2D:
  2433. pTexture = TextureManager()->ShadowNoise2D();
  2434. break;
  2435. case TEXTURE_IDENTITY_LIGHTWARP:
  2436. pTexture = TextureManager()->IdentityLightWarp();
  2437. return;
  2438. case TEXTURE_MORPH_ACCUMULATOR:
  2439. pTexture = g_pMorphMgr->MorphAccumulator();
  2440. break;
  2441. case TEXTURE_MORPH_WEIGHTS:
  2442. pTexture = g_pMorphMgr->MorphWeights();
  2443. break;
  2444. case TEXTURE_DEBUG_LUXELS:
  2445. pTexture = TextureManager()->DebugLuxels2D();
  2446. break;
  2447. }
  2448. if ( pTexture )
  2449. {
  2450. *pWidth = pTexture->GetActualWidth();
  2451. *pHeight = pTexture->GetActualHeight();
  2452. }
  2453. else
  2454. {
  2455. Warning( "GetStandardTextureDimensions: Couldn't find the texture to get the dimensions!\n" );
  2456. *pWidth = *pHeight = -1;
  2457. }
  2458. }
  2459. void CMatRenderContext::FogColor3f( float r, float g, float b )
  2460. {
  2461. unsigned char fogColor[3];
  2462. fogColor[0] = clamp( (int)(r * 255.0f), 0, 255 );
  2463. fogColor[1] = clamp( (int)(g * 255.0f), 0, 255 );
  2464. fogColor[2] = clamp( (int)(b * 255.0f), 0, 255 );
  2465. g_pShaderAPI->SceneFogColor3ub( fogColor[0], fogColor[1], fogColor[2] );
  2466. }
  2467. void CMatRenderContext::FogColor3fv( const float* rgb )
  2468. {
  2469. unsigned char fogColor[3];
  2470. fogColor[0] = clamp( (int)(rgb[0] * 255.0f), 0, 255 );
  2471. fogColor[1] = clamp( (int)(rgb[1] * 255.0f), 0, 255 );
  2472. fogColor[2] = clamp( (int)(rgb[2] * 255.0f), 0, 255 );
  2473. g_pShaderAPI->SceneFogColor3ub( fogColor[0], fogColor[1], fogColor[2] );
  2474. }
  2475. void CMatRenderContext::SetFlashlightMode( bool bEnable )
  2476. {
  2477. if( bEnable != m_bFlashlightEnable )
  2478. {
  2479. g_pShaderAPI->FlushBufferedPrimitives();
  2480. m_bFlashlightEnable = bEnable;
  2481. }
  2482. }
  2483. bool CMatRenderContext::GetFlashlightMode( ) const
  2484. {
  2485. return m_bFlashlightEnable;
  2486. }
  2487. void CMatRenderContext::SetFlashlightStateEx( const FlashlightState_t &state, const VMatrix &worldToTexture, ITexture *pFlashlightDepthTexture )
  2488. {
  2489. g_pShaderAPI->SetFlashlightStateEx( state, worldToTexture, pFlashlightDepthTexture );
  2490. if ( IsPC() && g_config.dxSupportLevel <= 70 )
  2491. {
  2492. // Going to go ahead and set a single hardware light here to do all lighting except for
  2493. // the spotlight falloff function, which is done with a texture.
  2494. SetAmbientLight( 0.0f, 0.0f, 0.0f );
  2495. static Vector4D blackCube[6];
  2496. int i;
  2497. for( i = 0; i < 6; i++ )
  2498. {
  2499. blackCube[i].Init( 0.0f, 0.0f, 0.0f, 0.0f );
  2500. }
  2501. SetAmbientLightCube( blackCube );
  2502. // Disable all the lights except for the first one.
  2503. for( i = 1; i < HardwareConfig()->MaxNumLights(); ++i )
  2504. {
  2505. LightDesc_t desc;
  2506. desc.m_Type = MATERIAL_LIGHT_DISABLE;
  2507. SetLight( i, desc );
  2508. }
  2509. LightDesc_t desc;
  2510. desc.m_Type = MATERIAL_LIGHT_POINT;
  2511. desc.m_Attenuation0 = state.m_fConstantAtten;
  2512. desc.m_Attenuation1 = state.m_fLinearAtten;
  2513. desc.m_Attenuation2 = state.m_fQuadraticAtten;
  2514. // flashlightfixme: I don't know why this scale has to be here to get fixed function lighting to work.
  2515. desc.m_Color.x = state.m_Color[0] * 17000.0f;
  2516. desc.m_Color.y = state.m_Color[1] * 17000.0f;
  2517. desc.m_Color.z = state.m_Color[2] * 17000.0f;
  2518. desc.m_Position = state.m_vecLightOrigin;
  2519. QAngle angles;
  2520. QuaternionAngles( state.m_quatOrientation, angles );
  2521. AngleVectors( angles, &desc.m_Direction );
  2522. desc.m_Range = state.m_FarZ;
  2523. desc.m_Falloff = 0.0f;
  2524. SetLight( 0, desc );
  2525. }
  2526. }
  2527. void CMatRenderContext::SetScissorRect( const int nLeft, const int nTop, const int nRight, const int nBottom, const bool bEnableScissor )
  2528. {
  2529. g_pShaderAPI->SetScissorRect( nLeft, nTop, nRight, nBottom, bEnableScissor );
  2530. }
  2531. void CMatRenderContext::SetToneMappingScaleLinear( const Vector &scale )
  2532. {
  2533. g_pShaderAPI->SetToneMappingScaleLinear( scale );
  2534. }
  2535. void CMatRenderContext::BeginBatch( IMesh* pIndices )
  2536. {
  2537. Assert( !m_pBatchMesh && !m_pBatchIndices);
  2538. m_pBatchIndices = pIndices;
  2539. }
  2540. void CMatRenderContext::BindBatch( IMesh* pVertices, IMaterial *pAutoBind )
  2541. {
  2542. m_pBatchMesh = GetDynamicMesh( false, pVertices, m_pBatchIndices, pAutoBind );
  2543. }
  2544. void CMatRenderContext::DrawBatch(int firstIndex, int numIndices )
  2545. {
  2546. Assert( m_pBatchMesh );
  2547. m_pBatchMesh->Draw( firstIndex, numIndices );
  2548. }
  2549. void CMatRenderContext::EndBatch()
  2550. {
  2551. m_pBatchIndices = NULL;
  2552. m_pBatchMesh = NULL;
  2553. }
  2554. bool CMatRenderContext::OnDrawMesh( IMesh *pMesh, int firstIndex, int numIndices )
  2555. {
  2556. SyncMatrices();
  2557. return true;
  2558. }
  2559. bool CMatRenderContext::OnDrawMesh( IMesh *pMesh, CPrimList *pLists, int nLists )
  2560. {
  2561. SyncMatrices();
  2562. return true;
  2563. }
  2564. void CMatRenderContext::AsyncCreateTextureFromRenderTarget( ITexture* pSrcRt, const char* pDstName, ImageFormat dstFmt, bool bGenMips, int nAdditionalCreationFlags, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs )
  2565. {
  2566. if ( g_pMaterialSystem->GetThreadMode() == MATERIAL_SINGLE_THREADED )
  2567. {
  2568. OnAsyncCreateTextureFromRenderTarget( pSrcRt, &pDstName, pRecipient );
  2569. }
  2570. TextureManager()->AsyncCreateTextureFromRenderTarget( pSrcRt, pDstName, dstFmt, bGenMips, nAdditionalCreationFlags, pRecipient, pExtraArgs );
  2571. }
  2572. void CMatRenderContext::AsyncMap( ITextureInternal* pTexToMap, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs )
  2573. {
  2574. if ( g_pMaterialSystem->GetThreadMode() == MATERIAL_SINGLE_THREADED )
  2575. {
  2576. OnAsyncMap( pTexToMap, pRecipient, pExtraArgs );
  2577. }
  2578. void* pMemory = NULL;
  2579. int nPitch = NULL;
  2580. pTexToMap->Map( &pMemory, &nPitch );
  2581. pRecipient->OnAsyncMapComplete( pTexToMap, pExtraArgs, pMemory, nPitch );
  2582. // Release references held earlier in OnAsyncMap
  2583. SafeRelease( &pRecipient );
  2584. SafeRelease( &pTexToMap );
  2585. }
  2586. void CMatRenderContext::AsyncUnmap( ITextureInternal* pTexToUnmap )
  2587. {
  2588. if ( g_pMaterialSystem->GetThreadMode() == MATERIAL_SINGLE_THREADED )
  2589. {
  2590. OnAsyncUnmap( pTexToUnmap );
  2591. }
  2592. pTexToUnmap->Unmap();
  2593. SafeRelease( &pTexToUnmap ); // Matches AddRef from OnAsyncUnmap
  2594. }
  2595. void CMatRenderContext::AsyncCopyRenderTargetToStagingTexture( ITexture* pDst, ITexture* pSrc, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs )
  2596. {
  2597. if ( g_pMaterialSystem->GetThreadMode() == MATERIAL_SINGLE_THREADED )
  2598. {
  2599. OnAsyncCopyRenderTargetToStagingTexture( pDst, pSrc, pRecipient );
  2600. }
  2601. pSrc->CopyToStagingTexture( pDst );
  2602. pRecipient->OnAsyncReadbackBegin( pDst, pSrc, pExtraArgs );
  2603. SafeRelease( &pDst );
  2604. SafeRelease( &pSrc );
  2605. SafeRelease( &pRecipient );
  2606. }
  2607. //-----------------------------------------------------------------------------
  2608. // Methods related to morph accumulation
  2609. //-----------------------------------------------------------------------------
  2610. void CMatRenderContext::BeginMorphAccumulation()
  2611. {
  2612. g_pMorphMgr->BeginMorphAccumulation( m_pMorphRenderContext );
  2613. }
  2614. void CMatRenderContext::EndMorphAccumulation()
  2615. {
  2616. g_pMorphMgr->EndMorphAccumulation( m_pMorphRenderContext );
  2617. }
  2618. void CMatRenderContext::AccumulateMorph( IMorph* pMorph, int nMorphCount, const MorphWeight_t* pWeights )
  2619. {
  2620. g_pMorphMgr->AccumulateMorph( m_pMorphRenderContext, pMorph, nMorphCount, pWeights );
  2621. }
  2622. bool CMatRenderContext::GetMorphAccumulatorTexCoord( Vector2D *pTexCoord, IMorph *pMorph, int nVertex )
  2623. {
  2624. return g_pMorphMgr->GetMorphAccumulatorTexCoord( m_pMorphRenderContext, pTexCoord, pMorph, nVertex );
  2625. }
  2626. //-----------------------------------------------------------------------------
  2627. // Occlusion query support
  2628. //-----------------------------------------------------------------------------
  2629. OcclusionQueryObjectHandle_t CMatRenderContext::CreateOcclusionQueryObject()
  2630. {
  2631. OcclusionQueryObjectHandle_t h = g_pOcclusionQueryMgr->CreateOcclusionQueryObject();
  2632. g_pOcclusionQueryMgr->OnCreateOcclusionQueryObject( h );
  2633. return h;
  2634. }
  2635. int CMatRenderContext::OcclusionQuery_GetNumPixelsRendered( OcclusionQueryObjectHandle_t h )
  2636. {
  2637. return g_pOcclusionQueryMgr->OcclusionQuery_GetNumPixelsRendered( h, true );
  2638. }
  2639. void CMatRenderContext::SetFullScreenDepthTextureValidityFlag( bool bIsValid )
  2640. {
  2641. m_bFullFrameDepthIsValid = bIsValid;
  2642. }
  2643. //-----------------------------------------------------------------------------
  2644. // Debug logging
  2645. //-----------------------------------------------------------------------------
  2646. void CMatRenderContext::PrintfVA( char *fmt, va_list vargs )
  2647. {
  2648. #if GLMDEBUG
  2649. g_pShaderAPI->PrintfVA( fmt, vargs );
  2650. #endif
  2651. }
  2652. void CMatRenderContext::Printf( const char *fmt, ... )
  2653. {
  2654. #if GLMDEBUG
  2655. va_list vargs;
  2656. va_start(vargs, fmt);
  2657. g_pShaderAPI->PrintfVA( (char *)fmt, vargs );
  2658. va_end( vargs );
  2659. #endif
  2660. }
  2661. float CMatRenderContext::Knob( char *knobname, float *setvalue )
  2662. {
  2663. #if GLMDEBUG
  2664. return g_pShaderAPI->Knob( knobname, setvalue );
  2665. #else
  2666. return 0.0f;
  2667. #endif
  2668. }