diff --git a/src/game/client/baseclientrendertargets.cpp b/src/game/client/baseclientrendertargets.cpp index 3aa642cf0ba..2cd16c3929f 100644 --- a/src/game/client/baseclientrendertargets.cpp +++ b/src/game/client/baseclientrendertargets.cpp @@ -45,6 +45,17 @@ ITexture* CBaseClientRenderTargets::CreateCameraTexture( IMaterialSystem* pMater CREATERENDERTARGETFLAGS_HDR ); } +ITexture *CBaseClientRenderTargets::CreateViewmodelTexture( IMaterialSystem *pMaterialSystem ) +{ + return pMaterialSystem->CreateNamedRenderTargetTextureEx2( + "_rt_viewmodel", + 1, 1, RT_SIZE_FULL_FRAME_BUFFER, + IMAGE_FORMAT_BGRA8888, + MATERIAL_RT_DEPTH_SHARED, + TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_EIGHTBITALPHA, + CREATERENDERTARGETFLAGS_HDR ); +} + //----------------------------------------------------------------------------- // Purpose: Called by the engine in material system init and shutdown. // Clients should override this in their inherited version, but the base @@ -60,6 +71,8 @@ void CBaseClientRenderTargets::InitClientRenderTargets( IMaterialSystem* pMateri // Monitors m_CameraTexture.Init( CreateCameraTexture( pMaterialSystem, iCameraTextureSize ) ); + + m_ViewmodelTexture.Init( CreateViewmodelTexture( pMaterialSystem ) ); } //----------------------------------------------------------------------------- @@ -75,4 +88,6 @@ void CBaseClientRenderTargets::ShutdownClientRenderTargets() // Monitors m_CameraTexture.Shutdown(); + + m_ViewmodelTexture.Shutdown(); } \ No newline at end of file diff --git a/src/game/client/baseclientrendertargets.h b/src/game/client/baseclientrendertargets.h index a1aad1ca59e..3b91a10fed7 100644 --- a/src/game/client/baseclientrendertargets.h +++ b/src/game/client/baseclientrendertargets.h @@ -54,10 +54,14 @@ class CBaseClientRenderTargets : public IClientRenderTargets // Used for the HUD in stereo and head tracking mode CTextureReference m_UITexture; + // Used for transparent viewmodels + CTextureReference m_ViewmodelTexture; + // Init functions for the common render targets ITexture* CreateWaterReflectionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 ); ITexture* CreateWaterRefractionTexture( IMaterialSystem* pMaterialSystem, int iSize = 1024 ); ITexture* CreateCameraTexture( IMaterialSystem* pMaterialSystem, int iSize = 256 ); + ITexture *CreateViewmodelTexture( IMaterialSystem *pMaterialSystem ); }; diff --git a/src/game/client/c_baseviewmodel.cpp b/src/game/client/c_baseviewmodel.cpp index bcf609c5e40..39a908ec0c6 100644 --- a/src/game/client/c_baseviewmodel.cpp +++ b/src/game/client/c_baseviewmodel.cpp @@ -316,19 +316,22 @@ int C_BaseViewModel::DrawModel( int flags ) } #endif - int ret; - // If the local player's overriding the viewmodel rendering, let him do it - if ( pPlayer && pPlayer->IsOverridingViewmodel() ) - { - ret = pPlayer->DrawOverriddenViewmodel( this, flags ); - } - else if ( pWeapon && pWeapon->IsOverridingViewmodel() ) + int ret = 0; + if ( !(flags & STUDIO_DRAWTRANSLUCENTSUBMODELS) ) { - ret = pWeapon->DrawOverriddenViewmodel( this, flags ); - } - else - { - ret = BaseClass::DrawModel( flags ); + // If the local player's overriding the viewmodel rendering, let him do it + if ( pPlayer && pPlayer->IsOverridingViewmodel() ) + { + ret = pPlayer->DrawOverriddenViewmodel( this, flags ); + } + else if ( pWeapon && pWeapon->IsOverridingViewmodel() ) + { + ret = pWeapon->DrawOverriddenViewmodel( this, flags ); + } + else + { + ret = BaseClass::DrawModel( flags ); + } } // Now that we've rendered, reset the animation restart flag @@ -339,7 +342,7 @@ int C_BaseViewModel::DrawModel( int flags ) m_nOldAnimationParity = m_nAnimationParity; } // Tell the weapon itself that we've rendered, in case it wants to do something - if ( pWeapon ) + if ( (flags & STUDIO_DRAWTRANSLUCENTSUBMODELS) && pWeapon ) { pWeapon->ViewModelDrawn( this ); } diff --git a/src/game/client/client_mapbase_hl2.vpc b/src/game/client/client_mapbase_hl2.vpc index a4cc20ff5e0..5d2f110e6a1 100644 --- a/src/game/client/client_mapbase_hl2.vpc +++ b/src/game/client/client_mapbase_hl2.vpc @@ -24,6 +24,9 @@ $Project // Original stunstick files are conditional'd out in the HL2 VPCs $File "$SRCDIR\game\shared\hl2mp\weapon_stunstick.cpp" $File "$SRCDIR\game\shared\hl2mp\weapon_stunstick.h" + // Rendertargets implementation for HL2 + $File "hl2\rendertargets.cpp" + $File "hl2\rendertargets.h" } $Folder "HL2MP" diff --git a/src/game/client/hl2/rendertargets.cpp b/src/game/client/hl2/rendertargets.cpp new file mode 100644 index 00000000000..906145621dc --- /dev/null +++ b/src/game/client/hl2/rendertargets.cpp @@ -0,0 +1,30 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Purpose: Implements IClientRenderTargets +// +// Author: Nooodles +// +//=============================================================================// +#include "cbase.h" +#include "rendertargets.h" + +// shamelessly copied from TF2's rendertargets impl +ConVar hl2_water_resolution( "hl2_water_resolution", "1024", FCVAR_NONE, "Needs to be set at game launch time to override." ); +ConVar hl2_monitor_resolution( "hl2_monitor_resolution", "1024", FCVAR_NONE, "Needs to be set at game launch time to override." ); + +void CRenderTargets::InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig ) +{ + BaseClass::InitClientRenderTargets( pMaterialSystem, pHardwareConfig, + hl2_water_resolution.GetInt(), hl2_monitor_resolution.GetInt() ); +} + +//----------------------------------------------------------------------------- +// Purpose: Shutdown client render targets. This gets called during shutdown in the engine +// Input : - +//----------------------------------------------------------------------------- +void CRenderTargets::ShutdownClientRenderTargets() +{ + BaseClass::ShutdownClientRenderTargets(); +} + +EXPOSE_INTERFACE( CRenderTargets, IClientRenderTargets, CLIENTRENDERTARGETS_INTERFACE_VERSION ); \ No newline at end of file diff --git a/src/game/client/hl2/rendertargets.h b/src/game/client/hl2/rendertargets.h new file mode 100644 index 00000000000..e8cb58f3ee8 --- /dev/null +++ b/src/game/client/hl2/rendertargets.h @@ -0,0 +1,24 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Purpose: Implements IClientRenderTargets +// +// Author: Nooodles +// +//=============================================================================// + +#ifndef RENDERTARGETS_H +#define RENDERTARGETS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "baseclientrendertargets.h" + +class CRenderTargets : public CBaseClientRenderTargets +{ + DECLARE_CLASS_GAMEROOT( CRenderTargets, CBaseClientRenderTargets ); +public: + virtual void InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig ); + virtual void ShutdownClientRenderTargets(); +}; +#endif diff --git a/src/game/client/view.cpp b/src/game/client/view.cpp index e84101c83cc..c1f03b8570b 100644 --- a/src/game/client/view.cpp +++ b/src/game/client/view.cpp @@ -323,6 +323,13 @@ void CViewRender::Init( void ) m_flLastFOV = default_fov.GetFloat(); #endif + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetString( "$basetexture", "_rt_viewmodel" ); + pVMTKeyValues->SetInt( "$vertexcolor", 0 ); + pVMTKeyValues->SetInt( "$vertexalpha", 0 ); + pVMTKeyValues->SetInt( "$translucent", 1 ); + pVMTKeyValues->SetInt( "$additive", 0 ); + m_transparentVMMaterial.Init( "__viewmodel", TEXTURE_GROUP_RENDER_TARGET, pVMTKeyValues ); } //----------------------------------------------------------------------------- diff --git a/src/game/client/viewrender.cpp b/src/game/client/viewrender.cpp index b9fba9f8a07..7f8e12574ee 100644 --- a/src/game/client/viewrender.cpp +++ b/src/game/client/viewrender.cpp @@ -189,6 +189,15 @@ extern ConVar localplayer_visionflags; static ConVar r_nearz_skybox( "r_nearz_skybox", "2.0", FCVAR_CHEAT ); #endif +ConVar r_viewmodel_opacity( "r_viewmodel_opacity", "1", FCVAR_ARCHIVE, "", true, 0.f, true, 1.f ); +// personal preference to have occlusion disable on TF2 by default +#ifdef TF_CLIENT_DLL +ConVar r_viewmodel_opacity_occlude_effects( "r_viewmodel_opacity_occlude_effects", "0", +#else +ConVar r_viewmodel_opacity_occlude_effects( "r_viewmodel_opacity_occlude_effects", "1", +#endif + FCVAR_ARCHIVE, "When the opacity is less than 1 should it occlude effects rendered with the viewmodel such as particles" ); + //----------------------------------------------------------------------------- // Globals //----------------------------------------------------------------------------- @@ -1143,6 +1152,7 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod CUtlVector< IClientRenderable * > opaqueViewModelList( 32 ); CUtlVector< IClientRenderable * > translucentViewModelList( 32 ); + CUtlVector< IClientRenderable * > transparentList( 64 ); ClientLeafSystem()->CollateViewModelRenderables( opaqueViewModelList, translucentViewModelList ); @@ -1171,15 +1181,106 @@ void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmod } } - if ( !UpdateRefractIfNeededByList( opaqueViewModelList ) ) + if ( r_viewmodel_opacity.GetFloat() >= 1.f ) + { + if ( !UpdateRefractIfNeededByList( opaqueViewModelList ) ) + { + UpdateRefractIfNeededByList( translucentViewModelList ); + } + } + else { - UpdateRefractIfNeededByList( translucentViewModelList ); + // move our vm models to a different list + int nOpaque = opaqueViewModelList.Count(); + for ( int i = nOpaque - 1; i >= 0; --i ) + { + IClientRenderable *pRenderable = opaqueViewModelList[i]; + CBaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( pEntity ) + { + transparentList.AddToTail( pRenderable ); + opaqueViewModelList.FastRemove( i ); + } + } + + int nTranslucent = translucentViewModelList.Count(); + for ( int i = nTranslucent - 1; i >= 0; --i ) + { + IClientRenderable *pRenderable = translucentViewModelList[i]; + CBaseEntity *pEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( pEntity ) + { + transparentList.AddToTail( pRenderable ); + translucentViewModelList.FastRemove( i ); + } + } + + if ( transparentList.Count() ) + { + ITexture *pRenderTarget = materials->FindTexture( "_rt_viewmodel", TEXTURE_GROUP_RENDER_TARGET ); + pRenderContext->PushRenderTargetAndViewport( pRenderTarget, viewRender.x, viewRender.y, viewRender.width, viewRender.height ); + pRenderContext->ClearColor4ub( 0, 0, 0, 0 ); + pRenderContext->ClearBuffers( true, true, true ); + + // write the stencil and draw the viewmodel for the vm render target + pRenderContext->SetStencilEnable( true ); + pRenderContext->SetStencilReferenceValue( 1 ); + pRenderContext->SetStencilWriteMask( 0xFF ); + pRenderContext->SetStencilTestMask( 0xFF ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS ); + pRenderContext->SetStencilPassOperation( STENCILOPERATION_REPLACE ); + pRenderContext->SetStencilFailOperation( STENCILOPERATION_KEEP ); + pRenderContext->SetStencilZFailOperation( STENCILOPERATION_KEEP ); + DrawRenderablesInList( transparentList, STUDIO_TRANSPARENCY ); + + // clear the alpha channel based on what we just drew + float opacity = r_viewmodel_opacity.GetFloat() * 255.f; + pRenderContext->ClearColor4ub( 0, 0, 0, static_cast( opacity ) ); + + pRenderContext->SetStencilWriteMask( 0 ); + pRenderContext->SetStencilReferenceValue( 1 ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ); + pRenderContext->ClearBuffersObeyStencilEx( false, true, true ); + pRenderContext->PopRenderTargetAndViewport(); + + // Do we want to occlude rendered effects and particles? + if ( !r_viewmodel_opacity_occlude_effects.GetBool() ) + pRenderContext->SetStencilEnable( false ); + else + { + // write our stencil for the main render target + pRenderContext->SetStencilEnable( true ); + pRenderContext->SetStencilReferenceValue( 1 ); + pRenderContext->SetStencilWriteMask( 0x3 ); + pRenderContext->SetStencilTestMask( 0x3 ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_LESS ); + pRenderContext->SetStencilPassOperation( STENCILOPERATION_ZERO ); + pRenderContext->SetStencilFailOperation( STENCILOPERATION_REPLACE ); + pRenderContext->SetStencilZFailOperation( STENCILOPERATION_REPLACE ); + + // something about drawing the ItemModelPanel render target ruins everything + // so just don't write colour which mostly works + pRenderContext->OverrideColorWriteEnable( true, false ); + DrawRenderablesInList( transparentList, STUDIO_TRANSPARENCY ); + pRenderContext->OverrideColorWriteEnable( false, true ); + + // setup for occlusion + pRenderContext->SetStencilWriteMask( 0 ); + pRenderContext->SetStencilReferenceValue( 0 ); + pRenderContext->SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ); + } + DrawRenderablesInList( transparentList, STUDIO_DRAWTRANSLUCENTSUBMODELS ); + } } DrawRenderablesInList( opaqueViewModelList ); + DrawRenderablesInList( opaqueViewModelList, STUDIO_DRAWTRANSLUCENTSUBMODELS ); DrawRenderablesInList( translucentViewModelList, STUDIO_TRANSPARENCY ); + DrawRenderablesInList( translucentViewModelList, STUDIO_TRANSPARENCY | STUDIO_DRAWTRANSLUCENTSUBMODELS ); + pRenderContext->SetStencilEnable( false ); } + // Reset the depth range to the original values if( bUseDepthHack ) pRenderContext->DepthRange( depthmin, depthmax ); @@ -2484,8 +2585,30 @@ void CViewRender::RenderView( const CViewSetup &viewRender, int nClearFlags, int DownscaleRect.x, DownscaleRect.y, DownscaleRect.x+DownscaleRect.width-1, DownscaleRect.y+DownscaleRect.height-1, pFullFrameFB1->GetActualWidth(), pFullFrameFB1->GetActualHeight() ); + if ( r_drawviewmodel.GetBool() && r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() > 0.f ) + { + m_transparentVMMaterial->IncrementReferenceCount(); + + pRenderContextUpscale->DrawScreenSpaceRectangle( m_transparentVMMaterial, UpscaleRect.x, UpscaleRect.y, UpscaleRect.width, UpscaleRect.height, + DownscaleRect.x, DownscaleRect.y, DownscaleRect.x + DownscaleRect.width - 1, DownscaleRect.y + DownscaleRect.height - 1, + pFullFrameFB1->GetActualWidth(), pFullFrameFB1->GetActualHeight() ); + + m_transparentVMMaterial->DecrementReferenceCount(); + } + pCopyMaterial->DecrementReferenceCount(); } + else if ( r_drawviewmodel.GetBool() && r_viewmodel_opacity.GetFloat() < 1.f && r_viewmodel_opacity.GetFloat() > 0.f ) + { + CMatRenderContextPtr pRenderContextVM( materials ); + m_transparentVMMaterial->IncrementReferenceCount(); + + ITexture *pFullFrameFB1 = materials->FindTexture( "_rt_FullFrameFB1", TEXTURE_GROUP_RENDER_TARGET ); + pRenderContextVM->DrawScreenSpaceRectangle( m_transparentVMMaterial, viewRender.x, viewRender.y, viewRender.width, viewRender.height, + viewRender.x, viewRender.y, viewRender.x + viewRender.width - 1, viewRender.y + viewRender.height - 1, + pFullFrameFB1->GetActualWidth(), pFullFrameFB1->GetActualHeight() ); + m_transparentVMMaterial->DecrementReferenceCount(); + } // if we're in VR mode we might need to override the render target if( UseVR() ) diff --git a/src/game/client/viewrender.h b/src/game/client/viewrender.h index f732914f027..7eebd984282 100644 --- a/src/game/client/viewrender.h +++ b/src/game/client/viewrender.h @@ -527,6 +527,8 @@ class CViewRender : public IViewRender, CMaterialReference m_ScriptOverlayMaterial; char m_szCurrentScriptMaterialName[ MAX_PATH ]; + CMaterialReference m_transparentVMMaterial; + Vector m_vecLastFacing; float m_flCheapWaterStartDistance; float m_flCheapWaterEndDistance;