source-engine/game/client/swarm/asw_view_scene.cpp
2023-10-03 17:23:56 +03:00

386 lines
11 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Responsible for drawing the scene
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "asw_view_scene.h"
#include "view_scene.h"
#include "precache_register.h"
#include "materialsystem/imaterialsystemhardwareconfig.h"
#include "c_asw_render_targets.h"
#include "materialsystem/IMaterialVar.h"
#include "renderparm.h"
#include "asw_weapon_night_vision.h"
#include "c_asw_player.h"
#include "c_asw_marine.h"
#include "functionproxy.h"
#include "imaterialproxydict.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
float g_fMarinePoisonDuration = 0;
bool g_bBlurredLastTime = false;
ConVar asw_motionblur("asw_motionblur", "0", 0, "Motion Blur"); // motion blur on/off
ConVar asw_motionblur_addalpha("asw_motionblur_addalpha", "0.1", 0, "Motion Blur Alpha"); // The amount of alpha to use when adding the FB to our custom buffer
ConVar asw_motionblur_drawalpha("asw_motionblur_drawalpha", "1", 0, "Motion Blur Draw Alpha"); // The amount of alpha to use when adding our custom buffer to the FB
ConVar asw_motionblur_time("asw_motionblur_time", "0.05", 0, "The amount of time to wait until updating the FB"); // Delay to add between capturing the FB
ConVar asw_night_vision_self_illum_multiplier( "asw_night_vision_self_illum_multiplier", "25", 0, "For materials that use the NightVision proxy, multiply the result (normally in the [0,1] range) by this value." );
ConVar asw_sniper_scope_self_illum_multiplier( "asw_sniper_scope_self_illum_multiplier", "0.5", 0, "For materials that use the NightVision proxy, multiply the result (normally in the [0,1] range) by this value." );
// @TODO: move this parameter to an entity property rather than convar
ConVar mat_dest_alpha_range( "mat_dest_alpha_range", "1000", 0, "Amount to scale depth values before writing into destination alpha ([0,1] range)." );
PRECACHE_REGISTER_BEGIN( GLOBAL, ASWPrecacheViewRender )
PRECACHE( MATERIAL, "swarm/effects/frontbuffer" )
PRECACHE( MATERIAL, "effects/nightvision" )
PRECACHE( MATERIAL, "effects/nightvision_flash" )
PRECACHE( MATERIAL, "effects/nightvision_noise" )
PRECACHE( MATERIAL, "effects/object_motion_blur" )
PRECACHE_REGISTER_END()
static CASWViewRender g_ViewRender;
IViewRender *GetViewRenderInstance()
{
return &g_ViewRender;
}
CASWViewRender::CASWViewRender()
{
}
void CASWViewRender::OnRenderStart()
{
CViewRender::OnRenderStart();
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->SetFloatRenderingParameter( FLOAT_RENDERPARM_DEST_ALPHA_DEPTH_SCALE, mat_dest_alpha_range.GetFloat() );
}
//-----------------------------------------------------------------------------
// Purpose: Renders extra 2D effects in derived classes while the 2D view is on the stack
//-----------------------------------------------------------------------------
void CASWViewRender::Render2DEffectsPreHUD( const CViewSetup &view )
{
PerformNightVisionEffect( view ); // this needs to come before the HUD is drawn, or it will wash the HUD out
#ifndef _X360
// @TODO: Motion blur not supported on X360 yet due to EDRAM issues
DoMotionBlur( view );
#endif
}
void CASWViewRender::DoMotionBlur( const CViewSetup &view )
{
if ( asw_motionblur.GetInt() == 0 && g_fMarinePoisonDuration <= 0)
{
g_bBlurredLastTime = false;
return;
}
static float fNextDrawTime = 0.0f;
bool found;
IMaterialVar* mv = NULL;
IMaterial *pMatScreen = NULL;
ITexture *pMotionBlur = NULL;
ITexture *pOriginalTexture = NULL;
// Get the front buffer material
pMatScreen = materials->FindMaterial( "swarm/effects/frontbuffer", TEXTURE_GROUP_OTHER, true );
// Get our custom render target
pMotionBlur = g_pASWRenderTargets->GetASWMotionBlurTexture();
// Store the current render target
CMatRenderContextPtr pRenderContext( materials );
ITexture *pOriginalRenderTarget = pRenderContext->GetRenderTarget();
// Set the camera up so we can draw the overlay
int oldX, oldY, oldW, oldH;
pRenderContext->GetViewport( oldX, oldY, oldW, oldH );
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
// set our blur parameters, based on convars or the poison duration
float add_alpha = asw_motionblur_addalpha.GetFloat();
float blur_time = asw_motionblur_time.GetFloat();
float draw_alpha = asw_motionblur_drawalpha.GetFloat();
if (g_fMarinePoisonDuration > 0)
{
if (g_fMarinePoisonDuration < 1.0f)
{
draw_alpha = g_fMarinePoisonDuration;
add_alpha = 0.3f;
}
else
{
draw_alpha = 1.0f;
float over_time = g_fMarinePoisonDuration - 1.0f;
over_time = -MIN(4.0f, over_time);
// map 0 to -4, to 0.3 to 0.05
add_alpha = (over_time + 4) * 0.0625 + 0.05f;
}
blur_time = 0.05f;
}
if (!g_bBlurredLastTime)
add_alpha = 1.0f; // add the whole buffer if this is the first time we're blurring after a while, so we don't end up with images from ages ago
if ( fNextDrawTime - gpGlobals->curtime > 1.0f)
{
fNextDrawTime = 0.0f;
}
if( gpGlobals->curtime >= fNextDrawTime )
{
UpdateScreenEffectTexture( 0, view.x, view.y, view.width, view.height );
// Set the alpha to whatever our console variable is
mv = pMatScreen->FindVar( "$alpha", &found, false );
if (found)
{
if ( fNextDrawTime == 0 )
{
mv->SetFloatValue( 1.0f );
}
else
{
mv->SetFloatValue( add_alpha );
}
}
pRenderContext->SetRenderTarget( pMotionBlur );
pRenderContext->DrawScreenSpaceQuad( pMatScreen );
// Set the next draw time according to the convar
fNextDrawTime = gpGlobals->curtime + blur_time;
}
// Set the alpha
mv = pMatScreen->FindVar( "$alpha", &found, false );
if (found)
{
mv->SetFloatValue( draw_alpha );
}
// Set the texture to our buffer
mv = pMatScreen->FindVar( "$basetexture", &found, false );
if (found)
{
pOriginalTexture = mv->GetTextureValue();
mv->SetTextureValue( pMotionBlur );
}
// Pretend we were never here, set everything back
pRenderContext->SetRenderTarget( pOriginalRenderTarget );
pRenderContext->DrawScreenSpaceQuad( pMatScreen );
// Set our texture back to _rt_FullFrameFB
if (found)
{
mv->SetTextureValue( pOriginalTexture );
}
pRenderContext->DepthRange( 0.0f, 1.0f );
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PopMatrix();
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PopMatrix();
g_bBlurredLastTime = true;
}
inline bool ASW_SetMaterialVarFloat( IMaterial* pMat, const char* pVarName, float flValue )
{
Assert( pMat != NULL );
Assert( pVarName != NULL );
if ( pMat == NULL || pVarName == NULL )
{
return false;
}
bool bFound = false;
IMaterialVar* pVar = pMat->FindVar( pVarName, &bFound );
if ( bFound )
{
pVar->SetFloatValue( flValue );
}
return bFound;
}
inline bool ASW_SetMaterialVarInt( IMaterial* pMat, const char* pVarName, int iValue )
{
Assert( pMat != NULL );
Assert( pVarName != NULL );
if ( pMat == NULL || pVarName == NULL )
{
return false;
}
bool bFound = false;
IMaterialVar* pVar = pMat->FindVar( pVarName, &bFound );
if ( bFound )
{
pVar->SetIntValue( iValue );
}
return bFound;
}
inline bool ASW_SetMaterialVarVector4D( IMaterial* pMat, const char* pVarName, const Vector4D &vValue )
{
Assert( pMat != NULL );
Assert( pVarName != NULL );
if ( pMat == NULL || pVarName == NULL )
{
return false;
}
bool bFound = false;
IMaterialVar* pVar = pMat->FindVar( pVarName, &bFound );
if ( bFound )
{
pVar->SetVecValue( vValue.Base(), 4 );
}
return bFound;
}
// Set to true by the client mode when rendering glows, false when done
bool g_bRenderingGlows;
//-----------------------------------------------------------------------------
// Material proxy for getting the strength of the self-illum effect to
// apply to objects when night vision is enabled (value is always 0 when
// the effect is disabled)
//-----------------------------------------------------------------------------
class CASWNightVisionSelfIllumProxy : public CResultProxy
{
public:
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
virtual void OnBind( void *pC_BaseEntity );
};
bool CASWNightVisionSelfIllumProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
{
if ( !CResultProxy::Init( pMaterial, pKeyValues ) )
return false;
return true;
}
void CASWNightVisionSelfIllumProxy::OnBind( void *pC_BaseEntity )
{
Assert( m_pResult );
C_ASW_Player *pPlayer = C_ASW_Player::GetLocalASWPlayer();
if ( !pPlayer || !pC_BaseEntity )
{
SetFloatResult( 0.0f );
return;
}
C_ASW_Marine *pMarine = pPlayer->GetMarine();
if ( !pMarine )
{
SetFloatResult( 0.0f );
return;
}
C_BaseCombatWeapon* pExtraItem = pMarine->GetWeapon( 2 );
if ( pExtraItem && pExtraItem->Classify() == CLASS_ASW_NIGHT_VISION )
{
C_ASW_Weapon_Night_Vision *pVision = assert_cast<CASW_Weapon_Night_Vision*>( pExtraItem );
float flVisionAlpha = pVision->m_flVisionAlpha;
if ( flVisionAlpha != 0.0f )
{
SetFloatResult( flVisionAlpha / 255.0f * asw_night_vision_self_illum_multiplier.GetFloat() );
return;
}
}
if ( pPlayer->IsSniperScopeActive() && g_bRenderingGlows )
{
SetFloatResult( asw_sniper_scope_self_illum_multiplier.GetFloat() );
return;
}
SetFloatResult( 0.0f );
}
EXPOSE_MATERIAL_PROXY( CASWNightVisionSelfIllumProxy, NightVisionSelfIllum );
void CASWViewRender::PerformNightVisionEffect( const CViewSetup &view )
{
C_ASW_Player *pPlayer = C_ASW_Player::GetLocalASWPlayer();
if ( !pPlayer )
return;
C_ASW_Marine *pMarine = pPlayer->GetMarine();
if ( !pMarine )
return;
float flVisionAlpha = 0.0f;
float flFlashAlpha = 0.0f;
C_BaseCombatWeapon* pExtraItem = pMarine->GetWeapon( 2 );
if ( pExtraItem && pExtraItem->Classify() == CLASS_ASW_NIGHT_VISION )
{
C_ASW_Weapon_Night_Vision *pVision = assert_cast<CASW_Weapon_Night_Vision*>( pExtraItem );
flVisionAlpha = pVision->UpdateVisionAlpha();
flFlashAlpha = pVision->UpdateFlashAlpha();
}
if ( flVisionAlpha > 0 )
{
IMaterial *pMaterial = materials->FindMaterial( "effects/nightvision", TEXTURE_GROUP_CLIENT_EFFECTS, true );
if ( pMaterial )
{
byte overlaycolor[4] = { 0, 255, 0, 255 };
UpdateScreenEffectTexture( 0, view.x, view.y, view.width, view.height );
overlaycolor[3] = flVisionAlpha;
render->ViewDrawFade( overlaycolor, pMaterial );
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->DrawScreenSpaceQuad( pMaterial );
render->ViewDrawFade( overlaycolor, pMaterial );
pRenderContext->DrawScreenSpaceQuad( pMaterial );
}
IMaterial *pNoiseMaterial = materials->FindMaterial( "effects/nightvision_noise", TEXTURE_GROUP_CLIENT_EFFECTS, true );
if ( pNoiseMaterial )
{
byte overlaycolor[4] = { 255, 255, 255, 255 };
overlaycolor[3] = MAX( flFlashAlpha, 16.0f );
CMatRenderContextPtr pRenderContext( materials );
render->ViewDrawFade( overlaycolor, pNoiseMaterial );
}
}
if ( flFlashAlpha > 0 )
{
IMaterial *pMaterial = materials->FindMaterial( "effects/nightvision_flash", TEXTURE_GROUP_CLIENT_EFFECTS, true );
if ( pMaterial )
{
byte overlaycolor[4] = { 255, 255, 255, 255 };
overlaycolor[3] = flFlashAlpha;
CMatRenderContextPtr pRenderContext( materials );
render->ViewDrawFade( overlaycolor, pMaterial );
}
}
}