You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3157 lines
90 KiB
3157 lines
90 KiB
//========= 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 (intp)pMat1 - (intp)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 |
|
} |
|
|
|
|