diff options
Diffstat (limited to 'studiorender/studiorender.cpp')
| -rw-r--r-- | studiorender/studiorender.cpp | 762 |
1 files changed, 762 insertions, 0 deletions
diff --git a/studiorender/studiorender.cpp b/studiorender/studiorender.cpp new file mode 100644 index 0000000..6749052 --- /dev/null +++ b/studiorender/studiorender.cpp @@ -0,0 +1,762 @@ +//========= 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 +} + |