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.
762 lines
24 KiB
762 lines
24 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//===========================================================================// |
|
|
|
#include <stdlib.h> |
|
#include "studiorender.h" |
|
#include "studiorendercontext.h" |
|
#include "materialsystem/imaterialsystem.h" |
|
#include "materialsystem/imaterialsystemhardwareconfig.h" |
|
#include "materialsystem/imaterial.h" |
|
#include "materialsystem/imaterialvar.h" |
|
#include "materialsystem/imesh.h" |
|
#include "optimize.h" |
|
#include "mathlib/vmatrix.h" |
|
#include "tier0/vprof.h" |
|
#include "tier1/strtools.h" |
|
#include "tier1/KeyValues.h" |
|
#include "tier0/memalloc.h" |
|
#include "convar.h" |
|
#include "materialsystem/itexture.h" |
|
#include "tier2/tier2.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
//----------------------------------------------------------------------------- |
|
// Singleton instance |
|
//----------------------------------------------------------------------------- |
|
CStudioRender g_StudioRender; |
|
CStudioRender *g_pStudioRenderImp = &g_StudioRender; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Activate to get stats |
|
//----------------------------------------------------------------------------- |
|
//#define REPORT_FLEX_STATS 1 |
|
|
|
#ifdef REPORT_FLEX_STATS |
|
static int s_nModelsDrawn = 0; |
|
static int s_nActiveFlexCount = 0; |
|
static ConVar r_flexstats( "r_flexstats", "0", FCVAR_CHEAT ); |
|
#endif |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Constructor |
|
//----------------------------------------------------------------------------- |
|
CStudioRender::CStudioRender() |
|
{ |
|
m_pRC = NULL; |
|
m_pBoneToWorld = NULL; |
|
m_pFlexWeights = NULL; |
|
m_pFlexDelayedWeights = NULL; |
|
m_pStudioHdr = NULL; |
|
m_pStudioMeshes = NULL; |
|
m_pSubModel = NULL; |
|
m_pGlintTexture = NULL; |
|
m_GlintWidth = 0; |
|
m_GlintHeight = 0; |
|
|
|
// Cache-align our important matrices |
|
MemAlloc_PushAllocDbgInfo( __FILE__, __LINE__ ); |
|
|
|
m_PoseToWorld = (matrix3x4_t*)MemAlloc_AllocAligned( MAXSTUDIOBONES * sizeof(matrix3x4_t), 32 ); |
|
m_PoseToDecal = (matrix3x4_t*)MemAlloc_AllocAligned( MAXSTUDIOBONES * sizeof(matrix3x4_t), 32 ); |
|
|
|
MemAlloc_PopAllocDbgInfo(); |
|
m_nDecalId = 1; |
|
} |
|
|
|
CStudioRender::~CStudioRender() |
|
{ |
|
MemAlloc_FreeAligned(m_PoseToWorld); |
|
MemAlloc_FreeAligned(m_PoseToDecal); |
|
} |
|
|
|
void CStudioRender::InitDebugMaterials( void ) |
|
{ |
|
m_pMaterialMRMWireframe = |
|
g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugmrmwireframe", TEXTURE_GROUP_OTHER, true ); |
|
m_pMaterialMRMWireframe->IncrementReferenceCount(); |
|
|
|
m_pMaterialMRMWireframeZBuffer = |
|
g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugmrmwireframezbuffer", TEXTURE_GROUP_OTHER, true ); |
|
m_pMaterialMRMWireframeZBuffer->IncrementReferenceCount(); |
|
|
|
m_pMaterialMRMNormals = |
|
g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugmrmnormals", TEXTURE_GROUP_OTHER, true ); |
|
m_pMaterialMRMNormals->IncrementReferenceCount(); |
|
|
|
m_pMaterialTangentFrame = |
|
g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugvertexcolor", TEXTURE_GROUP_OTHER, true ); |
|
m_pMaterialTangentFrame->IncrementReferenceCount(); |
|
|
|
m_pMaterialTranslucentModelHulls = |
|
g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugtranslucentmodelhulls", TEXTURE_GROUP_OTHER, true ); |
|
m_pMaterialTranslucentModelHulls->IncrementReferenceCount(); |
|
|
|
m_pMaterialSolidModelHulls = |
|
g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugsolidmodelhulls", TEXTURE_GROUP_OTHER, true ); |
|
m_pMaterialSolidModelHulls->IncrementReferenceCount(); |
|
|
|
m_pMaterialAdditiveVertexColorVertexAlpha = |
|
g_pMaterialSystem->FindMaterial( "//platform/materials/debug/additivevertexcolorvertexalpha", TEXTURE_GROUP_OTHER, true ); |
|
m_pMaterialAdditiveVertexColorVertexAlpha->IncrementReferenceCount(); |
|
|
|
m_pMaterialModelBones = |
|
g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugmodelbones", TEXTURE_GROUP_OTHER, true ); |
|
m_pMaterialModelBones->IncrementReferenceCount(); |
|
|
|
m_pMaterialModelEnvCubemap = |
|
g_pMaterialSystem->FindMaterial( "//platform/materials/debug/env_cubemap_model", TEXTURE_GROUP_OTHER, true ); |
|
m_pMaterialModelEnvCubemap->IncrementReferenceCount(); |
|
|
|
m_pMaterialWorldWireframe = |
|
g_pMaterialSystem->FindMaterial( "//platform/materials/debug/debugworldwireframe", TEXTURE_GROUP_OTHER, true ); |
|
m_pMaterialWorldWireframe->IncrementReferenceCount(); |
|
|
|
if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 90 ) |
|
{ |
|
KeyValues *pVMTKeyValues = new KeyValues( "DepthWrite" ); |
|
pVMTKeyValues->SetInt( "$no_fullbright", 1 ); |
|
pVMTKeyValues->SetInt( "$alphatest", 0 ); |
|
pVMTKeyValues->SetInt( "$nocull", 0 ); |
|
m_pDepthWrite[0][0] = g_pMaterialSystem->FindProceduralMaterial( "__DepthWrite00", TEXTURE_GROUP_OTHER, pVMTKeyValues ); |
|
m_pDepthWrite[0][0]->IncrementReferenceCount(); |
|
|
|
pVMTKeyValues = new KeyValues( "DepthWrite" ); |
|
pVMTKeyValues->SetInt( "$no_fullbright", 1 ); |
|
pVMTKeyValues->SetInt( "$alphatest", 0 ); |
|
pVMTKeyValues->SetInt( "$nocull", 1 ); |
|
m_pDepthWrite[0][1] = g_pMaterialSystem->FindProceduralMaterial( "__DepthWrite01", TEXTURE_GROUP_OTHER, pVMTKeyValues ); |
|
m_pDepthWrite[0][1]->IncrementReferenceCount(); |
|
|
|
pVMTKeyValues = new KeyValues( "DepthWrite" ); |
|
pVMTKeyValues->SetInt( "$no_fullbright", 1 ); |
|
pVMTKeyValues->SetInt( "$alphatest", 1 ); |
|
pVMTKeyValues->SetInt( "$nocull", 0 ); |
|
m_pDepthWrite[1][0] = g_pMaterialSystem->FindProceduralMaterial( "__DepthWrite10", TEXTURE_GROUP_OTHER, pVMTKeyValues ); |
|
m_pDepthWrite[1][0]->IncrementReferenceCount(); |
|
|
|
pVMTKeyValues = new KeyValues( "DepthWrite" ); |
|
pVMTKeyValues->SetInt( "$no_fullbright", 1 ); |
|
pVMTKeyValues->SetInt( "$alphatest", 1 ); |
|
pVMTKeyValues->SetInt( "$nocull", 1 ); |
|
m_pDepthWrite[1][1] = g_pMaterialSystem->FindProceduralMaterial( "__DepthWrite11", TEXTURE_GROUP_OTHER, pVMTKeyValues ); |
|
m_pDepthWrite[1][1]->IncrementReferenceCount(); |
|
|
|
pVMTKeyValues = new KeyValues( "DepthWrite" ); |
|
pVMTKeyValues->SetInt( "$no_fullbright", 1 ); |
|
pVMTKeyValues->SetInt( "$alphatest", 0 ); |
|
pVMTKeyValues->SetInt( "$nocull", 0 ); |
|
pVMTKeyValues->SetInt( "$color_depth", 1 ); |
|
m_pSSAODepthWrite[0][0] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite00", TEXTURE_GROUP_OTHER, pVMTKeyValues ); |
|
m_pSSAODepthWrite[0][0]->IncrementReferenceCount(); |
|
|
|
pVMTKeyValues = new KeyValues( "DepthWrite" ); |
|
pVMTKeyValues->SetInt( "$no_fullbright", 1 ); |
|
pVMTKeyValues->SetInt( "$alphatest", 0 ); |
|
pVMTKeyValues->SetInt( "$nocull", 1 ); |
|
pVMTKeyValues->SetInt( "$color_depth", 1 ); |
|
m_pSSAODepthWrite[0][1] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite01", TEXTURE_GROUP_OTHER, pVMTKeyValues ); |
|
m_pSSAODepthWrite[0][1]->IncrementReferenceCount(); |
|
|
|
pVMTKeyValues = new KeyValues( "DepthWrite" ); |
|
pVMTKeyValues->SetInt( "$no_fullbright", 1 ); |
|
pVMTKeyValues->SetInt( "$alphatest", 1 ); |
|
pVMTKeyValues->SetInt( "$nocull", 0 ); |
|
pVMTKeyValues->SetInt( "$color_depth", 1 ); |
|
m_pSSAODepthWrite[1][0] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite10", TEXTURE_GROUP_OTHER, pVMTKeyValues ); |
|
m_pSSAODepthWrite[1][0]->IncrementReferenceCount(); |
|
|
|
pVMTKeyValues = new KeyValues( "DepthWrite" ); |
|
pVMTKeyValues->SetInt( "$no_fullbright", 1 ); |
|
pVMTKeyValues->SetInt( "$alphatest", 1 ); |
|
pVMTKeyValues->SetInt( "$nocull", 1 ); |
|
pVMTKeyValues->SetInt( "$color_depth", 1 ); |
|
m_pSSAODepthWrite[1][1] = g_pMaterialSystem->FindProceduralMaterial( "__ColorDepthWrite11", TEXTURE_GROUP_OTHER, pVMTKeyValues ); |
|
m_pSSAODepthWrite[1][1]->IncrementReferenceCount(); |
|
|
|
pVMTKeyValues = new KeyValues( "EyeGlint" ); |
|
m_pGlintBuildMaterial = g_pMaterialSystem->CreateMaterial( "___glintbuildmaterial", pVMTKeyValues ); |
|
} |
|
} |
|
|
|
void CStudioRender::ShutdownDebugMaterials( void ) |
|
{ |
|
#ifdef _WIN32 |
|
if ( m_pMaterialMRMWireframe ) |
|
{ |
|
m_pMaterialMRMWireframe->DecrementReferenceCount(); |
|
m_pMaterialMRMWireframe = NULL; |
|
} |
|
|
|
if ( m_pMaterialMRMWireframeZBuffer ) |
|
{ |
|
m_pMaterialMRMWireframeZBuffer->DecrementReferenceCount(); |
|
m_pMaterialMRMWireframeZBuffer = NULL; |
|
} |
|
|
|
if ( m_pMaterialMRMNormals ) |
|
{ |
|
m_pMaterialMRMNormals->DecrementReferenceCount(); |
|
m_pMaterialMRMNormals = NULL; |
|
} |
|
|
|
if ( m_pMaterialTangentFrame ) |
|
{ |
|
m_pMaterialTangentFrame->DecrementReferenceCount(); |
|
m_pMaterialTangentFrame = NULL; |
|
} |
|
|
|
if ( m_pMaterialTranslucentModelHulls ) |
|
{ |
|
m_pMaterialTranslucentModelHulls->DecrementReferenceCount(); |
|
m_pMaterialTranslucentModelHulls = NULL; |
|
} |
|
|
|
if ( m_pMaterialSolidModelHulls ) |
|
{ |
|
m_pMaterialSolidModelHulls->DecrementReferenceCount(); |
|
m_pMaterialSolidModelHulls = NULL; |
|
} |
|
|
|
if ( m_pMaterialAdditiveVertexColorVertexAlpha ) |
|
{ |
|
m_pMaterialAdditiveVertexColorVertexAlpha->DecrementReferenceCount(); |
|
m_pMaterialAdditiveVertexColorVertexAlpha = NULL; |
|
} |
|
|
|
if ( m_pMaterialModelBones ) |
|
{ |
|
m_pMaterialModelBones->DecrementReferenceCount(); |
|
m_pMaterialModelBones = NULL; |
|
} |
|
|
|
if ( m_pMaterialModelEnvCubemap ) |
|
{ |
|
m_pMaterialModelEnvCubemap->DecrementReferenceCount(); |
|
m_pMaterialModelEnvCubemap = NULL; |
|
} |
|
|
|
if ( m_pMaterialWorldWireframe ) |
|
{ |
|
m_pMaterialWorldWireframe->DecrementReferenceCount(); |
|
m_pMaterialWorldWireframe = NULL; |
|
} |
|
|
|
// DepthWrite materials |
|
for ( int32 i = 0; i < 4; i++ ) |
|
{ |
|
if ( m_pDepthWrite[ ( i & 0x2 ) >> 1 ][ i & 0x1 ] ) |
|
{ |
|
m_pDepthWrite[ ( i & 0x2 ) >> 1 ][ i & 0x1 ]->DecrementReferenceCount(); |
|
m_pDepthWrite[ ( i & 0x2 ) >> 1 ][ i & 0x1 ] = NULL; |
|
} |
|
|
|
if ( m_pSSAODepthWrite[ ( i & 0x2 ) >> 1 ][ i & 0x1 ] ) |
|
{ |
|
m_pSSAODepthWrite[ ( i & 0x2 ) >> 1 ][ i & 0x1 ]->DecrementReferenceCount(); |
|
m_pSSAODepthWrite[ ( i & 0x2 ) >> 1 ][ i & 0x1 ] = NULL; |
|
} |
|
} |
|
|
|
if ( m_pGlintBuildMaterial ) |
|
{ |
|
m_pGlintBuildMaterial->DecrementReferenceCount(); |
|
m_pGlintBuildMaterial = NULL; |
|
} |
|
#endif |
|
} |
|
|
|
static void ReleaseMaterialSystemObjects() |
|
{ |
|
// g_StudioRender.UncacheGlint(); |
|
} |
|
|
|
static void RestoreMaterialSystemObjects( int nChangeFlags ) |
|
{ |
|
// g_StudioRender.PrecacheGlint(); |
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Init, shutdown |
|
//----------------------------------------------------------------------------- |
|
InitReturnVal_t CStudioRender::Init() |
|
{ |
|
if ( g_pMaterialSystem && g_pMaterialSystemHardwareConfig ) |
|
{ |
|
g_pMaterialSystem->AddReleaseFunc( ReleaseMaterialSystemObjects ); |
|
g_pMaterialSystem->AddRestoreFunc( RestoreMaterialSystemObjects ); |
|
|
|
InitDebugMaterials(); |
|
|
|
return INIT_OK; |
|
} |
|
|
|
return INIT_FAILED; |
|
} |
|
|
|
void CStudioRender::Shutdown( void ) |
|
{ |
|
UncacheGlint(); |
|
ShutdownDebugMaterials(); |
|
|
|
if ( g_pMaterialSystem ) |
|
{ |
|
g_pMaterialSystem->RemoveReleaseFunc( ReleaseMaterialSystemObjects ); |
|
g_pMaterialSystem->RemoveRestoreFunc( RestoreMaterialSystemObjects ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets the lighting render state |
|
//----------------------------------------------------------------------------- |
|
void CStudioRender::SetLightingRenderState() |
|
{ |
|
CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); |
|
|
|
// FIXME: What happens when we use the fixed function pipeline but vertex shaders |
|
// are active? For the time being this only works because everything that does |
|
// vertex lighting does, in fact, have a vertex shader which is used to render it. |
|
pRenderContext->SetAmbientLightCube( m_pRC->m_LightBoxColors ); |
|
|
|
if ( m_pRC->m_Config.bSoftwareLighting || m_pRC->m_NumLocalLights == 0 ) |
|
{ |
|
pRenderContext->DisableAllLocalLights(); |
|
} |
|
else |
|
{ |
|
int nMaxLightCount = g_pMaterialSystemHardwareConfig->MaxNumLights(); |
|
LightDesc_t desc; |
|
desc.m_Type = MATERIAL_LIGHT_DISABLE; |
|
|
|
int i; |
|
int nLightCount = min( m_pRC->m_NumLocalLights, nMaxLightCount ); |
|
for( i = 0; i < nLightCount; ++i ) |
|
{ |
|
pRenderContext->SetLight( i, m_pRC->m_LocalLights[i] ); |
|
} |
|
for( ; i < nMaxLightCount; ++i ) |
|
{ |
|
pRenderContext->SetLight( i, desc ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Shadow state (affects the models as they are rendered) |
|
//----------------------------------------------------------------------------- |
|
void CStudioRender::AddShadow( IMaterial* pMaterial, void* pProxyData, FlashlightState_t *pFlashlightState, VMatrix *pWorldToTexture, ITexture *pFlashlightDepthTexture ) |
|
{ |
|
int i = m_ShadowState.AddToTail(); |
|
ShadowState_t& state = m_ShadowState[i]; |
|
state.m_pMaterial = pMaterial; |
|
state.m_pProxyData = pProxyData; |
|
state.m_pFlashlightState = pFlashlightState; |
|
state.m_pWorldToTexture = pWorldToTexture; |
|
state.m_pFlashlightDepthTexture = pFlashlightDepthTexture; |
|
} |
|
|
|
void CStudioRender::ClearAllShadows() |
|
{ |
|
m_ShadowState.RemoveAll(); |
|
} |
|
|
|
void CStudioRender::GetFlexStats( ) |
|
{ |
|
#ifdef REPORT_FLEX_STATS |
|
static bool s_bLastFlexStats = false; |
|
bool bDoStats = r_flexstats.GetInt() != 0; |
|
if ( bDoStats ) |
|
{ |
|
if ( !s_bLastFlexStats ) |
|
{ |
|
s_nModelsDrawn = 0; |
|
s_nActiveFlexCount = 0; |
|
} |
|
|
|
// Count number of active weights |
|
int nActiveFlexCount = 0; |
|
for ( int i = 0; i < MAXSTUDIOFLEXDESC; ++i ) |
|
{ |
|
if ( fabs( m_FlexWeights[i] ) >= 0.001f || fabs( m_FlexDelayedWeights[i] ) >= 0.001f ) |
|
{ |
|
++nActiveFlexCount; |
|
} |
|
} |
|
|
|
++s_nModelsDrawn; |
|
s_nActiveFlexCount += nActiveFlexCount; |
|
} |
|
else |
|
{ |
|
if ( s_bLastFlexStats ) |
|
{ |
|
if ( s_nModelsDrawn ) |
|
{ |
|
Msg( "Average number of flexes/model: %d\n", s_nActiveFlexCount / s_nModelsDrawn ); |
|
} |
|
else |
|
{ |
|
Msg( "No models rendered to take stats of\n" ); |
|
} |
|
|
|
s_nModelsDrawn = 0; |
|
s_nActiveFlexCount = 0; |
|
} |
|
} |
|
|
|
s_bLastFlexStats = bDoStats; |
|
#endif |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Main model rendering entry point |
|
//----------------------------------------------------------------------------- |
|
void CStudioRender::DrawModel( const DrawModelInfo_t& info, const StudioRenderContext_t &rc, |
|
matrix3x4_t *pBoneToWorld, const FlexWeights_t &flex, int flags ) |
|
{ |
|
if ( ( flags & STUDIORENDER_GENERATE_STATS ) != 0 ) |
|
{ |
|
ModelStats( info, rc, pBoneToWorld, flex, flags ); |
|
|
|
return; |
|
} |
|
|
|
VPROF( "CStudioRender::DrawModel"); |
|
|
|
m_pRC = const_cast< StudioRenderContext_t* >( &rc ); |
|
m_pFlexWeights = flex.m_pFlexWeights; |
|
m_pFlexDelayedWeights = flex.m_pFlexDelayedWeights; |
|
m_pBoneToWorld = pBoneToWorld; |
|
|
|
CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); |
|
|
|
// Disable flex if we're told to... |
|
bool flexConfig = m_pRC->m_Config.bFlex; |
|
if (flags & STUDIORENDER_DRAW_NO_FLEXES) |
|
{ |
|
m_pRC->m_Config.bFlex = false; |
|
} |
|
|
|
// Enable wireframe if we're told to... |
|
bool bWireframe = m_pRC->m_Config.bWireframe; |
|
if ( flags & STUDIORENDER_DRAW_WIREFRAME ) |
|
{ |
|
m_pRC->m_Config.bWireframe = true; |
|
} |
|
|
|
int boneMask = BONE_USED_BY_VERTEX_AT_LOD( info.m_Lod ); |
|
|
|
// Preserve the matrices if we're skinning |
|
pRenderContext->MatrixMode( MATERIAL_MODEL ); |
|
pRenderContext->PushMatrix(); |
|
pRenderContext->LoadIdentity(); |
|
|
|
m_VertexCache.StartModel(); |
|
|
|
m_pStudioHdr = info.m_pStudioHdr; |
|
if ( !info.m_pHardwareData->m_pLODs ) |
|
{ |
|
// If we are missing LODs then print the model name before returning |
|
// so we can perhaps correct the underlying problem. |
|
Msg( "Missing LODs for %s, lod index is %d.\n", m_pStudioHdr->pszName(), info.m_Lod ); |
|
return; |
|
} |
|
m_pStudioMeshes = info.m_pHardwareData->m_pLODs[info.m_Lod].m_pMeshData; |
|
|
|
// Bone to world must be set before calling drawmodel; it uses that here |
|
ComputePoseToWorld( m_PoseToWorld, m_pStudioHdr, boneMask, m_pRC->m_ViewOrigin, pBoneToWorld ); |
|
|
|
R_StudioRenderModel( pRenderContext, info.m_Skin, info.m_Body, info.m_HitboxSet, info.m_pClientEntity, |
|
info.m_pHardwareData->m_pLODs[info.m_Lod].ppMaterials, |
|
info.m_pHardwareData->m_pLODs[info.m_Lod].pMaterialFlags, flags, boneMask, info.m_Lod, info.m_pColorMeshes); |
|
|
|
// Draw all the decals on this model |
|
// If the model is not in memory, this code may not function correctly |
|
// This code assumes the model has been rendered! |
|
// So skip if the model hasn't been rendered |
|
// Also, skip if we're rendering to the shadow depth map |
|
if ( ( m_pStudioMeshes != 0 ) && !( flags & ( STUDIORENDER_SHADOWDEPTHTEXTURE | STUDIORENDER_SSAODEPTHTEXTURE )) ) |
|
{ |
|
if ((flags & STUDIORENDER_DRAW_GROUP_MASK) != STUDIORENDER_DRAW_TRANSLUCENT_ONLY) |
|
{ |
|
DrawDecal( info, info.m_Lod, info.m_Body ); |
|
} |
|
|
|
// Draw shadows |
|
if ( !( flags & STUDIORENDER_DRAW_NO_SHADOWS ) ) |
|
{ |
|
DrawShadows( info, flags, boneMask ); |
|
} |
|
|
|
if( (flags & STUDIORENDER_DRAW_GROUP_MASK) != STUDIORENDER_DRAW_TRANSLUCENT_ONLY && |
|
!( flags & STUDIORENDER_DRAW_NO_SHADOWS ) ) |
|
{ |
|
DrawFlashlightDecals( info, info.m_Lod ); |
|
} |
|
} |
|
|
|
// Restore the matrices if we're skinning |
|
pRenderContext->MatrixMode( MATERIAL_MODEL ); |
|
pRenderContext->PopMatrix(); |
|
|
|
// Restore the configs |
|
m_pRC->m_Config.bFlex = flexConfig; |
|
m_pRC->m_Config.bWireframe = bWireframe; |
|
|
|
#ifdef REPORT_FLEX_STATS |
|
GetFlexStats(); |
|
#endif |
|
|
|
pRenderContext->SetNumBoneWeights( 0 ); |
|
m_pRC = NULL; |
|
m_pBoneToWorld = NULL; |
|
m_pFlexWeights = NULL; |
|
m_pFlexDelayedWeights = NULL; |
|
} |
|
|
|
void CStudioRender::DrawModelStaticProp( const DrawModelInfo_t& info, |
|
const StudioRenderContext_t &rc, const matrix3x4_t& rootToWorld, int flags ) |
|
{ |
|
VPROF( "CStudioRender::DrawModelStaticProp"); |
|
|
|
m_pRC = const_cast<StudioRenderContext_t*>( &rc ); |
|
|
|
CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); |
|
|
|
memcpy( &m_StaticPropRootToWorld, &rootToWorld, sizeof(matrix3x4_t) ); |
|
memcpy( &m_PoseToWorld[0], &rootToWorld, sizeof(matrix3x4_t) ); |
|
m_pBoneToWorld = &m_StaticPropRootToWorld; |
|
|
|
bool flexConfig = m_pRC->m_Config.bFlex; |
|
m_pRC->m_Config.bFlex = false; |
|
bool bWireframe = m_pRC->m_Config.bWireframe; |
|
if ( flags & STUDIORENDER_DRAW_WIREFRAME ) |
|
{ |
|
m_pRC->m_Config.bWireframe = true; |
|
} |
|
|
|
int lod = info.m_Lod; |
|
m_pStudioHdr = info.m_pStudioHdr; |
|
m_pStudioMeshes = info.m_pHardwareData->m_pLODs[lod].m_pMeshData; |
|
|
|
if ( ( flags & STUDIORENDER_GENERATE_STATS ) != 0 ) |
|
{ |
|
FlexWeights_t flex; |
|
|
|
ModelStats( info, rc, m_pBoneToWorld, flex, flags | STUDIORENDER_DRAW_NO_FLEXES ); |
|
|
|
return; |
|
} |
|
|
|
R_StudioRenderModel( pRenderContext, info.m_Skin, info.m_Body, info.m_HitboxSet, info.m_pClientEntity, |
|
info.m_pHardwareData->m_pLODs[lod].ppMaterials, |
|
info.m_pHardwareData->m_pLODs[lod].pMaterialFlags, flags, BONE_USED_BY_ANYTHING, lod, info.m_pColorMeshes); |
|
|
|
// If we're not shadow depth mapping |
|
if ( ( flags & ( STUDIORENDER_SHADOWDEPTHTEXTURE | STUDIORENDER_SSAODEPTHTEXTURE ) ) == 0 ) |
|
{ |
|
// FIXME: Should this occur in a separate call? |
|
// Draw all the decals on this model |
|
if ((flags & STUDIORENDER_DRAW_GROUP_MASK) != STUDIORENDER_DRAW_TRANSLUCENT_ONLY) |
|
{ |
|
DrawDecal( info, lod, info.m_Body ); |
|
} |
|
|
|
// Draw shadows |
|
if ( !( flags & STUDIORENDER_DRAW_NO_SHADOWS ) ) |
|
{ |
|
DrawShadows( info, flags, BONE_USED_BY_ANYTHING ); |
|
} |
|
|
|
if( (flags & STUDIORENDER_DRAW_GROUP_MASK) != STUDIORENDER_DRAW_TRANSLUCENT_ONLY && |
|
!( flags & STUDIORENDER_DRAW_NO_SHADOWS ) ) |
|
{ |
|
DrawFlashlightDecals( info, lod ); |
|
} |
|
} |
|
|
|
// Restore the configs |
|
m_pRC->m_Config.bFlex = flexConfig; |
|
m_pRC->m_Config.bWireframe = bWireframe; |
|
|
|
pRenderContext->SetNumBoneWeights( 0 ); |
|
m_pBoneToWorld = NULL; |
|
m_pRC = NULL; |
|
} |
|
|
|
|
|
|
|
|
|
// UNDONE: Currently no flex supported, no per instance cubemap or other lighting state supported, no eyeballs supported |
|
// NOTE: This is a fast path for simple models with skeletons but not many other features |
|
void CStudioRender::DrawModelArray( const DrawModelInfo_t &drawInfo, const StudioRenderContext_t &rc, int arrayCount, model_array_instance_t *pInstanceData, int instanceStride, int flags ) |
|
{ |
|
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %d", __FUNCTION__, arrayCount ); |
|
|
|
#ifndef SWDS // no drawing on dedicated server |
|
#if 0 |
|
FlexWeights_t flex; |
|
memset(&flex, 0, sizeof(flex)); |
|
for ( int i = 0; i < arrayCount; i++ ) |
|
{ |
|
DrawModel( drawInfo, rc, &pInstanceData[i].modelToWorld, flex, flags ); |
|
} |
|
return; |
|
#endif |
|
|
|
m_pRC = const_cast< StudioRenderContext_t* >( &rc ); |
|
CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); |
|
|
|
// Preserve the matrices if we're skinning |
|
pRenderContext->MatrixMode( MATERIAL_MODEL ); |
|
pRenderContext->PushMatrix(); |
|
pRenderContext->LoadIdentity(); |
|
pRenderContext->SetNumBoneWeights( 0 ); |
|
|
|
// get the studio mesh data for this lod |
|
studiomeshdata_t *pMeshDataBase = drawInfo.m_pHardwareData->m_pLODs[drawInfo.m_Lod].m_pMeshData; |
|
IMaterial **ppMaterials = drawInfo.m_pHardwareData->m_pLODs[drawInfo.m_Lod].ppMaterials; |
|
int *pMaterialFlags = drawInfo.m_pHardwareData->m_pLODs[drawInfo.m_Lod].pMaterialFlags; |
|
studiohdr_t *pStudioHdr = drawInfo.m_pStudioHdr; |
|
m_bDrawTranslucentSubModels = false; |
|
|
|
int skin = drawInfo.m_Skin; |
|
short *pskinref = pStudioHdr->pSkinref( 0 ); |
|
if ( skin > 0 && skin < pStudioHdr->numskinfamilies ) |
|
{ |
|
pskinref += ( skin * pStudioHdr->numskinref ); |
|
} |
|
|
|
for ( int body = 0; body < pStudioHdr->numbodyparts; ++body ) |
|
{ |
|
mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( body ); |
|
|
|
int index = drawInfo.m_Body / pbodypart->base; |
|
index = index % pbodypart->nummodels; |
|
mstudiomodel_t *pSubmodel = pbodypart->pModel( index ); |
|
|
|
|
|
for ( int meshIndex = 0; meshIndex < pSubmodel->nummeshes; ++meshIndex ) |
|
{ |
|
mstudiomesh_t *pmesh = pSubmodel->pMesh(meshIndex); |
|
studiomeshdata_t *pMeshData = &pMeshDataBase[pmesh->meshid]; |
|
Assert( pMeshData ); |
|
|
|
if ( !pMeshData->m_NumGroup ) |
|
continue; |
|
|
|
if ( !pMaterialFlags ) |
|
continue; |
|
|
|
StudioModelLighting_t lighting = LIGHTING_HARDWARE; |
|
int materialFlags = pMaterialFlags[pskinref[pmesh->material]]; |
|
|
|
IMaterial* pMaterial = R_StudioSetupSkinAndLighting( pRenderContext, pskinref[ pmesh->material ], ppMaterials, materialFlags, drawInfo.m_pClientEntity, NULL, lighting ); |
|
if ( !pMaterial ) |
|
continue; |
|
|
|
// eyeball! can't do those in array mode yet |
|
Assert( pmesh->materialtype != 1 ); |
|
//R_StudioDrawMesh( pRenderContext, pmesh, pMeshData, lighting, pMaterial, NULL, drawInfo.m_Lod ); |
|
// Draw all the various mesh groups... |
|
for ( int meshGroupIndex = 0; meshGroupIndex < pMeshData->m_NumGroup; ++meshGroupIndex ) |
|
{ |
|
studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[meshGroupIndex]; |
|
|
|
// Older models are merely flexed while new ones are also delta flexed |
|
Assert(!(pGroup->m_Flags & MESHGROUP_IS_FLEXED)); |
|
Assert(!(pGroup->m_Flags & MESHGROUP_IS_DELTA_FLEXED)); |
|
IMesh *pMesh = pGroup->m_pMesh; |
|
|
|
// Needed when we switch back and forth between hardware + software lighting |
|
if ( IsPC() && pGroup->m_MeshNeedsRestore ) |
|
{ |
|
VertexCompressionType_t compressionType = CompressionType( pMesh->GetVertexFormat() ); |
|
switch ( compressionType ) |
|
{ |
|
case VERTEX_COMPRESSION_ON: |
|
R_StudioRestoreMesh<VERTEX_COMPRESSION_ON>( pmesh, pGroup ); |
|
case VERTEX_COMPRESSION_NONE: |
|
default: |
|
R_StudioRestoreMesh<VERTEX_COMPRESSION_NONE>( pmesh, pGroup ); |
|
break; |
|
} |
|
pGroup->m_MeshNeedsRestore = false; |
|
} |
|
pMesh->SetColorMesh( NULL, 0 ); |
|
|
|
MaterialPrimitiveType_t stripType = MATERIAL_TRIANGLES; |
|
pMesh->SetPrimitiveType(stripType); |
|
if ( pStudioHdr->numbones > 1 ) |
|
{ |
|
byte *pData = (byte *)pInstanceData; |
|
for ( int i = 0;i < arrayCount; i++, pData += instanceStride ) |
|
{ |
|
matrix3x4_t *pBones = &( ((model_array_instance_t *)pData)->modelToWorld ); |
|
pRenderContext->LoadMatrix( pBones[0] ); |
|
for (int j = 0; j < pGroup->m_NumStrips; ++j) |
|
{ |
|
OptimizedModel::StripHeader_t* pStrip = &pGroup->m_pStripData[j]; |
|
// Reset bone state if we're hardware skinning |
|
pRenderContext->SetNumBoneWeights( pStrip->numBones ); |
|
for (int k = 0; k < pStrip->numBoneStateChanges; ++k) |
|
{ |
|
OptimizedModel::BoneStateChangeHeader_t* pStateChange = pStrip->pBoneStateChange(k); |
|
if ( pStateChange->newBoneID < 0 ) |
|
break; |
|
|
|
pRenderContext->LoadBoneMatrix( pStateChange->hardwareID, pBones[pStateChange->newBoneID] ); |
|
} |
|
MaterialPrimitiveType_t localStripType = pStrip->flags & OptimizedModel::STRIP_IS_TRISTRIP ? MATERIAL_TRIANGLE_STRIP : MATERIAL_TRIANGLES; |
|
|
|
if ( localStripType != stripType ) |
|
{ |
|
pMesh->SetPrimitiveType( localStripType ); |
|
stripType = localStripType; |
|
} |
|
pMesh->Draw( pStrip->indexOffset, pStrip->numIndices ); |
|
} |
|
} |
|
pRenderContext->SetNumBoneWeights( 0 ); |
|
} |
|
else |
|
{ |
|
byte *pData = (byte *)pInstanceData; |
|
for ( int i = 0;i < arrayCount; i++, pData += instanceStride ) |
|
{ |
|
matrix3x4_t *pBones = &( ((model_array_instance_t *)pData)->modelToWorld ); |
|
pRenderContext->LoadMatrix( pBones[0] ); |
|
for (int j = 0; j < pGroup->m_NumStrips; ++j) |
|
{ |
|
OptimizedModel::StripHeader_t* pStrip = &pGroup->m_pStripData[j]; |
|
MaterialPrimitiveType_t localStripType = pStrip->flags & OptimizedModel::STRIP_IS_TRISTRIP ? MATERIAL_TRIANGLE_STRIP : MATERIAL_TRIANGLES; |
|
|
|
if ( localStripType != stripType ) |
|
{ |
|
pMesh->SetPrimitiveType( localStripType ); |
|
stripType = localStripType; |
|
} |
|
pMesh->Draw( pStrip->indexOffset, pStrip->numIndices ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
pRenderContext->MatrixMode( MATERIAL_MODEL ); |
|
pRenderContext->PopMatrix(); |
|
#endif |
|
} |
|
|
|
|