2025-05-17 14:14:20 -04:00
//===== Copyright © 1996-2007, Valve Corporation, All rights reserved. ======//
2010-07-22 01:46:14 -05:00
//
// Purpose:
//
// $Revision: $
// $NoKeywords: $
//
// Fast path model rendering
//
//===========================================================================//
# include "cbase.h"
# include "modelrendersystem.h"
# include "model_types.h"
# include "iviewrender.h"
# include "tier3/tier3.h"
# include <algorithm>
# include "tier1/memstack.h"
# include "engine/ivdebugoverlay.h"
# include "shaderapi/ishaderapi.h"
# include "materialsystem/materialsystemutil.h"
# include "tier0/vprof.h"
// NOTE: This has to be the last file included!
# include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Convars defined by other systems
//-----------------------------------------------------------------------------
ConVar r_lod ( " r_lod " , " -1 " ) ;
//ConVar r_shadowlod( "r_shadowlod", "-1" );
ConVar r_drawmodellightorigin ( " r_DrawModelLightOrigin " , " 0 " , FCVAR_CHEAT ) ;
extern ConVar g_CV_FlexSmooth ;
extern ConVar r_fastzreject ;
//-----------------------------------------------------------------------------
// The client leaf system
//-----------------------------------------------------------------------------
class CModelRenderSystem : public CAutoGameSystem , public IModelRenderSystem
{
// Methods of IModelRenderSystem
public :
virtual void DrawModels ( ModelRenderSystemData_t * pEntities , int nCount , ModelRenderMode_t renderMode ) ;
virtual void ComputeTranslucentRenderData ( ModelRenderSystemData_t * pModels , int nCount , TranslucentInstanceRenderData_t * pRenderData , TranslucentTempData_t * pTempData ) ;
virtual void CleanupTranslucentTempData ( TranslucentTempData_t * pTempData ) ;
virtual IMaterial * GetFastPathColorMaterial ( ) { return m_DebugMaterial ; }
// Methods of IGameSystem
public :
virtual void LevelInitPostEntity ( ) ;
virtual void LevelShutdownPreEntity ( ) ;
// Other public methods
public :
CModelRenderSystem ( ) ;
virtual ~ CModelRenderSystem ( ) ;
private :
struct ModelListNode_t
{
ModelRenderSystemData_t m_Entry ;
int32 m_nInitialListIndex : 24 ;
int32 m_bBoneMerge : 1 ;
int32 m_nLOD : 7 ;
ShaderStencilState_t * m_pStencilState ;
ModelListNode_t * m_pNext ;
} ;
struct RenderModelInfo_t : public StudioArrayInstanceData_t
{
ModelRenderSystemData_t m_Entry ;
ModelInstanceHandle_t m_hInstance ;
matrix3x4a_t * m_pBoneToWorld ;
uint32 m_nInitialListIndex : 24 ;
uint32 m_bSetupBonesOnly : 1 ;
uint32 m_bBoneMerge : 1 ;
} ;
struct ModelListByType_t : public StudioModelArrayInfo_t
{
RenderableLightingModel_t m_nLightingModel ;
const model_t * m_pModel ;
ModelListNode_t * m_pFirstNode ;
int m_nCount ;
int m_nSetupBoneCount ;
uint32 m_nParentDepth : 31 ;
uint32 m_bWantsStencil : 1 ;
RenderModelInfo_t * m_pRenderModels ;
ModelListByType_t * m_pNextLightingModel ;
// speed up std::sort by implementing these
ModelListByType_t & operator = ( const ModelListByType_t & rhs )
{
memcpy ( this , & rhs , sizeof ( ModelListByType_t ) ) ;
return * this ;
}
ModelListByType_t ( ) { }
ModelListByType_t ( const ModelListByType_t & rhs )
{
memcpy ( this , & rhs , sizeof ( ModelListByType_t ) ) ;
}
} ;
struct LightingList_t
{
ModelListByType_t * m_pFirstModel ;
int m_nCount ;
int m_nTotalModelCount ;
} ;
private :
int BucketModelsByMDL ( ModelListByType_t * pModelList , ModelListNode_t * pModelListNodes , ModelRenderSystemData_t * pEntities , int nCount , ModelRenderMode_t renderMode , int * pModelsRenderingStencilCountOut ) ;
bool AddModelToLists ( int & nModelTypeCount , ModelListByType_t * pModelList , int & nModelNodeCount , ModelListNode_t * pModelListNodes , int nDataIndex , ModelRenderSystemData_t & data , ModelRenderMode_t renderMode ) ;
void SortBucketsByDependency ( int nModelTypeCount , ModelListByType_t * pModelList , LightingList_t * pLightingList ) ;
void ComputeModelLODs ( int nModelTypeCount , ModelListByType_t * pModelList , ModelListNode_t * pModelListNode , ModelRenderMode_t renderMode ) ;
void SlamModelLODs ( int nLOD , int nModelTypeCount , ModelListByType_t * pModelList , ModelListNode_t * pModelListNode ) ;
void SortModels ( RenderModelInfo_t * pSortedModelListNode , int nModelTypeCount , ModelListByType_t * pModelList , ModelListNode_t * pModelListNode ) ;
static bool SortLessFunc ( const RenderModelInfo_t & left , const RenderModelInfo_t & right ) ;
void SetupBones ( int nModelTypeCount , ModelListByType_t * pModelList ) ;
void SetupFlexes ( int nModelTypeCount , ModelListByType_t * pModelList ) ;
void ComputeLightingOrigin ( ModelListByType_t & list , LightingQuery_t * pLightingQuery , int nQueryStride ) ;
int SetupLighting ( LightingList_t * pLightingList , int nModelTypeCount , ModelListByType_t * pModelList , DataCacheHandle_t * pColorMeshHandles , ModelRenderMode_t renderMode ) ;
void RenderModels ( StudioModelArrayInfo2_t * pInfo , int nModelTypeCount , ModelListByType_t * pModelList , int nTotalModelCount , ModelRenderMode_t renderMode ) ;
void SetupTranslucentData ( int nModelTypeCount , ModelListByType_t * pModelList , int nTotalModelCount , TranslucentInstanceRenderData_t * pRenderData ) ;
void SetupFlashlightsAndDecals ( StudioModelArrayInfo2_t * pInfo , int nModelTypeCount , ModelListByType_t * pModelList , int nTotalModelCount , RenderModelInfo_t * pModelInfo , ModelRenderMode_t renderMode ) ;
void SetupPerInstanceColorModulation ( int nModelTypeCount , ModelListByType_t * pModelList ) ;
void DebugDrawLightingOrigin ( const ModelListByType_t & list , const RenderModelInfo_t & model ) ;
int BuildLightingList ( ModelListByType_t * * ppLists , unsigned char * pFlags , int * pTotalModels , const LightingList_t & lightingList ) ;
int SetupStaticPropLighting ( LightingList_t & lightingList , DataCacheHandle_t * pColorMeshHandles ) ;
void SetupStandardLighting ( LightingList_t & lightingList ) ;
int SetupPhysicsPropLighting ( LightingList_t & lightingList , DataCacheHandle_t * pColorMeshHandles ) ;
void HookUpStaticLightingState ( int nCount , ModelListByType_t * * ppLists , unsigned char * pFlags , ITexture * * ppEnvCubemap , MaterialLightingState_t * pLightingState , MaterialLightingState_t * pDecalLightingState , ColorMeshInfo_t * * ppColorMeshInfo ) ;
void RenderDebugOverlays ( int nModelTypeCount , ModelListByType_t * pModelList , ModelRenderMode_t renderMode ) ;
void RenderVCollideDebugOverlay ( int nModelTypeCount , ModelListByType_t * pModelList ) ;
void RenderBBoxDebugOverlay ( int nModelTypeCount , ModelListByType_t * pModelList ) ;
int ComputeParentDepth ( C_BaseEntity * pEnt ) ;
static bool DependencySortLessFunc ( const ModelListByType_t & left , const ModelListByType_t & right ) ;
static bool StencilSortLessFunc ( const ModelListByType_t & left , const ModelListByType_t & right ) ;
CMemoryStack m_BoneToWorld ;
CTextureReference m_DefaultCubemap ;
CMaterialReference m_DebugMaterial ;
CMaterialReference m_ShadowBuild ;
IMatRenderContext * m_pRenderContext ;
CUtlMemoryFixedGrowable < DataCacheHandle_t , 1024 > m_ColorMeshHandles ;
CUtlMemoryFixedGrowable < ModelListByType_t , 128 > m_ModelList ;
CUtlMemoryFixedGrowable < ModelListNode_t , 1024 > m_ModelListNode ;
CUtlMemoryFixedGrowable < RenderModelInfo_t , 1024 > m_RenderModelInfo ;
int m_nColorMeshHandles ;
int m_nModelTypeCount ;
int m_nTotalModelCount ;
bool m_bShadowDepth ;
bool m_bHasInstanceData ;
} ;
//-----------------------------------------------------------------------------
// Singleton accessor
//-----------------------------------------------------------------------------
static CModelRenderSystem s_ModelRenderSystem ;
extern IModelRenderSystem * g_pModelRenderSystem = & s_ModelRenderSystem ;
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CModelRenderSystem : : CModelRenderSystem ( )
{
m_bHasInstanceData = false ;
m_BoneToWorld . Init ( 1 * 1024 * 1024 , 32 * 1024 , 0 , 32 ) ;
}
CModelRenderSystem : : ~ CModelRenderSystem ( )
{
m_BoneToWorld . Term ( ) ;
}
//-----------------------------------------------------------------------------
// Level init, shutdown
//-----------------------------------------------------------------------------
void CModelRenderSystem : : LevelInitPostEntity ( )
{
m_DefaultCubemap . Init ( " engine/defaultcubemap " , TEXTURE_GROUP_CUBE_MAP ) ;
m_DebugMaterial . Init ( " debug/debugempty " , TEXTURE_GROUP_OTHER ) ;
m_ShadowBuild . Init ( " engine/shadowbuild " , TEXTURE_GROUP_OTHER ) ;
}
void CModelRenderSystem : : LevelShutdownPreEntity ( )
{
m_DefaultCubemap . Shutdown ( ) ;
m_DebugMaterial . Shutdown ( ) ;
m_ShadowBuild . Shutdown ( ) ;
}
//-----------------------------------------------------------------------------
// returns bone setup dependency depth
//-----------------------------------------------------------------------------
int CModelRenderSystem : : ComputeParentDepth ( C_BaseEntity * pEnt )
{
if ( ! pEnt )
return 0 ;
int nDepth = 0 ;
while ( pEnt - > IsFollowingEntity ( ) | | ( pEnt - > GetMoveParent ( ) & & pEnt - > GetParentAttachment ( ) > 0 ) )
{
+ + nDepth ;
pEnt = pEnt - > GetMoveParent ( ) ;
}
return nDepth ;
}
//-----------------------------------------------------------------------------
// Adds a model to the appropriate render lists
//-----------------------------------------------------------------------------
bool CModelRenderSystem : : AddModelToLists ( int & nModelTypeCount , ModelListByType_t * pModelList ,
int & nModelNodeCount , ModelListNode_t * pModelListNodes , int nInitialListIndex , ModelRenderSystemData_t & data , ModelRenderMode_t renderMode )
{
// NOTE: we actually are bucketing both by model + also by lighting model
// Bucketing by lighting model is not strictly necessary, but doing so
// simplifies the code a lot in exchange for having two batches if the
// same model is used but a different lighting model, something that could
// theoretically happen if a static prop + physics prop use the same .mdl
// My thought is that even if this split happens, it will be rare, and
// we still will get a lot of sharing.
// L4D2: We'll also bucket by whether the model renders stencil or not.
// This allows us to keep stenciling models in the fastpath but group them together
// to be rendered AFTER the 360 Z prepass ends. (360 doesn't allow stencil rendering
// during the Z prepass).
const model_t * pModel = data . m_pRenderable - > GetModel ( ) ;
Assert ( modelinfo - > GetModelType ( pModel ) = = mod_studio ) ;
RenderableLightingModel_t nLightingModel = LIGHTING_MODEL_NONE ;
uint bWantsStencil = 0 ;
ShaderStencilState_t tempStencil ;
if ( data . m_pModelRenderable )
{
data . m_pModelRenderable - > GetRenderData ( & nLightingModel , MODEL_DATA_LIGHTING_MODEL ) ;
if ( renderMode = = MODEL_RENDER_MODE_NORMAL )
{
// I considered making a MODEL_DATA_STENCIL_ENABLE renderdata type that would only return a bool
// if stencil was enabled, but it turns out most of the work for MODEL_DATA_STENCIL is computing
// that bool, so pulling this out into a separate piece didn't turn out to be a perf win.
bWantsStencil = data . m_pModelRenderable - > GetRenderData ( & tempStencil , MODEL_DATA_STENCIL ) ? 1 : 0 ;
}
}
else
{
ExecuteOnce ( DevWarning ( " data.m_pModelRenderable is NULL for %s \n " , modelinfo - > GetModelName ( pModel ) ) ) ;
}
bool bRetVal = bWantsStencil ? true : false ;
int j ;
for ( j = 0 ; j < nModelTypeCount ; + + j )
{
if ( pModelList [ j ] . m_pModel = = pModel & &
pModelList [ j ] . m_nLightingModel = = nLightingModel & &
pModelList [ j ] . m_bWantsStencil = = bWantsStencil )
break ;
}
if ( j = = nModelTypeCount )
{
// Bail if we're rendering into shadow depth map and this model doesn't cast shadows
// NOTE: if m_pModelRenderable is NULL, it's a dependent bone setup so we need to keep it
studiohdr_t * pStudioHdr = modelinfo - > GetStudiomodel ( pModel ) ;
if ( ( renderMode ! = MODEL_RENDER_MODE_NORMAL ) & & data . m_pModelRenderable & & ( ( pStudioHdr - > flags & STUDIOHDR_FLAGS_DO_NOT_CAST_SHADOWS ) ! = 0 ) )
{
return bRetVal ;
}
MDLHandle_t hMDL = modelinfo - > GetCacheHandle ( pModel ) ;
studiohwdata_t * pHardwareData = g_pMDLCache - > GetHardwareData ( hMDL ) ;
// This can occur if there was an error loading the model; for instance
// if the vtx and mdl are out of sync.
if ( ! pHardwareData | | ! pHardwareData - > m_pLODs )
{
AssertMsg ( 0 , UTIL_VarArgs ( " %s failed to load and is causing EVIL in the model render system!! " , pStudioHdr - > name ) ) ;
return bRetVal ;
}
ModelListByType_t & list = pModelList [ nModelTypeCount ] ;
list . m_pModel = pModel ;
list . m_nLightingModel = nLightingModel ;
list . m_bWantsStencil = bWantsStencil ;
list . m_pStudioHdr = pStudioHdr ;
list . m_pHardwareData = pHardwareData ;
list . m_nFlashlightCount = 0 ;
list . m_pFlashlights = NULL ;
list . m_nCount = 0 ;
list . m_pFirstNode = 0 ;
list . m_pRenderModels = 0 ;
list . m_nParentDepth = 0 ;
list . m_pNextLightingModel = NULL ;
j = nModelTypeCount + + ;
}
C_BaseEntity * pEntity = data . m_pRenderable - > GetIClientUnknown ( ) - > GetBaseEntity ( ) ;
uint nParentDepth = ComputeParentDepth ( pEntity ) ;
ModelListByType_t & list = pModelList [ j ] ;
ModelListNode_t & node = pModelListNodes [ nModelNodeCount + + ] ;
node . m_Entry = data ;
node . m_nInitialListIndex = nInitialListIndex ;
node . m_bBoneMerge = pEntity & & pEntity - > IsEffectActive ( EF_BONEMERGE ) ;
if ( bWantsStencil & & ( renderMode = = MODEL_RENDER_MODE_NORMAL ) )
{
CMatRenderData < ShaderStencilState_t > rdStencil ( m_pRenderContext , 1 ) ;
memcpy ( & rdStencil [ 0 ] , & tempStencil , sizeof ( tempStencil ) ) ;
node . m_pStencilState = & rdStencil [ 0 ] ;
}
else
{
node . m_pStencilState = NULL ;
}
node . m_pNext = list . m_pFirstNode ;
list . m_nParentDepth = MAX ( list . m_nParentDepth , nParentDepth ) ;
list . m_pFirstNode = & node ;
+ + list . m_nCount ;
return bRetVal ;
}
//-----------------------------------------------------------------------------
// bucket models by type, return # of unique types
//-----------------------------------------------------------------------------
int CModelRenderSystem : : BucketModelsByMDL ( ModelListByType_t * pModelList , ModelListNode_t * pModelListNodes , ModelRenderSystemData_t * pEntities , int nCount , ModelRenderMode_t renderMode ,
int * pModelsRenderingStencilCountOut )
{
int nModelTypeCount = 0 ;
int nModelNodeCount = 0 ;
* pModelsRenderingStencilCountOut = 0 ;
for ( int i = 0 ; i < nCount ; + + i )
{
bool bModelWantsStencil = AddModelToLists ( nModelTypeCount , pModelList , nModelNodeCount , pModelListNodes , i , pEntities [ i ] , renderMode ) ;
* pModelsRenderingStencilCountOut + = bModelWantsStencil ? 1 : 0 ;
}
return nModelTypeCount ;
}
//-----------------------------------------------------------------------------
// Sort model types function
//-----------------------------------------------------------------------------
inline bool CModelRenderSystem : : DependencySortLessFunc ( const ModelListByType_t & left , const ModelListByType_t & right )
{
// Ensures bone setup occurs in the correct order
if ( left . m_nParentDepth ! = right . m_nParentDepth )
return left . m_nParentDepth < right . m_nParentDepth ;
// Ensure stenciling models are at the end of the list.
// This doesn't guarantee that stencil stuff is at the end because parent depth trumps it,
// so we'll have to sort again before rendering.
if ( left . m_bWantsStencil ! = right . m_bWantsStencil )
{
return left . m_bWantsStencil < right . m_bWantsStencil ;
}
// Keep same models with different lighting types together
return left . m_pModel < right . m_pModel ;
}
//-----------------------------------------------------------------------------
// Sorts so that bone setup occurs in the appropriate order (parents set up first)
//-----------------------------------------------------------------------------
void CModelRenderSystem : : SortBucketsByDependency ( int nModelTypeCount , ModelListByType_t * pModelList , LightingList_t * pLightingList )
{
std : : sort ( pModelList , pModelList + nModelTypeCount , DependencySortLessFunc ) ;
// Assign models to the appropriate lighting list
for ( int i = nModelTypeCount ; - - i > = 0 ; )
{
ModelListByType_t & list = pModelList [ i ] ;
// Hook into lighting list
if ( list . m_nLightingModel = = LIGHTING_MODEL_NONE )
continue ;
LightingList_t & lightList = pLightingList [ list . m_nLightingModel ] ;
list . m_pNextLightingModel = lightList . m_pFirstModel ;
lightList . m_pFirstModel = & list ;
+ + lightList . m_nCount ;
lightList . m_nTotalModelCount + = list . m_nCount ;
}
# ifdef _DEBUG
// Don't want to allow some MDLs of type A to depend on MDLs of type B
// and other MDLS of type B to depend on type A because that would
// dramatically increase complexity of the system here. With this assumption,
// we can always have all models of the same type be set up at the same time,
// also improving cache efficiency.
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
if ( list . m_nParentDepth = = 0 )
continue ;
for ( ModelListNode_t * pNode = list . m_pFirstNode ; pNode ; pNode = pNode - > m_pNext )
{
C_BaseEntity * pEnt = pNode - > m_Entry . m_pRenderable - > GetIClientUnknown ( ) - > GetBaseEntity ( ) ;
if ( ! pEnt )
continue ;
C_BaseEntity * pTest = pEnt ;
while ( pEnt - > IsFollowingEntity ( ) | | ( pEnt - > GetMoveParent ( ) & & pEnt - > GetParentAttachment ( ) > 0 ) )
{
pEnt = pEnt - > GetMoveParent ( ) ;
const model_t * pModel = pEnt - > GetModel ( ) ;
bool bFound = false ;
for ( int j = 0 ; j < nModelTypeCount ; + + j )
{
if ( pModelList [ j ] . m_pModel ! = pModel )
continue ;
if ( pModelList [ j ] . m_nParentDepth > = list . m_nParentDepth )
{
// NOTE: GetClassname() stores the name in a global, hence need to do the warning on 2 lines
Warning ( " Bone setup dependency ordering issue [ent %s " , pTest - > GetClassname ( ) ) ;
Warning ( " depends on ent %s]! \n " , pEnt - > GetClassname ( ) ) ;
}
for ( ModelListNode_t * pParentNode = pModelList [ j ] . m_pFirstNode ; pParentNode ; pParentNode = pParentNode - > m_pNext )
{
if ( pParentNode - > m_Entry . m_pRenderable = = pEnt - > GetClientRenderable ( ) )
{
bFound = true ;
break ;
}
}
}
if ( ! bFound )
{
// NOTE: GetClassname() stores the name in a global, hence need to do the warning on 2 lines
// Warning( "Missing bone setup dependency [ent %s ", pTest->GetClassname() );
// Warning( "depends on ent %s]!\n", pEnt->GetClassname() );
}
}
}
}
# endif
}
//-----------------------------------------------------------------------------
// Slam model LODs to the appropriate level
//-----------------------------------------------------------------------------
void CModelRenderSystem : : SlamModelLODs ( int nLOD , int nModelTypeCount , ModelListByType_t * pModelList , ModelListNode_t * pModelListNode )
{
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
int nLODCount = list . m_pHardwareData - > m_NumLODs ;
int nRootLOD = list . m_pHardwareData - > m_RootLOD ;
bool bHasShadowLOD = ( list . m_pStudioHdr - > flags & STUDIOHDR_FLAGS_HASSHADOWLOD ) ! = 0 ;
int nMaxLOD = bHasShadowLOD ? nLODCount - 2 : nLODCount - 1 ;
for ( ModelListNode_t * pNode = list . m_pFirstNode ; pNode ; pNode = pNode - > m_pNext )
{
pNode - > m_nLOD = clamp ( nLOD , nRootLOD , nMaxLOD ) ;
}
}
}
//-----------------------------------------------------------------------------
// Compute model LODs
//-----------------------------------------------------------------------------
void CModelRenderSystem : : ComputeModelLODs ( int nModelTypeCount , ModelListByType_t * pModelList , ModelListNode_t * pModelListNode , ModelRenderMode_t renderMode )
{
if ( renderMode = = MODEL_RENDER_MODE_RTT_SHADOWS )
{
// Slam to shadow lod
//int nShadowLodConVar = r_shadowlod.GetInt();
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
int nLODCount = list . m_pHardwareData - > m_NumLODs ;
//int nRootLOD = list.m_pHardwareData->m_RootLOD;
int nMaxLOD = nLODCount - 1 ;
for ( ModelListNode_t * pNode = list . m_pFirstNode ; pNode ; pNode = pNode - > m_pNext )
{
// Just always use the lowest LOD right now
//int nLOD = nShadowLodConVar;
//pNode->m_nLOD = clamp( nLOD, nRootLOD, nMaxLOD );
pNode - > m_nLOD = nMaxLOD ;
}
}
return ;
}
int nLOD = r_lod . GetInt ( ) ;
if ( nLOD > = 0 )
{
SlamModelLODs ( nLOD , nModelTypeCount , pModelList , pModelListNode ) ;
return ;
}
ScreenSizeComputeInfo_t info ;
ComputeScreenSizeInfo ( & info ) ;
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
int nLODCount = list . m_pHardwareData - > m_NumLODs ;
int nRootLOD = list . m_pHardwareData - > m_RootLOD ;
int nMaxLOD = nLODCount - 1 ;
for ( ModelListNode_t * pNode = list . m_pFirstNode ; pNode ; pNode = pNode - > m_pNext )
{
// FIXME: SIMD-ize, eliminate all extraneous calls (get view render state outside of loop)
const Vector & vecRenderOrigin = pNode - > m_Entry . m_pRenderable - > GetRenderOrigin ( ) ;
// NOTE: The 2.0 is for legacy reasons
float flScreenSize = 2.0f * ComputeScreenSize ( vecRenderOrigin , 0.5f , info ) ;
float flMetric = list . m_pHardwareData - > LODMetric ( flScreenSize ) ;
nLOD = list . m_pHardwareData - > GetLODForMetric ( flMetric ) ;
pNode - > m_nLOD = clamp ( nLOD , nRootLOD , nMaxLOD ) ;
}
}
}
//-----------------------------------------------------------------------------
// Sort models function
//-----------------------------------------------------------------------------
inline bool CModelRenderSystem : : SortLessFunc ( const RenderModelInfo_t & left , const RenderModelInfo_t & right )
{
// NOTE: Could do this, but it is not faster, because the cost of an integer multiply is about three
// times that of a branch penalty:
// int nLeft = left.m_nSkin * 1000000 + left.m_nLOD * 1000 + left.m_nBody;
// int nRight = right.m_nSkin * 1000000 + right.m_nLOD * 1000 + right.m_nBody;
// return nLeft > nRight;
if ( left . m_bSetupBonesOnly ! = right . m_bSetupBonesOnly )
return ! left . m_bSetupBonesOnly ;
if ( left . m_nSkin ! = right . m_nSkin )
return left . m_nSkin > right . m_nSkin ;
if ( left . m_nLOD ! = right . m_nLOD )
return left . m_nLOD > right . m_nLOD ;
return left . m_nBody > right . m_nBody ;
}
//-----------------------------------------------------------------------------
// Sort models
//-----------------------------------------------------------------------------
void CModelRenderSystem : : SortModels ( RenderModelInfo_t * pRenderModelInfo ,
int nModelTypeCount , ModelListByType_t * pModelList , ModelListNode_t * pModelListNode )
{
// First place them in arrays
RenderModelInfo_t * pCurrInfo = pRenderModelInfo ;
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
list . m_pRenderModels = pCurrInfo ;
list . m_nSetupBoneCount = 0 ;
for ( ModelListNode_t * pNode = list . m_pFirstNode ; pNode ; pNode = pNode - > m_pNext )
{
memset ( pCurrInfo , 0 , sizeof ( RenderModelInfo_t ) ) ;
pCurrInfo - > m_Entry = pNode - > m_Entry ;
pCurrInfo - > m_nLOD = pNode - > m_nLOD ;
pCurrInfo - > m_nSkin = pNode - > m_Entry . m_pRenderable - > GetSkin ( ) ;
pCurrInfo - > m_nBody = pNode - > m_Entry . m_pRenderable - > GetBody ( ) ;
pCurrInfo - > m_hInstance = pNode - > m_Entry . m_pRenderable - > GetModelInstance ( ) ;
pCurrInfo - > m_Decals = STUDIORENDER_DECAL_INVALID ;
pCurrInfo - > m_nInitialListIndex = pNode - > m_nInitialListIndex ;
pCurrInfo - > m_bBoneMerge = pNode - > m_bBoneMerge ;
pCurrInfo - > m_bSetupBonesOnly = ( pNode - > m_Entry . m_pModelRenderable = = NULL ) ;
pCurrInfo - > m_pStencilState = pNode - > m_pStencilState ;
list . m_nSetupBoneCount + = pCurrInfo - > m_bSetupBonesOnly ;
+ + pCurrInfo ;
}
// Sort within this model type. skin first, then LOD, then body.
Assert ( pCurrInfo - list . m_pRenderModels = = list . m_nCount ) ;
std : : sort ( list . m_pRenderModels , list . m_pRenderModels + list . m_nCount , SortLessFunc ) ;
list . m_nCount - = list . m_nSetupBoneCount ;
list . m_nSetupBoneCount + = list . m_nCount ;
}
}
//-----------------------------------------------------------------------------
// Sets up bones on all models
//-----------------------------------------------------------------------------
void CModelRenderSystem : : SetupBones ( int nModelTypeCount , ModelListByType_t * pModelList )
{
// FIXME: Can we make parallel bone setup faster? Yes, we can!
const float flCurTime = gpGlobals - > curtime ;
matrix3x4a_t pPoseToBone [ MAXSTUDIOBONES ] ;
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
const int nBoneCount = list . m_pStudioHdr - > numbones ;
// Force setup of attachments if we're going to use an illumposition
const int nAttachmentMask = ( list . m_pStudioHdr - > IllumPositionAttachmentIndex ( ) > 0 ) ? BONE_USED_BY_ATTACHMENT : 0 ;
for ( int j = 0 ; j < list . m_nSetupBoneCount ; + + j )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
const int nBoneMask = BONE_USED_BY_VERTEX_AT_LOD ( pModel - > m_nLOD ) | nAttachmentMask ;
pModel - > m_pBoneToWorld = ( matrix3x4a_t * ) m_BoneToWorld . Alloc ( nBoneCount * sizeof ( matrix3x4a_t ) ) ;
const bool bOk = pModel - > m_Entry . m_pRenderable - > SetupBones ( pModel - > m_pBoneToWorld , nBoneCount , nBoneMask , flCurTime ) ;
if ( ! bOk )
{
for ( int k = 0 ; k < nBoneCount ; + + k )
{
SetIdentityMatrix ( pModel - > m_pBoneToWorld [ k ] ) ;
}
}
}
if ( list . m_nCount = = 0 )
continue ;
// Get the pose to bone for the model
if ( ! list . m_pStudioHdr - > pLinearBones ( ) )
{
// convert bone to world transformations into pose to world transformations
for ( int k = 0 ; k < nBoneCount ; k + + )
{
mstudiobone_t * pCurBone = list . m_pStudioHdr - > pBone ( k ) ;
MatrixCopy ( pCurBone - > poseToBone , pPoseToBone [ k ] ) ;
}
}
else
{
mstudiolinearbone_t * pLinearBones = list . m_pStudioHdr - > pLinearBones ( ) ;
// convert bone to world transformations into pose to world transformations
for ( int k = 0 ; k < nBoneCount ; k + + )
{
MatrixCopy ( pLinearBones - > poseToBone ( k ) , pPoseToBone [ k ] ) ;
}
}
// Apply the pose-to-bone matrix to all instances
// NOTE: We should be able to optimize this a ton since it's very parallelizable
// NOTE: We may well want to compute the aggregate bone to world here also.
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
CMatRenderData < matrix3x4a_t > rdPoseToWorld ( m_pRenderContext , nBoneCount ) ;
pModel - > m_pPoseToWorld = rdPoseToWorld . Base ( ) ;
for ( int b = 0 ; b < nBoneCount ; b + + )
{
ConcatTransforms_Aligned ( pModel - > m_pBoneToWorld [ b ] , pPoseToBone [ b ] , pModel - > m_pPoseToWorld [ b ] ) ;
}
}
}
}
//-----------------------------------------------------------------------------
// Sets up flexes on all models
//-----------------------------------------------------------------------------
void CModelRenderSystem : : SetupFlexes ( int nModelTypeCount , ModelListByType_t * pModelList )
{
bool bUsesDelayedWeights = g_CV_FlexSmooth . GetBool ( ) ;
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
const int nFlexCount = list . m_pStudioHdr - > numflexdesc ;
if ( ! nFlexCount )
continue ;
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
CMatRenderData < float > rdFlexWeights ( m_pRenderContext ) ;
CMatRenderData < float > rdDelayedFlexWeights ( m_pRenderContext ) ;
pModel - > m_pFlexWeights = rdFlexWeights . Lock ( nFlexCount ) ;
if ( bUsesDelayedWeights )
{
pModel - > m_pDelayedFlexWeights = rdDelayedFlexWeights . Lock ( nFlexCount ) ;
}
pModel - > m_Entry . m_pRenderable - > SetupWeights ( pModel - > m_pBoneToWorld , nFlexCount , pModel - > m_pFlexWeights , pModel - > m_pDelayedFlexWeights ) ;
}
}
}
//-----------------------------------------------------------------------------
// Draws debugging information for lighting
//-----------------------------------------------------------------------------
void CModelRenderSystem : : DebugDrawLightingOrigin ( const ModelListByType_t & list , const RenderModelInfo_t & model )
{
if ( ! model . m_pLightingState )
return ;
const Vector & lightOrigin = model . m_pLightingState - > m_vecLightingOrigin ;
const matrix3x4_t & modelToWorld = model . m_Entry . m_pRenderable - > RenderableToWorldTransform ( ) ;
// draw z planar cross at lighting origin
Vector pt0 ;
Vector pt1 ;
pt0 = lightOrigin ;
pt1 = lightOrigin ;
pt0 . x - = 4 ;
pt1 . x + = 4 ;
debugoverlay - > AddLineOverlay ( pt0 , pt1 , 0 , 255 , 0 , true , 0.0f ) ;
pt0 = lightOrigin ;
pt1 = lightOrigin ;
pt0 . y - = 4 ;
pt1 . y + = 4 ;
debugoverlay - > AddLineOverlay ( pt0 , pt1 , 0 , 255 , 0 , true , 0.0f ) ;
// draw lines from the light origin to the hull boundaries to identify model
Vector pt ;
pt0 . x = list . m_pStudioHdr - > hull_min . x ;
pt0 . y = list . m_pStudioHdr - > hull_min . y ;
pt0 . z = list . m_pStudioHdr - > hull_min . z ;
VectorTransform ( pt0 , modelToWorld , pt1 ) ;
debugoverlay - > AddLineOverlay ( lightOrigin , pt1 , 100 , 100 , 150 , true , 0.0f ) ;
pt0 . x = list . m_pStudioHdr - > hull_min . x ;
pt0 . y = list . m_pStudioHdr - > hull_max . y ;
pt0 . z = list . m_pStudioHdr - > hull_min . z ;
VectorTransform ( pt0 , modelToWorld , pt1 ) ;
debugoverlay - > AddLineOverlay ( lightOrigin , pt1 , 100 , 100 , 150 , true , 0.0f ) ;
pt0 . x = list . m_pStudioHdr - > hull_max . x ;
pt0 . y = list . m_pStudioHdr - > hull_max . y ;
pt0 . z = list . m_pStudioHdr - > hull_min . z ;
VectorTransform ( pt0 , modelToWorld , pt1 ) ;
debugoverlay - > AddLineOverlay ( lightOrigin , pt1 , 100 , 100 , 150 , true , 0.0f ) ;
pt0 . x = list . m_pStudioHdr - > hull_max . x ;
pt0 . y = list . m_pStudioHdr - > hull_min . y ;
pt0 . z = list . m_pStudioHdr - > hull_min . z ;
VectorTransform ( pt0 , modelToWorld , pt1 ) ;
debugoverlay - > AddLineOverlay ( lightOrigin , pt1 , 100 , 100 , 150 , true , 0.0f ) ;
pt0 . x = list . m_pStudioHdr - > hull_min . x ;
pt0 . y = list . m_pStudioHdr - > hull_min . y ;
pt0 . z = list . m_pStudioHdr - > hull_max . z ;
VectorTransform ( pt0 , modelToWorld , pt1 ) ;
debugoverlay - > AddLineOverlay ( lightOrigin , pt1 , 100 , 100 , 150 , true , 0.0f ) ;
pt0 . x = list . m_pStudioHdr - > hull_min . x ;
pt0 . y = list . m_pStudioHdr - > hull_max . y ;
pt0 . z = list . m_pStudioHdr - > hull_max . z ;
VectorTransform ( pt0 , modelToWorld , pt1 ) ;
debugoverlay - > AddLineOverlay ( lightOrigin , pt1 , 100 , 100 , 150 , true , 0.0f ) ;
pt0 . x = list . m_pStudioHdr - > hull_max . x ;
pt0 . y = list . m_pStudioHdr - > hull_max . y ;
pt0 . z = list . m_pStudioHdr - > hull_max . z ;
VectorTransform ( pt0 , modelToWorld , pt1 ) ;
debugoverlay - > AddLineOverlay ( lightOrigin , pt1 , 100 , 100 , 150 , true , 0.0f ) ;
pt0 . x = list . m_pStudioHdr - > hull_max . x ;
pt0 . y = list . m_pStudioHdr - > hull_min . y ;
pt0 . z = list . m_pStudioHdr - > hull_max . z ;
VectorTransform ( pt0 , modelToWorld , pt1 ) ;
debugoverlay - > AddLineOverlay ( lightOrigin , pt1 , 100 , 100 , 150 , true , 0.0f ) ;
}
//-----------------------------------------------------------------------------
// Compute lighting origin on all models
//-----------------------------------------------------------------------------
void CModelRenderSystem : : ComputeLightingOrigin ( ModelListByType_t & list , LightingQuery_t * pLightingQueryBase , int nQueryStride )
{
LightingQuery_t * pLightingQuery = pLightingQueryBase ;
//int nBoneMergeCount = 0;
int nAttachmentIndex = list . m_pStudioHdr - > IllumPositionAttachmentIndex ( ) ;
bool bAmbientBoost = ( list . m_pStudioHdr - > flags & STUDIOHDR_FLAGS_AMBIENT_BOOST ) ! = 0 ;
if ( nAttachmentIndex < = 0 | | nAttachmentIndex > list . m_pStudioHdr - > GetNumAttachments ( ) )
{
const Vector & vecIllumPosition = list . m_pStudioHdr - > illumposition ;
for ( int j = 0 ; j < list . m_nCount ; + + j , pLightingQuery = ( LightingQuery_t * ) ( ( unsigned char * ) pLightingQuery + nQueryStride ) )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
//nBoneMergeCount += pModel->m_bBoneMerge;
const matrix3x4_t & renderToWorld = pModel - > m_Entry . m_pRenderable - > RenderableToWorldTransform ( ) ;
pLightingQuery - > m_InstanceHandle = pModel - > m_hInstance ;
VectorTransform ( vecIllumPosition , renderToWorld , pLightingQuery - > m_LightingOrigin ) ;
//pLightingQuery->m_ParentInstanceHandle = MODEL_INSTANCE_INVALID;
pLightingQuery - > m_bAmbientBoost = bAmbientBoost ;
}
}
else
{
// NOTE: We don't care about orientation here.
// Assume the attachment->bone matrix has identity rotation. Given that,
// compute attachment->world = bone->world * attachment->bone.
// We only care about the translation component of attachment->world
// which can be obtained by transforming the attachment offset by bone->world
// Oh, and tough noogies if you want an illumposition offset also.
// Just make an attachment exactly where you want it. Otherwise this is slower.
# ifdef _DEBUG
if ( list . m_pStudioHdr - > illumposition ! = vec3_origin )
{
static int nWarnCount = 0 ;
if ( nWarnCount + + < 10 )
{
AssertMsg ( false , " Model fast path: illumposition must be (0,0,0) if an attachment is being used! \n " ) ;
}
}
# endif
// Attachment index is 1 too large, 0 means no attachment
- - nAttachmentIndex ;
Vector attachmentOffset ;
const mstudioattachment_t & attachment = list . m_pStudioHdr - > pAttachment ( nAttachmentIndex ) ;
MatrixGetColumn ( attachment . local , 3 , attachmentOffset ) ;
int iBone = list . m_pStudioHdr - > GetAttachmentBone ( nAttachmentIndex ) ;
for ( int j = 0 ; j < list . m_nCount ; + + j , pLightingQuery = ( LightingQuery_t * ) ( ( unsigned char * ) pLightingQuery + nQueryStride ) )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
//nBoneMergeCount += pModel->m_bBoneMerge;
pLightingQuery - > m_InstanceHandle = pModel - > m_hInstance ;
VectorTransform ( attachmentOffset , pModel - > m_pBoneToWorld [ iBone ] , pLightingQuery - > m_LightingOrigin ) ;
//pLightingQuery->m_ParentInstanceHandle = MODEL_INSTANCE_INVALID;
pLightingQuery - > m_bAmbientBoost = bAmbientBoost ;
}
}
#if 0
// NOTE: This is more expensive, but hopefully is uncommon
// Bonemerged models will copy the lighting environment from their parent entity.
// This fixes issues with L4D2 infected wounds where the wounds would sometimes receive different lighting
// than the body they're embedded in.
if ( nBoneMergeCount > 0 )
{
pLightingQuery = pLightingQueryBase ;
for ( int j = 0 ; j < list . m_nCount ; + + j , pLightingQuery = ( LightingQuery_t * ) ( ( unsigned char * ) pLightingQuery + nQueryStride ) )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
if ( ! pModel - > m_bBoneMerge )
continue ;
C_BaseEntity * pEnt = pModel - > m_Entry . m_pRenderable - > GetIClientUnknown ( ) - > GetBaseEntity ( ) ;
C_BaseEntity * pParent = pEnt - > GetMoveParent ( ) ;
if ( ! pParent )
continue ;
pLightingQuery - > m_ParentInstanceHandle = pParent - > GetModelInstance ( ) ;
}
}
# endif
}
//-----------------------------------------------------------------------------
// Builds the model lighting list
//-----------------------------------------------------------------------------
enum
{
LIGHTING_USES_ENV_CUBEMAP = 0x1 ,
LIGHTING_IS_VERTEX_LIT = 0x2 ,
LIGHTING_IS_STATIC_LIT = 0x4 ,
} ;
int CModelRenderSystem : : BuildLightingList ( ModelListByType_t * * ppLists , unsigned char * pFlags , int * pTotalModels , const LightingList_t & lightingList )
{
// FIXME: This may be better placed in the engine to avoid all the virtual calls?
int nSetupCount = 0 ;
* pTotalModels = 0 ;
for ( ModelListByType_t * pList = lightingList . m_pFirstModel ; pList ; pList = pList - > m_pNextLightingModel )
{
// FIXME: Under what conditions can the static prop skip lighting? [unlit materials]
bool bIsLit = modelinfo - > IsModelVertexLit ( pList - > m_pModel ) ;
bool bUsesEnvCubemap = modelinfo - > UsesEnvCubemap ( pList - > m_pModel ) ;
bool bIsStaticLit = modelinfo - > UsesStaticLighting ( pList - > m_pModel ) ;
if ( ! bIsLit & & ! bUsesEnvCubemap & & ! bIsStaticLit )
continue ;
ppLists [ nSetupCount ] = pList ;
pFlags [ nSetupCount ] = ( bIsStaticLit < < 2 ) | ( bIsLit < < 1 ) | ( bUsesEnvCubemap < < 0 ) ;
* pTotalModels + = pList - > m_nCount ;
+ + nSetupCount ;
}
return nSetupCount ;
}
//-----------------------------------------------------------------------------
// Hook up computed lighting state
//-----------------------------------------------------------------------------
void CModelRenderSystem : : HookUpStaticLightingState ( int nCount , ModelListByType_t * * ppLists ,
unsigned char * pFlags , ITexture * * ppEnvCubemap , MaterialLightingState_t * pLightingState ,
MaterialLightingState_t * pDecalLightingState , ColorMeshInfo_t * * ppColorMeshInfo )
{
// FIXME: This has got to be more efficient that this
for ( int i = 0 ; i < nCount ; + + i )
{
ModelListByType_t & list = * ( ppLists [ i ] ) ;
if ( pFlags [ i ] & LIGHTING_USES_ENV_CUBEMAP )
{
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
pModel - > m_pEnvCubemapTexture = ppEnvCubemap [ j ] ? ppEnvCubemap [ j ] : m_DefaultCubemap ;
}
}
if ( pFlags [ i ] & LIGHTING_IS_VERTEX_LIT )
{
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
pModel - > m_pLightingState = & pLightingState [ j ] ;
pModel - > m_pDecalLightingState = & pDecalLightingState [ j ] ;
}
}
if ( pFlags [ i ] & LIGHTING_IS_STATIC_LIT )
{
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
pModel - > m_pColorMeshInfo = ppColorMeshInfo [ j ] ;
}
}
ppEnvCubemap + = list . m_nCount ;
pLightingState + = list . m_nCount ;
pDecalLightingState + = list . m_nCount ;
ppColorMeshInfo + = list . m_nCount ;
}
}
//-----------------------------------------------------------------------------
// Sets up lighting on all models
//-----------------------------------------------------------------------------
int CModelRenderSystem : : SetupStaticPropLighting ( LightingList_t & lightingList , DataCacheHandle_t * pColorMeshHandle )
{
if ( lightingList . m_nCount = = 0 )
return 0 ;
// Build list of everything that needs lighting
int nTotalModels ;
ModelListByType_t * * ppLists = ( ModelListByType_t * * ) stackalloc ( lightingList . m_nCount * sizeof ( ModelListByType_t * ) ) ;
unsigned char * pFlags = ( unsigned char * ) stackalloc ( lightingList . m_nCount * sizeof ( unsigned char ) ) ;
int nSetupCount = BuildLightingList ( ppLists , pFlags , & nTotalModels , lightingList ) ;
if ( nSetupCount = = 0 )
return 0 ;
// Build queries used to compute lighting
StaticLightingQuery_t * pLightingQuery = ( StaticLightingQuery_t * ) stackalloc ( nTotalModels * sizeof ( StaticLightingQuery_t ) ) ;
int nOffset = 0 ;
for ( int i = 0 ; i < nSetupCount ; + + i )
{
ModelListByType_t & list = * ( ppLists [ i ] ) ;
for ( int j = 0 ; j < list . m_nCount ; + + j , + + nOffset )
{
pLightingQuery [ nOffset ] . m_pRenderable = list . m_pRenderModels [ j ] . m_Entry . m_pRenderable ;
pLightingQuery [ nOffset ] . m_InstanceHandle = list . m_pRenderModels [ j ] . m_hInstance ;
pLightingQuery [ nOffset ] . m_bAmbientBoost = false ;
}
}
// Compute lighting origins
staticpropmgr - > GetLightingOrigins ( & pLightingQuery [ 0 ] . m_LightingOrigin ,
sizeof ( StaticLightingQuery_t ) , nTotalModels , & pLightingQuery [ 0 ] . m_pRenderable , sizeof ( StaticLightingQuery_t ) ) ;
// Does all lighting computations for all models
ColorMeshInfo_t * * ppColorMeshInfo = ( ColorMeshInfo_t * * ) stackalloc ( nTotalModels * sizeof ( ColorMeshInfo_t * ) ) ;
ITexture * * ppEnvCubemap = ( ITexture * * ) stackalloc ( nTotalModels * sizeof ( ITexture * ) ) ;
CMatRenderData < MaterialLightingState_t > rdLightingState ( m_pRenderContext , 2 * nTotalModels ) ;
MaterialLightingState_t * pLightingState = rdLightingState . Base ( ) ;
MaterialLightingState_t * pDecalLightingState = & rdLightingState [ nTotalModels ] ;
modelrender - > ComputeStaticLightingState ( nTotalModels , pLightingQuery , pLightingState , pDecalLightingState , ppColorMeshInfo , ppEnvCubemap , pColorMeshHandle ) ;
// Hook up pointers
HookUpStaticLightingState ( nSetupCount , ppLists , pFlags , ppEnvCubemap , pLightingState , pDecalLightingState , ppColorMeshInfo ) ;
return nTotalModels ;
}
void CModelRenderSystem : : SetupStandardLighting ( LightingList_t & lightingList )
{
if ( lightingList . m_nCount = = 0 )
return ;
// Determine which groups need lighting
ModelListByType_t * * ppLists = ( ModelListByType_t * * ) stackalloc ( lightingList . m_nCount * sizeof ( ModelListByType_t * ) ) ;
unsigned char * pFlags = ( unsigned char * ) stackalloc ( lightingList . m_nCount * sizeof ( unsigned char ) ) ;
int nTotalModels = 0 ;
int nSetupCount = BuildLightingList ( ppLists , pFlags , & nTotalModels , lightingList ) ;
if ( nSetupCount = = 0 )
return ;
// Compute data necessary for lighting computations
int nOffset = 0 ;
LightingQuery_t * pLightingQuery = ( LightingQuery_t * ) stackalloc ( nTotalModels * sizeof ( LightingQuery_t ) ) ;
CMatRenderData < MaterialLightingState_t > rdLightingState ( m_pRenderContext , nTotalModels ) ;
MaterialLightingState_t * pLightingState = rdLightingState . Base ( ) ;
memset ( pLightingState , 0 , nTotalModels * sizeof ( MaterialLightingState_t ) ) ;
for ( int i = 0 ; i < nSetupCount ; + + i )
{
ModelListByType_t & list = * ( ppLists [ i ] ) ;
ComputeLightingOrigin ( list , & pLightingQuery [ nOffset ] , sizeof ( LightingQuery_t ) ) ;
nOffset + = list . m_nCount ;
}
// Does all lighting computations for all models
ITexture * * ppEnvCubemap = ( ITexture * * ) stackalloc ( nTotalModels * sizeof ( ITexture * ) ) ;
modelrender - > ComputeLightingState ( nTotalModels , pLightingQuery , pLightingState , ppEnvCubemap ) ;
// Hook up pointers
MaterialLightingState_t * pCurrState = pLightingState ;
for ( int i = 0 ; i < nSetupCount ; + + i )
{
ModelListByType_t & list = * ( ppLists [ i ] ) ;
if ( pFlags [ i ] & 0x1 )
{
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
pModel - > m_pEnvCubemapTexture = ppEnvCubemap [ j ] ? ppEnvCubemap [ j ] : m_DefaultCubemap ;
}
}
if ( pFlags [ i ] & 0x2 )
{
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
pModel - > m_pLightingState = & pCurrState [ j ] ;
}
}
ppEnvCubemap + = list . m_nCount ;
pCurrState + = list . m_nCount ;
}
}
int CModelRenderSystem : : SetupPhysicsPropLighting ( LightingList_t & lightingList , DataCacheHandle_t * pColorMeshHandle )
{
if ( lightingList . m_nCount = = 0 )
return 0 ;
// NOTE: Physics prop lighting is the same as static prop lighting, only
// the static lighting is *always* used (the system goes to the standard path
// for physics props which are moving or which use bumpmapping).
ModelListByType_t * * ppLists = ( ModelListByType_t * * ) stackalloc ( lightingList . m_nCount * sizeof ( ModelListByType_t * ) ) ;
unsigned char * pFlags = ( unsigned char * ) stackalloc ( lightingList . m_nCount * sizeof ( unsigned char ) ) ;
int nTotalModels = 0 ;
int nSetupCount = BuildLightingList ( ppLists , pFlags , & nTotalModels , lightingList ) ;
if ( nSetupCount = = 0 )
return 0 ;
StaticLightingQuery_t * pLightingQuery = ( StaticLightingQuery_t * ) stackalloc ( nTotalModels * sizeof ( StaticLightingQuery_t ) ) ;
int nOffset = 0 ;
for ( int i = 0 ; i < nSetupCount ; + + i )
{
ModelListByType_t & list = * ( ppLists [ i ] ) ;
ComputeLightingOrigin ( list , & pLightingQuery [ nOffset ] , sizeof ( StaticLightingQuery_t ) ) ;
for ( int j = 0 ; j < list . m_nCount ; + + j , + + nOffset )
{
pLightingQuery [ nOffset ] . m_pRenderable = list . m_pRenderModels [ j ] . m_Entry . m_pRenderable ;
}
}
// Does all lighting computations for all models
ColorMeshInfo_t * * ppColorMeshInfo = ( ColorMeshInfo_t * * ) stackalloc ( nTotalModels * sizeof ( ColorMeshInfo_t * ) ) ;
ITexture * * ppEnvCubemap = ( ITexture * * ) stackalloc ( nTotalModels * sizeof ( ITexture * ) ) ;
CMatRenderData < MaterialLightingState_t > rdLightingState ( m_pRenderContext , 2 * nTotalModels ) ;
MaterialLightingState_t * pLightingState = rdLightingState . Base ( ) ;
MaterialLightingState_t * pDecalLightingState = & pLightingState [ nTotalModels ] ;
modelrender - > ComputeStaticLightingState ( nTotalModels , pLightingQuery , pLightingState , pDecalLightingState , ppColorMeshInfo , ppEnvCubemap , pColorMeshHandle ) ;
// Hook up pointers
HookUpStaticLightingState ( nSetupCount , ppLists , pFlags , ppEnvCubemap , pLightingState , pDecalLightingState , ppColorMeshInfo ) ;
return nTotalModels ;
}
int CModelRenderSystem : : SetupLighting ( LightingList_t * pLightingList , int nModelTypeCount , ModelListByType_t * pModelList , DataCacheHandle_t * pColorMeshHandles , ModelRenderMode_t renderMode )
{
if ( renderMode ! = MODEL_RENDER_MODE_NORMAL )
{
return 0 ;
}
int nCount = SetupStaticPropLighting ( pLightingList [ LIGHTING_MODEL_STATIC_PROP ] , pColorMeshHandles ) ;
pColorMeshHandles + = nCount ;
SetupStandardLighting ( pLightingList [ LIGHTING_MODEL_STANDARD ] ) ;
nCount + = SetupPhysicsPropLighting ( pLightingList [ LIGHTING_MODEL_PHYSICS_PROP ] , pColorMeshHandles ) ;
// Debugging info
if ( r_drawmodellightorigin . GetBool ( ) )
{
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
const ModelListByType_t & list = pModelList [ i ] ;
if ( list . m_nLightingModel = = LIGHTING_MODEL_NONE )
continue ;
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
const RenderModelInfo_t & info = list . m_pRenderModels [ j ] ;
DebugDrawLightingOrigin ( list , info ) ;
}
}
}
return nCount ;
}
//-----------------------------------------------------------------------------
// Setup render state related to flashlights and decals
//-----------------------------------------------------------------------------
void CModelRenderSystem : : SetupFlashlightsAndDecals ( StudioModelArrayInfo2_t * pInfo , int nModelTypeCount , ModelListByType_t * pModelList , int nTotalModelCount , RenderModelInfo_t * pRenderModels , ModelRenderMode_t renderMode )
{
// Skip lighting + decals if we don't need it
if ( renderMode ! = MODEL_RENDER_MODE_NORMAL )
return ;
ShadowHandle_t pFlashlights [ MAX_FLASHLIGHTS_PER_INSTANCE_DRAW_CALL ] ;
int nInstCount = 0 ;
ModelInstanceHandle_t * pModelInstanceHandle = ( ModelInstanceHandle_t * ) stackalloc ( nTotalModelCount * sizeof ( ModelInstanceHandle_t ) ) ;
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
pModelInstanceHandle [ nInstCount + + ] = pModel - > m_hInstance ;
}
}
Assert ( nTotalModelCount = = nInstCount ) ;
if ( nTotalModelCount ! = nInstCount )
{
DevWarning ( " CModelRenderSystem::SetupFlashlightsAndDecals sorted model list count incorrect! A model was probably unable to load! " ) ;
nTotalModelCount = nInstCount ;
}
// Gets all decals
StudioDecalHandle_t * pDecals = & pRenderModels - > m_Decals ;
modelrender - > GetModelDecalHandles ( pDecals , sizeof ( RenderModelInfo_t ) , nTotalModelCount , pModelInstanceHandle ) ;
// Builds a list of all flashlights affecting this model
uint32 * pFlashlightUsage = & pRenderModels - > m_nFlashlightUsage ;
pInfo - > m_nFlashlightCount = shadowmgr - > SetupFlashlightRenderInstanceInfo ( pFlashlights , pFlashlightUsage , sizeof ( RenderModelInfo_t ) , nTotalModelCount , pModelInstanceHandle ) ;
if ( pInfo - > m_nFlashlightCount )
{
// Copy over the flashlight state
// FIXME: Should we do this over the entire list of all instances?
// There's going to be a fair amount of copying of flashlight_ts
CMatRenderData < FlashlightInstance_t > rdFlashlights ( m_pRenderContext , pInfo - > m_nFlashlightCount ) ;
pInfo - > m_pFlashlights = rdFlashlights . Base ( ) ;
shadowmgr - > GetFlashlightRenderInfo ( pInfo - > m_pFlashlights , pInfo - > m_nFlashlightCount , pFlashlights ) ;
}
else
{
pInfo - > m_pFlashlights = NULL ;
}
// FIXME: Hack!
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
list . m_nFlashlightCount = pInfo - > m_nFlashlightCount ;
list . m_pFlashlights = pInfo - > m_pFlashlights ;
}
}
void CModelRenderSystem : : SetupPerInstanceColorModulation ( int nModelTypeCount , ModelListByType_t * pModelList )
{
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
if ( ! list . m_nCount )
continue ;
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
RenderModelInfo_t * pModel = & list . m_pRenderModels [ j ] ;
IClientRenderable * pRenderable = pModel - > m_Entry . m_pRenderable ;
#if 0
Vector diffuseModulation ;
pRenderable - > GetColorModulation ( diffuseModulation . Base ( ) ) ;
pModel - > m_DiffuseModulation . x = diffuseModulation . x ;
pModel - > m_DiffuseModulation . y = diffuseModulation . y ;
pModel - > m_DiffuseModulation . z = diffuseModulation . z ;
# else // preferred to do it this way, because it avoids a load-hit-store on 360
pRenderable - > GetColorModulation ( pModel - > m_DiffuseModulation . AsVector3D ( ) . Base ( ) ) ;
# endif
pModel - > m_DiffuseModulation . w = pModel - > m_Entry . m_InstanceData . m_nAlpha * ( 1.0f / 255.0f ) ;
}
}
}
//-----------------------------------------------------------------------------
// Call into studiorender
//-----------------------------------------------------------------------------
ConVar cl_colorfastpath ( " cl_colorfastpath " , " 0 " ) ;
void CModelRenderSystem : : RenderModels ( StudioModelArrayInfo2_t * pInfo , int nModelTypeCount , ModelListByType_t * pModelList , int nTotalModelCount , ModelRenderMode_t renderMode )
{
if ( renderMode = = MODEL_RENDER_MODE_NORMAL )
{
bool bColorize = cl_colorfastpath . GetBool ( ) ;
if ( bColorize )
{
g_pStudioRender - > ForcedMaterialOverride ( m_DebugMaterial ) ;
}
const int nFlags = STUDIORENDER_DRAW_OPAQUE_ONLY ;
CMatRenderData < StudioArrayData_t > rdArray ( m_pRenderContext , nModelTypeCount ) ;
# ifdef _DEBUG
bool bFoundStencil = false ;
# endif
int nNonStencilModelTypeCount = 0 ;
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
rdArray [ i ] . m_pStudioHdr = list . m_pStudioHdr ;
rdArray [ i ] . m_pHardwareData = list . m_pHardwareData ;
rdArray [ i ] . m_pInstanceData = list . m_pRenderModels ;
rdArray [ i ] . m_nCount = list . m_nCount ;
nNonStencilModelTypeCount + = list . m_bWantsStencil ? 0 : 1 ;
# ifdef _DEBUG
if ( list . m_bWantsStencil )
{
bFoundStencil = true ;
}
else
{
Assert ( ! bFoundStencil ) ;
}
# endif
}
if ( IsX360 ( ) & & r_fastzreject . GetBool ( ) & & ( nNonStencilModelTypeCount ! = nModelTypeCount ) )
{
// Render all models without stencil
g_pStudioRender - > DrawModelArray ( * pInfo , nNonStencilModelTypeCount , rdArray . Base ( ) , sizeof ( RenderModelInfo_t ) , nFlags ) ;
# ifdef _X360
// end z prepass here
CMatRenderContextPtr pRenderContext ( g_pMaterialSystem ) ;
pRenderContext - > End360ZPass ( ) ;
# endif
// Render all models with stencil
g_pStudioRender - > DrawModelArray ( * pInfo , nModelTypeCount - nNonStencilModelTypeCount , rdArray . Base ( ) + nNonStencilModelTypeCount ,
sizeof ( RenderModelInfo_t ) , nFlags ) ;
}
else
{
// PC renders all models in one go regardless of stencil state
g_pStudioRender - > DrawModelArray ( * pInfo , nModelTypeCount , rdArray . Base ( ) , sizeof ( RenderModelInfo_t ) , nFlags ) ;
}
g_pStudioRender - > ForcedMaterialOverride ( NULL ) ;
}
else if ( renderMode = = MODEL_RENDER_MODE_SHADOW_DEPTH )
{
// NOTE: Use this path because we can aggregate draw calls across mdls
const int nFlags = STUDIORENDER_SHADOWDEPTHTEXTURE | STUDIORENDER_DRAW_OPAQUE_ONLY ;
CMatRenderData < StudioArrayData_t > rdShadow ( m_pRenderContext , nModelTypeCount ) ;
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
rdShadow [ i ] . m_pStudioHdr = list . m_pStudioHdr ;
rdShadow [ i ] . m_pHardwareData = list . m_pHardwareData ;
rdShadow [ i ] . m_pInstanceData = list . m_pRenderModels ;
rdShadow [ i ] . m_nCount = list . m_nCount ;
}
g_pStudioRender - > DrawModelShadowArray ( nModelTypeCount , rdShadow . Base ( ) , sizeof ( RenderModelInfo_t ) , nFlags ) ;
}
else if ( renderMode = = MODEL_RENDER_MODE_RTT_SHADOWS )
{
// shouldn't get here unless the code is ported from l4d2 to drive this properly.
Assert ( 0 ) ;
#if 0
// HACK: Assume all models in this batch use the same material. This only works because we submit batches of 1 model from the client shadow manager at the moment
IMaterial * pShadowDrawMaterial = pModelList [ 0 ] . m_pFirstNode - > m_Entry . m_pRenderable - > GetShadowDrawMaterial ( ) ;
g_pStudioRender - > ForcedMaterialOverride ( pShadowDrawMaterial ? pShadowDrawMaterial : m_ShadowBuild , OVERRIDE_BUILD_SHADOWS ) ;
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
g_pStudioRender - > DrawModelArray ( list , list . m_nCount , list . m_pRenderModels , sizeof ( RenderModelInfo_t ) , STUDIORENDER_DRAW_OPAQUE_ONLY ) ;
}
g_pStudioRender - > ForcedMaterialOverride ( NULL ) ;
# endif
}
}
//-----------------------------------------------------------------------------
// Call into studiorender
//-----------------------------------------------------------------------------
void CModelRenderSystem : : SetupTranslucentData ( int nModelTypeCount , ModelListByType_t * pModelList , int nTotalModelCount , TranslucentInstanceRenderData_t * pRenderData )
{
memset ( pRenderData , 0 , nTotalModelCount * sizeof ( TranslucentInstanceRenderData_t ) ) ;
CMatRenderData < StudioModelArrayInfo_t > arrayInfo ( m_pRenderContext , nModelTypeCount ) ;
CMatRenderData < StudioArrayInstanceData_t > instanceData ( m_pRenderContext , nTotalModelCount ) ;
int nCurInstance = 0 ;
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
StudioModelArrayInfo_t * pModelInfo = & arrayInfo [ i ] ;
memcpy ( pModelInfo , & list , sizeof ( StudioModelArrayInfo_t ) ) ;
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
RenderModelInfo_t & info = list . m_pRenderModels [ j ] ;
StudioArrayInstanceData_t * pInstanceData = & instanceData [ nCurInstance + + ] ;
memcpy ( pInstanceData , & info , sizeof ( StudioArrayInstanceData_t ) ) ;
TranslucentInstanceRenderData_t & data = pRenderData [ info . m_nInitialListIndex ] ;
data . m_pModelInfo = pModelInfo ;
data . m_pInstanceData = pInstanceData ;
}
}
}
//-----------------------------------------------------------------------------
// Renders debug overlays
//-----------------------------------------------------------------------------
void CModelRenderSystem : : RenderVCollideDebugOverlay ( int nModelTypeCount , ModelListByType_t * pModelList )
{
if ( ! vcollide_wireframe . GetBool ( ) )
return ;
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
IClientRenderable * pRenderable = list . m_pRenderModels [ j ] . m_Entry . m_pRenderable ;
C_BaseAnimating * pAnim = dynamic_cast < C_BaseAnimating * > ( pRenderable ) ;
if ( pAnim & & pAnim - > IsRagdoll ( ) )
{
pAnim - > m_pRagdoll - > DrawWireframe ( ) ;
continue ;
}
ICollideable * pCollideable = pRenderable - > GetIClientUnknown ( ) - > GetCollideable ( ) ;
if ( pCollideable & & ( pCollideable - > GetSolid ( ) = = SOLID_VPHYSICS ) & &
IsSolid ( pCollideable - > GetSolid ( ) , pCollideable - > GetSolidFlags ( ) ) )
{
vcollide_t * pCollide = modelinfo - > GetVCollide ( pCollideable - > GetCollisionModel ( ) ) ;
if ( pCollide & & pCollide - > solidCount = = 1 )
{
static color32 debugColor = { 0 , 255 , 255 , 0 } ;
engine - > DebugDrawPhysCollide ( pCollide - > solids [ 0 ] , NULL , pCollideable - > CollisionToWorldTransform ( ) , debugColor ) ;
C_BaseEntity * pEntity = pRenderable - > GetIClientUnknown ( ) - > GetBaseEntity ( ) ;
if ( pEntity & & pEntity - > VPhysicsGetObject ( ) )
{
static color32 debugColorPhys = { 255 , 0 , 0 , 0 } ;
matrix3x4_t matrix ;
pEntity - > VPhysicsGetObject ( ) - > GetPositionMatrix ( & matrix ) ;
engine - > DebugDrawPhysCollide ( pCollide - > solids [ 0 ] , NULL , matrix , debugColorPhys ) ;
}
}
continue ;
}
}
}
}
void CModelRenderSystem : : RenderBBoxDebugOverlay ( int nModelTypeCount , ModelListByType_t * pModelList )
{
for ( int i = 0 ; i < nModelTypeCount ; + + i )
{
ModelListByType_t & list = pModelList [ i ] ;
for ( int j = 0 ; j < list . m_nCount ; + + j )
{
IClientRenderable * pRenderable = list . m_pRenderModels [ j ] . m_Entry . m_pRenderable ;
if ( ! pRenderable - > GetIClientUnknown ( ) )
continue ;
C_BaseEntity * pEntity = pRenderable - > GetIClientUnknown ( ) - > GetBaseEntity ( ) ;
if ( ! pEntity )
continue ;
pEntity - > DrawBBoxVisualizations ( ) ;
}
}
}
//-----------------------------------------------------------------------------
// Renders debug overlays
//-----------------------------------------------------------------------------
void CModelRenderSystem : : RenderDebugOverlays ( int nModelTypeCount , ModelListByType_t * pModelList , ModelRenderMode_t renderMode )
{
if ( renderMode ! = MODEL_RENDER_MODE_NORMAL )
{
return ;
}
RenderVCollideDebugOverlay ( nModelTypeCount , pModelList ) ;
RenderBBoxDebugOverlay ( nModelTypeCount , pModelList ) ;
}
//-----------------------------------------------------------------------------
// Sort model types function
//-----------------------------------------------------------------------------
inline bool CModelRenderSystem : : StencilSortLessFunc ( const ModelListByType_t & left , const ModelListByType_t & right )
{
// Ensure stenciling models are at the end of the list
if ( left . m_bWantsStencil ! = right . m_bWantsStencil )
{
return left . m_bWantsStencil < right . m_bWantsStencil ;
}
// Keep same models with different lighting types together
return left . m_pModel < right . m_pModel ;
}
//-----------------------------------------------------------------------------
// Draw models
//-----------------------------------------------------------------------------
static ConVar cl_skipfastpath ( " cl_skipfastpath " , " 0 " , FCVAR_CHEAT , " Set to 1 to stop all models that go through the model fast path from rendering " ) ;
void CModelRenderSystem : : DrawModels ( ModelRenderSystemData_t * pEntities , int nCount , ModelRenderMode_t renderMode )
{
if ( nCount = = 0 | | cl_skipfastpath . GetInt ( ) )
return ;
VPROF_BUDGET ( " CModelRenderSystem::DrawModels " , VPROF_BUDGETGROUP_MODEL_FAST_PATH_RENDERING ) ;
MDLCACHE_CRITICAL_SECTION_ ( g_pMDLCache ) ;
// While doing this, we need materialsystem to keep around its temp allocations
// which we use for bone matrices + flexes
CMatRenderContextPtr matRenderContext ( g_pMaterialSystem ) ;
m_pRenderContext = matRenderContext ;
PIXEVENT ( m_pRenderContext , " CModelRenderSystem::DrawModels (FASTPATH) " ) ;
CMatRenderDataReference rdLock ( m_pRenderContext ) ;
// FIXME: This is infected-specific for perf test reasons.
// Will break into a more fixed pipeline at a later date
DataCacheHandle_t * pColorMeshHandles = NULL ;
if ( renderMode = = MODEL_RENDER_MODE_NORMAL )
{
pColorMeshHandles = ( DataCacheHandle_t * ) stackalloc ( nCount * sizeof ( DataCacheHandle_t ) ) ;
}
ModelListByType_t * pModelList = ( ModelListByType_t * ) stackalloc ( nCount * sizeof ( ModelListByType_t ) ) ;
ModelListNode_t * pModelListNode = ( ModelListNode_t * ) stackalloc ( nCount * sizeof ( ModelListNode_t ) ) ;
int nModelsRenderingStencilCount = 0 ;
int nModelTypeCount = BucketModelsByMDL ( pModelList , pModelListNode , pEntities , nCount , renderMode , & nModelsRenderingStencilCount ) ;
LightingList_t pLightingList [ LIGHTING_MODEL_COUNT ] ;
memset ( pLightingList , 0 , LIGHTING_MODEL_COUNT * sizeof ( LightingList_t ) ) ;
SortBucketsByDependency ( nModelTypeCount , pModelList , pLightingList ) ;
// Compute LODs for each model
ComputeModelLODs ( nModelTypeCount , pModelList , pModelListNode , renderMode ) ;
// Sort processing list by body, lod, skin, etc.
CMatRenderData < RenderModelInfo_t > rdRenderModelInfo ( m_pRenderContext , nCount ) ;
RenderModelInfo_t * pSortedModelListNode = rdRenderModelInfo . Base ( ) ;
SortModels ( pSortedModelListNode , nModelTypeCount , pModelList , pModelListNode ) ;
// Setup bones
SetupBones ( nModelTypeCount , pModelList ) ;
// Setup flexes
if ( renderMode ! = MODEL_RENDER_MODE_RTT_SHADOWS )
{
SetupFlexes ( nModelTypeCount , pModelList ) ;
}
// Setup lighting
int nColorMeshHandles = SetupLighting ( pLightingList , nModelTypeCount , pModelList , pColorMeshHandles , renderMode ) ;
// Setup flashlights + decals
StudioModelArrayInfo2_t info ;
SetupFlashlightsAndDecals ( & info , nModelTypeCount , pModelList , nCount , pSortedModelListNode , renderMode ) ;
// Setup per-instance color modulation
SetupPerInstanceColorModulation ( nModelTypeCount , pModelList ) ;
// Setup per-instance wound data
//SetupInfectedWoundRenderData( nModelTypeCount, pModelList, nCount, renderMode );
if ( IsX360 ( ) & & ( renderMode = = MODEL_RENDER_MODE_NORMAL ) & & ( nModelsRenderingStencilCount > 0 ) )
{
// resort here to make sure all models rendering stencil come last
std : : sort ( pModelList , pModelList + nModelTypeCount , StencilSortLessFunc ) ;
}
// Draw models
RenderModels ( & info , nModelTypeCount , pModelList , nCount , renderMode ) ;
rdLock . Release ( ) ;
if ( renderMode = = MODEL_RENDER_MODE_NORMAL )
{
modelrender - > CleanupStaticLightingState ( nColorMeshHandles , pColorMeshHandles ) ;
stackfree ( pColorMeshHandles ) ;
}
// Blat out temporary memory for bone-to-world transforms
m_BoneToWorld . FreeAll ( false ) ;
RenderDebugOverlays ( nModelTypeCount , pModelList , renderMode ) ;
m_pRenderContext = NULL ;
}
//-----------------------------------------------------------------------------
// Computes per-instance data for fast path rendering
//-----------------------------------------------------------------------------
void CModelRenderSystem : : ComputeTranslucentRenderData ( ModelRenderSystemData_t * pModels , int nCount , TranslucentInstanceRenderData_t * pRenderData , TranslucentTempData_t * pTempData )
{
if ( nCount = = 0 )
{
pTempData - > m_nColorMeshHandleCount = 0 ;
pTempData - > m_bReleaseRenderData = false ;
return ;
}
VPROF_BUDGET ( " CModelRenderSystem::ComputeTranslucentRenderData " , VPROF_BUDGETGROUP_MODEL_FAST_PATH_RENDERING ) ;
MDLCACHE_CRITICAL_SECTION_ ( g_pMDLCache ) ;
// While doing this, we need materialsystem to keep around its temp allocations
// which we use for bone matrices + flexes
CMatRenderContextPtr matRenderContext ( g_pMaterialSystem ) ;
m_pRenderContext = matRenderContext ;
PIXEVENT ( m_pRenderContext , " CModelRenderSystem::ComputeTranslucentRenderData (FASTPATH) " ) ;
m_pRenderContext - > AddRefRenderData ( ) ;
pTempData - > m_bReleaseRenderData = true ;
ModelRenderMode_t renderMode = MODEL_RENDER_MODE_NORMAL ;
// FIXME: This is infected-specific for perf test reasons.
// Will break into a more fixed pipeline at a later date
DataCacheHandle_t * pColorMeshHandles = pTempData - > m_pColorMeshHandles ;
ModelListByType_t * pModelList = ( ModelListByType_t * ) stackalloc ( nCount * sizeof ( ModelListByType_t ) ) ;
ModelListNode_t * pModelListNode = ( ModelListNode_t * ) stackalloc ( nCount * sizeof ( ModelListNode_t ) ) ;
int nModelsRenderingStencilCount = 0 ;
int nModelTypeCount = BucketModelsByMDL ( pModelList , pModelListNode , pModels , nCount , renderMode , & nModelsRenderingStencilCount ) ;
LightingList_t pLightingList [ LIGHTING_MODEL_COUNT ] ;
memset ( pLightingList , 0 , LIGHTING_MODEL_COUNT * sizeof ( LightingList_t ) ) ;
SortBucketsByDependency ( nModelTypeCount , pModelList , pLightingList ) ;
// Compute LODs for each model
ComputeModelLODs ( nModelTypeCount , pModelList , pModelListNode , renderMode ) ;
// Sort processing list by body, lod, skin, etc.
RenderModelInfo_t * pSortedModelListNode = ( RenderModelInfo_t * ) stackalloc ( nCount * sizeof ( RenderModelInfo_t ) ) ;
SortModels ( pSortedModelListNode , nModelTypeCount , pModelList , pModelListNode ) ;
// Setup bones
SetupBones ( nModelTypeCount , pModelList ) ;
// Setup flexes
SetupFlexes ( nModelTypeCount , pModelList ) ;
// Setup lighting
pTempData - > m_nColorMeshHandleCount = SetupLighting ( pLightingList , nModelTypeCount , pModelList , pColorMeshHandles , renderMode ) ;
// Setup flashlights + decals
StudioModelArrayInfo2_t info ;
SetupFlashlightsAndDecals ( & info , nModelTypeCount , pModelList , nCount , pSortedModelListNode , renderMode ) ;
// Setup per-instance color modulation
SetupPerInstanceColorModulation ( nModelTypeCount , pModelList ) ;
// Setup per-instance wound data
// SetupInfectedWoundRenderData( nModelTypeCount, pModelList, nCount, renderMode );
// Draw models
SetupTranslucentData ( nModelTypeCount , pModelList , nCount , pRenderData ) ;
// Blat out temporary memory for bone-to-world transforms
m_BoneToWorld . FreeAll ( false ) ;
RenderDebugOverlays ( nModelTypeCount , pModelList , renderMode ) ;
m_pRenderContext = NULL ;
}
void CModelRenderSystem : : CleanupTranslucentTempData ( TranslucentTempData_t * pTempData )
{
if ( pTempData - > m_bReleaseRenderData )
{
modelrender - > CleanupStaticLightingState ( pTempData - > m_nColorMeshHandleCount , pTempData - > m_pColorMeshHandles ) ;
CMatRenderContextPtr matRenderContext ( g_pMaterialSystem ) ;
matRenderContext - > ReleaseRenderData ( ) ;
}
}