//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================
# include "cbase.h"
# include "materialsystem/imaterialsystem.h"
# include "materialsystem/itexture.h"
# include "materialsystem/imaterialvar.h"
# include "materialsystem/imaterialsystemhardwareconfig.h"
# include "materialsystem/materialsystem_config.h"
# include "tier1/callqueue.h"
# include "colorcorrectionmgr.h"
# include "view_scene.h"
# include "c_world.h"
# include "bitmap/tgawriter.h"
# include "filesystem.h"
# include "tier0/vprof.h"
# include "proxyentity.h"
//-----------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------
// mapmaker controlled autoexposure
bool g_bUseCustomAutoExposureMin = false ;
bool g_bUseCustomAutoExposureMax = false ;
bool g_bUseCustomBloomScale = false ;
float g_flCustomAutoExposureMin = 0 ;
float g_flCustomAutoExposureMax = 0 ;
float g_flCustomBloomScale = 0.0f ;
float g_flCustomBloomScaleMinimum = 0.0f ;
bool g_bFlashlightIsOn = false ;
// hdr parameters
ConVar mat_bloomscale ( " mat_bloomscale " , " 1 " ) ;
ConVar mat_hdr_level ( " mat_hdr_level " , " 2 " , FCVAR_ARCHIVE ) ;
ConVar mat_bloomamount_rate ( " mat_bloomamount_rate " , " 0.05f " , FCVAR_CHEAT ) ;
static ConVar debug_postproc ( " mat_debug_postprocessing_effects " , " 0 " , FCVAR_NONE , " 0 = off, 1 = show post-processing passes in quadrants of the screen, 2 = only apply post-processing to the centre of the screen " ) ;
static ConVar split_postproc ( " mat_debug_process_halfscreen " , " 0 " , FCVAR_CHEAT ) ;
static ConVar mat_postprocessing_combine ( " mat_postprocessing_combine " , " 1 " , FCVAR_NONE , " Combine bloom, software anti-aliasing and color correction into one post-processing pass " ) ;
static ConVar mat_dynamic_tonemapping ( " mat_dynamic_tonemapping " , " 1 " , FCVAR_CHEAT ) ;
static ConVar mat_show_ab_hdr ( " mat_show_ab_hdr " , " 0 " ) ;
static ConVar mat_tonemapping_occlusion_use_stencil ( " mat_tonemapping_occlusion_use_stencil " , " 0 " ) ;
ConVar mat_debug_autoexposure ( " mat_debug_autoexposure " , " 0 " , FCVAR_CHEAT ) ;
static ConVar mat_autoexposure_max ( " mat_autoexposure_max " , " 2 " ) ;
static ConVar mat_autoexposure_min ( " mat_autoexposure_min " , " 0.5 " ) ;
static ConVar mat_show_histogram ( " mat_show_histogram " , " 0 " ) ;
ConVar mat_hdr_tonemapscale ( " mat_hdr_tonemapscale " , " 1.0 " , FCVAR_CHEAT ) ;
ConVar mat_hdr_uncapexposure ( " mat_hdr_uncapexposure " , " 0 " , FCVAR_CHEAT ) ;
ConVar mat_force_bloom ( " mat_force_bloom " , " 0 " , FCVAR_CHEAT ) ;
ConVar mat_disable_bloom ( " mat_disable_bloom " , " 0 " ) ;
ConVar mat_debug_bloom ( " mat_debug_bloom " , " 0 " , FCVAR_CHEAT ) ;
ConVar mat_colorcorrection ( " mat_colorcorrection " , " 0 " ) ;
ConVar mat_accelerate_adjust_exposure_down ( " mat_accelerate_adjust_exposure_down " , " 3.0 " , FCVAR_CHEAT ) ;
ConVar mat_hdr_manual_tonemap_rate ( " mat_hdr_manual_tonemap_rate " , " 1.0 " ) ;
// fudge factor to make non-hdr bloom more closely match hdr bloom. Because of auto-exposure, high
// bloomscales don't blow out as much in hdr. this factor was derived by comparing images in a
// reference scene.
ConVar mat_non_hdr_bloom_scalefactor ( " mat_non_hdr_bloom_scalefactor " , " .3 " ) ;
// Apply addition scale to the final bloom scale
static ConVar mat_bloom_scalefactor_scalar ( " mat_bloom_scalefactor_scalar " , " 1.0 " ) ;
//ConVar mat_exposure_center_region_x( "mat_exposure_center_region_x","0.75", FCVAR_CHEAT );
//ConVar mat_exposure_center_region_y( "mat_exposure_center_region_y","0.80", FCVAR_CHEAT );
//ConVar mat_exposure_center_region_x_flashlight( "mat_exposure_center_region_x_flashlight","0.33", FCVAR_CHEAT );
//ConVar mat_exposure_center_region_y_flashlight( "mat_exposure_center_region_y_flashlight","0.33", FCVAR_CHEAT );
ConVar mat_exposure_center_region_x ( " mat_exposure_center_region_x " , " 0.9 " , FCVAR_CHEAT ) ;
ConVar mat_exposure_center_region_y ( " mat_exposure_center_region_y " , " 0.85 " , FCVAR_CHEAT ) ;
ConVar mat_exposure_center_region_x_flashlight ( " mat_exposure_center_region_x_flashlight " , " 0.9 " , FCVAR_CHEAT ) ;
ConVar mat_exposure_center_region_y_flashlight ( " mat_exposure_center_region_y_flashlight " , " 0.85 " , FCVAR_CHEAT ) ;
ConVar mat_tonemap_algorithm ( " mat_tonemap_algorithm " , " 1 " , FCVAR_CHEAT , " 0 = Original Algorithm 1 = New Algorithm " ) ;
ConVar mat_tonemap_percent_target ( " mat_tonemap_percent_target " , " 60.0 " , FCVAR_CHEAT ) ;
ConVar mat_tonemap_percent_bright_pixels ( " mat_tonemap_percent_bright_pixels " , " 2.0 " , FCVAR_CHEAT ) ;
ConVar mat_tonemap_min_avglum ( " mat_tonemap_min_avglum " , " 3.0 " , FCVAR_CHEAT ) ;
ConVar mat_fullbright ( " mat_fullbright " , " 0 " , FCVAR_CHEAT ) ;
extern ConVar localplayer_visionflags ;
enum PostProcessingCondition {
PPP_ALWAYS ,
PPP_IF_COND_VAR ,
PPP_IF_NOT_COND_VAR
} ;
struct PostProcessingPass {
PostProcessingCondition ppp_test ;
ConVar const * cvar_to_test ;
char const * material_name ; // terminate list with null
char const * dest_rendering_target ;
char const * src_rendering_target ; // can be null. needed for source scaling
int xdest_scale , ydest_scale ; // allows scaling down
int xsrc_scale , ysrc_scale ; // allows scaling down
CMaterialReference m_mat_ref ; // so we don't have to keep searching
} ;
# define PPP_PROCESS_PARTIAL_SRC(srcmatname,dest_rt_name,src_tname,scale) \
{ PPP_ALWAYS , 0 , srcmatname , dest_rt_name , src_tname , 1 , 1 , scale , scale }
# define PPP_PROCESS_PARTIAL_DEST(srcmatname,dest_rt_name,src_tname,scale) \
{ PPP_ALWAYS , 0 , srcmatname , dest_rt_name , src_tname , scale , scale , 1 , 1 }
# define PPP_PROCESS_PARTIAL_SRC_PARTIAL_DEST(srcmatname,dest_rt_name,src_tname,srcscale,destscale) \
{ PPP_ALWAYS , 0 , srcmatname , dest_rt_name , src_tname , destscale , destscale , srcscale , srcscale }
# define PPP_END {PPP_ALWAYS,0,NULL,NULL,0,0,0,0,0}
# define PPP_PROCESS(srcmatname,dest_rt_name) {PPP_ALWAYS,0,srcmatname,dest_rt_name,0,1,1,1,1}
# define PPP_PROCESS_IF_CVAR(cvarptr,srcmatname,dest_rt_name) \
{ PPP_IF_COND_VAR , cvarptr , srcmatname , dest_rt_name , 0 , 1 , 1 , 1 , 1 }
# define PPP_PROCESS_IF_NOT_CVAR(cvarptr,srcmatname,dest_rt_name) \
{ PPP_IF_NOT_COND_VAR , cvarptr , srcmatname , dest_rt_name , 0 , 1 , 1 , 1 , 1 }
# define PPP_PROCESS_IF_NOT_CVAR_SRCTEXTURE(cvarptr,srcmatname,src_tname,dest_rt_name) \
{ PPP_IF_NOT_COND_VAR , cvarptr , srcmatname , dest_rt_name , src_tname , 1 , 1 , 1 , 1 }
# define PPP_PROCESS_IF_CVAR_SRCTEXTURE(cvarptr,srcmatname,src_txtrname,dest_rt_name) \
{ PPP_IF_COND_VAR , cvarptr , srcmatname , dest_rt_name , src_txtrname , 1 , 1 , 1 , 1 }
# define PPP_PROCESS_SRCTEXTURE(srcmatname,src_tname,dest_rt_name) \
{ PPP_ALWAYS , 0 , srcmatname , dest_rt_name , src_tname , 1 , 1 , 1 , 1 }
struct ClipBox
{
int m_minx , m_miny ;
int m_maxx , m_maxy ;
} ;
static void DrawClippedScreenSpaceRectangle (
IMaterial * pMaterial ,
int destx , int desty ,
int width , int height ,
float src_texture_x0 , float src_texture_y0 , // which texel you want to appear at
// destx/y
float src_texture_x1 , float src_texture_y1 , // which texel you want to appear at
// destx+width-1, desty+height-1
int src_texture_width , int src_texture_height , // needed for fixup
ClipBox const * clipbox ,
void * pClientRenderable = NULL )
{
if ( clipbox )
{
if ( ( destx > clipbox - > m_maxx ) | | ( desty > clipbox - > m_maxy ) )
return ;
if ( ( destx + width - 1 < clipbox - > m_minx ) | | ( desty + height - 1 < clipbox - > m_miny ) )
return ;
// left clip
if ( destx < clipbox - > m_minx )
{
src_texture_x0 = FLerp ( src_texture_x0 , src_texture_x1 , destx , destx + width - 1 , clipbox - > m_minx ) ;
width - = ( clipbox - > m_minx - destx ) ;
destx = clipbox - > m_minx ;
}
// top clip
if ( desty < clipbox - > m_miny )
{
src_texture_y0 = FLerp ( src_texture_y0 , src_texture_y1 , desty , desty + height - 1 , clipbox - > m_miny ) ;
height - = ( clipbox - > m_miny - desty ) ;
desty = clipbox - > m_miny ;
}
// right clip
if ( destx + width - 1 > clipbox - > m_maxx )
{
src_texture_x1 = FLerp ( src_texture_x0 , src_texture_x1 , destx , destx + width - 1 , clipbox - > m_maxx ) ;
width = clipbox - > m_maxx - destx ;
}
// bottom clip
if ( desty + height - 1 > clipbox - > m_maxy )
{
src_texture_y1 = FLerp ( src_texture_y0 , src_texture_y1 , desty , desty + height - 1 , clipbox - > m_maxy ) ;
height = clipbox - > m_maxy - desty ;
}
}
CMatRenderContextPtr pRenderContext ( materials ) ;
pRenderContext - > DrawScreenSpaceRectangle ( pMaterial , destx , desty , width , height , src_texture_x0 ,
src_texture_y0 , src_texture_x1 , src_texture_y1 ,
src_texture_width , src_texture_height , pClientRenderable ) ;
}
void ApplyPostProcessingPasses ( PostProcessingPass * pass_list , // table of effects to apply
ClipBox const * clipbox = 0 , // clipping box for these effects
ClipBox * dest_coords_out = 0 ) // receives dest coords of last blit
{
CMatRenderContextPtr pRenderContext ( materials ) ;
ITexture * pSaveRenderTarget = pRenderContext - > GetRenderTarget ( ) ;
int pcount = 0 ;
if ( debug_postproc . GetInt ( ) = = 1 )
{
pRenderContext - > SetRenderTarget ( NULL ) ;
int dest_width , dest_height ;
pRenderContext - > GetRenderTargetDimensions ( dest_width , dest_height ) ;
pRenderContext - > Viewport ( 0 , 0 , dest_width , dest_height ) ;
pRenderContext - > ClearColor3ub ( 255 , 0 , 0 ) ;
// pRenderContext->ClearBuffers(true,true);
}
while ( pass_list - > material_name )
{
bool do_it = true ;
switch ( pass_list - > ppp_test )
{
case PPP_IF_COND_VAR :
do_it = ( pass_list - > cvar_to_test ) - > GetBool ( ) ;
break ;
case PPP_IF_NOT_COND_VAR :
do_it = ! ( ( pass_list - > cvar_to_test ) - > GetBool ( ) ) ;
break ;
}
if ( ( pass_list - > dest_rendering_target = = 0 ) & & ( debug_postproc . GetInt ( ) = = 1 ) )
do_it = 0 ;
if ( do_it )
{
ClipBox const * cb = 0 ;
if ( pass_list - > dest_rendering_target = = 0 )
{
cb = clipbox ;
}
IMaterial * src_mat = pass_list - > m_mat_ref ;
if ( ! src_mat )
{
src_mat = materials - > FindMaterial ( pass_list - > material_name ,
TEXTURE_GROUP_OTHER , true ) ;
if ( src_mat )
{
pass_list - > m_mat_ref . Init ( src_mat ) ;
}
}
if ( pass_list - > dest_rendering_target )
{
ITexture * dest_rt = materials - > FindTexture ( pass_list - > dest_rendering_target ,
TEXTURE_GROUP_RENDER_TARGET ) ;
pRenderContext - > SetRenderTarget ( dest_rt ) ;
}
else
{
pRenderContext - > SetRenderTarget ( NULL ) ;
}
int dest_width , dest_height ;
pRenderContext - > GetRenderTargetDimensions ( dest_width , dest_height ) ;
pRenderContext - > Viewport ( 0 , 0 , dest_width , dest_height ) ;
dest_width / = pass_list - > xdest_scale ;
dest_height / = pass_list - > ydest_scale ;
if ( pass_list - > src_rendering_target )
{
ITexture * src_rt = materials - > FindTexture ( pass_list - > src_rendering_target ,
TEXTURE_GROUP_RENDER_TARGET ) ;
int src_width = src_rt - > GetActualWidth ( ) ;
int src_height = src_rt - > GetActualHeight ( ) ;
int ssrc_width = ( src_width - 1 ) / pass_list - > xsrc_scale ;
int ssrc_height = ( src_height - 1 ) / pass_list - > ysrc_scale ;
DrawClippedScreenSpaceRectangle (
src_mat , 0 , 0 , dest_width , dest_height ,
0 , 0 , ssrc_width , ssrc_height , src_width , src_height , cb ) ;
if ( ( pass_list - > dest_rendering_target ) & & ( debug_postproc . GetInt ( ) = = 1 ) )
{
pRenderContext - > SetRenderTarget ( NULL ) ;
int row = pcount / 2 ;
int col = pcount % 2 ;
int vdest_width , vdest_height ;
pRenderContext - > GetRenderTargetDimensions ( vdest_width , vdest_height ) ;
pRenderContext - > Viewport ( 0 , 0 , vdest_width , vdest_height ) ;
pRenderContext - > DrawScreenSpaceRectangle (
src_mat , col * 400 , 200 + row * 300 , dest_width , dest_height ,
0 , 0 , ssrc_width , ssrc_height , src_width , src_height ) ;
}
}
else
{
// just draw the whole source
if ( ( pass_list - > dest_rendering_target = = 0 ) & & split_postproc . GetInt ( ) )
{
DrawClippedScreenSpaceRectangle ( src_mat , 0 , 0 , dest_width / 2 , dest_height ,
0 , 0 , .5 , 1 , 1 , 1 , cb ) ;
}
else
{
DrawClippedScreenSpaceRectangle ( src_mat , 0 , 0 , dest_width , dest_height ,
0 , 0 , 1 , 1 , 1 , 1 , cb ) ;
}
if ( ( pass_list - > dest_rendering_target ) & & ( debug_postproc . GetInt ( ) = = 1 ) )
{
pRenderContext - > SetRenderTarget ( NULL ) ;
int row = pcount / 4 ;
int col = pcount % 4 ;
int dest_width , dest_height ;
pRenderContext - > GetRenderTargetDimensions ( dest_width , dest_height ) ;
pRenderContext - > Viewport ( 0 , 0 , dest_width , dest_height ) ;
DrawClippedScreenSpaceRectangle ( src_mat , 10 + col * 220 , 10 + row * 220 ,
200 , 200 ,
0 , 0 , 1 , 1 , 1 , 1 , cb ) ;
}
}
if ( dest_coords_out )
{
dest_coords_out - > m_minx = 0 ;
dest_coords_out - > m_maxx = dest_width - 1 ;
dest_coords_out - > m_miny = 0 ;
dest_coords_out - > m_maxy = dest_height - 1 ;
}
}
pass_list + + ;
pcount + + ;
}
pRenderContext - > SetRenderTarget ( pSaveRenderTarget ) ;
}
PostProcessingPass HDRFinal_Float [ ] =
{
PPP_PROCESS_SRCTEXTURE ( " dev/downsample " , " _rt_FullFrameFB " , " _rt_SmallFB0 " ) ,
PPP_PROCESS_SRCTEXTURE ( " dev/blurfilterx " , " _rt_SmallFB0 " , " _rt_SmallFB1 " ) ,
PPP_PROCESS_SRCTEXTURE ( " dev/blurfiltery " , " _rt_SmallFB1 " , " _rt_SmallFB0 " ) ,
PPP_PROCESS_SRCTEXTURE ( " dev/floattoscreen_combine " , " _rt_FullFrameFB " , NULL ) ,
PPP_END
} ;
PostProcessingPass HDRFinal_Float_NoBloom [ ] =
{
PPP_PROCESS_SRCTEXTURE ( " dev/copyfullframefb " , " _rt_FullFrameFB " , NULL ) ,
PPP_END
} ;
PostProcessingPass HDRSimulate_NonHDR [ ] =
{
PPP_PROCESS ( " dev/copyfullframefb_vanilla " , NULL ) ,
PPP_END
} ;
static void SetRenderTargetAndViewPort ( ITexture * rt )
{
tmZone ( TELEMETRY_LEVEL0 , TMZF_NONE , " %s " , __FUNCTION__ ) ;
CMatRenderContextPtr pRenderContext ( materials ) ;
pRenderContext - > SetRenderTarget ( rt ) ;
pRenderContext - > Viewport ( 0 , 0 , rt - > GetActualWidth ( ) , rt - > GetActualHeight ( ) ) ;
}
# define FILTER_KERNEL_SLOP 20
// Note carefully about the downsampling: the first downsampling samples from the full rendertarget
// down to a temp. When doing this sampling, the texture source clamping will take care of the out
// of bounds sampling done because of the filter kernels's width. However, on any of the subsequent
// sampling operations, we will be sampling from a partially filled render target. So, texture
// coordinate clamping cannot help us here. So, we need to always render a few more pixels to the
// destination than we actually intend to, so as to replicate the border pixels so that garbage
// pixels do not get sucked into the sampling. To deal with this, we always add FILTER_KERNEL_SLOP
// to our widths/heights if there is room for them in the destination.
static void DrawScreenSpaceRectangleWithSlop (
ITexture * dest_rt ,
IMaterial * pMaterial ,
int destx , int desty ,
int width , int height ,
float src_texture_x0 , float src_texture_y0 , // which texel you want to appear at
// destx/y
float src_texture_x1 , float src_texture_y1 , // which texel you want to appear at
// destx+width-1, desty+height-1
int src_texture_width , int src_texture_height // needed for fixup
)
{
// add slop
int slopwidth = width + FILTER_KERNEL_SLOP ; //min(dest_rt->GetActualWidth()-destx,width+FILTER_KERNEL_SLOP);
int slopheight = height + FILTER_KERNEL_SLOP ; //min(dest_rt->GetActualHeight()-desty,height+FILTER_KERNEL_SLOP);
// adjust coordinates for slop
src_texture_x1 = FLerp ( src_texture_x0 , src_texture_x1 , destx , destx + width - 1 , destx + slopwidth - 1 ) ;
src_texture_y1 = FLerp ( src_texture_y0 , src_texture_y1 , desty , desty + height - 1 , desty + slopheight - 1 ) ;
width = slopwidth ;
height = slopheight ;
CMatRenderContextPtr pRenderContext ( materials ) ;
pRenderContext - > DrawScreenSpaceRectangle ( pMaterial , destx , desty , width , height ,
src_texture_x0 , src_texture_y0 ,
src_texture_x1 , src_texture_y1 ,
src_texture_width , src_texture_height ) ;
}
enum Histogram_entry_state_t
{
HESTATE_INITIAL = 0 ,
HESTATE_FIRST_QUERY_IN_FLIGHT ,
HESTATE_QUERY_IN_FLIGHT ,
HESTATE_QUERY_DONE ,
} ;
# define N_LUMINANCE_RANGES 31
# define N_LUMINANCE_RANGES_NEW 17
# define MAX_QUERIES_PER_FRAME 1
class CHistogram_entry_t
{
public :
Histogram_entry_state_t m_state ;
OcclusionQueryObjectHandle_t m_occ_handle ; // the occlusion query handle
int m_frame_queued ; // when this query was last queued
int m_npixels ; // # of pixels this histogram represents
int m_npixels_in_range ;
float m_min_lum , m_max_lum ; // the luminance range this entry was queried with
float m_minx , m_miny , m_maxx , m_maxy ; // range is 0..1 in fractions of the screen
bool ContainsValidData ( void )
{
return ( m_state = = HESTATE_QUERY_DONE ) | | ( m_state = = HESTATE_QUERY_IN_FLIGHT ) ;
}
void IssueQuery ( int frm_num ) ;
} ;
void CHistogram_entry_t : : IssueQuery ( int frm_num )
{
CMatRenderContextPtr pRenderContext ( materials ) ;
if ( ! m_occ_handle )
{
m_occ_handle = pRenderContext - > CreateOcclusionQueryObject ( ) ;
}
int xl , yl , dest_width , dest_height ;
pRenderContext - > GetViewport ( xl , yl , dest_width , dest_height ) ;
// Find min and max gamma-space text range
float flTestRangeMin = m_min_lum ;
float flTestRangeMax = ( m_max_lum = = 1.0f ) ? 10000.0f : m_max_lum ; // Count all pixels >1.0 as 1.0
// First, set stencil bits where the colors match
IMaterial * test_mat = materials - > FindMaterial ( " dev/lumcompare " , TEXTURE_GROUP_OTHER , true ) ;
IMaterialVar * pMinVar = test_mat - > FindVar ( " $C0_X " , NULL ) ;
pMinVar - > SetFloatValue ( flTestRangeMin ) ;
IMaterialVar * pMaxVar = test_mat - > FindVar ( " $C0_Y " , NULL ) ;
pMaxVar - > SetFloatValue ( flTestRangeMax ) ;
int scrx_min = FLerp ( xl , ( xl + dest_width - 1 ) , 0 , 1 , m_minx ) ;
int scrx_max = FLerp ( xl , ( xl + dest_width - 1 ) , 0 , 1 , m_maxx ) ;
int scry_min = FLerp ( yl , ( yl + dest_height - 1 ) , 0 , 1 , m_miny ) ;
int scry_max = FLerp ( yl , ( yl + dest_height - 1 ) , 0 , 1 , m_maxy ) ;
float exposure_width_scale , exposure_height_scale ;
// now, shrink region of interest if the flashlight is on
if ( g_bFlashlightIsOn )
{
exposure_width_scale = ( 0.5f * ( 1.0f - mat_exposure_center_region_x_flashlight . GetFloat ( ) ) ) ;
exposure_height_scale = ( 0.5f * ( 1.0f - mat_exposure_center_region_y_flashlight . GetFloat ( ) ) ) ;
}
else
{
exposure_width_scale = ( 0.5f * ( 1.0f - mat_exposure_center_region_x . GetFloat ( ) ) ) ;
exposure_height_scale = ( 0.5f * ( 1.0f - mat_exposure_center_region_y . GetFloat ( ) ) ) ;
}
int skip_edgex = ( 1 + scrx_max - scrx_min ) * exposure_width_scale ;
int skip_edgey = ( 1 + scry_max - scry_min ) * exposure_height_scale ;
// now, do luminance compare
float tscale = 1.0 ;
if ( g_pMaterialSystemHardwareConfig - > GetHDRType ( ) = = HDR_TYPE_FLOAT )
{
tscale = pRenderContext - > GetToneMappingScaleLinear ( ) . x ;
}
IMaterialVar * use_t_scale = test_mat - > FindVar ( " $C0_Z " , NULL ) ;
use_t_scale - > SetFloatValue ( tscale ) ;
m_npixels = ( 1 + scrx_max - scrx_min ) * ( 1 + scry_max - scry_min ) ;
if ( mat_tonemapping_occlusion_use_stencil . GetInt ( ) )
{
pRenderContext - > SetStencilWriteMask ( 1 ) ;
// AV - We don't need to clear stencil here because it's already been cleared at the beginning of the frame
//pRenderContext->ClearStencilBufferRectangle( scrx_min, scry_min, scrx_max, scry_max, 0 );
pRenderContext - > SetStencilEnable ( true ) ;
pRenderContext - > SetStencilPassOperation ( STENCILOPERATION_REPLACE ) ;
pRenderContext - > SetStencilCompareFunction ( STENCILCOMPARISONFUNCTION_ALWAYS ) ;
pRenderContext - > SetStencilFailOperation ( STENCILOPERATION_KEEP ) ;
pRenderContext - > SetStencilZFailOperation ( STENCILOPERATION_KEEP ) ;
pRenderContext - > SetStencilReferenceValue ( 1 ) ;
}
else
{
pRenderContext - > BeginOcclusionQueryDrawing ( m_occ_handle ) ;
}
scrx_min + = skip_edgex ;
scry_min + = skip_edgey ;
scrx_max - = skip_edgex ;
scry_max - = skip_edgey ;
pRenderContext - > DrawScreenSpaceRectangle ( test_mat ,
scrx_min , scry_min ,
1 + scrx_max - scrx_min ,
1 + scry_max - scry_min ,
scrx_min , scry_min ,
scrx_max , scry_max ,
dest_width , dest_height ) ;
if ( mat_tonemapping_occlusion_use_stencil . GetInt ( ) )
{
// now, start counting how many pixels had their stencil bit set via an occlusion query
pRenderContext - > BeginOcclusionQueryDrawing ( m_occ_handle ) ;
// now, issue an occlusion query using stencil as the mask
pRenderContext - > SetStencilEnable ( true ) ;
pRenderContext - > SetStencilTestMask ( 1 ) ;
pRenderContext - > SetStencilPassOperation ( STENCILOPERATION_KEEP ) ;
pRenderContext - > SetStencilCompareFunction ( STENCILCOMPARISONFUNCTION_EQUAL ) ;
pRenderContext - > SetStencilFailOperation ( STENCILOPERATION_KEEP ) ;
pRenderContext - > SetStencilZFailOperation ( STENCILOPERATION_KEEP ) ;
pRenderContext - > SetStencilReferenceValue ( 1 ) ;
IMaterial * stest_mat = materials - > FindMaterial ( " dev/no_pixel_write " , TEXTURE_GROUP_OTHER , true ) ;
pRenderContext - > DrawScreenSpaceRectangle ( stest_mat ,
scrx_min , scry_min ,
1 + scrx_max - scrx_min ,
1 + scry_max - scry_min ,
scrx_min , scry_min ,
scrx_max , scry_max ,
dest_width , dest_height ) ;
pRenderContext - > SetStencilEnable ( false ) ;
}
pRenderContext - > EndOcclusionQueryDrawing ( m_occ_handle ) ;
if ( m_state = = HESTATE_INITIAL )
m_state = HESTATE_FIRST_QUERY_IN_FLIGHT ;
else
m_state = HESTATE_QUERY_IN_FLIGHT ;
m_frame_queued = frm_num ;
}
# define HISTOGRAM_BAR_SIZE 200
class CLuminanceHistogramSystem
{
CHistogram_entry_t CurHistogram [ N_LUMINANCE_RANGES ] ;
int cur_query_frame ;
public :
float FindLocationOfPercentBrightPixels ( float flPercentBrightPixels , float flPercentTarget ) ;
float GetTargetTonemapScalar ( bool bGetIdealTargetForDebugMode ) ;
void Update ( void ) ;
void DisplayHistogram ( void ) ;
void UpdateLuminanceRanges ( void ) ;
CLuminanceHistogramSystem ( void )
{
UpdateLuminanceRanges ( ) ;
}
} ;
void CLuminanceHistogramSystem : : Update ( void )
{
UpdateLuminanceRanges ( ) ;
// find which histogram entries should have something done this frame
int n_queries_issued_this_frame = 0 ;
cur_query_frame + + ;
int nNumRanges = N_LUMINANCE_RANGES ;
if ( mat_tonemap_algorithm . GetInt ( ) = = 1 )
nNumRanges = N_LUMINANCE_RANGES_NEW ;
for ( int i = 0 ; i < nNumRanges ; i + + )
{
switch ( CurHistogram [ i ] . m_state )
{
case HESTATE_INITIAL :
if ( n_queries_issued_this_frame < MAX_QUERIES_PER_FRAME )
{
CurHistogram [ i ] . IssueQuery ( cur_query_frame ) ;
n_queries_issued_this_frame + + ;
}
break ;
case HESTATE_FIRST_QUERY_IN_FLIGHT :
case HESTATE_QUERY_IN_FLIGHT :
if ( cur_query_frame > CurHistogram [ i ] . m_frame_queued + 2 )
{
CMatRenderContextPtr pRenderContext ( materials ) ;
int np = pRenderContext - > OcclusionQuery_GetNumPixelsRendered (
CurHistogram [ i ] . m_occ_handle ) ;
if ( np ! = - 1 ) // -1=query not finished. wait until
// next time
{
CurHistogram [ i ] . m_npixels_in_range = np ;
// if (mat_debug_autoexposure.GetInt())
// Warning("min=%f max=%f np = %d\n",CurHistogram[i].m_min_lum,CurHistogram[i].m_max_lum,np);
CurHistogram [ i ] . m_state = HESTATE_QUERY_DONE ;
}
}
break ;
}
}
// now, issue queries for the oldest finished queries we have
while ( n_queries_issued_this_frame < MAX_QUERIES_PER_FRAME )
{
int nNumRanges = N_LUMINANCE_RANGES ;
if ( mat_tonemap_algorithm . GetInt ( ) = = 1 )
nNumRanges = N_LUMINANCE_RANGES_NEW ;
int oldest_so_far = - 1 ;
for ( int i = 0 ; i < nNumRanges ; i + + )
if ( ( CurHistogram [ i ] . m_state = = HESTATE_QUERY_DONE ) & &
( ( oldest_so_far = = - 1 ) | |
( CurHistogram [ i ] . m_frame_queued <
CurHistogram [ oldest_so_far ] . m_frame_queued ) ) )
oldest_so_far = i ;
if ( oldest_so_far = = - 1 ) // nothing to do
break ;
CurHistogram [ oldest_so_far ] . IssueQuery ( cur_query_frame ) ;
n_queries_issued_this_frame + + ;
}
}
float CLuminanceHistogramSystem : : FindLocationOfPercentBrightPixels ( float flPercentBrightPixels , float flPercentTargetToSnapToIfInSameBin = - 1.0f )
{
if ( mat_tonemap_algorithm . GetInt ( ) = = 1 ) // New algorithm
{
int nTotalValidPixels = 0 ;
for ( int i = 0 ; i < N_LUMINANCE_RANGES_NEW - 1 ; i + + )
{
if ( CurHistogram [ i ] . ContainsValidData ( ) )
{
nTotalValidPixels + = CurHistogram [ i ] . m_npixels_in_range ;
}
}
if ( nTotalValidPixels = = 0 )
{
return - 1.0f ;
}
// Find where percent range border is
float flTotalPercentRangeTested = 0.0f ;
float flTotalPercentPixelsTested = 0.0f ;
for ( int i = N_LUMINANCE_RANGES_NEW - 2 ; i > = 0 ; i - - ) // Start at the bright end
{
if ( ! CurHistogram [ i ] . ContainsValidData ( ) )
return - 1.0f ;
float flPixelPercentNeeded = ( flPercentBrightPixels / 100.0f ) - flTotalPercentPixelsTested ;
float flThisBinPercentOfTotalPixels = float ( CurHistogram [ i ] . m_npixels_in_range ) / float ( nTotalValidPixels ) ;
float flThisBinLuminanceRange = CurHistogram [ i ] . m_max_lum - CurHistogram [ i ] . m_min_lum ;
if ( flThisBinPercentOfTotalPixels > = flPixelPercentNeeded ) // We found the bin needed
{
if ( flPercentTargetToSnapToIfInSameBin > = 0.0f )
{
if ( ( CurHistogram [ i ] . m_min_lum < = ( flPercentTargetToSnapToIfInSameBin / 100.0f ) ) & & ( CurHistogram [ i ] . m_max_lum > = ( flPercentTargetToSnapToIfInSameBin / 100.0f ) ) )
{
// Sticky bin...We're in the same bin as the target so keep the tonemap scale where it is
return ( flPercentTargetToSnapToIfInSameBin / 100.0f ) ;
}
}
float flPercentOfThesePixelsNeeded = flPixelPercentNeeded / flThisBinPercentOfTotalPixels ;
float flPercentLocationOfBorder = 1.0f - ( flTotalPercentRangeTested + ( flThisBinLuminanceRange * flPercentOfThesePixelsNeeded ) ) ;
flPercentLocationOfBorder = MAX ( CurHistogram [ i ] . m_min_lum , MIN ( CurHistogram [ i ] . m_max_lum , flPercentLocationOfBorder ) ) ; // Clamp to this bin just in case
return flPercentLocationOfBorder ;
}
flTotalPercentPixelsTested + = flThisBinPercentOfTotalPixels ;
flTotalPercentRangeTested + = flThisBinLuminanceRange ;
}
return - 1.0f ;
}
else
{
// Don't know what to do for other algorithms yet
return - 1.0f ;
}
}
float CLuminanceHistogramSystem : : GetTargetTonemapScalar ( bool bGetIdealTargetForDebugMode = false )
{
if ( mat_tonemap_algorithm . GetInt ( ) = = 1 ) // New algorithm
{
float flPercentLocationOfTarget ;
if ( bGetIdealTargetForDebugMode = = true )
flPercentLocationOfTarget = FindLocationOfPercentBrightPixels ( mat_tonemap_percent_bright_pixels . GetFloat ( ) ) ; // Don't pass in the second arg so the scalar doesn't snap to a bin
else
flPercentLocationOfTarget = FindLocationOfPercentBrightPixels ( mat_tonemap_percent_bright_pixels . GetFloat ( ) , mat_tonemap_percent_target . GetFloat ( ) ) ;
if ( flPercentLocationOfTarget < 0.0f ) // This is the return error code
{
flPercentLocationOfTarget = mat_tonemap_percent_target . GetFloat ( ) / 100.0f ; // Pretend we're at the target
}
// Make sure this is > 0.0f
flPercentLocationOfTarget = MAX ( 0.0001f , flPercentLocationOfTarget ) ;
// Compute target scalar
float flTargetScalar = ( mat_tonemap_percent_target . GetFloat ( ) / 100.0f ) / flPercentLocationOfTarget ;
// Compute secondary target scalar
float flAverageLuminanceLocation = FindLocationOfPercentBrightPixels ( 50.0f ) ;
if ( flAverageLuminanceLocation > 0.0f )
{
float flTargetScalar2 = ( mat_tonemap_min_avglum . GetFloat ( ) / 100.0f ) / flAverageLuminanceLocation ;
// Only override it if it's trying to brighten the image more than the primary algorithm
if ( flTargetScalar2 > flTargetScalar )
{
flTargetScalar = flTargetScalar2 ;
}
}
// Apply this against last frames scalar
CMatRenderContextPtr pRenderContext ( materials ) ;
float flLastScale = pRenderContext - > GetToneMappingScaleLinear ( ) . x ;
flTargetScalar * = flLastScale ;
flTargetScalar = MAX ( 0.001f , flTargetScalar ) ;
return flTargetScalar ;
}
else // Original tonemapping
{
float average_luminance = 0.5f ;
float total = 0 ;
int total_pixels = 0 ;
float scale_value = 1.0 ;
if ( CurHistogram [ N_LUMINANCE_RANGES - 1 ] . ContainsValidData ( ) )
{
scale_value = CurHistogram [ N_LUMINANCE_RANGES - 1 ] . m_npixels * ( 1.0f / CurHistogram [ N_LUMINANCE_RANGES - 1 ] . m_npixels_in_range ) ;
if ( mat_debug_autoexposure . GetInt ( ) )
{
engine - > Con_NPrintf ( 20 , " Scale value = %f " , scale_value ) ;
//Warning( "scale value=%f\n", scale_value );
}
}
else
average_luminance = 0.5 ;
if ( ! IsFinite ( scale_value ) )
scale_value = 1.0f ;
for ( int i = 0 ; i < N_LUMINANCE_RANGES - 1 ; i + + )
{
if ( CurHistogram [ i ] . ContainsValidData ( ) )
{
total + = scale_value * CurHistogram [ i ] . m_npixels_in_range * AVG ( CurHistogram [ i ] . m_min_lum , CurHistogram [ i ] . m_max_lum ) ;
total_pixels + = CurHistogram [ i ] . m_npixels ;
}
else
average_luminance = 0.5 ; // always return 0.5 until we've queried a whole frame
}
if ( total_pixels > 0 )
average_luminance = total * ( 1.0 / total_pixels ) ;
else
average_luminance = 0.5 ;
// Make sure this is > 0.0f
average_luminance = MAX ( 0.0001f , average_luminance ) ;
// Compute target scalar
float flTargetScalar = 0.005 / average_luminance ;
return flTargetScalar ;
}
}
static float GetCurrentBloomScale ( void )
{
// Use the appropriate bloom scale settings. Mapmakers's overrides the convar settings.
float flCurrentBloomScale = 1.0f ;
if ( g_bUseCustomBloomScale )
{
flCurrentBloomScale = g_flCustomBloomScale ;
}
else
{
flCurrentBloomScale = mat_bloomscale . GetFloat ( ) ;
}
return flCurrentBloomScale ;
}
static void GetExposureRange ( float * flAutoExposureMin , float * flAutoExposureMax )
{
// Get min
if ( ( g_bUseCustomAutoExposureMin ) & & ( g_flCustomAutoExposureMin > 0.0f ) )
{
* flAutoExposureMin = g_flCustomAutoExposureMin ;
}
else
{
* flAutoExposureMin = mat_autoexposure_min . GetFloat ( ) ;
}
// Get max
if ( ( g_bUseCustomAutoExposureMax ) & & ( g_flCustomAutoExposureMax > 0.0f ) )
{
* flAutoExposureMax = g_flCustomAutoExposureMax ;
}
else
{
* flAutoExposureMax = mat_autoexposure_max . GetFloat ( ) ;
}
// Override
if ( mat_hdr_uncapexposure . GetInt ( ) )
{
* flAutoExposureMax = 20.0f ;
* flAutoExposureMin = 0.0f ;
}
// Make sure min <= max
if ( * flAutoExposureMin > * flAutoExposureMax )
{
* flAutoExposureMax = * flAutoExposureMin ;
}
}
void CLuminanceHistogramSystem : : UpdateLuminanceRanges ( void )
{
// Only update if our mode changed
static int s_nCurrentBucketAlgorithm = - 1 ;
if ( s_nCurrentBucketAlgorithm = = mat_tonemap_algorithm . GetInt ( ) )
return ;
s_nCurrentBucketAlgorithm = mat_tonemap_algorithm . GetInt ( ) ;
//==================================================================//
// Force fallback to original tone mapping algorithm for these mods //
//==================================================================//
static bool s_bFirstTime = true ;
if ( engine = = NULL )
{
// Force this code to get hit again so we can change algorithm based on the client
s_nCurrentBucketAlgorithm = - 1 ;
}
else if ( s_bFirstTime = = true )
{
s_bFirstTime = false ;
// This seems like a bad idea but it's fine for now
const char * sModsForOriginalAlgorithm [ ] = { " dod " , " cstrike " , " lostcoast " , " hl1 " } ;
for ( int i = 0 ; i < 3 ; i + + )
{
if ( strlen ( engine - > GetGameDirectory ( ) ) > = strlen ( sModsForOriginalAlgorithm [ i ] ) )
{
if ( stricmp ( & ( engine - > GetGameDirectory ( ) [ strlen ( engine - > GetGameDirectory ( ) ) - strlen ( sModsForOriginalAlgorithm [ i ] ) ] ) , sModsForOriginalAlgorithm [ i ] ) = = 0 )
{
mat_tonemap_algorithm . SetValue ( 0 ) ; // Original algorithm
s_nCurrentBucketAlgorithm = mat_tonemap_algorithm . GetInt ( ) ;
break ;
}
}
}
}
int nNumRanges = N_LUMINANCE_RANGES ;
if ( mat_tonemap_algorithm . GetInt ( ) = = 1 )
nNumRanges = N_LUMINANCE_RANGES_NEW ;
cur_query_frame = 0 ;
for ( int bucket = 0 ; bucket < nNumRanges ; bucket + + )
{
int idx = bucket ;
CHistogram_entry_t & e = CurHistogram [ idx ] ;
e . m_state = HESTATE_INITIAL ;
e . m_minx = 0 ;
e . m_maxx = 1 ;
e . m_miny = 0 ;
e . m_maxy = 1 ;
if ( bucket ! = nNumRanges - 1 ) // Last bucket is special
{
if ( mat_tonemap_algorithm . GetInt ( ) = = 0 ) // Original algorithm
{
// Use a logarithmic ramp for high range in the low range
e . m_min_lum = - 0.01 + exp ( FLerp ( log ( .01 ) , log ( .01 + 1 ) , 0 , nNumRanges - 1 , bucket ) ) ;
e . m_max_lum = - 0.01 + exp ( FLerp ( log ( .01 ) , log ( .01 + 1 ) , 0 , nNumRanges - 1 , bucket + 1 ) ) ;
}
else
{
// Use even distribution
e . m_min_lum = float ( bucket ) / float ( nNumRanges - 1 ) ;
e . m_max_lum = float ( bucket + 1 ) / float ( nNumRanges - 1 ) ;
// Use a distribution with slightly more bins in the low range
e . m_min_lum = e . m_min_lum > 0.0f ? powf ( e . m_min_lum , 1.5f ) : e . m_min_lum ;
e . m_max_lum = e . m_max_lum > 0.0f ? powf ( e . m_max_lum , 1.5f ) : e . m_max_lum ;
}
}
else
{
// The last bucket is used as a test to determine the return range for occlusion
// queries to use as a scale factor. some boards (nvidia) have their occlusion
// query return values larger when using AA.
e . m_min_lum = 0 ;
e . m_max_lum = 100000.0 ;
}
//Warning( "Bucket %d: min/max %f / %f ", bucket, e.m_min_lum, e.m_max_lum );
}
}
void CLuminanceHistogramSystem : : DisplayHistogram ( void )
{
bool bDrawTextThisFrame = true ;
if ( IsX360 ( ) )
{
static float s_flLastTimeUpdate = 0.0f ;
if ( int ( gpGlobals - > curtime ) - int ( s_flLastTimeUpdate ) > = 2 )
{
s_flLastTimeUpdate = gpGlobals - > curtime ;
bDrawTextThisFrame = true ;
}
else
{
bDrawTextThisFrame = false ;
}
}
CMatRenderContextPtr pRenderContext ( materials ) ;
pRenderContext - > PushRenderTargetAndViewport ( ) ;
int nNumRanges = N_LUMINANCE_RANGES - 1 ;
if ( mat_tonemap_algorithm . GetInt ( ) = = 1 )
nNumRanges = N_LUMINANCE_RANGES_NEW - 1 ;
int nMaxValidPixels = 0 ;
int nTotalValidPixels = 0 ;
int nTotalGraphPixelsWide = 0 ;
for ( int l = 0 ; l < nNumRanges ; l + + )
{
CHistogram_entry_t & e = CurHistogram [ l ] ;
if ( e . ContainsValidData ( ) )
{
nTotalValidPixels + = e . m_npixels_in_range ;
if ( e . m_npixels_in_range > nMaxValidPixels )
{
nMaxValidPixels = e . m_npixels_in_range ;
}
}
int width = MAX ( 1 , 500 * ( e . m_max_lum - e . m_min_lum ) ) ;
nTotalGraphPixelsWide + = width + 2 ;
}
int xl , yl , dest_width , dest_height ;
pRenderContext - > GetViewport ( xl , yl , dest_width , dest_height ) ;
if ( bDrawTextThisFrame = = true )
{
engine - > Con_NPrintf ( 17 , " (All values in linear space) " ) ;
engine - > Con_NPrintf ( 21 , " AvgLum @ %4.2f%% mat_tonemap_min_avglum = %4.2f%% Using %d pixels of %d pixels on screen (%3d%%) " ,
MAX ( 0.0f , FindLocationOfPercentBrightPixels ( 50.0f ) ) * 100.0f , mat_tonemap_min_avglum . GetFloat ( ) ,
nTotalValidPixels , ( dest_width * dest_height ) , int ( float ( nTotalValidPixels ) * 100.0f / float ( dest_width * dest_height ) ) ) ;
engine - > Con_NPrintf ( 23 , " BloomScale = %4.2f mat_hdr_manual_tonemap_rate = %4.2f mat_accelerate_adjust_exposure_down = %4.2f " ,
GetCurrentBloomScale ( ) , mat_hdr_manual_tonemap_rate . GetFloat ( ) , mat_accelerate_adjust_exposure_down . GetFloat ( ) ) ;
}
if ( mat_tonemap_algorithm . GetInt ( ) = = 1 ) // New algorithm only
{
float vTotalPixelsAndHigher [ N_LUMINANCE_RANGES ] ;
for ( int i = 0 ; i < nNumRanges ; i + + )
{
vTotalPixelsAndHigher [ i ] = CurHistogram [ nNumRanges - 1 - i ] . m_npixels_in_range ;
if ( i > 0 )
{
vTotalPixelsAndHigher [ i ] + = vTotalPixelsAndHigher [ i - 1 ] ;
}
}
/* // This code works when N_LUMINANCE_RANGES_NEW = 11
if ( bDrawTextThisFrame = = true )
{
engine - > Con_NPrintf ( 17 , " %04.2f %04.2f %04.2f %04.2f %04.2f %04.2f %04.2f %04.2f %04.2f %04.2f " ,
100.0f * float ( vTotalPixelsAndHigher [ 9 ] ) / float ( nTotalValidPixels ) ,
100.0f * float ( vTotalPixelsAndHigher [ 8 ] ) / float ( nTotalValidPixels ) ,
100.0f * float ( vTotalPixelsAndHigher [ 7 ] ) / float ( nTotalValidPixels ) ,
100.0f * float ( vTotalPixelsAndHigher [ 6 ] ) / float ( nTotalValidPixels ) ,
100.0f * float ( vTotalPixelsAndHigher [ 5 ] ) / float ( nTotalValidPixels ) ,
100.0f * float ( vTotalPixelsAndHigher [ 4 ] ) / float ( nTotalValidPixels ) ,
100.0f * float ( vTotalPixelsAndHigher [ 3 ] ) / float ( nTotalValidPixels ) ,
100.0f * float ( vTotalPixelsAndHigher [ 2 ] ) / float ( nTotalValidPixels ) ,
100.0f * float ( vTotalPixelsAndHigher [ 1 ] ) / float ( nTotalValidPixels ) ,
100.0f * float ( vTotalPixelsAndHigher [ 0 ] ) / float ( nTotalValidPixels ) ) ;
engine - > Con_NPrintf ( 15 , " %04.2f %04.2f %04.2f %04.2f %04.2f %04.2f %04.2f %04.2f %04.2f %04.2f " ,
100.0f * float ( CurHistogram [ nNumRanges - 1 - 9 ] . m_npixels_in_range ) / float ( nTotalValidPixels ) ,
100.0f * float ( CurHistogram [ nNumRanges - 1 - 8 ] . m_npixels_in_range ) / float ( nTotalValidPixels ) ,
100.0f * float ( CurHistogram [ nNumRanges - 1 - 7 ] . m_npixels_in_range ) / float ( nTotalValidPixels ) ,
100.0f * float ( CurHistogram [ nNumRanges - 1 - 6 ] . m_npixels_in_range ) / float ( nTotalValidPixels ) ,
100.0f * float ( CurHistogram [ nNumRanges - 1 - 5 ] . m_npixels_in_range ) / float ( nTotalValidPixels ) ,
100.0f * float ( CurHistogram [ nNumRanges - 1 - 4 ] . m_npixels_in_range ) / float ( nTotalValidPixels ) ,
100.0f * float ( CurHistogram [ nNumRanges - 1 - 3 ] . m_npixels_in_range ) / float ( nTotalValidPixels ) ,
100.0f * float ( CurHistogram [ nNumRanges - 1 - 2 ] . m_npixels_in_range ) / float ( nTotalValidPixels ) ,
100.0f * float ( CurHistogram [ nNumRanges - 1 - 1 ] . m_npixels_in_range ) / float ( nTotalValidPixels ) ,
100.0f * float ( CurHistogram [ nNumRanges - 1 - 0 ] . m_npixels_in_range ) / float ( nTotalValidPixels ) ) ;
}
//*/
}
else
{
if ( bDrawTextThisFrame = = true )
{
engine - > Con_NPrintf ( 17 , " " ) ;
engine - > Con_NPrintf ( 15 , " " ) ;
}
}
int xpStart = dest_width - nTotalGraphPixelsWide - 10 ;
if ( IsX360 ( ) )
{
xpStart - = 50 ;
}
int xp = xpStart ;
for ( int l = 0 ; l < nNumRanges ; l + + )
{
int np = 0 ;
CHistogram_entry_t & e = CurHistogram [ l ] ;
if ( e . ContainsValidData ( ) )
np + = e . m_npixels_in_range ;
int width = MAX ( 1 , 500 * ( e . m_max_lum - e . m_min_lum ) ) ;
//Warning( "Bucket %d: min/max %f / %f. m_npixels_in_range=%d m_npixels=%d\n", l, e.m_min_lum, e.m_max_lum, e.m_npixels_in_range, e.m_npixels );
if ( np )
{
int height = MAX ( 1 , MIN ( HISTOGRAM_BAR_SIZE , ( ( float ) np / ( float ) nMaxValidPixels ) * HISTOGRAM_BAR_SIZE ) ) ;
pRenderContext - > ClearColor3ub ( 255 , 0 , 0 ) ;
pRenderContext - > Viewport ( xp , 4 + HISTOGRAM_BAR_SIZE - height , width , height ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
}
else
{
int height = 1 ;
pRenderContext - > ClearColor3ub ( 0 , 0 , 255 ) ;
pRenderContext - > Viewport ( xp , 4 + HISTOGRAM_BAR_SIZE - height , width , height ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
}
xp + = width + 2 ;
}
if ( mat_tonemap_algorithm . GetInt ( ) = = 1 ) // New algorithm only
{
float flYellowTargetPixelStart = ( xpStart + ( float ( nTotalGraphPixelsWide ) * mat_tonemap_percent_target . GetFloat ( ) / 100.0f ) ) ;
float flYellowAveragePixelStart = ( xpStart + ( float ( nTotalGraphPixelsWide ) * mat_tonemap_min_avglum . GetFloat ( ) / 100.0f ) ) ;
float flTargetPixelStart = ( xpStart + ( float ( nTotalGraphPixelsWide ) * FindLocationOfPercentBrightPixels ( mat_tonemap_percent_bright_pixels . GetFloat ( ) , mat_tonemap_percent_target . GetFloat ( ) ) ) ) ;
float flAveragePixelStart = ( xpStart + ( float ( nTotalGraphPixelsWide ) * FindLocationOfPercentBrightPixels ( 50.0f ) ) ) ;
// Draw target yellow border bar
int height = HISTOGRAM_BAR_SIZE ;
// Green is current percent target location
pRenderContext - > Viewport ( flYellowTargetPixelStart , 4 + HISTOGRAM_BAR_SIZE - height , 4 , height ) ;
pRenderContext - > ClearColor3ub ( 200 , 200 , 0 ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
pRenderContext - > Viewport ( flTargetPixelStart , 4 + HISTOGRAM_BAR_SIZE - height , 4 , height ) ;
pRenderContext - > ClearColor3ub ( 0 , 255 , 0 ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
// Blue is average luminance location
pRenderContext - > Viewport ( flYellowAveragePixelStart , 4 + HISTOGRAM_BAR_SIZE - height , 4 , height ) ;
pRenderContext - > ClearColor3ub ( 200 , 200 , 0 ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
pRenderContext - > Viewport ( flAveragePixelStart , 4 + HISTOGRAM_BAR_SIZE - height , 4 , height ) ;
pRenderContext - > ClearColor3ub ( 0 , 200 , 200 ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
}
// Show actual tonemap value
if ( 1 )
{
float flAutoExposureMin ;
float flAutoExposureMax ;
GetExposureRange ( & flAutoExposureMin , & flAutoExposureMax ) ;
float flBarWidth = 600.0f ;
float flBarStart = dest_width - flBarWidth - 10.0f ;
if ( IsX360 ( ) )
{
flBarStart - = 50 ;
}
pRenderContext - > Viewport ( flBarStart , 4 + HISTOGRAM_BAR_SIZE - 4 + 75 , flBarWidth , 4 ) ;
pRenderContext - > ClearColor3ub ( 200 , 200 , 200 ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
pRenderContext - > Viewport ( flBarStart , 4 + HISTOGRAM_BAR_SIZE - 4 + 75 + 1 , flBarWidth , 2 ) ;
pRenderContext - > ClearColor3ub ( 0 , 0 , 0 ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
pRenderContext - > Viewport ( flBarStart + ( flBarWidth * ( ( pRenderContext - > GetToneMappingScaleLinear ( ) . x - flAutoExposureMin ) / ( flAutoExposureMax - flAutoExposureMin ) ) ) ,
4 + HISTOGRAM_BAR_SIZE - 4 + 75 - 6 , 4 , 16 ) ;
pRenderContext - > ClearColor3ub ( 255 , 0 , 0 ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
if ( bDrawTextThisFrame = = true )
{
if ( IsX360 ( ) )
engine - > Con_NPrintf ( 26 , " Min: %.2f Max: %.2f " , flAutoExposureMin , flAutoExposureMax ) ;
else
engine - > Con_NPrintf ( 26 , " %.2f %.2f %.2f " , flAutoExposureMin , ( flAutoExposureMax + flAutoExposureMin ) / 2.0f , flAutoExposureMax ) ;
}
}
// Last bar doesn't clear properly so draw an extra pixel
pRenderContext - > Viewport ( 0 , 0 , 1 , 1 ) ;
pRenderContext - > ClearColor3ub ( 0 , 0 , 0 ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
pRenderContext - > PopRenderTargetAndViewport ( ) ;
}
static CLuminanceHistogramSystem g_HDR_HistogramSystem ;
static float s_MovingAverageToneMapScale [ 10 ] = { 1.0f , 1.0f , 1.0f , 1.0f , 1.0f , 1.0f , 1.0f , 1.0f , 1.0f , 1.0f } ;
static int s_nInAverage = 0 ;
void ResetToneMapping ( float value )
{
CMatRenderContextPtr pRenderContext ( materials ) ;
s_nInAverage = 0 ;
pRenderContext - > ResetToneMappingScale ( value ) ;
}
static ConVar mat_force_tonemap_scale ( " mat_force_tonemap_scale " , " 0.0 " , FCVAR_CHEAT ) ;
static void SetToneMapScale ( IMatRenderContext * pRenderContext , float newvalue , float minvalue , float maxvalue )
{
Assert ( IsFinite ( newvalue ) ) ;
if ( ! IsFinite ( newvalue ) )
return ;
float flForcedTonemapScale = mat_force_tonemap_scale . GetFloat ( ) ;
if ( mat_fullbright . GetInt ( ) = = 1 )
{
flForcedTonemapScale = 1.0f ;
}
if ( flForcedTonemapScale > 0.0f )
{
mat_hdr_tonemapscale . SetValue ( flForcedTonemapScale ) ;
pRenderContext - > ResetToneMappingScale ( flForcedTonemapScale ) ;
return ;
}
mat_hdr_tonemapscale . SetValue ( newvalue ) ;
pRenderContext - > SetGoalToneMappingScale ( newvalue ) ;
if ( s_nInAverage < ARRAYSIZE ( s_MovingAverageToneMapScale ) )
{
s_MovingAverageToneMapScale [ s_nInAverage + + ] = newvalue ;
}
else
{
// scroll, losing oldest
for ( int i = 0 ; i < ARRAYSIZE ( s_MovingAverageToneMapScale ) - 1 ; i + + )
s_MovingAverageToneMapScale [ i ] = s_MovingAverageToneMapScale [ i + 1 ] ;
s_MovingAverageToneMapScale [ ARRAYSIZE ( s_MovingAverageToneMapScale ) - 1 ] = newvalue ;
}
// now, use the average of the last tonemap calculations as our goal scale
if ( s_nInAverage = = ARRAYSIZE ( s_MovingAverageToneMapScale ) ) // got full buffer yet?
{
float avg = 0. ;
float sumweights = 0 ;
int sample_pt = ARRAYSIZE ( s_MovingAverageToneMapScale ) / 2 ;
for ( int i = 0 ; i < ARRAYSIZE ( s_MovingAverageToneMapScale ) ; i + + )
{
float weight = abs ( i - sample_pt ) * ( 1.0 / ( ARRAYSIZE ( s_MovingAverageToneMapScale ) / 2 ) ) ;
sumweights + = weight ;
avg + = weight * s_MovingAverageToneMapScale [ i ] ;
}
avg * = ( 1.0 / sumweights ) ;
avg = MIN ( maxvalue , MAX ( minvalue , avg ) ) ;
pRenderContext - > SetGoalToneMappingScale ( avg ) ;
mat_hdr_tonemapscale . SetValue ( avg ) ;
}
}
//=====================================================================================================================
// Engine_Post material proxy ============================================================================================
//=====================================================================================================================
static ConVar mat_software_aa_strength ( " mat_software_aa_strength " , " -1.0 " , FCVAR_ARCHIVE , " Software AA - perform a software anti-aliasing post-process (an alternative/supplement to MSAA) . This value sets the strength of the effect : ( 0.0 - off ) , ( 1.0 - full ) " ) ;
static ConVar mat_software_aa_quality ( " mat_software_aa_quality " , " 0 " , FCVAR_ARCHIVE , " Software AA quality mode: (0 - 5-tap filter) , ( 1 - 9 - tap filter ) " ) ;
static ConVar mat_software_aa_edge_threshold ( " mat_software_aa_edge_threshold " , " 1.0 " , FCVAR_ARCHIVE , " Software AA - adjusts the sensitivity of the software AA shader's edge detection (default 1.0 - a lower value will soften more edges, a higher value will soften fewer) " ) ;
static ConVar mat_software_aa_blur_one_pixel_lines ( " mat_software_aa_blur_one_pixel_lines " , " 0.5 " , FCVAR_ARCHIVE , " How much software AA should blur one-pixel thick lines: (0.0 - none) , ( 1.0 - lots ) " ) ;
static ConVar mat_software_aa_tap_offset ( " mat_software_aa_tap_offset " , " 1.0 " , FCVAR_ARCHIVE , " Software AA - adjusts the displacement of the taps used by the software AA shader (default 1.0 - a lower value will make the image sharper, higher will make it blurrier) " ) ;
static ConVar mat_software_aa_debug ( " mat_software_aa_debug " , " 0 " , FCVAR_NONE , " Software AA debug mode: (0 - off) , ( 1 - show number of ' unlike ' samples : 0 - > black , 1 - > red , 2 - > green , 3 - > blue ) , ( 2 - show anti - alias blend strength ) , ( 3 - show averaged ' unlike ' colour ) " ) ;
static ConVar mat_software_aa_strength_vgui ( " mat_software_aa_strength_vgui " , " -1.0 " , FCVAR_ARCHIVE , " Same as mat_software_aa_strength, but forced to this value when called by the post vgui AA pass. " ) ;
class CEnginePostMaterialProxy : public CEntityMaterialProxy
{
public :
CEnginePostMaterialProxy ( ) ;
virtual ~ CEnginePostMaterialProxy ( ) ;
virtual bool Init ( IMaterial * pMaterial , KeyValues * pKeyValues ) ;
virtual void OnBind ( C_BaseEntity * pEntity ) ;
virtual IMaterial * GetMaterial ( ) ;
private :
IMaterialVar * m_pMaterialParam_AAValues ;
IMaterialVar * m_pMaterialParam_AAValues2 ;
IMaterialVar * m_pMaterialParam_BloomEnable ;
IMaterialVar * m_pMaterialParam_BloomUVTransform ;
IMaterialVar * m_pMaterialParam_ColCorrectEnable ;
IMaterialVar * m_pMaterialParam_ColCorrectNumLookups ;
IMaterialVar * m_pMaterialParam_ColCorrectDefaultWeight ;
IMaterialVar * m_pMaterialParam_ColCorrectLookupWeights ;
public :
static IMaterial * SetupEnginePostMaterial ( const Vector4D & fullViewportBloomUVs , const Vector4D & fullViewportFBUVs , const Vector2D & destTexSize ,
bool bPerformSoftwareAA , bool bPerformBloom , bool bPerformColCorrect , float flAAStrength ) ;
static void SetupEnginePostMaterialAA ( bool bPerformSoftwareAA , float flAAStrength ) ;
static void SetupEnginePostMaterialTextureTransform ( const Vector4D & fullViewportBloomUVs , const Vector4D & fullViewportFBUVs , Vector2D destTexSize ) ;
private :
static float s_vBloomAAValues [ 4 ] ;
static float s_vBloomAAValues2 [ 4 ] ;
static float s_vBloomUVTransform [ 4 ] ;
static int s_PostBloomEnable ;
} ;
float CEnginePostMaterialProxy : : s_vBloomAAValues [ 4 ] = { 0.0f , 0.0f , 0.0f , 0.0f } ;
float CEnginePostMaterialProxy : : s_vBloomAAValues2 [ 4 ] = { 0.0f , 0.0f , 0.0f , 0.0f } ;
float CEnginePostMaterialProxy : : s_vBloomUVTransform [ 4 ] = { 0.0f , 0.0f , 0.0f , 0.0f } ;
int CEnginePostMaterialProxy : : s_PostBloomEnable = 1 ;
CEnginePostMaterialProxy : : CEnginePostMaterialProxy ( )
{
m_pMaterialParam_AAValues = NULL ;
m_pMaterialParam_AAValues2 = NULL ;
m_pMaterialParam_BloomUVTransform = NULL ;
m_pMaterialParam_BloomEnable = NULL ;
m_pMaterialParam_ColCorrectEnable = NULL ;
m_pMaterialParam_ColCorrectNumLookups = NULL ;
m_pMaterialParam_ColCorrectDefaultWeight = NULL ;
m_pMaterialParam_ColCorrectLookupWeights = NULL ;
}
CEnginePostMaterialProxy : : ~ CEnginePostMaterialProxy ( )
{
// Do nothing
}
bool CEnginePostMaterialProxy : : Init ( IMaterial * pMaterial , KeyValues * pKeyValues )
{
bool bFoundVar = false ;
m_pMaterialParam_AAValues = pMaterial - > FindVar ( " $AAInternal1 " , & bFoundVar , false ) ;
m_pMaterialParam_AAValues2 = pMaterial - > FindVar ( " $AAInternal3 " , & bFoundVar , false ) ;
m_pMaterialParam_BloomUVTransform = pMaterial - > FindVar ( " $AAInternal2 " , & bFoundVar , false ) ;
m_pMaterialParam_BloomEnable = pMaterial - > FindVar ( " $bloomEnable " , & bFoundVar , false ) ;
m_pMaterialParam_ColCorrectEnable = pMaterial - > FindVar ( " $colCorrectEnable " , & bFoundVar , false ) ;
m_pMaterialParam_ColCorrectNumLookups = pMaterial - > FindVar ( " $colCorrect_NumLookups " , & bFoundVar , false ) ;
m_pMaterialParam_ColCorrectDefaultWeight = pMaterial - > FindVar ( " $colCorrect_DefaultWeight " , & bFoundVar , false ) ;
m_pMaterialParam_ColCorrectLookupWeights = pMaterial - > FindVar ( " $colCorrect_LookupWeights " , & bFoundVar , false ) ;
return true ;
}
void CEnginePostMaterialProxy : : OnBind ( C_BaseEntity * pEnt )
{
if ( m_pMaterialParam_AAValues )
m_pMaterialParam_AAValues - > SetVecValue ( s_vBloomAAValues , 4 ) ;
if ( m_pMaterialParam_AAValues2 )
m_pMaterialParam_AAValues2 - > SetVecValue ( s_vBloomAAValues2 , 4 ) ;
if ( m_pMaterialParam_BloomUVTransform )
m_pMaterialParam_BloomUVTransform - > SetVecValue ( s_vBloomUVTransform , 4 ) ;
if ( m_pMaterialParam_BloomEnable )
m_pMaterialParam_BloomEnable - > SetIntValue ( s_PostBloomEnable ) ;
}
IMaterial * CEnginePostMaterialProxy : : GetMaterial ( )
{
if ( m_pMaterialParam_AAValues = = NULL )
return NULL ;
return m_pMaterialParam_AAValues - > GetOwningMaterial ( ) ;
}
void CEnginePostMaterialProxy : : SetupEnginePostMaterialAA ( bool bPerformSoftwareAA , float flAAStrength )
{
if ( bPerformSoftwareAA )
{
// Pass ConVars to the material by proxy
// - the strength of the AA effect (from 0 to 1)
// - how much to allow 1-pixel lines to be blurred (from 0 to 1)
// - pick one of the two quality modes (5-tap or 9-tap filter)
// - optionally enable one of several debug modes (via dynamic combos)
// NOTE: this order matches pixel shader constants in Engine_Post_ps2x.fxc
s_vBloomAAValues [ 0 ] = flAAStrength ;
s_vBloomAAValues [ 1 ] = 1.0f - mat_software_aa_blur_one_pixel_lines . GetFloat ( ) ;
s_vBloomAAValues [ 2 ] = mat_software_aa_quality . GetInt ( ) ;
s_vBloomAAValues [ 3 ] = mat_software_aa_debug . GetInt ( ) ;
s_vBloomAAValues2 [ 0 ] = mat_software_aa_edge_threshold . GetFloat ( ) ;
s_vBloomAAValues2 [ 1 ] = mat_software_aa_tap_offset . GetFloat ( ) ;
//s_vBloomAAValues2[2] = unused;
//s_vBloomAAValues2[3] = unused;
}
else
{
// Zero-strength AA is interpreted as "AA disabled"
s_vBloomAAValues [ 0 ] = 0.0f ;
}
}
void CEnginePostMaterialProxy : : SetupEnginePostMaterialTextureTransform ( const Vector4D & fullViewportBloomUVs , const Vector4D & fullViewportFBUVs , Vector2D fbSize )
{
// Engine_Post uses a UV transform (from (quarter-res) bloom texture coords ('1')
// to (full-res) framebuffer texture coords ('2')).
//
// We compute the UV transform as an offset and a scale, using the texture coordinates
// of the top-left corner of the screen to compute the offset and the coordinate
// change from the top-left to the bottom-right of the quad to compute the scale.
// Take texel coordinates (start = top-left, end = bottom-right):
Vector2D texelStart1 = Vector2D ( fullViewportBloomUVs . x , fullViewportBloomUVs . y ) ;
Vector2D texelStart2 = Vector2D ( fullViewportFBUVs . x , fullViewportFBUVs . y ) ;
Vector2D texelEnd1 = Vector2D ( fullViewportBloomUVs . z , fullViewportBloomUVs . w ) ;
Vector2D texelEnd2 = Vector2D ( fullViewportFBUVs . z , fullViewportFBUVs . w ) ;
// ...and transform to UV coordinates:
Vector2D texRes1 = fbSize / 4 ;
Vector2D texRes2 = fbSize ;
Vector2D uvStart1 = ( texelStart1 + Vector2D ( 0.5 , 0.5 ) ) / texRes1 ;
Vector2D uvStart2 = ( texelStart2 + Vector2D ( 0.5 , 0.5 ) ) / texRes2 ;
Vector2D dUV1 = ( texelEnd1 - texelStart1 ) / texRes1 ;
Vector2D dUV2 = ( texelEnd2 - texelStart2 ) / texRes2 ;
// We scale about the rect's top-left pixel centre (not the origin) in UV-space:
// uv' = ((uv - uvStart1)*uvScale + uvStart1) + uvOffset
// = uvScale*uv + uvOffset + uvStart1*(1 - uvScale)
Vector2D uvOffset = uvStart2 - uvStart1 ;
Vector2D uvScale = dUV2 / dUV1 ;
uvOffset = uvOffset + uvStart1 * ( Vector2D ( 1 , 1 ) - uvScale ) ;
s_vBloomUVTransform [ 0 ] = uvOffset . x ;
s_vBloomUVTransform [ 1 ] = uvOffset . y ;
s_vBloomUVTransform [ 2 ] = uvScale . x ;
s_vBloomUVTransform [ 3 ] = uvScale . y ;
}
IMaterial * CEnginePostMaterialProxy : : SetupEnginePostMaterial ( const Vector4D & fullViewportBloomUVs , const Vector4D & fullViewportFBUVs , const Vector2D & destTexSize ,
bool bPerformSoftwareAA , bool bPerformBloom , bool bPerformColCorrect , float flAAStrength )
{
// Shouldn't get here if none of the effects are enabled
Assert ( bPerformSoftwareAA | | bPerformBloom | | bPerformColCorrect ) ;
s_PostBloomEnable = bPerformBloom ? 1 : 0 ;
SetupEnginePostMaterialAA ( bPerformSoftwareAA , flAAStrength ) ;
if ( bPerformSoftwareAA | | bPerformColCorrect )
{
SetupEnginePostMaterialTextureTransform ( fullViewportBloomUVs , fullViewportFBUVs , destTexSize ) ;
return materials - > FindMaterial ( " dev/engine_post " , TEXTURE_GROUP_OTHER , true ) ;
}
else
{
// Just use the old bloomadd material (which uses additive blending, unlike engine_post)
// NOTE: this path is what gets used for DX8 (which cannot enable AA or col-correction)
return materials - > FindMaterial ( " dev/bloomadd " , TEXTURE_GROUP_OTHER , true ) ;
}
}
EXPOSE_INTERFACE ( CEnginePostMaterialProxy , IMaterialProxy , " engine_post " IMATERIAL_PROXY_INTERFACE_VERSION ) ;
static void DrawBloomDebugBoxes ( IMatRenderContext * pRenderContext )
{
// draw inset rects which should have a centered bloom
pRenderContext - > SetRenderTarget ( NULL ) ;
int dest_width , dest_height ;
pRenderContext - > GetRenderTargetDimensions ( dest_width , dest_height ) ;
// full screen clear
pRenderContext - > Viewport ( 0 , 0 , dest_width , dest_height ) ;
pRenderContext - > ClearColor3ub ( 0 , 0 , 0 ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
// inset for screensafe
int inset = 64 ;
int size = 32 ;
// centerish, translating
static int wx = 0 ;
wx = ( wx + 1 ) & 63 ;
pRenderContext - > Viewport ( dest_width / 2 + wx , dest_height / 2 , size , size ) ;
pRenderContext - > ClearColor3ub ( 255 , 255 , 255 ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
// upper left
pRenderContext - > Viewport ( inset , inset , size , size ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
// upper right
pRenderContext - > Viewport ( dest_width - inset - size , inset , size , size ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
// lower right
pRenderContext - > Viewport ( dest_width - inset - size , dest_height - inset - size , size , size ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
// lower left
pRenderContext - > Viewport ( inset , dest_height - inset - size , size , size ) ;
pRenderContext - > ClearBuffers ( true , true ) ;
// restore
pRenderContext - > Viewport ( 0 , 0 , dest_width , dest_height ) ;
}
static float GetBloomAmount ( void )
{
// return bloom amount ( 0.0 if disabled or otherwise turned off )
if ( engine - > GetDXSupportLevel ( ) < 80 )
return 0.0 ;
HDRType_t hdrType = g_pMaterialSystemHardwareConfig - > GetHDRType ( ) ;
bool bBloomEnabled = ( mat_hdr_level . GetInt ( ) > = 1 ) ;
if ( ! engine - > MapHasHDRLighting ( ) )
bBloomEnabled = false ;
if ( mat_force_bloom . GetInt ( ) )
bBloomEnabled = true ;
if ( mat_disable_bloom . GetInt ( ) )
bBloomEnabled = false ;
if ( building_cubemaps . GetBool ( ) )
bBloomEnabled = false ;
if ( mat_fullbright . GetInt ( ) = = 1 )
{
bBloomEnabled = false ;
}
if ( ! g_pMaterialSystemHardwareConfig - > CanDoSRGBReadFromRTs ( ) & & g_pMaterialSystemHardwareConfig - > FakeSRGBWrite ( ) )
{
bBloomEnabled = false ;
}
float flBloomAmount = 0.0 ;
if ( bBloomEnabled )
{
static float currentBloomAmount = 1.0f ;
float rate = mat_bloomamount_rate . GetFloat ( ) ;
// Use the appropriate bloom scale settings. Mapmakers's overrides the convar settings.
currentBloomAmount = GetCurrentBloomScale ( ) * rate + ( 1.0f - rate ) * currentBloomAmount ;
flBloomAmount = currentBloomAmount ;
}
if ( hdrType = = HDR_TYPE_NONE )
{
flBloomAmount * = mat_non_hdr_bloom_scalefactor . GetFloat ( ) / 2.f ;
}
flBloomAmount * = mat_bloom_scalefactor_scalar . GetFloat ( ) ;
return flBloomAmount ;
}
// Control for dumping render targets to files for debugging
static ConVar mat_dump_rts ( " mat_dump_rts " , " 0 " ) ;
static int s_nRTIndex = 0 ;
bool g_bDumpRenderTargets = false ;
// Dump a rendertarget to a TGA. Useful for looking at intermediate render target results.
void DumpTGAofRenderTarget ( const int width , const int height , const char * pFilename )
{
// Ensure that mat_queue_mode is zero
static ConVarRef mat_queue_mode ( " mat_queue_mode " ) ;
if ( mat_queue_mode . GetInt ( ) ! = 0 )
{
DevMsg ( " Error: mat_queue_mode must be 0 to dump debug rendertargets \n " ) ;
mat_dump_rts . SetValue ( 0 ) ; // Just report this error once and stop trying to dump images
return ;
}
CMatRenderContextPtr pRenderContext ( materials ) ;
// Get the data from the render target and save to disk bitmap bits
unsigned char * pImage = ( unsigned char * ) malloc ( width * 4 * height ) ;
// Get Bits from the material system
pRenderContext - > ReadPixels ( 0 , 0 , width , height , pImage , IMAGE_FORMAT_RGBA8888 ) ;
// allocate a buffer to write the tga into
int iMaxTGASize = 1024 + ( width * height * 4 ) ;
void * pTGA = malloc ( iMaxTGASize ) ;
CUtlBuffer buffer ( pTGA , iMaxTGASize ) ;
if ( ! TGAWriter : : WriteToBuffer ( pImage , buffer , width , height , IMAGE_FORMAT_RGBA8888 , IMAGE_FORMAT_RGBA8888 ) )
{
Error ( " Couldn't write bitmap data snapshot. \n " ) ;
}
free ( pImage ) ;
// async write to disk (this will take ownership of the memory)
char szPathedFileName [ _MAX_PATH ] ;
Q_snprintf ( szPathedFileName , sizeof ( szPathedFileName ) , " //MOD/%d_%s_%s.tga " , s_nRTIndex + + , pFilename , IsOSX ( ) ? " OSX " : " PC " ) ;
FileHandle_t fileTGA = filesystem - > Open ( szPathedFileName , " wb " ) ;
filesystem - > Write ( buffer . Base ( ) , buffer . TellPut ( ) , fileTGA ) ;
filesystem - > Close ( fileTGA ) ;
free ( pTGA ) ;
}
static bool s_bScreenEffectTextureIsUpdated = false ;
static void Generate8BitBloomTexture ( IMatRenderContext * pRenderContext , float flBloomScale ,
int x , int y , int w , int h )
{
tmZone ( TELEMETRY_LEVEL0 , TMZF_NONE , " %s " , __FUNCTION__ ) ;
pRenderContext - > PushRenderTargetAndViewport ( ) ;
ITexture * pSrc = materials - > FindTexture ( " _rt_FullFrameFB " , TEXTURE_GROUP_RENDER_TARGET ) ;
int nSrcWidth = pSrc - > GetActualWidth ( ) ;
int nSrcHeight = pSrc - > GetActualHeight ( ) ; //,dest_height;
// Counter-Strike: Source uses a different downsample algorithm than other games
# ifdef CSTRIKE_DLL
IMaterial * downsample_mat = materials - > FindMaterial ( " dev/downsample_non_hdr_cstrike " , TEXTURE_GROUP_OTHER , true ) ;
# else
IMaterial * downsample_mat = materials - > FindMaterial ( " dev/downsample_non_hdr " , TEXTURE_GROUP_OTHER , true ) ;
# endif
IMaterial * xblur_mat = materials - > FindMaterial ( " dev/blurfilterx_nohdr " , TEXTURE_GROUP_OTHER , true ) ;
IMaterial * yblur_mat = materials - > FindMaterial ( " dev/blurfiltery_nohdr " , TEXTURE_GROUP_OTHER , true ) ;
ITexture * dest_rt0 = materials - > FindTexture ( " _rt_SmallFB0 " , TEXTURE_GROUP_RENDER_TARGET ) ;
ITexture * dest_rt1 = materials - > FindTexture ( " _rt_SmallFB1 " , TEXTURE_GROUP_RENDER_TARGET ) ;
// *Everything* in here relies on the small RTs being exactly 1/4 the full FB res
Assert ( dest_rt0 - > GetActualWidth ( ) = = pSrc - > GetActualWidth ( ) / 4 ) ;
Assert ( dest_rt0 - > GetActualHeight ( ) = = pSrc - > GetActualHeight ( ) / 4 ) ;
Assert ( dest_rt1 - > GetActualWidth ( ) = = pSrc - > GetActualWidth ( ) / 4 ) ;
Assert ( dest_rt1 - > GetActualHeight ( ) = = pSrc - > GetActualHeight ( ) / 4 ) ;
// Downsample fb to rt0
SetRenderTargetAndViewPort ( dest_rt0 ) ;
// note the -2's below. Thats because we are downsampling on each axis and the shader
// accesses pixels on both sides of the source coord
pRenderContext - > DrawScreenSpaceRectangle ( downsample_mat , 0 , 0 , nSrcWidth / 4 , nSrcHeight / 4 ,
0 , 0 , nSrcWidth - 2 , nSrcHeight - 2 ,
nSrcWidth , nSrcHeight ) ;
if ( IsX360 ( ) )
{
pRenderContext - > CopyRenderTargetToTextureEx ( dest_rt0 , 0 , NULL , NULL ) ;
}
else if ( g_bDumpRenderTargets )
{
DumpTGAofRenderTarget ( nSrcWidth / 4 , nSrcHeight / 4 , " QuarterSizeFB " ) ;
}
// Gaussian blur x rt0 to rt1
SetRenderTargetAndViewPort ( dest_rt1 ) ;
pRenderContext - > DrawScreenSpaceRectangle ( xblur_mat , 0 , 0 , nSrcWidth / 4 , nSrcHeight / 4 ,
0 , 0 , nSrcWidth / 4 - 1 , nSrcHeight / 4 - 1 ,
nSrcWidth / 4 , nSrcHeight / 4 ) ;
if ( IsX360 ( ) )
{
pRenderContext - > CopyRenderTargetToTextureEx ( dest_rt1 , 0 , NULL , NULL ) ;
}
else if ( g_bDumpRenderTargets )
{
DumpTGAofRenderTarget ( nSrcWidth / 4 , nSrcHeight / 4 , " BlurX " ) ;
}
// Gaussian blur y rt1 to rt0
SetRenderTargetAndViewPort ( dest_rt0 ) ;
IMaterialVar * pBloomAmountVar = yblur_mat - > FindVar ( " $bloomamount " , NULL ) ;
pBloomAmountVar - > SetFloatValue ( flBloomScale ) ;
pRenderContext - > DrawScreenSpaceRectangle ( yblur_mat , 0 , 0 , nSrcWidth / 4 , nSrcHeight / 4 ,
0 , 0 , nSrcWidth / 4 - 1 , nSrcHeight / 4 - 1 ,
nSrcWidth / 4 , nSrcHeight / 4 ) ;
if ( IsX360 ( ) )
{
pRenderContext - > CopyRenderTargetToTextureEx ( dest_rt0 , 0 , NULL , NULL ) ;
}
else if ( g_bDumpRenderTargets )
{
DumpTGAofRenderTarget ( nSrcWidth / 4 , nSrcHeight / 4 , " BlurYAndBloom " ) ;
}
pRenderContext - > PopRenderTargetAndViewport ( ) ;
}
static void DoPreBloomTonemapping ( IMatRenderContext * pRenderContext , int nX , int nY , int nWidth , int nHeight , float flAutoExposureMin , float flAutoExposureMax )
{
// Update HDR histogram before bloom
if ( mat_dynamic_tonemapping . GetInt ( ) | | mat_show_histogram . GetInt ( ) )
{
tmZone ( TELEMETRY_LEVEL0 , TMZF_NONE , " %s " , __FUNCTION__ ) ;
if ( s_bScreenEffectTextureIsUpdated = = false )
{
// FIXME: nX/nY/nWidth/nHeight are used here, but the equivalent parameters are ignored in Generate8BitBloomTexture
UpdateScreenEffectTexture ( 0 , nX , nY , nWidth , nHeight , true ) ;
s_bScreenEffectTextureIsUpdated = true ;
}
g_HDR_HistogramSystem . Update ( ) ;
if ( mat_dynamic_tonemapping . GetInt ( ) | | mat_show_histogram . GetInt ( ) )
{
float flTargetScalar = g_HDR_HistogramSystem . GetTargetTonemapScalar ( ) ;
float flTargetScalarClamped = MAX ( flAutoExposureMin , MIN ( flAutoExposureMax , flTargetScalar ) ) ;
flTargetScalarClamped = MAX ( 0.001f , flTargetScalarClamped ) ; // Don't let this go to 0!
if ( mat_dynamic_tonemapping . GetInt ( ) )
{
SetToneMapScale ( pRenderContext , flTargetScalarClamped , flAutoExposureMin , flAutoExposureMax ) ;
}
if ( mat_debug_autoexposure . GetInt ( ) | | mat_show_histogram . GetInt ( ) )
{
bool bDrawTextThisFrame = true ;
if ( IsX360 ( ) )
{
static float s_flLastTimeUpdate = 0.0f ;
if ( int ( gpGlobals - > curtime ) - int ( s_flLastTimeUpdate ) > = 2 )
{
s_flLastTimeUpdate = gpGlobals - > curtime ;
bDrawTextThisFrame = true ;
}
else
{
bDrawTextThisFrame = false ;
}
}
if ( bDrawTextThisFrame = = true )
{
if ( mat_tonemap_algorithm . GetInt ( ) = = 0 )
{
engine - > Con_NPrintf ( 19 , " (Original algorithm) Target Scalar = %4.2f Min/Max( %4.2f, %4.2f ) Final Scalar: %4.2f Actual: %4.2f " ,
flTargetScalar , flAutoExposureMin , flAutoExposureMax , mat_hdr_tonemapscale . GetFloat ( ) , pRenderContext - > GetToneMappingScaleLinear ( ) . x ) ;
}
else
{
engine - > Con_NPrintf ( 19 , " %.2f%% of pixels above %d%% target @ %4.2f%% Target Scalar = %4.2f Min/Max( %4.2f, %4.2f ) Final Scalar: %4.2f Actual: %4.2f " ,
mat_tonemap_percent_bright_pixels . GetFloat ( ) , mat_tonemap_percent_target . GetInt ( ) ,
( g_HDR_HistogramSystem . FindLocationOfPercentBrightPixels ( mat_tonemap_percent_bright_pixels . GetFloat ( ) , mat_tonemap_percent_target . GetFloat ( ) ) * 100.0f ) ,
g_HDR_HistogramSystem . GetTargetTonemapScalar ( true ) , flAutoExposureMin , flAutoExposureMax , mat_hdr_tonemapscale . GetFloat ( ) , pRenderContext - > GetToneMappingScaleLinear ( ) . x ) ;
}
}
}
}
}
}
static void DoPostBloomTonemapping ( IMatRenderContext * pRenderContext , int nX , int nY , int nWidth , int nHeight , float flAutoExposureMin , float flAutoExposureMax )
{
if ( mat_show_histogram . GetInt ( ) & & ( engine - > GetDXSupportLevel ( ) > = 90 ) )
{
g_HDR_HistogramSystem . DisplayHistogram ( ) ;
}
}
static void CenterScaleQuadUVs ( Vector4D & quadUVs , const Vector2D & uvScale )
{
Vector2D uvMid = 0.5f * Vector2D ( ( quadUVs . z + quadUVs . x ) , ( quadUVs . w + quadUVs . y ) ) ;
Vector2D uvRange = 0.5f * Vector2D ( ( quadUVs . z - quadUVs . x ) , ( quadUVs . w - quadUVs . y ) ) ;
quadUVs . x = uvMid . x - uvScale . x * uvRange . x ;
quadUVs . y = uvMid . y - uvScale . y * uvRange . y ;
quadUVs . z = uvMid . x + uvScale . x * uvRange . x ;
quadUVs . w = uvMid . y + uvScale . y * uvRange . y ;
}
typedef struct SPyroSide
{
float m_vCornerPos [ 2 ] [ 2 ] ;
float m_flIntensity ;
float m_flIntensityLimit ;
float m_flRate ;
bool m_bHorizontal ;
bool m_bIncreasing ;
bool m_bAlive ;
} TPyroSide ;
# define MAX_PYRO_SIDES 50
# define NUM_PYRO_SEGMENTS 8
# define MIN_PYRO_SIDE_LENGTH 0.5f
# define MAX_PYRO_SIDE_LENGTH 0.90f
# define MIN_PYRO_SIDE_WIDTH 0.25f
# define MAX_PYRO_SIDE_WIDTH 0.95f
static TPyroSide PyroSides [ MAX_PYRO_SIDES ] ;
ConVar pyro_vignette ( " pyro_vignette " , " 2 " , FCVAR_ARCHIVE ) ;
ConVar pyro_vignette_distortion ( " pyro_vignette_distortion " , " 1 " , FCVAR_ARCHIVE ) ;
ConVar pyro_min_intensity ( " pyro_min_intensity " , " 0.1 " , FCVAR_ARCHIVE ) ;
ConVar pyro_max_intensity ( " pyro_max_intensity " , " 0.35 " , FCVAR_ARCHIVE ) ;
ConVar pyro_min_rate ( " pyro_min_rate " , " 0.05 " , FCVAR_ARCHIVE ) ;
ConVar pyro_max_rate ( " pyro_max_rate " , " 0.2 " , FCVAR_ARCHIVE ) ;
ConVar pyro_min_side_length ( " pyro_min_side_length " , " 0.3 " , FCVAR_ARCHIVE ) ;
ConVar pyro_max_side_length ( " pyro_max_side_length " , " 0.55 " , FCVAR_ARCHIVE ) ;
ConVar pyro_min_side_width ( " pyro_min_side_width " , " 0.65 " , FCVAR_ARCHIVE ) ;
ConVar pyro_max_side_width ( " pyro_max_side_width " , " 0.95 " , FCVAR_ARCHIVE ) ;
static void CreatePyroSide ( int nSide , Vector2D & vMaxSize )
{
int nFound = 0 ;
for ( ; nFound < MAX_PYRO_SIDES ; nFound + + )
{
if ( ! PyroSides [ nFound ] . m_bAlive )
{
break ;
}
}
if ( nFound > = MAX_PYRO_SIDES )
{
return ;
}
TPyroSide * pSide = & PyroSides [ nFound ] ;
pSide - > m_flIntensity = 0.0f ;
pSide - > m_flIntensityLimit = RandomFloat ( pyro_min_intensity . GetFloat ( ) , pyro_max_intensity . GetFloat ( ) ) ;
pSide - > m_flRate = RandomFloat ( pyro_min_rate . GetFloat ( ) , pyro_max_rate . GetFloat ( ) ) ;
pSide - > m_bIncreasing = true ;
pSide - > m_bHorizontal = ( ( nSide > > 1 ) & 1 ) = = 0 ;
pSide - > m_bAlive = true ;
// float flWidth = RandomFloat( MIN_PYRO_SIDE_WIDTH, MAX_PYRO_SIDE_WIDTH ) * 2.0f;
// float flLength = RandomFloat( MIN_PYRO_SIDE_LENGTH, MAX_PYRO_SIDE_LENGTH );
float flWidth = RandomFloat ( pyro_min_side_width . GetFloat ( ) , pyro_max_side_width . GetFloat ( ) ) * 2.0f ;
float flLength = RandomFloat ( pyro_min_side_length . GetFloat ( ) , pyro_max_side_length . GetFloat ( ) ) ;
switch ( nSide )
{
case 0 :
{
pSide - > m_vCornerPos [ 0 ] [ 0 ] = - 1.0f ;
pSide - > m_vCornerPos [ 0 ] [ 1 ] = 1.0f ;
pSide - > m_vCornerPos [ 1 ] [ 0 ] = - 1.0f + flWidth ;
pSide - > m_vCornerPos [ 1 ] [ 1 ] = 1.0f - ( flLength * vMaxSize . y ) ;
}
break ;
case 1 :
{
pSide - > m_vCornerPos [ 0 ] [ 0 ] = 1.0f ;
pSide - > m_vCornerPos [ 0 ] [ 1 ] = 1.0f ;
pSide - > m_vCornerPos [ 1 ] [ 0 ] = 1.0f - flWidth ;
pSide - > m_vCornerPos [ 1 ] [ 1 ] = 1.0f - ( flLength * vMaxSize . y ) ;
}
break ;
case 2 :
{
pSide - > m_vCornerPos [ 0 ] [ 0 ] = 1.0f ;
pSide - > m_vCornerPos [ 0 ] [ 1 ] = 1.0f ;
pSide - > m_vCornerPos [ 1 ] [ 0 ] = 1.0f - ( flLength * vMaxSize . x ) ;
pSide - > m_vCornerPos [ 1 ] [ 1 ] = 1.0f - flWidth ;
}
break ;
case 3 :
{
pSide - > m_vCornerPos [ 0 ] [ 0 ] = 1.0f ;
pSide - > m_vCornerPos [ 0 ] [ 1 ] = - 1.0f ;
pSide - > m_vCornerPos [ 1 ] [ 0 ] = 1.0f - ( flLength * vMaxSize . x ) ;
pSide - > m_vCornerPos [ 1 ] [ 1 ] = - 1.0f + flWidth ;
}
break ;
case 4 :
{
pSide - > m_vCornerPos [ 0 ] [ 0 ] = 1.0f ;
pSide - > m_vCornerPos [ 0 ] [ 1 ] = - 1.0f ;
pSide - > m_vCornerPos [ 1 ] [ 0 ] = 1.0f - flWidth ;
pSide - > m_vCornerPos [ 1 ] [ 1 ] = - 1.0f + ( flLength * vMaxSize . y ) ;
}
break ;
case 5 :
{
pSide - > m_vCornerPos [ 0 ] [ 0 ] = - 1.0f ;
pSide - > m_vCornerPos [ 0 ] [ 1 ] = - 1.0f ;
pSide - > m_vCornerPos [ 1 ] [ 0 ] = - 1.0f + flWidth ;
pSide - > m_vCornerPos [ 1 ] [ 1 ] = - 1.0f + ( flLength * vMaxSize . y ) ;
}
break ;
case 6 :
{
pSide - > m_vCornerPos [ 0 ] [ 0 ] = - 1.0f ;
pSide - > m_vCornerPos [ 0 ] [ 1 ] = - 1.0f ;
pSide - > m_vCornerPos [ 1 ] [ 0 ] = - 1.0f + ( flLength * vMaxSize . x ) ;
pSide - > m_vCornerPos [ 1 ] [ 1 ] = - 1.0f + flWidth ;
}
break ;
case 7 :
{
pSide - > m_vCornerPos [ 0 ] [ 0 ] = - 1.0f ;
pSide - > m_vCornerPos [ 0 ] [ 1 ] = 1.0f ;
pSide - > m_vCornerPos [ 1 ] [ 0 ] = - 1.0f + ( flLength * vMaxSize . x ) ;
pSide - > m_vCornerPos [ 1 ] [ 1 ] = 1.0f - flWidth ;
}
break ;
}
}
static float PryoVignetteSTHorizontal [ 6 ] [ 2 ] =
{
{ 0.0f , 0.0f } ,
{ 0.0f , 1.0f } ,
{ 1.0f , 1.0f } ,
{ 1.0f , 1.0f } ,
{ 0.0f , 0.0f } ,
{ 1.0f , 0.0f }
} ;
static float PryoVignetteSTVertical [ 6 ] [ 2 ] =
{
{ 0.0f , 0.0f } ,
{ 1.0f , 0.0f } ,
{ 1.0f , 1.0f } ,
{ 1.0f , 1.0f } ,
{ 0.0f , 0.0f } ,
{ 0.0f , 1.0f }
} ;
static int PryoSideIndexes [ 6 ] [ 2 ] =
{
{ 0 , 0 } ,
{ 0 , 1 } ,
{ 1 , 1 } ,
{ 1 , 1 } ,
{ 0 , 0 } ,
{ 1 , 0 }
} ;
static void DrawPyroVignette ( int nDestX , int nDestY , int nWidth , int nHeight , // Rect to draw into in screen space
float flSrcTextureX0 , float flSrcTextureY0 , // which texel you want to appear at destx/y
float flSrcTextureX1 , float flSrcTextureY1 , // which texel you want to appear at destx+width-1, desty+height-1
void * pClientRenderable )
{
static bool bInit = false ;
static int nNextSide = 0 ;
CMatRenderContextPtr pRenderContext ( g_pMaterialSystem ) ;
IMaterial * pVignetteBorder = materials - > FindMaterial ( " dev/pyro_vignette_border " , TEXTURE_GROUP_OTHER , true ) ;
IMaterial * pMaterial = materials - > FindMaterial ( " dev/pyro_vignette " , TEXTURE_GROUP_OTHER , true ) ;
ITexture * pRenderTarget = materials - > FindTexture ( " _rt_ResolvedFullFrameDepth " , TEXTURE_GROUP_RENDER_TARGET ) ;
pRenderContext - > PushRenderTargetAndViewport ( pRenderTarget ) ;
pRenderContext - > ClearColor4ub ( 0 , 0 , 0 , 0 ) ;
pRenderContext - > ClearBuffers ( true , false ) ;
int nScreenWidth , nScreenHeight ;
pRenderContext - > GetRenderTargetDimensions ( nScreenWidth , nScreenHeight ) ;
pRenderContext - > DrawScreenSpaceRectangle ( pVignetteBorder , 0 , 0 , nScreenWidth , nScreenHeight , 0 , 0 , nScreenWidth - 1 , nScreenHeight - 1 , nScreenWidth , nScreenHeight , pClientRenderable ) ;
if ( pyro_vignette . GetInt ( ) > 1 )
{
float flPyroSegments = 2.0f / NUM_PYRO_SEGMENTS ;
Vector2D vMaxSize ( flPyroSegments , flPyroSegments ) ;
if ( ! bInit )
{
for ( int i = 0 ; i < MAX_PYRO_SIDES ; i + + )
{
PyroSides [ i ] . m_bAlive = false ;
}
CreatePyroSide ( nNextSide , vMaxSize ) ;
nNextSide = ( nNextSide + 1 ) & 7 ;
bInit = true ;
}
int nNumAlive = 0 ;
TPyroSide * pSide = & PyroSides [ 0 ] ;
for ( int nIndex = 0 ; nIndex < MAX_PYRO_SIDES ; nIndex + + , pSide + + )
{
if ( pSide - > m_bAlive )
{
if ( pSide - > m_bIncreasing )
{
pSide - > m_flIntensity + = pSide - > m_flRate * gpGlobals - > frametime ;
if ( pSide - > m_flIntensity > = pSide - > m_flIntensityLimit )
{
pSide - > m_bIncreasing = false ;
}
}
else
{
pSide - > m_flIntensity - = pSide - > m_flRate * gpGlobals - > frametime ;
if ( pSide - > m_flIntensity < = 0.0f )
{
pSide - > m_bAlive = false ;
}
}
}
if ( pSide - > m_bAlive )
{
nNumAlive + + ;
}
}
if ( nNumAlive > 0 )
{
pRenderContext - > MatrixMode ( MATERIAL_VIEW ) ;
pRenderContext - > PushMatrix ( ) ;
pRenderContext - > LoadIdentity ( ) ;
pRenderContext - > MatrixMode ( MATERIAL_PROJECTION ) ;
pRenderContext - > PushMatrix ( ) ;
pRenderContext - > LoadIdentity ( ) ;
pRenderContext - > Bind ( pMaterial , pClientRenderable ) ;
CMeshBuilder meshBuilder ;
IMesh * pMesh = pRenderContext - > GetDynamicMesh ( true ) ;
meshBuilder . Begin ( pMesh , MATERIAL_TRIANGLES , nNumAlive * 2 ) ;
pSide = & PyroSides [ 0 ] ;
for ( int nIndex = 0 ; nIndex < MAX_PYRO_SIDES ; nIndex + + , pSide + + )
{
if ( pSide - > m_bAlive )
{
for ( int i = 0 ; i < 6 ; i + + )
{
meshBuilder . Position3f ( pSide - > m_vCornerPos [ PryoSideIndexes [ i ] [ 0 ] ] [ 0 ] , pSide - > m_vCornerPos [ PryoSideIndexes [ i ] [ 1 ] ] [ 1 ] , 0.0f ) ;
meshBuilder . Color4f ( pSide - > m_flIntensity , pSide - > m_flIntensity , pSide - > m_flIntensity , 1.0f ) ;
meshBuilder . TexCoord2fv ( 0 , pSide - > m_bHorizontal ? PryoVignetteSTHorizontal [ i ] : PryoVignetteSTVertical [ i ] ) ;
meshBuilder . TangentS3f ( 0.0f , 1.0f , 0.0f ) ;
meshBuilder . TangentT3f ( 1.0f , 0.0f , 0.0f ) ;
meshBuilder . Normal3f ( 0.0f , 0.0f , 1.0f ) ;
meshBuilder . AdvanceVertex ( ) ;
}
}
}
meshBuilder . End ( ) ;
pMesh - > Draw ( ) ;
pRenderContext - > MatrixMode ( MATERIAL_VIEW ) ;
pRenderContext - > PopMatrix ( ) ;
pRenderContext - > MatrixMode ( MATERIAL_PROJECTION ) ;
pRenderContext - > PopMatrix ( ) ;
}
if ( nNumAlive < 25 )
{
CreatePyroSide ( nNextSide , vMaxSize ) ;
nNextSide = ( nNextSide + 1 ) & 7 ;
}
}
pRenderContext - > PopRenderTargetAndViewport ( ) ;
}
static void DrawPyroPost ( IMaterial * pMaterial ,
int nDestX , int nDestY , int nWidth , int nHeight , // Rect to draw into in screen space
float flSrcTextureX0 , float flSrcTextureY0 , // which texel you want to appear at destx/y
float flSrcTextureX1 , float flSrcTextureY1 , // which texel you want to appear at destx+width-1, desty+height-1
int nSrcTextureWidth , int nSrcTextureHeight , // needed for fixup
void * pClientRenderable ) // Used to pass to the bind proxies
{
bool bFound = false ;
IMaterialVar * pVar = pMaterial - > FindVar ( " $disabled " , & bFound , false ) ;
if ( bFound & & pVar - > GetIntValue ( ) )
{
return ;
}
CMatRenderContextPtr pRenderContext ( g_pMaterialSystem ) ;
pRenderContext - > MatrixMode ( MATERIAL_VIEW ) ;
pRenderContext - > PushMatrix ( ) ;
pRenderContext - > LoadIdentity ( ) ;
pRenderContext - > MatrixMode ( MATERIAL_PROJECTION ) ;
pRenderContext - > PushMatrix ( ) ;
pRenderContext - > LoadIdentity ( ) ;
pRenderContext - > Bind ( pMaterial , pClientRenderable ) ;
int xSegments = NUM_PYRO_SEGMENTS ;
int ySegments = NUM_PYRO_SEGMENTS ;
CMeshBuilder meshBuilder ;
IMesh * pMesh = pRenderContext - > GetDynamicMesh ( true ) ;
meshBuilder . Begin ( pMesh , MATERIAL_QUADS , 4 ) ;
int nScreenWidth , nScreenHeight ;
pRenderContext - > GetRenderTargetDimensions ( nScreenWidth , nScreenHeight ) ;
float flOffset = IsPosix ( ) ? 0.0f : 0.5f ;
float flLeftX = nDestX - flOffset ;
float flRightX = nDestX + nWidth - flOffset ;
float flTopY = nDestY - flOffset ;
float flBottomY = nDestY + nHeight - flOffset ;
float flSubrectWidth = flSrcTextureX1 - flSrcTextureX0 ;
float flSubrectHeight = flSrcTextureY1 - flSrcTextureY0 ;
float flTexelsPerPixelX = ( nWidth > 1 ) ? flSubrectWidth / ( nWidth - 1 ) : 0.0f ;
float flTexelsPerPixelY = ( nHeight > 1 ) ? flSubrectHeight / ( nHeight - 1 ) : 0.0f ;
float flLeftU = flSrcTextureX0 + 0.5f - ( 0.5f * flTexelsPerPixelX ) ;
float flRightU = flSrcTextureX1 + 0.5f + ( 0.5f * flTexelsPerPixelX ) ;
float flTopV = flSrcTextureY0 + 0.5f - ( 0.5f * flTexelsPerPixelY ) ;
float flBottomV = flSrcTextureY1 + 0.5f + ( 0.5f * flTexelsPerPixelY ) ;
float flOOTexWidth = 1.0f / nSrcTextureWidth ;
float flOOTexHeight = 1.0f / nSrcTextureHeight ;
flLeftU * = flOOTexWidth ;
flRightU * = flOOTexWidth ;
flTopV * = flOOTexHeight ;
flBottomV * = flOOTexHeight ;
// Get the current viewport size
int vx , vy , vw , vh ;
pRenderContext - > GetViewport ( vx , vy , vw , vh ) ;
// map from screen pixel coords to -1..1
flRightX = FLerp ( - 1 , 1 , 0 , vw , flRightX ) ;
flLeftX = FLerp ( - 1 , 1 , 0 , vw , flLeftX ) ;
flTopY = FLerp ( 1 , - 1 , 0 , vh , flTopY ) ;
flBottomY = FLerp ( 1 , - 1 , 0 , vh , flBottomY ) ;
// Screen height and width of a subrect
float flWidth = ( flRightX - flLeftX ) / ( float ) xSegments ;
float flHeight = ( flTopY - flBottomY ) / ( float ) ySegments ;
// UV height and width of a subrect
float flUWidth = ( flRightU - flLeftU ) / ( float ) xSegments ;
float flVHeight = ( flBottomV - flTopV ) / ( float ) ySegments ;
// Top Bar
// Top left
meshBuilder . Position3f ( flLeftX + ( float ) 0 * flWidth , flTopY - ( float ) 0 * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) 0 * flUWidth , flTopV + ( float ) 0 * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Top right (x+1)
meshBuilder . Position3f ( flLeftX + ( float ) ( xSegments + 1 ) * flWidth , flTopY - ( float ) 0 * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( xSegments + 1 ) * flUWidth , flTopV + ( float ) 0 * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Bottom right (x+1), (y+1)
meshBuilder . Position3f ( flLeftX + ( float ) ( xSegments + 1 ) * flWidth , flTopY - ( float ) ( 0 + 1 ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( xSegments + 1 ) * flUWidth , flTopV + ( float ) ( 0 + 1 ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Bottom left (y+1)
meshBuilder . Position3f ( flLeftX + ( float ) 0 * flWidth , flTopY - ( float ) ( 0 + 1 ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) 0 * flUWidth , flTopV + ( float ) ( 0 + 1 ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Bottom Bar
// Top left
meshBuilder . Position3f ( flLeftX + ( float ) 0 * flWidth , flTopY - ( float ) ( ySegments - 1 ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) 0 * flUWidth , flTopV + ( float ) ( ySegments - 1 ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Top right (x+1)
meshBuilder . Position3f ( flLeftX + ( float ) ( xSegments ) * flWidth , flTopY - ( float ) ( ySegments - 1 ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( xSegments ) * flUWidth , flTopV + ( float ) ( ySegments - 1 ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Bottom right (x+1), (y+1)
meshBuilder . Position3f ( flLeftX + ( float ) ( xSegments ) * flWidth , flTopY - ( float ) ( ySegments ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( xSegments ) * flUWidth , flTopV + ( float ) ( ySegments ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Bottom left (y+1)
meshBuilder . Position3f ( flLeftX + ( float ) 0 * flWidth , flTopY - ( float ) ( ySegments ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) 0 * flUWidth , flTopV + ( float ) ( ySegments ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Left Bar
// Top left
meshBuilder . Position3f ( flLeftX + ( float ) 0 * flWidth , flTopY - ( float ) 1 * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) 0 * flUWidth , flTopV + ( float ) 1 * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Top right (x+1)
meshBuilder . Position3f ( flLeftX + ( float ) ( 0 + 1 ) * flWidth , flTopY - ( float ) 1 * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( 0 + 1 ) * flUWidth , flTopV + ( float ) 1 * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Bottom right (x+1), (y+1)
meshBuilder . Position3f ( flLeftX + ( float ) ( 0 + 1 ) * flWidth , flTopY - ( float ) ( ySegments - 1 ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( 0 + 1 ) * flUWidth , flTopV + ( float ) ( ySegments - 1 ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Bottom left (y+1)
meshBuilder . Position3f ( flLeftX + ( float ) 0 * flWidth , flTopY - ( float ) ( ySegments - 1 ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) 0 * flUWidth , flTopV + ( float ) ( ySegments - 1 ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Right Bar
// Top left
meshBuilder . Position3f ( flLeftX + ( float ) ( xSegments - 1 ) * flWidth , flTopY - ( float ) 1 * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( xSegments - 1 ) * flUWidth , flTopV + ( float ) 1 * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Top right (x+1)
meshBuilder . Position3f ( flLeftX + ( float ) ( xSegments ) * flWidth , flTopY - ( float ) 1 * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( xSegments ) * flUWidth , flTopV + ( float ) 1 * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Bottom right (x+1), (y+1)
meshBuilder . Position3f ( flLeftX + ( float ) ( xSegments ) * flWidth , flTopY - ( float ) ( ySegments - 1 ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( xSegments ) * flUWidth , flTopV + ( float ) ( ySegments - 1 ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Bottom left (y+1)
meshBuilder . Position3f ( flLeftX + ( float ) ( xSegments - 1 ) * flWidth , flTopY - ( float ) ( ySegments - 1 ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( xSegments - 1 ) * flUWidth , flTopV + ( float ) ( ySegments - 1 ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
#if 0
for ( int x = 0 ; x < xSegments ; x + + )
{
for ( int y = 0 ; y < ySegments ; y + + )
{
if ( ( x = = 1 | | x = = 2 ) & & ( y = = 1 | | y = = 2 ) )
{ // skip the center 4 segments
continue ;
}
// Top left
meshBuilder . Position3f ( flLeftX + ( float ) x * flWidth , flTopY - ( float ) y * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) x * flUWidth , flTopV + ( float ) y * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Top right (x+1)
meshBuilder . Position3f ( flLeftX + ( float ) ( x + 1 ) * flWidth , flTopY - ( float ) y * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( x + 1 ) * flUWidth , flTopV + ( float ) y * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Bottom right (x+1), (y+1)
meshBuilder . Position3f ( flLeftX + ( float ) ( x + 1 ) * flWidth , flTopY - ( float ) ( y + 1 ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) ( x + 1 ) * flUWidth , flTopV + ( float ) ( y + 1 ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
// Bottom left (y+1)
meshBuilder . Position3f ( flLeftX + ( float ) x * flWidth , flTopY - ( float ) ( y + 1 ) * flHeight , 0.0f ) ;
meshBuilder . TexCoord2f ( 0 , flLeftU + ( float ) x * flUWidth , flTopV + ( float ) ( y + 1 ) * flVHeight ) ;
meshBuilder . AdvanceVertex ( ) ;
}
}
# endif
meshBuilder . End ( ) ;
pMesh - > Draw ( ) ;
pRenderContext - > MatrixMode ( MATERIAL_VIEW ) ;
pRenderContext - > PopMatrix ( ) ;
pRenderContext - > MatrixMode ( MATERIAL_PROJECTION ) ;
pRenderContext - > PopMatrix ( ) ;
}
static ConVar r_queued_post_processing ( " r_queued_post_processing " , " 0 " ) ;
// How much to dice up the screen during post-processing on 360
// This has really marginal effects, but 4x1 does seem vaguely better for post-processing
static ConVar mat_postprocess_x ( " mat_postprocess_x " , " 4 " ) ;
static ConVar mat_postprocess_y ( " mat_postprocess_y " , " 1 " ) ;
void DoEnginePostProcessing ( int x , int y , int w , int h , bool bFlashlightIsOn , bool bPostVGui )
{
tmZone ( TELEMETRY_LEVEL0 , TMZF_NONE , " %s " , __FUNCTION__ ) ;
CMatRenderContextPtr pRenderContext ( materials ) ;
if ( g_bDumpRenderTargets )
{
g_bDumpRenderTargets = false ; // Turn off from previous frame
}
if ( mat_dump_rts . GetBool ( ) )
{
g_bDumpRenderTargets = true ; // Dump intermediate render targets this frame
s_nRTIndex = 0 ; // Used for numbering the TGA files for easy browsing
mat_dump_rts . SetValue ( 0 ) ; // We only want to capture one frame, on rising edge of this convar
DumpTGAofRenderTarget ( w , h , " BackBuffer " ) ;
}
# if defined( _X360 )
pRenderContext - > PushVertexShaderGPRAllocation ( 16 ) ; //max out pixel shader threads
# endif
if ( r_queued_post_processing . GetInt ( ) )
{
ICallQueue * pCallQueue = pRenderContext - > GetCallQueue ( ) ;
if ( pCallQueue )
{
pCallQueue - > QueueCall ( DoEnginePostProcessing , x , y , w , h , bFlashlightIsOn , bPostVGui ) ;
return ;
}
}
float flBloomScale = GetBloomAmount ( ) ;
HDRType_t hdrType = g_pMaterialSystemHardwareConfig - > GetHDRType ( ) ;
g_bFlashlightIsOn = bFlashlightIsOn ;
// Use the appropriate autoexposure min / max settings.
// Mapmaker's overrides the convar settings.
float flAutoExposureMin ;
float flAutoExposureMax ;
GetExposureRange ( & flAutoExposureMin , & flAutoExposureMax ) ;
if ( mat_debug_bloom . GetInt ( ) = = 1 )
{
DrawBloomDebugBoxes ( pRenderContext ) ;
}
switch ( hdrType )
{
case HDR_TYPE_NONE :
case HDR_TYPE_INTEGER :
{
s_bScreenEffectTextureIsUpdated = false ;
if ( hdrType ! = HDR_TYPE_NONE )
{
DoPreBloomTonemapping ( pRenderContext , x , y , w , h , flAutoExposureMin , flAutoExposureMax ) ;
}
// Set software-AA on by default for 360
if ( mat_software_aa_strength . GetFloat ( ) = = - 1.0f )
{
if ( IsX360 ( ) )
{
mat_software_aa_strength . SetValue ( 1.0f ) ;
if ( g_pMaterialSystem - > GetCurrentConfigForVideoCard ( ) . m_VideoMode . m_Height > 480 )
{
mat_software_aa_quality . SetValue ( 0 ) ;
}
else
{
// For standard-def, we have fewer pixels so we can afford 'high quality' mode (5->9 taps/pixel)
mat_software_aa_quality . SetValue ( 1 ) ;
}
}
else
{
mat_software_aa_strength . SetValue ( 0.0f ) ;
}
}
// Same trick for setting up the vgui aa strength
if ( mat_software_aa_strength_vgui . GetFloat ( ) = = - 1.0f )
{
if ( IsX360 ( ) & & ( g_pMaterialSystem - > GetCurrentConfigForVideoCard ( ) . m_VideoMode . m_Height = = 720 ) )
{
mat_software_aa_strength_vgui . SetValue ( 2.0f ) ;
}
else
{
mat_software_aa_strength_vgui . SetValue ( 1.0f ) ;
}
}
float flAAStrength ;
// We do a second AA blur pass over the TF intro menus. use mat_software_aa_strength_vgui there instead
if ( IsX360 ( ) & & bPostVGui )
{
flAAStrength = mat_software_aa_strength_vgui . GetFloat ( ) ;
}
else
{
flAAStrength = mat_software_aa_strength . GetFloat ( ) ;
}
// bloom, software-AA and colour-correction (applied in 1 pass, after generation of the bloom texture)
bool bPerformSoftwareAA = IsX360 ( ) & & ( engine - > GetDXSupportLevel ( ) > = 90 ) & & ( flAAStrength ! = 0.0f ) ;
bool bPerformBloom = ! bPostVGui & & ( flBloomScale > 0.0f ) & & ( engine - > GetDXSupportLevel ( ) > = 90 ) ;
bool bPerformColCorrect = ! bPostVGui & &
( g_pMaterialSystemHardwareConfig - > GetDXSupportLevel ( ) > = 90 ) & &
( g_pMaterialSystemHardwareConfig - > GetHDRType ( ) ! = HDR_TYPE_FLOAT ) & &
g_pColorCorrectionMgr - > HasNonZeroColorCorrectionWeights ( ) & &
mat_colorcorrection . GetInt ( ) ;
bool bSplitScreenHDR = mat_show_ab_hdr . GetInt ( ) ;
pRenderContext - > EnableColorCorrection ( bPerformColCorrect ) ;
if ( bPerformBloom | | bPerformSoftwareAA | | bPerformColCorrect )
{
tmZone ( TELEMETRY_LEVEL0 , TMZF_NONE , " ColorCorrection " ) ;
ITexture * pSrc = materials - > FindTexture ( " _rt_FullFrameFB " , TEXTURE_GROUP_RENDER_TARGET ) ;
int nSrcWidth = pSrc - > GetActualWidth ( ) ;
int nSrcHeight = pSrc - > GetActualHeight ( ) ;
ITexture * dest_rt1 = materials - > FindTexture ( " _rt_SmallFB1 " , TEXTURE_GROUP_RENDER_TARGET ) ;
if ( ! s_bScreenEffectTextureIsUpdated )
{
// NOTE: UpdateScreenEffectTexture() uses StretchRect, so _rt_FullFrameFB is always 100%
// filled, even when the viewport is not fullscreen (e.g. with 'mat_viewportscale 0.5')
UpdateScreenEffectTexture ( 0 , x , y , w , h , true ) ;
s_bScreenEffectTextureIsUpdated = true ;
}
if ( bPerformBloom )
{
Generate8BitBloomTexture ( pRenderContext , flBloomScale , x , y , w , h ) ;
}
// Now add bloom (dest_rt0) to the framebuffer and perform software anti-aliasing and
// colour correction, all in one pass (improves performance, reduces quantization errors)
//
// First, set up texel coords (in the bloom and fb textures) at the centres of the outer pixel of the viewport:
Vector4D fullViewportPostSrcCorners ( 0.0f , - 0.5f , nSrcWidth / 4 - 1 , nSrcHeight / 4 - 1 ) ;
Vector4D fullViewportPostDestCorners ( 0.0f , 0.0f , nSrcWidth - 1 , nSrcHeight - 1 ) ;
Rect_t fullViewportPostDestRect = { x , y , w , h } ;
Vector2D destTexSize ( nSrcWidth , nSrcHeight ) ;
// When the viewport is not fullscreen, the UV-space size of a pixel changes
// (due to a stretchrect blit being used in UpdateScreenEffectTexture()), so
// we need to adjust the corner-pixel UVs sent to our drawrect call:
Vector2D uvScale ( ( nSrcWidth - ( nSrcWidth / ( float ) w ) ) / ( nSrcWidth - 1 ) ,
( nSrcHeight - ( nSrcHeight / ( float ) h ) ) / ( nSrcHeight - 1 ) ) ;
CenterScaleQuadUVs ( fullViewportPostSrcCorners , uvScale ) ;
CenterScaleQuadUVs ( fullViewportPostDestCorners , uvScale ) ;
Rect_t partialViewportPostDestRect = fullViewportPostDestRect ;
Vector4D partialViewportPostSrcCorners = fullViewportPostSrcCorners ;
if ( debug_postproc . GetInt ( ) = = 2 )
{
// Restrict the post effects to the centre quarter of the screen
// (we only use a portion of the bloom texture, so this *does* affect bloom texture UVs)
partialViewportPostDestRect . x + = 0.25f * fullViewportPostDestRect . width ;
partialViewportPostDestRect . y + = 0.25f * fullViewportPostDestRect . height ;
partialViewportPostDestRect . width - = 0.50f * fullViewportPostDestRect . width ;
partialViewportPostDestRect . height - = 0.50f * fullViewportPostDestRect . height ;
// This math interprets texel coords as being at corner pixel centers (*not* at corner vertices):
Vector2D uvScale ( 1.0f - ( ( w / 2 ) / ( float ) ( w - 1 ) ) ,
1.0f - ( ( h / 2 ) / ( float ) ( h - 1 ) ) ) ;
CenterScaleQuadUVs ( partialViewportPostSrcCorners , uvScale ) ;
}
// Temporary hack... Color correction was crashing on the first frame
// when run outside the debugger for some mods (DoD). This forces it to skip
// a frame, ensuring we don't get the weird texture crash we otherwise would.
// FIXME: This will be removed when the true cause is found [added: Main CL 144694]
static bool bFirstFrame = ! IsX360 ( ) ;
if ( ! bFirstFrame | | ! bPerformColCorrect )
{
bool bFBUpdated = false ;
if ( mat_postprocessing_combine . GetInt ( ) )
{
// Perform post-processing in one combined pass
IMaterial * post_mat = CEnginePostMaterialProxy : : SetupEnginePostMaterial ( fullViewportPostSrcCorners , fullViewportPostDestCorners , destTexSize , bPerformSoftwareAA , bPerformBloom , bPerformColCorrect , flAAStrength ) ;
if ( bSplitScreenHDR )
{
pRenderContext - > SetScissorRect ( partialViewportPostDestRect . width / 2 , 0 , partialViewportPostDestRect . width , partialViewportPostDestRect . height , true ) ;
}
pRenderContext - > DrawScreenSpaceRectangle ( post_mat ,
// TomF - offset already done by the viewport.
0 , 0 , //partialViewportPostDestRect.x, partialViewportPostDestRect.y,
partialViewportPostDestRect . width , partialViewportPostDestRect . height ,
partialViewportPostSrcCorners . x , partialViewportPostSrcCorners . y ,
partialViewportPostSrcCorners . z , partialViewportPostSrcCorners . w ,
dest_rt1 - > GetActualWidth ( ) , dest_rt1 - > GetActualHeight ( ) ,
GetClientWorldEntity ( ) - > GetClientRenderable ( ) ,
mat_postprocess_x . GetInt ( ) , mat_postprocess_y . GetInt ( ) ) ;
if ( bSplitScreenHDR )
{
pRenderContext - > SetScissorRect ( - 1 , - 1 , - 1 , - 1 , false ) ;
}
bFBUpdated = true ;
}
else
{
// Perform post-processing in three separate passes
if ( bPerformSoftwareAA )
{
IMaterial * aa_mat = CEnginePostMaterialProxy : : SetupEnginePostMaterial ( fullViewportPostSrcCorners , fullViewportPostDestCorners , destTexSize , bPerformSoftwareAA , false , false , flAAStrength ) ;
if ( bSplitScreenHDR )
{
pRenderContext - > SetScissorRect ( partialViewportPostDestRect . width / 2 , 0 , partialViewportPostDestRect . width , partialViewportPostDestRect . height , true ) ;
}
pRenderContext - > DrawScreenSpaceRectangle ( aa_mat ,
// TODO: check if offsets should be 0,0 here, as with the combined-pass case
partialViewportPostDestRect . x , partialViewportPostDestRect . y ,
partialViewportPostDestRect . width , partialViewportPostDestRect . height ,
partialViewportPostSrcCorners . x , partialViewportPostSrcCorners . y ,
partialViewportPostSrcCorners . z , partialViewportPostSrcCorners . w ,
dest_rt1 - > GetActualWidth ( ) , dest_rt1 - > GetActualHeight ( ) ,
GetClientWorldEntity ( ) - > GetClientRenderable ( ) ) ;
if ( bSplitScreenHDR )
{
pRenderContext - > SetScissorRect ( - 1 , - 1 , - 1 , - 1 , false ) ;
}
bFBUpdated = true ;
}
if ( bPerformBloom )
{
IMaterial * bloom_mat = CEnginePostMaterialProxy : : SetupEnginePostMaterial ( fullViewportPostSrcCorners , fullViewportPostDestCorners , destTexSize , false , bPerformBloom , false , flAAStrength ) ;
if ( bSplitScreenHDR )
{
pRenderContext - > SetScissorRect ( partialViewportPostDestRect . width / 2 , 0 , partialViewportPostDestRect . width , partialViewportPostDestRect . height , true ) ;
}
pRenderContext - > DrawScreenSpaceRectangle ( bloom_mat ,
// TODO: check if offsets should be 0,0 here, as with the combined-pass case
partialViewportPostDestRect . x , partialViewportPostDestRect . y ,
partialViewportPostDestRect . width , partialViewportPostDestRect . height ,
partialViewportPostSrcCorners . x , partialViewportPostSrcCorners . y ,
partialViewportPostSrcCorners . z , partialViewportPostSrcCorners . w ,
dest_rt1 - > GetActualWidth ( ) , dest_rt1 - > GetActualHeight ( ) ,
GetClientWorldEntity ( ) - > GetClientRenderable ( ) ) ;
if ( bSplitScreenHDR )
{
pRenderContext - > SetScissorRect ( - 1 , - 1 , - 1 , - 1 , false ) ;
}
bFBUpdated = true ;
}
if ( bPerformColCorrect )
{
if ( bFBUpdated )
{
Rect_t actualRect ;
UpdateScreenEffectTexture ( 0 , x , y , w , h , false , & actualRect ) ;
}
IMaterial * colcorrect_mat = CEnginePostMaterialProxy : : SetupEnginePostMaterial ( fullViewportPostSrcCorners , fullViewportPostDestCorners , destTexSize , false , false , bPerformColCorrect , flAAStrength ) ;
if ( bSplitScreenHDR )
{
pRenderContext - > SetScissorRect ( partialViewportPostDestRect . width / 2 , 0 , partialViewportPostDestRect . width , partialViewportPostDestRect . height , true ) ;
}
pRenderContext - > DrawScreenSpaceRectangle ( colcorrect_mat ,
// TODO: check if offsets should be 0,0 here, as with the combined-pass case
partialViewportPostDestRect . x , partialViewportPostDestRect . y ,
partialViewportPostDestRect . width , partialViewportPostDestRect . height ,
partialViewportPostSrcCorners . x , partialViewportPostSrcCorners . y ,
partialViewportPostSrcCorners . z , partialViewportPostSrcCorners . w ,
dest_rt1 - > GetActualWidth ( ) , dest_rt1 - > GetActualHeight ( ) ,
GetClientWorldEntity ( ) - > GetClientRenderable ( ) ) ;
if ( bSplitScreenHDR )
{
pRenderContext - > SetScissorRect ( - 1 , - 1 , - 1 , - 1 , false ) ;
}
bFBUpdated = true ;
}
}
bool bVisionOverride = ( localplayer_visionflags . GetInt ( ) & ( 0x01 ) ) ; // Pyro-vision Goggles
if ( bVisionOverride & & g_pMaterialSystemHardwareConfig - > SupportsPixelShaders_2_0 ( ) & & pyro_vignette . GetInt ( ) > 0 )
{
if ( bFBUpdated )
{
Rect_t actualRect ;
UpdateScreenEffectTexture ( 0 , x , y , w , h , false , & actualRect ) ;
}
DrawPyroVignette (
// TODO: check if offsets should be 0,0 here, as with the combined-pass case
partialViewportPostDestRect . x , partialViewportPostDestRect . y ,
partialViewportPostDestRect . width , partialViewportPostDestRect . height ,
partialViewportPostSrcCorners . x , partialViewportPostSrcCorners . y ,
partialViewportPostSrcCorners . z , partialViewportPostSrcCorners . w ,
GetClientWorldEntity ( ) - > GetClientRenderable ( ) ) ;
IMaterial * pPyroVisionPostMaterial = materials - > FindMaterial ( " dev/pyro_post " , TEXTURE_GROUP_OTHER , true ) ;
DrawPyroPost ( pPyroVisionPostMaterial ,
// TODO: check if offsets should be 0,0 here, as with the combined-pass case
partialViewportPostDestRect . x , partialViewportPostDestRect . y ,
partialViewportPostDestRect . width , partialViewportPostDestRect . height ,
partialViewportPostSrcCorners . x , partialViewportPostSrcCorners . y ,
partialViewportPostSrcCorners . z , partialViewportPostSrcCorners . w ,
dest_rt1 - > GetActualWidth ( ) , dest_rt1 - > GetActualHeight ( ) ,
GetClientWorldEntity ( ) - > GetClientRenderable ( ) ) ;
}
if ( g_bDumpRenderTargets )
{
DumpTGAofRenderTarget ( partialViewportPostDestRect . width , partialViewportPostDestRect . height , " EnginePost " ) ;
}
}
bFirstFrame = false ;
}
if ( hdrType ! = HDR_TYPE_NONE )
{
DoPostBloomTonemapping ( pRenderContext , x , y , w , h , flAutoExposureMin , flAutoExposureMax ) ;
}
}
break ;
case HDR_TYPE_FLOAT :
{
int dest_width , dest_height ;
pRenderContext - > GetRenderTargetDimensions ( dest_width , dest_height ) ;
if ( mat_dynamic_tonemapping . GetInt ( ) | | mat_show_histogram . GetInt ( ) )
{
g_HDR_HistogramSystem . Update ( ) ;
// Warning("avg_lum=%f\n",g_HDR_HistogramSystem.GetTargetTonemapScalar());
if ( mat_dynamic_tonemapping . GetInt ( ) )
{
float avg_lum = MAX ( 0.0001 , g_HDR_HistogramSystem . GetTargetTonemapScalar ( ) ) ;
float scalevalue = MAX ( flAutoExposureMin ,
MIN ( flAutoExposureMax , 0.18 / avg_lum ) ) ;
pRenderContext - > SetGoalToneMappingScale ( scalevalue ) ;
mat_hdr_tonemapscale . SetValue ( scalevalue ) ;
}
}
IMaterial * pBloomMaterial ;
pBloomMaterial = materials - > FindMaterial ( " dev/floattoscreen_combine " , " " ) ;
IMaterialVar * pBloomAmountVar = pBloomMaterial - > FindVar ( " $bloomamount " , NULL ) ;
pBloomAmountVar - > SetFloatValue ( flBloomScale ) ;
PostProcessingPass * selectedHDR ;
if ( flBloomScale > 0.0 )
{
selectedHDR = HDRFinal_Float ;
}
else
{
selectedHDR = HDRFinal_Float_NoBloom ;
}
if ( mat_show_ab_hdr . GetInt ( ) )
{
ClipBox splitScreenClip ;
splitScreenClip . m_minx = splitScreenClip . m_miny = 0 ;
// Left half
splitScreenClip . m_maxx = dest_width / 2 ;
splitScreenClip . m_maxy = dest_height - 1 ;
ApplyPostProcessingPasses ( HDRSimulate_NonHDR , & splitScreenClip ) ;
// Right half
splitScreenClip . m_minx = splitScreenClip . m_maxx ;
splitScreenClip . m_maxx = dest_width - 1 ;
ApplyPostProcessingPasses ( selectedHDR , & splitScreenClip ) ;
}
else
{
ApplyPostProcessingPasses ( selectedHDR ) ;
}
pRenderContext - > SetRenderTarget ( NULL ) ;
if ( mat_show_histogram . GetInt ( ) & & ( engine - > GetDXSupportLevel ( ) > = 90 ) )
g_HDR_HistogramSystem . DisplayHistogram ( ) ;
if ( mat_dynamic_tonemapping . GetInt ( ) )
{
float avg_lum = MAX ( 0.0001 , g_HDR_HistogramSystem . GetTargetTonemapScalar ( ) ) ;
float scalevalue = MAX ( flAutoExposureMin ,
MIN ( flAutoExposureMax , 0.023 / avg_lum ) ) ;
SetToneMapScale ( pRenderContext , scalevalue , flAutoExposureMin , flAutoExposureMax ) ;
}
pRenderContext - > SetRenderTarget ( NULL ) ;
break ;
}
}
# if defined( _X360 )
pRenderContext - > PopVertexShaderGPRAllocation ( ) ;
# endif
}
// Motion Blur Material Proxy =========================================================================================
static float g_vMotionBlurValues [ 4 ] = { 0.0f , 0.0f , 0.0f , 0.0f } ;
class CMotionBlurMaterialProxy : public CEntityMaterialProxy
{
public :
CMotionBlurMaterialProxy ( ) ;
virtual ~ CMotionBlurMaterialProxy ( ) ;
virtual bool Init ( IMaterial * pMaterial , KeyValues * pKeyValues ) ;
virtual void OnBind ( C_BaseEntity * pEntity ) ;
virtual IMaterial * GetMaterial ( ) ;
private :
IMaterialVar * m_pMaterialParam ;
} ;
CMotionBlurMaterialProxy : : CMotionBlurMaterialProxy ( )
{
m_pMaterialParam = NULL ;
}
CMotionBlurMaterialProxy : : ~ CMotionBlurMaterialProxy ( )
{
// Do nothing
}
bool CMotionBlurMaterialProxy : : Init ( IMaterial * pMaterial , KeyValues * pKeyValues )
{
bool bFoundVar = false ;
m_pMaterialParam = pMaterial - > FindVar ( " $MotionBlurInternal " , & bFoundVar , false ) ;
if ( bFoundVar = = false )
return false ;
return true ;
}
void CMotionBlurMaterialProxy : : OnBind ( C_BaseEntity * pEnt )
{
if ( m_pMaterialParam ! = NULL )
{
m_pMaterialParam - > SetVecValue ( g_vMotionBlurValues , 4 ) ;
}
}
IMaterial * CMotionBlurMaterialProxy : : GetMaterial ( )
{
if ( m_pMaterialParam = = NULL )
return NULL ;
return m_pMaterialParam - > GetOwningMaterial ( ) ;
}
EXPOSE_INTERFACE ( CMotionBlurMaterialProxy , IMaterialProxy , " MotionBlur " IMATERIAL_PROXY_INTERFACE_VERSION ) ;
//=====================================================================================================================
// Image-space Motion Blur ============================================================================================
//=====================================================================================================================
ConVar mat_motion_blur_enabled ( " mat_motion_blur_enabled " , " 1 " , FCVAR_ARCHIVE ) ;
ConVar mat_motion_blur_forward_enabled ( " mat_motion_blur_forward_enabled " , " 0 " ) ;
ConVar mat_motion_blur_falling_min ( " mat_motion_blur_falling_min " , " 10.0 " ) ;
ConVar mat_motion_blur_falling_max ( " mat_motion_blur_falling_max " , " 20.0 " ) ;
ConVar mat_motion_blur_falling_intensity ( " mat_motion_blur_falling_intensity " , " 1.0 " ) ;
//ConVar mat_motion_blur_roll_intensity( "mat_motion_blur_roll_intensity", "1.0" );
ConVar mat_motion_blur_rotation_intensity ( " mat_motion_blur_rotation_intensity " , " 1.0 " ) ;
ConVar mat_motion_blur_strength ( " mat_motion_blur_strength " , " 1.0 " ) ;
void DoImageSpaceMotionBlur ( const CViewSetup & view , int x , int y , int w , int h )
{
# ifdef CSS_PERF_TEST
return ;
# endif
if ( ( ! mat_motion_blur_enabled . GetInt ( ) ) | | ( g_pMaterialSystemHardwareConfig - > GetDXSupportLevel ( ) < 90 ) )
{
return ;
}
//======================================================================================================//
// Get these convars here to make it easier to remove them later and to default each client differently //
//======================================================================================================//
float flMotionBlurRotationIntensity = mat_motion_blur_rotation_intensity . GetFloat ( ) * 0.15f ; // The default is to not blur past 15% of the range
float flMotionBlurRollIntensity = 0.3f ; // * mat_motion_blur_roll_intensity.GetFloat(); // The default is to not blur past 30% of the range
float flMotionBlurFallingIntensity = mat_motion_blur_falling_intensity . GetFloat ( ) ;
float flMotionBlurFallingMin = mat_motion_blur_falling_min . GetFloat ( ) ;
float flMotionBlurFallingMax = mat_motion_blur_falling_max . GetFloat ( ) ;
float flMotionBlurGlobalStrength = mat_motion_blur_strength . GetFloat ( ) ;
//===============================================================================//
// Set global g_vMotionBlurValues[4] values so material proxy can get the values //
//===============================================================================//
if ( true )
{
//=====================//
// Previous frame data //
//=====================//
static float s_flLastTimeUpdate = 0.0f ;
static float s_flPreviousPitch = 0.0f ;
static float s_flPreviousYaw = 0.0f ;
static float s_vPreviousPositon [ 3 ] = { 0.0f , 0.0f , 0.0f } ;
static matrix3x4_t s_mPreviousFrameBasisVectors ;
static float s_flNoRotationalMotionBlurUntil = 0.0f ;
//float vPreviousSideVec[3] = { s_mPreviousFrameBasisVectors[0][1], s_mPreviousFrameBasisVectors[1][1], s_mPreviousFrameBasisVectors[2][1] };
//float vPreviousForwardVec[3] = { s_mPreviousFrameBasisVectors[0][0], s_mPreviousFrameBasisVectors[1][0], s_mPreviousFrameBasisVectors[2][0] };
//float vPreviousUpVec[3] = { s_mPreviousFrameBasisVectors[0][2], s_mPreviousFrameBasisVectors[1][2], s_mPreviousFrameBasisVectors[2][2] };
float flTimeElapsed = gpGlobals - > realtime - s_flLastTimeUpdate ;
//===================================//
// Get current pitch & wrap to +-180 //
//===================================//
float flCurrentPitch = view . angles [ PITCH ] ;
while ( flCurrentPitch > 180.0f )
flCurrentPitch - = 360.0f ;
while ( flCurrentPitch < - 180.0f )
flCurrentPitch + = 360.0f ;
//=================================//
// Get current yaw & wrap to +-180 //
//=================================//
float flCurrentYaw = view . angles [ YAW ] ;
while ( flCurrentYaw > 180.0f )
flCurrentYaw - = 360.0f ;
while ( flCurrentYaw < - 180.0f )
flCurrentYaw + = 360.0f ;
//engine->Con_NPrintf( 0, "Blur Pitch: %6.2f Yaw: %6.2f", flCurrentPitch, flCurrentYaw );
//engine->Con_NPrintf( 1, "Blur FOV: %6.2f Aspect: %6.2f Ortho: %s", view.fov, view.m_flAspectRatio, view.m_bOrtho ? "Yes" : "No" );
//===========================//
// Get current basis vectors //
//===========================//
matrix3x4_t mCurrentBasisVectors ;
AngleMatrix ( view . angles , mCurrentBasisVectors ) ;
float vCurrentSideVec [ 3 ] = { mCurrentBasisVectors [ 0 ] [ 1 ] , mCurrentBasisVectors [ 1 ] [ 1 ] , mCurrentBasisVectors [ 2 ] [ 1 ] } ;
float vCurrentForwardVec [ 3 ] = { mCurrentBasisVectors [ 0 ] [ 0 ] , mCurrentBasisVectors [ 1 ] [ 0 ] , mCurrentBasisVectors [ 2 ] [ 0 ] } ;
//float vCurrentUpVec[3] = { mCurrentBasisVectors[0][2], mCurrentBasisVectors[1][2], mCurrentBasisVectors[2][2] };
//======================//
// Get current position //
//======================//
float vCurrentPosition [ 3 ] = { view . origin . x , view . origin . y , view . origin . z } ;
//===============================================================//
// Evaluate change in position to determine if we need to update //
//===============================================================//
float vPositionChange [ 3 ] = { 0.0f , 0.0f , 0.0f } ;
VectorSubtract ( s_vPreviousPositon , vCurrentPosition , vPositionChange ) ;
if ( ( VectorLength ( vPositionChange ) > 30.0f ) & & ( flTimeElapsed > = 0.5f ) )
{
//=======================================================//
// If we moved a far distance in one frame and more than //
// half a second elapsed, disable motion blur this frame //
//=======================================================//
//engine->Con_NPrintf( 8, " Pos change && time > 0.5 seconds %f ", gpGlobals->realtime );
g_vMotionBlurValues [ 0 ] = 0.0f ;
g_vMotionBlurValues [ 1 ] = 0.0f ;
g_vMotionBlurValues [ 2 ] = 0.0f ;
g_vMotionBlurValues [ 3 ] = 0.0f ;
}
else if ( flTimeElapsed > ( 1.0f / 15.0f ) )
{
//==========================================//
// If slower than 15 fps, don't motion blur //
//==========================================//
g_vMotionBlurValues [ 0 ] = 0.0f ;
g_vMotionBlurValues [ 1 ] = 0.0f ;
g_vMotionBlurValues [ 2 ] = 0.0f ;
g_vMotionBlurValues [ 3 ] = 0.0f ;
}
else if ( VectorLength ( vPositionChange ) > 50.0f )
{
//================================================================================//
// We moved a far distance in a frame, use the same motion blur as last frame //
// because I think we just went through a portal (should we ifdef this behavior?) //
//================================================================================//
//engine->Con_NPrintf( 8, " Position changed %f units @ %.2f time ", VectorLength( vPositionChange ), gpGlobals->realtime );
s_flNoRotationalMotionBlurUntil = gpGlobals - > realtime + 1.0f ; // Wait a second until the portal craziness calms down
}
else
{
//====================//
// Normal update path //
//====================//
// Compute horizontal and vertical fov
float flHorizontalFov = view . fov ;
float flVerticalFov = ( view . m_flAspectRatio < = 0.0f ) ? ( view . fov ) : ( view . fov / view . m_flAspectRatio ) ;
//engine->Con_NPrintf( 2, "Horizontal Fov: %6.2f Vertical Fov: %6.2f", flHorizontalFov, flVerticalFov );
//=====================//
// Forward motion blur //
//=====================//
float flViewDotMotion = DotProduct ( vCurrentForwardVec , vPositionChange ) ;
if ( mat_motion_blur_forward_enabled . GetBool ( ) ) // Want forward and falling
g_vMotionBlurValues [ 2 ] = flViewDotMotion ;
else // Falling only
g_vMotionBlurValues [ 2 ] = flViewDotMotion * fabs ( vCurrentForwardVec [ 2 ] ) ; // Only want this if we're looking up or down;
//====================================//
// Yaw (Compensate for circle strafe) //
//====================================//
float flSideDotMotion = DotProduct ( vCurrentSideVec , vPositionChange ) ;
float flYawDiffOriginal = s_flPreviousYaw - flCurrentYaw ;
if ( ( ( s_flPreviousYaw - flCurrentYaw > 180.0f ) | | ( s_flPreviousYaw - flCurrentYaw < - 180.0f ) ) & &
( ( s_flPreviousYaw + flCurrentYaw > - 180.0f ) & & ( s_flPreviousYaw + flCurrentYaw < 180.0f ) ) )
flYawDiffOriginal = s_flPreviousYaw + flCurrentYaw ;
float flYawDiffAdjusted = flYawDiffOriginal + ( flSideDotMotion / 3.0f ) ; // Yes, 3.0 is a magic number, sue me
// Make sure the adjustment only lessens the effect, not magnify it or reverse it
if ( flYawDiffOriginal < 0.0f )
flYawDiffAdjusted = clamp ( flYawDiffAdjusted , flYawDiffOriginal , 0.0f ) ;
else
flYawDiffAdjusted = clamp ( flYawDiffAdjusted , 0.0f , flYawDiffOriginal ) ;
// Use pitch to dampen yaw
float flUndampenedYaw = flYawDiffAdjusted / flHorizontalFov ;
g_vMotionBlurValues [ 0 ] = flUndampenedYaw * ( 1.0f - ( fabs ( flCurrentPitch ) / 90.0f ) ) ; // Dampen horizontal yaw blur based on pitch
//engine->Con_NPrintf( 4, "flSideDotMotion: %6.2f yaw diff: %6.2f ( %6.2f, %6.2f )", flSideDotMotion, ( s_flPreviousYaw - flCurrentYaw ), flYawDiffOriginal, flYawDiffAdjusted );
//=======================================//
// Pitch (Compensate for forward motion) //
//=======================================//
float flPitchCompensateMask = 1.0f - ( ( 1.0f - fabs ( vCurrentForwardVec [ 2 ] ) ) * ( 1.0f - fabs ( vCurrentForwardVec [ 2 ] ) ) ) ;
float flPitchDiffOriginal = s_flPreviousPitch - flCurrentPitch ;
float flPitchDiffAdjusted = flPitchDiffOriginal ;
if ( flCurrentPitch > 0.0f )
flPitchDiffAdjusted = flPitchDiffOriginal - ( ( flViewDotMotion / 2.0f ) * flPitchCompensateMask ) ; // Yes, 2.0 is a magic number, sue me
else
flPitchDiffAdjusted = flPitchDiffOriginal + ( ( flViewDotMotion / 2.0f ) * flPitchCompensateMask ) ; // Yes, 2.0 is a magic number, sue me
// Make sure the adjustment only lessens the effect, not magnify it or reverse it
if ( flPitchDiffOriginal < 0.0f )
flPitchDiffAdjusted = clamp ( flPitchDiffAdjusted , flPitchDiffOriginal , 0.0f ) ;
else
flPitchDiffAdjusted = clamp ( flPitchDiffAdjusted , 0.0f , flPitchDiffOriginal ) ;
g_vMotionBlurValues [ 1 ] = flPitchDiffAdjusted / flVerticalFov ;
//engine->Con_NPrintf( 5, "flViewDotMotion %6.2f, flPitchCompensateMask %6.2f, flPitchDiffOriginal %6.2f, flPitchDiffAdjusted %6.2f, g_vMotionBlurValues[1] %6.2f", flViewDotMotion, flPitchCompensateMask, flPitchDiffOriginal, flPitchDiffAdjusted, g_vMotionBlurValues[1]);
//========================================================//
// Roll (Enabled when we're looking down and yaw changes) //
//========================================================//
g_vMotionBlurValues [ 3 ] = flUndampenedYaw ; // Roll starts out as undampened yaw intensity and is then scaled by pitch
g_vMotionBlurValues [ 3 ] * = ( fabs ( flCurrentPitch ) / 90.0f ) * ( fabs ( flCurrentPitch ) / 90.0f ) * ( fabs ( flCurrentPitch ) / 90.0f ) ; // Dampen roll based on pitch^3
//engine->Con_NPrintf( 4, "[2] before scale and bias: %6.2f", g_vMotionBlurValues[2] );
//engine->Con_NPrintf( 5, "[3] before scale and bias: %6.2f", g_vMotionBlurValues[3] );
//==============================================================//
// Time-adjust falling effect until we can do something smarter //
//==============================================================//
if ( flTimeElapsed > 0.0f )
g_vMotionBlurValues [ 2 ] / = flTimeElapsed * 30.0f ; // 1/30th of a second?
else
g_vMotionBlurValues [ 2 ] = 0.0f ;
// Scale and bias values after time adjustment
g_vMotionBlurValues [ 2 ] = clamp ( ( fabs ( g_vMotionBlurValues [ 2 ] ) - flMotionBlurFallingMin ) / ( flMotionBlurFallingMax - flMotionBlurFallingMin ) , 0.0f , 1.0f ) * ( g_vMotionBlurValues [ 2 ] > = 0.0f ? 1.0f : - 1.0f ) ;
g_vMotionBlurValues [ 2 ] / = 30.0f ; // To counter-adjust for time adjustment above
//=================//
// Apply intensity //
//=================//
g_vMotionBlurValues [ 0 ] * = flMotionBlurRotationIntensity * flMotionBlurGlobalStrength ;
g_vMotionBlurValues [ 1 ] * = flMotionBlurRotationIntensity * flMotionBlurGlobalStrength ;
g_vMotionBlurValues [ 2 ] * = flMotionBlurFallingIntensity * flMotionBlurGlobalStrength ;
g_vMotionBlurValues [ 3 ] * = flMotionBlurRollIntensity * flMotionBlurGlobalStrength ;
//===============================================================//
// Dampen motion blur from 100%-0% as fps drops from 50fps-30fps //
//===============================================================//
if ( ! IsX360 ( ) ) // I'm not doing this on the 360 yet since I can't test it
{
float flSlowFps = 30.0f ;
float flFastFps = 50.0f ;
float flCurrentFps = ( flTimeElapsed > 0.0f ) ? ( 1.0f / flTimeElapsed ) : 0.0f ;
float flDampenFactor = clamp ( ( ( flCurrentFps - flSlowFps ) / ( flFastFps - flSlowFps ) ) , 0.0f , 1.0f ) ;
//engine->Con_NPrintf( 4, "gpGlobals->realtime %.2f gpGlobals->curtime %.2f", gpGlobals->realtime, gpGlobals->curtime );
//engine->Con_NPrintf( 5, "flCurrentFps %.2f", flCurrentFps );
//engine->Con_NPrintf( 7, "flTimeElapsed %.2f", flTimeElapsed );
g_vMotionBlurValues [ 0 ] * = flDampenFactor ;
g_vMotionBlurValues [ 1 ] * = flDampenFactor ;
g_vMotionBlurValues [ 2 ] * = flDampenFactor ;
g_vMotionBlurValues [ 3 ] * = flDampenFactor ;
//engine->Con_NPrintf( 6, "Dampen: %.2f", flDampenFactor );
}
//engine->Con_NPrintf( 6, "Final values: { %6.2f%%, %6.2f%%, %6.2f%%, %6.2f%% }", g_vMotionBlurValues[0]*100.0f, g_vMotionBlurValues[1]*100.0f, g_vMotionBlurValues[2]*100.0f, g_vMotionBlurValues[3]*100.0f );
}
//============================================//
// Zero out blur if still in that time window //
//============================================//
if ( gpGlobals - > realtime < s_flNoRotationalMotionBlurUntil )
{
//engine->Con_NPrintf( 9, " No Rotation @ %f ", gpGlobals->realtime );
// Zero out rotational blur but leave forward/falling blur alone
g_vMotionBlurValues [ 0 ] = 0.0f ; // X
g_vMotionBlurValues [ 1 ] = 0.0f ; // Y
g_vMotionBlurValues [ 3 ] = 0.0f ; // Roll
}
else
{
s_flNoRotationalMotionBlurUntil = 0.0f ;
}
//====================================//
// Store current frame for next frame //
//====================================//
VectorCopy ( vCurrentPosition , s_vPreviousPositon ) ;
s_mPreviousFrameBasisVectors = mCurrentBasisVectors ;
s_flPreviousPitch = flCurrentPitch ;
s_flPreviousYaw = flCurrentYaw ;
s_flLastTimeUpdate = gpGlobals - > realtime ;
}
//=============================================================================================//
// Render quad and let material proxy pick up the g_vMotionBlurValues[4] values just set above //
//=============================================================================================//
if ( true )
{
CMatRenderContextPtr pRenderContext ( materials ) ;
//pRenderContext->PushRenderTargetAndViewport();
ITexture * pSrc = materials - > FindTexture ( " _rt_FullFrameFB " , TEXTURE_GROUP_RENDER_TARGET ) ;
int nSrcWidth = pSrc - > GetActualWidth ( ) ;
int nSrcHeight = pSrc - > GetActualHeight ( ) ;
int dest_width , dest_height , nDummy ;
pRenderContext - > GetViewport ( nDummy , nDummy , dest_width , dest_height ) ;
if ( g_pMaterialSystemHardwareConfig - > GetHDRType ( ) ! = HDR_TYPE_FLOAT )
{
UpdateScreenEffectTexture ( 0 , x , y , w , h , true ) ; // Do we need to check if we already did this?
}
// Get material pointer
IMaterial * pMatMotionBlur = materials - > FindMaterial ( " dev/motion_blur " , TEXTURE_GROUP_OTHER , true ) ;
//SetRenderTargetAndViewPort( dest_rt0 );
//pRenderContext->PopRenderTargetAndViewport();
if ( pMatMotionBlur ! = NULL )
{
pRenderContext - > DrawScreenSpaceRectangle (
pMatMotionBlur ,
0 , 0 , dest_width , dest_height ,
0 , 0 , nSrcWidth - 1 , nSrcHeight - 1 ,
nSrcWidth , nSrcHeight , GetClientWorldEntity ( ) - > GetClientRenderable ( ) ) ;
if ( g_bDumpRenderTargets )
{
DumpTGAofRenderTarget ( dest_width , dest_height , " MotionBlur " ) ;
}
}
}
}