summaryrefslogtreecommitdiff
path: root/materialsystem/cmatrendercontext.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /materialsystem/cmatrendercontext.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'materialsystem/cmatrendercontext.cpp')
-rw-r--r--materialsystem/cmatrendercontext.cpp3157
1 files changed, 3157 insertions, 0 deletions
diff --git a/materialsystem/cmatrendercontext.cpp b/materialsystem/cmatrendercontext.cpp
new file mode 100644
index 0000000..c8f217f
--- /dev/null
+++ b/materialsystem/cmatrendercontext.cpp
@@ -0,0 +1,3157 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "pch_materialsystem.h"
+
+#define MATSYS_INTERNAL
+
+#include <math.h>
+#include "cmatrendercontext.h"
+#include "tier2/renderutils.h"
+#include "cmaterialsystem.h"
+#include "occlusionquerymgr.h"
+#include "texturemanager.h"
+#include "IHardwareConfigInternal.h"
+#include "ctype.h"
+
+#include "tier1/fmtstr.h"
+#include "togl/rendermechanism.h"
+
+// NOTE: This must be the last file included!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+
+// FIXME: right now, always keeping shader API in sync, because debug overlays don't seem to work 100% with the delayed matrix loading
+#define FORCE_MATRIX_SYNC 1
+
+#ifdef VALIDATE_MATRICES
+#define ShouldValidateMatrices() true
+#else
+#define ShouldValidateMatrices() false
+#endif
+
+#ifdef VALIDATE_MATRICES
+#define AllowLazyMatrixSync() false
+#define ForceSync() ((void)(0))
+#elif defined(FORCE_MATRIX_SYNC)
+#define AllowLazyMatrixSync() false
+#define ForceSync() ForceSyncMatrix( m_MatrixMode )
+#else
+#define AllowLazyMatrixSync() true
+#define ForceSync() ((void)(0))
+#endif
+
+#ifdef _X360
+static bool s_bDirtyDisk = false;
+#endif
+
+
+void ValidateMatrices( const VMatrix &m1, const VMatrix &m2, float eps = .001 )
+{
+ if ( !ShouldValidateMatrices() )
+ return;
+
+ for ( int i = 0; i < 16; i++ )
+ {
+ AssertFloatEquals( m1.Base()[i], m1.Base()[i], eps );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// The dirty disk error report function (NOTE: Could be called from any thread!)
+//-----------------------------------------------------------------------------
+#ifdef _X360
+unsigned ThreadedDirtyDiskErrorDisplay( void *pParam )
+{
+ XShowDirtyDiscErrorUI( XBX_GetPrimaryUserId() );
+}
+#endif
+
+
+void SpinPresent()
+{
+ while ( true )
+ {
+ g_pShaderAPI->ClearColor3ub( 0, 0, 0 );
+ g_pShaderAPI->ClearBuffers( true, true, true, -1, -1 );
+ g_pShaderDevice->Present();
+ }
+}
+
+void ReportDirtyDisk()
+{
+#ifdef _X360
+ s_bDirtyDisk = true;
+ ThreadHandle_t h = CreateSimpleThread( ThreadedDirtyDiskErrorDisplay, NULL );
+ ThreadSetPriority( h, THREAD_PRIORITY_HIGHEST );
+
+ // If this is being called from the render thread, immediately swap
+ if ( ( ThreadGetCurrentId() == MaterialSystem()->GetRenderThreadId() ) ||
+ ( ThreadInMainThread() && g_pMaterialSystem->GetThreadMode() != MATERIAL_QUEUED_THREADED ) )
+ {
+ SpinPresent();
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Install dirty disk error reporting function (call after SetMode)
+//-----------------------------------------------------------------------------
+void SetupDirtyDiskReportFunc()
+{
+ g_pFullFileSystem->InstallDirtyDiskReportFunc( ReportDirtyDisk );
+}
+
+
+//-----------------------------------------------------------------------------
+// Globals
+//-----------------------------------------------------------------------------
+CMemoryStack CMatRenderContextBase::sm_RenderData[2];
+int CMatRenderContextBase::sm_nRenderLockCount = 0;
+int CMatRenderContextBase::sm_nRenderStack = 0;
+int CMatRenderContextBase::sm_nInitializeCount = 0;
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CMatRenderContextBase::CMatRenderContextBase() :
+ m_pMaterialSystem( NULL ), m_RenderTargetStack( 16, 32 ), m_MatrixMode( NUM_MATRIX_MODES )
+{
+ int i;
+
+ m_bDirtyViewState = true;
+
+ // Put a special element at the top of the RT stack (indicating back buffer is current top of stack)
+ // NULL indicates back buffer, -1 indicates full-size viewport
+#if !defined( _X360 )
+ RenderTargetStackElement_t initialElement = { {NULL, NULL, NULL, NULL}, NULL, 0, 0, -1, -1 };
+#else
+ RenderTargetStackElement_t initialElement = { {NULL}, NULL, 0, 0, -1, -1 };
+#endif
+
+
+ m_RenderTargetStack.Push( initialElement );
+
+ for ( i = 0; i < MAX_FB_TEXTURES; i++ )
+ {
+ m_pCurrentFrameBufferCopyTexture[i] = NULL;
+ }
+
+ m_pCurrentMaterial = NULL;
+ m_pCurrentProxyData = NULL;
+ m_pUserDefinedLightmap = NULL;
+ m_HeightClipMode = MATERIAL_HEIGHTCLIPMODE_DISABLE;
+ m_HeightClipZ = 0.0f;
+ m_bEnableClipping = true;
+ m_bFlashlightEnable = false;
+ m_bFullFrameDepthIsValid = false;
+
+ for ( i = 0; i < NUM_MATRIX_MODES; i++ )
+ {
+ m_MatrixStacks[i].Push();
+ m_MatrixStacks[i].Top().matrix.Identity();
+ m_MatrixStacks[i].Top().flags |= ( MSF_DIRTY| MSF_IDENTITY );
+ }
+ m_pCurMatrixItem = &m_MatrixStacks[0].Top();
+
+ m_Viewport.Init( 0, 0, 0, 0 );
+
+ m_LastSetToneMapScale=Vector(1,1,1);
+ m_CurToneMapScale=1.0;
+ m_GoalToneMapScale = 1.0f;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+InitReturnVal_t CMatRenderContextBase::Init( )
+{
+ MEM_ALLOC_CREDIT();
+ if ( !sm_nInitializeCount )
+ {
+ int nSize = 2200 * 1024;
+ int nCommitSize = 32 * 1024;
+
+#ifdef SWDS
+ nSize = nCommitSize = 1024;
+#endif
+
+ const char *gamedir = CommandLine()->ParmValue("-game", CommandLine()->ParmValue( "-defaultgamedir", "hl2" ) );
+ if ( gamedir && !Q_stricmp( "garrysmod", gamedir ) )
+ {
+ nSize = 4400 * 1024;
+ }
+
+ sm_RenderData[0].Init( nSize, nCommitSize, 0, 32 );
+ sm_RenderData[1].Init( nSize, nCommitSize, 0, 32 );
+ sm_nRenderStack = 0;
+ sm_nRenderLockCount = 0;
+ }
+ ++sm_nInitializeCount;
+ return INIT_OK;
+}
+
+void CMatRenderContextBase::Shutdown( )
+{
+ Assert( sm_nInitializeCount >= 0 );
+ if ( --sm_nInitializeCount == 0 )
+ {
+ sm_RenderData[0].Term();
+ sm_RenderData[1].Term();
+ }
+}
+
+void CMatRenderContextBase::CompactMemory()
+{
+ if ( sm_nRenderLockCount )
+ {
+ DevWarning( "CMatRenderContext: Trying to compact with render data still locked!\n" );
+ sm_nRenderLockCount = 0;
+ }
+ sm_RenderData[0].FreeAll();
+ sm_RenderData[1].FreeAll();
+}
+
+void CMatRenderContextBase::MarkRenderDataUnused( bool bFrameBegin )
+{
+ if ( sm_nRenderLockCount )
+ {
+ DevWarning( "CMatRenderContext: Trying to clear render data with render data still locked (%d)!\n", sm_nRenderLockCount );
+ sm_nRenderLockCount = 0;
+ }
+
+
+ // JAY: DO NOT MERGE FROM TF2 - L4D HAS CHANGED THE UNDERLYING INTERFACE IN A WAY THAT DOESN'T REQUIRE THIS
+#if 0
+ // Switch stacks
+ if ( bFrameBegin )
+ {
+ sm_nRenderStack = 1 - sm_nRenderStack;
+ }
+
+ // Clear the new stack
+#ifdef _DEBUG
+ memset( sm_RenderData[sm_nRenderStack].GetBase(), 0xFF, RenderDataSizeUsed() );
+#endif
+ sm_RenderData[ sm_nRenderStack ].FreeAll( false );
+#else
+ // Just for TF2, don't free the stack until the end of frame. TF2 Allocates render data and holds it over the lock
+ // period because we haven't revised the studiorender interface yet to change patterns.
+ // Switch stacks
+ if ( bFrameBegin )
+ {
+ sm_nRenderStack = 1 - sm_nRenderStack;
+ // Clear the new stack
+#ifdef _DEBUG
+ memset( sm_RenderData[sm_nRenderStack].GetBase(), 0xFF, RenderDataSizeUsed() );
+#endif
+ sm_RenderData[ sm_nRenderStack ].FreeAll( false );
+ }
+#endif
+
+
+}
+
+int CMatRenderContextBase::RenderDataSizeUsed() const
+{
+ return sm_RenderData[sm_nRenderStack].GetUsed();
+}
+
+bool CMatRenderContextBase::IsRenderData( const void *pData ) const
+{
+ intp nData = (intp)pData;
+ intp nBaseAddress = (intp)sm_RenderData[sm_nRenderStack].GetBase();
+ intp nLastAddress = nBaseAddress + RenderDataSizeUsed();
+ return ( nData == 0 ) || ( nData >= nBaseAddress && nData < nLastAddress );
+}
+
+
+//-----------------------------------------------------------------------------
+// debug logging - empty in base class
+//-----------------------------------------------------------------------------
+
+void CMatRenderContextBase::PrintfVA( char *fmt, va_list vargs )
+{
+}
+
+void CMatRenderContextBase::Printf( const char *fmt, ... )
+{
+}
+
+float CMatRenderContextBase::Knob( char *knobname, float *setvalue )
+{
+ return 0.0f;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+
+#define g_pShaderAPI Cannot_use_ShaderAPI_in_CMatRenderContextBase
+
+void CMatRenderContextBase::InitializeFrom( CMatRenderContextBase *pInitialState )
+{
+ int i;
+
+ m_pCurrentMaterial = pInitialState->m_pCurrentMaterial;
+ m_pCurrentProxyData = pInitialState->m_pCurrentProxyData;
+ m_lightmapPageID = pInitialState->m_lightmapPageID;
+ m_pUserDefinedLightmap = pInitialState->m_pUserDefinedLightmap;
+ m_pLocalCubemapTexture = pInitialState->m_pLocalCubemapTexture;
+
+ memcpy( m_pCurrentFrameBufferCopyTexture, pInitialState->m_pCurrentFrameBufferCopyTexture, MAX_FB_TEXTURES * sizeof(ITexture *) );
+
+ m_bEnableClipping = pInitialState->m_bEnableClipping;
+
+ m_HeightClipMode = pInitialState->m_HeightClipMode;
+ m_HeightClipZ = pInitialState->m_HeightClipZ;
+
+ m_pBoundMorph = pInitialState->m_pBoundMorph; // not reference counted?
+
+ m_RenderTargetStack.Clear();
+ m_RenderTargetStack.EnsureCapacity( pInitialState->m_RenderTargetStack.Count() );
+
+ for ( i = 0; i < pInitialState->m_RenderTargetStack.Count(); i++ )
+ {
+ m_RenderTargetStack.Push( pInitialState->m_RenderTargetStack[i] );
+ }
+
+ m_MatrixMode = pInitialState->m_MatrixMode;
+ for ( i = 0; i < NUM_MATRIX_MODES; i++ )
+ {
+ m_MatrixStacks[i].CopyFrom( pInitialState->m_MatrixStacks[i] );
+ }
+
+ m_bFlashlightEnable = pInitialState->m_bFlashlightEnable;
+
+ m_FrameTime = pInitialState->m_FrameTime;
+ m_GoalToneMapScale = pInitialState->m_GoalToneMapScale;
+ m_CurToneMapScale = pInitialState->m_CurToneMapScale;
+ m_LastSetToneMapScale = pInitialState->m_LastSetToneMapScale;
+}
+
+void CMatRenderContextBase::Bind( IMaterial *iMaterial, void *proxyData )
+{
+ IMaterialInternal *material = static_cast<IMaterialInternal *>( iMaterial );
+
+ if ( !material )
+ {
+ Warning( "Programming error: CMatRenderContext::Bind: NULL material\n" );
+ material = static_cast<IMaterialInternal *>( g_pErrorMaterial );
+ }
+ material = material->GetRealTimeVersion(); //always work with the real time versions of materials internally
+
+ if ( GetCurrentMaterialInternal() != material )
+ {
+ if( !material->IsPrecached() )
+ {
+ DevWarning( "Binding uncached material \"%s\", artificially incrementing refcount\n", material->GetName() );
+ material->ArtificialAddRef();
+ material->Precache();
+ }
+ SetCurrentMaterialInternal(material);
+ }
+
+ SetCurrentProxy( proxyData );
+}
+
+void CMatRenderContextBase::BindLightmapPage( int lightmapPageID )
+{
+ m_lightmapPageID = lightmapPageID;
+
+}
+
+void CMatRenderContextBase::SetRenderTargetEx( int nRenderTargetID, ITexture *pNewTarget )
+{
+ // Verify valid top of RT stack
+ Assert ( m_RenderTargetStack.Count() > 0 );
+
+ // Reset the top of stack to the new target with old viewport
+ RenderTargetStackElement_t newTOS = m_RenderTargetStack.Top();
+ newTOS.m_pRenderTargets[nRenderTargetID] = pNewTarget;
+ m_RenderTargetStack.Pop( );
+ m_RenderTargetStack.Push( newTOS );
+}
+
+void CMatRenderContextBase::BindLocalCubemap( ITexture *pTexture )
+{
+ if( pTexture )
+ {
+ m_pLocalCubemapTexture = pTexture;
+ }
+ else
+ {
+ m_pLocalCubemapTexture = TextureManager()->ErrorTexture();
+ }
+}
+
+ITexture *CMatRenderContextBase::GetRenderTarget( void )
+{
+ if (m_RenderTargetStack.Count() > 0)
+ {
+ return m_RenderTargetStack.Top().m_pRenderTargets[0];
+ }
+ else
+ {
+ return NULL; // should this be something else, since NULL indicates back buffer?
+ }
+}
+
+ITexture *CMatRenderContextBase::GetRenderTargetEx( int nRenderTargetID )
+{
+ // Verify valid top of stack
+ Assert ( m_RenderTargetStack.Count() > 0 );
+
+ // Top of render target stack
+ ITexture *pTexture = m_RenderTargetStack.Top().m_pRenderTargets[ nRenderTargetID ];
+ return pTexture;
+}
+
+void CMatRenderContextBase::SetFrameBufferCopyTexture( ITexture *pTexture, int textureIndex )
+{
+ if( textureIndex < 0 || textureIndex > MAX_FB_TEXTURES )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ // FIXME: Do I need to increment/decrement ref counts here, or assume that the app is going to do it?
+ m_pCurrentFrameBufferCopyTexture[textureIndex] = pTexture;
+}
+
+ITexture *CMatRenderContextBase::GetFrameBufferCopyTexture( int textureIndex )
+{
+ if( textureIndex < 0 || textureIndex > MAX_FB_TEXTURES )
+ {
+ Assert( 0 );
+ return NULL; // FIXME! This should return the error texture.
+ }
+ return m_pCurrentFrameBufferCopyTexture[textureIndex];
+}
+
+
+void CMatRenderContextBase::MatrixMode( MaterialMatrixMode_t mode )
+{
+ Assert( m_MatrixStacks[mode].Count() );
+ m_MatrixMode = mode;
+ m_pCurMatrixItem = &m_MatrixStacks[mode].Top();
+}
+
+void CMatRenderContextBase::CurrentMatrixChanged()
+{
+ if ( m_MatrixMode == MATERIAL_VIEW )
+ {
+ m_bDirtyViewState = true;
+ m_bDirtyViewProjState = true;
+ }
+ else if ( m_MatrixMode == MATERIAL_PROJECTION )
+ {
+ m_bDirtyViewProjState = true;
+ }
+}
+
+void CMatRenderContextBase::PushMatrix()
+{
+ CUtlStack<MatrixStackItem_t> &curStack = m_MatrixStacks[ m_MatrixMode ];
+ Assert( curStack.Count() );
+ int iNew = curStack.Push();
+ curStack[ iNew ] = curStack[ iNew - 1 ];
+ m_pCurMatrixItem = &curStack.Top();
+ CurrentMatrixChanged();
+}
+
+void CMatRenderContextBase::PopMatrix()
+{
+ Assert( m_MatrixStacks[m_MatrixMode].Count() > 1 );
+ m_MatrixStacks[ m_MatrixMode ].Pop();
+ m_pCurMatrixItem = &m_MatrixStacks[m_MatrixMode].Top();
+ CurrentMatrixChanged();
+}
+
+void CMatRenderContextBase::LoadMatrix( const VMatrix& matrix )
+{
+ m_pCurMatrixItem->matrix = matrix;
+ m_pCurMatrixItem->flags = MSF_DIRTY; // clearing identity implicitly
+ CurrentMatrixChanged();
+}
+
+void CMatRenderContextBase::LoadMatrix( const matrix3x4_t& matrix )
+{
+ m_pCurMatrixItem->matrix = matrix;
+ m_pCurMatrixItem->flags = MSF_DIRTY; // clearing identity implicitly
+ CurrentMatrixChanged();
+}
+
+void CMatRenderContextBase::MultMatrix( const VMatrix& matrix )
+{
+ VMatrix result;
+
+ MatrixMultiply( matrix, m_pCurMatrixItem->matrix, result );
+ m_pCurMatrixItem->matrix = result;
+ m_pCurMatrixItem->flags = MSF_DIRTY; // clearing identity implicitly
+ CurrentMatrixChanged();
+}
+
+void CMatRenderContextBase::MultMatrix( const matrix3x4_t& matrix )
+{
+ CMatRenderContextBase::MultMatrix( VMatrix( matrix ) );
+}
+
+void CMatRenderContextBase::MultMatrixLocal( const VMatrix& matrix )
+{
+ VMatrix result;
+ MatrixMultiply( m_pCurMatrixItem->matrix, matrix, result );
+ m_pCurMatrixItem->matrix = result;
+ m_pCurMatrixItem->flags = MSF_DIRTY; // clearing identity implicitly
+ CurrentMatrixChanged();
+}
+
+void CMatRenderContextBase::MultMatrixLocal( const matrix3x4_t& matrix )
+{
+ CMatRenderContextBase::MultMatrixLocal( VMatrix( matrix ) );
+}
+
+void CMatRenderContextBase::LoadIdentity()
+{
+ // FIXME: possibly track is identity so can call shader API LoadIdentity() later instead of LoadMatrix()?
+ m_pCurMatrixItem->matrix.Identity();
+ m_pCurMatrixItem->flags = ( MSF_DIRTY | MSF_IDENTITY );
+ CurrentMatrixChanged();
+}
+
+void CMatRenderContextBase::Ortho( double left, double top, double right, double bottom, double zNear, double zFar )
+{
+ MatrixOrtho( m_pCurMatrixItem->matrix, left, top, right, bottom, zNear, zFar );
+ m_pCurMatrixItem->flags = MSF_DIRTY;
+}
+
+void CMatRenderContextBase::PerspectiveX( double flFovX, double flAspect, double flZNear, double flZFar )
+{
+ MatrixPerspectiveX( m_pCurMatrixItem->matrix, flFovX, flAspect, flZNear, flZFar );
+ m_pCurMatrixItem->flags = MSF_DIRTY;
+}
+
+void CMatRenderContextBase::PerspectiveOffCenterX( double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right )
+{
+ MatrixPerspectiveOffCenterX( m_pCurMatrixItem->matrix, flFovX, flAspect, flZNear, flZFar, bottom, top, left, right );
+ m_pCurMatrixItem->flags = MSF_DIRTY;
+}
+
+void CMatRenderContextBase::PickMatrix( int x, int y, int nWidth, int nHeight )
+{
+ int vx, vy, vwidth, vheight;
+ GetViewport( vx, vy, vwidth, vheight );
+
+ // Compute the location of the pick region in projection space...
+ float px = 2.0 * (float)(x - vx) / (float)vwidth - 1;
+ float py = 2.0 * (float)(y - vy)/ (float)vheight - 1;
+ float pw = 2.0 * (float)nWidth / (float)vwidth;
+ float ph = 2.0 * (float)nHeight / (float)vheight;
+
+ // we need to translate (px, py) to the origin
+ // and scale so (pw,ph) -> (2, 2)
+ VMatrix mat;
+ MatrixSetIdentity( mat );
+ mat.m[0][0] = 2.0 / pw;
+ mat.m[1][1] = 2.0 / ph;
+ mat.m[0][3] = -2.0 * px / pw;
+ mat.m[1][3] = -2.0 * py / ph;
+
+ CMatRenderContextBase::MultMatrixLocal( mat );
+}
+
+void CMatRenderContextBase::Rotate( float flAngle, float x, float y, float z )
+{
+ MatrixRotate( m_pCurMatrixItem->matrix, Vector( x, y, z ), flAngle );
+ m_pCurMatrixItem->flags = MSF_DIRTY;
+}
+
+void CMatRenderContextBase::Translate( float x, float y, float z )
+{
+ MatrixTranslate( m_pCurMatrixItem->matrix, Vector( x, y, z ) );
+ m_pCurMatrixItem->flags = MSF_DIRTY;
+}
+
+void CMatRenderContextBase::Scale( float x, float y, float z )
+{
+ VMatrix mat;
+ MatrixBuildScale( mat, x, y, z );
+ CMatRenderContextBase::MultMatrixLocal( mat );
+}
+
+void CMatRenderContextBase::GetMatrix( MaterialMatrixMode_t matrixMode, VMatrix *pMatrix )
+{
+ CUtlStack<MatrixStackItem_t> &stack = m_MatrixStacks[ matrixMode ];
+
+ if ( !stack.Count() )
+ {
+ pMatrix->Identity();
+ return;
+ }
+
+ *pMatrix = stack.Top().matrix;
+}
+
+void CMatRenderContextBase::GetMatrix( MaterialMatrixMode_t matrixMode, matrix3x4_t *pMatrix )
+{
+ CUtlStack<MatrixStackItem_t> &stack = m_MatrixStacks[ matrixMode ];
+
+ if ( !stack.Count() )
+ {
+ SetIdentityMatrix( *pMatrix );
+ return;
+ }
+
+ *pMatrix = stack.Top().matrix.As3x4();
+}
+
+void CMatRenderContextBase::RecomputeViewState()
+{
+ if ( !m_bDirtyViewState )
+ return;
+ m_bDirtyViewState = false;
+
+ // FIXME: Cache this off to make it less expensive?
+ matrix3x4_t viewMatrix;
+ GetMatrix( MATERIAL_VIEW, &viewMatrix );
+ m_vecViewOrigin.x =
+ -( viewMatrix[0][3] * viewMatrix[0][0] +
+ viewMatrix[1][3] * viewMatrix[1][0] +
+ viewMatrix[2][3] * viewMatrix[2][0] );
+ m_vecViewOrigin.y =
+ -( viewMatrix[0][3] * viewMatrix[0][1] +
+ viewMatrix[1][3] * viewMatrix[1][1] +
+ viewMatrix[2][3] * viewMatrix[2][1] );
+ m_vecViewOrigin.z =
+ -( viewMatrix[0][3] * viewMatrix[0][2] +
+ viewMatrix[1][3] * viewMatrix[1][2] +
+ viewMatrix[2][3] * viewMatrix[2][2] );
+
+ // FIXME Implement computation of m_vecViewForward, etc
+ m_vecViewForward.Init();
+ m_vecViewRight.Init();
+
+ // FIXME: Is this correct?
+ m_vecViewUp.Init( viewMatrix[1][0], viewMatrix[1][1], viewMatrix[1][2] );
+}
+
+void CMatRenderContextBase::GetWorldSpaceCameraPosition( Vector *pCameraPos )
+{
+ RecomputeViewState();
+ VectorCopy( m_vecViewOrigin, *pCameraPos );
+}
+
+void CMatRenderContextBase::GetWorldSpaceCameraVectors( Vector *pVecForward, Vector *pVecRight, Vector *pVecUp )
+{
+ RecomputeViewState();
+
+ // FIXME Implement computation of m_vecViewForward
+ Assert( 0 );
+
+ if ( pVecForward )
+ {
+ VectorCopy( m_vecViewForward, *pVecForward );
+ }
+ if ( pVecRight )
+ {
+ VectorCopy( m_vecViewRight, *pVecRight );
+ }
+ if ( pVecUp )
+ {
+ VectorCopy( m_vecViewUp, *pVecUp );
+ }
+}
+
+void *CMatRenderContextBase::LockRenderData( int nSizeInBytes )
+{
+ MEM_ALLOC_CREDIT();
+ void *pDest = sm_RenderData[ sm_nRenderStack ].Alloc( nSizeInBytes, false );
+ if ( !pDest )
+ {
+ ExecuteNTimes( 10, Warning("MaterialSystem: Out of memory in render data!\n") );
+ }
+ AddRefRenderData();
+ return pDest;
+}
+
+void CMatRenderContextBase::UnlockRenderData( void *pData )
+{
+ ReleaseRenderData();
+}
+
+void CMatRenderContextBase::AddRefRenderData()
+{
+ ++sm_nRenderLockCount;
+}
+
+void CMatRenderContextBase::ReleaseRenderData()
+{
+ --sm_nRenderLockCount;
+ Assert( sm_nRenderLockCount >= 0 );
+ if ( sm_nRenderLockCount == 0 )
+ {
+ OnRenderDataUnreferenced();
+ }
+}
+
+void CMatRenderContextBase::SyncMatrices()
+{
+}
+
+void CMatRenderContextBase::SyncMatrix( MaterialMatrixMode_t mode )
+{
+}
+
+void CMatRenderContextBase::SetHeightClipMode( enum MaterialHeightClipMode_t heightClipMode )
+{
+ if( m_HeightClipMode != heightClipMode )
+ {
+ m_HeightClipMode = heightClipMode;
+ UpdateHeightClipUserClipPlane();
+ /*if ( HardwareConfig()->MaxUserClipPlanes() >= 1 && !HardwareConfig()->UseFastClipping())
+ {
+ UpdateHeightClipUserClipPlane();
+ }
+ else
+ {
+ g_pShaderAPI->SetHeightClipMode( heightClipMode );
+ }*/
+ }
+}
+
+void CMatRenderContextBase::SetHeightClipZ( float z )
+{
+ if( z != m_HeightClipZ )
+ {
+ m_HeightClipZ = z;
+ UpdateHeightClipUserClipPlane();
+ }
+
+ // FIXME! : Need to move user clip plane support back to pre-dx9 cards (all of the pixel shaders
+ // have texkill in them. . blich.)
+
+ /*if ( HardwareConfig()->MaxUserClipPlanes() >= 1 && !HardwareConfig()->UseFastClipping() )
+ {
+ UpdateHeightClipUserClipPlane();
+ }
+ else
+ {
+ g_pShaderAPI->SetHeightClipZ( z );
+ }*/
+}
+
+bool CMatRenderContextBase::EnableClipping( bool bEnable )
+{
+ if( bEnable != m_bEnableClipping )
+ {
+ m_bEnableClipping = bEnable;
+ ApplyCustomClipPlanes();
+
+ return !bEnable;
+ }
+ return bEnable;
+}
+
+void CMatRenderContextBase::Viewport( int x, int y, int width, int height )
+{
+ // Verify valid top of RT stack
+ Assert ( m_RenderTargetStack.Count() > 0 );
+
+ // Reset the top of stack to the new viewport
+ RenderTargetStackElement_t newTOS;
+ memcpy(&newTOS,&(m_RenderTargetStack.Top()),sizeof(newTOS));
+ newTOS.m_nViewX = x;
+ newTOS.m_nViewY = y;
+ newTOS.m_nViewW = width;
+ newTOS.m_nViewH = height;
+
+ m_RenderTargetStack.Pop( );
+ m_RenderTargetStack.Push( newTOS );
+}
+
+
+//-----------------------------------------------------------------------------
+// This version will push the current rendertarget + current viewport onto the stack
+//-----------------------------------------------------------------------------
+void CMatRenderContextBase::PushRenderTargetAndViewport( )
+{
+ // Necessary to push the stack top onto itself; realloc could happen otherwise
+ m_RenderTargetStack.EnsureCapacity( m_RenderTargetStack.Count() + 1 );
+ m_RenderTargetStack.Push( m_RenderTargetStack.Top() );
+ CommitRenderTargetAndViewport();
+}
+
+
+//-----------------------------------------------------------------------------
+// Pushes a render target on the render target stack. Without a specific
+// viewport also being pushed, this function uses dummy values which indicate
+// that the viewport should span the the full render target and pushes
+// the RenderTargetStackElement_t onto the stack
+//
+// The push and pop methods also implicitly set the render target to the new top of stack
+//
+// NULL for pTexture indicates rendering to the back buffer
+//-----------------------------------------------------------------------------
+void CMatRenderContextBase::PushRenderTargetAndViewport( ITexture *pTexture )
+{
+ // Just blindly push the data on the stack with flags indicating full bounds
+#if !defined( _X360 )
+ RenderTargetStackElement_t element = { {pTexture, NULL, NULL, NULL}, 0, 0, -1, -1 };
+#else
+ RenderTargetStackElement_t element = { {pTexture}, 0, 0, -1, -1 };
+#endif
+ m_RenderTargetStack.Push( element );
+ CommitRenderTargetAndViewport();
+}
+
+
+//-----------------------------------------------------------------------------
+// Pushes a render target on the render target stack and sets the viewport
+//
+// NULL for pTexture indicates rendering to the back buffer
+//
+// The push and pop methods also implicitly set the render target to the new top of stack
+//-----------------------------------------------------------------------------
+void CMatRenderContextBase::PushRenderTargetAndViewport( ITexture *pTexture, int nViewX, int nViewY, int nViewW, int nViewH )
+{
+ CMatRenderContextBase::PushRenderTargetAndViewport( pTexture, NULL, nViewX, nViewY, nViewW, nViewH );
+}
+
+
+//-----------------------------------------------------------------------------
+// Pushes a render target on the render target stack and sets the viewport
+// The push and pop methods also implicitly set the render target to the new top of stack
+//-----------------------------------------------------------------------------
+void CMatRenderContextBase::PushRenderTargetAndViewport( ITexture *pTexture, ITexture *pDepthTexture, int nViewX, int nViewY, int nViewW, int nViewH )
+{
+ // Just blindly push the data on the stack
+#if !defined( _X360 )
+ RenderTargetStackElement_t element = { {pTexture, NULL, NULL, NULL}, pDepthTexture, nViewX, nViewY, nViewW, nViewH };
+#else
+ RenderTargetStackElement_t element = { {pTexture}, pDepthTexture, nViewX, nViewY, nViewW, nViewH };
+#endif
+ m_RenderTargetStack.Push( element );
+ CommitRenderTargetAndViewport();
+}
+
+
+//-----------------------------------------------------------------------------
+// Pops from the render target stack
+// Also implicitly sets the render target to the new top of stack
+//-----------------------------------------------------------------------------
+void CMatRenderContextBase::PopRenderTargetAndViewport( void )
+{
+ // Check for underflow
+ if ( m_RenderTargetStack.Count() == 0 )
+ {
+ Assert( !"CMatRenderContext::PopRenderTargetAndViewport: Stack is empty!!!" );
+ return;
+ }
+
+ // Changelist #266217 added this to main/src/materialsystem.
+ Flush();
+
+ // Remove the top of stack
+ m_RenderTargetStack.Pop( );
+ CommitRenderTargetAndViewport();
+}
+
+void CMatRenderContextBase::RecomputeViewProjState()
+{
+ if ( m_bDirtyViewProjState )
+ {
+ VMatrix viewMatrix, projMatrix;
+
+ // FIXME: Should consider caching this upon change for projection or view matrix.
+ GetMatrix( MATERIAL_VIEW, &viewMatrix );
+ GetMatrix( MATERIAL_PROJECTION, &projMatrix );
+ m_viewProjMatrix = projMatrix * viewMatrix;
+ m_bDirtyViewProjState = false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// This returns the diameter of the sphere in pixels based on
+// the current model, view, + projection matrices and viewport.
+//-----------------------------------------------------------------------------
+float CMatRenderContextBase::ComputePixelDiameterOfSphere( const Vector& vecAbsOrigin, float flRadius )
+{
+ RecomputeViewState();
+ RecomputeViewProjState();
+ // This is sort of faked, but it's faster that way
+ // FIXME: Also, there's a much faster way to do this with similar triangles
+ // but I want to make sure it exactly matches the current matrices, so
+ // for now, I do it this conservative way
+ Vector4D testPoint1, testPoint2;
+ VectorMA( vecAbsOrigin, flRadius, m_vecViewUp, testPoint1.AsVector3D() );
+ VectorMA( vecAbsOrigin, -flRadius, m_vecViewUp, testPoint2.AsVector3D() );
+ testPoint1.w = testPoint2.w = 1.0f;
+
+ Vector4D clipPos1, clipPos2;
+ Vector4DMultiply( m_viewProjMatrix, testPoint1, clipPos1 );
+ Vector4DMultiply( m_viewProjMatrix, testPoint2, clipPos2 );
+ if (clipPos1.w >= 0.001f)
+ {
+ clipPos1.y /= clipPos1.w;
+ }
+ else
+ {
+ clipPos1.y *= 1000;
+ }
+ if (clipPos2.w >= 0.001f)
+ {
+ clipPos2.y /= clipPos2.w;
+ }
+ else
+ {
+ clipPos2.y *= 1000;
+ }
+ int vx, vy, vwidth, vheight;
+ GetViewport( vx, vy, vwidth, vheight );
+
+ // The divide-by-two here is because y goes from -1 to 1 in projection space
+ return vheight * fabs( clipPos2.y - clipPos1.y ) / 2.0f;
+}
+
+ConVar mat_accelerate_adjust_exposure_down( "mat_accelerate_adjust_exposure_down", "3.0", FCVAR_CHEAT );
+ConVar mat_hdr_manual_tonemap_rate( "mat_hdr_manual_tonemap_rate", "1.0" );
+ConVar mat_hdr_tonemapscale( "mat_hdr_tonemapscale", "1.0", FCVAR_CHEAT );
+ConVar mat_tonemap_algorithm( "mat_tonemap_algorithm", "1", FCVAR_CHEAT, "0 = Original Algorithm 1 = New Algorithm" );
+
+void CMatRenderContextBase::TurnOnToneMapping(void)
+{
+ if ( ( HardwareConfig()->GetHDRType() != HDR_TYPE_NONE ) && ( m_FrameTime > 0.0f ) )
+ {
+ float elapsed_time = m_FrameTime;
+ float goalScale = m_GoalToneMapScale;
+ float rate = mat_hdr_manual_tonemap_rate.GetFloat();
+
+ if ( mat_tonemap_algorithm.GetInt() == 1 )
+ {
+ rate *= 2.0f; // Default 2x for the new tone mapping algorithm so it feels the same as the original
+ }
+
+ if ( rate == 0.0f ) // Zero indicates instantaneous tonemap scaling
+ {
+ m_CurToneMapScale = goalScale;
+ }
+ else
+ {
+ if ( goalScale < m_CurToneMapScale )
+ {
+ float acc_exposure_adjust = mat_accelerate_adjust_exposure_down.GetFloat();
+
+ // Adjust at up to 4x rate when over-exposed.
+ rate = min( ( acc_exposure_adjust * rate ), FLerp( rate, ( acc_exposure_adjust * rate ), 0.0f, 1.5f, ( m_CurToneMapScale - goalScale ) ) );
+ }
+
+ float flRateTimesTime = rate * elapsed_time;
+ if ( mat_tonemap_algorithm.GetInt() == 1 )
+ {
+ // For the new tone mapping algorithm, limit the rate based on the number of bins to
+ // help reduce the tone map scalar "riding the wave" of the histogram re-building
+
+ //Warning( "flRateTimesTime = %.4f", flRateTimesTime );
+ flRateTimesTime = min( flRateTimesTime, ( 1.0f / 16.0f ) * 0.25f ); // 16 is number of HDR sample bins defined in viewpostprocess.cpp
+ //Warning( " --> %.4f\n", flRateTimesTime );
+ }
+
+ float alpha = max( 0.0f, min( 1.0f, flRateTimesTime ) );
+ m_CurToneMapScale = ( goalScale * alpha ) + ( m_CurToneMapScale * ( 1.0f - alpha ) );
+
+ if ( !IsFinite( m_CurToneMapScale ) )
+ {
+ Assert( 0 );
+ m_CurToneMapScale = goalScale;
+ }
+ }
+
+ SetToneMappingScaleLinear( Vector( m_CurToneMapScale, m_CurToneMapScale, m_CurToneMapScale ) );
+ m_LastSetToneMapScale = Vector( m_CurToneMapScale, m_CurToneMapScale, m_CurToneMapScale );
+ }
+}
+
+void CMatRenderContextBase::ResetToneMappingScale(float sc)
+{
+ m_CurToneMapScale = sc;
+ SetToneMappingScaleLinear( Vector( m_CurToneMapScale, m_CurToneMapScale, m_CurToneMapScale ) );
+ m_LastSetToneMapScale = Vector( m_CurToneMapScale, m_CurToneMapScale, m_CurToneMapScale );
+ // mat_hdr_tonemapscale.SetValue(1.0f);
+ m_GoalToneMapScale = 1;
+}
+
+void CMatRenderContextBase::SetGoalToneMappingScale( float monoscale)
+{
+ Assert( IsFinite( monoscale ) );
+ if( IsFinite( monoscale ) )
+ {
+ m_GoalToneMapScale = monoscale;
+ }
+}
+
+Vector CMatRenderContextBase::GetToneMappingScaleLinear( void )
+{
+ if ( HardwareConfig()->GetHDRType() == HDR_TYPE_NONE )
+ return Vector( 1.0f, 1.0f, 1.0f );
+ else
+ return m_LastSetToneMapScale;
+}
+
+void CMatRenderContextBase::OnAsyncCreateTextureFromRenderTarget( ITexture* pSrcRt, const char** ppDstName, IAsyncTextureOperationReceiver* pRecipient )
+{
+ Assert( pSrcRt != NULL );
+ Assert( pRecipient != NULL );
+ Assert( ppDstName != NULL && *ppDstName != NULL);
+
+ // 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.
+ pSrcRt->AddRef();
+ pRecipient->AddRef();
+
+ // Also, need to allocate a copy of the string and use that one s.t. the caller doesn't have to worry about it.
+ char* pDstNameCopy = new char[ V_strlen( *ppDstName ) + 1 ];
+ V_strcpy( pDstNameCopy, *ppDstName );
+ ( *ppDstName ) = pDstNameCopy;
+}
+
+// Map and unmap a texture. The pRecipient->OnAsyncMapComplete is called when complete.
+void CMatRenderContextBase::OnAsyncMap( ITextureInternal* pTexToMap, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs )
+{
+ Assert( pTexToMap != NULL );
+ Assert( pRecipient != NULL );
+
+ pTexToMap->AddRef();
+ pRecipient->AddRef();
+}
+
+void CMatRenderContextBase::OnAsyncUnmap( ITextureInternal* pTexToUnmap )
+{
+ Assert( pTexToUnmap != NULL );
+
+ pTexToUnmap->AddRef();
+}
+
+void CMatRenderContextBase::OnAsyncCopyRenderTargetToStagingTexture( ITexture* pDst, ITexture* pSrc, IAsyncTextureOperationReceiver* pRecipient )
+{
+ Assert( pDst != NULL );
+ Assert( pSrc != NULL );
+ Assert( pRecipient != NULL );
+
+ pDst->AddRef();
+ pSrc->AddRef();
+ pRecipient->AddRef();
+}
+
+#undef g_pShaderAPI
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+CMatRenderContext::CMatRenderContext()
+{
+ g_FrameNum = 0;
+ m_pBatchIndices = NULL;
+ m_pBatchMesh = NULL;
+ m_pCurrentIndexBuffer = NULL;
+ m_pMorphRenderContext = NULL;
+ m_NonInteractiveMode = MATERIAL_NON_INTERACTIVE_MODE_NONE;
+}
+
+InitReturnVal_t CMatRenderContext::Init( CMaterialSystem *pMaterialSystem )
+{
+ InitReturnVal_t nRetVal = BaseClass::Init();
+ if ( nRetVal != INIT_OK )
+ return nRetVal;
+
+ m_pMaterialSystem = pMaterialSystem;
+
+ m_pBoundMorph = NULL;
+
+ // Create some lovely textures
+ m_pLocalCubemapTexture = TextureManager()->ErrorTexture();
+ m_pMorphRenderContext = g_pMorphMgr->AllocateRenderContext();
+
+ return INIT_OK;
+}
+
+void CMatRenderContext::Shutdown( )
+{
+ if ( m_pUserDefinedLightmap )
+ {
+ m_pUserDefinedLightmap->DecrementReferenceCount();
+ m_pUserDefinedLightmap = NULL;
+ }
+
+ if ( m_pMorphRenderContext )
+ {
+ g_pMorphMgr->FreeRenderContext( m_pMorphRenderContext );
+ m_pMorphRenderContext = NULL;
+ }
+
+ BaseClass::Shutdown();
+}
+
+void CMatRenderContext::OnReleaseShaderObjects()
+{
+ // alt-tab unbinds the morph
+ m_pBoundMorph = NULL;
+}
+
+#ifdef DX_TO_GL_ABSTRACTION
+void CMatRenderContext::DoStartupShaderPreloading( void )
+{
+ g_pShaderDevice->DoStartupShaderPreloading();
+}
+#endif
+
+void CMatRenderContext::TextureManagerUpdate()
+{
+ TextureManager()->Update();
+}
+
+
+inline IMaterialInternal *CMatRenderContext::GetMaterialInternal( MaterialHandle_t h ) const
+{
+ return GetMaterialSystem()->GetMaterialInternal( h );
+}
+
+inline IMaterialInternal *CMatRenderContext::GetDrawFlatMaterial()
+{
+ return GetMaterialSystem()->GetDrawFlatMaterial();
+}
+
+inline IMaterialInternal *CMatRenderContext::GetBufferClearObeyStencil( int i )
+{
+ return GetMaterialSystem()->GetBufferClearObeyStencil(i );
+}
+
+inline ShaderAPITextureHandle_t CMatRenderContext::GetFullbrightLightmapTextureHandle() const
+{
+ return GetMaterialSystem()->GetFullbrightLightmapTextureHandle();
+}
+
+inline ShaderAPITextureHandle_t CMatRenderContext::GetFullbrightBumpedLightmapTextureHandle() const
+{
+ return GetMaterialSystem()->GetFullbrightBumpedLightmapTextureHandle();
+}
+
+inline ShaderAPITextureHandle_t CMatRenderContext::GetBlackTextureHandle() const
+{
+ return GetMaterialSystem()->GetBlackTextureHandle();
+}
+
+inline ShaderAPITextureHandle_t CMatRenderContext::GetFlatNormalTextureHandle() const
+{
+ return GetMaterialSystem()->GetFlatNormalTextureHandle();
+}
+
+inline ShaderAPITextureHandle_t CMatRenderContext::GetGreyTextureHandle() const
+{
+ return GetMaterialSystem()->GetGreyTextureHandle();
+}
+
+inline ShaderAPITextureHandle_t CMatRenderContext::GetGreyAlphaZeroTextureHandle() const
+{
+ return GetMaterialSystem()->GetGreyAlphaZeroTextureHandle();
+}
+
+inline ShaderAPITextureHandle_t CMatRenderContext::GetWhiteTextureHandle() const
+{
+ return GetMaterialSystem()->GetWhiteTextureHandle();
+}
+
+inline const CMatLightmaps *CMatRenderContext::GetLightmaps() const
+{
+ return GetMaterialSystem()->GetLightmaps();
+}
+
+inline CMatLightmaps *CMatRenderContext::GetLightmaps()
+{
+ return GetMaterialSystem()->GetLightmaps();
+}
+
+inline ShaderAPITextureHandle_t CMatRenderContext::GetMaxDepthTextureHandle() const
+{
+ return GetMaterialSystem()->GetMaxDepthTextureHandle();
+}
+
+void CMatRenderContext::BeginRender()
+{
+#if 1 // Rick's optimization: not sure this is needed anymore
+ if ( GetMaterialSystem()->GetThreadMode() != MATERIAL_SINGLE_THREADED )
+ {
+ VPROF_INCREMENT_GROUP_COUNTER( "render/CMatBeginRender", COUNTER_GROUP_TELEMETRY, 1 );
+
+ TelemetrySetLockName( TELEMETRY_LEVEL1, (char const *)&g_MatSysMutex, "MatSysMutex" );
+
+ tmTryLock( TELEMETRY_LEVEL1, (char const *)&g_MatSysMutex, "BeginRender" );
+ g_MatSysMutex.Lock();
+ tmEndTryLock( TELEMETRY_LEVEL1, (char const *)&g_MatSysMutex, TMLR_SUCCESS );
+ tmSetLockState( TELEMETRY_LEVEL1, (char const *)&g_MatSysMutex, TMLS_LOCKED, "BeginRender" );
+ }
+#endif
+}
+
+void CMatRenderContext::EndRender()
+{
+#if 1 // Rick's optimization: not sure this is needed anymore
+ if ( GetMaterialSystem()->GetThreadMode() != MATERIAL_SINGLE_THREADED )
+ {
+ g_MatSysMutex.Unlock();
+ tmSetLockState( TELEMETRY_LEVEL1, (char const *)&g_MatSysMutex, TMLS_RELEASED, "EndRender" );
+ }
+#endif
+}
+
+void CMatRenderContext::Flush( bool flushHardware )
+{
+ VPROF( "CMatRenderContextBase::Flush" );
+
+ g_pShaderAPI->FlushBufferedPrimitives();
+ if ( IsPC() && flushHardware )
+ {
+ g_pShaderAPI->FlushBufferedPrimitives();
+ }
+}
+
+bool CMatRenderContext::TestMatrixSync( MaterialMatrixMode_t mode )
+{
+ if ( !ShouldValidateMatrices() )
+ {
+ return true;
+ }
+
+ VMatrix transposeMatrix, matrix;
+ g_pShaderAPI->GetMatrix( mode, (float*)transposeMatrix.m );
+ MatrixTranspose( transposeMatrix, matrix );
+
+ ValidateMatrices( matrix, m_MatrixStacks[mode].Top().matrix );
+
+ return true;
+}
+
+void CMatRenderContext::MatrixMode( MaterialMatrixMode_t mode )
+{
+ CMatRenderContextBase::MatrixMode( mode );
+ g_pShaderAPI->MatrixMode( mode );
+ if ( ShouldValidateMatrices() )
+ {
+ TestMatrixSync( mode );
+ }
+
+}
+void CMatRenderContext::PushMatrix()
+{
+ if ( ShouldValidateMatrices() )
+ {
+ TestMatrixSync( m_MatrixMode );
+ }
+
+ CMatRenderContextBase::PushMatrix();
+ g_pShaderAPI->PushMatrix();
+
+ if ( ShouldValidateMatrices() )
+ {
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::PopMatrix()
+{
+ if ( ShouldValidateMatrices() )
+ {
+ TestMatrixSync( m_MatrixMode );
+ }
+
+ CMatRenderContextBase::PopMatrix();
+ g_pShaderAPI->PopMatrix();
+
+ if ( ShouldValidateMatrices() )
+ {
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::LoadMatrix( const VMatrix& matrix )
+{
+ CMatRenderContextBase::LoadMatrix( matrix );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ VMatrix transposeMatrix;
+ MatrixTranspose( matrix, transposeMatrix );
+ g_pShaderAPI->LoadMatrix( transposeMatrix.Base() );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::LoadMatrix( const matrix3x4_t& matrix )
+{
+ CMatRenderContextBase::LoadMatrix( matrix );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ VMatrix transposeMatrix;
+ MatrixTranspose( VMatrix(matrix), transposeMatrix );
+ g_pShaderAPI->LoadMatrix( transposeMatrix.Base() );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::MultMatrix( const VMatrix& matrix )
+{
+ CMatRenderContextBase::MultMatrix( matrix );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ VMatrix transposeMatrix;
+ MatrixTranspose( matrix, transposeMatrix );
+ g_pShaderAPI->MultMatrix( transposeMatrix.Base() );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::MultMatrix( const matrix3x4_t& matrix )
+{
+ CMatRenderContextBase::MultMatrix( VMatrix( matrix ) );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ VMatrix transposeMatrix;
+ MatrixTranspose( VMatrix(matrix), transposeMatrix );
+ g_pShaderAPI->MultMatrix( transposeMatrix.Base() );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::MultMatrixLocal( const VMatrix& matrix )
+{
+ CMatRenderContextBase::MultMatrixLocal( matrix );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ VMatrix transposeMatrix;
+ MatrixTranspose( matrix, transposeMatrix );
+ g_pShaderAPI->MultMatrixLocal( transposeMatrix.Base() );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::MultMatrixLocal( const matrix3x4_t& matrix )
+{
+ CMatRenderContextBase::MultMatrixLocal( VMatrix( matrix ) );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ VMatrix transposeMatrix;
+ MatrixTranspose( VMatrix(matrix), transposeMatrix );
+ g_pShaderAPI->MultMatrixLocal( transposeMatrix.Base() );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::LoadIdentity()
+{
+ CMatRenderContextBase::LoadIdentity();
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ g_pShaderAPI->LoadIdentity();
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::Ortho( double left, double top, double right, double bottom, double zNear, double zFar )
+{
+ CMatRenderContextBase::Ortho( left, top, right, bottom, zNear, zFar );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ g_pShaderAPI->Ortho( left, top, right, bottom, zNear, zFar );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::PerspectiveX( double flFovX, double flAspect, double flZNear, double flZFar )
+{
+ CMatRenderContextBase::PerspectiveX( flFovX, flAspect, flZNear, flZFar );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ g_pShaderAPI->PerspectiveX( flFovX, flAspect, flZNear, flZFar );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::PerspectiveOffCenterX( double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right )
+{
+ CMatRenderContextBase::PerspectiveOffCenterX( flFovX, flAspect, flZNear, flZFar, bottom, top, left, right );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ g_pShaderAPI->PerspectiveOffCenterX( flFovX, flAspect, flZNear, flZFar, bottom, top, left, right );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::PickMatrix( int x, int y, int nWidth, int nHeight )
+{
+ CMatRenderContextBase::PickMatrix( x, y, nWidth, nHeight );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ g_pShaderAPI->PickMatrix( x, y, nWidth, nHeight );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::Rotate( float flAngle, float x, float y, float z )
+{
+ CMatRenderContextBase::Rotate( flAngle, x, y, z );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ g_pShaderAPI->Rotate( flAngle, x, y, z );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::Translate( float x, float y, float z )
+{
+ CMatRenderContextBase::Translate( x, y, z );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ g_pShaderAPI->Translate( x, y, z );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::Scale( float x, float y, float z )
+{
+ CMatRenderContextBase::Scale( x, y, z );
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ g_pShaderAPI->Scale( x, y, z );
+ TestMatrixSync( m_MatrixMode );
+ }
+}
+
+void CMatRenderContext::GetMatrix( MaterialMatrixMode_t matrixMode, VMatrix *pMatrix )
+{
+ CMatRenderContextBase::GetMatrix( matrixMode, pMatrix );
+
+ ForceSync();
+ if ( ShouldValidateMatrices() )
+ {
+ VMatrix testMatrix;
+ VMatrix transposeMatrix;
+ g_pShaderAPI->GetMatrix( matrixMode, (float*)transposeMatrix.m );
+ MatrixTranspose( transposeMatrix, testMatrix );
+
+ ValidateMatrices( testMatrix, *pMatrix );
+ }
+}
+
+void CMatRenderContext::GetMatrix( MaterialMatrixMode_t matrixMode, matrix3x4_t *pMatrix )
+{
+ if ( !ShouldValidateMatrices() )
+ {
+ CMatRenderContextBase::GetMatrix( matrixMode, pMatrix );
+ }
+ else
+ {
+ VMatrix matrix;
+ CMatRenderContext::GetMatrix( matrixMode, &matrix );
+ *pMatrix = matrix.As3x4();
+ }
+}
+
+void CMatRenderContext::SyncMatrices()
+{
+ if ( !ShouldValidateMatrices() && AllowLazyMatrixSync() )
+ {
+ for( int i = 0; i < NUM_MATRIX_MODES; i++ )
+ {
+ MatrixStackItem_t &top = m_MatrixStacks[i].Top();
+ if ( top.flags & MSF_DIRTY )
+ {
+ g_pShaderAPI->MatrixMode( (MaterialMatrixMode_t)i );
+ if ( !( top.flags & MSF_IDENTITY ) )
+ {
+ VMatrix transposeTop;
+ MatrixTranspose( top.matrix, transposeTop );
+ g_pShaderAPI->LoadMatrix( transposeTop.Base() );
+ }
+ else
+ {
+ g_pShaderAPI->LoadIdentity();
+ }
+
+ top.flags &= ~MSF_DIRTY;
+ }
+ }
+ }
+}
+
+void CMatRenderContext::ForceSyncMatrix( MaterialMatrixMode_t mode )
+{
+ MatrixStackItem_t &top = m_MatrixStacks[mode].Top();
+ if ( top.flags & MSF_DIRTY )
+ {
+ bool bSetMode = ( m_MatrixMode != mode );
+ if ( bSetMode )
+ {
+ g_pShaderAPI->MatrixMode( (MaterialMatrixMode_t)mode );
+ }
+
+ if ( !( top.flags & MSF_IDENTITY ) )
+ {
+ VMatrix transposeTop;
+ MatrixTranspose( top.matrix, transposeTop );
+ g_pShaderAPI->LoadMatrix( transposeTop.Base() );
+ }
+ else
+ {
+ g_pShaderAPI->LoadIdentity();
+ }
+
+ if ( bSetMode )
+ {
+ g_pShaderAPI->MatrixMode( (MaterialMatrixMode_t)mode );
+ }
+
+ top.flags &= ~MSF_DIRTY;
+ }
+}
+
+void CMatRenderContext::SyncMatrix( MaterialMatrixMode_t mode )
+{
+ if ( !ShouldValidateMatrices() && AllowLazyMatrixSync() )
+ {
+ ForceSyncMatrix( mode );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Swap buffers
+//-----------------------------------------------------------------------------
+void CMatRenderContext::SwapBuffers()
+{
+ g_pMorphMgr->AdvanceFrame();
+ g_pOcclusionQueryMgr->AdvanceFrame();
+ g_pShaderDevice->Present();
+
+#ifdef _X360
+ if ( s_bDirtyDisk )
+ {
+ SpinPresent();
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Clears the render data after we're done with it
+//-----------------------------------------------------------------------------
+void CMatRenderContext::OnRenderDataUnreferenced()
+{
+ MarkRenderDataUnused( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Custom clip planes
+//-----------------------------------------------------------------------------
+void CMatRenderContext::PushCustomClipPlane( const float *pPlane )
+{
+ PlaneStackElement psePlane;
+ memcpy( psePlane.fValues, pPlane, sizeof( float ) * 4 );
+ psePlane.bHack_IsHeightClipPlane = false;
+ m_CustomClipPlanes.AddToTail( psePlane ); //we're doing this as a UtlVector so height clip planes never change their cached index
+ ApplyCustomClipPlanes();
+}
+
+void CMatRenderContext::PopCustomClipPlane( void )
+{
+ Assert( m_CustomClipPlanes.Count() );
+
+ //remove the endmost non-height plane found
+ int i;
+ for( i = m_CustomClipPlanes.Count(); --i >= 0; )
+ {
+ if( m_CustomClipPlanes[i].bHack_IsHeightClipPlane == false )
+ {
+ m_CustomClipPlanes.Remove(i);
+ break;
+ }
+ }
+ Assert( i != -1 ); //only the height clip plane was found, which means this pop had no associated push
+ ApplyCustomClipPlanes();
+}
+
+void CMatRenderContext::ApplyCustomClipPlanes( void )
+{
+ int iMaxClipPlanes = HardwareConfig()->MaxUserClipPlanes();
+ int iCustomPlanes;
+
+ if( m_bEnableClipping )
+ iCustomPlanes = m_CustomClipPlanes.Count();
+ else
+ iCustomPlanes = 0;
+
+ float fFakePlane[4];
+ unsigned int iFakePlaneVal = 0xFFFFFFFF;
+ fFakePlane[0] = fFakePlane[1] = fFakePlane[2] = fFakePlane[3] = *((float *)&iFakePlaneVal);
+
+ SyncMatrices();
+
+ if( iMaxClipPlanes >= 1 && !HardwareConfig()->UseFastClipping() )
+ {
+ //yay, we get to be the cool clipping club
+ if( iMaxClipPlanes >= iCustomPlanes )
+ {
+ int i;
+ for( i = 0; i < iCustomPlanes; ++i )
+ {
+ g_pShaderAPI->SetClipPlane( i, m_CustomClipPlanes[i].fValues );
+ g_pShaderAPI->EnableClipPlane( i, true );
+ }
+ for( ; i < iMaxClipPlanes; ++i ) //disable unused planes
+ {
+ g_pShaderAPI->EnableClipPlane( i, false );
+ g_pShaderAPI->SetClipPlane( i, fFakePlane );
+ }
+ }
+ else
+ {
+ int iCustomPlaneOffset = iCustomPlanes - iMaxClipPlanes;
+
+ //can't enable them all
+ for( int i = iCustomPlaneOffset; i < iCustomPlanes; ++i )
+ {
+ g_pShaderAPI->SetClipPlane( i % iMaxClipPlanes, m_CustomClipPlanes[i].fValues );
+ g_pShaderAPI->EnableClipPlane( i % iMaxClipPlanes, true );
+ }
+ }
+ }
+ else
+ {
+ //hmm, at most we can make 1 clip plane work
+ if( iCustomPlanes == 0 )
+ {
+ //no planes at all
+ g_pShaderAPI->EnableFastClip( false );
+ g_pShaderAPI->SetFastClipPlane( fFakePlane );
+ }
+ else
+ {
+ //we have to wire the topmost plane into the fast clipping scheme
+ g_pShaderAPI->EnableFastClip( true );
+ g_pShaderAPI->SetFastClipPlane( m_CustomClipPlanes[iCustomPlanes - 1].fValues );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates/destroys morph data associated w/ a particular material
+//-----------------------------------------------------------------------------
+IMorph *CMatRenderContext::CreateMorph( MorphFormat_t format, const char *pDebugName )
+{
+ Assert( format != 0 );
+ IMorphInternal *pMorph = g_pMorphMgr->CreateMorph( );
+ pMorph->Init( format, pDebugName );
+ return pMorph;
+}
+
+void CMatRenderContext::DestroyMorph( IMorph *pMorph )
+{
+ g_pMorphMgr->DestroyMorph( static_cast<IMorphInternal*>(pMorph) );
+}
+
+void CMatRenderContext::BindMorph( IMorph *pMorph )
+{
+ IMorphInternal *pMorphInternal = static_cast<IMorphInternal*>(pMorph);
+
+ if ( m_pBoundMorph != pMorphInternal )
+ {
+ g_pShaderAPI->FlushBufferedPrimitives();
+
+ m_pBoundMorph = pMorphInternal;
+
+ bool bEnableHWMorph = false;
+ if ( pMorphInternal == MATERIAL_MORPH_DECAL )
+ {
+ bEnableHWMorph = true;
+ }
+ else if ( pMorphInternal )
+ {
+ bEnableHWMorph = true;
+ pMorphInternal->Bind( m_pMorphRenderContext );
+ }
+ g_pShaderAPI->EnableHWMorphing( bEnableHWMorph );
+ }
+}
+
+IMesh* CMatRenderContext::GetDynamicMesh( bool buffered, IMesh* pVertexOverride, IMesh* pIndexOverride, IMaterial *pAutoBind )
+{
+ VPROF_ASSERT_ACCOUNTED( "CMatRenderContext::GetDynamicMesh" );
+ if( pAutoBind )
+ {
+ Bind( pAutoBind, NULL );
+ }
+
+ if ( pVertexOverride )
+ {
+ if ( CompressionType( pVertexOverride->GetVertexFormat() ) != VERTEX_COMPRESSION_NONE )
+ {
+ // UNDONE: support compressed dynamic meshes if needed (pro: less VB memory, con: time spent compressing)
+ DebuggerBreak();
+ return NULL;
+ }
+ }
+
+ // For anything more than 1 bone, imply the last weight from the 1 - the sum of the others.
+ int nCurrentBoneCount = GetCurrentNumBones();
+ Assert( nCurrentBoneCount <= 4 );
+ if ( nCurrentBoneCount > 1 )
+ {
+ --nCurrentBoneCount;
+ }
+
+ return g_pShaderAPI->GetDynamicMesh( GetCurrentMaterialInternal(), nCurrentBoneCount,
+ buffered, pVertexOverride, pIndexOverride);
+}
+
+IMesh* CMatRenderContext::GetDynamicMeshEx( VertexFormat_t vertexFormat, bool bBuffered, IMesh* pVertexOverride, IMesh* pIndexOverride, IMaterial *pAutoBind )
+{
+ VPROF_ASSERT_ACCOUNTED( "CMatRenderContext::GetDynamicMesh" );
+ if( pAutoBind )
+ {
+ Bind( pAutoBind, NULL );
+ }
+
+ if ( pVertexOverride )
+ {
+ if ( CompressionType( pVertexOverride->GetVertexFormat() ) != VERTEX_COMPRESSION_NONE )
+ {
+ // UNDONE: support compressed dynamic meshes if needed (pro: less VB memory, con: time spent compressing)
+ DebuggerBreak();
+ return NULL;
+ }
+ }
+
+ // For anything more than 1 bone, imply the last weight from the 1 - the sum of the others.
+ // FIXME: this seems wrong - in common_vs_fxc.h, we only infer the last weight if we have 3 (not 2)
+ int nCurrentBoneCount = GetCurrentNumBones();
+ Assert( nCurrentBoneCount <= 4 );
+ if ( nCurrentBoneCount > 1 )
+ {
+ --nCurrentBoneCount;
+ }
+
+ return g_pShaderAPI->GetDynamicMeshEx( GetCurrentMaterialInternal(), vertexFormat, nCurrentBoneCount,
+ bBuffered, pVertexOverride, pIndexOverride );
+}
+
+
+//-----------------------------------------------------------------------------
+// Deals with depth range
+//-----------------------------------------------------------------------------
+void CMatRenderContext::DepthRange( float zNear, float zFar )
+{
+ m_Viewport.m_flMinZ = zNear;
+ m_Viewport.m_flMaxZ = zFar;
+ g_pShaderAPI->SetViewports( 1, &m_Viewport );
+}
+
+
+//-----------------------------------------------------------------------------
+// Private utility function to actually commit the top of the RT/Viewport stack
+// to the device. Only called by the push and pop routines above.
+//-----------------------------------------------------------------------------
+void CMatRenderContext::CommitRenderTargetAndViewport( void )
+{
+ Assert( m_RenderTargetStack.Count() > 0 );
+
+ const RenderTargetStackElement_t &element = m_RenderTargetStack.Top( );
+
+ for( int rt=0; rt<NELEMS(element.m_pRenderTargets); rt++ )
+ {
+ // If we're dealing with the back buffer
+ if ( element.m_pRenderTargets[rt] == NULL )
+ {
+ g_pShaderAPI->SetRenderTargetEx(rt); // No texture parameter here indicates back buffer
+
+ if ( IsPC() )
+ {
+ Assert( ImageLoader::SizeInBytes( g_pShaderDevice->GetBackBufferFormat() ) <= 4 );
+ g_pShaderAPI->EnableLinearColorSpaceFrameBuffer( false );
+ }
+
+ if (rt == 0) // the first rt sets the viewport
+ {
+ // If either dimension is negative, set to full bounds of back buffer
+ if ( (element.m_nViewW < 0) || (element.m_nViewH < 0) )
+ {
+ m_Viewport.m_nTopLeftX = 0;
+ m_Viewport.m_nTopLeftY = 0;
+ g_pShaderAPI->GetBackBufferDimensions( m_Viewport.m_nWidth, m_Viewport.m_nHeight );
+ g_pShaderAPI->SetViewports( 1, &m_Viewport );
+ }
+ else // use the bounds in the element
+ {
+ m_Viewport.m_nTopLeftX = element.m_nViewX;
+ m_Viewport.m_nTopLeftY = element.m_nViewY;
+ m_Viewport.m_nWidth = element.m_nViewW;
+ m_Viewport.m_nHeight = element.m_nViewH;
+ g_pShaderAPI->SetViewports( 1, &m_Viewport );
+ }
+ }
+ }
+ else // We're dealing with a texture
+ {
+ ITextureInternal *pTexInt = static_cast<ITextureInternal*>(element.m_pRenderTargets[rt]);
+ pTexInt->SetRenderTarget( rt, element.m_pDepthTexture );
+
+ if (rt == 0)
+ {
+ if ( IsPC() )
+ {
+ if( element.m_pRenderTargets[rt]->GetImageFormat() == IMAGE_FORMAT_RGBA16161616F )
+ {
+ g_pShaderAPI->EnableLinearColorSpaceFrameBuffer( true );
+ }
+ else
+ {
+ g_pShaderAPI->EnableLinearColorSpaceFrameBuffer( false );
+ }
+ }
+
+ // If either dimension is negative, set to full bounds of target
+ if ( (element.m_nViewW < 0) || (element.m_nViewH < 0) )
+ {
+ m_Viewport.m_nTopLeftX = 0;
+ m_Viewport.m_nTopLeftY = 0;
+ m_Viewport.m_nWidth = element.m_pRenderTargets[rt]->GetActualWidth();
+ m_Viewport.m_nHeight = element.m_pRenderTargets[rt]->GetActualHeight();
+ g_pShaderAPI->SetViewports( 1, &m_Viewport );
+ }
+ else // use the bounds passed in
+ {
+ m_Viewport.m_nTopLeftX = element.m_nViewX;
+ m_Viewport.m_nTopLeftY = element.m_nViewY;
+ m_Viewport.m_nWidth = element.m_nViewW;
+ m_Viewport.m_nHeight = element.m_nViewH;
+ g_pShaderAPI->SetViewports( 1, &m_Viewport );
+ }
+ }
+ }
+ }
+}
+
+
+void CMatRenderContext::SetFrameBufferCopyTexture( ITexture *pTexture, int textureIndex )
+{
+ if( textureIndex < 0 || textureIndex > MAX_FB_TEXTURES )
+ {
+ Assert( 0 );
+ return;
+ }
+ if( m_pCurrentFrameBufferCopyTexture[textureIndex] != pTexture )
+ {
+ g_pShaderAPI->FlushBufferedPrimitives();
+ }
+ // FIXME: Do I need to increment/decrement ref counts here, or assume that the app is going to do it?
+ m_pCurrentFrameBufferCopyTexture[textureIndex] = pTexture;
+}
+
+void CMatRenderContext::BindLocalCubemap( ITexture *pTexture )
+{
+ ITexture *pPreviousTexture = m_pLocalCubemapTexture;
+
+ CMatRenderContextBase::BindLocalCubemap( pTexture );
+
+ if( m_pLocalCubemapTexture != pPreviousTexture )
+ {
+ g_pShaderAPI->FlushBufferedPrimitives();
+ }
+}
+
+void CMatRenderContext::SetNonInteractivePacifierTexture( ITexture *pTexture, float flNormalizedX, float flNormalizedY, float flNormalizedSize )
+{
+ m_pNonInteractivePacifier.Init( pTexture );
+ m_flNormalizedX = flNormalizedX;
+ m_flNormalizedY = flNormalizedY;
+ m_flNormalizedSize = flNormalizedSize;
+}
+
+void CMatRenderContext::SetNonInteractiveTempFullscreenBuffer( ITexture *pTexture, MaterialNonInteractiveMode_t mode )
+{
+ if ( mode != MATERIAL_NON_INTERACTIVE_MODE_NONE )
+ {
+ m_pNonInteractiveTempFullscreenBuffer[mode].Init( pTexture );
+ }
+}
+
+void CMatRenderContext::RefreshFrontBufferNonInteractive()
+{
+ g_pShaderDevice->RefreshFrontBufferNonInteractive();
+#ifdef _X360
+ if ( s_bDirtyDisk )
+ {
+ if ( m_NonInteractiveMode == MATERIAL_NON_INTERACTIVE_MODE_NONE )
+ {
+ SpinPresent();
+ }
+ else
+ {
+ while ( true )
+ {
+ g_pShaderDevice->RefreshFrontBufferNonInteractive();
+ }
+ }
+ }
+#endif
+}
+
+void CMatRenderContext::EnableNonInteractiveMode( MaterialNonInteractiveMode_t mode )
+{
+ m_NonInteractiveMode = mode;
+ if ( mode == MATERIAL_NON_INTERACTIVE_MODE_NONE )
+ {
+ g_pShaderDevice->EnableNonInteractiveMode( mode );
+ }
+ else
+ {
+ ShaderNonInteractiveInfo_t info;
+ info.m_flNormalizedX = m_flNormalizedX;
+ info.m_flNormalizedY = m_flNormalizedY;
+ info.m_flNormalizedSize = m_flNormalizedSize;
+
+ ITextureInternal *pTexInternal = static_cast<ITextureInternal*>( (ITexture*)m_pNonInteractiveTempFullscreenBuffer[mode] );
+ info.m_hTempFullscreenTexture = pTexInternal ?
+ pTexInternal->GetTextureHandle(0) : INVALID_SHADERAPI_TEXTURE_HANDLE;
+ ITextureInternal *pTexPacifierInternal = static_cast<ITextureInternal*>( (ITexture*)m_pNonInteractivePacifier );
+ info.m_nPacifierCount = pTexPacifierInternal ? pTexPacifierInternal->GetNumAnimationFrames() : 0;
+ for ( int i = 0; i < info.m_nPacifierCount; ++i )
+ {
+ info.m_pPacifierTextures[i] = pTexPacifierInternal->GetTextureHandle( i );
+ }
+ g_pShaderDevice->EnableNonInteractiveMode( mode, &info );
+ }
+}
+
+void CMatRenderContext::SetRenderTargetEx( int nRenderTargetID, ITexture *pNewTarget )
+{
+ // Verify valid top of RT stack
+ Assert ( m_RenderTargetStack.Count() > 0 );
+
+ // Grab the old target
+ ITexture *pOldTarget = m_RenderTargetStack.Top().m_pRenderTargets[nRenderTargetID];
+
+ CMatRenderContextBase::SetRenderTargetEx( nRenderTargetID, pNewTarget );
+
+ // If we're actually changing render targets
+ if( pNewTarget != pOldTarget )
+ {
+ // If we're going to render to the back buffer
+ if ( pNewTarget == NULL )
+ {
+ if ( nRenderTargetID == 0) // reset viewport on set of rt 0
+ {
+ m_Viewport.m_nTopLeftX = 0;
+ m_Viewport.m_nTopLeftY = 0;
+ g_pShaderAPI->GetBackBufferDimensions( m_Viewport.m_nWidth, m_Viewport.m_nHeight );
+ g_pShaderAPI->SetViewports( 1, &m_Viewport );
+ }
+ g_pShaderAPI->SetRenderTargetEx( nRenderTargetID ); // No parameter here indicates back buffer
+ }
+ else
+ {
+ // If we're going to render to a texture
+ // Make sure the texture is a render target...
+ bool reset = true;
+ if (nRenderTargetID==0)
+ {
+ // reset vp on change of rt#0
+ m_Viewport.m_nTopLeftX = 0;
+ m_Viewport.m_nTopLeftY = 0;
+ m_Viewport.m_nWidth = pNewTarget->GetActualWidth();
+ m_Viewport.m_nHeight = pNewTarget->GetActualHeight();
+ g_pShaderAPI->SetViewports( 1, &m_Viewport );
+ }
+ ITextureInternal *pTexInt = static_cast<ITextureInternal*>(pNewTarget);
+ if ( pTexInt )
+ {
+ reset = !pTexInt->SetRenderTarget( nRenderTargetID );
+ if ( reset )
+ {
+ g_pShaderAPI->SetRenderTargetEx( nRenderTargetID );
+ }
+ }
+
+ if( pNewTarget && pNewTarget->GetImageFormat() == IMAGE_FORMAT_RGBA16161616F )
+ {
+ g_pShaderAPI->EnableLinearColorSpaceFrameBuffer( true );
+ }
+ else
+ {
+ g_pShaderAPI->EnableLinearColorSpaceFrameBuffer( false );
+ }
+ }
+ }
+ CommitRenderTargetAndViewport();
+}
+
+
+void CMatRenderContext::GetRenderTargetDimensions( int &width, int &height ) const
+{
+ // Target at top of stack
+ ITexture *pTOS = m_RenderTargetStack.Top().m_pRenderTargets[0];
+
+ // If top of stack isn't the back buffer, get dimensions from the texture
+ if ( pTOS != NULL )
+ {
+ width = pTOS->GetActualWidth();
+ height = pTOS->GetActualHeight();
+ }
+ else // otherwise, get them from the shader API
+ {
+ g_pShaderAPI->GetBackBufferDimensions( width, height );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// What are the lightmap dimensions?
+//-----------------------------------------------------------------------------
+void CMatRenderContext::GetLightmapDimensions( int *w, int *h )
+{
+ *w = GetMaterialSystem()->GetLightmapWidth( GetLightmapPage() );
+ *h = GetMaterialSystem()->GetLightmapHeight( GetLightmapPage() );
+}
+
+void CMatRenderContext::DrawScreenSpaceQuad( IMaterial* pMaterial )
+{
+ // Despite saying we render a full screen quad, this actually renders a single triangle
+ // that covers the whole screen.
+ int w, h;
+
+ GetRenderTargetDimensions( w, h );
+ if ( ( w == 0 ) || ( h == 0 ) )
+ return;
+
+ // DX9 disagrees about (0, 0) in a render target and (0, 0) in the texture.
+ // Fix that here by doing a half-pixel offset for the pixel.
+ // Because we are working in clip space which is 2 units across, the adjustment factor is 1.
+ float flOffsetW = 1.0f / w;
+ float flOffsetH = 1.0f / h;
+
+ Bind( pMaterial );
+ IMesh* pMesh = GetDynamicMesh( true );
+
+ CMeshBuilder meshBuilder;;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 1 );
+
+ enum { TL, BL, TR, COORDS_COUNT };
+
+ struct CoordSSQ_t
+ {
+ float x, y;
+ float u, v;
+ };
+
+ CoordSSQ_t coords[] = {
+ { -1.0f - 1.0f * flOffsetW, 1.0f + 1.0f * flOffsetH, 0.0f, 0.0f }, // TL
+ { -1.0f - 1.0f * flOffsetW, -3.0f + 1.0f * flOffsetH, 0.0f, 2.0f }, // BL
+ { 3.0f - 1.0f * flOffsetW, 1.0f + 1.0f * flOffsetH, 2.0f, 0.0f }, // TR
+ };
+
+ static_assert( ARRAYSIZE( coords ) == COORDS_COUNT, "Unexpected number of coords in triangle, should match enum." );
+
+ MatrixMode( MATERIAL_VIEW );
+ PushMatrix();
+ LoadIdentity();
+
+ MatrixMode( MATERIAL_PROJECTION );
+ PushMatrix();
+ LoadIdentity();
+
+ for ( int i = 0; i < COORDS_COUNT; ++i )
+ {
+ meshBuilder.Position3f( coords[ i ].x, coords[ i ].y, 0.0f );
+ meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
+ meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
+ meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
+ meshBuilder.TexCoord2f( 0, coords[ i ].u, coords[ i ].v );
+
+ meshBuilder.AdvanceVertex();
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+
+ MatrixMode( MATERIAL_VIEW );
+ PopMatrix();
+
+ MatrixMode( MATERIAL_PROJECTION );
+ PopMatrix();
+}
+
+void CMatRenderContext::DrawScreenSpaceRectangle(
+ IMaterial *pMaterial,
+ int destx, int desty,
+ int width, int height,
+ float src_texture_x0, float src_texture_y0, // which texel you want to appear at
+ // destx/y
+ float src_texture_x1, float src_texture_y1, // which texel you want to appear at
+ // destx+width-1, desty+height-1
+ int src_texture_width, int src_texture_height, // needed for fixup
+ void *pClientRenderable,
+ int nXDice, int nYDice ) // Amount to tessellate the quad
+{
+ pMaterial = ((IMaterialInternal *)pMaterial)->GetRealTimeVersion();
+
+ ::DrawScreenSpaceRectangle( pMaterial, destx, desty, width, height,
+ src_texture_x0, src_texture_y0, src_texture_x1, src_texture_y1,
+ src_texture_width, src_texture_height, pClientRenderable, nXDice, nYDice );
+ return;
+}
+
+static int CompareVertexFormats( VertexFormat_t Fmt1, VertexFormat_t Fmt2 )
+{
+ if ( Fmt1 != Fmt2 )
+ {
+ if ( Fmt1 > Fmt2 )
+ return 1;
+ else
+ return -1;
+ }
+ else
+ return 0;
+}
+
+int CMatRenderContext::CompareMaterialCombos( IMaterial *pMaterial1, IMaterial *pMaterial2, int lightMapID1, int lightMapID2 )
+{
+ pMaterial1 = ((IMaterialInternal *)pMaterial1)->GetRealTimeVersion(); //always work with the real time version of materials internally.
+ pMaterial2 = ((IMaterialInternal *)pMaterial2)->GetRealTimeVersion(); //always work with the real time version of materials internally.
+
+ IMaterialInternal *pMat1 = (IMaterialInternal *)pMaterial1;
+ IMaterialInternal *pMat2 = (IMaterialInternal *)pMaterial2;
+ ShaderRenderState_t *pState1 = pMat1->GetRenderState();
+ ShaderRenderState_t *pState2 = pMat2->GetRenderState();
+ int dPass = pState2->m_pSnapshots->m_nPassCount - pState1->m_pSnapshots->m_nPassCount;
+ if ( dPass )
+ return dPass;
+
+ if ( pState1->m_pSnapshots->m_nPassCount > 1 )
+ {
+ int dFormat = CompareVertexFormats( pMat1->GetVertexFormat(), pMat2->GetVertexFormat() );
+ if ( dFormat )
+ return dFormat;
+ }
+
+ for ( int i = 0; i < pState1->m_pSnapshots->m_nPassCount; i++ )
+ {
+ // UNDONE: Compare snapshots in the shaderapi?
+ int dSnapshot = pState1->m_pSnapshots->m_Snapshot[i] - pState2->m_pSnapshots->m_Snapshot[i];
+ if ( dSnapshot )
+ {
+ dSnapshot = g_pShaderAPI->CompareSnapshots( pState1->m_pSnapshots->m_Snapshot[i], pState2->m_pSnapshots->m_Snapshot[i] );
+ if ( dSnapshot )
+ return dSnapshot;
+ }
+ }
+
+ int dFormat = CompareVertexFormats( pMat1->GetVertexFormat(), pMat2->GetVertexFormat() );
+ if ( dFormat )
+ return dFormat;
+
+ IMaterialVar **pParams1 = pMat1->GetShaderParams();
+ IMaterialVar **pParams2 = pMat2->GetShaderParams();
+ int nParams1 = pMat1->ShaderParamCount();
+ int nParams2 = pMat2->ShaderParamCount();
+ int nBaseTexParamType1 = pParams1 && nParams1 > BASETEXTURE ? pParams1[BASETEXTURE]->GetType() : -1;
+ int nBaseTexParamType2 = pParams2 && nParams2 > BASETEXTURE ? pParams2[BASETEXTURE]->GetType() : -1;
+ if( nBaseTexParamType1 == MATERIAL_VAR_TYPE_TEXTURE || nBaseTexParamType2 == MATERIAL_VAR_TYPE_TEXTURE )
+ {
+ if( nBaseTexParamType1 != nBaseTexParamType2 )
+ {
+ return nBaseTexParamType2 - nBaseTexParamType1;
+ }
+ int dBaseTexture = Q_stricmp( pParams1[BASETEXTURE]->GetTextureValue()->GetName(), pParams2[BASETEXTURE]->GetTextureValue()->GetName() );
+ if ( dBaseTexture )
+ return dBaseTexture;
+ }
+
+ int dLightmap = lightMapID1 - lightMapID2;
+ if ( dLightmap )
+ return dLightmap;
+
+ return (int)pMat1 - (int)pMat2;
+}
+
+
+void CMatRenderContext::Bind( IMaterial *iMaterial, void *proxyData )
+{
+ if ( !iMaterial )
+ {
+ if ( !g_pErrorMaterial )
+ return;
+ Warning( "Programming error: CMatRenderContext::Bind: NULL material\n" );
+ iMaterial = g_pErrorMaterial;
+ }
+ else
+ {
+ iMaterial = iMaterial->CheckProxyReplacement( proxyData );
+ }
+
+ IMaterialInternal *material = static_cast<IMaterialInternal *>( iMaterial );
+ material = material->GetRealTimeVersion(); //always work with the real time versions of materials internally
+ if ( material->GetReferenceCount() <= 0 )
+ {
+ static ConVarRef matTextureListConVar( "mat_texture_list" );
+ static ConVarRef matShowWaterTextureConVar( "mat_showwatertextures" );
+
+ if ( ( !matTextureListConVar.IsValid() || !matTextureListConVar.GetBool() ) &&
+ ( !matShowWaterTextureConVar.IsValid() || !matShowWaterTextureConVar.GetBool() ))
+ {
+ Warning( "Material %s has bad reference count %d when being bound\n", material->GetName(), material->GetReferenceCount() );
+ // The usual solution for this for global materials that really don't need refcounting is to do material->AddRef();
+ Assert( 0 );
+ iMaterial = g_pErrorMaterial;
+ }
+ }
+
+ if (g_config.bDrawFlat && !material->NoDebugOverride())
+ {
+ material = static_cast<IMaterialInternal *>( GetDrawFlatMaterial() );
+ }
+
+ CMatRenderContextBase::Bind( iMaterial, proxyData );
+
+ // We've always gotta call the bind proxy
+ SyncMatrices();
+ if ( GetMaterialSystem()->GetThreadMode() == MATERIAL_SINGLE_THREADED )
+ {
+ GetCurrentMaterialInternal()->CallBindProxy( proxyData );
+ }
+ g_pShaderAPI->Bind( GetCurrentMaterialInternal() );
+}
+
+void CMatRenderContext::CopyRenderTargetToTextureEx( ITexture *pTexture, int nRenderTargetID, Rect_t *pSrcRect, Rect_t *pDstRect )
+{
+ if ( !pTexture )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ GetMaterialSystem()->Flush( false );
+ ITextureInternal *pTextureInternal = (ITextureInternal *)pTexture;
+
+ if ( IsPC() || !IsX360() )
+ {
+ pTextureInternal->CopyFrameBufferToMe( nRenderTargetID, pSrcRect, pDstRect );
+ }
+ else
+ {
+ // X360 only does 1:1 resolves. So we can do full resolves to textures of size
+ // equal or greater than the viewport trivially. Downsizing is nasty.
+ Rect_t srcRect;
+ if ( !pSrcRect )
+ {
+ // build out source rect
+ pSrcRect = &srcRect;
+ int x, y, w, h;
+ GetViewport( x, y, w, h );
+
+ pSrcRect->x = 0;
+ pSrcRect->y = 0;
+ pSrcRect->width = w;
+ pSrcRect->height = h;
+ }
+
+ Rect_t dstRect;
+ if ( !pDstRect )
+ {
+ // build out target rect
+ pDstRect = &dstRect;
+
+ pDstRect->x = 0;
+ pDstRect->y = 0;
+ pDstRect->width = pTexture->GetActualWidth();
+ pDstRect->height = pTexture->GetActualHeight();
+ }
+
+ if ( pSrcRect->width == pDstRect->width && pSrcRect->height == pDstRect->height )
+ {
+ // 1:1 mapping, no stretching needed, use direct path
+ pTextureInternal->CopyFrameBufferToMe( nRenderTargetID, pSrcRect, pDstRect );
+ return;
+ }
+
+ if( (pDstRect->x == 0) && (pDstRect->y == 0) &&
+ (pDstRect->width == pTexture->GetActualWidth()) && (pDstRect->height == pTexture->GetActualHeight()) &&
+ (pDstRect->width >= pSrcRect->width) && (pDstRect->height >= pSrcRect->height) )
+ {
+ // Resolve takes up the whole texture, and the texture is large enough to hold the resolve.
+ // 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)
+ pTextureInternal->CopyFrameBufferToMe( nRenderTargetID, pSrcRect, pDstRect );
+ return;
+ }
+
+ // currently assuming disparate copies are only for FB blits
+ // ensure active render target is actually the back buffer
+ Assert( m_RenderTargetStack.Top().m_pRenderTargets[0] == NULL );
+
+ // nasty sequence:
+ // resolve FB surface to matching clone DDR texture
+ // gpu draw from clone DDR FB texture to disparate RT target surface
+ // resolve to its matching DDR clone texture
+ ITextureInternal *pFullFrameFB = (ITextureInternal*)GetMaterialSystem()->FindTexture( "_rt_FullFrameFB", TEXTURE_GROUP_RENDER_TARGET );
+ pFullFrameFB->CopyFrameBufferToMe( nRenderTargetID, NULL, NULL );
+
+ // target texture must be a render target
+ PushRenderTargetAndViewport( pTexture );
+
+ // blit FB source to render target
+ DrawScreenSpaceRectangle(
+ GetMaterialSystem()->GetRenderTargetBlitMaterial(),
+ pDstRect->x, pDstRect->y, pDstRect->width, pDstRect->height,
+ pSrcRect->x, pSrcRect->y, pSrcRect->x+pSrcRect->width-1, pSrcRect->y+pSrcRect->height-1,
+ pFullFrameFB->GetActualWidth(), pFullFrameFB->GetActualHeight() );
+
+ // resolve render target to texture
+ ((ITextureInternal *)pTexture)->CopyFrameBufferToMe( 0, NULL, NULL );
+
+ // restore render target and viewport
+ PopRenderTargetAndViewport();
+ }
+}
+
+void CMatRenderContext::CopyRenderTargetToTexture( ITexture *pTexture )
+{
+ CopyRenderTargetToTextureEx( pTexture, NULL, NULL );
+}
+
+
+void CMatRenderContext::CopyTextureToRenderTargetEx( int nRenderTargetID, ITexture *pTexture, Rect_t *pSrcRect, Rect_t *pDstRect )
+{
+ if ( !pTexture )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ GetMaterialSystem()->Flush( false );
+ ITextureInternal *pTextureInternal = (ITextureInternal *)pTexture;
+
+ if ( IsPC() || !IsX360() )
+ {
+ pTextureInternal->CopyMeToFrameBuffer( nRenderTargetID, pSrcRect, pDstRect );
+ }
+ else
+ {
+ Assert( 0 );
+ }
+}
+
+
+void CMatRenderContext::ClearBuffers( bool bClearColor, bool bClearDepth, bool bClearStencil )
+{
+ int width, height;
+ GetRenderTargetDimensions( width, height );
+ g_pShaderAPI->ClearBuffers( bClearColor, bClearDepth, bClearStencil, width, height );
+}
+
+void CMatRenderContext::DrawClearBufferQuad( unsigned char r, unsigned char g, unsigned char b, unsigned char a, bool bClearColor, bool bClearAlpha, bool bClearDepth )
+{
+ IMaterialInternal *pClearMaterial = GetBufferClearObeyStencil( bClearColor + ( bClearAlpha << 1 ) + ( bClearDepth << 2 ) );
+ Bind( pClearMaterial );
+
+ IMesh* pMesh = GetDynamicMesh( true );
+
+ MatrixMode( MATERIAL_MODEL );
+ PushMatrix();
+ LoadIdentity();
+
+ MatrixMode( MATERIAL_VIEW );
+ PushMatrix();
+ LoadIdentity();
+
+ MatrixMode( MATERIAL_PROJECTION );
+ PushMatrix();
+ LoadIdentity();
+
+ float flDepth = GetMaterialSystem()->GetConfig().bReverseDepth ? 0.0f : 1.0f;
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ //1.1 instead of 1.0 to fix small borders around the edges in full screen with anti-aliasing enabled
+ meshBuilder.Position3f( -1.1f, -1.1f, flDepth );
+ meshBuilder.Color4ub( r, g, b, a );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( -1.1f, 1.1f, flDepth );
+ meshBuilder.Color4ub( r, g, b, a );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( 1.1f, 1.1f, flDepth );
+ meshBuilder.Color4ub( r, g, b, a );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( 1.1f, -1.1f, flDepth );
+ meshBuilder.Color4ub( r, g, b, a );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+
+ MatrixMode( MATERIAL_MODEL );
+ PopMatrix();
+
+ MatrixMode( MATERIAL_VIEW );
+ PopMatrix();
+
+ MatrixMode( MATERIAL_PROJECTION );
+ PopMatrix();
+}
+
+//-----------------------------------------------------------------------------
+// Should really be called SetViewport
+//-----------------------------------------------------------------------------
+void CMatRenderContext::Viewport( int x, int y, int width, int height )
+{
+ CMatRenderContextBase::Viewport( x, y, width, height );
+
+ // If either dimension is negative, set to full bounds of current target
+ if ( (width < 0) || (height < 0) )
+ {
+ ITexture *pTarget = m_RenderTargetStack.Top().m_pRenderTargets[0];
+
+ // If target is the back buffer
+ if ( pTarget == NULL )
+ {
+ m_Viewport.m_nTopLeftX = 0;
+ m_Viewport.m_nTopLeftY = 0;
+ g_pShaderAPI->GetBackBufferDimensions( m_Viewport.m_nWidth, m_Viewport.m_nHeight );
+ g_pShaderAPI->SetViewports( 1, &m_Viewport );
+ }
+ else // target is a texture
+ {
+ m_Viewport.m_nTopLeftX = 0;
+ m_Viewport.m_nTopLeftY = 0;
+ m_Viewport.m_nWidth = pTarget->GetActualWidth();
+ m_Viewport.m_nHeight = pTarget->GetActualHeight();
+ g_pShaderAPI->SetViewports( 1, &m_Viewport );
+ }
+ }
+ else // use the bounds passed in
+ {
+ m_Viewport.m_nTopLeftX = x;
+ m_Viewport.m_nTopLeftY = y;
+ m_Viewport.m_nWidth = width;
+ m_Viewport.m_nHeight = height;
+ g_pShaderAPI->SetViewports( 1, &m_Viewport );
+ }
+}
+
+void CMatRenderContext::GetViewport( int& x, int& y, int& width, int& height ) const
+{
+ // Verify valid top of RT stack
+ Assert ( m_RenderTargetStack.Count() > 0 );
+
+ // Grab the top of stack
+ const RenderTargetStackElement_t& element = m_RenderTargetStack.Top();
+
+ // If either dimension is not positive, set to full bounds of current target
+ if ( (element.m_nViewW <= 0) || (element.m_nViewH <= 0) )
+ {
+ // Viewport origin at target origin
+ x = y = 0;
+
+ // If target is back buffer
+ if ( element.m_pRenderTargets[0] == NULL )
+ {
+ g_pShaderAPI->GetBackBufferDimensions( width, height );
+ }
+ else // if target is texture
+ {
+ width = element.m_pRenderTargets[0]->GetActualWidth();
+ height = element.m_pRenderTargets[0]->GetActualHeight();
+ }
+ }
+ else // use the bounds from the stack directly
+ {
+ x = element.m_nViewX;
+ y = element.m_nViewY;
+ width = element.m_nViewW;
+ height = element.m_nViewH;
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Methods related to user clip planes
+//-----------------------------------------------------------------------------
+void CMatRenderContext::UpdateHeightClipUserClipPlane( void )
+{
+ PlaneStackElement pse;
+ pse.bHack_IsHeightClipPlane = true;
+
+ int iExistingHeightClipPlaneIndex;
+ for( iExistingHeightClipPlaneIndex = m_CustomClipPlanes.Count(); --iExistingHeightClipPlaneIndex >= 0; )
+ {
+ if( m_CustomClipPlanes[iExistingHeightClipPlaneIndex].bHack_IsHeightClipPlane )
+ break;
+ }
+
+ switch( m_HeightClipMode )
+ {
+ case MATERIAL_HEIGHTCLIPMODE_DISABLE:
+ if( iExistingHeightClipPlaneIndex != -1 )
+ m_CustomClipPlanes.Remove( iExistingHeightClipPlaneIndex );
+ break;
+ case MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT:
+ pse.fValues[0] = 0.0f;
+ pse.fValues[1] = 0.0f;
+ pse.fValues[2] = 1.0f;
+ pse.fValues[3] = m_HeightClipZ;
+ if( iExistingHeightClipPlaneIndex != -1 )
+ {
+ memcpy( m_CustomClipPlanes.Base() + iExistingHeightClipPlaneIndex, &pse, sizeof( PlaneStackElement ) );
+ }
+ else
+ {
+ m_CustomClipPlanes.AddToTail( pse );
+ }
+ break;
+ case MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT:
+ pse.fValues[0] = 0.0f;
+ pse.fValues[1] = 0.0f;
+ pse.fValues[2] = -1.0f;
+ pse.fValues[3] = -m_HeightClipZ;
+ if( iExistingHeightClipPlaneIndex != -1 )
+ {
+ memcpy( m_CustomClipPlanes.Base() + iExistingHeightClipPlaneIndex, &pse, sizeof( PlaneStackElement ) );
+ }
+ else
+ {
+ m_CustomClipPlanes.AddToTail( pse );
+ }
+ break;
+ };
+
+ ApplyCustomClipPlanes();
+
+ /*switch( m_HeightClipMode )
+ {
+ case MATERIAL_HEIGHTCLIPMODE_DISABLE:
+ g_pShaderAPI->EnableClipPlane( 0, false );
+ break;
+ case MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT:
+ plane[0] = 0.0f;
+ plane[1] = 0.0f;
+ plane[2] = 1.0f;
+ plane[3] = m_HeightClipZ;
+ g_pShaderAPI->SetClipPlane( 0, plane );
+ g_pShaderAPI->EnableClipPlane( 0, true );
+ break;
+ case MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT:
+ plane[0] = 0.0f;
+ plane[1] = 0.0f;
+ plane[2] = -1.0f;
+ plane[3] = -m_HeightClipZ;
+ g_pShaderAPI->SetClipPlane( 0, plane );
+ g_pShaderAPI->EnableClipPlane( 0, true );
+ break;
+ }*/
+}
+
+
+//-----------------------------------------------------------------------------
+// Lightmap stuff
+//-----------------------------------------------------------------------------
+void CMatRenderContext::BindLightmapPage( int lightmapPageID )
+{
+ if ( m_lightmapPageID == lightmapPageID )
+ return;
+
+ // We gotta make sure there's no buffered primitives 'cause this'll
+ // change the render state.
+ g_pShaderAPI->FlushBufferedPrimitives();
+
+ CMatRenderContextBase::BindLightmapPage( lightmapPageID );
+}
+
+void CMatRenderContext::BindLightmapTexture( ITexture *pLightmapTexture )
+{
+ if ( ( m_lightmapPageID == MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED ) && ( m_pUserDefinedLightmap == pLightmapTexture ) )
+ return;
+
+ // We gotta make sure there's no buffered primitives 'cause this'll
+ // change the render state.
+ g_pShaderAPI->FlushBufferedPrimitives();
+
+ m_lightmapPageID = MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED;
+ if ( pLightmapTexture )
+ {
+ pLightmapTexture->IncrementReferenceCount();
+ }
+ if ( m_pUserDefinedLightmap )
+ {
+ m_pUserDefinedLightmap->DecrementReferenceCount();
+ }
+ m_pUserDefinedLightmap = static_cast<ITextureInternal*>( pLightmapTexture );
+}
+
+
+void CMatRenderContext::BindLightmap( Sampler_t sampler )
+{
+ switch ( m_lightmapPageID )
+ {
+ default:
+ Assert( ( m_lightmapPageID == 0 && GetLightmaps()->GetNumLightmapPages() == 0 ) || ( m_lightmapPageID >= 0 && m_lightmapPageID < GetLightmaps()->GetNumLightmapPages() ) );
+ if( m_lightmapPageID >= 0 && m_lightmapPageID < GetLightmaps()->GetNumLightmapPages() )
+ {
+ g_pShaderAPI->BindTexture( sampler, GetLightmaps()->GetLightmapPageTextureHandle( m_lightmapPageID ) );
+ }
+ break;
+
+ case MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED:
+ AssertOnce( m_pUserDefinedLightmap );
+ g_pShaderAPI->BindTexture( sampler, m_pUserDefinedLightmap->GetTextureHandle( 0 ) );
+ break;
+
+ case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE:
+ BindFullbrightLightmap( sampler );
+ break;
+
+ case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP:
+ BindBumpedFullbrightLightmap( sampler );
+ break;
+ }
+}
+
+void CMatRenderContext::BindBumpLightmap( Sampler_t sampler )
+{
+ switch ( m_lightmapPageID )
+ {
+ default:
+ Assert( m_lightmapPageID >= 0 && m_lightmapPageID < GetLightmaps()->GetNumLightmapPages() );
+ if( m_lightmapPageID >= 0 && m_lightmapPageID < GetLightmaps()->GetNumLightmapPages() )
+ {
+ g_pShaderAPI->BindTexture( sampler, GetLightmaps()->GetLightmapPageTextureHandle( m_lightmapPageID ) );
+ g_pShaderAPI->BindTexture( (Sampler_t)(sampler+1), GetLightmaps()->GetLightmapPageTextureHandle( m_lightmapPageID ) );
+ g_pShaderAPI->BindTexture( (Sampler_t)(sampler+2), GetLightmaps()->GetLightmapPageTextureHandle( m_lightmapPageID ) );
+ }
+ break;
+ case MATERIAL_SYSTEM_LIGHTMAP_PAGE_USER_DEFINED:
+ AssertOnce( m_pUserDefinedLightmap );
+ g_pShaderAPI->BindTexture( sampler, m_pUserDefinedLightmap->GetTextureHandle( 0 ) );
+ g_pShaderAPI->BindTexture( (Sampler_t)(sampler+1), m_pUserDefinedLightmap->GetTextureHandle( 0 ) );
+ g_pShaderAPI->BindTexture( (Sampler_t)(sampler+2), m_pUserDefinedLightmap->GetTextureHandle( 0 ) );
+ break;
+ case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP:
+ BindBumpedFullbrightLightmap( sampler );
+ BindBumpedFullbrightLightmap( (Sampler_t)(sampler+1) );
+ BindBumpedFullbrightLightmap( (Sampler_t)(sampler+2) );
+ break;
+ case MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE:
+ BindBumpedFullbrightLightmap( sampler );
+ BindBumpedFullbrightLightmap( (Sampler_t)(sampler+1) );
+ BindBumpedFullbrightLightmap( (Sampler_t)(sampler+2) );
+ break;
+ }
+}
+
+void CMatRenderContext::BindFullbrightLightmap( Sampler_t sampler )
+{
+ g_pShaderAPI->BindTexture( sampler, GetFullbrightLightmapTextureHandle() );
+}
+
+void CMatRenderContext::BindBumpedFullbrightLightmap( Sampler_t sampler )
+{
+ g_pShaderAPI->BindTexture( sampler, GetFullbrightBumpedLightmapTextureHandle() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Bind standard textures
+//-----------------------------------------------------------------------------
+void CMatRenderContext::BindStandardTexture( Sampler_t sampler, StandardTextureId_t id )
+{
+ switch ( id )
+ {
+ case TEXTURE_LIGHTMAP:
+ BindLightmap( sampler );
+ return;
+
+ case TEXTURE_LIGHTMAP_BUMPED:
+ BindBumpLightmap( sampler );
+ return;
+
+ case TEXTURE_LIGHTMAP_FULLBRIGHT:
+ BindFullbrightLightmap( sampler );
+ return;
+
+ case TEXTURE_LIGHTMAP_BUMPED_FULLBRIGHT:
+ BindBumpedFullbrightLightmap( sampler );
+ return;
+
+ case TEXTURE_WHITE:
+ g_pShaderAPI->BindTexture( sampler, GetWhiteTextureHandle() );
+ return;
+
+ case TEXTURE_BLACK:
+ g_pShaderAPI->BindTexture( sampler, GetBlackTextureHandle() );
+ return;
+
+ case TEXTURE_GREY:
+ g_pShaderAPI->BindTexture( sampler, GetGreyTextureHandle() );
+ return;
+
+ case TEXTURE_GREY_ALPHA_ZERO:
+ g_pShaderAPI->BindTexture( sampler, GetGreyAlphaZeroTextureHandle() );
+ return;
+
+ case TEXTURE_NORMALMAP_FLAT:
+ g_pShaderAPI->BindTexture( sampler, GetFlatNormalTextureHandle() );
+ return;
+
+ case TEXTURE_NORMALIZATION_CUBEMAP:
+ TextureManager()->NormalizationCubemap()->Bind( sampler );
+ return;
+
+ case TEXTURE_NORMALIZATION_CUBEMAP_SIGNED:
+ TextureManager()->SignedNormalizationCubemap()->Bind( sampler );
+ return;
+
+ case TEXTURE_FRAME_BUFFER_FULL_TEXTURE_0:
+ case TEXTURE_FRAME_BUFFER_FULL_TEXTURE_1:
+ {
+ int nTextureIndex = id - TEXTURE_FRAME_BUFFER_FULL_TEXTURE_0;
+ if( m_pCurrentFrameBufferCopyTexture[ nTextureIndex ] )
+ {
+ ( ( ITextureInternal * )m_pCurrentFrameBufferCopyTexture[ nTextureIndex ] )->Bind( sampler );
+ }
+ }
+ return;
+
+ case TEXTURE_COLOR_CORRECTION_VOLUME_0:
+ case TEXTURE_COLOR_CORRECTION_VOLUME_1:
+ case TEXTURE_COLOR_CORRECTION_VOLUME_2:
+ case TEXTURE_COLOR_CORRECTION_VOLUME_3:
+ {
+ ITextureInternal *pTexture = TextureManager()->ColorCorrectionTexture( id - TEXTURE_COLOR_CORRECTION_VOLUME_0 );
+ if( pTexture )
+ {
+ pTexture->Bind( sampler );
+ }
+ }
+ return;
+
+ case TEXTURE_SHADOW_NOISE_2D:
+ TextureManager()->ShadowNoise2D()->Bind( sampler );
+ return;
+
+ case TEXTURE_IDENTITY_LIGHTWARP:
+ TextureManager()->IdentityLightWarp()->Bind( sampler );
+ return;
+
+ case TEXTURE_MORPH_ACCUMULATOR:
+ g_pMorphMgr->MorphAccumulator()->Bind( sampler );
+ return;
+
+ case TEXTURE_MORPH_WEIGHTS:
+ g_pMorphMgr->MorphWeights()->Bind( sampler );
+ return;
+
+ case TEXTURE_FRAME_BUFFER_FULL_DEPTH:
+ if( m_bFullFrameDepthIsValid )
+ TextureManager()->FullFrameDepthTexture()->Bind( sampler );
+ else
+ g_pShaderAPI->BindTexture( sampler, GetMaxDepthTextureHandle() );
+ return;
+
+ case TEXTURE_DEBUG_LUXELS:
+ TextureManager()->DebugLuxels2D()->Bind( sampler );
+ return;
+
+ default:
+ Assert(0);
+ }
+}
+
+void CMatRenderContext::BindStandardVertexTexture( VertexTextureSampler_t sampler, StandardTextureId_t id )
+{
+ switch ( id )
+ {
+ case TEXTURE_MORPH_ACCUMULATOR:
+ g_pMorphMgr->MorphAccumulator()->BindVertexTexture( sampler );
+ return;
+
+ case TEXTURE_MORPH_WEIGHTS:
+ g_pMorphMgr->MorphWeights()->BindVertexTexture( sampler );
+ return;
+
+ default:
+ Assert(0);
+ }
+}
+
+void CMatRenderContext::GetStandardTextureDimensions( int *pWidth, int *pHeight, StandardTextureId_t id )
+{
+ ITexture *pTexture = NULL;
+ switch ( id )
+ {
+ case TEXTURE_LIGHTMAP:
+ case TEXTURE_LIGHTMAP_BUMPED:
+ case TEXTURE_LIGHTMAP_FULLBRIGHT:
+ case TEXTURE_LIGHTMAP_BUMPED_FULLBRIGHT:
+ // NOTE: Doesn't exactly work since we may be in fullbright mode
+// GetLightmapDimensions( pWidth, pHeight );
+// break;
+
+ case TEXTURE_WHITE:
+ case TEXTURE_BLACK:
+ case TEXTURE_GREY:
+ case TEXTURE_GREY_ALPHA_ZERO:
+ case TEXTURE_NORMALMAP_FLAT:
+ default:
+ Assert( 0 );
+ Warning( "GetStandardTextureDimensions: still unimplemented for this type!\n" );
+ *pWidth = *pHeight = -1;
+ break;
+
+ case TEXTURE_NORMALIZATION_CUBEMAP:
+ pTexture = TextureManager()->NormalizationCubemap();
+ break;
+
+ case TEXTURE_NORMALIZATION_CUBEMAP_SIGNED:
+ pTexture = TextureManager()->SignedNormalizationCubemap();
+ break;
+
+ case TEXTURE_FRAME_BUFFER_FULL_TEXTURE_0:
+ case TEXTURE_FRAME_BUFFER_FULL_TEXTURE_1:
+ {
+ int nTextureIndex = id - TEXTURE_FRAME_BUFFER_FULL_TEXTURE_0;
+ pTexture = m_pCurrentFrameBufferCopyTexture[ nTextureIndex ];
+ }
+ break;
+
+ case TEXTURE_COLOR_CORRECTION_VOLUME_0:
+ case TEXTURE_COLOR_CORRECTION_VOLUME_1:
+ case TEXTURE_COLOR_CORRECTION_VOLUME_2:
+ case TEXTURE_COLOR_CORRECTION_VOLUME_3:
+ pTexture = TextureManager()->ColorCorrectionTexture( id - TEXTURE_COLOR_CORRECTION_VOLUME_0 );
+ break;
+
+ case TEXTURE_SHADOW_NOISE_2D:
+ pTexture = TextureManager()->ShadowNoise2D();
+ break;
+
+ case TEXTURE_IDENTITY_LIGHTWARP:
+ pTexture = TextureManager()->IdentityLightWarp();
+ return;
+
+ case TEXTURE_MORPH_ACCUMULATOR:
+ pTexture = g_pMorphMgr->MorphAccumulator();
+ break;
+
+ case TEXTURE_MORPH_WEIGHTS:
+ pTexture = g_pMorphMgr->MorphWeights();
+ break;
+
+ case TEXTURE_DEBUG_LUXELS:
+ pTexture = TextureManager()->DebugLuxels2D();
+ break;
+ }
+
+ if ( pTexture )
+ {
+ *pWidth = pTexture->GetActualWidth();
+ *pHeight = pTexture->GetActualHeight();
+ }
+ else
+ {
+ Warning( "GetStandardTextureDimensions: Couldn't find the texture to get the dimensions!\n" );
+ *pWidth = *pHeight = -1;
+ }
+}
+
+void CMatRenderContext::FogColor3f( float r, float g, float b )
+{
+ unsigned char fogColor[3];
+ fogColor[0] = clamp( (int)(r * 255.0f), 0, 255 );
+ fogColor[1] = clamp( (int)(g * 255.0f), 0, 255 );
+ fogColor[2] = clamp( (int)(b * 255.0f), 0, 255 );
+ g_pShaderAPI->SceneFogColor3ub( fogColor[0], fogColor[1], fogColor[2] );
+}
+
+void CMatRenderContext::FogColor3fv( const float* rgb )
+{
+ unsigned char fogColor[3];
+ fogColor[0] = clamp( (int)(rgb[0] * 255.0f), 0, 255 );
+ fogColor[1] = clamp( (int)(rgb[1] * 255.0f), 0, 255 );
+ fogColor[2] = clamp( (int)(rgb[2] * 255.0f), 0, 255 );
+ g_pShaderAPI->SceneFogColor3ub( fogColor[0], fogColor[1], fogColor[2] );
+}
+
+
+
+void CMatRenderContext::SetFlashlightMode( bool bEnable )
+{
+ if( bEnable != m_bFlashlightEnable )
+ {
+ g_pShaderAPI->FlushBufferedPrimitives();
+ m_bFlashlightEnable = bEnable;
+ }
+}
+
+bool CMatRenderContext::GetFlashlightMode( ) const
+{
+ return m_bFlashlightEnable;
+}
+
+void CMatRenderContext::SetFlashlightStateEx( const FlashlightState_t &state, const VMatrix &worldToTexture, ITexture *pFlashlightDepthTexture )
+{
+ g_pShaderAPI->SetFlashlightStateEx( state, worldToTexture, pFlashlightDepthTexture );
+ if ( IsPC() && g_config.dxSupportLevel <= 70 )
+ {
+ // Going to go ahead and set a single hardware light here to do all lighting except for
+ // the spotlight falloff function, which is done with a texture.
+ SetAmbientLight( 0.0f, 0.0f, 0.0f );
+ static Vector4D blackCube[6];
+ int i;
+ for( i = 0; i < 6; i++ )
+ {
+ blackCube[i].Init( 0.0f, 0.0f, 0.0f, 0.0f );
+ }
+ SetAmbientLightCube( blackCube );
+
+ // Disable all the lights except for the first one.
+ for( i = 1; i < HardwareConfig()->MaxNumLights(); ++i )
+ {
+ LightDesc_t desc;
+ desc.m_Type = MATERIAL_LIGHT_DISABLE;
+ SetLight( i, desc );
+ }
+
+ LightDesc_t desc;
+ desc.m_Type = MATERIAL_LIGHT_POINT;
+ desc.m_Attenuation0 = state.m_fConstantAtten;
+ desc.m_Attenuation1 = state.m_fLinearAtten;
+ desc.m_Attenuation2 = state.m_fQuadraticAtten;
+ // flashlightfixme: I don't know why this scale has to be here to get fixed function lighting to work.
+ desc.m_Color.x = state.m_Color[0] * 17000.0f;
+ desc.m_Color.y = state.m_Color[1] * 17000.0f;
+ desc.m_Color.z = state.m_Color[2] * 17000.0f;
+ desc.m_Position = state.m_vecLightOrigin;
+
+ QAngle angles;
+ QuaternionAngles( state.m_quatOrientation, angles );
+ AngleVectors( angles, &desc.m_Direction );
+
+ desc.m_Range = state.m_FarZ;
+ desc.m_Falloff = 0.0f;
+ SetLight( 0, desc );
+ }
+}
+
+void CMatRenderContext::SetScissorRect( const int nLeft, const int nTop, const int nRight, const int nBottom, const bool bEnableScissor )
+{
+ g_pShaderAPI->SetScissorRect( nLeft, nTop, nRight, nBottom, bEnableScissor );
+}
+
+void CMatRenderContext::SetToneMappingScaleLinear( const Vector &scale )
+{
+ g_pShaderAPI->SetToneMappingScaleLinear( scale );
+}
+
+void CMatRenderContext::BeginBatch( IMesh* pIndices )
+{
+ Assert( !m_pBatchMesh && !m_pBatchIndices);
+ m_pBatchIndices = pIndices;
+}
+
+void CMatRenderContext::BindBatch( IMesh* pVertices, IMaterial *pAutoBind )
+{
+ m_pBatchMesh = GetDynamicMesh( false, pVertices, m_pBatchIndices, pAutoBind );
+}
+
+void CMatRenderContext::DrawBatch(int firstIndex, int numIndices )
+{
+ Assert( m_pBatchMesh );
+ m_pBatchMesh->Draw( firstIndex, numIndices );
+}
+
+void CMatRenderContext::EndBatch()
+{
+ m_pBatchIndices = NULL;
+ m_pBatchMesh = NULL;
+}
+
+bool CMatRenderContext::OnDrawMesh( IMesh *pMesh, int firstIndex, int numIndices )
+{
+ SyncMatrices();
+ return true;
+}
+
+bool CMatRenderContext::OnDrawMesh( IMesh *pMesh, CPrimList *pLists, int nLists )
+{
+ SyncMatrices();
+ return true;
+}
+
+void CMatRenderContext::AsyncCreateTextureFromRenderTarget( ITexture* pSrcRt, const char* pDstName, ImageFormat dstFmt, bool bGenMips, int nAdditionalCreationFlags, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs )
+{
+ if ( g_pMaterialSystem->GetThreadMode() == MATERIAL_SINGLE_THREADED )
+ {
+ OnAsyncCreateTextureFromRenderTarget( pSrcRt, &pDstName, pRecipient );
+ }
+
+ TextureManager()->AsyncCreateTextureFromRenderTarget( pSrcRt, pDstName, dstFmt, bGenMips, nAdditionalCreationFlags, pRecipient, pExtraArgs );
+}
+
+void CMatRenderContext::AsyncMap( ITextureInternal* pTexToMap, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs )
+{
+ if ( g_pMaterialSystem->GetThreadMode() == MATERIAL_SINGLE_THREADED )
+ {
+ OnAsyncMap( pTexToMap, pRecipient, pExtraArgs );
+ }
+
+ void* pMemory = NULL;
+ int nPitch = NULL;
+
+ pTexToMap->Map( &pMemory, &nPitch );
+
+ pRecipient->OnAsyncMapComplete( pTexToMap, pExtraArgs, pMemory, nPitch );
+
+ // Release references held earlier in OnAsyncMap
+ SafeRelease( &pRecipient );
+ SafeRelease( &pTexToMap );
+}
+
+void CMatRenderContext::AsyncUnmap( ITextureInternal* pTexToUnmap )
+{
+ if ( g_pMaterialSystem->GetThreadMode() == MATERIAL_SINGLE_THREADED )
+ {
+ OnAsyncUnmap( pTexToUnmap );
+ }
+
+ pTexToUnmap->Unmap();
+ SafeRelease( &pTexToUnmap ); // Matches AddRef from OnAsyncUnmap
+}
+
+void CMatRenderContext::AsyncCopyRenderTargetToStagingTexture( ITexture* pDst, ITexture* pSrc, IAsyncTextureOperationReceiver* pRecipient, void* pExtraArgs )
+{
+ if ( g_pMaterialSystem->GetThreadMode() == MATERIAL_SINGLE_THREADED )
+ {
+ OnAsyncCopyRenderTargetToStagingTexture( pDst, pSrc, pRecipient );
+ }
+
+ pSrc->CopyToStagingTexture( pDst );
+ pRecipient->OnAsyncReadbackBegin( pDst, pSrc, pExtraArgs );
+
+ SafeRelease( &pDst );
+ SafeRelease( &pSrc );
+ SafeRelease( &pRecipient );
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods related to morph accumulation
+//-----------------------------------------------------------------------------
+void CMatRenderContext::BeginMorphAccumulation()
+{
+ g_pMorphMgr->BeginMorphAccumulation( m_pMorphRenderContext );
+}
+
+void CMatRenderContext::EndMorphAccumulation()
+{
+ g_pMorphMgr->EndMorphAccumulation( m_pMorphRenderContext );
+}
+
+void CMatRenderContext::AccumulateMorph( IMorph* pMorph, int nMorphCount, const MorphWeight_t* pWeights )
+{
+ g_pMorphMgr->AccumulateMorph( m_pMorphRenderContext, pMorph, nMorphCount, pWeights );
+}
+
+bool CMatRenderContext::GetMorphAccumulatorTexCoord( Vector2D *pTexCoord, IMorph *pMorph, int nVertex )
+{
+ return g_pMorphMgr->GetMorphAccumulatorTexCoord( m_pMorphRenderContext, pTexCoord, pMorph, nVertex );
+}
+
+
+//-----------------------------------------------------------------------------
+// Occlusion query support
+//-----------------------------------------------------------------------------
+OcclusionQueryObjectHandle_t CMatRenderContext::CreateOcclusionQueryObject()
+{
+ OcclusionQueryObjectHandle_t h = g_pOcclusionQueryMgr->CreateOcclusionQueryObject();
+ g_pOcclusionQueryMgr->OnCreateOcclusionQueryObject( h );
+ return h;
+}
+
+int CMatRenderContext::OcclusionQuery_GetNumPixelsRendered( OcclusionQueryObjectHandle_t h )
+{
+ return g_pOcclusionQueryMgr->OcclusionQuery_GetNumPixelsRendered( h, true );
+}
+
+
+
+
+void CMatRenderContext::SetFullScreenDepthTextureValidityFlag( bool bIsValid )
+{
+ m_bFullFrameDepthIsValid = bIsValid;
+}
+
+//-----------------------------------------------------------------------------
+// Debug logging
+//-----------------------------------------------------------------------------
+
+void CMatRenderContext::PrintfVA( char *fmt, va_list vargs )
+{
+ #if GLMDEBUG
+ g_pShaderAPI->PrintfVA( fmt, vargs );
+ #endif
+}
+
+void CMatRenderContext::Printf( const char *fmt, ... )
+{
+ #if GLMDEBUG
+ va_list vargs;
+
+ va_start(vargs, fmt);
+
+ g_pShaderAPI->PrintfVA( (char *)fmt, vargs );
+
+ va_end( vargs );
+ #endif
+}
+
+float CMatRenderContext::Knob( char *knobname, float *setvalue )
+{
+ #if GLMDEBUG
+ return g_pShaderAPI->Knob( knobname, setvalue );
+ #else
+ return 0.0f;
+ #endif
+}
+