diff --git a/mp/src/game/client/viewrender.cpp b/mp/src/game/client/viewrender.cpp index a8ec8883..2747443b 100644 --- a/mp/src/game/client/viewrender.cpp +++ b/mp/src/game/client/viewrender.cpp @@ -1,6288 +1,6292 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: Responsible for drawing the scene -// -//===========================================================================// - -#include "cbase.h" -#include "view.h" -#include "iviewrender.h" -#include "view_shared.h" -#include "ivieweffects.h" -#include "iinput.h" -#include "model_types.h" -#include "clientsideeffects.h" -#include "particlemgr.h" -#include "viewrender.h" -#include "iclientmode.h" -#include "voice_status.h" -#include "glow_overlay.h" -#include "materialsystem/imesh.h" -#include "materialsystem/itexture.h" -#include "materialsystem/imaterial.h" -#include "materialsystem/imaterialvar.h" -#include "materialsystem/imaterialsystem.h" -#include "detailobjectsystem.h" -#include "tier0/vprof.h" -#include "tier1/mempool.h" -#include "vstdlib/jobthread.h" -#include "datacache/imdlcache.h" -#include "engine/IEngineTrace.h" -#include "engine/ivmodelinfo.h" -#include "tier0/icommandline.h" -#include "view_scene.h" -#include "particles_ez.h" -#include "engine/IStaticPropMgr.h" -#include "engine/ivdebugoverlay.h" -#include "c_pixel_visibility.h" -#include "clienteffectprecachesystem.h" -#include "c_rope.h" -#include "c_effects.h" -#include "smoke_fog_overlay.h" -#include "materialsystem/imaterialsystemhardwareconfig.h" -#include "VGuiMatSurface/IMatSystemSurface.h" -#include "vgui_int.h" -#include "ienginevgui.h" -#include "ScreenSpaceEffects.h" -#include "toolframework_client.h" -#include "c_func_reflective_glass.h" -#include "KeyValues.h" -#include "renderparm.h" -#include "studio_stats.h" -#include "con_nprint.h" -#include "clientmode_shared.h" -#include "sourcevr/isourcevirtualreality.h" -#include "client_virtualreality.h" - -#ifdef PORTAL -//#include "C_Portal_Player.h" -#include "portal_render_targets.h" -#include "PortalRender.h" -#endif -#if defined( HL2_CLIENT_DLL ) || defined( CSTRIKE_DLL ) -#define USE_MONITORS -#endif -#include "rendertexture.h" -#include "viewpostprocess.h" -#include "viewdebug.h" - -#if defined USES_ECON_ITEMS -#include "econ_wearable.h" -#endif - -#ifdef USE_MONITORS -#include "c_point_camera.h" -#endif // USE_MONITORS - -// Projective textures -#include "C_Env_Projected_Texture.h" - -#if defined (WIN32) -#include "ShaderEditor/ShaderEditorSystem.h" // FF --> hlstriker: Added -#endif -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - - -static void testfreezeframe_f( void ) -{ - view->FreezeFrame( 3.0 ); -} -static ConCommand test_freezeframe( "test_freezeframe", testfreezeframe_f, "Test the freeze frame code.", FCVAR_CHEAT ); - -//----------------------------------------------------------------------------- - -static ConVar r_visocclusion( "r_visocclusion", "0", FCVAR_CHEAT ); -extern ConVar r_flashlightdepthtexture; -extern ConVar vcollide_wireframe; -extern ConVar mat_motion_blur_enabled; -extern ConVar r_depthoverlay; -extern ConVar mat_viewportscale; -extern ConVar mat_viewportupscale; -extern bool g_bDumpRenderTargets; - -//----------------------------------------------------------------------------- -// Convars related to controlling rendering -//----------------------------------------------------------------------------- -static ConVar cl_maxrenderable_dist("cl_maxrenderable_dist", "3000", FCVAR_CHEAT, "Max distance from the camera at which things will be rendered" ); - -ConVar r_entityclips( "r_entityclips", "1" ); //FIXME: Nvidia drivers before 81.94 on cards that support user clip planes will have problems with this, require driver update? Detect and disable? - -// Matches the version in the engine -static ConVar r_drawopaqueworld( "r_drawopaqueworld", "1", FCVAR_CHEAT ); -static ConVar r_drawtranslucentworld( "r_drawtranslucentworld", "1", FCVAR_CHEAT ); -static ConVar r_3dsky( "r_3dsky","1", 0, "Enable the rendering of 3d sky boxes" ); -static ConVar r_skybox( "r_skybox","1", FCVAR_CHEAT, "Enable the rendering of sky boxes" ); -#ifdef TF_CLIENT_DLL -ConVar r_drawviewmodel( "r_drawviewmodel","1", FCVAR_ARCHIVE ); -#else -ConVar r_drawviewmodel( "r_drawviewmodel","1", FCVAR_CHEAT ); -#endif -static ConVar r_drawtranslucentrenderables( "r_drawtranslucentrenderables", "1", FCVAR_CHEAT ); -static ConVar r_drawopaquerenderables( "r_drawopaquerenderables", "1", FCVAR_CHEAT ); -static ConVar r_threaded_renderables( "r_threaded_renderables", "0" ); - -// FIXME: This is not static because we needed to turn it off for TF2 playtests -ConVar r_DrawDetailProps( "r_DrawDetailProps", "1", FCVAR_NONE, "0=Off, 1=Normal, 2=Wireframe" ); - -ConVar r_worldlistcache( "r_worldlistcache", "1" ); - -//----------------------------------------------------------------------------- -// Convars related to fog color -//----------------------------------------------------------------------------- -static ConVar fog_override( "fog_override", "0", FCVAR_CHEAT ); -// set any of these to use the maps fog -static ConVar fog_start( "fog_start", "-1", FCVAR_CHEAT ); -static ConVar fog_end( "fog_end", "-1", FCVAR_CHEAT ); -static ConVar fog_color( "fog_color", "-1 -1 -1", FCVAR_CHEAT ); -static ConVar fog_enable( "fog_enable", "1", FCVAR_CHEAT ); -static ConVar fog_startskybox( "fog_startskybox", "-1", FCVAR_CHEAT ); -static ConVar fog_endskybox( "fog_endskybox", "-1", FCVAR_CHEAT ); -static ConVar fog_maxdensityskybox( "fog_maxdensityskybox", "-1", FCVAR_CHEAT ); -static ConVar fog_colorskybox( "fog_colorskybox", "-1 -1 -1", FCVAR_CHEAT ); -static ConVar fog_enableskybox( "fog_enableskybox", "1", FCVAR_CHEAT ); -static ConVar fog_maxdensity( "fog_maxdensity", "-1", FCVAR_CHEAT ); - - -//----------------------------------------------------------------------------- -// Water-related convars -//----------------------------------------------------------------------------- -static ConVar r_debugcheapwater( "r_debugcheapwater", "0", FCVAR_CHEAT ); -#ifndef _X360 -static ConVar r_waterforceexpensive( "r_waterforceexpensive", "0", FCVAR_ARCHIVE ); -#endif -static ConVar r_waterforcereflectentities( "r_waterforcereflectentities", "0" ); -static ConVar r_WaterDrawRefraction( "r_WaterDrawRefraction", "1", 0, "Enable water refraction" ); -static ConVar r_WaterDrawReflection( "r_WaterDrawReflection", "1", 0, "Enable water reflection" ); -static ConVar r_ForceWaterLeaf( "r_ForceWaterLeaf", "1", 0, "Enable for optimization to water - considers view in leaf under water for purposes of culling" ); -static ConVar mat_drawwater( "mat_drawwater", "1", FCVAR_CHEAT ); -static ConVar mat_clipz( "mat_clipz", "1" ); - - -//----------------------------------------------------------------------------- -// Other convars -//----------------------------------------------------------------------------- -static ConVar r_screenfademinsize( "r_screenfademinsize", "0" ); -static ConVar r_screenfademaxsize( "r_screenfademaxsize", "0" ); -static ConVar cl_drawmonitors( "cl_drawmonitors", "1" ); -static ConVar r_eyewaterepsilon( "r_eyewaterepsilon", "10.0f", FCVAR_CHEAT ); - -#ifdef TF_CLIENT_DLL -static ConVar pyro_dof( "pyro_dof", "1", FCVAR_ARCHIVE ); -#endif - -extern ConVar cl_leveloverview; - -extern ConVar localplayer_visionflags; - -//----------------------------------------------------------------------------- -// Globals -//----------------------------------------------------------------------------- -static Vector g_vecCurrentRenderOrigin(0,0,0); -static QAngle g_vecCurrentRenderAngles(0,0,0); -static Vector g_vecCurrentVForward(0,0,0), g_vecCurrentVRight(0,0,0), g_vecCurrentVUp(0,0,0); -static VMatrix g_matCurrentCamInverse; -bool s_bCanAccessCurrentView = false; -IntroData_t *g_pIntroData = NULL; -static bool g_bRenderingView = false; // For debugging... -static int g_CurrentViewID = VIEW_NONE; -bool g_bRenderingScreenshot = false; - - -#define FREEZECAM_SNAPSHOT_FADE_SPEED 340 -float g_flFreezeFlash = 0.0f; - -//----------------------------------------------------------------------------- - -CON_COMMAND( r_cheapwaterstart, "" ) -{ - if( args.ArgC() == 2 ) - { - float dist = atof( args[ 1 ] ); - view->SetCheapWaterStartDistance( dist ); - } - else - { - float start, end; - view->GetWaterLODParams( start, end ); - Warning( "r_cheapwaterstart: %f\n", start ); - } -} - -CON_COMMAND( r_cheapwaterend, "" ) -{ - if( args.ArgC() == 2 ) - { - float dist = atof( args[ 1 ] ); - view->SetCheapWaterEndDistance( dist ); - } - else - { - float start, end; - view->GetWaterLODParams( start, end ); - Warning( "r_cheapwaterend: %f\n", end ); - } -} - - - -//----------------------------------------------------------------------------- -// Describes a pruned set of leaves to be rendered this view. Reference counted -// because potentially shared by a number of views -//----------------------------------------------------------------------------- -struct ClientWorldListInfo_t : public CRefCounted1 -{ - ClientWorldListInfo_t() - { - memset( (WorldListInfo_t *)this, 0, sizeof(WorldListInfo_t) ); - m_pActualLeafIndex = NULL; - m_bPooledAlloc = false; - } - - // Allocate a list intended for pruning - static ClientWorldListInfo_t *AllocPooled( const ClientWorldListInfo_t &exemplar ); - - // Because we remap leaves to eliminate unused leaves, we need a remap - // when drawing translucent surfaces, which requires the *original* leaf index - // using m_pActualLeafMap[ remapped leaf index ] == actual leaf index - LeafIndex_t *m_pActualLeafIndex; - -private: - virtual bool OnFinalRelease(); - - bool m_bPooledAlloc; - static CObjectPool gm_Pool; -}; - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- - -class CWorldListCache -{ -public: - CWorldListCache() - { - - } - void Flush() - { - for ( int i = m_Entries.FirstInorder(); i != m_Entries.InvalidIndex(); i = m_Entries.NextInorder( i ) ) - { - delete m_Entries[i]; - } - m_Entries.RemoveAll(); - } - - bool Find( const CViewSetup &viewSetup, IWorldRenderList **ppList, ClientWorldListInfo_t **ppListInfo ) - { - Entry_t lookup( viewSetup ); - - int i = m_Entries.Find( &lookup ); - - if ( i != m_Entries.InvalidIndex() ) - { - Entry_t *pEntry = m_Entries[i]; - *ppList = InlineAddRef( pEntry->pList ); - *ppListInfo = InlineAddRef( pEntry->pListInfo ); - return true; - } - - return false; - } - - void Add( const CViewSetup &viewSetup, IWorldRenderList *pList, ClientWorldListInfo_t *pListInfo ) - { - m_Entries.Insert( new Entry_t( viewSetup, pList, pListInfo ) ); - } - -private: - struct Entry_t - { - Entry_t( const CViewSetup &viewSetup, IWorldRenderList *pList = NULL, ClientWorldListInfo_t *pListInfo = NULL ) : - pList( ( pList ) ? InlineAddRef( pList ) : NULL ), - pListInfo( ( pListInfo ) ? InlineAddRef( pListInfo ) : NULL ) - { - // @NOTE (toml 8/18/2006): because doing memcmp, need to fill all of the fields and the padding! - memset( &m_bOrtho, 0, offsetof(Entry_t, pList ) - offsetof(Entry_t, m_bOrtho ) ); - m_bOrtho = viewSetup.m_bOrtho; - m_OrthoLeft = viewSetup.m_OrthoLeft; - m_OrthoTop = viewSetup.m_OrthoTop; - m_OrthoRight = viewSetup.m_OrthoRight; - m_OrthoBottom = viewSetup.m_OrthoBottom; - fov = viewSetup.fov; - origin = viewSetup.origin; - angles = viewSetup.angles; - zNear = viewSetup.zNear; - zFar = viewSetup.zFar; - m_flAspectRatio = viewSetup.m_flAspectRatio; - m_bOffCenter = viewSetup.m_bOffCenter; - m_flOffCenterTop = viewSetup.m_flOffCenterTop; - m_flOffCenterBottom = viewSetup.m_flOffCenterBottom; - m_flOffCenterLeft = viewSetup.m_flOffCenterLeft; - m_flOffCenterRight = viewSetup.m_flOffCenterRight; - } - - ~Entry_t() - { - if ( pList ) - pList->Release(); - if ( pListInfo ) - pListInfo->Release(); - } - - // The fields from CViewSetup that would actually affect the list - float m_OrthoLeft; - float m_OrthoTop; - float m_OrthoRight; - float m_OrthoBottom; - float fov; - Vector origin; - QAngle angles; - float zNear; - float zFar; - float m_flAspectRatio; - float m_flOffCenterTop; - float m_flOffCenterBottom; - float m_flOffCenterLeft; - float m_flOffCenterRight; - bool m_bOrtho; - bool m_bOffCenter; - - IWorldRenderList *pList; - ClientWorldListInfo_t *pListInfo; - }; - - class CEntryComparator - { - public: - CEntryComparator( int ) {} - bool operator!() const { return false; } - bool operator()( const Entry_t *lhs, const Entry_t *rhs ) const - { - return ( memcmp( lhs, rhs, sizeof(Entry_t) - ( sizeof(Entry_t) - offsetof(Entry_t, pList ) ) ) < 0 ); - } - }; - - CUtlRBTree m_Entries; -}; - -CWorldListCache g_WorldListCache; - -//----------------------------------------------------------------------------- -// Standard 3d skybox view -//----------------------------------------------------------------------------- -class CSkyboxView : public CRendering3dView -{ - DECLARE_CLASS( CSkyboxView, CRendering3dView ); -public: - CSkyboxView(CViewRender *pMainView) : - CRendering3dView( pMainView ), - m_pSky3dParams( NULL ) - { - } - - bool Setup( const CViewSetup &view, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible ); - void Draw(); - -protected: - -#ifdef PORTAL - virtual bool ShouldDrawPortals() { return false; } -#endif - - virtual SkyboxVisibility_t ComputeSkyboxVisibility(); - - bool GetSkyboxFogEnable(); - - void Enable3dSkyboxFog( void ); - void DrawInternal( view_id_t iSkyBoxViewID, bool bInvokePreAndPostRender, ITexture *pRenderTarget, ITexture *pDepthTarget ); - - sky3dparams_t * PreRender3dSkyboxWorld( SkyboxVisibility_t nSkyboxVisible ); - - sky3dparams_t *m_pSky3dParams; -}; - -//----------------------------------------------------------------------------- -// 3d skybox view when drawing portals -//----------------------------------------------------------------------------- -#ifdef PORTAL -class CPortalSkyboxView : public CSkyboxView -{ - DECLARE_CLASS( CPortalSkyboxView, CSkyboxView ); -public: - CPortalSkyboxView(CViewRender *pMainView) : - CSkyboxView( pMainView ), - m_pRenderTarget( NULL ) - {} - - bool Setup( const CViewSetup &view, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible, ITexture *pRenderTarget = NULL ); - - //Skybox drawing through portals with workarounds to fix area bits, position/scaling, view id's.......... - void Draw(); - -private: - virtual SkyboxVisibility_t ComputeSkyboxVisibility(); - - ITexture *m_pRenderTarget; -}; -#endif - - -//----------------------------------------------------------------------------- -// Shadow depth texture -//----------------------------------------------------------------------------- -class CShadowDepthView : public CRendering3dView -{ - DECLARE_CLASS( CShadowDepthView, CRendering3dView ); -public: - CShadowDepthView(CViewRender *pMainView) : CRendering3dView( pMainView ) {} - - void Setup( const CViewSetup &shadowViewIn, ITexture *pRenderTarget, ITexture *pDepthTexture ); - void Draw(); - -private: - ITexture *m_pRenderTarget; - ITexture *m_pDepthTexture; -}; - -//----------------------------------------------------------------------------- -// Freeze frame. Redraws the frame at which it was enabled. -//----------------------------------------------------------------------------- -class CFreezeFrameView : public CRendering3dView -{ - DECLARE_CLASS( CFreezeFrameView, CRendering3dView ); -public: - CFreezeFrameView(CViewRender *pMainView) : CRendering3dView( pMainView ) {} - - void Setup( const CViewSetup &view ); - void Draw(); - -private: - CMaterialReference m_pFreezeFrame; - CMaterialReference m_TranslucentSingleColor; -}; - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -class CBaseWorldView : public CRendering3dView -{ - DECLARE_CLASS( CBaseWorldView, CRendering3dView ); -protected: - CBaseWorldView(CViewRender *pMainView) : CRendering3dView( pMainView ) {} - - virtual bool AdjustView( float waterHeight ); - - void DrawSetup( float waterHeight, int flags, float waterZAdjust, int iForceViewLeaf = -1 ); - void DrawExecute( float waterHeight, view_id_t viewID, float waterZAdjust ); - - virtual void PushView( float waterHeight ); - virtual void PopView(); - - void SSAO_DepthPass(); - void DrawDepthOfField(); -}; - - -//----------------------------------------------------------------------------- -// Draws the scene when there's no water or only cheap water -//----------------------------------------------------------------------------- -class CSimpleWorldView : public CBaseWorldView -{ - DECLARE_CLASS( CSimpleWorldView, CBaseWorldView ); -public: - CSimpleWorldView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} - - void Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& info, ViewCustomVisibility_t *pCustomVisibility = NULL ); - void Draw(); - -private: - VisibleFogVolumeInfo_t m_fogInfo; - -}; - - -//----------------------------------------------------------------------------- -// Base class for scenes with water -//----------------------------------------------------------------------------- -class CBaseWaterView : public CBaseWorldView -{ - DECLARE_CLASS( CBaseWaterView, CBaseWorldView ); -public: - CBaseWaterView(CViewRender *pMainView) : - CBaseWorldView( pMainView ), - m_SoftwareIntersectionView( pMainView ) - {} - - // void Setup( const CViewSetup &, const WaterRenderInfo_t& info ); - -protected: - void CalcWaterEyeAdjustments( const VisibleFogVolumeInfo_t &fogInfo, float &newWaterHeight, float &waterZAdjust, bool bSoftwareUserClipPlane ); - - class CSoftwareIntersectionView : public CBaseWorldView - { - DECLARE_CLASS( CSoftwareIntersectionView, CBaseWorldView ); - public: - CSoftwareIntersectionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} - - void Setup( bool bAboveWater ); - void Draw(); - - private: - CBaseWaterView *GetOuter() { return GET_OUTER( CBaseWaterView, m_SoftwareIntersectionView ); } - }; - - friend class CSoftwareIntersectionView; - - CSoftwareIntersectionView m_SoftwareIntersectionView; - - WaterRenderInfo_t m_waterInfo; - float m_waterHeight; - float m_waterZAdjust; - bool m_bSoftwareUserClipPlane; - VisibleFogVolumeInfo_t m_fogInfo; -}; - - -//----------------------------------------------------------------------------- -// Scenes above water -//----------------------------------------------------------------------------- -class CAboveWaterView : public CBaseWaterView -{ - DECLARE_CLASS( CAboveWaterView, CBaseWaterView ); -public: - CAboveWaterView(CViewRender *pMainView) : - CBaseWaterView( pMainView ), - m_ReflectionView( pMainView ), - m_RefractionView( pMainView ), - m_IntersectionView( pMainView ) - {} - - void Setup( const CViewSetup &view, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo ); - void Draw(); - - class CReflectionView : public CBaseWorldView - { - DECLARE_CLASS( CReflectionView, CBaseWorldView ); - public: - CReflectionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} - - void Setup( bool bReflectEntities ); - void Draw(); - - private: - CAboveWaterView *GetOuter() { return GET_OUTER( CAboveWaterView, m_ReflectionView ); } - }; - - class CRefractionView : public CBaseWorldView - { - DECLARE_CLASS( CRefractionView, CBaseWorldView ); - public: - CRefractionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} - - void Setup(); - void Draw(); - - private: - CAboveWaterView *GetOuter() { return GET_OUTER( CAboveWaterView, m_RefractionView ); } - }; - - class CIntersectionView : public CBaseWorldView - { - DECLARE_CLASS( CIntersectionView, CBaseWorldView ); - public: - CIntersectionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} - - void Setup(); - void Draw(); - - private: - CAboveWaterView *GetOuter() { return GET_OUTER( CAboveWaterView, m_IntersectionView ); } - }; - - - friend class CRefractionView; - friend class CReflectionView; - friend class CIntersectionView; - - bool m_bViewIntersectsWater; - - CReflectionView m_ReflectionView; - CRefractionView m_RefractionView; - CIntersectionView m_IntersectionView; -}; - - -//----------------------------------------------------------------------------- -// Scenes below water -//----------------------------------------------------------------------------- -class CUnderWaterView : public CBaseWaterView -{ - DECLARE_CLASS( CUnderWaterView, CBaseWaterView ); -public: - CUnderWaterView(CViewRender *pMainView) : - CBaseWaterView( pMainView ), - m_RefractionView( pMainView ) - {} - - void Setup( const CViewSetup &view, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& info ); - void Draw(); - - class CRefractionView : public CBaseWorldView - { - DECLARE_CLASS( CRefractionView, CBaseWorldView ); - public: - CRefractionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} - - void Setup(); - void Draw(); - - private: - CUnderWaterView *GetOuter() { return GET_OUTER( CUnderWaterView, m_RefractionView ); } - }; - - friend class CRefractionView; - - bool m_bDrawSkybox; // @MULTICORE (toml 8/17/2006): remove after setup hoisted - - CRefractionView m_RefractionView; -}; - - -//----------------------------------------------------------------------------- -// Scenes containing reflective glass -//----------------------------------------------------------------------------- -class CReflectiveGlassView : public CSimpleWorldView -{ - DECLARE_CLASS( CReflectiveGlassView, CSimpleWorldView ); -public: - CReflectiveGlassView( CViewRender *pMainView ) : BaseClass( pMainView ) - { - } - - virtual bool AdjustView( float flWaterHeight ); - virtual void PushView( float waterHeight ); - virtual void PopView( ); - void Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane ); - void Draw(); - - cplane_t m_ReflectionPlane; -}; - -class CRefractiveGlassView : public CSimpleWorldView -{ - DECLARE_CLASS( CRefractiveGlassView, CSimpleWorldView ); -public: - CRefractiveGlassView( CViewRender *pMainView ) : BaseClass( pMainView ) - { - } - - virtual bool AdjustView( float flWaterHeight ); - virtual void PushView( float waterHeight ); - virtual void PopView( ); - void Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane ); - void Draw(); - - cplane_t m_ReflectionPlane; -}; - - -//----------------------------------------------------------------------------- -// Computes draw flags for the engine to build its world surface lists -//----------------------------------------------------------------------------- -static inline unsigned long BuildEngineDrawWorldListFlags( unsigned nDrawFlags ) -{ - unsigned long nEngineFlags = 0; - - if ( nDrawFlags & DF_DRAWSKYBOX ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_SKYBOX; - } - - if ( nDrawFlags & DF_RENDER_ABOVEWATER ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_STRICTLYABOVEWATER; - nEngineFlags |= DRAWWORLDLISTS_DRAW_INTERSECTSWATER; - } - - if ( nDrawFlags & DF_RENDER_UNDERWATER ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_STRICTLYUNDERWATER; - nEngineFlags |= DRAWWORLDLISTS_DRAW_INTERSECTSWATER; - } - - if ( nDrawFlags & DF_RENDER_WATER ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_WATERSURFACE; - } - - if( nDrawFlags & DF_CLIP_SKYBOX ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_CLIPSKYBOX; - } - - if( nDrawFlags & DF_SHADOW_DEPTH_MAP ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_SHADOWDEPTH; - } - - if( nDrawFlags & DF_RENDER_REFRACTION ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_REFRACTION; - } - - if( nDrawFlags & DF_RENDER_REFLECTION ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_REFLECTION; - } - - if( nDrawFlags & DF_SSAO_DEPTH_PASS ) - { - nEngineFlags |= DRAWWORLDLISTS_DRAW_SSAO | DRAWWORLDLISTS_DRAW_STRICTLYUNDERWATER | DRAWWORLDLISTS_DRAW_INTERSECTSWATER | DRAWWORLDLISTS_DRAW_STRICTLYABOVEWATER ; - nEngineFlags &= ~( DRAWWORLDLISTS_DRAW_WATERSURFACE | DRAWWORLDLISTS_DRAW_REFRACTION | DRAWWORLDLISTS_DRAW_REFLECTION ); - } - - return nEngineFlags; -} - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -static void SetClearColorToFogColor() -{ - unsigned char ucFogColor[3]; - CMatRenderContextPtr pRenderContext( materials ); - pRenderContext->GetFogColor( ucFogColor ); - if( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER ) - { - // @MULTICORE (toml 8/16/2006): Find a way to not do this twice in eye above water case - float scale = LinearToGammaFullRange( pRenderContext->GetToneMappingScaleLinear().x ); - ucFogColor[0] *= scale; - ucFogColor[1] *= scale; - ucFogColor[2] *= scale; - } - pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); -} - -//----------------------------------------------------------------------------- -// Precache of necessary materials -//----------------------------------------------------------------------------- - -#ifdef HL2_CLIENT_DLL -CLIENTEFFECT_REGISTER_BEGIN( PrecacheViewRender ) - CLIENTEFFECT_MATERIAL( "scripted/intro_screenspaceeffect" ) -CLIENTEFFECT_REGISTER_END() -#endif - -CLIENTEFFECT_REGISTER_BEGIN( PrecachePostProcessingEffects ) - CLIENTEFFECT_MATERIAL( "dev/blurfiltery_and_add_nohdr" ) - CLIENTEFFECT_MATERIAL( "dev/blurfilterx" ) - CLIENTEFFECT_MATERIAL( "dev/blurfilterx_nohdr" ) - CLIENTEFFECT_MATERIAL( "dev/blurfiltery" ) - CLIENTEFFECT_MATERIAL( "dev/blurfiltery_nohdr" ) - CLIENTEFFECT_MATERIAL( "dev/bloomadd" ) - CLIENTEFFECT_MATERIAL( "dev/downsample" ) - #ifdef CSTRIKE_DLL - CLIENTEFFECT_MATERIAL( "dev/downsample_non_hdr_cstrike" ) - #else - CLIENTEFFECT_MATERIAL( "dev/downsample_non_hdr" ) - #endif - CLIENTEFFECT_MATERIAL( "dev/no_pixel_write" ) - CLIENTEFFECT_MATERIAL( "dev/lumcompare" ) - CLIENTEFFECT_MATERIAL( "dev/floattoscreen_combine" ) - CLIENTEFFECT_MATERIAL( "dev/copyfullframefb_vanilla" ) - CLIENTEFFECT_MATERIAL( "dev/copyfullframefb" ) - CLIENTEFFECT_MATERIAL( "dev/engine_post" ) - CLIENTEFFECT_MATERIAL( "dev/motion_blur" ) - CLIENTEFFECT_MATERIAL( "dev/upscale" ) - -#ifdef TF_CLIENT_DLL - CLIENTEFFECT_MATERIAL( "dev/pyro_blur_filter_y" ) - CLIENTEFFECT_MATERIAL( "dev/pyro_blur_filter_x" ) - CLIENTEFFECT_MATERIAL( "dev/pyro_dof" ) - CLIENTEFFECT_MATERIAL( "dev/pyro_vignette_border" ) - CLIENTEFFECT_MATERIAL( "dev/pyro_vignette" ) - CLIENTEFFECT_MATERIAL( "dev/pyro_post" ) -#endif - - // FF --> hlstriker: Added. -#ifdef GLOWS_ENABLE - CLIENTEFFECT_MATERIAL( "dev/glow_color" ) - CLIENTEFFECT_MATERIAL( "dev/halo_add_to_screen" ) -#endif - // FF <-- -CLIENTEFFECT_REGISTER_END_CONDITIONAL( engine->GetDXSupportLevel() >= 90 ) - -//----------------------------------------------------------------------------- -// Accessors to return the current view being rendered -//----------------------------------------------------------------------------- -const Vector &CurrentViewOrigin() -{ - Assert( s_bCanAccessCurrentView ); - return g_vecCurrentRenderOrigin; -} - -const QAngle &CurrentViewAngles() -{ - Assert( s_bCanAccessCurrentView ); - return g_vecCurrentRenderAngles; -} - -const Vector &CurrentViewForward() -{ - Assert( s_bCanAccessCurrentView ); - return g_vecCurrentVForward; -} - -const Vector &CurrentViewRight() -{ - Assert( s_bCanAccessCurrentView ); - return g_vecCurrentVRight; -} - -const Vector &CurrentViewUp() -{ - Assert( s_bCanAccessCurrentView ); - return g_vecCurrentVUp; -} - -const VMatrix &CurrentWorldToViewMatrix() -{ - Assert( s_bCanAccessCurrentView ); - return g_matCurrentCamInverse; -} - - -//----------------------------------------------------------------------------- -// Methods to set the current view/guard access to view parameters -//----------------------------------------------------------------------------- -void AllowCurrentViewAccess( bool allow ) -{ - s_bCanAccessCurrentView = allow; -} - -bool IsCurrentViewAccessAllowed() -{ - return s_bCanAccessCurrentView; -} - -void SetupCurrentView( const Vector &vecOrigin, const QAngle &angles, view_id_t viewID ) -{ - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - // Store off view origin and angles - g_vecCurrentRenderOrigin = vecOrigin; - g_vecCurrentRenderAngles = angles; - - // Compute the world->main camera transform - ComputeCameraVariables( vecOrigin, angles, - &g_vecCurrentVForward, &g_vecCurrentVRight, &g_vecCurrentVUp, &g_matCurrentCamInverse ); - - g_CurrentViewID = viewID; - s_bCanAccessCurrentView = true; - - // Cache off fade distances - float flScreenFadeMinSize, flScreenFadeMaxSize; - view->GetScreenFadeDistances( &flScreenFadeMinSize, &flScreenFadeMaxSize ); - modelinfo->SetViewScreenFadeRange( flScreenFadeMinSize, flScreenFadeMaxSize ); - - CMatRenderContextPtr pRenderContext( materials ); -#ifdef PORTAL - if ( g_pPortalRender->GetViewRecursionLevel() == 0 ) - { - pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, ((viewID == VIEW_MAIN) || (viewID == VIEW_3DSKY)) ? 1 : 0 ); - } -#else - pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, ((viewID == VIEW_MAIN) || (viewID == VIEW_3DSKY)) ? 1 : 0 ); -#endif -} - -view_id_t CurrentViewID() -{ - Assert( g_CurrentViewID != VIEW_ILLEGAL ); - return ( view_id_t )g_CurrentViewID; -} - -//----------------------------------------------------------------------------- -// Purpose: Portal views are considered 'Main' views. This function tests a view id -// against all view ids used by portal renderables, as well as the main view. -//----------------------------------------------------------------------------- -bool IsMainView ( view_id_t id ) -{ -#if defined(PORTAL) - return ( (id == VIEW_MAIN) || g_pPortalRender->IsPortalViewID( id ) ); -#else - return (id == VIEW_MAIN); -#endif -} - -void FinishCurrentView() -{ - s_bCanAccessCurrentView = false; -} - -//----------------------------------------------------------------------------- -// Constructor -//----------------------------------------------------------------------------- -void CSimpleRenderExecutor::AddView( CRendering3dView *pView ) -{ - CBase3dView *pPrevRenderer = m_pMainView->SetActiveRenderer( pView ); - pView->Draw(); - m_pMainView->SetActiveRenderer( pPrevRenderer ); -} - -//----------------------------------------------------------------------------- -// Constructor -//----------------------------------------------------------------------------- -CViewRender::CViewRender() - : m_SimpleExecutor( this ) -{ - m_flCheapWaterStartDistance = 0.0f; - m_flCheapWaterEndDistance = 0.1f; - m_BaseDrawFlags = 0; - m_pActiveRenderer = NULL; - m_pCurrentlyDrawingEntity = NULL; -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -inline bool CViewRender::ShouldDrawEntities( void ) -{ - return ( !m_pDrawEntities || (m_pDrawEntities->GetInt() != 0) ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Check all conditions which would prevent drawing the view model -// Input : drawViewmodel - -// *viewmodel - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CViewRender::ShouldDrawViewModel( bool bDrawViewmodel ) -{ - if ( !bDrawViewmodel ) - return false; - - if ( !r_drawviewmodel.GetBool() ) - return false; - - if ( C_BasePlayer::ShouldDrawLocalPlayer() ) - return false; - - if ( !ShouldDrawEntities() ) - return false; - - if ( render->GetViewEntity() > gpGlobals->maxClients ) - return false; - - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -bool CViewRender::UpdateRefractIfNeededByList( CUtlVector< IClientRenderable * > &list ) -{ - int nCount = list.Count(); - for( int i=0; i < nCount; ++i ) - { - IClientUnknown *pUnk = list[i]->GetIClientUnknown(); - Assert( pUnk ); - - IClientRenderable *pRenderable = pUnk->GetClientRenderable(); - Assert( pRenderable ); - - if ( pRenderable->UsesPowerOfTwoFrameBufferTexture() ) - { - UpdateRefractTexture(); - return true; - } - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CViewRender::DrawRenderablesInList( CUtlVector< IClientRenderable * > &list, int flags ) -{ - Assert( m_pCurrentlyDrawingEntity == NULL ); - int nCount = list.Count(); - for( int i=0; i < nCount; ++i ) - { - IClientUnknown *pUnk = list[i]->GetIClientUnknown(); - Assert( pUnk ); - - IClientRenderable *pRenderable = pUnk->GetClientRenderable(); - Assert( pRenderable ); - - // Non-view models wanting to render in view model list... - if ( pRenderable->ShouldDraw() ) - { - m_pCurrentlyDrawingEntity = pUnk->GetBaseEntity(); - pRenderable->DrawModel( STUDIO_RENDER | flags ); - } - } - m_pCurrentlyDrawingEntity = NULL; -} - - -//----------------------------------------------------------------------------- -// Purpose: Actually draw the view model -// Input : drawViewModel - -//----------------------------------------------------------------------------- -void CViewRender::DrawViewModels( const CViewSetup &view, bool drawViewmodel ) -{ - VPROF( "CViewRender::DrawViewModel" ); - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - -#ifdef PORTAL //in portal, we'd like a copy of the front buffer without the gun in it for use with the depth doubler - g_pPortalRender->UpdateDepthDoublerTexture( view ); -#endif - - bool bShouldDrawPlayerViewModel = ShouldDrawViewModel( drawViewmodel ); - bool bShouldDrawToolViewModels = ToolsEnabled(); - - CMatRenderContextPtr pRenderContext( materials ); - - PIXEVENT( pRenderContext, "DrawViewModels" ); - - // Restore the matrices - pRenderContext->MatrixMode( MATERIAL_PROJECTION ); - pRenderContext->PushMatrix(); - - CViewSetup viewModelSetup( view ); - viewModelSetup.zNear = view.zNearViewmodel; - viewModelSetup.zFar = view.zFarViewmodel; - viewModelSetup.fov = view.fovViewmodel; - viewModelSetup.m_flAspectRatio = engine->GetScreenAspectRatio(); - - ITexture *pRTColor = NULL; - ITexture *pRTDepth = NULL; - if( view.m_eStereoEye != STEREO_EYE_MONO ) - { - pRTColor = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(view.m_eStereoEye-1), ISourceVirtualReality::RT_Color ); - pRTDepth = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(view.m_eStereoEye-1), ISourceVirtualReality::RT_Depth ); - } - - render->Push3DView( viewModelSetup, 0, pRTColor, GetFrustum(), pRTDepth ); - -#ifdef PORTAL //the depth range hack doesn't work well enough for the portal mod (and messing with the depth hack values makes some models draw incorrectly) - //step up to a full depth clear if we're extremely close to a portal (in a portal environment) - extern bool LocalPlayerIsCloseToPortal( void ); //defined in C_Portal_Player.cpp, abstracting to a single bool function to remove explicit dependence on c_portal_player.h/cpp, you can define the function as a "return true" in other build configurations at the cost of some perf - bool bUseDepthHack = !LocalPlayerIsCloseToPortal(); - if( !bUseDepthHack ) - pRenderContext->ClearBuffers( false, true, false ); -#else - const bool bUseDepthHack = true; -#endif - - // FIXME: Add code to read the current depth range - float depthmin = 0.0f; - float depthmax = 1.0f; - - // HACK HACK: Munge the depth range to prevent view model from poking into walls, etc. - // Force clipped down range - if( bUseDepthHack ) - pRenderContext->DepthRange( 0.0f, 0.1f ); - - if ( bShouldDrawPlayerViewModel || bShouldDrawToolViewModels ) - { - - CUtlVector< IClientRenderable * > opaqueViewModelList( 32 ); - CUtlVector< IClientRenderable * > translucentViewModelList( 32 ); - - ClientLeafSystem()->CollateViewModelRenderables( opaqueViewModelList, translucentViewModelList ); - - if ( ToolsEnabled() && ( !bShouldDrawPlayerViewModel || !bShouldDrawToolViewModels ) ) - { - int nOpaque = opaqueViewModelList.Count(); - for ( int i = nOpaque-1; i >= 0; --i ) - { - IClientRenderable *pRenderable = opaqueViewModelList[ i ]; - bool bEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); - if ( ( bEntity && !bShouldDrawPlayerViewModel ) || ( !bEntity && !bShouldDrawToolViewModels ) ) - { - opaqueViewModelList.FastRemove( i ); - } - } - - int nTranslucent = translucentViewModelList.Count(); - for ( int i = nTranslucent-1; i >= 0; --i ) - { - IClientRenderable *pRenderable = translucentViewModelList[ i ]; - bool bEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); - if ( ( bEntity && !bShouldDrawPlayerViewModel ) || ( !bEntity && !bShouldDrawToolViewModels ) ) - { - translucentViewModelList.FastRemove( i ); - } - } - } - - if ( !UpdateRefractIfNeededByList( opaqueViewModelList ) ) - { - UpdateRefractIfNeededByList( translucentViewModelList ); - } - - DrawRenderablesInList( opaqueViewModelList ); - DrawRenderablesInList( translucentViewModelList, STUDIO_TRANSPARENCY ); - } - - // Reset the depth range to the original values - if( bUseDepthHack ) - pRenderContext->DepthRange( depthmin, depthmax ); - - render->PopView( GetFrustum() ); - - // Restore the matrices - pRenderContext->MatrixMode( MATERIAL_PROJECTION ); - pRenderContext->PopMatrix(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CViewRender::ShouldDrawBrushModels( void ) -{ - if ( m_pDrawBrushModels && !m_pDrawBrushModels->GetInt() ) - return false; - - return true; -} - - -//----------------------------------------------------------------------------- -// Purpose: Performs screen space effects, if any -//----------------------------------------------------------------------------- -void CViewRender::PerformScreenSpaceEffects( int x, int y, int w, int h ) -{ - VPROF("CViewRender::PerformScreenSpaceEffects()"); - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - // FIXME: Screen-space effects are busted in the editor - if ( engine->IsHammerRunning() ) - return; - - g_pScreenSpaceEffects->RenderEffects( x, y, w, h ); -} - - -//----------------------------------------------------------------------------- -// Purpose: Sets the screen space effect material (can't be done during rendering) -//----------------------------------------------------------------------------- -void CViewRender::SetScreenOverlayMaterial( IMaterial *pMaterial ) -{ - m_ScreenOverlayMaterial.Init( pMaterial ); -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -IMaterial *CViewRender::GetScreenOverlayMaterial( ) -{ - return m_ScreenOverlayMaterial; -} - - -//----------------------------------------------------------------------------- -// Purpose: Performs screen space effects, if any -//----------------------------------------------------------------------------- -void CViewRender::PerformScreenOverlay( int x, int y, int w, int h ) -{ - VPROF("CViewRender::PerformScreenOverlay()"); - - if (m_ScreenOverlayMaterial) - { - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - if ( m_ScreenOverlayMaterial->NeedsFullFrameBufferTexture() ) - { - // FIXME: check with multi/sub-rect renders. Should this be 0,0,w,h instead? - DrawScreenEffectMaterial( m_ScreenOverlayMaterial, x, y, w, h ); - } - else if ( m_ScreenOverlayMaterial->NeedsPowerOfTwoFrameBufferTexture() ) - { - // First copy the FB off to the offscreen texture - UpdateRefractTexture( x, y, w, h, true ); - - // Now draw the entire screen using the material... - CMatRenderContextPtr pRenderContext( materials ); - ITexture *pTexture = GetPowerOfTwoFrameBufferTexture( ); - int sw = pTexture->GetActualWidth(); - int sh = pTexture->GetActualHeight(); - // Note - don't offset by x,y - already done by the viewport. - pRenderContext->DrawScreenSpaceRectangle( m_ScreenOverlayMaterial, 0, 0, w, h, - 0, 0, sw-1, sh-1, sw, sh ); - } - else - { - byte color[4] = { 255, 255, 255, 255 }; - render->ViewDrawFade( color, m_ScreenOverlayMaterial ); - } - } -} - -void CViewRender::DrawUnderwaterOverlay( void ) -{ - IMaterial *pOverlayMat = m_UnderWaterOverlayMaterial; - - if ( pOverlayMat ) - { - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - CMatRenderContextPtr pRenderContext( materials ); - - int x, y, w, h; - - pRenderContext->GetViewport( x, y, w, h ); - if ( pOverlayMat->NeedsFullFrameBufferTexture() ) - { - // FIXME: check with multi/sub-rect renders. Should this be 0,0,w,h instead? - DrawScreenEffectMaterial( pOverlayMat, x, y, w, h ); - } - else if ( pOverlayMat->NeedsPowerOfTwoFrameBufferTexture() ) - { - // First copy the FB off to the offscreen texture - UpdateRefractTexture( x, y, w, h, true ); - - // Now draw the entire screen using the material... - CMatRenderContextPtr pRenderContext( materials ); - ITexture *pTexture = GetPowerOfTwoFrameBufferTexture( ); - int sw = pTexture->GetActualWidth(); - int sh = pTexture->GetActualHeight(); - // Note - don't offset by x,y - already done by the viewport. - pRenderContext->DrawScreenSpaceRectangle( pOverlayMat, 0, 0, w, h, - 0, 0, sw-1, sh-1, sw, sh ); - } - else - { - // Note - don't offset by x,y - already done by the viewport. - // FIXME: actually test this code path. - pRenderContext->DrawScreenSpaceRectangle( pOverlayMat, 0, 0, w, h, - 0, 0, 1, 1, 1, 1 ); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Returns the min/max fade distances -//----------------------------------------------------------------------------- -void CViewRender::GetScreenFadeDistances( float *min, float *max ) -{ - if ( min ) - { - *min = r_screenfademinsize.GetFloat(); - } - - if ( max ) - { - *max = r_screenfademaxsize.GetFloat(); - } -} - -C_BaseEntity *CViewRender::GetCurrentlyDrawingEntity() -{ - return m_pCurrentlyDrawingEntity; -} - -void CViewRender::SetCurrentlyDrawingEntity( C_BaseEntity *pEnt ) -{ - m_pCurrentlyDrawingEntity = pEnt; -} - -bool CViewRender::UpdateShadowDepthTexture( ITexture *pRenderTarget, ITexture *pDepthTexture, const CViewSetup &shadowViewIn ) -{ - VPROF_INCREMENT_COUNTER( "shadow depth textures rendered", 1 ); - - CMatRenderContextPtr pRenderContext( materials ); - - char szPIXEventName[128]; - sprintf( szPIXEventName, "UpdateShadowDepthTexture (%s)", pDepthTexture->GetName() ); - PIXEVENT( pRenderContext, szPIXEventName ); - - CRefPtr pShadowDepthView = new CShadowDepthView( this ); - pShadowDepthView->Setup( shadowViewIn, pRenderTarget, pDepthTexture ); - AddViewToScene( pShadowDepthView ); - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Renders world and all entities, etc. -//----------------------------------------------------------------------------- -void CViewRender::ViewDrawScene( bool bDrew3dSkybox, SkyboxVisibility_t nSkyboxVisible, const CViewSetup &view, - int nClearFlags, view_id_t viewID, bool bDrawViewModel, int baseDrawFlags, ViewCustomVisibility_t *pCustomVisibility ) -{ - VPROF( "CViewRender::ViewDrawScene" ); - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - // this allows the refract texture to be updated once per *scene* on 360 - // (e.g. once for a monitor scene and once for the main scene) - g_viewscene_refractUpdateFrame = gpGlobals->framecount - 1; - - g_pClientShadowMgr->PreRender(); - - // Shadowed flashlights supported on ps_2_b and up... - if ( r_flashlightdepthtexture.GetBool() && (viewID == VIEW_MAIN) ) - { - g_pClientShadowMgr->ComputeShadowDepthTextures( view ); - } - - m_BaseDrawFlags = baseDrawFlags; - - SetupCurrentView( view.origin, view.angles, viewID ); - - // Invoke pre-render methods - IGameSystem::PreRenderAllSystems(); - - // Start view - unsigned int visFlags; - SetupVis( view, visFlags, pCustomVisibility ); - - if ( !bDrew3dSkybox && - ( nSkyboxVisible == SKYBOX_NOT_VISIBLE ) && ( visFlags & IVRenderView::VIEW_SETUP_VIS_EX_RETURN_FLAGS_USES_RADIAL_VIS ) ) - { - // This covers the case where we don't see a 3dskybox, yet radial vis is clipping - // the far plane. Need to clear to fog color in this case. - nClearFlags |= VIEW_CLEAR_COLOR; - SetClearColorToFogColor( ); - } - - bool drawSkybox = r_skybox.GetBool(); - if ( bDrew3dSkybox || ( nSkyboxVisible == SKYBOX_NOT_VISIBLE ) ) - { - drawSkybox = false; - } - - ParticleMgr()->IncrementFrameCode(); - - DrawWorldAndEntities( drawSkybox, view, nClearFlags, pCustomVisibility ); - - // FF --> hlstriker: Added -#if defined (WIN32) - VisibleFogVolumeInfo_t fogVolumeInfo; - render->GetVisibleFogVolume( view.origin, &fogVolumeInfo ); - WaterRenderInfo_t info; - DetermineWaterRenderInfo( fogVolumeInfo, info ); - g_ShaderEditorSystem->CustomViewRender( &g_CurrentViewID, fogVolumeInfo, info ); -#endif - // <-- - - // Disable fog for the rest of the stuff - DisableFog(); - - // UNDONE: Don't do this with masked brush models, they should probably be in a separate list - // render->DrawMaskEntities() - - // Here are the overlays... - - CGlowOverlay::DrawOverlays( view.m_bCacheFullSceneState ); - - // issue the pixel visibility tests - if ( IsMainView( CurrentViewID() ) ) - { - PixelVisibility_EndCurrentView(); - } - - // Draw rain.. - DrawPrecipitation(); - - // Make sure sound doesn't stutter - engine->Sound_ExtraUpdate(); - - // Debugging info goes over the top - CDebugViewRender::Draw3DDebuggingInfo( view ); - - // Draw client side effects - // NOTE: These are not sorted against the rest of the frame - clienteffects->DrawEffects( gpGlobals->frametime ); - - // Mark the frame as locked down for client fx additions - SetFXCreationAllowed( false ); - - // Invoke post-render methods - IGameSystem::PostRenderAllSystems(); - - FinishCurrentView(); - - // Free shadow depth textures for use in future view - if ( r_flashlightdepthtexture.GetBool() ) - { - g_pClientShadowMgr->UnlockAllShadowDepthTextures(); - } -} - - -void CheckAndTransitionColor( float flPercent, float *pColor, float *pLerpToColor ) -{ - if ( pLerpToColor[0] != pColor[0] || pLerpToColor[1] != pColor[1] || pLerpToColor[2] != pColor[2] ) - { - float flDestColor[3]; - - flDestColor[0] = pLerpToColor[0]; - flDestColor[1] = pLerpToColor[1]; - flDestColor[2] = pLerpToColor[2]; - - pColor[0] = FLerp( pColor[0], flDestColor[0], flPercent ); - pColor[1] = FLerp( pColor[1], flDestColor[1], flPercent ); - pColor[2] = FLerp( pColor[2], flDestColor[2], flPercent ); - } - else - { - pColor[0] = pLerpToColor[0]; - pColor[1] = pLerpToColor[1]; - pColor[2] = pLerpToColor[2]; - } -} - -static void GetFogColorTransition( fogparams_t *pFogParams, float *pColorPrimary, float *pColorSecondary ) -{ - if ( !pFogParams ) - return; - - if ( pFogParams->lerptime >= gpGlobals->curtime ) - { - float flPercent = 1.0f - (( pFogParams->lerptime - gpGlobals->curtime ) / pFogParams->duration ); - - float flPrimaryColorLerp[3] = { pFogParams->colorPrimaryLerpTo.GetR(), pFogParams->colorPrimaryLerpTo.GetG(), pFogParams->colorPrimaryLerpTo.GetB() }; - float flSecondaryColorLerp[3] = { pFogParams->colorSecondaryLerpTo.GetR(), pFogParams->colorSecondaryLerpTo.GetG(), pFogParams->colorSecondaryLerpTo.GetB() }; - - CheckAndTransitionColor( flPercent, pColorPrimary, flPrimaryColorLerp ); - CheckAndTransitionColor( flPercent, pColorSecondary, flSecondaryColorLerp ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Returns the fog color to use in rendering the current frame. -//----------------------------------------------------------------------------- -static void GetFogColor( fogparams_t *pFogParams, float *pColor ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if ( !pbp || !pFogParams ) - return; - - const char *fogColorString = fog_color.GetString(); - if( fog_override.GetInt() && fogColorString ) - { - sscanf( fogColorString, "%f%f%f", pColor, pColor+1, pColor+2 ); - } - else - { - float flPrimaryColor[3] = { pFogParams->colorPrimary.GetR(), pFogParams->colorPrimary.GetG(), pFogParams->colorPrimary.GetB() }; - float flSecondaryColor[3] = { pFogParams->colorSecondary.GetR(), pFogParams->colorSecondary.GetG(), pFogParams->colorSecondary.GetB() }; - - GetFogColorTransition( pFogParams, flPrimaryColor, flSecondaryColor ); - - if( pFogParams->blend ) - { - // - // Blend between two fog colors based on viewing angle. - // The secondary fog color is at 180 degrees to the primary fog color. - // - Vector forward; - pbp->EyeVectors( &forward, NULL, NULL ); - - Vector vNormalized = pFogParams->dirPrimary; - VectorNormalize( vNormalized ); - pFogParams->dirPrimary = vNormalized; - - float flBlendFactor = 0.5 * forward.Dot( pFogParams->dirPrimary ) + 0.5; - - // FIXME: convert to linear colorspace - pColor[0] = flPrimaryColor[0] * flBlendFactor + flSecondaryColor[0] * ( 1 - flBlendFactor ); - pColor[1] = flPrimaryColor[1] * flBlendFactor + flSecondaryColor[1] * ( 1 - flBlendFactor ); - pColor[2] = flPrimaryColor[2] * flBlendFactor + flSecondaryColor[2] * ( 1 - flBlendFactor ); - } - else - { - pColor[0] = flPrimaryColor[0]; - pColor[1] = flPrimaryColor[1]; - pColor[2] = flPrimaryColor[2]; - } - } - - VectorScale( pColor, 1.0f / 255.0f, pColor ); -} - - -static float GetFogStart( fogparams_t *pFogParams ) -{ - if( !pFogParams ) - return 0.0f; - - if( fog_override.GetInt() ) - { - if( fog_start.GetFloat() == -1.0f ) - { - return pFogParams->start; - } - else - { - return fog_start.GetFloat(); - } - } - else - { - if ( pFogParams->lerptime > gpGlobals->curtime ) - { - if ( pFogParams->start != pFogParams->startLerpTo ) - { - if ( pFogParams->lerptime > gpGlobals->curtime ) - { - float flPercent = 1.0f - (( pFogParams->lerptime - gpGlobals->curtime ) / pFogParams->duration ); - - return FLerp( pFogParams->start, pFogParams->startLerpTo, flPercent ); - } - else - { - if ( pFogParams->start != pFogParams->startLerpTo ) - { - pFogParams->start = pFogParams->startLerpTo; - } - } - } - } - - return pFogParams->start; - } -} - -static float GetFogEnd( fogparams_t *pFogParams ) -{ - if( !pFogParams ) - return 0.0f; - - if( fog_override.GetInt() ) - { - if( fog_end.GetFloat() == -1.0f ) - { - return pFogParams->end; - } - else - { - return fog_end.GetFloat(); - } - } - else - { - if ( pFogParams->lerptime > gpGlobals->curtime ) - { - if ( pFogParams->end != pFogParams->endLerpTo ) - { - if ( pFogParams->lerptime > gpGlobals->curtime ) - { - float flPercent = 1.0f - (( pFogParams->lerptime - gpGlobals->curtime ) / pFogParams->duration ); - - return FLerp( pFogParams->end, pFogParams->endLerpTo, flPercent ); - } - else - { - if ( pFogParams->end != pFogParams->endLerpTo ) - { - pFogParams->end = pFogParams->endLerpTo; - } - } - } - } - - return pFogParams->end; - } -} - -static bool GetFogEnable( fogparams_t *pFogParams ) -{ - if ( cl_leveloverview.GetFloat() > 0 ) - return false; - - // Ask the clientmode - if ( g_pClientMode->ShouldDrawFog() == false ) - return false; - - if( fog_override.GetInt() ) - { - if( fog_enable.GetInt() ) - { - return true; - } - else - { - return false; - } - } - else - { - if( pFogParams ) - return pFogParams->enable != false; - - return false; - } -} - - -static float GetFogMaxDensity( fogparams_t *pFogParams ) -{ - if( !pFogParams ) - return 1.0f; - - if ( cl_leveloverview.GetFloat() > 0 ) - return 1.0f; - - // Ask the clientmode - if ( !g_pClientMode->ShouldDrawFog() ) - return 1.0f; - - if ( fog_override.GetInt() ) - { - if ( fog_maxdensity.GetFloat() == -1.0f ) - return pFogParams->maxdensity; - else - return fog_maxdensity.GetFloat(); - } - else - return pFogParams->maxdensity; -} - - -//----------------------------------------------------------------------------- -// Purpose: Returns the skybox fog color to use in rendering the current frame. -//----------------------------------------------------------------------------- -static void GetSkyboxFogColor( float *pColor ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return; - } - CPlayerLocalData *local = &pbp->m_Local; - - const char *fogColorString = fog_colorskybox.GetString(); - if( fog_override.GetInt() && fogColorString ) - { - sscanf( fogColorString, "%f%f%f", pColor, pColor+1, pColor+2 ); - } - else - { - if( local->m_skybox3d.fog.blend ) - { - // - // Blend between two fog colors based on viewing angle. - // The secondary fog color is at 180 degrees to the primary fog color. - // - Vector forward; - pbp->EyeVectors( &forward, NULL, NULL ); - - Vector vNormalized = local->m_skybox3d.fog.dirPrimary; - VectorNormalize( vNormalized ); - local->m_skybox3d.fog.dirPrimary = vNormalized; - - float flBlendFactor = 0.5 * forward.Dot( local->m_skybox3d.fog.dirPrimary ) + 0.5; - - // FIXME: convert to linear colorspace - pColor[0] = local->m_skybox3d.fog.colorPrimary.GetR() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetR() * ( 1 - flBlendFactor ); - pColor[1] = local->m_skybox3d.fog.colorPrimary.GetG() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetG() * ( 1 - flBlendFactor ); - pColor[2] = local->m_skybox3d.fog.colorPrimary.GetB() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetB() * ( 1 - flBlendFactor ); - } - else - { - pColor[0] = local->m_skybox3d.fog.colorPrimary.GetR(); - pColor[1] = local->m_skybox3d.fog.colorPrimary.GetG(); - pColor[2] = local->m_skybox3d.fog.colorPrimary.GetB(); - } - } - - VectorScale( pColor, 1.0f / 255.0f, pColor ); -} - - -static float GetSkyboxFogStart( void ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return 0.0f; - } - CPlayerLocalData *local = &pbp->m_Local; - - if( fog_override.GetInt() ) - { - if( fog_startskybox.GetFloat() == -1.0f ) - { - return local->m_skybox3d.fog.start; - } - else - { - return fog_startskybox.GetFloat(); - } - } - else - { - return local->m_skybox3d.fog.start; - } -} - -static float GetSkyboxFogEnd( void ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return 0.0f; - } - CPlayerLocalData *local = &pbp->m_Local; - - if( fog_override.GetInt() ) - { - if( fog_endskybox.GetFloat() == -1.0f ) - { - return local->m_skybox3d.fog.end; - } - else - { - return fog_endskybox.GetFloat(); - } - } - else - { - return local->m_skybox3d.fog.end; - } -} - - -static float GetSkyboxFogMaxDensity() -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if ( !pbp ) - return 1.0f; - - CPlayerLocalData *local = &pbp->m_Local; - - if ( cl_leveloverview.GetFloat() > 0 ) - return 1.0f; - - // Ask the clientmode - if ( !g_pClientMode->ShouldDrawFog() ) - return 1.0f; - - if ( fog_override.GetInt() ) - { - if ( fog_maxdensityskybox.GetFloat() == -1.0f ) - return local->m_skybox3d.fog.maxdensity; - else - return fog_maxdensityskybox.GetFloat(); - } - else - return local->m_skybox3d.fog.maxdensity; -} - - -void CViewRender::DisableFog( void ) -{ - VPROF("CViewRander::DisableFog()"); - - CMatRenderContextPtr pRenderContext( materials ); - pRenderContext->FogMode( MATERIAL_FOG_NONE ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CViewRender::SetupVis( const CViewSetup& view, unsigned int &visFlags, ViewCustomVisibility_t *pCustomVisibility ) -{ - VPROF( "CViewRender::SetupVis" ); - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - if ( pCustomVisibility && pCustomVisibility->m_nNumVisOrigins ) - { - // Pass array or vis origins to merge - render->ViewSetupVisEx( ShouldForceNoVis(), pCustomVisibility->m_nNumVisOrigins, pCustomVisibility->m_rgVisOrigins, visFlags ); - } - else - { - // Use render origin as vis origin by default - render->ViewSetupVisEx( ShouldForceNoVis(), 1, &view.origin, visFlags ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Renders voice feedback and other sprites attached to players -// Input : none -//----------------------------------------------------------------------------- -void CViewRender::RenderPlayerSprites() -{ - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - GetClientVoiceMgr()->DrawHeadLabels(); -} - -//----------------------------------------------------------------------------- -// Sets up, cleans up the main 3D view -//----------------------------------------------------------------------------- -void CViewRender::SetupMain3DView( const CViewSetup &view, int &nClearFlags ) -{ - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - // FIXME: I really want these fields removed from CViewSetup - // and passed in as independent flags - // Clear the color here if requested. - - int nDepthStencilFlags = nClearFlags & ( VIEW_CLEAR_DEPTH | VIEW_CLEAR_STENCIL ); - nClearFlags &= ~( nDepthStencilFlags ); // Clear these flags - if ( nClearFlags & VIEW_CLEAR_COLOR ) - { - nClearFlags |= nDepthStencilFlags; // Add them back in if we're clearing color - } - - // If we are using HDR, we render to the HDR full frame buffer texture - // instead of whatever was previously the render target - if( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT ) - { - render->Push3DView( view, nClearFlags, GetFullFrameFrameBufferTexture( 0 ), GetFrustum() ); - } - else - { - ITexture *pRTColor = NULL; - ITexture *pRTDepth = NULL; - if( view.m_eStereoEye != STEREO_EYE_MONO ) - { - pRTColor = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(view.m_eStereoEye-1), ISourceVirtualReality::RT_Color ); - pRTDepth = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(view.m_eStereoEye-1), ISourceVirtualReality::RT_Depth ); - } - - render->Push3DView( view, nClearFlags, pRTColor, GetFrustum(), pRTDepth ); - } - - // If we didn't clear the depth here, we'll need to clear it later - nClearFlags ^= nDepthStencilFlags; // Toggle these bits - if ( nClearFlags & VIEW_CLEAR_COLOR ) - { - // If we cleared the color here, we don't need to clear it later - nClearFlags &= ~( VIEW_CLEAR_COLOR | VIEW_CLEAR_FULL_TARGET ); - } -} - -void CViewRender::CleanupMain3DView( const CViewSetup &view ) -{ - render->PopView( GetFrustum() ); -} - - -//----------------------------------------------------------------------------- -// Queues up an overlay rendering -//----------------------------------------------------------------------------- -void CViewRender::QueueOverlayRenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ) -{ - // Can't have 2 in a single scene - Assert( !m_bDrawOverlay ); - - m_bDrawOverlay = true; - m_OverlayViewSetup = view; - m_OverlayClearFlags = nClearFlags; - m_OverlayDrawFlags = whatToDraw; -} - -//----------------------------------------------------------------------------- -// Purpose: Force the view to freeze on the next frame for the specified time -//----------------------------------------------------------------------------- -void CViewRender::FreezeFrame( float flFreezeTime ) -{ - if ( flFreezeTime == 0 ) - { - m_flFreezeFrameUntil = 0; - for( int i=0; i < STEREO_EYE_MAX; i++ ) - { - m_rbTakeFreezeFrame[ i ] = false; - } - } - else - { - if ( m_flFreezeFrameUntil > gpGlobals->curtime ) - { - m_flFreezeFrameUntil += flFreezeTime; - } - else - { - m_flFreezeFrameUntil = gpGlobals->curtime + flFreezeTime; - for( int i=GetFirstEye(); i <= GetLastEye(); i++ ) - { - m_rbTakeFreezeFrame[ i ] = true; - } - } - } -} - -const char *COM_GetModDirectory(); - - -//----------------------------------------------------------------------------- -// Purpose: This renders the entire 3D view and the in-game hud/viewmodel -// Input : &view - -// whatToDraw - -//----------------------------------------------------------------------------- -// This renders the entire 3D view. -void CViewRender::RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ) -{ - m_UnderWaterOverlayMaterial.Shutdown(); // underwater view will set - - m_CurrentView = view; - - C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true ); - VPROF( "CViewRender::RenderView" ); - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - // Don't want TF2 running less than DX 8 - if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) - { - // We know they were running at least 8.0 when the game started...we check the - // value in ClientDLL_Init()...so they must be messing with their DirectX settings. - if ( ( Q_stricmp( COM_GetModDirectory(), "tf" ) == 0 ) || ( Q_stricmp( COM_GetModDirectory(), "tf_beta" ) == 0 ) ) - { - static bool bFirstTime = true; - if ( bFirstTime ) - { - bFirstTime = false; - Msg( "This game has a minimum requirement of DirectX 8.0 to run properly.\n" ); - } - return; - } - } - - CMatRenderContextPtr pRenderContext( materials ); - ITexture *saveRenderTarget = pRenderContext->GetRenderTarget(); - pRenderContext.SafeRelease(); // don't want to hold for long periods in case in a locking active share thread mode - - if ( !m_rbTakeFreezeFrame[ view.m_eStereoEye ] && m_flFreezeFrameUntil > gpGlobals->curtime ) - { - CRefPtr pFreezeFrameView = new CFreezeFrameView( this ); - pFreezeFrameView->Setup( view ); - AddViewToScene( pFreezeFrameView ); - - g_bRenderingView = true; - s_bCanAccessCurrentView = true; - } - else - { - g_flFreezeFlash = 0.0f; - - g_pClientShadowMgr->AdvanceFrame(); - - #ifdef USE_MONITORS - if ( cl_drawmonitors.GetBool() && - ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 70 ) && - ( ( whatToDraw & RENDERVIEW_SUPPRESSMONITORRENDERING ) == 0 ) ) - { - CViewSetup viewMiddle = GetView( STEREO_EYE_MONO ); - DrawMonitors( viewMiddle ); - } - #endif - - g_bRenderingView = true; - - // Must be first - render->SceneBegin(); - - pRenderContext.GetFrom( materials ); - pRenderContext->TurnOnToneMapping(); - pRenderContext.SafeRelease(); - - // clear happens here probably - SetupMain3DView( view, nClearFlags ); - - bool bDrew3dSkybox = false; - SkyboxVisibility_t nSkyboxVisible = SKYBOX_NOT_VISIBLE; - - // if the 3d skybox world is drawn, then don't draw the normal skybox - CSkyboxView *pSkyView = new CSkyboxView( this ); - if ( ( bDrew3dSkybox = pSkyView->Setup( view, &nClearFlags, &nSkyboxVisible ) ) != false ) - { - AddViewToScene( pSkyView ); -#if defined (WIN32) - g_ShaderEditorSystem->UpdateSkymask(); // FF --> hlstriker: Added -#endif - } - SafeRelease( pSkyView ); - - // Force it to clear the framebuffer if they're in solid space. - if ( ( nClearFlags & VIEW_CLEAR_COLOR ) == 0 ) - { - if ( enginetrace->GetPointContents( view.origin ) == CONTENTS_SOLID ) - { - nClearFlags |= VIEW_CLEAR_COLOR; - } - } - - // Render world and all entities, particles, etc. - if( !g_pIntroData ) - { - ViewDrawScene( bDrew3dSkybox, nSkyboxVisible, view, nClearFlags, VIEW_MAIN, whatToDraw & RENDERVIEW_DRAWVIEWMODEL ); - } - else - { - ViewDrawScene_Intro( view, nClearFlags, *g_pIntroData ); - } - - // We can still use the 'current view' stuff set up in ViewDrawScene - s_bCanAccessCurrentView = true; - - - engine->DrawPortals(); - - DisableFog(); - - // Finish scene - render->SceneEnd(); - - // Draw lightsources if enabled - render->DrawLights(); - - RenderPlayerSprites(); - - // Image-space motion blur - if ( !building_cubemaps.GetBool() && view.m_bDoBloomAndToneMapping ) // We probably should use a different view. variable here - { - if ( ( mat_motion_blur_enabled.GetInt() ) && ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 90 ) ) - { - pRenderContext.GetFrom( materials ); - { - PIXEVENT( pRenderContext, "DoImageSpaceMotionBlur" ); - DoImageSpaceMotionBlur( view, view.x, view.y, view.width, view.height ); - } - pRenderContext.SafeRelease(); - } - } - - GetClientModeNormal()->DoPostScreenSpaceEffects( &view ); - - // Now actually draw the viewmodel - DrawViewModels( view, whatToDraw & RENDERVIEW_DRAWVIEWMODEL ); - -#if defined (WIN32) - g_ShaderEditorSystem->UpdateSkymask( bDrew3dSkybox ); // FF --> hlstriker: Added -#endif - - DrawUnderwaterOverlay(); - - PixelVisibility_EndScene(); - - // Draw fade over entire screen if needed - byte color[4]; - bool blend; - vieweffects->GetFadeParams( &color[0], &color[1], &color[2], &color[3], &blend ); - - // Draw an overlay to make it even harder to see inside smoke particle systems. - DrawSmokeFogOverlay(); - - // Overlay screen fade on entire screen - IMaterial* pMaterial = blend ? m_ModulateSingleColor : m_TranslucentSingleColor; - render->ViewDrawFade( color, pMaterial ); - PerformScreenOverlay( view.x, view.y, view.width, view.height ); - - // Prevent sound stutter if going slow - engine->Sound_ExtraUpdate(); - - if ( !building_cubemaps.GetBool() && view.m_bDoBloomAndToneMapping ) - { - pRenderContext.GetFrom( materials ); - { - PIXEVENT( pRenderContext, "DoEnginePostProcessing" ); - - bool bFlashlightIsOn = false; - C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer(); - if ( pLocal ) - { - bFlashlightIsOn = pLocal->IsEffectActive( EF_DIMLIGHT ); - } - DoEnginePostProcessing( view.x, view.y, view.width, view.height, bFlashlightIsOn ); - } - pRenderContext.SafeRelease(); - } -#if defined (WIN32) - g_ShaderEditorSystem->CustomPostRender(); // FF --> hlstriker: Added -#endif - - // And here are the screen-space effects - - if ( IsPC() ) - { - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "GrabPreColorCorrectedFrame" ); - - // Grab the pre-color corrected frame for editing purposes - engine->GrabPreColorCorrectedFrame( view.x, view.y, view.width, view.height ); - } - - PerformScreenSpaceEffects( 0, 0, view.width, view.height ); - - if ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER ) - { - pRenderContext.GetFrom( materials ); - pRenderContext->SetToneMappingScaleLinear(Vector(1,1,1)); - pRenderContext.SafeRelease(); - } - - CleanupMain3DView( view ); - - if ( m_rbTakeFreezeFrame[ view.m_eStereoEye ] ) - { - Rect_t rect; - rect.x = view.x; - rect.y = view.y; - rect.width = view.width; - rect.height = view.height; - - pRenderContext = materials->GetRenderContext(); - if ( IsX360() ) - { - // 360 doesn't create the Fullscreen texture - pRenderContext->CopyRenderTargetToTextureEx( GetFullFrameFrameBufferTexture( 1 ), 0, &rect, &rect ); - } - else - { - pRenderContext->CopyRenderTargetToTextureEx( GetFullscreenTexture(), 0, &rect, &rect ); - } - pRenderContext.SafeRelease(); - m_rbTakeFreezeFrame[ view.m_eStereoEye ] = false; - } - - pRenderContext = materials->GetRenderContext(); - pRenderContext->SetRenderTarget( saveRenderTarget ); - pRenderContext.SafeRelease(); - - // Draw the overlay - if ( m_bDrawOverlay ) - { - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DrawOverlay" ); - - // This allows us to be ok if there are nested overlay views - CViewSetup currentView = m_CurrentView; - CViewSetup tempView = m_OverlayViewSetup; - tempView.fov = ScaleFOVByWidthRatio( tempView.fov, tempView.m_flAspectRatio / ( 4.0f / 3.0f ) ); - tempView.m_bDoBloomAndToneMapping = false; // FIXME: Hack to get Mark up and running - m_bDrawOverlay = false; - RenderView( tempView, m_OverlayClearFlags, m_OverlayDrawFlags ); - m_CurrentView = currentView; - } - - } - - if ( mat_viewportupscale.GetBool() && mat_viewportscale.GetFloat() < 1.0f ) - { - CMatRenderContextPtr pRenderContext( materials ); - - ITexture *pFullFrameFB1 = materials->FindTexture( "_rt_FullFrameFB1", TEXTURE_GROUP_RENDER_TARGET ); - IMaterial *pCopyMaterial = materials->FindMaterial( "dev/upscale", TEXTURE_GROUP_OTHER ); - pCopyMaterial->IncrementReferenceCount(); - - Rect_t DownscaleRect, UpscaleRect; - - DownscaleRect.x = view.x; - DownscaleRect.y = view.y; - DownscaleRect.width = view.width; - DownscaleRect.height = view.height; - - UpscaleRect.x = view.m_nUnscaledX; - UpscaleRect.y = view.m_nUnscaledY; - UpscaleRect.width = view.m_nUnscaledWidth; - UpscaleRect.height = view.m_nUnscaledHeight; - - pRenderContext->CopyRenderTargetToTextureEx( pFullFrameFB1, 0, &DownscaleRect, &DownscaleRect ); - pRenderContext->DrawScreenSpaceRectangle( pCopyMaterial, UpscaleRect.x, UpscaleRect.y, UpscaleRect.width, UpscaleRect.height, - DownscaleRect.x, DownscaleRect.y, DownscaleRect.x+DownscaleRect.width-1, DownscaleRect.y+DownscaleRect.height-1, - pFullFrameFB1->GetActualWidth(), pFullFrameFB1->GetActualHeight() ); - - pCopyMaterial->DecrementReferenceCount(); - } - - // if we're in VR mode we might need to override the render target - if( UseVR() ) - { - saveRenderTarget = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(view.m_eStereoEye - 1), ISourceVirtualReality::RT_Color ); - } - - // Draw the 2D graphics - render->Push2DView( view, 0, saveRenderTarget, GetFrustum() ); - - Render2DEffectsPreHUD( view ); - - if ( whatToDraw & RENDERVIEW_DRAWHUD ) - { - VPROF_BUDGET( "VGui_DrawHud", VPROF_BUDGETGROUP_OTHER_VGUI ); - int viewWidth = view.m_nUnscaledWidth; - int viewHeight = view.m_nUnscaledHeight; - int viewActualWidth = view.m_nUnscaledWidth; - int viewActualHeight = view.m_nUnscaledHeight; - int viewX = view.m_nUnscaledX; - int viewY = view.m_nUnscaledY; - int viewFramebufferX = 0; - int viewFramebufferY = 0; - int viewFramebufferWidth = viewWidth; - int viewFramebufferHeight = viewHeight; - bool bClear = false; - bool bPaintMainMenu = false; - ITexture *pTexture = NULL; - if( UseVR() ) - { - if( g_ClientVirtualReality.ShouldRenderHUDInWorld() ) - { - pTexture = materials->FindTexture( "_rt_gui", NULL, false ); - if( pTexture ) - { - bPaintMainMenu = true; - bClear = true; - viewX = 0; - viewY = 0; - viewActualWidth = pTexture->GetActualWidth(); - viewActualHeight = pTexture->GetActualHeight(); - - vgui::surface()->GetScreenSize( viewWidth, viewHeight ); - - viewFramebufferX = 0; - if( view.m_eStereoEye == STEREO_EYE_RIGHT && !saveRenderTarget ) - viewFramebufferX = viewFramebufferWidth; - viewFramebufferY = 0; - } - } - else - { - viewFramebufferX = view.m_eStereoEye == STEREO_EYE_RIGHT ? viewWidth : 0; - viewFramebufferY = 0; - } - } - - // Get the render context out of materials to avoid some debug stuff. - // WARNING THIS REQUIRES THE .SafeRelease below or it'll never release the ref - pRenderContext = materials->GetRenderContext(); - - // clear depth in the backbuffer before we push the render target - if( bClear ) - { - pRenderContext->ClearBuffers( false, true, true ); - } - - // constrain where VGUI can render to the view - pRenderContext->PushRenderTargetAndViewport( pTexture, NULL, viewX, viewY, viewActualWidth, viewActualHeight ); - // If drawing off-screen, force alpha for that pass - if (pTexture) - { - pRenderContext->OverrideAlphaWriteEnable( true, true ); - } - - // let vgui know where to render stuff for the forced-to-framebuffer panels - if( UseVR() ) - { - vgui::surface()->SetFullscreenViewportAndRenderTarget( viewFramebufferX, viewFramebufferY, viewFramebufferWidth, viewFramebufferHeight, saveRenderTarget ); - } - - // clear the render target if we need to - if( bClear ) - { - pRenderContext->ClearColor4ub( 0, 0, 0, 0 ); - pRenderContext->ClearBuffers( true, false ); - } - pRenderContext.SafeRelease(); - - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "VGui_DrawHud", __FUNCTION__ ); - - // paint the vgui screen - VGui_PreRender(); - - // Make sure the client .dll root panel is at the proper point before doing the "SolveTraverse" calls - vgui::VPANEL root = enginevgui->GetPanel( PANEL_CLIENTDLL ); - if ( root != 0 ) - { - vgui::ipanel()->SetSize( root, viewWidth, viewHeight ); - } - // Same for client .dll tools - root = enginevgui->GetPanel( PANEL_CLIENTDLL_TOOLS ); - if ( root != 0 ) - { - vgui::ipanel()->SetSize( root, viewWidth, viewHeight ); - } - - // The crosshair, etc. needs to get at the current setup stuff - AllowCurrentViewAccess( true ); - - // Draw the in-game stuff based on the actual viewport being used - render->VGui_Paint( PAINT_INGAMEPANELS ); - - // maybe paint the main menu and cursor too if we're in stereo hud mode - if( bPaintMainMenu ) - render->VGui_Paint( PAINT_UIPANELS | PAINT_CURSOR ); - - AllowCurrentViewAccess( false ); - - VGui_PostRender(); - - g_pClientMode->PostRenderVGui(); - pRenderContext = materials->GetRenderContext(); - if (pTexture) - { - pRenderContext->OverrideAlphaWriteEnable( false, true ); - } - pRenderContext->PopRenderTargetAndViewport(); - - if ( UseVR() ) - { - // figure out if we really want to draw the HUD based on freeze cam - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - bool bInFreezeCam = ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM ); - - // draw the HUD after the view model so its "I'm closer" depth queues work right. - if( !bInFreezeCam && g_ClientVirtualReality.ShouldRenderHUDInWorld() ) - { - // Now we've rendered the HUD to its texture, actually get it on the screen. - // Since we're drawing it as a 3D object, we need correctly set up frustum, etc. - int ClearFlags = 0; - SetupMain3DView( view, ClearFlags ); - - // TODO - a bit of a shonky test - basically trying to catch the main menu, the briefing screen, the loadout screen, etc. - bool bTranslucent = !g_pMatSystemSurface->IsCursorVisible(); - g_ClientVirtualReality.RenderHUDQuad( g_pClientMode->ShouldBlackoutAroundHUD(), bTranslucent ); - CleanupMain3DView( view ); - } - } - - pRenderContext->Flush(); - pRenderContext.SafeRelease(); - } - - CDebugViewRender::Draw2DDebuggingInfo( view ); - - Render2DEffectsPostHUD( view ); - - g_bRenderingView = false; - - // We can no longer use the 'current view' stuff set up in ViewDrawScene - s_bCanAccessCurrentView = false; - - if ( IsPC() ) - { - CDebugViewRender::GenerateOverdrawForTesting(); - } - - render->PopView( GetFrustum() ); - g_WorldListCache.Flush(); -} - -//----------------------------------------------------------------------------- -// Purpose: Renders extra 2D effects in derived classes while the 2D view is on the stack -//----------------------------------------------------------------------------- -void CViewRender::Render2DEffectsPreHUD( const CViewSetup &view ) -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Renders extra 2D effects in derived classes while the 2D view is on the stack -//----------------------------------------------------------------------------- -void CViewRender::Render2DEffectsPostHUD( const CViewSetup &view ) -{ -} - - - -//----------------------------------------------------------------------------- -// -// NOTE: Below here is all of the stuff that needs to be done for water rendering -// -//----------------------------------------------------------------------------- - - -//----------------------------------------------------------------------------- -// Determines what kind of water we're going to use -//----------------------------------------------------------------------------- -void CViewRender::DetermineWaterRenderInfo( const VisibleFogVolumeInfo_t &fogVolumeInfo, WaterRenderInfo_t &info ) -{ - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - // By default, assume cheap water (even if there's no water in the scene!) - info.m_bCheapWater = true; - info.m_bRefract = false; - info.m_bReflect = false; - info.m_bReflectEntities = false; - info.m_bDrawWaterSurface = false; - info.m_bOpaqueWater = true; - - - - IMaterial *pWaterMaterial = fogVolumeInfo.m_pFogVolumeMaterial; - if (( fogVolumeInfo.m_nVisibleFogVolume == -1 ) || !pWaterMaterial ) - return; - - - // Use cheap water if mat_drawwater is set - info.m_bDrawWaterSurface = mat_drawwater.GetBool(); - if ( !info.m_bDrawWaterSurface ) - { - info.m_bOpaqueWater = false; - return; - } - -#ifdef _X360 - bool bForceExpensive = false; -#else - bool bForceExpensive = r_waterforceexpensive.GetBool(); -#endif - bool bForceReflectEntities = r_waterforcereflectentities.GetBool(); - -#ifdef PORTAL - switch( g_pPortalRender->ShouldForceCheaperWaterLevel() ) - { - case 0: //force cheap water - info.m_bCheapWater = true; - return; - - case 1: //downgrade level to "simple reflection" - bForceExpensive = false; - - case 2: //downgrade level to "reflect world" - bForceReflectEntities = false; - - default: - break; - }; -#endif - - // Determine if the water surface is opaque or not - info.m_bOpaqueWater = !pWaterMaterial->IsTranslucent(); - - // DX level 70 can't handle anything but cheap water - if (engine->GetDXSupportLevel() < 80) - return; - - bool bForceCheap = false; - - // The material can override the default settings though - IMaterialVar *pForceCheapVar = pWaterMaterial->FindVar( "$forcecheap", NULL, false ); - IMaterialVar *pForceExpensiveVar = pWaterMaterial->FindVar( "$forceexpensive", NULL, false ); - if ( pForceCheapVar && pForceCheapVar->IsDefined() ) - { - bForceCheap = ( pForceCheapVar->GetIntValueFast() != 0 ); - if ( bForceCheap ) - { - bForceExpensive = false; - } - } - if ( !bForceCheap && pForceExpensiveVar && pForceExpensiveVar->IsDefined() ) - { - bForceExpensive = bForceExpensive || ( pForceExpensiveVar->GetIntValueFast() != 0 ); - } - - bool bDebugCheapWater = r_debugcheapwater.GetBool(); - if( bDebugCheapWater ) - { - Msg( "Water material: %s dist to water: %f\nforcecheap: %s forceexpensive: %s\n", - pWaterMaterial->GetName(), fogVolumeInfo.m_flDistanceToWater, - bForceCheap ? "true" : "false", bForceExpensive ? "true" : "false" ); - } - - // Unless expensive water is active, reflections are off. - bool bLocalReflection; -#ifdef _X360 - if( !r_WaterDrawReflection.GetBool() ) -#else - if( !bForceExpensive || !r_WaterDrawReflection.GetBool() ) -#endif - { - bLocalReflection = false; - } - else - { - IMaterialVar *pReflectTextureVar = pWaterMaterial->FindVar( "$reflecttexture", NULL, false ); - bLocalReflection = pReflectTextureVar && (pReflectTextureVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE); - } - - // Brian says FIXME: I disabled cheap water LOD when local specular is specified. - // There are very few places that appear to actually - // take advantage of it (places where water is in the PVS, but outside of LOD range). - // It was 2 hours before code lock, and I had the choice of either doubling fill-rate everywhere - // by making cheap water lod actually work (the water LOD wasn't actually rendering!!!) - // or to just always render the reflection + refraction if there's a local specular specified. - // Note that water LOD *does* work with refract-only water - - // Gary says: I'm reverting this change so that water LOD works on dx9 for ep2. - - // Check if the water is out of the cheap water LOD range; if so, use cheap water -#ifdef _X360 - if ( !bForceExpensive && ( bForceCheap || ( fogVolumeInfo.m_flDistanceToWater >= m_flCheapWaterEndDistance ) ) ) - { - return; - } -#else - if ( ( (fogVolumeInfo.m_flDistanceToWater >= m_flCheapWaterEndDistance) && !bLocalReflection ) || bForceCheap ) - return; -#endif - // Get the material that is for the water surface that is visible and check to see - // what render targets need to be rendered, if any. - if ( !r_WaterDrawRefraction.GetBool() ) - { - info.m_bRefract = false; - } - else - { - IMaterialVar *pRefractTextureVar = pWaterMaterial->FindVar( "$refracttexture", NULL, false ); - info.m_bRefract = pRefractTextureVar && (pRefractTextureVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE); - - // Refractive water can be seen through - if ( info.m_bRefract ) - { - info.m_bOpaqueWater = false; - } - } - - info.m_bReflect = bLocalReflection; - if ( info.m_bReflect ) - { - if( bForceReflectEntities ) - { - info.m_bReflectEntities = true; - } - else - { - IMaterialVar *pReflectEntitiesVar = pWaterMaterial->FindVar( "$reflectentities", NULL, false ); - info.m_bReflectEntities = pReflectEntitiesVar && (pReflectEntitiesVar->GetIntValueFast() != 0); - } - } - - info.m_bCheapWater = !info.m_bReflect && !info.m_bRefract; - - if( bDebugCheapWater ) - { - Warning( "refract: %s reflect: %s\n", info.m_bRefract ? "true" : "false", info.m_bReflect ? "true" : "false" ); - } -} - -//----------------------------------------------------------------------------- -// Draws the world and all entities -//----------------------------------------------------------------------------- -void CViewRender::DrawWorldAndEntities( bool bDrawSkybox, const CViewSetup &viewIn, int nClearFlags, ViewCustomVisibility_t *pCustomVisibility ) -{ - MDLCACHE_CRITICAL_SECTION(); - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - VisibleFogVolumeInfo_t fogVolumeInfo; -#ifdef PORTAL //in portal, we can't use the fog volume for the camera since it's almost never in the same fog volume as what's in front of the portal - if( g_pPortalRender->GetViewRecursionLevel() == 0 ) - { - render->GetVisibleFogVolume( viewIn.origin, &fogVolumeInfo ); - } - else - { - render->GetVisibleFogVolume( g_pPortalRender->GetExitPortalFogOrigin(), &fogVolumeInfo ); - } -#else - render->GetVisibleFogVolume( viewIn.origin, &fogVolumeInfo ); -#endif - - WaterRenderInfo_t info; - DetermineWaterRenderInfo( fogVolumeInfo, info ); - - if ( info.m_bCheapWater ) - { - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "bCheapWater" ); - cplane_t glassReflectionPlane; - if ( IsReflectiveGlassInView( viewIn, glassReflectionPlane ) ) - { - CRefPtr pGlassReflectionView = new CReflectiveGlassView( this ); - pGlassReflectionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, bDrawSkybox, fogVolumeInfo, info, glassReflectionPlane ); - AddViewToScene( pGlassReflectionView ); - - CRefPtr pGlassRefractionView = new CRefractiveGlassView( this ); - pGlassRefractionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, bDrawSkybox, fogVolumeInfo, info, glassReflectionPlane ); - AddViewToScene( pGlassRefractionView ); - } - - CRefPtr pNoWaterView = new CSimpleWorldView( this ); - pNoWaterView->Setup( viewIn, nClearFlags, bDrawSkybox, fogVolumeInfo, info, pCustomVisibility ); - AddViewToScene( pNoWaterView ); - return; - } - - Assert( !pCustomVisibility ); - - // Blat out the visible fog leaf if we're not going to use it - if ( !r_ForceWaterLeaf.GetBool() ) - { - fogVolumeInfo.m_nVisibleFogVolumeLeaf = -1; - } - - // We can see water of some sort - if ( !fogVolumeInfo.m_bEyeInFogVolume ) - { - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CAboveWaterView" ); - CRefPtr pAboveWaterView = new CAboveWaterView( this ); - pAboveWaterView->Setup( viewIn, bDrawSkybox, fogVolumeInfo, info ); - AddViewToScene( pAboveWaterView ); - } - else - { - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CUnderWaterView" ); - CRefPtr pUnderWaterView = new CUnderWaterView( this ); - pUnderWaterView->Setup( viewIn, bDrawSkybox, fogVolumeInfo, info ); - AddViewToScene( pUnderWaterView ); - } -} - - -//----------------------------------------------------------------------------- -// Pushes a water render target -//----------------------------------------------------------------------------- -static Vector SavedLinearLightMapScale(-1,-1,-1); // x<0 = no saved scale - -static void SetLightmapScaleForWater(void) -{ - if (g_pMaterialSystemHardwareConfig->GetHDRType()==HDR_TYPE_INTEGER) - { - CMatRenderContextPtr pRenderContext( materials ); - SavedLinearLightMapScale=pRenderContext->GetToneMappingScaleLinear(); - Vector t25=SavedLinearLightMapScale; - t25*=0.25; - pRenderContext->SetToneMappingScaleLinear(t25); - } -} - -//----------------------------------------------------------------------------- -// Returns true if the view plane intersects the water -//----------------------------------------------------------------------------- -bool DoesViewPlaneIntersectWater( float waterZ, int leafWaterDataID ) -{ - if ( leafWaterDataID == -1 ) - return false; - -#ifdef PORTAL //when rendering portal views point/plane intersections just don't cut it. - if( g_pPortalRender->GetViewRecursionLevel() != 0 ) - return g_pPortalRender->DoesExitPortalViewIntersectWaterPlane( waterZ, leafWaterDataID ); -#endif - - CMatRenderContextPtr pRenderContext( materials ); - - VMatrix viewMatrix, projectionMatrix, viewProjectionMatrix, inverseViewProjectionMatrix; - pRenderContext->GetMatrix( MATERIAL_VIEW, &viewMatrix ); - pRenderContext->GetMatrix( MATERIAL_PROJECTION, &projectionMatrix ); - MatrixMultiply( projectionMatrix, viewMatrix, viewProjectionMatrix ); - MatrixInverseGeneral( viewProjectionMatrix, inverseViewProjectionMatrix ); - - Vector mins, maxs; - ClearBounds( mins, maxs ); - Vector testPoint[4]; - testPoint[0].Init( -1.0f, -1.0f, 0.0f ); - testPoint[1].Init( -1.0f, 1.0f, 0.0f ); - testPoint[2].Init( 1.0f, -1.0f, 0.0f ); - testPoint[3].Init( 1.0f, 1.0f, 0.0f ); - int i; - bool bAbove = false; - bool bBelow = false; - float fudge = 7.0f; - for( i = 0; i < 4; i++ ) - { - Vector worldPos; - Vector3DMultiplyPositionProjective( inverseViewProjectionMatrix, testPoint[i], worldPos ); - AddPointToBounds( worldPos, mins, maxs ); -// Warning( "viewplanez: %f waterZ: %f\n", worldPos.z, waterZ ); - if( worldPos.z + fudge > waterZ ) - { - bAbove = true; - } - if( worldPos.z - fudge < waterZ ) - { - bBelow = true; - } - } - - // early out if the near plane doesn't cross the z plane of the water. - if( !( bAbove && bBelow ) ) - return false; - - Vector vecFudge( fudge, fudge, fudge ); - mins -= vecFudge; - maxs += vecFudge; - - // the near plane does cross the z value for the visible water volume. Call into - // the engine to find out if the near plane intersects the water volume. - return render->DoesBoxIntersectWaterVolume( mins, maxs, leafWaterDataID ); -} - -#ifdef PORTAL - -//----------------------------------------------------------------------------- -// Purpose: Draw the scene during another draw scene call. We must draw our portals -// after opaques but before translucents, so this ViewDrawScene resets the view -// and doesn't flag the rendering as ended when it ends. -// Input : bDrawSkybox - do we draw the skybox -// &view - the camera view to render from -// nClearFlags - how to clear the buffer -//----------------------------------------------------------------------------- -void CViewRender::ViewDrawScene_PortalStencil( const CViewSetup &viewIn, ViewCustomVisibility_t *pCustomVisibility ) -{ - VPROF( "CViewRender::ViewDrawScene_PortalStencil" ); - - CViewSetup view( viewIn ); - - // Record old view stats - Vector vecOldOrigin = CurrentViewOrigin(); - QAngle vecOldAngles = CurrentViewAngles(); - - int iCurrentViewID = g_CurrentViewID; - int iRecursionLevel = g_pPortalRender->GetViewRecursionLevel(); - Assert( iRecursionLevel > 0 ); - - //get references to reflection textures - CTextureReference pPrimaryWaterReflectionTexture; - pPrimaryWaterReflectionTexture.Init( GetWaterReflectionTexture() ); - CTextureReference pReplacementWaterReflectionTexture; - pReplacementWaterReflectionTexture.Init( portalrendertargets->GetWaterReflectionTextureForStencilDepth( iRecursionLevel ) ); - - //get references to refraction textures - CTextureReference pPrimaryWaterRefractionTexture; - pPrimaryWaterRefractionTexture.Init( GetWaterRefractionTexture() ); - CTextureReference pReplacementWaterRefractionTexture; - pReplacementWaterRefractionTexture.Init( portalrendertargets->GetWaterRefractionTextureForStencilDepth( iRecursionLevel ) ); - - - //swap texture contents for the primary render targets with those we set aside for this recursion level - if( pReplacementWaterReflectionTexture != NULL ) - pPrimaryWaterReflectionTexture->SwapContents( pReplacementWaterReflectionTexture ); - - if( pReplacementWaterRefractionTexture != NULL ) - pPrimaryWaterRefractionTexture->SwapContents( pReplacementWaterRefractionTexture ); - - bool bDrew3dSkybox = false; - SkyboxVisibility_t nSkyboxVisible = SKYBOX_NOT_VISIBLE; - int iClearFlags = 0; - - Draw3dSkyboxworld_Portal( view, iClearFlags, bDrew3dSkybox, nSkyboxVisible ); - - bool drawSkybox = r_skybox.GetBool(); - if ( bDrew3dSkybox || ( nSkyboxVisible == SKYBOX_NOT_VISIBLE ) ) - { - drawSkybox = false; - } - - //generate unique view ID's for each stencil view - view_id_t iNewViewID = (view_id_t)g_pPortalRender->GetCurrentViewId(); - SetupCurrentView( view.origin, view.angles, (view_id_t)iNewViewID ); - - // update vis data - unsigned int visFlags; - SetupVis( view, visFlags, pCustomVisibility ); - - VisibleFogVolumeInfo_t fogInfo; - if( g_pPortalRender->GetViewRecursionLevel() == 0 ) - { - render->GetVisibleFogVolume( view.origin, &fogInfo ); - } - else - { - render->GetVisibleFogVolume( g_pPortalRender->GetExitPortalFogOrigin(), &fogInfo ); - } - - WaterRenderInfo_t waterInfo; - DetermineWaterRenderInfo( fogInfo, waterInfo ); - - if ( waterInfo.m_bCheapWater ) - { - cplane_t glassReflectionPlane; - if ( IsReflectiveGlassInView( viewIn, glassReflectionPlane ) ) - { - CRefPtr pGlassReflectionView = new CReflectiveGlassView( this ); - pGlassReflectionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, glassReflectionPlane ); - AddViewToScene( pGlassReflectionView ); - - CRefPtr pGlassRefractionView = new CRefractiveGlassView( this ); - pGlassRefractionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, glassReflectionPlane ); - AddViewToScene( pGlassRefractionView ); - } - - CSimpleWorldView *pClientView = new CSimpleWorldView( this ); - pClientView->Setup( view, VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, pCustomVisibility ); - AddViewToScene( pClientView ); - SafeRelease( pClientView ); - } - else - { - // We can see water of some sort - if ( !fogInfo.m_bEyeInFogVolume ) - { - CRefPtr pAboveWaterView = new CAboveWaterView( this ); - pAboveWaterView->Setup( viewIn, drawSkybox, fogInfo, waterInfo ); - AddViewToScene( pAboveWaterView ); - } - else - { - CRefPtr pUnderWaterView = new CUnderWaterView( this ); - pUnderWaterView->Setup( viewIn, drawSkybox, fogInfo, waterInfo ); - AddViewToScene( pUnderWaterView ); - } - } - - // Disable fog for the rest of the stuff - DisableFog(); - - CGlowOverlay::DrawOverlays( view.m_bCacheFullSceneState ); - - // Draw rain.. - DrawPrecipitation(); - - //prerender version only - // issue the pixel visibility tests - PixelVisibility_EndCurrentView(); - - // Make sure sound doesn't stutter - engine->Sound_ExtraUpdate(); - - // Debugging info goes over the top - CDebugViewRender::Draw3DDebuggingInfo( view ); - - // Return to the previous view - SetupCurrentView( vecOldOrigin, vecOldAngles, (view_id_t)iCurrentViewID ); - g_CurrentViewID = iCurrentViewID; //just in case the cast to view_id_t screwed up the id # - - - //swap back the water render targets - if( pReplacementWaterReflectionTexture != NULL ) - pPrimaryWaterReflectionTexture->SwapContents( pReplacementWaterReflectionTexture ); - - if( pReplacementWaterRefractionTexture != NULL ) - pPrimaryWaterRefractionTexture->SwapContents( pReplacementWaterRefractionTexture ); -} - -void CViewRender::Draw3dSkyboxworld_Portal( const CViewSetup &view, int &nClearFlags, bool &bDrew3dSkybox, SkyboxVisibility_t &nSkyboxVisible, ITexture *pRenderTarget ) -{ - CRefPtr pSkyView = new CPortalSkyboxView( this ); - if ( ( bDrew3dSkybox = pSkyView->Setup( view, &nClearFlags, &nSkyboxVisible, pRenderTarget ) ) == true ) - { - AddViewToScene( pSkyView ); - } -} - -#endif //PORTAL - -//----------------------------------------------------------------------------- -// Methods related to controlling the cheap water distance -//----------------------------------------------------------------------------- -void CViewRender::SetCheapWaterStartDistance( float flCheapWaterStartDistance ) -{ - m_flCheapWaterStartDistance = flCheapWaterStartDistance; -} - -void CViewRender::SetCheapWaterEndDistance( float flCheapWaterEndDistance ) -{ - m_flCheapWaterEndDistance = flCheapWaterEndDistance; -} - -void CViewRender::GetWaterLODParams( float &flCheapWaterStartDistance, float &flCheapWaterEndDistance ) -{ - flCheapWaterStartDistance = m_flCheapWaterStartDistance; - flCheapWaterEndDistance = m_flCheapWaterEndDistance; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : &view - -// &introData - -//----------------------------------------------------------------------------- -void CViewRender::ViewDrawScene_Intro( const CViewSetup &view, int nClearFlags, const IntroData_t &introData ) -{ - VPROF( "CViewRender::ViewDrawScene" ); - - CMatRenderContextPtr pRenderContext( materials ); - - // this allows the refract texture to be updated once per *scene* on 360 - // (e.g. once for a monitor scene and once for the main scene) - g_viewscene_refractUpdateFrame = gpGlobals->framecount - 1; - - // ----------------------------------------------------------------------- - // Set the clear color to black since we are going to be adding up things - // in the frame buffer. - // ----------------------------------------------------------------------- - // Clear alpha to 255 so that masking with the vortigaunts (0) works properly. - pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); - - // ----------------------------------------------------------------------- - // Draw the primary scene and copy it to the first framebuffer texture - // ----------------------------------------------------------------------- - unsigned int visFlags; - - // NOTE: We only increment this once since time doesn't move forward. - ParticleMgr()->IncrementFrameCode(); - - if( introData.m_bDrawPrimary ) - { - CViewSetup playerView( view ); - playerView.origin = introData.m_vecCameraView; - playerView.angles = introData.m_vecCameraViewAngles; - if ( introData.m_playerViewFOV ) - { - playerView.fov = ScaleFOVByWidthRatio( introData.m_playerViewFOV, engine->GetScreenAspectRatio() / ( 4.0f / 3.0f ) ); - } - - g_pClientShadowMgr->PreRender(); - - // Shadowed flashlights supported on ps_2_b and up... - if ( r_flashlightdepthtexture.GetBool() ) - { - g_pClientShadowMgr->ComputeShadowDepthTextures( playerView ); - } - - SetupCurrentView( playerView.origin, playerView.angles, VIEW_INTRO_PLAYER ); - - // Invoke pre-render methods - IGameSystem::PreRenderAllSystems(); - - // Start view, clear frame/z buffer if necessary - SetupVis( playerView, visFlags ); - - render->Push3DView( playerView, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH, NULL, GetFrustum() ); - DrawWorldAndEntities( true /* drawSkybox */, playerView, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH ); - render->PopView( GetFrustum() ); - - // Free shadow depth textures for use in future view - if ( r_flashlightdepthtexture.GetBool() ) - { - g_pClientShadowMgr->UnlockAllShadowDepthTextures(); - } - } - else - { - pRenderContext->ClearBuffers( true, true ); - } - Rect_t actualRect; - UpdateScreenEffectTexture( 0, view.x, view.y, view.width, view.height, false, &actualRect ); - - g_pClientShadowMgr->PreRender(); - - // Shadowed flashlights supported on ps_2_b and up... - if ( r_flashlightdepthtexture.GetBool() ) - { - g_pClientShadowMgr->ComputeShadowDepthTextures( view ); - } - - // ----------------------------------------------------------------------- - // Draw the secondary scene and copy it to the second framebuffer texture - // ----------------------------------------------------------------------- - SetupCurrentView( view.origin, view.angles, VIEW_INTRO_CAMERA ); - - // Invoke pre-render methods - IGameSystem::PreRenderAllSystems(); - - // Start view, clear frame/z buffer if necessary - SetupVis( view, visFlags ); - - // Clear alpha to 255 so that masking with the vortigaunts (0) works properly. - pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); - - DrawWorldAndEntities( true /* drawSkybox */, view, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH ); - - UpdateScreenEffectTexture( 1, view.x, view.y, view.width, view.height ); - - // ----------------------------------------------------------------------- - // Draw quads on the screen for each screenspace pass. - // ----------------------------------------------------------------------- - // Find the material that we use to render the overlays - IMaterial *pOverlayMaterial = materials->FindMaterial( "scripted/intro_screenspaceeffect", TEXTURE_GROUP_OTHER ); - IMaterialVar *pModeVar = pOverlayMaterial->FindVar( "$mode", NULL ); - IMaterialVar *pAlphaVar = pOverlayMaterial->FindVar( "$alpha", NULL ); - - pRenderContext->ClearBuffers( true, true ); - - pRenderContext->MatrixMode( MATERIAL_VIEW ); - pRenderContext->PushMatrix(); - pRenderContext->LoadIdentity(); - - pRenderContext->MatrixMode( MATERIAL_PROJECTION ); - pRenderContext->PushMatrix(); - pRenderContext->LoadIdentity(); - - int passID; - for( passID = 0; passID < introData.m_Passes.Count(); passID++ ) - { - const IntroDataBlendPass_t& pass = introData.m_Passes[passID]; - if ( pass.m_Alpha == 0 ) - continue; - - // Pick one of the blend modes for the material. - if ( pass.m_BlendMode >= 0 && pass.m_BlendMode <= 9 ) - { - pModeVar->SetIntValue( pass.m_BlendMode ); - } - else - { - Assert(0); - } - // Set the alpha value for the material. - pAlphaVar->SetFloatValue( pass.m_Alpha ); - - // Draw a quad for this pass. - ITexture *pTexture = GetFullFrameFrameBufferTexture( 0 ); - pRenderContext->DrawScreenSpaceRectangle( pOverlayMaterial, 0, 0, view.width, view.height, - actualRect.x, actualRect.y, actualRect.x+actualRect.width-1, actualRect.y+actualRect.height-1, - pTexture->GetActualWidth(), pTexture->GetActualHeight() ); - } - - pRenderContext->MatrixMode( MATERIAL_VIEW ); - pRenderContext->PopMatrix(); - - pRenderContext->MatrixMode( MATERIAL_PROJECTION ); - pRenderContext->PopMatrix(); - - // Draw the starfield - // FIXME - // blur? - - // Disable fog for the rest of the stuff - DisableFog(); - - // Here are the overlays... - CGlowOverlay::DrawOverlays( view.m_bCacheFullSceneState ); - - // issue the pixel visibility tests - PixelVisibility_EndCurrentView(); - - // And here are the screen-space effects - PerformScreenSpaceEffects( 0, 0, view.width, view.height ); - - // Make sure sound doesn't stutter - engine->Sound_ExtraUpdate(); - - // Debugging info goes over the top - CDebugViewRender::Draw3DDebuggingInfo( view ); - - // Let the particle manager simulate things that haven't been simulated. - ParticleMgr()->PostRender(); - - FinishCurrentView(); - - // Free shadow depth textures for use in future view - if ( r_flashlightdepthtexture.GetBool() ) - { - g_pClientShadowMgr->UnlockAllShadowDepthTextures(); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Sets up scene and renders camera view -// Input : cameraNum - -// &cameraView -// *localPlayer - -// x - -// y - -// width - -// height - -// highend - -// Output : Returns true on success, false on failure. -//----------------------------------------------------------------------------- -bool CViewRender::DrawOneMonitor( ITexture *pRenderTarget, int cameraNum, C_PointCamera *pCameraEnt, - const CViewSetup &cameraView, C_BasePlayer *localPlayer, int x, int y, int width, int height ) -{ -#ifdef USE_MONITORS - VPROF_INCREMENT_COUNTER( "cameras rendered", 1 ); - // Setup fog state for the camera. - fogparams_t oldFogParams; - float flOldZFar = 0.0f; - - bool fogEnabled = pCameraEnt->IsFogEnabled(); - - CViewSetup monitorView = cameraView; - - fogparams_t *pFogParams = NULL; - - if ( fogEnabled ) - { - if ( !localPlayer ) - return false; - - pFogParams = localPlayer->GetFogParams(); - - // Save old fog data. - oldFogParams = *pFogParams; - flOldZFar = cameraView.zFar; - - pFogParams->enable = true; - pFogParams->start = pCameraEnt->GetFogStart(); - pFogParams->end = pCameraEnt->GetFogEnd(); - pFogParams->farz = pCameraEnt->GetFogEnd(); - pFogParams->maxdensity = pCameraEnt->GetFogMaxDensity(); - - unsigned char r, g, b; - pCameraEnt->GetFogColor( r, g, b ); - pFogParams->colorPrimary.SetR( r ); - pFogParams->colorPrimary.SetG( g ); - pFogParams->colorPrimary.SetB( b ); - - monitorView.zFar = pCameraEnt->GetFogEnd(); - } - - monitorView.width = width; - monitorView.height = height; - monitorView.x = x; - monitorView.y = y; - monitorView.origin = pCameraEnt->GetAbsOrigin(); - monitorView.angles = pCameraEnt->GetAbsAngles(); - monitorView.fov = pCameraEnt->GetFOV(); - monitorView.m_bOrtho = false; - monitorView.m_flAspectRatio = pCameraEnt->UseScreenAspectRatio() ? 0.0f : 1.0f; - monitorView.m_bViewToProjectionOverride = false; - - // @MULTICORE (toml 8/11/2006): this should be a renderer.... - Frustum frustum; - render->Push3DView( monitorView, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, pRenderTarget, (VPlane *)frustum ); - ViewDrawScene( false, SKYBOX_2DSKYBOX_VISIBLE, monitorView, 0, VIEW_MONITOR ); - render->PopView( frustum ); - - // Reset the world fog parameters. - if ( fogEnabled ) - { - if ( pFogParams ) - { - *pFogParams = oldFogParams; - } - monitorView.zFar = flOldZFar; - } -#endif // USE_MONITORS - return true; -} - -void CViewRender::DrawMonitors( const CViewSetup &cameraView ) -{ -#ifdef PORTAL - g_pPortalRender->DrawPortalsToTextures( this, cameraView ); -#endif - -#ifdef USE_MONITORS - - // Early out if no cameras - C_PointCamera *pCameraEnt = GetPointCameraList(); - if ( !pCameraEnt ) - return; - - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - -#ifdef _DEBUG - g_bRenderingCameraView = true; -#endif - - // FIXME: this should check for the ability to do a render target maybe instead. - // FIXME: shouldn't have to truck through all of the visible entities for this!!!! - ITexture *pCameraTarget = GetCameraTexture(); - int width = pCameraTarget->GetActualWidth(); - int height = pCameraTarget->GetActualHeight(); - - C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); - - int cameraNum; - for ( cameraNum = 0; pCameraEnt != NULL; pCameraEnt = pCameraEnt->m_pNext ) - { - if ( !pCameraEnt->IsActive() || pCameraEnt->IsDormant() ) - continue; - - if ( !DrawOneMonitor( pCameraTarget, cameraNum, pCameraEnt, cameraView, player, 0, 0, width, height ) ) - continue; - - ++cameraNum; - } - - if ( IsX360() && cameraNum > 0 ) - { - // resolve render target to system memory texture - // resolving *after* all monitors drawn to ensure a single blit using fastest resolve path - CMatRenderContextPtr pRenderContext( materials ); - pRenderContext->PushRenderTargetAndViewport( pCameraTarget ); - pRenderContext->CopyRenderTargetToTextureEx( pCameraTarget, 0, NULL, NULL ); - pRenderContext->PopRenderTargetAndViewport(); - } - -#ifdef _DEBUG - g_bRenderingCameraView = false; -#endif - -#endif // USE_MONITORS -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- - -ClientWorldListInfo_t *ClientWorldListInfo_t::AllocPooled( const ClientWorldListInfo_t &exemplar ) -{ - size_t nBytes = AlignValue( ( exemplar.m_LeafCount * ((sizeof(LeafIndex_t) * 2) + sizeof(LeafFogVolume_t)) ), 4096 ); - - ClientWorldListInfo_t *pResult = gm_Pool.GetObject(); - - byte *pMemory = (byte *)pResult->m_pLeafList; - - if ( pMemory ) - { - // Previously allocated, add a reference. Otherwise comes out of GetObject as a new object with a refcount of 1 - pResult->AddRef(); - } - - if ( !pMemory || _msize( pMemory ) < nBytes ) - { - pMemory = (byte *)realloc( pMemory, nBytes ); - } - - pResult->m_pLeafList = (LeafIndex_t*)pMemory; - pResult->m_pLeafFogVolume = (LeafFogVolume_t*)( pMemory + exemplar.m_LeafCount * sizeof(LeafIndex_t) ); - pResult->m_pActualLeafIndex = (LeafIndex_t*)( (byte *)( pResult->m_pLeafFogVolume ) + exemplar.m_LeafCount * sizeof(LeafFogVolume_t) ); - - pResult->m_bPooledAlloc = true; - - return pResult; -} - -bool ClientWorldListInfo_t::OnFinalRelease() -{ - if ( m_bPooledAlloc ) - { - Assert( m_pLeafList ); - gm_Pool.PutObject( this ); - return false; - } - return true; -} - -//----------------------------------------------------------------------------- -// Constructor -//----------------------------------------------------------------------------- -CBase3dView::CBase3dView( CViewRender *pMainView ) : -m_pMainView( pMainView ), -m_Frustum( pMainView->m_Frustum ) -{ -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : *pEnt - -// Output : int -//----------------------------------------------------------------------------- -VPlane* CBase3dView::GetFrustum() -{ - // The frustum is only valid while in a RenderView call. - // @MULTICORE (toml 8/11/2006): reimplement this when ready -- Assert(g_bRenderingView || g_bRenderingCameraView || g_bRenderingScreenshot); - return m_Frustum; -} - - -CObjectPool ClientWorldListInfo_t::gm_Pool; - - -//----------------------------------------------------------------------------- -// Base class for 3d views -//----------------------------------------------------------------------------- -CRendering3dView::CRendering3dView(CViewRender *pMainView) : - CBase3dView( pMainView ), - m_pWorldRenderList( NULL ), - m_pRenderablesList( NULL ), - m_pWorldListInfo( NULL ), - m_pCustomVisibility( NULL ), - m_DrawFlags( 0 ), - m_ClearFlags( 0 ) -{ -} - - -//----------------------------------------------------------------------------- -// Sort entities in a back-to-front ordering -//----------------------------------------------------------------------------- -void CRendering3dView::Setup( const CViewSetup &setup ) -{ - // @MULTICORE (toml 8/15/2006): don't reset if parameters don't require it. For now, just reset - memcpy( static_cast(this), &setup, sizeof( setup ) ); - ReleaseLists(); - - m_pRenderablesList = new CClientRenderablesList; - m_pCustomVisibility = NULL; -} - - -//----------------------------------------------------------------------------- -// Sort entities in a back-to-front ordering -//----------------------------------------------------------------------------- -void CRendering3dView::ReleaseLists() -{ - SafeRelease( m_pWorldRenderList ); - SafeRelease( m_pRenderablesList ); - SafeRelease( m_pWorldListInfo ); - m_pCustomVisibility = NULL; -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CRendering3dView::SetupRenderablesList( int viewID ) -{ - VPROF( "CViewRender::SetupRenderablesList" ); - - // Clear the list. - int i; - for( i=0; i < RENDER_GROUP_COUNT; i++ ) - { - m_pRenderablesList->m_RenderGroupCounts[i] = 0; - } - - // Now collate the entities in the leaves. - if( m_pMainView->ShouldDrawEntities() ) - { - // Precache information used commonly in CollateRenderables - SetupRenderInfo_t setupInfo; - setupInfo.m_pWorldListInfo = m_pWorldListInfo; - setupInfo.m_nRenderFrame = m_pMainView->BuildRenderablesListsNumber(); // only one incremented? - setupInfo.m_nDetailBuildFrame = m_pMainView->BuildWorldListsNumber(); // - setupInfo.m_pRenderList = m_pRenderablesList; - setupInfo.m_bDrawDetailObjects = g_pClientMode->ShouldDrawDetailObjects() && r_DrawDetailProps.GetInt(); - setupInfo.m_bDrawTranslucentObjects = (viewID != VIEW_SHADOW_DEPTH_TEXTURE); - - setupInfo.m_vecRenderOrigin = origin; - setupInfo.m_vecRenderForward = CurrentViewForward(); - - float fMaxDist = cl_maxrenderable_dist.GetFloat(); - - // Shadowing light typically has a smaller farz than cl_maxrenderable_dist - setupInfo.m_flRenderDistSq = (viewID == VIEW_SHADOW_DEPTH_TEXTURE) ? MIN(zFar, fMaxDist) : fMaxDist; - setupInfo.m_flRenderDistSq *= setupInfo.m_flRenderDistSq; - - ClientLeafSystem()->BuildRenderablesList( setupInfo ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: Builds lists of things to render in the world, called once per view -//----------------------------------------------------------------------------- -void CRendering3dView::UpdateRenderablesOpacity() -{ - // Compute the prop opacity based on the view position and fov zoom scale - float flFactor = 1.0f; - C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer(); - if ( pLocal ) - { - flFactor = pLocal->GetFOVDistanceAdjustFactor(); - } - - if ( cl_leveloverview.GetFloat() > 0 ) - { - // disable prop fading - flFactor = -1; - } - - // When zoomed in, tweak the opacity to stay visible from further away - staticpropmgr->ComputePropOpacity( origin, flFactor ); - - // Build a list of detail props to render - DetailObjectSystem()->BuildDetailObjectRenderLists( origin ); -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -// Kinda awkward...three optional parameters at the end... -void CRendering3dView::BuildWorldRenderLists( bool bDrawEntities, int iForceViewLeaf /* = -1 */, - bool bUseCacheIfEnabled /* = true */, bool bShadowDepth /* = false */, float *pReflectionWaterHeight /*= NULL*/ ) -{ - VPROF_BUDGET( "BuildWorldRenderLists", VPROF_BUDGETGROUP_WORLD_RENDERING ); - - // @MULTICORE (toml 8/18/2006): to address.... - extern void UpdateClientRenderableInPVSStatus(); - UpdateClientRenderableInPVSStatus(); - - Assert( !m_pWorldRenderList && !m_pWorldListInfo); - - m_pMainView->IncWorldListsNumber(); - // Override vis data if specified this render, otherwise use default behavior with NULL - VisOverrideData_t* pVisData = ( m_pCustomVisibility && m_pCustomVisibility->m_VisData.m_fDistToAreaPortalTolerance != FLT_MAX ) ? &m_pCustomVisibility->m_VisData : NULL; - bool bUseCache = ( bUseCacheIfEnabled && r_worldlistcache.GetBool() ); - if ( !bUseCache || pVisData || !g_WorldListCache.Find( *this, &m_pWorldRenderList, &m_pWorldListInfo ) ) - { - // @MULTICORE (toml 8/18/2006): when make parallel, will have to change caching to be atomic, where follow ons receive a pointer to a list that is not yet built - m_pWorldRenderList = render->CreateWorldList(); - m_pWorldListInfo = new ClientWorldListInfo_t; - - render->BuildWorldLists( m_pWorldRenderList, m_pWorldListInfo, - ( m_pCustomVisibility ) ? m_pCustomVisibility->m_iForceViewLeaf : iForceViewLeaf, - pVisData, bShadowDepth, pReflectionWaterHeight ); - - if ( bUseCache && !pVisData ) - { - g_WorldListCache.Add( *this, m_pWorldRenderList, m_pWorldListInfo ); - } - } - - if ( bDrawEntities ) - { - UpdateRenderablesOpacity(); - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Computes the actual world list info based on the render flags -//----------------------------------------------------------------------------- -void CRendering3dView::PruneWorldListInfo() -{ - // Drawing everything? Just return the world list info as-is - int nWaterDrawFlags = m_DrawFlags & (DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER); - if ( nWaterDrawFlags == (DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER) ) - { - return; - } - - ClientWorldListInfo_t *pNewInfo; - // Only allocate memory if actually will draw something - if ( m_pWorldListInfo->m_LeafCount > 0 && nWaterDrawFlags ) - { - pNewInfo = ClientWorldListInfo_t::AllocPooled( *m_pWorldListInfo ); - } - else - { - pNewInfo = new ClientWorldListInfo_t; - } - - pNewInfo->m_ViewFogVolume = m_pWorldListInfo->m_ViewFogVolume; - pNewInfo->m_LeafCount = 0; - - // Not drawing anything? Then don't bother with renderable lists - if ( nWaterDrawFlags != 0 ) - { - // Create a sub-list based on the actual leaves being rendered - bool bRenderingUnderwater = (nWaterDrawFlags & DF_RENDER_UNDERWATER) != 0; - for ( int i = 0; i < m_pWorldListInfo->m_LeafCount; ++i ) - { - bool bLeafIsUnderwater = ( m_pWorldListInfo->m_pLeafFogVolume[i] != -1 ); - if ( bRenderingUnderwater == bLeafIsUnderwater ) - { - pNewInfo->m_pLeafList[ pNewInfo->m_LeafCount ] = m_pWorldListInfo->m_pLeafList[ i ]; - pNewInfo->m_pLeafFogVolume[ pNewInfo->m_LeafCount ] = m_pWorldListInfo->m_pLeafFogVolume[ i ]; - pNewInfo->m_pActualLeafIndex[ pNewInfo->m_LeafCount ] = i; - ++pNewInfo->m_LeafCount; - } - } - } - - m_pWorldListInfo->Release(); - m_pWorldListInfo = pNewInfo; -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -static inline void UpdateBrushModelLightmap( IClientRenderable *pEnt ) -{ - model_t *pModel = ( model_t * )pEnt->GetModel(); - render->UpdateBrushModelLightmap( pModel, pEnt ); -} - - -void CRendering3dView::BuildRenderableRenderLists( int viewID ) -{ - MDLCACHE_CRITICAL_SECTION(); - - if ( viewID != VIEW_SHADOW_DEPTH_TEXTURE ) - { - render->BeginUpdateLightmaps(); - } - - m_pMainView->IncRenderablesListsNumber(); - - ClientWorldListInfo_t& info = *m_pWorldListInfo; - - // For better sorting, find out the leaf *nearest* to the camera - // and render translucent objects as if they are in that leaf. - if( m_pMainView->ShouldDrawEntities() && ( viewID != VIEW_SHADOW_DEPTH_TEXTURE ) ) - { - ClientLeafSystem()->ComputeTranslucentRenderLeaf( - info.m_LeafCount, info.m_pLeafList, info.m_pLeafFogVolume, m_pMainView->BuildRenderablesListsNumber(), viewID ); - } - - SetupRenderablesList( viewID ); - - if ( viewID == VIEW_MAIN ) - { - StudioStats_FindClosestEntity( m_pRenderablesList ); - } - - if ( viewID != VIEW_SHADOW_DEPTH_TEXTURE ) - { - // update lightmap on brush models if necessary - CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_OPAQUE_BRUSH]; - int nOpaque = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE_BRUSH]; - int i; - for( i=0; i < nOpaque; ++i ) - { - Assert(pEntities[i].m_TwoPass==0); - UpdateBrushModelLightmap( pEntities[i].m_pRenderable ); - } - - // update lightmap on brush models if necessary - pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; - int nTranslucent = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY]; - for( i=0; i < nTranslucent; ++i ) - { - const model_t *pModel = pEntities[i].m_pRenderable->GetModel(); - if( pModel ) - { - int nModelType = modelinfo->GetModelType( pModel ); - if( nModelType == mod_brush ) - { - UpdateBrushModelLightmap( pEntities[i].m_pRenderable ); - } - } - } - - render->EndUpdateLightmaps(); - } -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CRendering3dView::DrawWorld( float waterZAdjust ) -{ - VPROF_INCREMENT_COUNTER( "RenderWorld", 1 ); - VPROF_BUDGET( "DrawWorld", VPROF_BUDGETGROUP_WORLD_RENDERING ); - if( !r_drawopaqueworld.GetBool() ) - { - return; - } - - unsigned long engineFlags = BuildEngineDrawWorldListFlags( m_DrawFlags ); - - render->DrawWorldLists( m_pWorldRenderList, engineFlags, waterZAdjust ); -} - - -CMaterialReference g_material_WriteZ; //init'ed on by CViewRender::Init() - -//----------------------------------------------------------------------------- -// Fakes per-entity clip planes on cards that don't support user clip planes. -// Achieves the effect by drawing an invisible box that writes to the depth buffer -// around the clipped area. It's not perfect, but better than nothing. -//----------------------------------------------------------------------------- -static void DrawClippedDepthBox( IClientRenderable *pEnt, float *pClipPlane ) -{ -//#define DEBUG_DRAWCLIPPEDDEPTHBOX //uncomment to draw the depth box as a colorful box - - static const int iQuads[6][5] = { { 0, 4, 6, 2, 0 }, //always an extra copy of first index at end to make some algorithms simpler - { 3, 7, 5, 1, 3 }, - { 1, 5, 4, 0, 1 }, - { 2, 6, 7, 3, 2 }, - { 0, 2, 3, 1, 0 }, - { 5, 7, 6, 4, 5 } }; - - static const int iLines[12][2] = { { 0, 1 }, - { 0, 2 }, - { 0, 4 }, - { 1, 3 }, - { 1, 5 }, - { 2, 3 }, - { 2, 6 }, - { 3, 7 }, - { 4, 6 }, - { 4, 5 }, - { 5, 7 }, - { 6, 7 } }; - - -#ifdef DEBUG_DRAWCLIPPEDDEPTHBOX - static const float fColors[6][3] = { { 1.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 1.0f }, - { 0.0f, 1.0f, 0.0f }, - { 1.0f, 0.0f, 1.0f }, - { 0.0f, 0.0f, 1.0f }, - { 1.0f, 1.0f, 0.0f } }; -#endif - - - - - Vector vNormal = *(Vector *)pClipPlane; - float fPlaneDist = pClipPlane[3]; - - Vector vMins, vMaxs; - pEnt->GetRenderBounds( vMins, vMaxs ); - - Vector vOrigin = pEnt->GetRenderOrigin(); - QAngle qAngles = pEnt->GetRenderAngles(); - - Vector vForward, vUp, vRight; - AngleVectors( qAngles, &vForward, &vRight, &vUp ); - - Vector vPoints[8]; - vPoints[0] = vOrigin + (vForward * vMins.x) + (vRight * vMins.y) + (vUp * vMins.z); - vPoints[1] = vOrigin + (vForward * vMaxs.x) + (vRight * vMins.y) + (vUp * vMins.z); - vPoints[2] = vOrigin + (vForward * vMins.x) + (vRight * vMaxs.y) + (vUp * vMins.z); - vPoints[3] = vOrigin + (vForward * vMaxs.x) + (vRight * vMaxs.y) + (vUp * vMins.z); - vPoints[4] = vOrigin + (vForward * vMins.x) + (vRight * vMins.y) + (vUp * vMaxs.z); - vPoints[5] = vOrigin + (vForward * vMaxs.x) + (vRight * vMins.y) + (vUp * vMaxs.z); - vPoints[6] = vOrigin + (vForward * vMins.x) + (vRight * vMaxs.y) + (vUp * vMaxs.z); - vPoints[7] = vOrigin + (vForward * vMaxs.x) + (vRight * vMaxs.y) + (vUp * vMaxs.z); - - int iClipped[8]; - float fDists[8]; - for( int i = 0; i != 8; ++i ) - { - fDists[i] = vPoints[i].Dot( vNormal ) - fPlaneDist; - iClipped[i] = (fDists[i] > 0.0f) ? 1 : 0; - } - - Vector vSplitPoints[8][8]; //obviously there are only 12 lines, not 64 lines or 64 split points, but the indexing is way easier like this - int iLineStates[8][8]; //0 = unclipped, 2 = wholly clipped, 3 = first point clipped, 4 = second point clipped - - //categorize lines and generate split points where needed - for( int i = 0; i != 12; ++i ) - { - const int *pPoints = iLines[i]; - int iLineState = (iClipped[pPoints[0]] + iClipped[pPoints[1]]); - if( iLineState != 1 ) //either both points are clipped, or neither are clipped - { - iLineStates[pPoints[0]][pPoints[1]] = - iLineStates[pPoints[1]][pPoints[0]] = - iLineState; - } - else - { - //one point is clipped, the other is not - if( iClipped[pPoints[0]] == 1 ) - { - //first point was clipped, index 1 has the negative distance - float fInvTotalDist = 1.0f / (fDists[pPoints[0]] - fDists[pPoints[1]]); - vSplitPoints[pPoints[0]][pPoints[1]] = - vSplitPoints[pPoints[1]][pPoints[0]] = - (vPoints[pPoints[1]] * (fDists[pPoints[0]] * fInvTotalDist)) - (vPoints[pPoints[0]] * (fDists[pPoints[1]] * fInvTotalDist)); - - Assert( fabs( vNormal.Dot( vSplitPoints[pPoints[0]][pPoints[1]] ) - fPlaneDist ) < 0.01f ); - - iLineStates[pPoints[0]][pPoints[1]] = 3; - iLineStates[pPoints[1]][pPoints[0]] = 4; - } - else - { - //second point was clipped, index 0 has the negative distance - float fInvTotalDist = 1.0f / (fDists[pPoints[1]] - fDists[pPoints[0]]); - vSplitPoints[pPoints[0]][pPoints[1]] = - vSplitPoints[pPoints[1]][pPoints[0]] = - (vPoints[pPoints[0]] * (fDists[pPoints[1]] * fInvTotalDist)) - (vPoints[pPoints[1]] * (fDists[pPoints[0]] * fInvTotalDist)); - - Assert( fabs( vNormal.Dot( vSplitPoints[pPoints[0]][pPoints[1]] ) - fPlaneDist ) < 0.01f ); - - iLineStates[pPoints[0]][pPoints[1]] = 4; - iLineStates[pPoints[1]][pPoints[0]] = 3; - } - } - } - - - CMatRenderContextPtr pRenderContext( materials ); - -#ifdef DEBUG_DRAWCLIPPEDDEPTHBOX - pRenderContext->Bind( materials->FindMaterial( "debug/debugvertexcolor", TEXTURE_GROUP_OTHER ), NULL ); -#else - pRenderContext->Bind( g_material_WriteZ, NULL ); -#endif - - CMeshBuilder meshBuilder; - IMesh* pMesh = pRenderContext->GetDynamicMesh( false ); - meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 18 ); //6 sides, possible one cut per side. Any side is capable of having 3 tri's. Lots of padding for things that aren't possible - - //going to draw as a collection of triangles, arranged as a triangle fan on each side - for( int i = 0; i != 6; ++i ) - { - const int *pPoints = iQuads[i]; - - //can't start the fan on a wholly clipped line, so seek to one that isn't - int j = 0; - do - { - if( iLineStates[pPoints[j]][pPoints[j+1]] != 2 ) //at least part of this line will be drawn - break; - - ++j; - } while( j != 3 ); - - if( j == 3 ) //not enough lines to even form a triangle - continue; - - float *pStartPoint = 0; - float *pTriangleFanPoints[4]; //at most, one of our fans will have 5 points total, with the first point being stored separately as pStartPoint - int iTriangleFanPointCount = 1; //the switch below creates the first for sure - - //figure out how to start the fan - switch( iLineStates[pPoints[j]][pPoints[j+1]] ) - { - case 0: //uncut - pStartPoint = &vPoints[pPoints[j]].x; - pTriangleFanPoints[0] = &vPoints[pPoints[j+1]].x; - break; - - case 4: //second index was clipped - pStartPoint = &vPoints[pPoints[j]].x; - pTriangleFanPoints[0] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x; - break; - - case 3: //first index was clipped - pStartPoint = &vSplitPoints[pPoints[j]][pPoints[j+1]].x; - pTriangleFanPoints[0] = &vPoints[pPoints[j + 1]].x; - break; - - default: - Assert( false ); - break; - }; - - for( ++j; j != 3; ++j ) //add end points for the rest of the indices, we're assembling a triangle fan - { - switch( iLineStates[pPoints[j]][pPoints[j+1]] ) - { - case 0: //uncut line, normal endpoint - pTriangleFanPoints[iTriangleFanPointCount] = &vPoints[pPoints[j+1]].x; - ++iTriangleFanPointCount; - break; - - case 2: //wholly cut line, no endpoint - break; - - case 3: //first point is clipped, normal endpoint - //special case, adds start and end point - pTriangleFanPoints[iTriangleFanPointCount] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x; - ++iTriangleFanPointCount; - - pTriangleFanPoints[iTriangleFanPointCount] = &vPoints[pPoints[j+1]].x; - ++iTriangleFanPointCount; - break; - - case 4: //second point is clipped - pTriangleFanPoints[iTriangleFanPointCount] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x; - ++iTriangleFanPointCount; - break; - - default: - Assert( false ); - break; - }; - } - - //special case endpoints, half-clipped lines have a connecting line between them and the next line (first line in this case) - switch( iLineStates[pPoints[j]][pPoints[j+1]] ) - { - case 3: - case 4: - pTriangleFanPoints[iTriangleFanPointCount] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x; - ++iTriangleFanPointCount; - break; - }; - - Assert( iTriangleFanPointCount <= 4 ); - - //add the fan to the mesh - int iLoopStop = iTriangleFanPointCount - 1; - for( int k = 0; k != iLoopStop; ++k ) - { - meshBuilder.Position3fv( pStartPoint ); -#ifdef DEBUG_DRAWCLIPPEDDEPTHBOX - float fHalfColors[3] = { fColors[i][0] * 0.5f, fColors[i][1] * 0.5f, fColors[i][2] * 0.5f }; - meshBuilder.Color3fv( fHalfColors ); -#endif - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3fv( pTriangleFanPoints[k] ); -#ifdef DEBUG_DRAWCLIPPEDDEPTHBOX - meshBuilder.Color3fv( fColors[i] ); -#endif - meshBuilder.AdvanceVertex(); - - meshBuilder.Position3fv( pTriangleFanPoints[k+1] ); -#ifdef DEBUG_DRAWCLIPPEDDEPTHBOX - meshBuilder.Color3fv( fColors[i] ); -#endif - meshBuilder.AdvanceVertex(); - } - } - - meshBuilder.End(); - pMesh->Draw(); - pRenderContext->Flush( false ); -} - - -//----------------------------------------------------------------------------- -// Draws all opaque renderables in leaves that were rendered -//----------------------------------------------------------------------------- -static inline void DrawOpaqueRenderable( IClientRenderable *pEnt, bool bTwoPass, ERenderDepthMode DepthMode, int nDefaultFlags = 0 ) -{ - tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); - - float color[3]; - - pEnt->GetColorModulation( color ); - render->SetColorModulation( color ); - - int flags = nDefaultFlags | STUDIO_RENDER; - if ( bTwoPass ) - { - flags |= STUDIO_TWOPASS; - } - - if ( DepthMode == DEPTH_MODE_SHADOW ) - { - flags |= STUDIO_SHADOWDEPTHTEXTURE; - } - else if ( DepthMode == DEPTH_MODE_SSA0 ) - { - flags |= STUDIO_SSAODEPTHTEXTURE; - } - - float *pRenderClipPlane = NULL; - if( r_entityclips.GetBool() ) - pRenderClipPlane = pEnt->GetRenderClipPlane(); - - if( pRenderClipPlane ) - { - CMatRenderContextPtr pRenderContext( materials ); - if( !materials->UsingFastClipping() ) //do NOT change the fast clip plane mid-scene, depth problems result. Regular user clip planes are fine though - pRenderContext->PushCustomClipPlane( pRenderClipPlane ); - else - DrawClippedDepthBox( pEnt, pRenderClipPlane ); - Assert( view->GetCurrentlyDrawingEntity() == NULL ); - view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() ); - pEnt->DrawModel( flags ); - view->SetCurrentlyDrawingEntity( NULL ); - if( pRenderClipPlane && !materials->UsingFastClipping() ) - pRenderContext->PopCustomClipPlane(); - } - else - { - Assert( view->GetCurrentlyDrawingEntity() == NULL ); - view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() ); - pEnt->DrawModel( flags ); - view->SetCurrentlyDrawingEntity( NULL ); - } -} - -//------------------------------------- - - -ConVar r_drawopaquestaticpropslast( "r_drawopaquestaticpropslast", "0", 0, "Whether opaque static props are rendered after non-npcs" ); - -#define DEBUG_BUCKETS 0 - -#if DEBUG_BUCKETS -ConVar r_drawopaque_old( "r_drawopaque_old", "0", 0, "Whether old unbucketed technique is used" ); -ConVar r_drawopaquesbucket( "r_drawopaquesbucket", "0", FCVAR_CHEAT, "Draw only specific bucket: positive - props, negative - ents" ); -ConVar r_drawopaquesbucket_stats( "r_drawopaquesbucket_stats", "0", FCVAR_CHEAT, "Draw distribution of props/ents in the buckets" ); -#endif - - -static void SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating ) -{ - pBaseAnimating->SetupBones( NULL, -1, -1, gpGlobals->curtime ); -} - - -static void DrawOpaqueRenderables_DrawBrushModels( CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, ERenderDepthMode DepthMode ) -{ - for( CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity ) - { - Assert( !itEntity->m_TwoPass ); - DrawOpaqueRenderable( itEntity->m_pRenderable, false, DepthMode ); - } -} - -static void DrawOpaqueRenderables_DrawStaticProps( CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, ERenderDepthMode DepthMode ) -{ - if ( pEntitiesEnd == pEntitiesBegin ) - return; - - float one[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - render->SetColorModulation( one ); - render->SetBlend( 1.0f ); - - const int MAX_STATICS_PER_BATCH = 512; - IClientRenderable *pStatics[ MAX_STATICS_PER_BATCH ]; - - int numScheduled = 0, numAvailable = MAX_STATICS_PER_BATCH; - - for( CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity ) - { - if ( itEntity->m_pRenderable ) - NULL; - else - continue; - - if ( g_pStudioStatsEntity != NULL && g_CurrentViewID == VIEW_MAIN && itEntity->m_pRenderable == g_pStudioStatsEntity ) - { - DrawOpaqueRenderable( itEntity->m_pRenderable, false, DepthMode, STUDIO_GENERATE_STATS ); - continue; - } - - pStatics[ numScheduled ++ ] = itEntity->m_pRenderable; - if ( -- numAvailable > 0 ) - continue; // place a hint for compiler to predict more common case in the loop - - staticpropmgr->DrawStaticProps( pStatics, numScheduled, DepthMode, vcollide_wireframe.GetBool() ); - numScheduled = 0; - numAvailable = MAX_STATICS_PER_BATCH; - } - - if ( numScheduled ) - staticpropmgr->DrawStaticProps( pStatics, numScheduled, DepthMode, vcollide_wireframe.GetBool() ); -} - -static void DrawOpaqueRenderables_Range( CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, ERenderDepthMode DepthMode ) -{ - for( CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity ) - { - if ( itEntity->m_pRenderable ) - DrawOpaqueRenderable( itEntity->m_pRenderable, ( itEntity->m_TwoPass != 0 ), DepthMode ); - } -} - -void CRendering3dView::DrawOpaqueRenderables( ERenderDepthMode DepthMode ) -{ - VPROF_BUDGET("CViewRender::DrawOpaqueRenderables", "DrawOpaqueRenderables" ); - - if( !r_drawopaquerenderables.GetBool() ) - return; - - if( !m_pMainView->ShouldDrawEntities() ) - return; - - render->SetBlend( 1 ); - - // - // Prepare to iterate over all leaves that were visible, and draw opaque things in them. - // - RopeManager()->ResetRenderCache(); - g_pParticleSystemMgr->ResetRenderCache(); - - bool const bDrawopaquestaticpropslast = r_drawopaquestaticpropslast.GetBool(); - - - // - // First do the brush models - // - { - CClientRenderablesList::CEntry *pEntitiesBegin, *pEntitiesEnd; - pEntitiesBegin = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_OPAQUE_BRUSH]; - pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE_BRUSH]; - DrawOpaqueRenderables_DrawBrushModels( pEntitiesBegin, pEntitiesEnd, DepthMode ); - } - - - -#if DEBUG_BUCKETS - { - con_nprint_s nxPrn = { 0 }; - nxPrn.index = 16; - nxPrn.time_to_live = -1; - nxPrn.color[0] = 0.9f, nxPrn.color[1] = 1.0f, nxPrn.color[2] = 0.9f; - nxPrn.fixed_width_font = true; - - engine->Con_NXPrintf( &nxPrn, "Draw Opaque Technique : NEW" ); - if ( r_drawopaque_old.GetBool() ) - { - - engine->Con_NXPrintf( &nxPrn, "Draw Opaque Technique : OLD" ); - - // now the static props - { - for ( int bucket = RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS - 1; bucket -- > 0; ) - { - CClientRenderablesList::CEntry - * const pEntitiesBegin = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ], - * const pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ]; - DrawOpaqueRenderables_DrawStaticProps( pEntitiesBegin, pEntitiesEnd, bShadowDepth ); - } - } - - // now the other opaque entities - for ( int bucket = RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS - 1; bucket -- > 0; ) - { - CClientRenderablesList::CEntry - * const pEntitiesBegin = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ], - * const pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ]; - DrawOpaqueRenderables_Range( pEntitiesBegin, pEntitiesEnd, bShadowDepth ); - } - - // - // Ropes and particles - // - RopeManager()->DrawRenderCache( bShadowDepth ); - g_pParticleSystemMgr->DrawRenderCache( bShadowDepth ); - - return; - } - } -#endif - - - - // - // Sort everything that's not a static prop - // - int numOpaqueEnts = 0; - for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket ) - numOpaqueEnts += m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ]; - - CUtlVector< C_BaseAnimating * > arrBoneSetupNpcsLast( (C_BaseAnimating **)_alloca( numOpaqueEnts * sizeof( C_BaseAnimating * ) ), numOpaqueEnts, numOpaqueEnts ); - CUtlVector< CClientRenderablesList::CEntry > arrRenderEntsNpcsFirst( (CClientRenderablesList::CEntry *)_alloca( numOpaqueEnts * sizeof( CClientRenderablesList::CEntry ) ), numOpaqueEnts, numOpaqueEnts ); - int numNpcs = 0, numNonNpcsAnimating = 0; - - for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket ) - { - for( CClientRenderablesList::CEntry - * const pEntitiesBegin = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ], - * const pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ], - *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity ) - { - C_BaseEntity *pEntity = itEntity->m_pRenderable ? itEntity->m_pRenderable->GetIClientUnknown()->GetBaseEntity() : NULL; - if ( pEntity ) - { - if ( pEntity->IsNPC() ) - { - C_BaseAnimating *pba = assert_cast( pEntity ); - arrRenderEntsNpcsFirst[ numNpcs ++ ] = *itEntity; - arrBoneSetupNpcsLast[ numOpaqueEnts - numNpcs ] = pba; - - itEntity->m_pRenderable = NULL; // We will render NPCs separately - itEntity->m_RenderHandle = NULL; - - continue; - } - else if ( pEntity->GetBaseAnimating() ) - { - C_BaseAnimating *pba = assert_cast( pEntity ); - arrBoneSetupNpcsLast[ numNonNpcsAnimating ++ ] = pba; - // fall through - } - } - } - } - - if ( 0 && r_threaded_renderables.GetBool() ) - { - ParallelProcess( "BoneSetupNpcsLast", arrBoneSetupNpcsLast.Base() + numOpaqueEnts - numNpcs, numNpcs, &SetupBonesOnBaseAnimating ); - ParallelProcess( "BoneSetupNpcsLast NonNPCs", arrBoneSetupNpcsLast.Base(), numNonNpcsAnimating, &SetupBonesOnBaseAnimating ); - } - - - // - // Draw static props + opaque entities from the biggest bucket to the smallest - // - { - CClientRenderablesList::CEntry * pEnts[ RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ][2]; - CClientRenderablesList::CEntry * pProps[ RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ][2]; - - for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket ) - { - pEnts[bucket][0] = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ]; - pEnts[bucket][1] = pEnts[bucket][0] + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ]; - - pProps[bucket][0] = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ]; - pProps[bucket][1] = pProps[bucket][0] + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ]; - - // Render sequence debugging - #if DEBUG_BUCKETS - if ( r_drawopaquesbucket_stats.GetBool() ) - { - con_nprint_s nxPrn = { 0 }; - nxPrn.index = 20 + bucket * 3; - nxPrn.time_to_live = -1; - nxPrn.color[0] = 0.9f, nxPrn.color[1] = 1.0f, nxPrn.color[2] = 0.9f; - nxPrn.fixed_width_font = true; - - if ( bDrawopaquestaticpropslast ) - engine->Con_NXPrintf( &nxPrn, "[ %2d ] Ents : %3d", bucket + 1, pEnts[bucket][1] - pEnts[bucket][0] ), - ++ nxPrn.index, - engine->Con_NXPrintf( &nxPrn, "[ %2d ] Props: %3d", bucket + 1, pProps[bucket][1] - pProps[bucket][0] ); - else - engine->Con_NXPrintf( &nxPrn, "[ %2d ] Props: %3d", bucket + 1, pProps[bucket][1] - pProps[bucket][0] ), - ++ nxPrn.index, - engine->Con_NXPrintf( &nxPrn, "[ %2d ] Ents : %3d", bucket + 1, pEnts[bucket][1] - pEnts[bucket][0] ); - } - #endif - } - - -#if DEBUG_BUCKETS - if ( int iBucket = r_drawopaquesbucket.GetInt() ) - { - if ( iBucket > 0 && iBucket <= RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ) - { - DrawOpaqueRenderables_Range( pEnts[iBucket - 1][0], pEnts[iBucket - 1][1], bShadowDepth ); - } - if ( iBucket < 0 && iBucket >= -RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ) - { - DrawOpaqueRenderables_DrawStaticProps( pProps[- 1 - iBucket][0], pProps[- 1 - iBucket][1], bShadowDepth ); - } - } - else -#endif - - for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket ) - { - if ( bDrawopaquestaticpropslast ) - { - DrawOpaqueRenderables_Range( pEnts[bucket][0], pEnts[bucket][1], DepthMode ); - DrawOpaqueRenderables_DrawStaticProps( pProps[bucket][0], pProps[bucket][1], DepthMode ); - } - else - { - DrawOpaqueRenderables_Range( pEnts[bucket][0], pEnts[bucket][1], DepthMode ); - DrawOpaqueRenderables_DrawStaticProps( pProps[bucket][0], pProps[bucket][1], DepthMode ); - } - } - - - } - - // - // Draw NPCs now - // - DrawOpaqueRenderables_Range( arrRenderEntsNpcsFirst.Base(), arrRenderEntsNpcsFirst.Base() + numNpcs, DepthMode ); - - // - // Ropes and particles - // - RopeManager()->DrawRenderCache( DepthMode ); - g_pParticleSystemMgr->DrawRenderCache( DepthMode ); -} - - -//----------------------------------------------------------------------------- -// Renders all translucent world + detail objects in a particular set of leaves -//----------------------------------------------------------------------------- -void CRendering3dView::DrawTranslucentWorldInLeaves( bool bShadowDepth ) -{ - VPROF_BUDGET( "CViewRender::DrawTranslucentWorldInLeaves", VPROF_BUDGETGROUP_WORLD_RENDERING ); - const ClientWorldListInfo_t& info = *m_pWorldListInfo; - for( int iCurLeafIndex = info.m_LeafCount - 1; iCurLeafIndex >= 0; iCurLeafIndex-- ) - { - int nActualLeafIndex = info.m_pActualLeafIndex ? info.m_pActualLeafIndex[ iCurLeafIndex ] : iCurLeafIndex; - Assert( nActualLeafIndex != INVALID_LEAF_INDEX ); - if ( render->LeafContainsTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, m_DrawFlags ) ) - { - // Now draw the surfaces in this leaf - render->DrawTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, m_DrawFlags, bShadowDepth ); - } - } -} - - -//----------------------------------------------------------------------------- -// Renders all translucent world + detail objects in a particular set of leaves -//----------------------------------------------------------------------------- -void CRendering3dView::DrawTranslucentWorldAndDetailPropsInLeaves( int iCurLeafIndex, int iFinalLeafIndex, int nEngineDrawFlags, int &nDetailLeafCount, LeafIndex_t* pDetailLeafList, bool bShadowDepth ) -{ - VPROF_BUDGET( "CViewRender::DrawTranslucentWorldAndDetailPropsInLeaves", VPROF_BUDGETGROUP_WORLD_RENDERING ); - const ClientWorldListInfo_t& info = *m_pWorldListInfo; - for( ; iCurLeafIndex >= iFinalLeafIndex; iCurLeafIndex-- ) - { - int nActualLeafIndex = info.m_pActualLeafIndex ? info.m_pActualLeafIndex[ iCurLeafIndex ] : iCurLeafIndex; - Assert( nActualLeafIndex != INVALID_LEAF_INDEX ); - if ( render->LeafContainsTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, nEngineDrawFlags ) ) - { - // First draw any queued-up detail props from previously visited leaves - DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList ); - nDetailLeafCount = 0; - - // Now draw the surfaces in this leaf - render->DrawTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, nEngineDrawFlags, bShadowDepth ); - } - - // Queue up detail props that existed in this leaf - if ( ClientLeafSystem()->ShouldDrawDetailObjectsInLeaf( info.m_pLeafList[iCurLeafIndex], m_pMainView->BuildWorldListsNumber() ) ) - { - pDetailLeafList[nDetailLeafCount] = info.m_pLeafList[iCurLeafIndex]; - ++nDetailLeafCount; - } - } -} - - -//----------------------------------------------------------------------------- -// Renders all translucent entities in the render list -//----------------------------------------------------------------------------- -static inline void DrawTranslucentRenderable( IClientRenderable *pEnt, bool twoPass, bool bShadowDepth, bool bIgnoreDepth ) -{ - // Determine blending amount and tell engine - float blend = (float)( pEnt->GetFxBlend() / 255.0f ); - - // Totally gone - if ( blend <= 0.0f ) - return; - - if ( pEnt->IgnoresZBuffer() != bIgnoreDepth ) - return; - - // Tell engine - render->SetBlend( blend ); - - float color[3]; - pEnt->GetColorModulation( color ); - render->SetColorModulation( color ); - - int flags = STUDIO_RENDER | STUDIO_TRANSPARENCY; - if ( twoPass ) - flags |= STUDIO_TWOPASS; - - if ( bShadowDepth ) - flags |= STUDIO_SHADOWDEPTHTEXTURE; - - float *pRenderClipPlane = NULL; - if( r_entityclips.GetBool() ) - pRenderClipPlane = pEnt->GetRenderClipPlane(); - - if( pRenderClipPlane ) - { - CMatRenderContextPtr pRenderContext( materials ); - if( !materials->UsingFastClipping() ) //do NOT change the fast clip plane mid-scene, depth problems result. Regular user clip planes are fine though - pRenderContext->PushCustomClipPlane( pRenderClipPlane ); - else - DrawClippedDepthBox( pEnt, pRenderClipPlane ); - Assert( view->GetCurrentlyDrawingEntity() == NULL ); - view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() ); - pEnt->DrawModel( flags ); - view->SetCurrentlyDrawingEntity( NULL ); - - if( pRenderClipPlane && !materials->UsingFastClipping() ) - pRenderContext->PopCustomClipPlane(); - } - else - { - Assert( view->GetCurrentlyDrawingEntity() == NULL ); - view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() ); - pEnt->DrawModel( flags ); - view->SetCurrentlyDrawingEntity( NULL ); - } -} - - -//----------------------------------------------------------------------------- -// Renders all translucent entities in the render list -//----------------------------------------------------------------------------- -void CRendering3dView::DrawTranslucentRenderablesNoWorld( bool bInSkybox ) -{ - VPROF( "CViewRender::DrawTranslucentRenderablesNoWorld" ); - - if ( !m_pMainView->ShouldDrawEntities() || !r_drawtranslucentrenderables.GetBool() ) - return; - - // Draw the particle singletons. - DrawParticleSingletons( bInSkybox ); - - bool bShadowDepth = (m_DrawFlags & ( DF_SHADOW_DEPTH_MAP | DF_SSAO_DEPTH_PASS ) ) != 0; - - CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; - int iCurTranslucentEntity = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - 1; - - while( iCurTranslucentEntity >= 0 ) - { - IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable; - if ( pRenderable->UsesPowerOfTwoFrameBufferTexture() ) - { - UpdateRefractTexture(); - } - - if ( pRenderable->UsesFullFrameBufferTexture() ) - { - UpdateScreenEffectTexture(); - } - - DrawTranslucentRenderable( pRenderable, pEntities[iCurTranslucentEntity].m_TwoPass != 0, bShadowDepth, false ); - --iCurTranslucentEntity; - } - - // Reset the blend state. - render->SetBlend( 1 ); -} - - -//----------------------------------------------------------------------------- -// Renders all translucent entities in the render list that ignore the Z buffer -//----------------------------------------------------------------------------- -void CRendering3dView::DrawNoZBufferTranslucentRenderables( void ) -{ - VPROF( "CViewRender::DrawNoZBufferTranslucentRenderables" ); - - if ( !m_pMainView->ShouldDrawEntities() || !r_drawtranslucentrenderables.GetBool() ) - return; - - bool bShadowDepth = (m_DrawFlags & ( DF_SHADOW_DEPTH_MAP | DF_SSAO_DEPTH_PASS ) ) != 0; - - CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; - int iCurTranslucentEntity = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - 1; - - while( iCurTranslucentEntity >= 0 ) - { - IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable; - if ( pRenderable->UsesPowerOfTwoFrameBufferTexture() ) - { - UpdateRefractTexture(); - } - - if ( pRenderable->UsesFullFrameBufferTexture() ) - { - UpdateScreenEffectTexture(); - } - - DrawTranslucentRenderable( pRenderable, pEntities[iCurTranslucentEntity].m_TwoPass != 0, bShadowDepth, true ); - --iCurTranslucentEntity; - } - - // Reset the blend state. - render->SetBlend( 1 ); -} - - - -//----------------------------------------------------------------------------- -// Renders all translucent world, entities, and detail objects in a particular set of leaves -//----------------------------------------------------------------------------- -void CRendering3dView::DrawTranslucentRenderables( bool bInSkybox, bool bShadowDepth ) -{ - const ClientWorldListInfo_t& info = *m_pWorldListInfo; - -#ifdef PORTAL //if we're in the portal mod, we need to make a detour so we can render portal views using stencil areas - if( ShouldDrawPortals() ) //no recursive stencil views during skybox rendering (although we might be drawing a skybox while already in a recursive stencil view) - { - int iDrawFlagsBackup = m_DrawFlags; - - if( g_pPortalRender->DrawPortalsUsingStencils( (CViewRender *)m_pMainView ) )// @MULTICORE (toml 8/10/2006): remove this hack cast - { - m_DrawFlags = iDrawFlagsBackup; - - //reset visibility - unsigned int iVisFlags = 0; - m_pMainView->SetupVis( *this, iVisFlags, m_pCustomVisibility ); - - //recreate drawlists (since I can't find an easy way to backup the originals) - { - SafeRelease( m_pWorldRenderList ); - SafeRelease( m_pWorldListInfo ); - BuildWorldRenderLists( ((m_DrawFlags & DF_DRAW_ENTITITES) != 0), m_pCustomVisibility ? m_pCustomVisibility->m_iForceViewLeaf : -1, false ); - - AssertMsg( m_DrawFlags & DF_DRAW_ENTITITES, "It shouldn't be possible to get here if this wasn't set, needs special case investigation" ); - for( int i = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY]; --i >= 0; ) - { - m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY][i].m_pRenderable->ComputeFxBlend(); - } - } - - if( r_depthoverlay.GetBool() ) - { - CMatRenderContextPtr pRenderContext( materials ); - ITexture *pDepthTex = GetFullFrameDepthTexture(); - - IMaterial *pMaterial = materials->FindMaterial( "debug/showz", TEXTURE_GROUP_OTHER, true ); - pMaterial->IncrementReferenceCount(); - IMaterialVar *BaseTextureVar = pMaterial->FindVar( "$basetexture", NULL, false ); - IMaterialVar *pDepthInAlpha = NULL; - if( IsPC() ) - { - pDepthInAlpha = pMaterial->FindVar( "$ALPHADEPTH", NULL, false ); - pDepthInAlpha->SetIntValue( 1 ); - } - - BaseTextureVar->SetTextureValue( pDepthTex ); - - pRenderContext->OverrideDepthEnable( true, false ); //don't write to depth, or else we'll never see translucents - pRenderContext->DrawScreenSpaceQuad( pMaterial ); - pRenderContext->OverrideDepthEnable( false, true ); - pMaterial->DecrementReferenceCount(); - } - } - else - { - //done recursing in, time to go back out and do translucents - CMatRenderContextPtr pRenderContext( materials ); - - UpdateFullScreenDepthTexture(); - } - } -#else - { - //opaques generally write depth, and translucents generally don't. - //So immediately after opaques are done is the best time to snap off the depth buffer to a texture. - switch ( g_CurrentViewID ) - { - case VIEW_MAIN: -#ifdef _X360 - case VIEW_INTRO_CAMERA: - case VIEW_INTRO_PLAYER: -#endif - UpdateFullScreenDepthTexture(); - break; - - default: - materials->GetRenderContext()->SetFullScreenDepthTextureValidityFlag( false ); - break; - } - } -#endif - - if ( !r_drawtranslucentworld.GetBool() ) - { - DrawTranslucentRenderablesNoWorld( bInSkybox ); - return; - } - - VPROF_BUDGET( "CViewRender::DrawTranslucentRenderables", "DrawTranslucentRenderables" ); - int iPrevLeaf = info.m_LeafCount - 1; - int nDetailLeafCount = 0; - LeafIndex_t *pDetailLeafList = (LeafIndex_t*)stackalloc( info.m_LeafCount * sizeof(LeafIndex_t) ); - -// bool bDrawUnderWater = (nFlags & DF_RENDER_UNDERWATER) != 0; -// bool bDrawAboveWater = (nFlags & DF_RENDER_ABOVEWATER) != 0; -// bool bDrawWater = (nFlags & DF_RENDER_WATER) != 0; -// bool bClipSkybox = (nFlags & DF_CLIP_SKYBOX ) != 0; - unsigned long nEngineDrawFlags = BuildEngineDrawWorldListFlags( m_DrawFlags & ~DF_DRAWSKYBOX ); - - DetailObjectSystem()->BeginTranslucentDetailRendering(); - - if ( m_pMainView->ShouldDrawEntities() && r_drawtranslucentrenderables.GetBool() ) - { - MDLCACHE_CRITICAL_SECTION(); - // Draw the particle singletons. - DrawParticleSingletons( bInSkybox ); - - CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; - int iCurTranslucentEntity = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - 1; - - bool bRenderingWaterRenderTargets = m_DrawFlags & ( DF_RENDER_REFRACTION | DF_RENDER_REFLECTION ); - - while( iCurTranslucentEntity >= 0 ) - { - // Seek the current leaf up to our current translucent-entity leaf. - int iThisLeaf = pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf; - - // First draw the translucent parts of the world up to and including those in this leaf - DrawTranslucentWorldAndDetailPropsInLeaves( iPrevLeaf, iThisLeaf, nEngineDrawFlags, nDetailLeafCount, pDetailLeafList, bShadowDepth ); - - // We're traversing the leaf list backwards to get the appropriate sort ordering (back to front) - iPrevLeaf = iThisLeaf - 1; - - // Draw all the translucent entities with this leaf. - int nLeaf = info.m_pLeafList[iThisLeaf]; - - bool bDrawDetailProps = ClientLeafSystem()->ShouldDrawDetailObjectsInLeaf( nLeaf, m_pMainView->BuildWorldListsNumber() ); - if ( bDrawDetailProps ) - { - // Draw detail props up to but not including this leaf - Assert( nDetailLeafCount > 0 ); - --nDetailLeafCount; - Assert( pDetailLeafList[nDetailLeafCount] == nLeaf ); - DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList ); - - // Draw translucent renderables in the leaf interspersed with detail props - for( ;pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf == iThisLeaf && iCurTranslucentEntity >= 0; --iCurTranslucentEntity ) - { - IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable; - - // Draw any detail props in this leaf that's farther than the entity - const Vector &vecRenderOrigin = pRenderable->GetRenderOrigin(); - DetailObjectSystem()->RenderTranslucentDetailObjectsInLeaf( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nLeaf, &vecRenderOrigin ); - - bool bUsesPowerOfTwoFB = pRenderable->UsesPowerOfTwoFrameBufferTexture(); - bool bUsesFullFB = pRenderable->UsesFullFrameBufferTexture(); - - if ( ( bUsesPowerOfTwoFB || bUsesFullFB )&& !bShadowDepth ) - { - if( bRenderingWaterRenderTargets ) - { - continue; - } - - CMatRenderContextPtr pRenderContext( materials ); - ITexture *rt = pRenderContext->GetRenderTarget(); - - if ( rt && bUsesFullFB ) - { - UpdateScreenEffectTexture( 0, 0, 0, rt->GetActualWidth(), rt->GetActualHeight(), true ); - } - else if ( bUsesPowerOfTwoFB ) - { - UpdateRefractTexture(); - } - - pRenderContext.SafeRelease(); - } - - // Then draw the translucent renderable - DrawTranslucentRenderable( pRenderable, (pEntities[iCurTranslucentEntity].m_TwoPass != 0), bShadowDepth, false ); - } - - // Draw all remaining props in this leaf - DetailObjectSystem()->RenderTranslucentDetailObjectsInLeaf( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nLeaf, NULL ); - } - else - { - // Draw queued up detail props (we know that the list of detail leaves won't include this leaf, since ShouldDrawDetailObjectsInLeaf is false) - // Therefore no fixup on nDetailLeafCount is required as in the above section - DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList ); - - for( ;pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf == iThisLeaf && iCurTranslucentEntity >= 0; --iCurTranslucentEntity ) - { - IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable; - - bool bUsesPowerOfTwoFB = pRenderable->UsesPowerOfTwoFrameBufferTexture(); - bool bUsesFullFB = pRenderable->UsesFullFrameBufferTexture(); - - if ( ( bUsesPowerOfTwoFB || bUsesFullFB )&& !bShadowDepth ) - { - if( bRenderingWaterRenderTargets ) - { - continue; - } - - CMatRenderContextPtr pRenderContext( materials ); - ITexture *rt = pRenderContext->GetRenderTarget(); - - if ( rt ) - { - if ( bUsesFullFB ) - { - UpdateScreenEffectTexture( 0, 0, 0, rt->GetActualWidth(), rt->GetActualHeight(), true ); - } - else if ( bUsesPowerOfTwoFB ) - { - UpdateRefractTexture(0, 0, rt->GetActualWidth(), rt->GetActualHeight()); - } - } - else - { - if ( bUsesPowerOfTwoFB ) - { - UpdateRefractTexture(); - } - } - - pRenderContext.SafeRelease(); - } - - DrawTranslucentRenderable( pRenderable, (pEntities[iCurTranslucentEntity].m_TwoPass != 0), bShadowDepth, false ); - } - } - - nDetailLeafCount = 0; - } - } - - // Draw the rest of the surfaces in world leaves - DrawTranslucentWorldAndDetailPropsInLeaves( iPrevLeaf, 0, nEngineDrawFlags, nDetailLeafCount, pDetailLeafList, bShadowDepth ); - - // Draw any queued-up detail props from previously visited leaves - DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList ); - - // Reset the blend state. - render->SetBlend( 1 ); -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CRendering3dView::EnableWorldFog( void ) -{ - VPROF("CViewRender::EnableWorldFog"); - CMatRenderContextPtr pRenderContext( materials ); - - fogparams_t *pFogParams = NULL; - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if ( pbp ) - { - pFogParams = pbp->GetFogParams(); - } - - if( GetFogEnable( pFogParams ) ) - { - float fogColor[3]; - GetFogColor( pFogParams, fogColor ); - pRenderContext->FogMode( MATERIAL_FOG_LINEAR ); - pRenderContext->FogColor3fv( fogColor ); - pRenderContext->FogStart( GetFogStart( pFogParams ) ); - pRenderContext->FogEnd( GetFogEnd( pFogParams ) ); - pRenderContext->FogMaxDensity( GetFogMaxDensity( pFogParams ) ); - } - else - { - pRenderContext->FogMode( MATERIAL_FOG_NONE ); - } -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -int CRendering3dView::GetDrawFlags() -{ - return m_DrawFlags; -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CRendering3dView::SetFogVolumeState( const VisibleFogVolumeInfo_t &fogInfo, bool bUseHeightFog ) -{ - render->SetFogVolumeState( fogInfo.m_nVisibleFogVolume, bUseHeightFog ); - -#ifdef PORTAL - - //the idea behind fog shifting is this... - //Normal fog simulates the effect of countless tiny particles between your viewpoint and whatever geometry is rendering. - //But, when rendering to a portal view, there's a large space between the virtual camera and the portal exit surface. - //This space isn't supposed to exist, and therefore has none of the tiny particles that make up fog. - //So, we have to shift fog start/end out to align the distances with the portal exit surface instead of the virtual camera to eliminate fog simulation in the non-space - if( g_pPortalRender->GetViewRecursionLevel() == 0 ) - return; //rendering one of the primary views, do nothing - - g_pPortalRender->ShiftFogForExitPortalView(); - -#endif //#ifdef PORTAL -} - - -//----------------------------------------------------------------------------- -// Standard 3d skybox view -//----------------------------------------------------------------------------- -SkyboxVisibility_t CSkyboxView::ComputeSkyboxVisibility() -{ - return engine->IsSkyboxVisibleFromPoint( origin ); -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -bool CSkyboxView::GetSkyboxFogEnable() -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return false; - } - CPlayerLocalData *local = &pbp->m_Local; - - if( fog_override.GetInt() ) - { - if( fog_enableskybox.GetInt() ) - { - return true; - } - else - { - return false; - } - } - else - { - return !!local->m_skybox3d.fog.enable; - } -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CSkyboxView::Enable3dSkyboxFog( void ) -{ - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - if( !pbp ) - { - return; - } - CPlayerLocalData *local = &pbp->m_Local; - - CMatRenderContextPtr pRenderContext( materials ); - - if( GetSkyboxFogEnable() ) - { - float fogColor[3]; - GetSkyboxFogColor( fogColor ); - float scale = 1.0f; - if ( local->m_skybox3d.scale > 0.0f ) - { - scale = 1.0f / local->m_skybox3d.scale; - } - pRenderContext->FogMode( MATERIAL_FOG_LINEAR ); - pRenderContext->FogColor3fv( fogColor ); - pRenderContext->FogStart( GetSkyboxFogStart() * scale ); - pRenderContext->FogEnd( GetSkyboxFogEnd() * scale ); - pRenderContext->FogMaxDensity( GetSkyboxFogMaxDensity() ); - } - else - { - pRenderContext->FogMode( MATERIAL_FOG_NONE ); - } -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -sky3dparams_t *CSkyboxView::PreRender3dSkyboxWorld( SkyboxVisibility_t nSkyboxVisible ) -{ - if ( ( nSkyboxVisible != SKYBOX_3DSKYBOX_VISIBLE ) && r_3dsky.GetInt() != 2 ) - return NULL; - - // render the 3D skybox - if ( !r_3dsky.GetInt() ) - return NULL; - - C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); - - // No local player object yet... - if ( !pbp ) - return NULL; - - CPlayerLocalData* local = &pbp->m_Local; - if ( local->m_skybox3d.area == 255 ) - return NULL; - - return &local->m_skybox3d; -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CSkyboxView::DrawInternal( view_id_t iSkyBoxViewID, bool bInvokePreAndPostRender, ITexture *pRenderTarget, ITexture *pDepthTarget ) -{ - unsigned char **areabits = render->GetAreaBits(); - unsigned char *savebits; - unsigned char tmpbits[ 32 ]; - savebits = *areabits; - memset( tmpbits, 0, sizeof(tmpbits) ); - - // set the sky area bit - tmpbits[m_pSky3dParams->area>>3] |= 1 << (m_pSky3dParams->area&7); - - *areabits = tmpbits; - - // if you can get really close to the skybox geometry it's possible that you'll be able to clip into it - // with this near plane. If so, move it in a bit. It's at 2.0 to give us more precision. That means you - // need to keep the eye position at least 2 * scale away from the geometry in the skybox - zNear = 2.0; - zFar = MAX_TRACE_LENGTH; - - // scale origin by sky scale - if ( m_pSky3dParams->scale > 0 ) - { - float scale = 1.0f / m_pSky3dParams->scale; - VectorScale( origin, scale, origin ); - } - Enable3dSkyboxFog(); - VectorAdd( origin, m_pSky3dParams->origin, origin ); - - // BUGBUG: Fix this!!! We shouldn't need to call setup vis for the sky if we're connecting - // the areas. We'd have to mark all the clusters in the skybox area in the PVS of any - // cluster with sky. Then we could just connect the areas to do our vis. - //m_bOverrideVisOrigin could hose us here, so call direct - render->ViewSetupVis( false, 1, &m_pSky3dParams->origin.Get() ); - render->Push3DView( (*this), m_ClearFlags, pRenderTarget, GetFrustum(), pDepthTarget ); - - // Store off view origin and angles - SetupCurrentView( origin, angles, iSkyBoxViewID ); - -#if defined( _X360 ) - CMatRenderContextPtr pRenderContext( materials ); - pRenderContext->PushVertexShaderGPRAllocation( 32 ); - pRenderContext.SafeRelease(); -#endif - - // Invoke pre-render methods - if ( bInvokePreAndPostRender ) - { - IGameSystem::PreRenderAllSystems(); - } - - render->BeginUpdateLightmaps(); - BuildWorldRenderLists( true, true, -1 ); - BuildRenderableRenderLists( iSkyBoxViewID ); - render->EndUpdateLightmaps(); - - g_pClientShadowMgr->ComputeShadowTextures( (*this), m_pWorldListInfo->m_LeafCount, m_pWorldListInfo->m_pLeafList ); - - DrawWorld( 0.0f ); - - // Iterate over all leaves and render objects in those leaves - DrawOpaqueRenderables( DEPTH_MODE_NORMAL ); - - // Iterate over all leaves and render objects in those leaves - DrawTranslucentRenderables( true, false ); - DrawNoZBufferTranslucentRenderables(); - - m_pMainView->DisableFog(); - - CGlowOverlay::UpdateSkyOverlays( zFar, m_bCacheFullSceneState ); - - PixelVisibility_EndCurrentView(); - - // restore old area bits - *areabits = savebits; - - // Invoke post-render methods - if( bInvokePreAndPostRender ) - { - IGameSystem::PostRenderAllSystems(); - FinishCurrentView(); - } - - render->PopView( GetFrustum() ); - -#if defined( _X360 ) - pRenderContext.GetFrom( materials ); - pRenderContext->PopVertexShaderGPRAllocation(); -#endif -} - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -bool CSkyboxView::Setup( const CViewSetup &view, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible ) -{ - BaseClass::Setup( view ); - - // The skybox might not be visible from here - *pSkyboxVisible = ComputeSkyboxVisibility(); - m_pSky3dParams = PreRender3dSkyboxWorld( *pSkyboxVisible ); - - if ( !m_pSky3dParams ) - { - return false; - } - - // At this point, we've cleared everything we need to clear - // The next path will need to clear depth, though. - m_ClearFlags = *pClearFlags; - *pClearFlags &= ~( VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH | VIEW_CLEAR_STENCIL | VIEW_CLEAR_FULL_TARGET ); - *pClearFlags |= VIEW_CLEAR_DEPTH; // Need to clear depth after rednering the skybox - - m_DrawFlags = DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER | DF_RENDER_WATER; - if( r_skybox.GetBool() ) - { - m_DrawFlags |= DF_DRAWSKYBOX; - } - - return true; -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CSkyboxView::Draw() -{ - VPROF_BUDGET( "CViewRender::Draw3dSkyboxworld", "3D Skybox" ); - - ITexture *pRTColor = NULL; - ITexture *pRTDepth = NULL; - if( m_eStereoEye != STEREO_EYE_MONO ) - { - pRTColor = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(m_eStereoEye-1), ISourceVirtualReality::RT_Color ); - pRTDepth = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(m_eStereoEye-1), ISourceVirtualReality::RT_Depth ); - } - - DrawInternal(VIEW_3DSKY, true, pRTColor, pRTDepth ); -} - - -#ifdef PORTAL -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -bool CPortalSkyboxView::Setup( const CViewSetup &view, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible, ITexture *pRenderTarget ) -{ - if ( !BaseClass::Setup( view, pClearFlags, pSkyboxVisible ) ) - return false; - - m_pRenderTarget = pRenderTarget; - return true; -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -SkyboxVisibility_t CPortalSkyboxView::ComputeSkyboxVisibility() -{ - return g_pPortalRender->IsSkyboxVisibleFromExitPortal(); -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CPortalSkyboxView::Draw() -{ - AssertMsg( (g_pPortalRender->GetViewRecursionLevel() != 0) && g_pPortalRender->IsRenderingPortal(), "This is designed for through-portal views. Use the regular skybox drawing code for primary views" ); - - VPROF_BUDGET( "CViewRender::Draw3dSkyboxworld_Portal", "3D Skybox (portal view)" ); - - int iCurrentViewID = g_CurrentViewID; - - Frustum FrustumBackup; - memcpy( FrustumBackup, GetFrustum(), sizeof( Frustum ) ); - - CMatRenderContextPtr pRenderContext( materials ); - - bool bClippingEnabled = pRenderContext->EnableClipping( false ); - - //NOTE: doesn't magically map to VIEW_3DSKY at (0,0) like PORTAL_VIEWID maps to VIEW_MAIN - view_id_t iSkyBoxViewID = (view_id_t)g_pPortalRender->GetCurrentSkyboxViewId(); - - bool bInvokePreAndPostRender = ( g_pPortalRender->ShouldUseStencilsToRenderPortals() == false ); - - DrawInternal( iSkyBoxViewID, bInvokePreAndPostRender, m_pRenderTarget, NULL ); - - pRenderContext->EnableClipping( bClippingEnabled ); - - memcpy( GetFrustum(), FrustumBackup, sizeof( Frustum ) ); - render->OverrideViewFrustum( FrustumBackup ); - - g_CurrentViewID = iCurrentViewID; -} -#endif // PORTAL - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CShadowDepthView::Setup( const CViewSetup &shadowViewIn, ITexture *pRenderTarget, ITexture *pDepthTexture ) -{ - BaseClass::Setup( shadowViewIn ); - m_pRenderTarget = pRenderTarget; - m_pDepthTexture = pDepthTexture; -} - - -bool DrawingShadowDepthView( void ) //for easy externing -{ - return (CurrentViewID() == VIEW_SHADOW_DEPTH_TEXTURE); -} - -bool DrawingMainView() //for easy externing -{ - return (CurrentViewID() == VIEW_MAIN); -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CShadowDepthView::Draw() -{ - VPROF_BUDGET( "CShadowDepthView::Draw", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - - // Start view - unsigned int visFlags; - m_pMainView->SetupVis( (*this), visFlags ); // @MULTICORE (toml 8/9/2006): Portal problem, not sending custom vis down - - CMatRenderContextPtr pRenderContext( materials ); - - pRenderContext->ClearColor3ub(0xFF, 0xFF, 0xFF); - -#if defined( _X360 ) - pRenderContext->PushVertexShaderGPRAllocation( 112 ); //almost all work is done in vertex shaders for depth rendering, max out their threads -#endif - - pRenderContext.SafeRelease(); - - if( IsPC() ) - { - render->Push3DView( (*this), VIEW_CLEAR_DEPTH, m_pRenderTarget, GetFrustum(), m_pDepthTexture ); - } - else if( IsX360() ) - { - //for the 360, the dummy render target has a separate depth buffer which we Resolve() from afterward - render->Push3DView( (*this), VIEW_CLEAR_DEPTH, m_pRenderTarget, GetFrustum() ); - } - - SetupCurrentView( origin, angles, VIEW_SHADOW_DEPTH_TEXTURE ); - - MDLCACHE_CRITICAL_SECTION(); - - { - VPROF_BUDGET( "BuildWorldRenderLists", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - BuildWorldRenderLists( true, -1, true, true ); // @MULTICORE (toml 8/9/2006): Portal problem, not sending custom vis down - } - - { - VPROF_BUDGET( "BuildRenderableRenderLists", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - BuildRenderableRenderLists( CurrentViewID() ); - } - - engine->Sound_ExtraUpdate(); // Make sure sound doesn't stutter - - m_DrawFlags = m_pMainView->GetBaseDrawFlags() | DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER | DF_SHADOW_DEPTH_MAP; // Don't draw water surface... - - { - VPROF_BUDGET( "DrawWorld", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - DrawWorld( 0.0f ); - } - - // Draw opaque and translucent renderables with appropriate override materials - // OVERRIDE_DEPTH_WRITE is OK with a NULL material pointer - modelrender->ForcedMaterialOverride( NULL, OVERRIDE_DEPTH_WRITE ); - - { - VPROF_BUDGET( "DrawOpaqueRenderables", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - DrawOpaqueRenderables( DEPTH_MODE_SHADOW ); - } - - modelrender->ForcedMaterialOverride( 0 ); - - m_DrawFlags = 0; - - pRenderContext.GetFrom( materials ); - - if( IsX360() ) - { - //Resolve() the depth texture here. Before the pop so the copy will recognize that the resolutions are the same - pRenderContext->CopyRenderTargetToTextureEx( m_pDepthTexture, -1, NULL, NULL ); - } - - render->PopView( GetFrustum() ); - -#if defined( _X360 ) - pRenderContext->PopVertexShaderGPRAllocation(); -#endif -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CFreezeFrameView::Setup( const CViewSetup &shadowViewIn ) -{ - BaseClass::Setup( shadowViewIn ); - - KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); - pVMTKeyValues->SetString( "$basetexture", IsX360() ? "_rt_FullFrameFB1" : "_rt_FullScreen" ); - pVMTKeyValues->SetInt( "$nocull", 1 ); - pVMTKeyValues->SetInt( "$nofog", 1 ); - pVMTKeyValues->SetInt( "$ignorez", 1 ); - m_pFreezeFrame.Init( "FreezeFrame_FullScreen", TEXTURE_GROUP_OTHER, pVMTKeyValues ); - m_pFreezeFrame->Refresh(); - - m_TranslucentSingleColor.Init( "debug/debugtranslucentsinglecolor", TEXTURE_GROUP_OTHER ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CFreezeFrameView::Draw( void ) -{ - CMatRenderContextPtr pRenderContext( materials ); - -#if defined( _X360 ) - pRenderContext->PushVertexShaderGPRAllocation( 16 ); //max out pixel shader threads -#endif - - // we might only need half of the texture if we're rendering in stereo - int nTexX0 = 0, nTexY0 = 0; - int nTexX1 = width, nTexY1 = height; - int nTexWidth = width, nTexHeight = height; - - switch( m_eStereoEye ) - { - case STEREO_EYE_LEFT: - nTexX1 = width; - nTexWidth *= 2; - break; - - case STEREO_EYE_RIGHT: - nTexX0 = width; - nTexX1 = width*2; - nTexWidth *= 2; - break; - } - - pRenderContext->DrawScreenSpaceRectangle( m_pFreezeFrame, x, y, width, height, - nTexX0, nTexY0, nTexX1-1, nTexY1-1, nTexWidth, nTexHeight ); - - //Fake a fade during freezeframe view. - if ( g_flFreezeFlash >= gpGlobals->curtime && engine->IsTakingScreenshot() == false ) - { - // Overlay screen fade on entire screen - IMaterial* pMaterial = m_TranslucentSingleColor; - - int iFadeAlpha = FREEZECAM_SNAPSHOT_FADE_SPEED * ( g_flFreezeFlash - gpGlobals->curtime ); - - iFadeAlpha = MIN( iFadeAlpha, 255 ); - iFadeAlpha = MAX( 0, iFadeAlpha ); - - pMaterial->AlphaModulate( iFadeAlpha * ( 1.0f / 255.0f ) ); - pMaterial->ColorModulate( 1.0f, 1.0f, 1.0f ); - pMaterial->SetMaterialVarFlag( MATERIAL_VAR_IGNOREZ, true ); - - pRenderContext->DrawScreenSpaceRectangle( pMaterial, x, y, width, height, 0, 0, width-1, height-1, width, height ); - } - -#if defined( _X360 ) - pRenderContext->PopVertexShaderGPRAllocation(); -#endif -} - -//----------------------------------------------------------------------------- -// Pops a water render target -//----------------------------------------------------------------------------- -bool CBaseWorldView::AdjustView( float waterHeight ) -{ - if( m_DrawFlags & DF_RENDER_REFRACTION ) - { - ITexture *pTexture = GetWaterRefractionTexture(); - - // Use the aspect ratio of the main view! So, don't recompute it here - x = y = 0; - width = pTexture->GetActualWidth(); - height = pTexture->GetActualHeight(); - - return true; - } - - if( m_DrawFlags & DF_RENDER_REFLECTION ) - { - ITexture *pTexture = GetWaterReflectionTexture(); - - // If the main view is overriding the projection matrix (for Stereo or - // some other nefarious purpose) make sure to include any Y offset in - // the custom projection matrix in our reflected overridden projection - // matrix. - if( m_bViewToProjectionOverride ) - { - m_ViewToProjection[1][2] = -m_ViewToProjection[1][2]; - } - - // Use the aspect ratio of the main view! So, don't recompute it here - x = y = 0; - width = pTexture->GetActualWidth(); - height = pTexture->GetActualHeight(); - angles[0] = -angles[0]; - angles[2] = -angles[2]; - origin[2] -= 2.0f * ( origin[2] - (waterHeight)); - return true; - } - - return false; -} - - -//----------------------------------------------------------------------------- -// Pops a water render target -//----------------------------------------------------------------------------- -void CBaseWorldView::PushView( float waterHeight ) -{ - float spread = 2.0f; - if( m_DrawFlags & DF_FUDGE_UP ) - { - waterHeight += spread; - } - else - { - waterHeight -= spread; - } - - MaterialHeightClipMode_t clipMode = MATERIAL_HEIGHTCLIPMODE_DISABLE; - if ( ( m_DrawFlags & DF_CLIP_Z ) && mat_clipz.GetBool() ) - { - if( m_DrawFlags & DF_CLIP_BELOW ) - { - clipMode = MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT; - } - else - { - clipMode = MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT; - } - } - - CMatRenderContextPtr pRenderContext( materials ); - - if( m_DrawFlags & DF_RENDER_REFRACTION ) - { - pRenderContext->SetFogZ( waterHeight ); - pRenderContext->SetHeightClipZ( waterHeight ); - pRenderContext->SetHeightClipMode( clipMode ); - - // Have to re-set up the view since we reset the size - render->Push3DView( *this, m_ClearFlags, GetWaterRefractionTexture(), GetFrustum() ); - - return; - } - - if( m_DrawFlags & DF_RENDER_REFLECTION ) - { - ITexture *pTexture = GetWaterReflectionTexture(); - - pRenderContext->SetFogZ( waterHeight ); - - bool bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping(); - if( bSoftwareUserClipPlane && ( origin[2] > waterHeight - r_eyewaterepsilon.GetFloat() ) ) - { - waterHeight = origin[2] + r_eyewaterepsilon.GetFloat(); - } - - pRenderContext->SetHeightClipZ( waterHeight ); - pRenderContext->SetHeightClipMode( clipMode ); - - render->Push3DView( *this, m_ClearFlags, pTexture, GetFrustum() ); - - SetLightmapScaleForWater(); - return; - } - - if ( m_ClearFlags & ( VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_STENCIL ) ) - { - if ( m_ClearFlags & VIEW_CLEAR_OBEY_STENCIL ) - { - pRenderContext->ClearBuffersObeyStencil( m_ClearFlags & VIEW_CLEAR_COLOR, m_ClearFlags & VIEW_CLEAR_DEPTH ); - } - else - { - pRenderContext->ClearBuffers( m_ClearFlags & VIEW_CLEAR_COLOR, m_ClearFlags & VIEW_CLEAR_DEPTH, m_ClearFlags & VIEW_CLEAR_STENCIL ); - } - } - - pRenderContext->SetHeightClipMode( clipMode ); - if ( clipMode != MATERIAL_HEIGHTCLIPMODE_DISABLE ) - { - pRenderContext->SetHeightClipZ( waterHeight ); - } -} - - -//----------------------------------------------------------------------------- -// Pops a water render target -//----------------------------------------------------------------------------- -void CBaseWorldView::PopView() -{ - CMatRenderContextPtr pRenderContext( materials ); - - pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE ); - if( m_DrawFlags & (DF_RENDER_REFRACTION | DF_RENDER_REFLECTION) ) - { - if ( IsX360() ) - { - // these renders paths used their surfaces, so blit their results - if ( m_DrawFlags & DF_RENDER_REFRACTION ) - { - pRenderContext->CopyRenderTargetToTextureEx( GetWaterRefractionTexture(), NULL, NULL ); - } - if ( m_DrawFlags & DF_RENDER_REFLECTION ) - { - pRenderContext->CopyRenderTargetToTextureEx( GetWaterReflectionTexture(), NULL, NULL ); - } - } - - render->PopView( GetFrustum() ); - if (SavedLinearLightMapScale.x>=0) - { - pRenderContext->SetToneMappingScaleLinear(SavedLinearLightMapScale); - SavedLinearLightMapScale.x=-1; - } - } -} - - -//----------------------------------------------------------------------------- -// Draws the world + entities -//----------------------------------------------------------------------------- -void CBaseWorldView::DrawSetup( float waterHeight, int nSetupFlags, float waterZAdjust, int iForceViewLeaf ) -{ - int savedViewID = g_CurrentViewID; - g_CurrentViewID = VIEW_ILLEGAL; - - bool bViewChanged = AdjustView( waterHeight ); - - if ( bViewChanged ) - { - render->Push3DView( *this, 0, NULL, GetFrustum() ); - } - - render->BeginUpdateLightmaps(); - - bool bDrawEntities = ( nSetupFlags & DF_DRAW_ENTITITES ) != 0; - bool bDrawReflection = ( nSetupFlags & DF_RENDER_REFLECTION ) != 0; - BuildWorldRenderLists( bDrawEntities, iForceViewLeaf, true, false, bDrawReflection ? &waterHeight : NULL ); - - PruneWorldListInfo(); - - if ( bDrawEntities ) - { - BuildRenderableRenderLists( savedViewID ); - } - - render->EndUpdateLightmaps(); - - if ( bViewChanged ) - { - render->PopView( GetFrustum() ); - } - -#ifdef TF_CLIENT_DLL - bool bVisionOverride = ( localplayer_visionflags.GetInt() & ( 0x01 ) ); // Pyro-vision Goggles - - if ( savedViewID == VIEW_MAIN && bVisionOverride && pyro_dof.GetBool() ) - { - SSAO_DepthPass(); - } -#endif - - g_CurrentViewID = savedViewID; -} - - -void MaybeInvalidateLocalPlayerAnimation() -{ - C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); - if ( ( pPlayer != NULL ) && pPlayer->InFirstPersonView() ) - { - // We sometimes need different animation for the main view versus the shadow rendering, - // so we need to reset the cache to ensure this actually happens. - pPlayer->InvalidateBoneCache(); - - C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); - if ( pWeapon != NULL ) - { - pWeapon->InvalidateBoneCache(); - } - -#if defined USES_ECON_ITEMS - // ...and all the things you're wearing/holding/etc - int NumWearables = pPlayer->GetNumWearables(); - for ( int i = 0; i < NumWearables; ++i ) - { - CEconWearable* pItem = pPlayer->GetWearable ( i ); - if ( pItem != NULL ) - { - pItem->InvalidateBoneCache(); - } - } -#endif // USES_ECON_ITEMS - - } -} - -void CBaseWorldView::DrawExecute( float waterHeight, view_id_t viewID, float waterZAdjust ) -{ - int savedViewID = g_CurrentViewID; - - // @MULTICORE (toml 8/16/2006): rethink how, where, and when this is done... - g_CurrentViewID = VIEW_SHADOW_DEPTH_TEXTURE; - MaybeInvalidateLocalPlayerAnimation(); - g_pClientShadowMgr->ComputeShadowTextures( *this, m_pWorldListInfo->m_LeafCount, m_pWorldListInfo->m_pLeafList ); - MaybeInvalidateLocalPlayerAnimation(); - - // Make sure sound doesn't stutter - engine->Sound_ExtraUpdate(); - - g_CurrentViewID = viewID; - - // Update our render view flags. - int iDrawFlagsBackup = m_DrawFlags; - m_DrawFlags |= m_pMainView->GetBaseDrawFlags(); - - PushView( waterHeight ); - - CMatRenderContextPtr pRenderContext( materials ); - -#if defined( _X360 ) - pRenderContext->PushVertexShaderGPRAllocation( 32 ); -#endif - - ITexture *pSaveFrameBufferCopyTexture = pRenderContext->GetFrameBufferCopyTexture( 0 ); - if ( engine->GetDXSupportLevel() >= 80 ) - { - pRenderContext->SetFrameBufferCopyTexture( GetPowerOfTwoFrameBufferTexture() ); - } - - pRenderContext.SafeRelease(); - - ERenderDepthMode DepthMode = DEPTH_MODE_NORMAL; - - if ( m_DrawFlags & DF_DRAW_ENTITITES ) - { - DrawWorld( waterZAdjust ); - DrawOpaqueRenderables( DepthMode ); - -#ifdef TF_CLIENT_DLL - bool bVisionOverride = ( localplayer_visionflags.GetInt() & ( 0x01 ) ); // Pyro-vision Goggles - - if ( g_CurrentViewID == VIEW_MAIN && bVisionOverride && pyro_dof.GetBool() ) // Pyro-vision Goggles - { - DrawDepthOfField(); - } -#endif - DrawTranslucentRenderables( false, false ); - DrawNoZBufferTranslucentRenderables(); - } - else - { - DrawWorld( waterZAdjust ); - -#ifdef TF_CLIENT_DLL - bool bVisionOverride = ( localplayer_visionflags.GetInt() & ( 0x01 ) ); // Pyro-vision Goggles - - if ( g_CurrentViewID == VIEW_MAIN && bVisionOverride && pyro_dof.GetBool() ) // Pyro-vision Goggles - { - DrawDepthOfField(); - } -#endif - // Draw translucent world brushes only, no entities - DrawTranslucentWorldInLeaves( false ); - } - - // issue the pixel visibility tests for sub-views - if ( !IsMainView( CurrentViewID() ) && CurrentViewID() != VIEW_INTRO_CAMERA ) - { - PixelVisibility_EndCurrentView(); - } - - pRenderContext.GetFrom( materials ); - pRenderContext->SetFrameBufferCopyTexture( pSaveFrameBufferCopyTexture ); - PopView(); - - m_DrawFlags = iDrawFlagsBackup; - - g_CurrentViewID = savedViewID; - -#if defined( _X360 ) - pRenderContext->PopVertexShaderGPRAllocation(); -#endif -} - - -void CBaseWorldView::SSAO_DepthPass() -{ - if ( !g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_0() ) - { - return; - } - -#if 1 - VPROF_BUDGET( "CSimpleWorldView::SSAO_DepthPass", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - - int savedViewID = g_CurrentViewID; - g_CurrentViewID = VIEW_SSAO; - - ITexture *pSSAO = materials->FindTexture( "_rt_ResolvedFullFrameDepth", TEXTURE_GROUP_RENDER_TARGET ); - - CMatRenderContextPtr pRenderContext( materials ); - - pRenderContext->ClearColor4ub( 255, 255, 255, 255 ); - -#if defined( _X360 ) - Assert(0); // rebalance this if we ever use this on 360 - pRenderContext->PushVertexShaderGPRAllocation( 112 ); //almost all work is done in vertex shaders for depth rendering, max out their threads -#endif - - pRenderContext.SafeRelease(); - - if( IsPC() ) - { - render->Push3DView( (*this), VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, pSSAO, GetFrustum() ); - } - else if( IsX360() ) - { - render->Push3DView( (*this), VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, pSSAO, GetFrustum() ); - } - - MDLCACHE_CRITICAL_SECTION(); - - engine->Sound_ExtraUpdate(); // Make sure sound doesn't stutter - - m_DrawFlags |= DF_SSAO_DEPTH_PASS; - - { - VPROF_BUDGET( "DrawWorld", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - DrawWorld( 0.0f ); - } - - // Draw opaque and translucent renderables with appropriate override materials - // OVERRIDE_SSAO_DEPTH_WRITE is OK with a NULL material pointer - modelrender->ForcedMaterialOverride( NULL, OVERRIDE_SSAO_DEPTH_WRITE ); - - { - VPROF_BUDGET( "DrawOpaqueRenderables", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - DrawOpaqueRenderables( DEPTH_MODE_SSA0 ); - } - -#if 0 - if ( m_bRenderFlashlightDepthTranslucents || r_flashlightdepth_drawtranslucents.GetBool() ) - { - VPROF_BUDGET( "DrawTranslucentRenderables", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); - DrawTranslucentRenderables( false, true ); - } -#endif - - modelrender->ForcedMaterialOverride( 0 ); - - m_DrawFlags &= ~DF_SSAO_DEPTH_PASS; - - pRenderContext.GetFrom( materials ); - - if( IsX360() ) - { - //Resolve() the depth texture here. Before the pop so the copy will recognize that the resolutions are the same - pRenderContext->CopyRenderTargetToTextureEx( NULL, -1, NULL, NULL ); - } - - render->PopView( GetFrustum() ); - -#if defined( _X360 ) - pRenderContext->PopVertexShaderGPRAllocation(); -#endif - - pRenderContext.SafeRelease(); - - g_CurrentViewID = savedViewID; -#endif -} - - -void CBaseWorldView::DrawDepthOfField( ) -{ - if ( !g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_0() ) - { - return; - } - - CMatRenderContextPtr pRenderContext( materials ); - - ITexture *pSmallFB0 = materials->FindTexture( "_rt_smallfb0", TEXTURE_GROUP_RENDER_TARGET ); - ITexture *pSmallFB1 = materials->FindTexture( "_rt_smallfb1", TEXTURE_GROUP_RENDER_TARGET ); - - Rect_t DestRect; - int w = pSmallFB0->GetActualWidth(); - int h = pSmallFB0->GetActualHeight(); - DestRect.x = 0; - DestRect.y = 0; - DestRect.width = w; - DestRect.height = h; - - pRenderContext->CopyRenderTargetToTextureEx( pSmallFB0, 0, NULL, &DestRect ); - - IMaterial *pPyroBlurXMaterial = materials->FindMaterial( "dev/pyro_blur_filter_x", TEXTURE_GROUP_OTHER ); - IMaterial *pPyroBlurYMaterial = materials->FindMaterial( "dev/pyro_blur_filter_y", TEXTURE_GROUP_OTHER ); - - pRenderContext->PushRenderTargetAndViewport( pSmallFB1, 0, 0, w, h ); - pRenderContext->DrawScreenSpaceRectangle( pPyroBlurYMaterial, 0, 0, w, h, 0, 0, w - 1, h - 1, w, h ); - pRenderContext->PopRenderTargetAndViewport(); - - pRenderContext->PushRenderTargetAndViewport( pSmallFB0, 0, 0, w, h ); - pRenderContext->DrawScreenSpaceRectangle( pPyroBlurXMaterial, 0, 0, w, h, 0, 0, w - 1, h - 1, w, h ); - pRenderContext->PopRenderTargetAndViewport(); - - IMaterial *pPyroDepthOfFieldMaterial = materials->FindMaterial( "dev/pyro_dof", TEXTURE_GROUP_OTHER ); - - pRenderContext->DrawScreenSpaceRectangle( pPyroDepthOfFieldMaterial, x, y, width, height, 0, 0, width-1, height-1, width, height ); -} - -//----------------------------------------------------------------------------- -// Draws the scene when there's no water or only cheap water -//----------------------------------------------------------------------------- -void CSimpleWorldView::Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, ViewCustomVisibility_t *pCustomVisibility ) -{ - BaseClass::Setup( view ); - - m_ClearFlags = nClearFlags; - m_DrawFlags = DF_DRAW_ENTITITES; - - if ( !waterInfo.m_bOpaqueWater ) - { - m_DrawFlags |= DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER; - } - else - { - bool bViewIntersectsWater = DoesViewPlaneIntersectWater( fogInfo.m_flWaterHeight, fogInfo.m_nVisibleFogVolume ); - if( bViewIntersectsWater ) - { - // have to draw both sides if we can see both. - m_DrawFlags |= DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER; - } - else if ( fogInfo.m_bEyeInFogVolume ) - { - m_DrawFlags |= DF_RENDER_UNDERWATER; - } - else - { - m_DrawFlags |= DF_RENDER_ABOVEWATER; - } - } - if ( waterInfo.m_bDrawWaterSurface ) - { - m_DrawFlags |= DF_RENDER_WATER; - } - - if ( !fogInfo.m_bEyeInFogVolume && bDrawSkybox ) - { - m_DrawFlags |= DF_DRAWSKYBOX; - } - - m_pCustomVisibility = pCustomVisibility; - m_fogInfo = fogInfo; -} - - -//----------------------------------------------------------------------------- -// Draws the scene when there's no water or only cheap water -//----------------------------------------------------------------------------- -void CSimpleWorldView::Draw() -{ - VPROF( "CViewRender::ViewDrawScene_NoWater" ); - - CMatRenderContextPtr pRenderContext( materials ); - PIXEVENT( pRenderContext, "CSimpleWorldView::Draw" ); - -#if defined( _X360 ) - pRenderContext->PushVertexShaderGPRAllocation( 32 ); //lean toward pixel shader threads -#endif - - pRenderContext.SafeRelease(); - - DrawSetup( 0, m_DrawFlags, 0 ); - - if ( !m_fogInfo.m_bEyeInFogVolume ) - { - EnableWorldFog(); - } - else - { - m_ClearFlags |= VIEW_CLEAR_COLOR; - - SetFogVolumeState( m_fogInfo, false ); - - pRenderContext.GetFrom( materials ); - - unsigned char ucFogColor[3]; - pRenderContext->GetFogColor( ucFogColor ); - pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); - } - - pRenderContext.SafeRelease(); - - DrawExecute( 0, CurrentViewID(), 0 ); - - pRenderContext.GetFrom( materials ); - pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); - -#if defined( _X360 ) - pRenderContext->PopVertexShaderGPRAllocation(); -#endif -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CBaseWaterView::CalcWaterEyeAdjustments( const VisibleFogVolumeInfo_t &fogInfo, - float &newWaterHeight, float &waterZAdjust, bool bSoftwareUserClipPlane ) -{ - if( !bSoftwareUserClipPlane ) - { - newWaterHeight = fogInfo.m_flWaterHeight; - waterZAdjust = 0.0f; - return; - } - - newWaterHeight = fogInfo.m_flWaterHeight; - float eyeToWaterZDelta = origin[2] - fogInfo.m_flWaterHeight; - float epsilon = r_eyewaterepsilon.GetFloat(); - waterZAdjust = 0.0f; - if( fabs( eyeToWaterZDelta ) < epsilon ) - { - if( eyeToWaterZDelta > 0 ) - { - newWaterHeight = origin[2] - epsilon; - } - else - { - newWaterHeight = origin[2] + epsilon; - } - waterZAdjust = newWaterHeight - fogInfo.m_flWaterHeight; - } - - // Warning( "view.origin[2]: %f newWaterHeight: %f fogInfo.m_flWaterHeight: %f waterZAdjust: %f\n", - // ( float )view.origin[2], newWaterHeight, fogInfo.m_flWaterHeight, waterZAdjust ); -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CBaseWaterView::CSoftwareIntersectionView::Setup( bool bAboveWater ) -{ - BaseClass::Setup( *GetOuter() ); - - m_DrawFlags = 0; - m_DrawFlags = ( bAboveWater ) ? DF_RENDER_UNDERWATER : DF_RENDER_ABOVEWATER; -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CBaseWaterView::CSoftwareIntersectionView::Draw() -{ - DrawSetup( GetOuter()->m_waterHeight, m_DrawFlags, GetOuter()->m_waterZAdjust ); - DrawExecute( GetOuter()->m_waterHeight, CurrentViewID(), GetOuter()->m_waterZAdjust ); -} - -//----------------------------------------------------------------------------- -// Draws the scene when the view point is above the level of the water -//----------------------------------------------------------------------------- -void CAboveWaterView::Setup( const CViewSetup &view, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo ) -{ - BaseClass::Setup( view ); - - m_bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping(); - - CalcWaterEyeAdjustments( fogInfo, m_waterHeight, m_waterZAdjust, m_bSoftwareUserClipPlane ); - - // BROKEN STUFF! - if ( m_waterZAdjust == 0.0f ) - { - m_bSoftwareUserClipPlane = false; - } - - m_DrawFlags = DF_RENDER_ABOVEWATER | DF_DRAW_ENTITITES; - m_ClearFlags = VIEW_CLEAR_DEPTH; - -#ifdef PORTAL - if( g_pPortalRender->ShouldObeyStencilForClears() ) - m_ClearFlags |= VIEW_CLEAR_OBEY_STENCIL; -#endif - - if ( bDrawSkybox ) - { - m_DrawFlags |= DF_DRAWSKYBOX; - } - - if ( waterInfo.m_bDrawWaterSurface ) - { - m_DrawFlags |= DF_RENDER_WATER; - } - if ( !waterInfo.m_bRefract && !waterInfo.m_bOpaqueWater ) - { - m_DrawFlags |= DF_RENDER_UNDERWATER; - } - - m_fogInfo = fogInfo; - m_waterInfo = waterInfo; -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CAboveWaterView::Draw() -{ - VPROF( "CViewRender::ViewDrawScene_EyeAboveWater" ); - - // eye is outside of water - - CMatRenderContextPtr pRenderContext( materials ); - - // render the reflection - if( m_waterInfo.m_bReflect ) - { - m_ReflectionView.Setup( m_waterInfo.m_bReflectEntities ); - m_pMainView->AddViewToScene( &m_ReflectionView ); - } - - bool bViewIntersectsWater = false; - - // render refraction - if ( m_waterInfo.m_bRefract ) - { - m_RefractionView.Setup(); - m_pMainView->AddViewToScene( &m_RefractionView ); - - if( !m_bSoftwareUserClipPlane ) - { - bViewIntersectsWater = DoesViewPlaneIntersectWater( m_fogInfo.m_flWaterHeight, m_fogInfo.m_nVisibleFogVolume ); - } - } - else if ( !( m_DrawFlags & DF_DRAWSKYBOX ) ) - { - m_ClearFlags |= VIEW_CLEAR_COLOR; - } - -#ifdef PORTAL - if( g_pPortalRender->ShouldObeyStencilForClears() ) - m_ClearFlags |= VIEW_CLEAR_OBEY_STENCIL; -#endif - - // NOTE!!!!! YOU CAN ONLY DO THIS IF YOU HAVE HARDWARE USER CLIP PLANES!!!!!! - bool bHardwareUserClipPlanes = !g_pMaterialSystemHardwareConfig->UseFastClipping(); - if( bViewIntersectsWater && bHardwareUserClipPlanes ) - { - // This is necessary to keep the non-water fogged world from drawing underwater in - // the case where we want to partially see into the water. - m_DrawFlags |= DF_CLIP_Z | DF_CLIP_BELOW; - } - - // render the world - DrawSetup( m_waterHeight, m_DrawFlags, m_waterZAdjust ); - EnableWorldFog(); - DrawExecute( m_waterHeight, CurrentViewID(), m_waterZAdjust ); - - if ( m_waterInfo.m_bRefract ) - { - if ( m_bSoftwareUserClipPlane ) - { - m_SoftwareIntersectionView.Setup( true ); - m_SoftwareIntersectionView.Draw( ); - } - else if ( bViewIntersectsWater ) - { - m_IntersectionView.Setup(); - m_pMainView->AddViewToScene( &m_IntersectionView ); - } - } -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CAboveWaterView::CReflectionView::Setup( bool bReflectEntities ) -{ - BaseClass::Setup( *GetOuter() ); - - m_ClearFlags = VIEW_CLEAR_DEPTH; - - // NOTE: Clearing the color is unnecessary since we're drawing the skybox - // and dest-alpha is never used in the reflection - m_DrawFlags = DF_RENDER_REFLECTION | DF_CLIP_Z | DF_CLIP_BELOW | - DF_RENDER_ABOVEWATER; - - // NOTE: This will cause us to draw the 2d skybox in the reflection - // (which we want to do instead of drawing the 3d skybox) - m_DrawFlags |= DF_DRAWSKYBOX; - - if( bReflectEntities ) - { - m_DrawFlags |= DF_DRAW_ENTITITES; - } -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CAboveWaterView::CReflectionView::Draw() -{ -#ifdef PORTAL - g_pPortalRender->WaterRenderingHandler_PreReflection(); -#endif - - // Store off view origin and angles and set the new view - int nSaveViewID = CurrentViewID(); - SetupCurrentView( origin, angles, VIEW_REFLECTION ); - - // Disable occlusion visualization in reflection - bool bVisOcclusion = r_visocclusion.GetInt(); - r_visocclusion.SetValue( 0 ); - - DrawSetup( GetOuter()->m_fogInfo.m_flWaterHeight, m_DrawFlags, 0.0f, GetOuter()->m_fogInfo.m_nVisibleFogVolumeLeaf ); - - EnableWorldFog(); - DrawExecute( GetOuter()->m_fogInfo.m_flWaterHeight, VIEW_REFLECTION, 0.0f ); - - r_visocclusion.SetValue( bVisOcclusion ); - -#ifdef PORTAL - // deal with stencil - g_pPortalRender->WaterRenderingHandler_PostReflection(); -#endif - - // finish off the view and restore the previous view. - SetupCurrentView( origin, angles, ( view_id_t )nSaveViewID ); - - // This is here for multithreading - CMatRenderContextPtr pRenderContext( materials ); - pRenderContext->Flush(); -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CAboveWaterView::CRefractionView::Setup() -{ - BaseClass::Setup( *GetOuter() ); - - m_ClearFlags = VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH; - - m_DrawFlags = DF_RENDER_REFRACTION | DF_CLIP_Z | - DF_RENDER_UNDERWATER | DF_FUDGE_UP | - DF_DRAW_ENTITITES ; -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CAboveWaterView::CRefractionView::Draw() -{ -#ifdef PORTAL - g_pPortalRender->WaterRenderingHandler_PreRefraction(); -#endif - - // Store off view origin and angles and set the new view - int nSaveViewID = CurrentViewID(); - SetupCurrentView( origin, angles, VIEW_REFRACTION ); - - DrawSetup( GetOuter()->m_waterHeight, m_DrawFlags, GetOuter()->m_waterZAdjust ); - - SetFogVolumeState( GetOuter()->m_fogInfo, true ); - SetClearColorToFogColor(); - DrawExecute( GetOuter()->m_waterHeight, VIEW_REFRACTION, GetOuter()->m_waterZAdjust ); - -#ifdef PORTAL - // deal with stencil - g_pPortalRender->WaterRenderingHandler_PostRefraction(); -#endif - - // finish off the view. restore the previous view. - SetupCurrentView( origin, angles, ( view_id_t )nSaveViewID ); - - // This is here for multithreading - CMatRenderContextPtr pRenderContext( materials ); - pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); - pRenderContext->Flush(); -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CAboveWaterView::CIntersectionView::Setup() -{ - BaseClass::Setup( *GetOuter() ); - m_DrawFlags = DF_RENDER_UNDERWATER | DF_CLIP_Z | DF_DRAW_ENTITITES; -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CAboveWaterView::CIntersectionView::Draw() -{ - DrawSetup( GetOuter()->m_fogInfo.m_flWaterHeight, m_DrawFlags, 0 ); - - SetFogVolumeState( GetOuter()->m_fogInfo, true ); - SetClearColorToFogColor( ); - DrawExecute( GetOuter()->m_fogInfo.m_flWaterHeight, VIEW_NONE, 0 ); - CMatRenderContextPtr pRenderContext( materials ); - pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); -} - - -//----------------------------------------------------------------------------- -// Draws the scene when the view point is under the level of the water -//----------------------------------------------------------------------------- -void CUnderWaterView::Setup( const CViewSetup &view, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo ) -{ - BaseClass::Setup( view ); - - m_bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping(); - - CalcWaterEyeAdjustments( fogInfo, m_waterHeight, m_waterZAdjust, m_bSoftwareUserClipPlane ); - - IMaterial *pWaterMaterial = fogInfo.m_pFogVolumeMaterial; - if (engine->GetDXSupportLevel() >= 90 ) // screen voerlays underwater are a dx9 feature - { - IMaterialVar *pScreenOverlayVar = pWaterMaterial->FindVar( "$underwateroverlay", NULL, false ); - if ( pScreenOverlayVar && ( pScreenOverlayVar->IsDefined() ) ) - { - char const *pOverlayName = pScreenOverlayVar->GetStringValue(); - if ( pOverlayName[0] != '0' ) // fixme!!! - { - IMaterial *pOverlayMaterial = materials->FindMaterial( pOverlayName, TEXTURE_GROUP_OTHER ); - m_pMainView->SetWaterOverlayMaterial( pOverlayMaterial ); - } - } - } - // NOTE: We're not drawing the 2d skybox under water since it's assumed to not be visible. - - // render the world underwater - // Clear the color to get the appropriate underwater fog color - m_DrawFlags = DF_FUDGE_UP | DF_RENDER_UNDERWATER | DF_DRAW_ENTITITES; - m_ClearFlags = VIEW_CLEAR_DEPTH; - - if( !m_bSoftwareUserClipPlane ) - { - m_DrawFlags |= DF_CLIP_Z; - } - if ( waterInfo.m_bDrawWaterSurface ) - { - m_DrawFlags |= DF_RENDER_WATER; - } - if ( !waterInfo.m_bRefract && !waterInfo.m_bOpaqueWater ) - { - m_DrawFlags |= DF_RENDER_ABOVEWATER; - } - - m_fogInfo = fogInfo; - m_waterInfo = waterInfo; - m_bDrawSkybox = bDrawSkybox; -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CUnderWaterView::Draw() -{ - // FIXME: The 3d skybox shouldn't be drawn when the eye is under water - - VPROF( "CViewRender::ViewDrawScene_EyeUnderWater" ); - - CMatRenderContextPtr pRenderContext( materials ); - - // render refraction (out of water) - if ( m_waterInfo.m_bRefract ) - { - m_RefractionView.Setup( ); - m_pMainView->AddViewToScene( &m_RefractionView ); - } - - if ( !m_waterInfo.m_bRefract ) - { - SetFogVolumeState( m_fogInfo, true ); - unsigned char ucFogColor[3]; - pRenderContext->GetFogColor( ucFogColor ); - pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); - } - - DrawSetup( m_waterHeight, m_DrawFlags, m_waterZAdjust ); - SetFogVolumeState( m_fogInfo, false ); - DrawExecute( m_waterHeight, CurrentViewID(), m_waterZAdjust ); - m_ClearFlags = 0; - - if( m_waterZAdjust != 0.0f && m_bSoftwareUserClipPlane && m_waterInfo.m_bRefract ) - { - m_SoftwareIntersectionView.Setup( false ); - m_SoftwareIntersectionView.Draw( ); - } - pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); - -} - - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CUnderWaterView::CRefractionView::Setup() -{ - BaseClass::Setup( *GetOuter() ); - // NOTE: Refraction renders into the back buffer, over the top of the 3D skybox - // It is then blitted out into the refraction target. This is so that - // we only have to set up 3d sky vis once, and only render it once also! - m_DrawFlags = DF_CLIP_Z | - DF_CLIP_BELOW | DF_RENDER_ABOVEWATER | - DF_DRAW_ENTITITES; - - m_ClearFlags = VIEW_CLEAR_DEPTH; - if ( GetOuter()->m_bDrawSkybox ) - { - m_ClearFlags |= VIEW_CLEAR_COLOR; - m_DrawFlags |= DF_DRAWSKYBOX | DF_CLIP_SKYBOX; - } -} - - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- -void CUnderWaterView::CRefractionView::Draw() -{ - CMatRenderContextPtr pRenderContext( materials ); - SetFogVolumeState( GetOuter()->m_fogInfo, true ); - unsigned char ucFogColor[3]; - pRenderContext->GetFogColor( ucFogColor ); - pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); - - DrawSetup( GetOuter()->m_waterHeight, m_DrawFlags, GetOuter()->m_waterZAdjust ); - - EnableWorldFog(); - DrawExecute( GetOuter()->m_waterHeight, VIEW_REFRACTION, GetOuter()->m_waterZAdjust ); - - Rect_t srcRect; - srcRect.x = x; - srcRect.y = y; - srcRect.width = width; - srcRect.height = height; - - // Optionally write the rendered image to a debug texture - if ( g_bDumpRenderTargets ) - { - DumpTGAofRenderTarget( width, height, "WaterRefract" ); - } - - ITexture *pTexture = GetWaterRefractionTexture(); - pRenderContext->CopyRenderTargetToTextureEx( pTexture, 0, &srcRect, NULL ); -} - - -//----------------------------------------------------------------------------- -// -// Reflective glass view starts here -// -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// Draws the scene when the view contains reflective glass -//----------------------------------------------------------------------------- -void CReflectiveGlassView::Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, - const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane ) -{ - BaseClass::Setup( view, nClearFlags, bDrawSkybox, fogInfo, waterInfo, NULL ); - m_ReflectionPlane = reflectionPlane; -} - - -bool CReflectiveGlassView::AdjustView( float flWaterHeight ) -{ - ITexture *pTexture = GetWaterReflectionTexture(); - - // Use the aspect ratio of the main view! So, don't recompute it here - x = y = 0; - width = pTexture->GetActualWidth(); - height = pTexture->GetActualHeight(); - - // Reflect the camera origin + vectors around the reflection plane - float flDist = DotProduct( origin, m_ReflectionPlane.normal ) - m_ReflectionPlane.dist; - VectorMA( origin, - 2.0f * flDist, m_ReflectionPlane.normal, origin ); - - Vector vecForward, vecUp; - AngleVectors( angles, &vecForward, NULL, &vecUp ); - - float flDot = DotProduct( vecForward, m_ReflectionPlane.normal ); - VectorMA( vecForward, - 2.0f * flDot, m_ReflectionPlane.normal, vecForward ); - - flDot = DotProduct( vecUp, m_ReflectionPlane.normal ); - VectorMA( vecUp, - 2.0f * flDot, m_ReflectionPlane.normal, vecUp ); - - VectorAngles( vecForward, vecUp, angles ); - return true; -} - -void CReflectiveGlassView::PushView( float waterHeight ) -{ - render->Push3DView( *this, m_ClearFlags, GetWaterReflectionTexture(), GetFrustum() ); - - Vector4D plane; - VectorCopy( m_ReflectionPlane.normal, plane.AsVector3D() ); - plane.w = m_ReflectionPlane.dist + 0.1f; - - CMatRenderContextPtr pRenderContext( materials ); - pRenderContext->PushCustomClipPlane( plane.Base() ); -} - -void CReflectiveGlassView::PopView( ) -{ - CMatRenderContextPtr pRenderContext( materials ); - pRenderContext->PopCustomClipPlane( ); - render->PopView( GetFrustum() ); -} - - -//----------------------------------------------------------------------------- -// Renders reflective or refractive parts of glass -//----------------------------------------------------------------------------- -void CReflectiveGlassView::Draw() -{ - VPROF( "CReflectiveGlassView::Draw" ); - - CMatRenderContextPtr pRenderContext( materials ); - PIXEVENT( pRenderContext, "CReflectiveGlassView::Draw" ); - - // Disable occlusion visualization in reflection - bool bVisOcclusion = r_visocclusion.GetInt(); - r_visocclusion.SetValue( 0 ); - - BaseClass::Draw(); - - r_visocclusion.SetValue( bVisOcclusion ); - - pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); - pRenderContext->Flush(); -} - - - -//----------------------------------------------------------------------------- -// Draws the scene when the view contains reflective glass -//----------------------------------------------------------------------------- -void CRefractiveGlassView::Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, - const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane ) -{ - BaseClass::Setup( view, nClearFlags, bDrawSkybox, fogInfo, waterInfo, NULL ); - m_ReflectionPlane = reflectionPlane; -} - - -bool CRefractiveGlassView::AdjustView( float flWaterHeight ) -{ - ITexture *pTexture = GetWaterRefractionTexture(); - - // Use the aspect ratio of the main view! So, don't recompute it here - x = y = 0; - width = pTexture->GetActualWidth(); - height = pTexture->GetActualHeight(); - return true; -} - - -void CRefractiveGlassView::PushView( float waterHeight ) -{ - render->Push3DView( *this, m_ClearFlags, GetWaterRefractionTexture(), GetFrustum() ); - - Vector4D plane; - VectorMultiply( m_ReflectionPlane.normal, -1, plane.AsVector3D() ); - plane.w = -m_ReflectionPlane.dist + 0.1f; - - CMatRenderContextPtr pRenderContext( materials ); - pRenderContext->PushCustomClipPlane( plane.Base() ); -} - - -void CRefractiveGlassView::PopView( ) -{ - CMatRenderContextPtr pRenderContext( materials ); - pRenderContext->PopCustomClipPlane( ); - render->PopView( GetFrustum() ); -} - - - -//----------------------------------------------------------------------------- -// Renders reflective or refractive parts of glass -//----------------------------------------------------------------------------- -void CRefractiveGlassView::Draw() -{ - VPROF( "CRefractiveGlassView::Draw" ); - - CMatRenderContextPtr pRenderContext( materials ); - PIXEVENT( pRenderContext, "CRefractiveGlassView::Draw" ); - - BaseClass::Draw(); - - pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); - pRenderContext->Flush(); -} +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Responsible for drawing the scene +// +//===========================================================================// + +#include "cbase.h" +#include "view.h" +#include "iviewrender.h" +#include "view_shared.h" +#include "ivieweffects.h" +#include "iinput.h" +#include "model_types.h" +#include "clientsideeffects.h" +#include "particlemgr.h" +#include "viewrender.h" +#include "iclientmode.h" +#include "voice_status.h" +#include "glow_overlay.h" +#include "materialsystem/imesh.h" +#include "materialsystem/itexture.h" +#include "materialsystem/imaterial.h" +#include "materialsystem/imaterialvar.h" +#include "materialsystem/imaterialsystem.h" +#include "detailobjectsystem.h" +#include "tier0/vprof.h" +#include "tier1/mempool.h" +#include "vstdlib/jobthread.h" +#include "datacache/imdlcache.h" +#include "engine/IEngineTrace.h" +#include "engine/ivmodelinfo.h" +#include "tier0/icommandline.h" +#include "view_scene.h" +#include "particles_ez.h" +#include "engine/IStaticPropMgr.h" +#include "engine/ivdebugoverlay.h" +#include "c_pixel_visibility.h" +#include "clienteffectprecachesystem.h" +#include "c_rope.h" +#include "c_effects.h" +#include "smoke_fog_overlay.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "vgui_int.h" +#include "ienginevgui.h" +#include "ScreenSpaceEffects.h" +#include "toolframework_client.h" +#include "c_func_reflective_glass.h" +#include "KeyValues.h" +#include "renderparm.h" +#include "studio_stats.h" +#include "con_nprint.h" +#include "clientmode_shared.h" +#include "sourcevr/isourcevirtualreality.h" +#include "client_virtualreality.h" + +#ifdef PORTAL +//#include "C_Portal_Player.h" +#include "portal_render_targets.h" +#include "PortalRender.h" +#endif +#if defined( HL2_CLIENT_DLL ) || defined( CSTRIKE_DLL ) +#define USE_MONITORS +#endif +#include "rendertexture.h" +#include "viewpostprocess.h" +#include "viewdebug.h" + +#if defined USES_ECON_ITEMS +#include "econ_wearable.h" +#endif + +#ifdef USE_MONITORS +#include "c_point_camera.h" +#endif // USE_MONITORS + +// Projective textures +#include "C_Env_Projected_Texture.h" + +#if defined (WIN32) +#include "ShaderEditor/ShaderEditorSystem.h" // FF --> hlstriker: Added +#endif +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +static void testfreezeframe_f( void ) +{ + view->FreezeFrame( 3.0 ); +} +static ConCommand test_freezeframe( "test_freezeframe", testfreezeframe_f, "Test the freeze frame code.", FCVAR_CHEAT ); + +//----------------------------------------------------------------------------- + +static ConVar r_visocclusion( "r_visocclusion", "0", FCVAR_CHEAT ); +extern ConVar r_flashlightdepthtexture; +extern ConVar vcollide_wireframe; +extern ConVar mat_motion_blur_enabled; +extern ConVar r_depthoverlay; +extern ConVar mat_viewportscale; +extern ConVar mat_viewportupscale; +extern bool g_bDumpRenderTargets; + +//----------------------------------------------------------------------------- +// Convars related to controlling rendering +//----------------------------------------------------------------------------- +static ConVar cl_maxrenderable_dist("cl_maxrenderable_dist", "3000", FCVAR_CHEAT, "Max distance from the camera at which things will be rendered" ); + +ConVar r_entityclips( "r_entityclips", "1" ); //FIXME: Nvidia drivers before 81.94 on cards that support user clip planes will have problems with this, require driver update? Detect and disable? + +// Matches the version in the engine +static ConVar r_drawopaqueworld( "r_drawopaqueworld", "1", FCVAR_CHEAT ); +static ConVar r_drawtranslucentworld( "r_drawtranslucentworld", "1", FCVAR_CHEAT ); +static ConVar r_3dsky( "r_3dsky","1", 0, "Enable the rendering of 3d sky boxes" ); +static ConVar r_skybox( "r_skybox","1", FCVAR_CHEAT, "Enable the rendering of sky boxes" ); +#ifdef TF_CLIENT_DLL +ConVar r_drawviewmodel( "r_drawviewmodel","1", FCVAR_ARCHIVE ); +#else +ConVar r_drawviewmodel( "r_drawviewmodel","1", FCVAR_CHEAT ); +#endif +static ConVar r_drawtranslucentrenderables( "r_drawtranslucentrenderables", "1", FCVAR_CHEAT ); +static ConVar r_drawopaquerenderables( "r_drawopaquerenderables", "1", FCVAR_CHEAT ); +static ConVar r_threaded_renderables( "r_threaded_renderables", "0" ); + +// FIXME: This is not static because we needed to turn it off for TF2 playtests +ConVar r_DrawDetailProps( "r_DrawDetailProps", "1", FCVAR_NONE, "0=Off, 1=Normal, 2=Wireframe" ); + +ConVar r_worldlistcache( "r_worldlistcache", "1" ); + +//----------------------------------------------------------------------------- +// Convars related to fog color +//----------------------------------------------------------------------------- +static ConVar fog_override( "fog_override", "0", FCVAR_CHEAT ); +// set any of these to use the maps fog +static ConVar fog_start( "fog_start", "-1", FCVAR_CHEAT ); +static ConVar fog_end( "fog_end", "-1", FCVAR_CHEAT ); +static ConVar fog_color( "fog_color", "-1 -1 -1", FCVAR_CHEAT ); +static ConVar fog_enable( "fog_enable", "1", FCVAR_CHEAT ); +static ConVar fog_startskybox( "fog_startskybox", "-1", FCVAR_CHEAT ); +static ConVar fog_endskybox( "fog_endskybox", "-1", FCVAR_CHEAT ); +static ConVar fog_maxdensityskybox( "fog_maxdensityskybox", "-1", FCVAR_CHEAT ); +static ConVar fog_colorskybox( "fog_colorskybox", "-1 -1 -1", FCVAR_CHEAT ); +static ConVar fog_enableskybox( "fog_enableskybox", "1", FCVAR_CHEAT ); +static ConVar fog_maxdensity( "fog_maxdensity", "-1", FCVAR_CHEAT ); + + +//----------------------------------------------------------------------------- +// Water-related convars +//----------------------------------------------------------------------------- +static ConVar r_debugcheapwater( "r_debugcheapwater", "0", FCVAR_CHEAT ); +#ifndef _X360 +static ConVar r_waterforceexpensive( "r_waterforceexpensive", "0", FCVAR_ARCHIVE ); +#endif +static ConVar r_waterforcereflectentities( "r_waterforcereflectentities", "0" ); +static ConVar r_WaterDrawRefraction( "r_WaterDrawRefraction", "1", 0, "Enable water refraction" ); +static ConVar r_WaterDrawReflection( "r_WaterDrawReflection", "1", 0, "Enable water reflection" ); +static ConVar r_ForceWaterLeaf( "r_ForceWaterLeaf", "1", 0, "Enable for optimization to water - considers view in leaf under water for purposes of culling" ); +static ConVar mat_drawwater( "mat_drawwater", "1", FCVAR_CHEAT ); +static ConVar mat_clipz( "mat_clipz", "1" ); + + +//----------------------------------------------------------------------------- +// Other convars +//----------------------------------------------------------------------------- +static ConVar r_screenfademinsize( "r_screenfademinsize", "0" ); +static ConVar r_screenfademaxsize( "r_screenfademaxsize", "0" ); +static ConVar cl_drawmonitors( "cl_drawmonitors", "1" ); +static ConVar r_eyewaterepsilon( "r_eyewaterepsilon", "10.0f", FCVAR_CHEAT ); + +#ifdef TF_CLIENT_DLL +static ConVar pyro_dof( "pyro_dof", "1", FCVAR_ARCHIVE ); +#endif + +extern ConVar cl_leveloverview; + +extern ConVar localplayer_visionflags; + +//----------------------------------------------------------------------------- +// Globals +//----------------------------------------------------------------------------- +static Vector g_vecCurrentRenderOrigin(0,0,0); +static QAngle g_vecCurrentRenderAngles(0,0,0); +static Vector g_vecCurrentVForward(0,0,0), g_vecCurrentVRight(0,0,0), g_vecCurrentVUp(0,0,0); +static VMatrix g_matCurrentCamInverse; +bool s_bCanAccessCurrentView = false; +IntroData_t *g_pIntroData = NULL; +static bool g_bRenderingView = false; // For debugging... +static int g_CurrentViewID = VIEW_NONE; +bool g_bRenderingScreenshot = false; + + +#define FREEZECAM_SNAPSHOT_FADE_SPEED 340 +float g_flFreezeFlash = 0.0f; + +//----------------------------------------------------------------------------- + +CON_COMMAND( r_cheapwaterstart, "" ) +{ + if( args.ArgC() == 2 ) + { + float dist = atof( args[ 1 ] ); + view->SetCheapWaterStartDistance( dist ); + } + else + { + float start, end; + view->GetWaterLODParams( start, end ); + Warning( "r_cheapwaterstart: %f\n", start ); + } +} + +CON_COMMAND( r_cheapwaterend, "" ) +{ + if( args.ArgC() == 2 ) + { + float dist = atof( args[ 1 ] ); + view->SetCheapWaterEndDistance( dist ); + } + else + { + float start, end; + view->GetWaterLODParams( start, end ); + Warning( "r_cheapwaterend: %f\n", end ); + } +} + + + +//----------------------------------------------------------------------------- +// Describes a pruned set of leaves to be rendered this view. Reference counted +// because potentially shared by a number of views +//----------------------------------------------------------------------------- +struct ClientWorldListInfo_t : public CRefCounted1 +{ + ClientWorldListInfo_t() + { + memset( (WorldListInfo_t *)this, 0, sizeof(WorldListInfo_t) ); + m_pActualLeafIndex = NULL; + m_bPooledAlloc = false; + } + + // Allocate a list intended for pruning + static ClientWorldListInfo_t *AllocPooled( const ClientWorldListInfo_t &exemplar ); + + // Because we remap leaves to eliminate unused leaves, we need a remap + // when drawing translucent surfaces, which requires the *original* leaf index + // using m_pActualLeafMap[ remapped leaf index ] == actual leaf index + LeafIndex_t *m_pActualLeafIndex; + +private: + virtual bool OnFinalRelease(); + + bool m_bPooledAlloc; + static CObjectPool gm_Pool; +}; + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +class CWorldListCache +{ +public: + CWorldListCache() + { + + } + void Flush() + { + for ( int i = m_Entries.FirstInorder(); i != m_Entries.InvalidIndex(); i = m_Entries.NextInorder( i ) ) + { + delete m_Entries[i]; + } + m_Entries.RemoveAll(); + } + + bool Find( const CViewSetup &viewSetup, IWorldRenderList **ppList, ClientWorldListInfo_t **ppListInfo ) + { + Entry_t lookup( viewSetup ); + + int i = m_Entries.Find( &lookup ); + + if ( i != m_Entries.InvalidIndex() ) + { + Entry_t *pEntry = m_Entries[i]; + *ppList = InlineAddRef( pEntry->pList ); + *ppListInfo = InlineAddRef( pEntry->pListInfo ); + return true; + } + + return false; + } + + void Add( const CViewSetup &viewSetup, IWorldRenderList *pList, ClientWorldListInfo_t *pListInfo ) + { + m_Entries.Insert( new Entry_t( viewSetup, pList, pListInfo ) ); + } + +private: + struct Entry_t + { + Entry_t( const CViewSetup &viewSetup, IWorldRenderList *pList = NULL, ClientWorldListInfo_t *pListInfo = NULL ) : + pList( ( pList ) ? InlineAddRef( pList ) : NULL ), + pListInfo( ( pListInfo ) ? InlineAddRef( pListInfo ) : NULL ) + { + // @NOTE (toml 8/18/2006): because doing memcmp, need to fill all of the fields and the padding! + memset( &m_bOrtho, 0, offsetof(Entry_t, pList ) - offsetof(Entry_t, m_bOrtho ) ); + m_bOrtho = viewSetup.m_bOrtho; + m_OrthoLeft = viewSetup.m_OrthoLeft; + m_OrthoTop = viewSetup.m_OrthoTop; + m_OrthoRight = viewSetup.m_OrthoRight; + m_OrthoBottom = viewSetup.m_OrthoBottom; + fov = viewSetup.fov; + origin = viewSetup.origin; + angles = viewSetup.angles; + zNear = viewSetup.zNear; + zFar = viewSetup.zFar; + m_flAspectRatio = viewSetup.m_flAspectRatio; + m_bOffCenter = viewSetup.m_bOffCenter; + m_flOffCenterTop = viewSetup.m_flOffCenterTop; + m_flOffCenterBottom = viewSetup.m_flOffCenterBottom; + m_flOffCenterLeft = viewSetup.m_flOffCenterLeft; + m_flOffCenterRight = viewSetup.m_flOffCenterRight; + } + + ~Entry_t() + { + if ( pList ) + pList->Release(); + if ( pListInfo ) + pListInfo->Release(); + } + + // The fields from CViewSetup that would actually affect the list + float m_OrthoLeft; + float m_OrthoTop; + float m_OrthoRight; + float m_OrthoBottom; + float fov; + Vector origin; + QAngle angles; + float zNear; + float zFar; + float m_flAspectRatio; + float m_flOffCenterTop; + float m_flOffCenterBottom; + float m_flOffCenterLeft; + float m_flOffCenterRight; + bool m_bOrtho; + bool m_bOffCenter; + + IWorldRenderList *pList; + ClientWorldListInfo_t *pListInfo; + }; + + class CEntryComparator + { + public: + CEntryComparator( int ) {} + bool operator!() const { return false; } + bool operator()( const Entry_t *lhs, const Entry_t *rhs ) const + { + return ( memcmp( lhs, rhs, sizeof(Entry_t) - ( sizeof(Entry_t) - offsetof(Entry_t, pList ) ) ) < 0 ); + } + }; + + CUtlRBTree m_Entries; +}; + +CWorldListCache g_WorldListCache; + +//----------------------------------------------------------------------------- +// Standard 3d skybox view +//----------------------------------------------------------------------------- +class CSkyboxView : public CRendering3dView +{ + DECLARE_CLASS( CSkyboxView, CRendering3dView ); +public: + CSkyboxView(CViewRender *pMainView) : + CRendering3dView( pMainView ), + m_pSky3dParams( NULL ) + { + } + + bool Setup( const CViewSetup &view, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible ); + void Draw(); + +protected: + +#ifdef PORTAL + virtual bool ShouldDrawPortals() { return false; } +#endif + + virtual SkyboxVisibility_t ComputeSkyboxVisibility(); + + bool GetSkyboxFogEnable(); + + void Enable3dSkyboxFog( void ); + void DrawInternal( view_id_t iSkyBoxViewID, bool bInvokePreAndPostRender, ITexture *pRenderTarget, ITexture *pDepthTarget ); + + sky3dparams_t * PreRender3dSkyboxWorld( SkyboxVisibility_t nSkyboxVisible ); + + sky3dparams_t *m_pSky3dParams; +}; + +//----------------------------------------------------------------------------- +// 3d skybox view when drawing portals +//----------------------------------------------------------------------------- +#ifdef PORTAL +class CPortalSkyboxView : public CSkyboxView +{ + DECLARE_CLASS( CPortalSkyboxView, CSkyboxView ); +public: + CPortalSkyboxView(CViewRender *pMainView) : + CSkyboxView( pMainView ), + m_pRenderTarget( NULL ) + {} + + bool Setup( const CViewSetup &view, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible, ITexture *pRenderTarget = NULL ); + + //Skybox drawing through portals with workarounds to fix area bits, position/scaling, view id's.......... + void Draw(); + +private: + virtual SkyboxVisibility_t ComputeSkyboxVisibility(); + + ITexture *m_pRenderTarget; +}; +#endif + + +//----------------------------------------------------------------------------- +// Shadow depth texture +//----------------------------------------------------------------------------- +class CShadowDepthView : public CRendering3dView +{ + DECLARE_CLASS( CShadowDepthView, CRendering3dView ); +public: + CShadowDepthView(CViewRender *pMainView) : CRendering3dView( pMainView ) {} + + void Setup( const CViewSetup &shadowViewIn, ITexture *pRenderTarget, ITexture *pDepthTexture ); + void Draw(); + +private: + ITexture *m_pRenderTarget; + ITexture *m_pDepthTexture; +}; + +//----------------------------------------------------------------------------- +// Freeze frame. Redraws the frame at which it was enabled. +//----------------------------------------------------------------------------- +class CFreezeFrameView : public CRendering3dView +{ + DECLARE_CLASS( CFreezeFrameView, CRendering3dView ); +public: + CFreezeFrameView(CViewRender *pMainView) : CRendering3dView( pMainView ) {} + + void Setup( const CViewSetup &view ); + void Draw(); + +private: + CMaterialReference m_pFreezeFrame; + CMaterialReference m_TranslucentSingleColor; +}; + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +class CBaseWorldView : public CRendering3dView +{ + DECLARE_CLASS( CBaseWorldView, CRendering3dView ); +protected: + CBaseWorldView(CViewRender *pMainView) : CRendering3dView( pMainView ) {} + + virtual bool AdjustView( float waterHeight ); + + void DrawSetup( float waterHeight, int flags, float waterZAdjust, int iForceViewLeaf = -1 ); + void DrawExecute( float waterHeight, view_id_t viewID, float waterZAdjust ); + + virtual void PushView( float waterHeight ); + virtual void PopView(); + + void SSAO_DepthPass(); + void DrawDepthOfField(); +}; + + +//----------------------------------------------------------------------------- +// Draws the scene when there's no water or only cheap water +//----------------------------------------------------------------------------- +class CSimpleWorldView : public CBaseWorldView +{ + DECLARE_CLASS( CSimpleWorldView, CBaseWorldView ); +public: + CSimpleWorldView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} + + void Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& info, ViewCustomVisibility_t *pCustomVisibility = NULL ); + void Draw(); + +private: + VisibleFogVolumeInfo_t m_fogInfo; + +}; + + +//----------------------------------------------------------------------------- +// Base class for scenes with water +//----------------------------------------------------------------------------- +class CBaseWaterView : public CBaseWorldView +{ + DECLARE_CLASS( CBaseWaterView, CBaseWorldView ); +public: + CBaseWaterView(CViewRender *pMainView) : + CBaseWorldView( pMainView ), + m_SoftwareIntersectionView( pMainView ) + {} + + // void Setup( const CViewSetup &, const WaterRenderInfo_t& info ); + +protected: + void CalcWaterEyeAdjustments( const VisibleFogVolumeInfo_t &fogInfo, float &newWaterHeight, float &waterZAdjust, bool bSoftwareUserClipPlane ); + + class CSoftwareIntersectionView : public CBaseWorldView + { + DECLARE_CLASS( CSoftwareIntersectionView, CBaseWorldView ); + public: + CSoftwareIntersectionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} + + void Setup( bool bAboveWater ); + void Draw(); + + private: + CBaseWaterView *GetOuter() { return GET_OUTER( CBaseWaterView, m_SoftwareIntersectionView ); } + }; + + friend class CSoftwareIntersectionView; + + CSoftwareIntersectionView m_SoftwareIntersectionView; + + WaterRenderInfo_t m_waterInfo; + float m_waterHeight; + float m_waterZAdjust; + bool m_bSoftwareUserClipPlane; + VisibleFogVolumeInfo_t m_fogInfo; +}; + + +//----------------------------------------------------------------------------- +// Scenes above water +//----------------------------------------------------------------------------- +class CAboveWaterView : public CBaseWaterView +{ + DECLARE_CLASS( CAboveWaterView, CBaseWaterView ); +public: + CAboveWaterView(CViewRender *pMainView) : + CBaseWaterView( pMainView ), + m_ReflectionView( pMainView ), + m_RefractionView( pMainView ), + m_IntersectionView( pMainView ) + {} + + void Setup( const CViewSetup &view, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo ); + void Draw(); + + class CReflectionView : public CBaseWorldView + { + DECLARE_CLASS( CReflectionView, CBaseWorldView ); + public: + CReflectionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} + + void Setup( bool bReflectEntities ); + void Draw(); + + private: + CAboveWaterView *GetOuter() { return GET_OUTER( CAboveWaterView, m_ReflectionView ); } + }; + + class CRefractionView : public CBaseWorldView + { + DECLARE_CLASS( CRefractionView, CBaseWorldView ); + public: + CRefractionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} + + void Setup(); + void Draw(); + + private: + CAboveWaterView *GetOuter() { return GET_OUTER( CAboveWaterView, m_RefractionView ); } + }; + + class CIntersectionView : public CBaseWorldView + { + DECLARE_CLASS( CIntersectionView, CBaseWorldView ); + public: + CIntersectionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} + + void Setup(); + void Draw(); + + private: + CAboveWaterView *GetOuter() { return GET_OUTER( CAboveWaterView, m_IntersectionView ); } + }; + + + friend class CRefractionView; + friend class CReflectionView; + friend class CIntersectionView; + + bool m_bViewIntersectsWater; + + CReflectionView m_ReflectionView; + CRefractionView m_RefractionView; + CIntersectionView m_IntersectionView; +}; + + +//----------------------------------------------------------------------------- +// Scenes below water +//----------------------------------------------------------------------------- +class CUnderWaterView : public CBaseWaterView +{ + DECLARE_CLASS( CUnderWaterView, CBaseWaterView ); +public: + CUnderWaterView(CViewRender *pMainView) : + CBaseWaterView( pMainView ), + m_RefractionView( pMainView ) + {} + + void Setup( const CViewSetup &view, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& info ); + void Draw(); + + class CRefractionView : public CBaseWorldView + { + DECLARE_CLASS( CRefractionView, CBaseWorldView ); + public: + CRefractionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {} + + void Setup(); + void Draw(); + + private: + CUnderWaterView *GetOuter() { return GET_OUTER( CUnderWaterView, m_RefractionView ); } + }; + + friend class CRefractionView; + + bool m_bDrawSkybox; // @MULTICORE (toml 8/17/2006): remove after setup hoisted + + CRefractionView m_RefractionView; +}; + + +//----------------------------------------------------------------------------- +// Scenes containing reflective glass +//----------------------------------------------------------------------------- +class CReflectiveGlassView : public CSimpleWorldView +{ + DECLARE_CLASS( CReflectiveGlassView, CSimpleWorldView ); +public: + CReflectiveGlassView( CViewRender *pMainView ) : BaseClass( pMainView ) + { + } + + virtual bool AdjustView( float flWaterHeight ); + virtual void PushView( float waterHeight ); + virtual void PopView( ); + void Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane ); + void Draw(); + + cplane_t m_ReflectionPlane; +}; + +class CRefractiveGlassView : public CSimpleWorldView +{ + DECLARE_CLASS( CRefractiveGlassView, CSimpleWorldView ); +public: + CRefractiveGlassView( CViewRender *pMainView ) : BaseClass( pMainView ) + { + } + + virtual bool AdjustView( float flWaterHeight ); + virtual void PushView( float waterHeight ); + virtual void PopView( ); + void Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane ); + void Draw(); + + cplane_t m_ReflectionPlane; +}; + + +//----------------------------------------------------------------------------- +// Computes draw flags for the engine to build its world surface lists +//----------------------------------------------------------------------------- +static inline unsigned long BuildEngineDrawWorldListFlags( unsigned nDrawFlags ) +{ + unsigned long nEngineFlags = 0; + + if ( nDrawFlags & DF_DRAWSKYBOX ) + { + nEngineFlags |= DRAWWORLDLISTS_DRAW_SKYBOX; + } + + if ( nDrawFlags & DF_RENDER_ABOVEWATER ) + { + nEngineFlags |= DRAWWORLDLISTS_DRAW_STRICTLYABOVEWATER; + nEngineFlags |= DRAWWORLDLISTS_DRAW_INTERSECTSWATER; + } + + if ( nDrawFlags & DF_RENDER_UNDERWATER ) + { + nEngineFlags |= DRAWWORLDLISTS_DRAW_STRICTLYUNDERWATER; + nEngineFlags |= DRAWWORLDLISTS_DRAW_INTERSECTSWATER; + } + + if ( nDrawFlags & DF_RENDER_WATER ) + { + nEngineFlags |= DRAWWORLDLISTS_DRAW_WATERSURFACE; + } + + if( nDrawFlags & DF_CLIP_SKYBOX ) + { + nEngineFlags |= DRAWWORLDLISTS_DRAW_CLIPSKYBOX; + } + + if( nDrawFlags & DF_SHADOW_DEPTH_MAP ) + { + nEngineFlags |= DRAWWORLDLISTS_DRAW_SHADOWDEPTH; + } + + if( nDrawFlags & DF_RENDER_REFRACTION ) + { + nEngineFlags |= DRAWWORLDLISTS_DRAW_REFRACTION; + } + + if( nDrawFlags & DF_RENDER_REFLECTION ) + { + nEngineFlags |= DRAWWORLDLISTS_DRAW_REFLECTION; + } + + if( nDrawFlags & DF_SSAO_DEPTH_PASS ) + { + nEngineFlags |= DRAWWORLDLISTS_DRAW_SSAO | DRAWWORLDLISTS_DRAW_STRICTLYUNDERWATER | DRAWWORLDLISTS_DRAW_INTERSECTSWATER | DRAWWORLDLISTS_DRAW_STRICTLYABOVEWATER ; + nEngineFlags &= ~( DRAWWORLDLISTS_DRAW_WATERSURFACE | DRAWWORLDLISTS_DRAW_REFRACTION | DRAWWORLDLISTS_DRAW_REFLECTION ); + } + + return nEngineFlags; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +static void SetClearColorToFogColor() +{ + unsigned char ucFogColor[3]; + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->GetFogColor( ucFogColor ); + if( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER ) + { + // @MULTICORE (toml 8/16/2006): Find a way to not do this twice in eye above water case + float scale = LinearToGammaFullRange( pRenderContext->GetToneMappingScaleLinear().x ); + ucFogColor[0] *= scale; + ucFogColor[1] *= scale; + ucFogColor[2] *= scale; + } + pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); +} + +//----------------------------------------------------------------------------- +// Precache of necessary materials +//----------------------------------------------------------------------------- + +#ifdef HL2_CLIENT_DLL +CLIENTEFFECT_REGISTER_BEGIN( PrecacheViewRender ) + CLIENTEFFECT_MATERIAL( "scripted/intro_screenspaceeffect" ) +CLIENTEFFECT_REGISTER_END() +#endif + +CLIENTEFFECT_REGISTER_BEGIN( PrecachePostProcessingEffects ) + CLIENTEFFECT_MATERIAL( "dev/blurfiltery_and_add_nohdr" ) + CLIENTEFFECT_MATERIAL( "dev/blurfilterx" ) + CLIENTEFFECT_MATERIAL( "dev/blurfilterx_nohdr" ) + CLIENTEFFECT_MATERIAL( "dev/blurfiltery" ) + CLIENTEFFECT_MATERIAL( "dev/blurfiltery_nohdr" ) + CLIENTEFFECT_MATERIAL( "dev/bloomadd" ) + CLIENTEFFECT_MATERIAL( "dev/downsample" ) + #ifdef CSTRIKE_DLL + CLIENTEFFECT_MATERIAL( "dev/downsample_non_hdr_cstrike" ) + #else + CLIENTEFFECT_MATERIAL( "dev/downsample_non_hdr" ) + #endif + CLIENTEFFECT_MATERIAL( "dev/no_pixel_write" ) + CLIENTEFFECT_MATERIAL( "dev/lumcompare" ) + CLIENTEFFECT_MATERIAL( "dev/floattoscreen_combine" ) + CLIENTEFFECT_MATERIAL( "dev/copyfullframefb_vanilla" ) + CLIENTEFFECT_MATERIAL( "dev/copyfullframefb" ) + CLIENTEFFECT_MATERIAL( "dev/engine_post" ) + CLIENTEFFECT_MATERIAL( "dev/motion_blur" ) + CLIENTEFFECT_MATERIAL( "dev/upscale" ) + +#ifdef TF_CLIENT_DLL + CLIENTEFFECT_MATERIAL( "dev/pyro_blur_filter_y" ) + CLIENTEFFECT_MATERIAL( "dev/pyro_blur_filter_x" ) + CLIENTEFFECT_MATERIAL( "dev/pyro_dof" ) + CLIENTEFFECT_MATERIAL( "dev/pyro_vignette_border" ) + CLIENTEFFECT_MATERIAL( "dev/pyro_vignette" ) + CLIENTEFFECT_MATERIAL( "dev/pyro_post" ) +#endif + + // FF --> hlstriker: Added. +#ifdef GLOWS_ENABLE + CLIENTEFFECT_MATERIAL( "dev/glow_color" ) + CLIENTEFFECT_MATERIAL( "dev/halo_add_to_screen" ) +#endif + // FF <-- +CLIENTEFFECT_REGISTER_END_CONDITIONAL( engine->GetDXSupportLevel() >= 90 ) + +//----------------------------------------------------------------------------- +// Accessors to return the current view being rendered +//----------------------------------------------------------------------------- +const Vector &CurrentViewOrigin() +{ + Assert( s_bCanAccessCurrentView ); + return g_vecCurrentRenderOrigin; +} + +const QAngle &CurrentViewAngles() +{ + Assert( s_bCanAccessCurrentView ); + return g_vecCurrentRenderAngles; +} + +const Vector &CurrentViewForward() +{ + Assert( s_bCanAccessCurrentView ); + return g_vecCurrentVForward; +} + +const Vector &CurrentViewRight() +{ + Assert( s_bCanAccessCurrentView ); + return g_vecCurrentVRight; +} + +const Vector &CurrentViewUp() +{ + Assert( s_bCanAccessCurrentView ); + return g_vecCurrentVUp; +} + +const VMatrix &CurrentWorldToViewMatrix() +{ + Assert( s_bCanAccessCurrentView ); + return g_matCurrentCamInverse; +} + + +//----------------------------------------------------------------------------- +// Methods to set the current view/guard access to view parameters +//----------------------------------------------------------------------------- +void AllowCurrentViewAccess( bool allow ) +{ + s_bCanAccessCurrentView = allow; +} + +bool IsCurrentViewAccessAllowed() +{ + return s_bCanAccessCurrentView; +} + +void SetupCurrentView( const Vector &vecOrigin, const QAngle &angles, view_id_t viewID ) +{ + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + // Store off view origin and angles + g_vecCurrentRenderOrigin = vecOrigin; + g_vecCurrentRenderAngles = angles; + + // Compute the world->main camera transform + ComputeCameraVariables( vecOrigin, angles, + &g_vecCurrentVForward, &g_vecCurrentVRight, &g_vecCurrentVUp, &g_matCurrentCamInverse ); + + g_CurrentViewID = viewID; + s_bCanAccessCurrentView = true; + + // Cache off fade distances + float flScreenFadeMinSize, flScreenFadeMaxSize; + view->GetScreenFadeDistances( &flScreenFadeMinSize, &flScreenFadeMaxSize ); + modelinfo->SetViewScreenFadeRange( flScreenFadeMinSize, flScreenFadeMaxSize ); + + CMatRenderContextPtr pRenderContext( materials ); +#ifdef PORTAL + if ( g_pPortalRender->GetViewRecursionLevel() == 0 ) + { + pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, ((viewID == VIEW_MAIN) || (viewID == VIEW_3DSKY)) ? 1 : 0 ); + } +#else + pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, ((viewID == VIEW_MAIN) || (viewID == VIEW_3DSKY)) ? 1 : 0 ); +#endif +} + +view_id_t CurrentViewID() +{ + Assert( g_CurrentViewID != VIEW_ILLEGAL ); + return ( view_id_t )g_CurrentViewID; +} + +//----------------------------------------------------------------------------- +// Purpose: Portal views are considered 'Main' views. This function tests a view id +// against all view ids used by portal renderables, as well as the main view. +//----------------------------------------------------------------------------- +bool IsMainView ( view_id_t id ) +{ +#if defined(PORTAL) + return ( (id == VIEW_MAIN) || g_pPortalRender->IsPortalViewID( id ) ); +#else + return (id == VIEW_MAIN); +#endif +} + +void FinishCurrentView() +{ + s_bCanAccessCurrentView = false; +} + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +void CSimpleRenderExecutor::AddView( CRendering3dView *pView ) +{ + CBase3dView *pPrevRenderer = m_pMainView->SetActiveRenderer( pView ); + pView->Draw(); + m_pMainView->SetActiveRenderer( pPrevRenderer ); +} + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CViewRender::CViewRender() + : m_SimpleExecutor( this ) +{ + m_flCheapWaterStartDistance = 0.0f; + m_flCheapWaterEndDistance = 0.1f; + m_BaseDrawFlags = 0; + m_pActiveRenderer = NULL; + m_pCurrentlyDrawingEntity = NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +inline bool CViewRender::ShouldDrawEntities( void ) +{ + return ( !m_pDrawEntities || (m_pDrawEntities->GetInt() != 0) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Check all conditions which would prevent drawing the view model +// Input : drawViewmodel - +// *viewmodel - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CViewRender::ShouldDrawViewModel( bool bDrawViewmodel ) +{ + if ( !bDrawViewmodel ) + return false; + + if ( !r_drawviewmodel.GetBool() ) + return false; + + if ( C_BasePlayer::ShouldDrawLocalPlayer() ) + return false; + + if ( !ShouldDrawEntities() ) + return false; + + if ( render->GetViewEntity() > gpGlobals->maxClients ) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CViewRender::UpdateRefractIfNeededByList( CUtlVector< IClientRenderable * > &list ) +{ + int nCount = list.Count(); + for( int i=0; i < nCount; ++i ) + { + IClientUnknown *pUnk = list[i]->GetIClientUnknown(); + Assert( pUnk ); + + IClientRenderable *pRenderable = pUnk->GetClientRenderable(); + Assert( pRenderable ); + + if ( pRenderable->UsesPowerOfTwoFrameBufferTexture() ) + { + UpdateRefractTexture(); + return true; + } + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CViewRender::DrawRenderablesInList( CUtlVector< IClientRenderable * > &list, int flags ) +{ + Assert( m_pCurrentlyDrawingEntity == NULL ); + int nCount = list.Count(); + for( int i=0; i < nCount; ++i ) + { + IClientUnknown *pUnk = list[i]->GetIClientUnknown(); + Assert( pUnk ); + + IClientRenderable *pRenderable = pUnk->GetClientRenderable(); + Assert( pRenderable ); + + // Non-view models wanting to render in view model list... + if ( pRenderable->ShouldDraw() ) + { + m_pCurrentlyDrawingEntity = pUnk->GetBaseEntity(); + pRenderable->DrawModel( STUDIO_RENDER | flags ); + } + } + m_pCurrentlyDrawingEntity = NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: Actually draw the view model +// Input : drawViewModel - +//----------------------------------------------------------------------------- +void CViewRender::DrawViewModels( const CViewSetup &view, bool drawViewmodel ) +{ + VPROF( "CViewRender::DrawViewModel" ); + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + +#ifdef PORTAL //in portal, we'd like a copy of the front buffer without the gun in it for use with the depth doubler + g_pPortalRender->UpdateDepthDoublerTexture( view ); +#endif + + bool bShouldDrawPlayerViewModel = ShouldDrawViewModel( drawViewmodel ); + bool bShouldDrawToolViewModels = ToolsEnabled(); + + CMatRenderContextPtr pRenderContext( materials ); + + PIXEVENT( pRenderContext, "DrawViewModels" ); + + // Restore the matrices + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + + CViewSetup viewModelSetup( view ); + viewModelSetup.zNear = view.zNearViewmodel; + viewModelSetup.zFar = view.zFarViewmodel; + viewModelSetup.fov = view.fovViewmodel; + viewModelSetup.m_flAspectRatio = engine->GetScreenAspectRatio(); + + ITexture *pRTColor = NULL; + ITexture *pRTDepth = NULL; + if( view.m_eStereoEye != STEREO_EYE_MONO ) + { + pRTColor = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(view.m_eStereoEye-1), ISourceVirtualReality::RT_Color ); + pRTDepth = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(view.m_eStereoEye-1), ISourceVirtualReality::RT_Depth ); + } + + render->Push3DView( viewModelSetup, 0, pRTColor, GetFrustum(), pRTDepth ); + +#ifdef PORTAL //the depth range hack doesn't work well enough for the portal mod (and messing with the depth hack values makes some models draw incorrectly) + //step up to a full depth clear if we're extremely close to a portal (in a portal environment) + extern bool LocalPlayerIsCloseToPortal( void ); //defined in C_Portal_Player.cpp, abstracting to a single bool function to remove explicit dependence on c_portal_player.h/cpp, you can define the function as a "return true" in other build configurations at the cost of some perf + bool bUseDepthHack = !LocalPlayerIsCloseToPortal(); + if( !bUseDepthHack ) + pRenderContext->ClearBuffers( false, true, false ); +#else + const bool bUseDepthHack = true; +#endif + + // FIXME: Add code to read the current depth range + float depthmin = 0.0f; + float depthmax = 1.0f; + + // HACK HACK: Munge the depth range to prevent view model from poking into walls, etc. + // Force clipped down range + if( bUseDepthHack ) + pRenderContext->DepthRange( 0.0f, 0.1f ); + + if ( bShouldDrawPlayerViewModel || bShouldDrawToolViewModels ) + { + + CUtlVector< IClientRenderable * > opaqueViewModelList( 32 ); + CUtlVector< IClientRenderable * > translucentViewModelList( 32 ); + + ClientLeafSystem()->CollateViewModelRenderables( opaqueViewModelList, translucentViewModelList ); + + if ( ToolsEnabled() && ( !bShouldDrawPlayerViewModel || !bShouldDrawToolViewModels ) ) + { + int nOpaque = opaqueViewModelList.Count(); + for ( int i = nOpaque-1; i >= 0; --i ) + { + IClientRenderable *pRenderable = opaqueViewModelList[ i ]; + bool bEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( ( bEntity && !bShouldDrawPlayerViewModel ) || ( !bEntity && !bShouldDrawToolViewModels ) ) + { + opaqueViewModelList.FastRemove( i ); + } + } + + int nTranslucent = translucentViewModelList.Count(); + for ( int i = nTranslucent-1; i >= 0; --i ) + { + IClientRenderable *pRenderable = translucentViewModelList[ i ]; + bool bEntity = pRenderable->GetIClientUnknown()->GetBaseEntity(); + if ( ( bEntity && !bShouldDrawPlayerViewModel ) || ( !bEntity && !bShouldDrawToolViewModels ) ) + { + translucentViewModelList.FastRemove( i ); + } + } + } + + if ( !UpdateRefractIfNeededByList( opaqueViewModelList ) ) + { + UpdateRefractIfNeededByList( translucentViewModelList ); + } + + DrawRenderablesInList( opaqueViewModelList ); + DrawRenderablesInList( translucentViewModelList, STUDIO_TRANSPARENCY ); + } + + // Reset the depth range to the original values + if( bUseDepthHack ) + pRenderContext->DepthRange( depthmin, depthmax ); + + render->PopView( GetFrustum() ); + + // Restore the matrices + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CViewRender::ShouldDrawBrushModels( void ) +{ + if ( m_pDrawBrushModels && !m_pDrawBrushModels->GetInt() ) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Performs screen space effects, if any +//----------------------------------------------------------------------------- +void CViewRender::PerformScreenSpaceEffects( int x, int y, int w, int h ) +{ + VPROF("CViewRender::PerformScreenSpaceEffects()"); + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + // FIXME: Screen-space effects are busted in the editor + if ( engine->IsHammerRunning() ) + return; + + g_pScreenSpaceEffects->RenderEffects( x, y, w, h ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the screen space effect material (can't be done during rendering) +//----------------------------------------------------------------------------- +void CViewRender::SetScreenOverlayMaterial( IMaterial *pMaterial ) +{ + m_ScreenOverlayMaterial.Init( pMaterial ); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +IMaterial *CViewRender::GetScreenOverlayMaterial( ) +{ + return m_ScreenOverlayMaterial; +} + + +//----------------------------------------------------------------------------- +// Purpose: Performs screen space effects, if any +//----------------------------------------------------------------------------- +void CViewRender::PerformScreenOverlay( int x, int y, int w, int h ) +{ + VPROF("CViewRender::PerformScreenOverlay()"); + + if (m_ScreenOverlayMaterial) + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + if ( m_ScreenOverlayMaterial->NeedsFullFrameBufferTexture() ) + { + // FIXME: check with multi/sub-rect renders. Should this be 0,0,w,h instead? + DrawScreenEffectMaterial( m_ScreenOverlayMaterial, x, y, w, h ); + } + else if ( m_ScreenOverlayMaterial->NeedsPowerOfTwoFrameBufferTexture() ) + { + // First copy the FB off to the offscreen texture + UpdateRefractTexture( x, y, w, h, true ); + + // Now draw the entire screen using the material... + CMatRenderContextPtr pRenderContext( materials ); + ITexture *pTexture = GetPowerOfTwoFrameBufferTexture( ); + int sw = pTexture->GetActualWidth(); + int sh = pTexture->GetActualHeight(); + // Note - don't offset by x,y - already done by the viewport. + pRenderContext->DrawScreenSpaceRectangle( m_ScreenOverlayMaterial, 0, 0, w, h, + 0, 0, sw-1, sh-1, sw, sh ); + } + else + { + byte color[4] = { 255, 255, 255, 255 }; + render->ViewDrawFade( color, m_ScreenOverlayMaterial ); + } + } +} + +void CViewRender::DrawUnderwaterOverlay( void ) +{ + IMaterial *pOverlayMat = m_UnderWaterOverlayMaterial; + + if ( pOverlayMat ) + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + CMatRenderContextPtr pRenderContext( materials ); + + int x, y, w, h; + + pRenderContext->GetViewport( x, y, w, h ); + if ( pOverlayMat->NeedsFullFrameBufferTexture() ) + { + // FIXME: check with multi/sub-rect renders. Should this be 0,0,w,h instead? + DrawScreenEffectMaterial( pOverlayMat, x, y, w, h ); + } + else if ( pOverlayMat->NeedsPowerOfTwoFrameBufferTexture() ) + { + // First copy the FB off to the offscreen texture + UpdateRefractTexture( x, y, w, h, true ); + + // Now draw the entire screen using the material... + CMatRenderContextPtr pRenderContext( materials ); + ITexture *pTexture = GetPowerOfTwoFrameBufferTexture( ); + int sw = pTexture->GetActualWidth(); + int sh = pTexture->GetActualHeight(); + // Note - don't offset by x,y - already done by the viewport. + pRenderContext->DrawScreenSpaceRectangle( pOverlayMat, 0, 0, w, h, + 0, 0, sw-1, sh-1, sw, sh ); + } + else + { + // Note - don't offset by x,y - already done by the viewport. + // FIXME: actually test this code path. + pRenderContext->DrawScreenSpaceRectangle( pOverlayMat, 0, 0, w, h, + 0, 0, 1, 1, 1, 1 ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the min/max fade distances +//----------------------------------------------------------------------------- +void CViewRender::GetScreenFadeDistances( float *min, float *max ) +{ + if ( min ) + { + *min = r_screenfademinsize.GetFloat(); + } + + if ( max ) + { + *max = r_screenfademaxsize.GetFloat(); + } +} + +C_BaseEntity *CViewRender::GetCurrentlyDrawingEntity() +{ + return m_pCurrentlyDrawingEntity; +} + +void CViewRender::SetCurrentlyDrawingEntity( C_BaseEntity *pEnt ) +{ + m_pCurrentlyDrawingEntity = pEnt; +} + +bool CViewRender::UpdateShadowDepthTexture( ITexture *pRenderTarget, ITexture *pDepthTexture, const CViewSetup &shadowViewIn ) +{ + VPROF_INCREMENT_COUNTER( "shadow depth textures rendered", 1 ); + + CMatRenderContextPtr pRenderContext( materials ); + + char szPIXEventName[128]; + sprintf( szPIXEventName, "UpdateShadowDepthTexture (%s)", pDepthTexture->GetName() ); + PIXEVENT( pRenderContext, szPIXEventName ); + + CRefPtr pShadowDepthView = new CShadowDepthView( this ); + pShadowDepthView->Setup( shadowViewIn, pRenderTarget, pDepthTexture ); + AddViewToScene( pShadowDepthView ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Renders world and all entities, etc. +//----------------------------------------------------------------------------- +void CViewRender::ViewDrawScene( bool bDrew3dSkybox, SkyboxVisibility_t nSkyboxVisible, const CViewSetup &view, + int nClearFlags, view_id_t viewID, bool bDrawViewModel, int baseDrawFlags, ViewCustomVisibility_t *pCustomVisibility ) +{ + VPROF( "CViewRender::ViewDrawScene" ); + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + // this allows the refract texture to be updated once per *scene* on 360 + // (e.g. once for a monitor scene and once for the main scene) + g_viewscene_refractUpdateFrame = gpGlobals->framecount - 1; + + g_pClientShadowMgr->PreRender(); + + // Shadowed flashlights supported on ps_2_b and up... + if ( r_flashlightdepthtexture.GetBool() && (viewID == VIEW_MAIN) ) + { + g_pClientShadowMgr->ComputeShadowDepthTextures( view ); + } + + m_BaseDrawFlags = baseDrawFlags; + + SetupCurrentView( view.origin, view.angles, viewID ); + + // Invoke pre-render methods + IGameSystem::PreRenderAllSystems(); + + // Start view + unsigned int visFlags; + SetupVis( view, visFlags, pCustomVisibility ); + + if ( !bDrew3dSkybox && + ( nSkyboxVisible == SKYBOX_NOT_VISIBLE ) && ( visFlags & IVRenderView::VIEW_SETUP_VIS_EX_RETURN_FLAGS_USES_RADIAL_VIS ) ) + { + // This covers the case where we don't see a 3dskybox, yet radial vis is clipping + // the far plane. Need to clear to fog color in this case. + nClearFlags |= VIEW_CLEAR_COLOR; + SetClearColorToFogColor( ); + } + + bool drawSkybox = r_skybox.GetBool(); + if ( bDrew3dSkybox || ( nSkyboxVisible == SKYBOX_NOT_VISIBLE ) ) + { + drawSkybox = false; + } + + ParticleMgr()->IncrementFrameCode(); + + DrawWorldAndEntities( drawSkybox, view, nClearFlags, pCustomVisibility ); + + // FF --> hlstriker: Added +#if defined (WIN32) + VisibleFogVolumeInfo_t fogVolumeInfo; + render->GetVisibleFogVolume( view.origin, &fogVolumeInfo ); + WaterRenderInfo_t info; + DetermineWaterRenderInfo( fogVolumeInfo, info ); + g_ShaderEditorSystem->CustomViewRender( &g_CurrentViewID, fogVolumeInfo, info ); +#endif + // <-- + + // Disable fog for the rest of the stuff + DisableFog(); + + // UNDONE: Don't do this with masked brush models, they should probably be in a separate list + // render->DrawMaskEntities() + + // Here are the overlays... + + CGlowOverlay::DrawOverlays( view.m_bCacheFullSceneState ); + + // issue the pixel visibility tests + if ( IsMainView( CurrentViewID() ) ) + { + PixelVisibility_EndCurrentView(); + } + + // Draw rain.. + DrawPrecipitation(); + + // Make sure sound doesn't stutter + engine->Sound_ExtraUpdate(); + + // Debugging info goes over the top + CDebugViewRender::Draw3DDebuggingInfo( view ); + + // Draw client side effects + // NOTE: These are not sorted against the rest of the frame + clienteffects->DrawEffects( gpGlobals->frametime ); + + // Mark the frame as locked down for client fx additions + SetFXCreationAllowed( false ); + + // Invoke post-render methods + IGameSystem::PostRenderAllSystems(); + + FinishCurrentView(); + + // Free shadow depth textures for use in future view + if ( r_flashlightdepthtexture.GetBool() ) + { + g_pClientShadowMgr->UnlockAllShadowDepthTextures(); + } +} + + +void CheckAndTransitionColor( float flPercent, float *pColor, float *pLerpToColor ) +{ + if ( pLerpToColor[0] != pColor[0] || pLerpToColor[1] != pColor[1] || pLerpToColor[2] != pColor[2] ) + { + float flDestColor[3]; + + flDestColor[0] = pLerpToColor[0]; + flDestColor[1] = pLerpToColor[1]; + flDestColor[2] = pLerpToColor[2]; + + pColor[0] = FLerp( pColor[0], flDestColor[0], flPercent ); + pColor[1] = FLerp( pColor[1], flDestColor[1], flPercent ); + pColor[2] = FLerp( pColor[2], flDestColor[2], flPercent ); + } + else + { + pColor[0] = pLerpToColor[0]; + pColor[1] = pLerpToColor[1]; + pColor[2] = pLerpToColor[2]; + } +} + +static void GetFogColorTransition( fogparams_t *pFogParams, float *pColorPrimary, float *pColorSecondary ) +{ + if ( !pFogParams ) + return; + + if ( pFogParams->lerptime >= gpGlobals->curtime ) + { + float flPercent = 1.0f - (( pFogParams->lerptime - gpGlobals->curtime ) / pFogParams->duration ); + + float flPrimaryColorLerp[3] = { pFogParams->colorPrimaryLerpTo.GetR(), pFogParams->colorPrimaryLerpTo.GetG(), pFogParams->colorPrimaryLerpTo.GetB() }; + float flSecondaryColorLerp[3] = { pFogParams->colorSecondaryLerpTo.GetR(), pFogParams->colorSecondaryLerpTo.GetG(), pFogParams->colorSecondaryLerpTo.GetB() }; + + CheckAndTransitionColor( flPercent, pColorPrimary, flPrimaryColorLerp ); + CheckAndTransitionColor( flPercent, pColorSecondary, flSecondaryColorLerp ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the fog color to use in rendering the current frame. +//----------------------------------------------------------------------------- +static void GetFogColor( fogparams_t *pFogParams, float *pColor ) +{ + C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); + if ( !pbp || !pFogParams ) + return; + + const char *fogColorString = fog_color.GetString(); + if( fog_override.GetInt() && fogColorString ) + { + sscanf( fogColorString, "%f%f%f", pColor, pColor+1, pColor+2 ); + } + else + { + float flPrimaryColor[3] = { pFogParams->colorPrimary.GetR(), pFogParams->colorPrimary.GetG(), pFogParams->colorPrimary.GetB() }; + float flSecondaryColor[3] = { pFogParams->colorSecondary.GetR(), pFogParams->colorSecondary.GetG(), pFogParams->colorSecondary.GetB() }; + + GetFogColorTransition( pFogParams, flPrimaryColor, flSecondaryColor ); + + if( pFogParams->blend ) + { + // + // Blend between two fog colors based on viewing angle. + // The secondary fog color is at 180 degrees to the primary fog color. + // + Vector forward; + pbp->EyeVectors( &forward, NULL, NULL ); + + Vector vNormalized = pFogParams->dirPrimary; + VectorNormalize( vNormalized ); + pFogParams->dirPrimary = vNormalized; + + float flBlendFactor = 0.5 * forward.Dot( pFogParams->dirPrimary ) + 0.5; + + // FIXME: convert to linear colorspace + pColor[0] = flPrimaryColor[0] * flBlendFactor + flSecondaryColor[0] * ( 1 - flBlendFactor ); + pColor[1] = flPrimaryColor[1] * flBlendFactor + flSecondaryColor[1] * ( 1 - flBlendFactor ); + pColor[2] = flPrimaryColor[2] * flBlendFactor + flSecondaryColor[2] * ( 1 - flBlendFactor ); + } + else + { + pColor[0] = flPrimaryColor[0]; + pColor[1] = flPrimaryColor[1]; + pColor[2] = flPrimaryColor[2]; + } + } + + VectorScale( pColor, 1.0f / 255.0f, pColor ); +} + + +static float GetFogStart( fogparams_t *pFogParams ) +{ + if( !pFogParams ) + return 0.0f; + + if( fog_override.GetInt() ) + { + if( fog_start.GetFloat() == -1.0f ) + { + return pFogParams->start; + } + else + { + return fog_start.GetFloat(); + } + } + else + { + if ( pFogParams->lerptime > gpGlobals->curtime ) + { + if ( pFogParams->start != pFogParams->startLerpTo ) + { + if ( pFogParams->lerptime > gpGlobals->curtime ) + { + float flPercent = 1.0f - (( pFogParams->lerptime - gpGlobals->curtime ) / pFogParams->duration ); + + return FLerp( pFogParams->start, pFogParams->startLerpTo, flPercent ); + } + else + { + if ( pFogParams->start != pFogParams->startLerpTo ) + { + pFogParams->start = pFogParams->startLerpTo; + } + } + } + } + + return pFogParams->start; + } +} + +static float GetFogEnd( fogparams_t *pFogParams ) +{ + if( !pFogParams ) + return 0.0f; + + if( fog_override.GetInt() ) + { + if( fog_end.GetFloat() == -1.0f ) + { + return pFogParams->end; + } + else + { + return fog_end.GetFloat(); + } + } + else + { + if ( pFogParams->lerptime > gpGlobals->curtime ) + { + if ( pFogParams->end != pFogParams->endLerpTo ) + { + if ( pFogParams->lerptime > gpGlobals->curtime ) + { + float flPercent = 1.0f - (( pFogParams->lerptime - gpGlobals->curtime ) / pFogParams->duration ); + + return FLerp( pFogParams->end, pFogParams->endLerpTo, flPercent ); + } + else + { + if ( pFogParams->end != pFogParams->endLerpTo ) + { + pFogParams->end = pFogParams->endLerpTo; + } + } + } + } + + return pFogParams->end; + } +} + +static bool GetFogEnable( fogparams_t *pFogParams ) +{ + if ( cl_leveloverview.GetFloat() > 0 ) + return false; + + // Ask the clientmode + if ( g_pClientMode->ShouldDrawFog() == false ) + return false; + + if( fog_override.GetInt() ) + { + if( fog_enable.GetInt() ) + { + return true; + } + else + { + return false; + } + } + else + { + if( pFogParams ) + return pFogParams->enable != false; + + return false; + } +} + + +static float GetFogMaxDensity( fogparams_t *pFogParams ) +{ + if( !pFogParams ) + return 1.0f; + + if ( cl_leveloverview.GetFloat() > 0 ) + return 1.0f; + + // Ask the clientmode + if ( !g_pClientMode->ShouldDrawFog() ) + return 1.0f; + + if ( fog_override.GetInt() ) + { + if ( fog_maxdensity.GetFloat() == -1.0f ) + return pFogParams->maxdensity; + else + return fog_maxdensity.GetFloat(); + } + else + return pFogParams->maxdensity; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the skybox fog color to use in rendering the current frame. +//----------------------------------------------------------------------------- +static void GetSkyboxFogColor( float *pColor ) +{ + C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); + if( !pbp ) + { + return; + } + CPlayerLocalData *local = &pbp->m_Local; + + const char *fogColorString = fog_colorskybox.GetString(); + if( fog_override.GetInt() && fogColorString ) + { + sscanf( fogColorString, "%f%f%f", pColor, pColor+1, pColor+2 ); + } + else + { + if( local->m_skybox3d.fog.blend ) + { + // + // Blend between two fog colors based on viewing angle. + // The secondary fog color is at 180 degrees to the primary fog color. + // + Vector forward; + pbp->EyeVectors( &forward, NULL, NULL ); + + Vector vNormalized = local->m_skybox3d.fog.dirPrimary; + VectorNormalize( vNormalized ); + local->m_skybox3d.fog.dirPrimary = vNormalized; + + float flBlendFactor = 0.5 * forward.Dot( local->m_skybox3d.fog.dirPrimary ) + 0.5; + + // FIXME: convert to linear colorspace + pColor[0] = local->m_skybox3d.fog.colorPrimary.GetR() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetR() * ( 1 - flBlendFactor ); + pColor[1] = local->m_skybox3d.fog.colorPrimary.GetG() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetG() * ( 1 - flBlendFactor ); + pColor[2] = local->m_skybox3d.fog.colorPrimary.GetB() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetB() * ( 1 - flBlendFactor ); + } + else + { + pColor[0] = local->m_skybox3d.fog.colorPrimary.GetR(); + pColor[1] = local->m_skybox3d.fog.colorPrimary.GetG(); + pColor[2] = local->m_skybox3d.fog.colorPrimary.GetB(); + } + } + + VectorScale( pColor, 1.0f / 255.0f, pColor ); +} + + +static float GetSkyboxFogStart( void ) +{ + C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); + if( !pbp ) + { + return 0.0f; + } + CPlayerLocalData *local = &pbp->m_Local; + + if( fog_override.GetInt() ) + { + if( fog_startskybox.GetFloat() == -1.0f ) + { + return local->m_skybox3d.fog.start; + } + else + { + return fog_startskybox.GetFloat(); + } + } + else + { + return local->m_skybox3d.fog.start; + } +} + +static float GetSkyboxFogEnd( void ) +{ + C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); + if( !pbp ) + { + return 0.0f; + } + CPlayerLocalData *local = &pbp->m_Local; + + if( fog_override.GetInt() ) + { + if( fog_endskybox.GetFloat() == -1.0f ) + { + return local->m_skybox3d.fog.end; + } + else + { + return fog_endskybox.GetFloat(); + } + } + else + { + return local->m_skybox3d.fog.end; + } +} + + +static float GetSkyboxFogMaxDensity() +{ + C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); + if ( !pbp ) + return 1.0f; + + CPlayerLocalData *local = &pbp->m_Local; + + if ( cl_leveloverview.GetFloat() > 0 ) + return 1.0f; + + // Ask the clientmode + if ( !g_pClientMode->ShouldDrawFog() ) + return 1.0f; + + if ( fog_override.GetInt() ) + { + if ( fog_maxdensityskybox.GetFloat() == -1.0f ) + return local->m_skybox3d.fog.maxdensity; + else + return fog_maxdensityskybox.GetFloat(); + } + else + return local->m_skybox3d.fog.maxdensity; +} + + +void CViewRender::DisableFog( void ) +{ + VPROF("CViewRander::DisableFog()"); + + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->FogMode( MATERIAL_FOG_NONE ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CViewRender::SetupVis( const CViewSetup& view, unsigned int &visFlags, ViewCustomVisibility_t *pCustomVisibility ) +{ + VPROF( "CViewRender::SetupVis" ); + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + if ( pCustomVisibility && pCustomVisibility->m_nNumVisOrigins ) + { + // Pass array or vis origins to merge + render->ViewSetupVisEx( ShouldForceNoVis(), pCustomVisibility->m_nNumVisOrigins, pCustomVisibility->m_rgVisOrigins, visFlags ); + } + else + { + // Use render origin as vis origin by default + render->ViewSetupVisEx( ShouldForceNoVis(), 1, &view.origin, visFlags ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Renders voice feedback and other sprites attached to players +// Input : none +//----------------------------------------------------------------------------- +void CViewRender::RenderPlayerSprites() +{ + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + GetClientVoiceMgr()->DrawHeadLabels(); +} + +//----------------------------------------------------------------------------- +// Sets up, cleans up the main 3D view +//----------------------------------------------------------------------------- +void CViewRender::SetupMain3DView( const CViewSetup &view, int &nClearFlags ) +{ + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + // FIXME: I really want these fields removed from CViewSetup + // and passed in as independent flags + // Clear the color here if requested. + + int nDepthStencilFlags = nClearFlags & ( VIEW_CLEAR_DEPTH | VIEW_CLEAR_STENCIL ); + nClearFlags &= ~( nDepthStencilFlags ); // Clear these flags + if ( nClearFlags & VIEW_CLEAR_COLOR ) + { + nClearFlags |= nDepthStencilFlags; // Add them back in if we're clearing color + } + + // If we are using HDR, we render to the HDR full frame buffer texture + // instead of whatever was previously the render target + if( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT ) + { + render->Push3DView( view, nClearFlags, GetFullFrameFrameBufferTexture( 0 ), GetFrustum() ); + } + else + { + ITexture *pRTColor = NULL; + ITexture *pRTDepth = NULL; + if( view.m_eStereoEye != STEREO_EYE_MONO ) + { + pRTColor = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(view.m_eStereoEye-1), ISourceVirtualReality::RT_Color ); + pRTDepth = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(view.m_eStereoEye-1), ISourceVirtualReality::RT_Depth ); + } + + render->Push3DView( view, nClearFlags, pRTColor, GetFrustum(), pRTDepth ); + } + + // If we didn't clear the depth here, we'll need to clear it later + nClearFlags ^= nDepthStencilFlags; // Toggle these bits + if ( nClearFlags & VIEW_CLEAR_COLOR ) + { + // If we cleared the color here, we don't need to clear it later + nClearFlags &= ~( VIEW_CLEAR_COLOR | VIEW_CLEAR_FULL_TARGET ); + } +} + +void CViewRender::CleanupMain3DView( const CViewSetup &view ) +{ + render->PopView( GetFrustum() ); +} + + +//----------------------------------------------------------------------------- +// Queues up an overlay rendering +//----------------------------------------------------------------------------- +void CViewRender::QueueOverlayRenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ) +{ + // Can't have 2 in a single scene + Assert( !m_bDrawOverlay ); + + m_bDrawOverlay = true; + m_OverlayViewSetup = view; + m_OverlayClearFlags = nClearFlags; + m_OverlayDrawFlags = whatToDraw; +} + +//----------------------------------------------------------------------------- +// Purpose: Force the view to freeze on the next frame for the specified time +//----------------------------------------------------------------------------- +void CViewRender::FreezeFrame( float flFreezeTime ) +{ + if ( flFreezeTime == 0 ) + { + m_flFreezeFrameUntil = 0; + for( int i=0; i < STEREO_EYE_MAX; i++ ) + { + m_rbTakeFreezeFrame[ i ] = false; + } + } + else + { + if ( m_flFreezeFrameUntil > gpGlobals->curtime ) + { + m_flFreezeFrameUntil += flFreezeTime; + } + else + { + m_flFreezeFrameUntil = gpGlobals->curtime + flFreezeTime; + for( int i=GetFirstEye(); i <= GetLastEye(); i++ ) + { + m_rbTakeFreezeFrame[ i ] = true; + } + } + } +} + +const char *COM_GetModDirectory(); + + +//----------------------------------------------------------------------------- +// Purpose: This renders the entire 3D view and the in-game hud/viewmodel +// Input : &view - +// whatToDraw - +//----------------------------------------------------------------------------- +// This renders the entire 3D view. +void CViewRender::RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw ) +{ + m_UnderWaterOverlayMaterial.Shutdown(); // underwater view will set + + m_CurrentView = view; + + C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true ); + VPROF( "CViewRender::RenderView" ); + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + // Don't want TF2 running less than DX 8 + if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 ) + { + // We know they were running at least 8.0 when the game started...we check the + // value in ClientDLL_Init()...so they must be messing with their DirectX settings. + if ( ( Q_stricmp( COM_GetModDirectory(), "tf" ) == 0 ) || ( Q_stricmp( COM_GetModDirectory(), "tf_beta" ) == 0 ) ) + { + static bool bFirstTime = true; + if ( bFirstTime ) + { + bFirstTime = false; + Msg( "This game has a minimum requirement of DirectX 8.0 to run properly.\n" ); + } + return; + } + } + + CMatRenderContextPtr pRenderContext( materials ); + ITexture *saveRenderTarget = pRenderContext->GetRenderTarget(); + pRenderContext.SafeRelease(); // don't want to hold for long periods in case in a locking active share thread mode + + if ( !m_rbTakeFreezeFrame[ view.m_eStereoEye ] && m_flFreezeFrameUntil > gpGlobals->curtime ) + { + CRefPtr pFreezeFrameView = new CFreezeFrameView( this ); + pFreezeFrameView->Setup( view ); + AddViewToScene( pFreezeFrameView ); + + g_bRenderingView = true; + s_bCanAccessCurrentView = true; + } + else + { + g_flFreezeFlash = 0.0f; + + g_pClientShadowMgr->AdvanceFrame(); + + #ifdef USE_MONITORS + if ( cl_drawmonitors.GetBool() && + ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 70 ) && + ( ( whatToDraw & RENDERVIEW_SUPPRESSMONITORRENDERING ) == 0 ) ) + { + CViewSetup viewMiddle = GetView( STEREO_EYE_MONO ); + DrawMonitors( viewMiddle ); + } + #endif + + g_bRenderingView = true; + + // Must be first + render->SceneBegin(); + + pRenderContext.GetFrom( materials ); + pRenderContext->TurnOnToneMapping(); + pRenderContext.SafeRelease(); + + // clear happens here probably + SetupMain3DView( view, nClearFlags ); + + bool bDrew3dSkybox = false; + SkyboxVisibility_t nSkyboxVisible = SKYBOX_NOT_VISIBLE; + + // if the 3d skybox world is drawn, then don't draw the normal skybox + CSkyboxView *pSkyView = new CSkyboxView( this ); + if ( ( bDrew3dSkybox = pSkyView->Setup( view, &nClearFlags, &nSkyboxVisible ) ) != false ) + { + AddViewToScene( pSkyView ); +#if defined (WIN32) + g_ShaderEditorSystem->UpdateSkymask(); // FF --> hlstriker: Added +#endif + } + SafeRelease( pSkyView ); + + // Force it to clear the framebuffer if they're in solid space. + if ( ( nClearFlags & VIEW_CLEAR_COLOR ) == 0 ) + { + if ( enginetrace->GetPointContents( view.origin ) == CONTENTS_SOLID ) + { + nClearFlags |= VIEW_CLEAR_COLOR; + } + } + + // Render world and all entities, particles, etc. + if( !g_pIntroData ) + { + ViewDrawScene( bDrew3dSkybox, nSkyboxVisible, view, nClearFlags, VIEW_MAIN, whatToDraw & RENDERVIEW_DRAWVIEWMODEL ); + } + else + { + ViewDrawScene_Intro( view, nClearFlags, *g_pIntroData ); + } + + // We can still use the 'current view' stuff set up in ViewDrawScene + s_bCanAccessCurrentView = true; + + + engine->DrawPortals(); + + DisableFog(); + + // Finish scene + render->SceneEnd(); + + // Draw lightsources if enabled + render->DrawLights(); + + RenderPlayerSprites(); + + // Image-space motion blur + if ( !building_cubemaps.GetBool() && view.m_bDoBloomAndToneMapping ) // We probably should use a different view. variable here + { + if ( ( mat_motion_blur_enabled.GetInt() ) && ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 90 ) ) + { + pRenderContext.GetFrom( materials ); + { + PIXEVENT( pRenderContext, "DoImageSpaceMotionBlur" ); + DoImageSpaceMotionBlur( view, view.x, view.y, view.width, view.height ); + } + pRenderContext.SafeRelease(); + } + } + + GetClientModeNormal()->DoPostScreenSpaceEffects( &view ); + + // Now actually draw the viewmodel + DrawViewModels( view, whatToDraw & RENDERVIEW_DRAWVIEWMODEL ); + +#if defined (WIN32) + g_ShaderEditorSystem->UpdateSkymask( bDrew3dSkybox ); // FF --> hlstriker: Added +#endif + + DrawUnderwaterOverlay(); + + PixelVisibility_EndScene(); + + // Draw fade over entire screen if needed + byte color[4]; + bool blend; + vieweffects->GetFadeParams( &color[0], &color[1], &color[2], &color[3], &blend ); + + // Draw an overlay to make it even harder to see inside smoke particle systems. + DrawSmokeFogOverlay(); + + // Overlay screen fade on entire screen + IMaterial* pMaterial = blend ? m_ModulateSingleColor : m_TranslucentSingleColor; + render->ViewDrawFade( color, pMaterial ); + PerformScreenOverlay( view.x, view.y, view.width, view.height ); + + // Prevent sound stutter if going slow + engine->Sound_ExtraUpdate(); + + if ( !building_cubemaps.GetBool() && view.m_bDoBloomAndToneMapping ) + { + pRenderContext.GetFrom( materials ); + { + PIXEVENT( pRenderContext, "DoEnginePostProcessing" ); + + bool bFlashlightIsOn = false; + C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer(); + if ( pLocal ) + { + bFlashlightIsOn = pLocal->IsEffectActive( EF_DIMLIGHT ); + } + DoEnginePostProcessing( view.x, view.y, view.width, view.height, bFlashlightIsOn ); + } + pRenderContext.SafeRelease(); + } +#if defined (WIN32) + g_ShaderEditorSystem->CustomPostRender(); // FF --> hlstriker: Added +#endif + + // And here are the screen-space effects + + if ( IsPC() ) + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "GrabPreColorCorrectedFrame" ); + + // Grab the pre-color corrected frame for editing purposes + engine->GrabPreColorCorrectedFrame( view.x, view.y, view.width, view.height ); + } + + PerformScreenSpaceEffects( 0, 0, view.width, view.height ); + + if ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER ) + { + pRenderContext.GetFrom( materials ); + pRenderContext->SetToneMappingScaleLinear(Vector(1,1,1)); + pRenderContext.SafeRelease(); + } + + CleanupMain3DView( view ); + + if ( m_rbTakeFreezeFrame[ view.m_eStereoEye ] ) + { + Rect_t rect; + rect.x = view.x; + rect.y = view.y; + rect.width = view.width; + rect.height = view.height; + + pRenderContext = materials->GetRenderContext(); + if ( IsX360() ) + { + // 360 doesn't create the Fullscreen texture + pRenderContext->CopyRenderTargetToTextureEx( GetFullFrameFrameBufferTexture( 1 ), 0, &rect, &rect ); + } + else + { + pRenderContext->CopyRenderTargetToTextureEx( GetFullscreenTexture(), 0, &rect, &rect ); + } + pRenderContext.SafeRelease(); + m_rbTakeFreezeFrame[ view.m_eStereoEye ] = false; + } + + pRenderContext = materials->GetRenderContext(); + pRenderContext->SetRenderTarget( saveRenderTarget ); + pRenderContext.SafeRelease(); + + // Draw the overlay + if ( m_bDrawOverlay ) + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DrawOverlay" ); + + // This allows us to be ok if there are nested overlay views + CViewSetup currentView = m_CurrentView; + CViewSetup tempView = m_OverlayViewSetup; + tempView.fov = ScaleFOVByWidthRatio( tempView.fov, tempView.m_flAspectRatio / ( 4.0f / 3.0f ) ); + tempView.m_bDoBloomAndToneMapping = false; // FIXME: Hack to get Mark up and running + m_bDrawOverlay = false; + RenderView( tempView, m_OverlayClearFlags, m_OverlayDrawFlags ); + m_CurrentView = currentView; + } + + } + + if ( mat_viewportupscale.GetBool() && mat_viewportscale.GetFloat() < 1.0f ) + { + CMatRenderContextPtr pRenderContext( materials ); + + ITexture *pFullFrameFB1 = materials->FindTexture( "_rt_FullFrameFB1", TEXTURE_GROUP_RENDER_TARGET ); + IMaterial *pCopyMaterial = materials->FindMaterial( "dev/upscale", TEXTURE_GROUP_OTHER ); + pCopyMaterial->IncrementReferenceCount(); + + Rect_t DownscaleRect, UpscaleRect; + + DownscaleRect.x = view.x; + DownscaleRect.y = view.y; + DownscaleRect.width = view.width; + DownscaleRect.height = view.height; + + UpscaleRect.x = view.m_nUnscaledX; + UpscaleRect.y = view.m_nUnscaledY; + UpscaleRect.width = view.m_nUnscaledWidth; + UpscaleRect.height = view.m_nUnscaledHeight; + + pRenderContext->CopyRenderTargetToTextureEx( pFullFrameFB1, 0, &DownscaleRect, &DownscaleRect ); + pRenderContext->DrawScreenSpaceRectangle( pCopyMaterial, UpscaleRect.x, UpscaleRect.y, UpscaleRect.width, UpscaleRect.height, + DownscaleRect.x, DownscaleRect.y, DownscaleRect.x+DownscaleRect.width-1, DownscaleRect.y+DownscaleRect.height-1, + pFullFrameFB1->GetActualWidth(), pFullFrameFB1->GetActualHeight() ); + + pCopyMaterial->DecrementReferenceCount(); + } + + // if we're in VR mode we might need to override the render target + if( UseVR() ) + { + saveRenderTarget = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(view.m_eStereoEye - 1), ISourceVirtualReality::RT_Color ); + } + + // Draw the 2D graphics + render->Push2DView( view, 0, saveRenderTarget, GetFrustum() ); + + Render2DEffectsPreHUD( view ); + + if ( whatToDraw & RENDERVIEW_DRAWHUD ) + { + VPROF_BUDGET( "VGui_DrawHud", VPROF_BUDGETGROUP_OTHER_VGUI ); + int viewWidth = view.m_nUnscaledWidth; + int viewHeight = view.m_nUnscaledHeight; + int viewActualWidth = view.m_nUnscaledWidth; + int viewActualHeight = view.m_nUnscaledHeight; + int viewX = view.m_nUnscaledX; + int viewY = view.m_nUnscaledY; + int viewFramebufferX = 0; + int viewFramebufferY = 0; + int viewFramebufferWidth = viewWidth; + int viewFramebufferHeight = viewHeight; + bool bClear = false; + bool bPaintMainMenu = false; + ITexture *pTexture = NULL; + if( UseVR() ) + { + if( g_ClientVirtualReality.ShouldRenderHUDInWorld() ) + { + pTexture = materials->FindTexture( "_rt_gui", NULL, false ); + if( pTexture ) + { + bPaintMainMenu = true; + bClear = true; + viewX = 0; + viewY = 0; + viewActualWidth = pTexture->GetActualWidth(); + viewActualHeight = pTexture->GetActualHeight(); + + vgui::surface()->GetScreenSize( viewWidth, viewHeight ); + + viewFramebufferX = 0; + if( view.m_eStereoEye == STEREO_EYE_RIGHT && !saveRenderTarget ) + viewFramebufferX = viewFramebufferWidth; + viewFramebufferY = 0; + } + } + else + { + viewFramebufferX = view.m_eStereoEye == STEREO_EYE_RIGHT ? viewWidth : 0; + viewFramebufferY = 0; + } + } + + // Get the render context out of materials to avoid some debug stuff. + // WARNING THIS REQUIRES THE .SafeRelease below or it'll never release the ref + pRenderContext = materials->GetRenderContext(); + + // clear depth in the backbuffer before we push the render target + if( bClear ) + { + pRenderContext->ClearBuffers( false, true, true ); + } + + // constrain where VGUI can render to the view + pRenderContext->PushRenderTargetAndViewport( pTexture, NULL, viewX, viewY, viewActualWidth, viewActualHeight ); + // If drawing off-screen, force alpha for that pass + if (pTexture) + { + pRenderContext->OverrideAlphaWriteEnable( true, true ); + } + + // let vgui know where to render stuff for the forced-to-framebuffer panels + if( UseVR() ) + { + g_pMatSystemSurface->SetFullscreenViewportAndRenderTarget( viewFramebufferX, viewFramebufferY, viewFramebufferWidth, viewFramebufferHeight, saveRenderTarget ); + } + + // clear the render target if we need to + if( bClear ) + { + pRenderContext->ClearColor4ub( 0, 0, 0, 0 ); + pRenderContext->ClearBuffers( true, false ); + } + pRenderContext.SafeRelease(); + + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "VGui_DrawHud", __FUNCTION__ ); + + // paint the vgui screen + VGui_PreRender(); + + // Make sure the client .dll root panel is at the proper point before doing the "SolveTraverse" calls + vgui::VPANEL root = enginevgui->GetPanel( PANEL_CLIENTDLL ); + if ( root != 0 ) + { + vgui::ipanel()->SetSize( root, viewWidth, viewHeight ); + } + // Same for client .dll tools + root = enginevgui->GetPanel( PANEL_CLIENTDLL_TOOLS ); + if ( root != 0 ) + { + vgui::ipanel()->SetSize( root, viewWidth, viewHeight ); + } + + // The crosshair, etc. needs to get at the current setup stuff + AllowCurrentViewAccess( true ); + + // Draw the in-game stuff based on the actual viewport being used + render->VGui_Paint( PAINT_INGAMEPANELS ); + + // maybe paint the main menu and cursor too if we're in stereo hud mode + if( bPaintMainMenu ) + render->VGui_Paint( PAINT_UIPANELS | PAINT_CURSOR ); + + AllowCurrentViewAccess( false ); + + VGui_PostRender(); + + g_pClientMode->PostRenderVGui(); + pRenderContext = materials->GetRenderContext(); + if (pTexture) + { + pRenderContext->OverrideAlphaWriteEnable( false, true ); + } + pRenderContext->PopRenderTargetAndViewport(); + + if ( UseVR() ) + { + // figure out if we really want to draw the HUD based on freeze cam + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + bool bInFreezeCam = ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM ); + + // draw the HUD after the view model so its "I'm closer" depth queues work right. + if( !bInFreezeCam && g_ClientVirtualReality.ShouldRenderHUDInWorld() ) + { + // Now we've rendered the HUD to its texture, actually get it on the screen. + // Since we're drawing it as a 3D object, we need correctly set up frustum, etc. + int ClearFlags = 0; + SetupMain3DView( view, ClearFlags ); + + // TODO - a bit of a shonky test - basically trying to catch the main menu, the briefing screen, the loadout screen, etc. + bool bTranslucent = !g_pMatSystemSurface->IsCursorVisible(); + g_ClientVirtualReality.RenderHUDQuad( g_pClientMode->ShouldBlackoutAroundHUD(), bTranslucent ); + CleanupMain3DView( view ); + } + } + + pRenderContext->Flush(); + pRenderContext.SafeRelease(); + } + + CDebugViewRender::Draw2DDebuggingInfo( view ); + + Render2DEffectsPostHUD( view ); + + g_bRenderingView = false; + + // We can no longer use the 'current view' stuff set up in ViewDrawScene + s_bCanAccessCurrentView = false; + + if ( IsPC() ) + { + CDebugViewRender::GenerateOverdrawForTesting(); + } + + render->PopView( GetFrustum() ); + g_WorldListCache.Flush(); +} + +//----------------------------------------------------------------------------- +// Purpose: Renders extra 2D effects in derived classes while the 2D view is on the stack +//----------------------------------------------------------------------------- +void CViewRender::Render2DEffectsPreHUD( const CViewSetup &view ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Renders extra 2D effects in derived classes while the 2D view is on the stack +//----------------------------------------------------------------------------- +void CViewRender::Render2DEffectsPostHUD( const CViewSetup &view ) +{ +} + + + +//----------------------------------------------------------------------------- +// +// NOTE: Below here is all of the stuff that needs to be done for water rendering +// +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// Determines what kind of water we're going to use +//----------------------------------------------------------------------------- +void CViewRender::DetermineWaterRenderInfo( const VisibleFogVolumeInfo_t &fogVolumeInfo, WaterRenderInfo_t &info ) +{ + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + // By default, assume cheap water (even if there's no water in the scene!) + info.m_bCheapWater = true; + info.m_bRefract = false; + info.m_bReflect = false; + info.m_bReflectEntities = false; + info.m_bDrawWaterSurface = false; + info.m_bOpaqueWater = true; + + + + IMaterial *pWaterMaterial = fogVolumeInfo.m_pFogVolumeMaterial; + if (( fogVolumeInfo.m_nVisibleFogVolume == -1 ) || !pWaterMaterial ) + return; + + + // Use cheap water if mat_drawwater is set + info.m_bDrawWaterSurface = mat_drawwater.GetBool(); + if ( !info.m_bDrawWaterSurface ) + { + info.m_bOpaqueWater = false; + return; + } + +#ifdef _X360 + bool bForceExpensive = false; +#else + bool bForceExpensive = r_waterforceexpensive.GetBool(); +#endif + bool bForceReflectEntities = r_waterforcereflectentities.GetBool(); + +#ifdef PORTAL + switch( g_pPortalRender->ShouldForceCheaperWaterLevel() ) + { + case 0: //force cheap water + info.m_bCheapWater = true; + return; + + case 1: //downgrade level to "simple reflection" + bForceExpensive = false; + + case 2: //downgrade level to "reflect world" + bForceReflectEntities = false; + + default: + break; + }; +#endif + + // Determine if the water surface is opaque or not + info.m_bOpaqueWater = !pWaterMaterial->IsTranslucent(); + + // DX level 70 can't handle anything but cheap water + if (engine->GetDXSupportLevel() < 80) + return; + + bool bForceCheap = false; + + // The material can override the default settings though + IMaterialVar *pForceCheapVar = pWaterMaterial->FindVar( "$forcecheap", NULL, false ); + IMaterialVar *pForceExpensiveVar = pWaterMaterial->FindVar( "$forceexpensive", NULL, false ); + if ( pForceCheapVar && pForceCheapVar->IsDefined() ) + { + bForceCheap = ( pForceCheapVar->GetIntValueFast() != 0 ); + if ( bForceCheap ) + { + bForceExpensive = false; + } + } + if ( !bForceCheap && pForceExpensiveVar && pForceExpensiveVar->IsDefined() ) + { + bForceExpensive = bForceExpensive || ( pForceExpensiveVar->GetIntValueFast() != 0 ); + } + + bool bDebugCheapWater = r_debugcheapwater.GetBool(); + if( bDebugCheapWater ) + { + Msg( "Water material: %s dist to water: %f\nforcecheap: %s forceexpensive: %s\n", + pWaterMaterial->GetName(), fogVolumeInfo.m_flDistanceToWater, + bForceCheap ? "true" : "false", bForceExpensive ? "true" : "false" ); + } + + // Unless expensive water is active, reflections are off. + bool bLocalReflection; +#ifdef _X360 + if( !r_WaterDrawReflection.GetBool() ) +#else + if( !bForceExpensive || !r_WaterDrawReflection.GetBool() ) +#endif + { + bLocalReflection = false; + } + else + { + IMaterialVar *pReflectTextureVar = pWaterMaterial->FindVar( "$reflecttexture", NULL, false ); + bLocalReflection = pReflectTextureVar && (pReflectTextureVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE); + } + + // Brian says FIXME: I disabled cheap water LOD when local specular is specified. + // There are very few places that appear to actually + // take advantage of it (places where water is in the PVS, but outside of LOD range). + // It was 2 hours before code lock, and I had the choice of either doubling fill-rate everywhere + // by making cheap water lod actually work (the water LOD wasn't actually rendering!!!) + // or to just always render the reflection + refraction if there's a local specular specified. + // Note that water LOD *does* work with refract-only water + + // Gary says: I'm reverting this change so that water LOD works on dx9 for ep2. + + // Check if the water is out of the cheap water LOD range; if so, use cheap water +#ifdef _X360 + if ( !bForceExpensive && ( bForceCheap || ( fogVolumeInfo.m_flDistanceToWater >= m_flCheapWaterEndDistance ) ) ) + { + return; + } +#else + if ( ( (fogVolumeInfo.m_flDistanceToWater >= m_flCheapWaterEndDistance) && !bLocalReflection ) || bForceCheap ) + return; +#endif + // Get the material that is for the water surface that is visible and check to see + // what render targets need to be rendered, if any. + if ( !r_WaterDrawRefraction.GetBool() ) + { + info.m_bRefract = false; + } + else + { + IMaterialVar *pRefractTextureVar = pWaterMaterial->FindVar( "$refracttexture", NULL, false ); + info.m_bRefract = pRefractTextureVar && (pRefractTextureVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE); + + // Refractive water can be seen through + if ( info.m_bRefract ) + { + info.m_bOpaqueWater = false; + } + } + + info.m_bReflect = bLocalReflection; + if ( info.m_bReflect ) + { + if( bForceReflectEntities ) + { + info.m_bReflectEntities = true; + } + else + { + IMaterialVar *pReflectEntitiesVar = pWaterMaterial->FindVar( "$reflectentities", NULL, false ); + info.m_bReflectEntities = pReflectEntitiesVar && (pReflectEntitiesVar->GetIntValueFast() != 0); + } + } + + info.m_bCheapWater = !info.m_bReflect && !info.m_bRefract; + + if( bDebugCheapWater ) + { + Warning( "refract: %s reflect: %s\n", info.m_bRefract ? "true" : "false", info.m_bReflect ? "true" : "false" ); + } +} + +//----------------------------------------------------------------------------- +// Draws the world and all entities +//----------------------------------------------------------------------------- +void CViewRender::DrawWorldAndEntities( bool bDrawSkybox, const CViewSetup &viewIn, int nClearFlags, ViewCustomVisibility_t *pCustomVisibility ) +{ + MDLCACHE_CRITICAL_SECTION(); + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + VisibleFogVolumeInfo_t fogVolumeInfo; +#ifdef PORTAL //in portal, we can't use the fog volume for the camera since it's almost never in the same fog volume as what's in front of the portal + if( g_pPortalRender->GetViewRecursionLevel() == 0 ) + { + render->GetVisibleFogVolume( viewIn.origin, &fogVolumeInfo ); + } + else + { + render->GetVisibleFogVolume( g_pPortalRender->GetExitPortalFogOrigin(), &fogVolumeInfo ); + } +#else + render->GetVisibleFogVolume( viewIn.origin, &fogVolumeInfo ); +#endif + + WaterRenderInfo_t info; + DetermineWaterRenderInfo( fogVolumeInfo, info ); + + if ( info.m_bCheapWater ) + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "bCheapWater" ); + cplane_t glassReflectionPlane; + if ( IsReflectiveGlassInView( viewIn, glassReflectionPlane ) ) + { + CRefPtr pGlassReflectionView = new CReflectiveGlassView( this ); + pGlassReflectionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, bDrawSkybox, fogVolumeInfo, info, glassReflectionPlane ); + AddViewToScene( pGlassReflectionView ); + + CRefPtr pGlassRefractionView = new CRefractiveGlassView( this ); + pGlassRefractionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, bDrawSkybox, fogVolumeInfo, info, glassReflectionPlane ); + AddViewToScene( pGlassRefractionView ); + } + + CRefPtr pNoWaterView = new CSimpleWorldView( this ); + pNoWaterView->Setup( viewIn, nClearFlags, bDrawSkybox, fogVolumeInfo, info, pCustomVisibility ); + AddViewToScene( pNoWaterView ); + return; + } + + Assert( !pCustomVisibility ); + + // Blat out the visible fog leaf if we're not going to use it + if ( !r_ForceWaterLeaf.GetBool() ) + { + fogVolumeInfo.m_nVisibleFogVolumeLeaf = -1; + } + + // We can see water of some sort + if ( !fogVolumeInfo.m_bEyeInFogVolume ) + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CAboveWaterView" ); + CRefPtr pAboveWaterView = new CAboveWaterView( this ); + pAboveWaterView->Setup( viewIn, bDrawSkybox, fogVolumeInfo, info ); + AddViewToScene( pAboveWaterView ); + } + else + { + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CUnderWaterView" ); + CRefPtr pUnderWaterView = new CUnderWaterView( this ); + pUnderWaterView->Setup( viewIn, bDrawSkybox, fogVolumeInfo, info ); + AddViewToScene( pUnderWaterView ); + } +} + + +//----------------------------------------------------------------------------- +// Pushes a water render target +//----------------------------------------------------------------------------- +static Vector SavedLinearLightMapScale(-1,-1,-1); // x<0 = no saved scale + +static void SetLightmapScaleForWater(void) +{ + if (g_pMaterialSystemHardwareConfig->GetHDRType()==HDR_TYPE_INTEGER) + { + CMatRenderContextPtr pRenderContext( materials ); + SavedLinearLightMapScale=pRenderContext->GetToneMappingScaleLinear(); + Vector t25=SavedLinearLightMapScale; + t25*=0.25; + pRenderContext->SetToneMappingScaleLinear(t25); + } +} + +//----------------------------------------------------------------------------- +// Returns true if the view plane intersects the water +//----------------------------------------------------------------------------- +bool DoesViewPlaneIntersectWater( float waterZ, int leafWaterDataID ) +{ + if ( leafWaterDataID == -1 ) + return false; + +#ifdef PORTAL //when rendering portal views point/plane intersections just don't cut it. + if( g_pPortalRender->GetViewRecursionLevel() != 0 ) + return g_pPortalRender->DoesExitPortalViewIntersectWaterPlane( waterZ, leafWaterDataID ); +#endif + + CMatRenderContextPtr pRenderContext( materials ); + + VMatrix viewMatrix, projectionMatrix, viewProjectionMatrix, inverseViewProjectionMatrix; + pRenderContext->GetMatrix( MATERIAL_VIEW, &viewMatrix ); + pRenderContext->GetMatrix( MATERIAL_PROJECTION, &projectionMatrix ); + MatrixMultiply( projectionMatrix, viewMatrix, viewProjectionMatrix ); + MatrixInverseGeneral( viewProjectionMatrix, inverseViewProjectionMatrix ); + + Vector mins, maxs; + ClearBounds( mins, maxs ); + Vector testPoint[4]; + testPoint[0].Init( -1.0f, -1.0f, 0.0f ); + testPoint[1].Init( -1.0f, 1.0f, 0.0f ); + testPoint[2].Init( 1.0f, -1.0f, 0.0f ); + testPoint[3].Init( 1.0f, 1.0f, 0.0f ); + int i; + bool bAbove = false; + bool bBelow = false; + float fudge = 7.0f; + for( i = 0; i < 4; i++ ) + { + Vector worldPos; + Vector3DMultiplyPositionProjective( inverseViewProjectionMatrix, testPoint[i], worldPos ); + AddPointToBounds( worldPos, mins, maxs ); +// Warning( "viewplanez: %f waterZ: %f\n", worldPos.z, waterZ ); + if( worldPos.z + fudge > waterZ ) + { + bAbove = true; + } + if( worldPos.z - fudge < waterZ ) + { + bBelow = true; + } + } + + // early out if the near plane doesn't cross the z plane of the water. + if( !( bAbove && bBelow ) ) + return false; + + Vector vecFudge( fudge, fudge, fudge ); + mins -= vecFudge; + maxs += vecFudge; + + // the near plane does cross the z value for the visible water volume. Call into + // the engine to find out if the near plane intersects the water volume. + return render->DoesBoxIntersectWaterVolume( mins, maxs, leafWaterDataID ); +} + +#ifdef PORTAL + +//----------------------------------------------------------------------------- +// Purpose: Draw the scene during another draw scene call. We must draw our portals +// after opaques but before translucents, so this ViewDrawScene resets the view +// and doesn't flag the rendering as ended when it ends. +// Input : bDrawSkybox - do we draw the skybox +// &view - the camera view to render from +// nClearFlags - how to clear the buffer +//----------------------------------------------------------------------------- +void CViewRender::ViewDrawScene_PortalStencil( const CViewSetup &viewIn, ViewCustomVisibility_t *pCustomVisibility ) +{ + VPROF( "CViewRender::ViewDrawScene_PortalStencil" ); + + CViewSetup view( viewIn ); + + // Record old view stats + Vector vecOldOrigin = CurrentViewOrigin(); + QAngle vecOldAngles = CurrentViewAngles(); + + int iCurrentViewID = g_CurrentViewID; + int iRecursionLevel = g_pPortalRender->GetViewRecursionLevel(); + Assert( iRecursionLevel > 0 ); + + //get references to reflection textures + CTextureReference pPrimaryWaterReflectionTexture; + pPrimaryWaterReflectionTexture.Init( GetWaterReflectionTexture() ); + CTextureReference pReplacementWaterReflectionTexture; + pReplacementWaterReflectionTexture.Init( portalrendertargets->GetWaterReflectionTextureForStencilDepth( iRecursionLevel ) ); + + //get references to refraction textures + CTextureReference pPrimaryWaterRefractionTexture; + pPrimaryWaterRefractionTexture.Init( GetWaterRefractionTexture() ); + CTextureReference pReplacementWaterRefractionTexture; + pReplacementWaterRefractionTexture.Init( portalrendertargets->GetWaterRefractionTextureForStencilDepth( iRecursionLevel ) ); + + + //swap texture contents for the primary render targets with those we set aside for this recursion level + if( pReplacementWaterReflectionTexture != NULL ) + pPrimaryWaterReflectionTexture->SwapContents( pReplacementWaterReflectionTexture ); + + if( pReplacementWaterRefractionTexture != NULL ) + pPrimaryWaterRefractionTexture->SwapContents( pReplacementWaterRefractionTexture ); + + bool bDrew3dSkybox = false; + SkyboxVisibility_t nSkyboxVisible = SKYBOX_NOT_VISIBLE; + int iClearFlags = 0; + + Draw3dSkyboxworld_Portal( view, iClearFlags, bDrew3dSkybox, nSkyboxVisible ); + + bool drawSkybox = r_skybox.GetBool(); + if ( bDrew3dSkybox || ( nSkyboxVisible == SKYBOX_NOT_VISIBLE ) ) + { + drawSkybox = false; + } + + //generate unique view ID's for each stencil view + view_id_t iNewViewID = (view_id_t)g_pPortalRender->GetCurrentViewId(); + SetupCurrentView( view.origin, view.angles, (view_id_t)iNewViewID ); + + // update vis data + unsigned int visFlags; + SetupVis( view, visFlags, pCustomVisibility ); + + VisibleFogVolumeInfo_t fogInfo; + if( g_pPortalRender->GetViewRecursionLevel() == 0 ) + { + render->GetVisibleFogVolume( view.origin, &fogInfo ); + } + else + { + render->GetVisibleFogVolume( g_pPortalRender->GetExitPortalFogOrigin(), &fogInfo ); + } + + WaterRenderInfo_t waterInfo; + DetermineWaterRenderInfo( fogInfo, waterInfo ); + + if ( waterInfo.m_bCheapWater ) + { + cplane_t glassReflectionPlane; + if ( IsReflectiveGlassInView( viewIn, glassReflectionPlane ) ) + { + CRefPtr pGlassReflectionView = new CReflectiveGlassView( this ); + pGlassReflectionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, glassReflectionPlane ); + AddViewToScene( pGlassReflectionView ); + + CRefPtr pGlassRefractionView = new CRefractiveGlassView( this ); + pGlassRefractionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, glassReflectionPlane ); + AddViewToScene( pGlassRefractionView ); + } + + CSimpleWorldView *pClientView = new CSimpleWorldView( this ); + pClientView->Setup( view, VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, pCustomVisibility ); + AddViewToScene( pClientView ); + SafeRelease( pClientView ); + } + else + { + // We can see water of some sort + if ( !fogInfo.m_bEyeInFogVolume ) + { + CRefPtr pAboveWaterView = new CAboveWaterView( this ); + pAboveWaterView->Setup( viewIn, drawSkybox, fogInfo, waterInfo ); + AddViewToScene( pAboveWaterView ); + } + else + { + CRefPtr pUnderWaterView = new CUnderWaterView( this ); + pUnderWaterView->Setup( viewIn, drawSkybox, fogInfo, waterInfo ); + AddViewToScene( pUnderWaterView ); + } + } + + // Disable fog for the rest of the stuff + DisableFog(); + + CGlowOverlay::DrawOverlays( view.m_bCacheFullSceneState ); + + // Draw rain.. + DrawPrecipitation(); + + //prerender version only + // issue the pixel visibility tests + PixelVisibility_EndCurrentView(); + + // Make sure sound doesn't stutter + engine->Sound_ExtraUpdate(); + + // Debugging info goes over the top + CDebugViewRender::Draw3DDebuggingInfo( view ); + + // Return to the previous view + SetupCurrentView( vecOldOrigin, vecOldAngles, (view_id_t)iCurrentViewID ); + g_CurrentViewID = iCurrentViewID; //just in case the cast to view_id_t screwed up the id # + + + //swap back the water render targets + if( pReplacementWaterReflectionTexture != NULL ) + pPrimaryWaterReflectionTexture->SwapContents( pReplacementWaterReflectionTexture ); + + if( pReplacementWaterRefractionTexture != NULL ) + pPrimaryWaterRefractionTexture->SwapContents( pReplacementWaterRefractionTexture ); +} + +void CViewRender::Draw3dSkyboxworld_Portal( const CViewSetup &view, int &nClearFlags, bool &bDrew3dSkybox, SkyboxVisibility_t &nSkyboxVisible, ITexture *pRenderTarget ) +{ + CRefPtr pSkyView = new CPortalSkyboxView( this ); + if ( ( bDrew3dSkybox = pSkyView->Setup( view, &nClearFlags, &nSkyboxVisible, pRenderTarget ) ) == true ) + { + AddViewToScene( pSkyView ); + } +} + +#endif //PORTAL + +//----------------------------------------------------------------------------- +// Methods related to controlling the cheap water distance +//----------------------------------------------------------------------------- +void CViewRender::SetCheapWaterStartDistance( float flCheapWaterStartDistance ) +{ + m_flCheapWaterStartDistance = flCheapWaterStartDistance; +} + +void CViewRender::SetCheapWaterEndDistance( float flCheapWaterEndDistance ) +{ + m_flCheapWaterEndDistance = flCheapWaterEndDistance; +} + +void CViewRender::GetWaterLODParams( float &flCheapWaterStartDistance, float &flCheapWaterEndDistance ) +{ + flCheapWaterStartDistance = m_flCheapWaterStartDistance; + flCheapWaterEndDistance = m_flCheapWaterEndDistance; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &view - +// &introData - +//----------------------------------------------------------------------------- +void CViewRender::ViewDrawScene_Intro( const CViewSetup &view, int nClearFlags, const IntroData_t &introData ) +{ + VPROF( "CViewRender::ViewDrawScene" ); + + CMatRenderContextPtr pRenderContext( materials ); + + // this allows the refract texture to be updated once per *scene* on 360 + // (e.g. once for a monitor scene and once for the main scene) + g_viewscene_refractUpdateFrame = gpGlobals->framecount - 1; + + // ----------------------------------------------------------------------- + // Set the clear color to black since we are going to be adding up things + // in the frame buffer. + // ----------------------------------------------------------------------- + // Clear alpha to 255 so that masking with the vortigaunts (0) works properly. + pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); + + // ----------------------------------------------------------------------- + // Draw the primary scene and copy it to the first framebuffer texture + // ----------------------------------------------------------------------- + unsigned int visFlags; + + // NOTE: We only increment this once since time doesn't move forward. + ParticleMgr()->IncrementFrameCode(); + + if( introData.m_bDrawPrimary ) + { + CViewSetup playerView( view ); + playerView.origin = introData.m_vecCameraView; + playerView.angles = introData.m_vecCameraViewAngles; + if ( introData.m_playerViewFOV ) + { + playerView.fov = ScaleFOVByWidthRatio( introData.m_playerViewFOV, engine->GetScreenAspectRatio() / ( 4.0f / 3.0f ) ); + } + + g_pClientShadowMgr->PreRender(); + + // Shadowed flashlights supported on ps_2_b and up... + if ( r_flashlightdepthtexture.GetBool() ) + { + g_pClientShadowMgr->ComputeShadowDepthTextures( playerView ); + } + + SetupCurrentView( playerView.origin, playerView.angles, VIEW_INTRO_PLAYER ); + + // Invoke pre-render methods + IGameSystem::PreRenderAllSystems(); + + // Start view, clear frame/z buffer if necessary + SetupVis( playerView, visFlags ); + + render->Push3DView( playerView, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH, NULL, GetFrustum() ); + DrawWorldAndEntities( true /* drawSkybox */, playerView, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH ); + render->PopView( GetFrustum() ); + + // Free shadow depth textures for use in future view + if ( r_flashlightdepthtexture.GetBool() ) + { + g_pClientShadowMgr->UnlockAllShadowDepthTextures(); + } + } + else + { + pRenderContext->ClearBuffers( true, true ); + } + Rect_t actualRect; + UpdateScreenEffectTexture( 0, view.x, view.y, view.width, view.height, false, &actualRect ); + + g_pClientShadowMgr->PreRender(); + + // Shadowed flashlights supported on ps_2_b and up... + if ( r_flashlightdepthtexture.GetBool() ) + { + g_pClientShadowMgr->ComputeShadowDepthTextures( view ); + } + + // ----------------------------------------------------------------------- + // Draw the secondary scene and copy it to the second framebuffer texture + // ----------------------------------------------------------------------- + SetupCurrentView( view.origin, view.angles, VIEW_INTRO_CAMERA ); + + // Invoke pre-render methods + IGameSystem::PreRenderAllSystems(); + + // Start view, clear frame/z buffer if necessary + SetupVis( view, visFlags ); + + // Clear alpha to 255 so that masking with the vortigaunts (0) works properly. + pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); + + DrawWorldAndEntities( true /* drawSkybox */, view, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH ); + + UpdateScreenEffectTexture( 1, view.x, view.y, view.width, view.height ); + + // ----------------------------------------------------------------------- + // Draw quads on the screen for each screenspace pass. + // ----------------------------------------------------------------------- + // Find the material that we use to render the overlays + IMaterial *pOverlayMaterial = materials->FindMaterial( "scripted/intro_screenspaceeffect", TEXTURE_GROUP_OTHER ); + IMaterialVar *pModeVar = pOverlayMaterial->FindVar( "$mode", NULL ); + IMaterialVar *pAlphaVar = pOverlayMaterial->FindVar( "$alpha", NULL ); + + pRenderContext->ClearBuffers( true, true ); + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + + int passID; + for( passID = 0; passID < introData.m_Passes.Count(); passID++ ) + { + const IntroDataBlendPass_t& pass = introData.m_Passes[passID]; + if ( pass.m_Alpha == 0 ) + continue; + + // Pick one of the blend modes for the material. + if ( pass.m_BlendMode >= 0 && pass.m_BlendMode <= 9 ) + { + pModeVar->SetIntValue( pass.m_BlendMode ); + } + else + { + Assert(0); + } + // Set the alpha value for the material. + pAlphaVar->SetFloatValue( pass.m_Alpha ); + + // Draw a quad for this pass. + ITexture *pTexture = GetFullFrameFrameBufferTexture( 0 ); + pRenderContext->DrawScreenSpaceRectangle( pOverlayMaterial, 0, 0, view.width, view.height, + actualRect.x, actualRect.y, actualRect.x+actualRect.width-1, actualRect.y+actualRect.height-1, + pTexture->GetActualWidth(), pTexture->GetActualHeight() ); + } + + pRenderContext->MatrixMode( MATERIAL_VIEW ); + pRenderContext->PopMatrix(); + + pRenderContext->MatrixMode( MATERIAL_PROJECTION ); + pRenderContext->PopMatrix(); + + // Draw the starfield + // FIXME + // blur? + + // Disable fog for the rest of the stuff + DisableFog(); + + // Here are the overlays... + CGlowOverlay::DrawOverlays( view.m_bCacheFullSceneState ); + + // issue the pixel visibility tests + PixelVisibility_EndCurrentView(); + + // And here are the screen-space effects + PerformScreenSpaceEffects( 0, 0, view.width, view.height ); + + // Make sure sound doesn't stutter + engine->Sound_ExtraUpdate(); + + // Debugging info goes over the top + CDebugViewRender::Draw3DDebuggingInfo( view ); + + // Let the particle manager simulate things that haven't been simulated. + ParticleMgr()->PostRender(); + + FinishCurrentView(); + + // Free shadow depth textures for use in future view + if ( r_flashlightdepthtexture.GetBool() ) + { + g_pClientShadowMgr->UnlockAllShadowDepthTextures(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Sets up scene and renders camera view +// Input : cameraNum - +// &cameraView +// *localPlayer - +// x - +// y - +// width - +// height - +// highend - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CViewRender::DrawOneMonitor( ITexture *pRenderTarget, int cameraNum, C_PointCamera *pCameraEnt, + const CViewSetup &cameraView, C_BasePlayer *localPlayer, int x, int y, int width, int height ) +{ +#ifdef USE_MONITORS + VPROF_INCREMENT_COUNTER( "cameras rendered", 1 ); + // Setup fog state for the camera. + fogparams_t oldFogParams; + float flOldZFar = 0.0f; + + bool fogEnabled = pCameraEnt->IsFogEnabled(); + + CViewSetup monitorView = cameraView; + + fogparams_t *pFogParams = NULL; + + if ( fogEnabled ) + { + if ( !localPlayer ) + return false; + + pFogParams = localPlayer->GetFogParams(); + + // Save old fog data. + oldFogParams = *pFogParams; + flOldZFar = cameraView.zFar; + + pFogParams->enable = true; + pFogParams->start = pCameraEnt->GetFogStart(); + pFogParams->end = pCameraEnt->GetFogEnd(); + pFogParams->farz = pCameraEnt->GetFogEnd(); + pFogParams->maxdensity = pCameraEnt->GetFogMaxDensity(); + + unsigned char r, g, b; + pCameraEnt->GetFogColor( r, g, b ); + pFogParams->colorPrimary.SetR( r ); + pFogParams->colorPrimary.SetG( g ); + pFogParams->colorPrimary.SetB( b ); + + monitorView.zFar = pCameraEnt->GetFogEnd(); + } + + monitorView.width = width; + monitorView.height = height; + monitorView.x = x; + monitorView.y = y; + monitorView.origin = pCameraEnt->GetAbsOrigin(); + monitorView.angles = pCameraEnt->GetAbsAngles(); + monitorView.fov = pCameraEnt->GetFOV(); + monitorView.m_bOrtho = false; + monitorView.m_flAspectRatio = pCameraEnt->UseScreenAspectRatio() ? 0.0f : 1.0f; + monitorView.m_bViewToProjectionOverride = false; + + // @MULTICORE (toml 8/11/2006): this should be a renderer.... + Frustum frustum; + render->Push3DView( monitorView, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, pRenderTarget, (VPlane *)frustum ); + ViewDrawScene( false, SKYBOX_2DSKYBOX_VISIBLE, monitorView, 0, VIEW_MONITOR ); + render->PopView( frustum ); + + // Reset the world fog parameters. + if ( fogEnabled ) + { + if ( pFogParams ) + { + *pFogParams = oldFogParams; + } + monitorView.zFar = flOldZFar; + } +#endif // USE_MONITORS + return true; +} + +void CViewRender::DrawMonitors( const CViewSetup &cameraView ) +{ +#ifdef PORTAL + g_pPortalRender->DrawPortalsToTextures( this, cameraView ); +#endif + +#ifdef USE_MONITORS + + // Early out if no cameras + C_PointCamera *pCameraEnt = GetPointCameraList(); + if ( !pCameraEnt ) + return; + + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + +#ifdef _DEBUG + g_bRenderingCameraView = true; +#endif + + // FIXME: this should check for the ability to do a render target maybe instead. + // FIXME: shouldn't have to truck through all of the visible entities for this!!!! + ITexture *pCameraTarget = GetCameraTexture(); + int width = pCameraTarget->GetActualWidth(); + int height = pCameraTarget->GetActualHeight(); + + C_BasePlayer *player = C_BasePlayer::GetLocalPlayer(); + + int cameraNum; + for ( cameraNum = 0; pCameraEnt != NULL; pCameraEnt = pCameraEnt->m_pNext ) + { + if ( !pCameraEnt->IsActive() || pCameraEnt->IsDormant() ) + continue; + + if ( !DrawOneMonitor( pCameraTarget, cameraNum, pCameraEnt, cameraView, player, 0, 0, width, height ) ) + continue; + + ++cameraNum; + } + + if ( IsX360() && cameraNum > 0 ) + { + // resolve render target to system memory texture + // resolving *after* all monitors drawn to ensure a single blit using fastest resolve path + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->PushRenderTargetAndViewport( pCameraTarget ); + pRenderContext->CopyRenderTargetToTextureEx( pCameraTarget, 0, NULL, NULL ); + pRenderContext->PopRenderTargetAndViewport(); + } + +#ifdef _DEBUG + g_bRenderingCameraView = false; +#endif + +#endif // USE_MONITORS +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +ClientWorldListInfo_t *ClientWorldListInfo_t::AllocPooled( const ClientWorldListInfo_t &exemplar ) +{ + size_t nBytes = AlignValue( ( exemplar.m_LeafCount * ((sizeof(LeafIndex_t) * 2) + sizeof(LeafFogVolume_t)) ), 4096 ); + + ClientWorldListInfo_t *pResult = gm_Pool.GetObject(); + + byte *pMemory = (byte *)pResult->m_pLeafList; + + if ( pMemory ) + { + // Previously allocated, add a reference. Otherwise comes out of GetObject as a new object with a refcount of 1 + pResult->AddRef(); + } + + if ( !pMemory || _msize( pMemory ) < nBytes ) + { + pMemory = (byte *)realloc( pMemory, nBytes ); + } + + pResult->m_pLeafList = (LeafIndex_t*)pMemory; + pResult->m_pLeafFogVolume = (LeafFogVolume_t*)( pMemory + exemplar.m_LeafCount * sizeof(LeafIndex_t) ); + pResult->m_pActualLeafIndex = (LeafIndex_t*)( (byte *)( pResult->m_pLeafFogVolume ) + exemplar.m_LeafCount * sizeof(LeafFogVolume_t) ); + + pResult->m_bPooledAlloc = true; + + return pResult; +} + +bool ClientWorldListInfo_t::OnFinalRelease() +{ + if ( m_bPooledAlloc ) + { + Assert( m_pLeafList ); + gm_Pool.PutObject( this ); + return false; + } + return true; +} + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CBase3dView::CBase3dView( CViewRender *pMainView ) : +m_pMainView( pMainView ), +m_Frustum( pMainView->m_Frustum ) +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pEnt - +// Output : int +//----------------------------------------------------------------------------- +VPlane* CBase3dView::GetFrustum() +{ + // The frustum is only valid while in a RenderView call. + // @MULTICORE (toml 8/11/2006): reimplement this when ready -- Assert(g_bRenderingView || g_bRenderingCameraView || g_bRenderingScreenshot); + return m_Frustum; +} + + +CObjectPool ClientWorldListInfo_t::gm_Pool; + + +//----------------------------------------------------------------------------- +// Base class for 3d views +//----------------------------------------------------------------------------- +CRendering3dView::CRendering3dView(CViewRender *pMainView) : + CBase3dView( pMainView ), + m_pWorldRenderList( NULL ), + m_pRenderablesList( NULL ), + m_pWorldListInfo( NULL ), + m_pCustomVisibility( NULL ), + m_DrawFlags( 0 ), + m_ClearFlags( 0 ) +{ +} + + +//----------------------------------------------------------------------------- +// Sort entities in a back-to-front ordering +//----------------------------------------------------------------------------- +void CRendering3dView::Setup( const CViewSetup &setup ) +{ + // @MULTICORE (toml 8/15/2006): don't reset if parameters don't require it. For now, just reset + memcpy( static_cast(this), &setup, sizeof( setup ) ); + ReleaseLists(); + + m_pRenderablesList = new CClientRenderablesList; + m_pCustomVisibility = NULL; +} + + +//----------------------------------------------------------------------------- +// Sort entities in a back-to-front ordering +//----------------------------------------------------------------------------- +void CRendering3dView::ReleaseLists() +{ + SafeRelease( m_pWorldRenderList ); + SafeRelease( m_pRenderablesList ); + SafeRelease( m_pWorldListInfo ); + m_pCustomVisibility = NULL; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CRendering3dView::SetupRenderablesList( int viewID ) +{ + VPROF( "CViewRender::SetupRenderablesList" ); + + // Clear the list. + int i; + for( i=0; i < RENDER_GROUP_COUNT; i++ ) + { + m_pRenderablesList->m_RenderGroupCounts[i] = 0; + } + + // Now collate the entities in the leaves. + if( m_pMainView->ShouldDrawEntities() ) + { + // Precache information used commonly in CollateRenderables + SetupRenderInfo_t setupInfo; + setupInfo.m_pWorldListInfo = m_pWorldListInfo; + setupInfo.m_nRenderFrame = m_pMainView->BuildRenderablesListsNumber(); // only one incremented? + setupInfo.m_nDetailBuildFrame = m_pMainView->BuildWorldListsNumber(); // + setupInfo.m_pRenderList = m_pRenderablesList; + setupInfo.m_bDrawDetailObjects = g_pClientMode->ShouldDrawDetailObjects() && r_DrawDetailProps.GetInt(); + setupInfo.m_bDrawTranslucentObjects = (viewID != VIEW_SHADOW_DEPTH_TEXTURE); + + setupInfo.m_vecRenderOrigin = origin; + setupInfo.m_vecRenderForward = CurrentViewForward(); + + float fMaxDist = cl_maxrenderable_dist.GetFloat(); + + // Shadowing light typically has a smaller farz than cl_maxrenderable_dist + setupInfo.m_flRenderDistSq = (viewID == VIEW_SHADOW_DEPTH_TEXTURE) ? MIN(zFar, fMaxDist) : fMaxDist; + setupInfo.m_flRenderDistSq *= setupInfo.m_flRenderDistSq; + + ClientLeafSystem()->BuildRenderablesList( setupInfo ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Builds lists of things to render in the world, called once per view +//----------------------------------------------------------------------------- +void CRendering3dView::UpdateRenderablesOpacity() +{ + // Compute the prop opacity based on the view position and fov zoom scale + float flFactor = 1.0f; + C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer(); + if ( pLocal ) + { + flFactor = pLocal->GetFOVDistanceAdjustFactor(); + } + + if ( cl_leveloverview.GetFloat() > 0 ) + { + // disable prop fading + flFactor = -1; + } + + // When zoomed in, tweak the opacity to stay visible from further away + staticpropmgr->ComputePropOpacity( origin, flFactor ); + + // Build a list of detail props to render + DetailObjectSystem()->BuildDetailObjectRenderLists( origin ); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +// Kinda awkward...three optional parameters at the end... +void CRendering3dView::BuildWorldRenderLists( bool bDrawEntities, int iForceViewLeaf /* = -1 */, + bool bUseCacheIfEnabled /* = true */, bool bShadowDepth /* = false */, float *pReflectionWaterHeight /*= NULL*/ ) +{ + VPROF_BUDGET( "BuildWorldRenderLists", VPROF_BUDGETGROUP_WORLD_RENDERING ); + + // @MULTICORE (toml 8/18/2006): to address.... + extern void UpdateClientRenderableInPVSStatus(); + UpdateClientRenderableInPVSStatus(); + + Assert( !m_pWorldRenderList && !m_pWorldListInfo); + + m_pMainView->IncWorldListsNumber(); + // Override vis data if specified this render, otherwise use default behavior with NULL + VisOverrideData_t* pVisData = ( m_pCustomVisibility && m_pCustomVisibility->m_VisData.m_fDistToAreaPortalTolerance != FLT_MAX ) ? &m_pCustomVisibility->m_VisData : NULL; + bool bUseCache = ( bUseCacheIfEnabled && r_worldlistcache.GetBool() ); + if ( !bUseCache || pVisData || !g_WorldListCache.Find( *this, &m_pWorldRenderList, &m_pWorldListInfo ) ) + { + // @MULTICORE (toml 8/18/2006): when make parallel, will have to change caching to be atomic, where follow ons receive a pointer to a list that is not yet built + m_pWorldRenderList = render->CreateWorldList(); + m_pWorldListInfo = new ClientWorldListInfo_t; + + render->BuildWorldLists( m_pWorldRenderList, m_pWorldListInfo, + ( m_pCustomVisibility ) ? m_pCustomVisibility->m_iForceViewLeaf : iForceViewLeaf, + pVisData, bShadowDepth, pReflectionWaterHeight ); + + if ( bUseCache && !pVisData ) + { + g_WorldListCache.Add( *this, m_pWorldRenderList, m_pWorldListInfo ); + } + } + + if ( bDrawEntities ) + { + UpdateRenderablesOpacity(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Computes the actual world list info based on the render flags +//----------------------------------------------------------------------------- +void CRendering3dView::PruneWorldListInfo() +{ + // Drawing everything? Just return the world list info as-is + int nWaterDrawFlags = m_DrawFlags & (DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER); + if ( nWaterDrawFlags == (DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER) ) + { + return; + } + + ClientWorldListInfo_t *pNewInfo; + // Only allocate memory if actually will draw something + if ( m_pWorldListInfo->m_LeafCount > 0 && nWaterDrawFlags ) + { + pNewInfo = ClientWorldListInfo_t::AllocPooled( *m_pWorldListInfo ); + } + else + { + pNewInfo = new ClientWorldListInfo_t; + } + + pNewInfo->m_ViewFogVolume = m_pWorldListInfo->m_ViewFogVolume; + pNewInfo->m_LeafCount = 0; + + // Not drawing anything? Then don't bother with renderable lists + if ( nWaterDrawFlags != 0 ) + { + // Create a sub-list based on the actual leaves being rendered + bool bRenderingUnderwater = (nWaterDrawFlags & DF_RENDER_UNDERWATER) != 0; + for ( int i = 0; i < m_pWorldListInfo->m_LeafCount; ++i ) + { + bool bLeafIsUnderwater = ( m_pWorldListInfo->m_pLeafFogVolume[i] != -1 ); + if ( bRenderingUnderwater == bLeafIsUnderwater ) + { + pNewInfo->m_pLeafList[ pNewInfo->m_LeafCount ] = m_pWorldListInfo->m_pLeafList[ i ]; + pNewInfo->m_pLeafFogVolume[ pNewInfo->m_LeafCount ] = m_pWorldListInfo->m_pLeafFogVolume[ i ]; + pNewInfo->m_pActualLeafIndex[ pNewInfo->m_LeafCount ] = i; + ++pNewInfo->m_LeafCount; + } + } + } + + m_pWorldListInfo->Release(); + m_pWorldListInfo = pNewInfo; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +static inline void UpdateBrushModelLightmap( IClientRenderable *pEnt ) +{ + model_t *pModel = ( model_t * )pEnt->GetModel(); + render->UpdateBrushModelLightmap( pModel, pEnt ); +} + + +void CRendering3dView::BuildRenderableRenderLists( int viewID ) +{ + MDLCACHE_CRITICAL_SECTION(); + + if ( viewID != VIEW_SHADOW_DEPTH_TEXTURE ) + { + render->BeginUpdateLightmaps(); + } + + m_pMainView->IncRenderablesListsNumber(); + + ClientWorldListInfo_t& info = *m_pWorldListInfo; + + // For better sorting, find out the leaf *nearest* to the camera + // and render translucent objects as if they are in that leaf. + if( m_pMainView->ShouldDrawEntities() && ( viewID != VIEW_SHADOW_DEPTH_TEXTURE ) ) + { + ClientLeafSystem()->ComputeTranslucentRenderLeaf( + info.m_LeafCount, info.m_pLeafList, info.m_pLeafFogVolume, m_pMainView->BuildRenderablesListsNumber(), viewID ); + } + + SetupRenderablesList( viewID ); + + if ( viewID == VIEW_MAIN ) + { + StudioStats_FindClosestEntity( m_pRenderablesList ); + } + + if ( viewID != VIEW_SHADOW_DEPTH_TEXTURE ) + { + // update lightmap on brush models if necessary + CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_OPAQUE_BRUSH]; + int nOpaque = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE_BRUSH]; + int i; + for( i=0; i < nOpaque; ++i ) + { + Assert(pEntities[i].m_TwoPass==0); + UpdateBrushModelLightmap( pEntities[i].m_pRenderable ); + } + + // update lightmap on brush models if necessary + pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; + int nTranslucent = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY]; + for( i=0; i < nTranslucent; ++i ) + { + const model_t *pModel = pEntities[i].m_pRenderable->GetModel(); + if( pModel ) + { + int nModelType = modelinfo->GetModelType( pModel ); + if( nModelType == mod_brush ) + { + UpdateBrushModelLightmap( pEntities[i].m_pRenderable ); + } + } + } + + render->EndUpdateLightmaps(); + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CRendering3dView::DrawWorld( float waterZAdjust ) +{ + VPROF_INCREMENT_COUNTER( "RenderWorld", 1 ); + VPROF_BUDGET( "DrawWorld", VPROF_BUDGETGROUP_WORLD_RENDERING ); + if( !r_drawopaqueworld.GetBool() ) + { + return; + } + + unsigned long engineFlags = BuildEngineDrawWorldListFlags( m_DrawFlags ); + + render->DrawWorldLists( m_pWorldRenderList, engineFlags, waterZAdjust ); +} + + +CMaterialReference g_material_WriteZ; //init'ed on by CViewRender::Init() + +//----------------------------------------------------------------------------- +// Fakes per-entity clip planes on cards that don't support user clip planes. +// Achieves the effect by drawing an invisible box that writes to the depth buffer +// around the clipped area. It's not perfect, but better than nothing. +//----------------------------------------------------------------------------- +static void DrawClippedDepthBox( IClientRenderable *pEnt, float *pClipPlane ) +{ +//#define DEBUG_DRAWCLIPPEDDEPTHBOX //uncomment to draw the depth box as a colorful box + + static const int iQuads[6][5] = { { 0, 4, 6, 2, 0 }, //always an extra copy of first index at end to make some algorithms simpler + { 3, 7, 5, 1, 3 }, + { 1, 5, 4, 0, 1 }, + { 2, 6, 7, 3, 2 }, + { 0, 2, 3, 1, 0 }, + { 5, 7, 6, 4, 5 } }; + + static const int iLines[12][2] = { { 0, 1 }, + { 0, 2 }, + { 0, 4 }, + { 1, 3 }, + { 1, 5 }, + { 2, 3 }, + { 2, 6 }, + { 3, 7 }, + { 4, 6 }, + { 4, 5 }, + { 5, 7 }, + { 6, 7 } }; + + +#ifdef DEBUG_DRAWCLIPPEDDEPTHBOX + static const float fColors[6][3] = { { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 1.0f }, + { 0.0f, 1.0f, 0.0f }, + { 1.0f, 0.0f, 1.0f }, + { 0.0f, 0.0f, 1.0f }, + { 1.0f, 1.0f, 0.0f } }; +#endif + + + + + Vector vNormal = *(Vector *)pClipPlane; + float fPlaneDist = pClipPlane[3]; + + Vector vMins, vMaxs; + pEnt->GetRenderBounds( vMins, vMaxs ); + + Vector vOrigin = pEnt->GetRenderOrigin(); + QAngle qAngles = pEnt->GetRenderAngles(); + + Vector vForward, vUp, vRight; + AngleVectors( qAngles, &vForward, &vRight, &vUp ); + + Vector vPoints[8]; + vPoints[0] = vOrigin + (vForward * vMins.x) + (vRight * vMins.y) + (vUp * vMins.z); + vPoints[1] = vOrigin + (vForward * vMaxs.x) + (vRight * vMins.y) + (vUp * vMins.z); + vPoints[2] = vOrigin + (vForward * vMins.x) + (vRight * vMaxs.y) + (vUp * vMins.z); + vPoints[3] = vOrigin + (vForward * vMaxs.x) + (vRight * vMaxs.y) + (vUp * vMins.z); + vPoints[4] = vOrigin + (vForward * vMins.x) + (vRight * vMins.y) + (vUp * vMaxs.z); + vPoints[5] = vOrigin + (vForward * vMaxs.x) + (vRight * vMins.y) + (vUp * vMaxs.z); + vPoints[6] = vOrigin + (vForward * vMins.x) + (vRight * vMaxs.y) + (vUp * vMaxs.z); + vPoints[7] = vOrigin + (vForward * vMaxs.x) + (vRight * vMaxs.y) + (vUp * vMaxs.z); + + int iClipped[8]; + float fDists[8]; + for( int i = 0; i != 8; ++i ) + { + fDists[i] = vPoints[i].Dot( vNormal ) - fPlaneDist; + iClipped[i] = (fDists[i] > 0.0f) ? 1 : 0; + } + + Vector vSplitPoints[8][8]; //obviously there are only 12 lines, not 64 lines or 64 split points, but the indexing is way easier like this + int iLineStates[8][8]; //0 = unclipped, 2 = wholly clipped, 3 = first point clipped, 4 = second point clipped + + //categorize lines and generate split points where needed + for( int i = 0; i != 12; ++i ) + { + const int *pPoints = iLines[i]; + int iLineState = (iClipped[pPoints[0]] + iClipped[pPoints[1]]); + if( iLineState != 1 ) //either both points are clipped, or neither are clipped + { + iLineStates[pPoints[0]][pPoints[1]] = + iLineStates[pPoints[1]][pPoints[0]] = + iLineState; + } + else + { + //one point is clipped, the other is not + if( iClipped[pPoints[0]] == 1 ) + { + //first point was clipped, index 1 has the negative distance + float fInvTotalDist = 1.0f / (fDists[pPoints[0]] - fDists[pPoints[1]]); + vSplitPoints[pPoints[0]][pPoints[1]] = + vSplitPoints[pPoints[1]][pPoints[0]] = + (vPoints[pPoints[1]] * (fDists[pPoints[0]] * fInvTotalDist)) - (vPoints[pPoints[0]] * (fDists[pPoints[1]] * fInvTotalDist)); + + Assert( fabs( vNormal.Dot( vSplitPoints[pPoints[0]][pPoints[1]] ) - fPlaneDist ) < 0.01f ); + + iLineStates[pPoints[0]][pPoints[1]] = 3; + iLineStates[pPoints[1]][pPoints[0]] = 4; + } + else + { + //second point was clipped, index 0 has the negative distance + float fInvTotalDist = 1.0f / (fDists[pPoints[1]] - fDists[pPoints[0]]); + vSplitPoints[pPoints[0]][pPoints[1]] = + vSplitPoints[pPoints[1]][pPoints[0]] = + (vPoints[pPoints[0]] * (fDists[pPoints[1]] * fInvTotalDist)) - (vPoints[pPoints[1]] * (fDists[pPoints[0]] * fInvTotalDist)); + + Assert( fabs( vNormal.Dot( vSplitPoints[pPoints[0]][pPoints[1]] ) - fPlaneDist ) < 0.01f ); + + iLineStates[pPoints[0]][pPoints[1]] = 4; + iLineStates[pPoints[1]][pPoints[0]] = 3; + } + } + } + + + CMatRenderContextPtr pRenderContext( materials ); + +#ifdef DEBUG_DRAWCLIPPEDDEPTHBOX + pRenderContext->Bind( materials->FindMaterial( "debug/debugvertexcolor", TEXTURE_GROUP_OTHER ), NULL ); +#else + pRenderContext->Bind( g_material_WriteZ, NULL ); +#endif + + CMeshBuilder meshBuilder; + IMesh* pMesh = pRenderContext->GetDynamicMesh( false ); + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 18 ); //6 sides, possible one cut per side. Any side is capable of having 3 tri's. Lots of padding for things that aren't possible + + //going to draw as a collection of triangles, arranged as a triangle fan on each side + for( int i = 0; i != 6; ++i ) + { + const int *pPoints = iQuads[i]; + + //can't start the fan on a wholly clipped line, so seek to one that isn't + int j = 0; + do + { + if( iLineStates[pPoints[j]][pPoints[j+1]] != 2 ) //at least part of this line will be drawn + break; + + ++j; + } while( j != 3 ); + + if( j == 3 ) //not enough lines to even form a triangle + continue; + + float *pStartPoint = 0; + float *pTriangleFanPoints[4]; //at most, one of our fans will have 5 points total, with the first point being stored separately as pStartPoint + int iTriangleFanPointCount = 1; //the switch below creates the first for sure + + //figure out how to start the fan + switch( iLineStates[pPoints[j]][pPoints[j+1]] ) + { + case 0: //uncut + pStartPoint = &vPoints[pPoints[j]].x; + pTriangleFanPoints[0] = &vPoints[pPoints[j+1]].x; + break; + + case 4: //second index was clipped + pStartPoint = &vPoints[pPoints[j]].x; + pTriangleFanPoints[0] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x; + break; + + case 3: //first index was clipped + pStartPoint = &vSplitPoints[pPoints[j]][pPoints[j+1]].x; + pTriangleFanPoints[0] = &vPoints[pPoints[j + 1]].x; + break; + + default: + Assert( false ); + break; + }; + + for( ++j; j != 3; ++j ) //add end points for the rest of the indices, we're assembling a triangle fan + { + switch( iLineStates[pPoints[j]][pPoints[j+1]] ) + { + case 0: //uncut line, normal endpoint + pTriangleFanPoints[iTriangleFanPointCount] = &vPoints[pPoints[j+1]].x; + ++iTriangleFanPointCount; + break; + + case 2: //wholly cut line, no endpoint + break; + + case 3: //first point is clipped, normal endpoint + //special case, adds start and end point + pTriangleFanPoints[iTriangleFanPointCount] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x; + ++iTriangleFanPointCount; + + pTriangleFanPoints[iTriangleFanPointCount] = &vPoints[pPoints[j+1]].x; + ++iTriangleFanPointCount; + break; + + case 4: //second point is clipped + pTriangleFanPoints[iTriangleFanPointCount] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x; + ++iTriangleFanPointCount; + break; + + default: + Assert( false ); + break; + }; + } + + //special case endpoints, half-clipped lines have a connecting line between them and the next line (first line in this case) + switch( iLineStates[pPoints[j]][pPoints[j+1]] ) + { + case 3: + case 4: + pTriangleFanPoints[iTriangleFanPointCount] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x; + ++iTriangleFanPointCount; + break; + }; + + Assert( iTriangleFanPointCount <= 4 ); + + //add the fan to the mesh + int iLoopStop = iTriangleFanPointCount - 1; + for( int k = 0; k != iLoopStop; ++k ) + { + meshBuilder.Position3fv( pStartPoint ); +#ifdef DEBUG_DRAWCLIPPEDDEPTHBOX + float fHalfColors[3] = { fColors[i][0] * 0.5f, fColors[i][1] * 0.5f, fColors[i][2] * 0.5f }; + meshBuilder.Color3fv( fHalfColors ); +#endif + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pTriangleFanPoints[k] ); +#ifdef DEBUG_DRAWCLIPPEDDEPTHBOX + meshBuilder.Color3fv( fColors[i] ); +#endif + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3fv( pTriangleFanPoints[k+1] ); +#ifdef DEBUG_DRAWCLIPPEDDEPTHBOX + meshBuilder.Color3fv( fColors[i] ); +#endif + meshBuilder.AdvanceVertex(); + } + } + + meshBuilder.End(); + pMesh->Draw(); + pRenderContext->Flush( false ); +} + + +//----------------------------------------------------------------------------- +// Draws all opaque renderables in leaves that were rendered +//----------------------------------------------------------------------------- +static inline void DrawOpaqueRenderable( IClientRenderable *pEnt, bool bTwoPass, ERenderDepthMode DepthMode, int nDefaultFlags = 0 ) +{ + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + float color[3]; + + pEnt->GetColorModulation( color ); + render->SetColorModulation( color ); + + int flags = nDefaultFlags | STUDIO_RENDER; + if ( bTwoPass ) + { + flags |= STUDIO_TWOPASS; + } + + if ( DepthMode == DEPTH_MODE_SHADOW ) + { + flags |= STUDIO_SHADOWDEPTHTEXTURE; + } + else if ( DepthMode == DEPTH_MODE_SSA0 ) + { + flags |= STUDIO_SSAODEPTHTEXTURE; + } + + float *pRenderClipPlane = NULL; + if( r_entityclips.GetBool() ) + pRenderClipPlane = pEnt->GetRenderClipPlane(); + + if( pRenderClipPlane ) + { + CMatRenderContextPtr pRenderContext( materials ); + if( !materials->UsingFastClipping() ) //do NOT change the fast clip plane mid-scene, depth problems result. Regular user clip planes are fine though + pRenderContext->PushCustomClipPlane( pRenderClipPlane ); + else + DrawClippedDepthBox( pEnt, pRenderClipPlane ); + Assert( view->GetCurrentlyDrawingEntity() == NULL ); + view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() ); + pEnt->DrawModel( flags ); + view->SetCurrentlyDrawingEntity( NULL ); + if( pRenderClipPlane && !materials->UsingFastClipping() ) + pRenderContext->PopCustomClipPlane(); + } + else + { + Assert( view->GetCurrentlyDrawingEntity() == NULL ); + view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() ); + pEnt->DrawModel( flags ); + view->SetCurrentlyDrawingEntity( NULL ); + } +} + +//------------------------------------- + + +ConVar r_drawopaquestaticpropslast( "r_drawopaquestaticpropslast", "0", 0, "Whether opaque static props are rendered after non-npcs" ); + +#define DEBUG_BUCKETS 0 + +#if DEBUG_BUCKETS +ConVar r_drawopaque_old( "r_drawopaque_old", "0", 0, "Whether old unbucketed technique is used" ); +ConVar r_drawopaquesbucket( "r_drawopaquesbucket", "0", FCVAR_CHEAT, "Draw only specific bucket: positive - props, negative - ents" ); +ConVar r_drawopaquesbucket_stats( "r_drawopaquesbucket_stats", "0", FCVAR_CHEAT, "Draw distribution of props/ents in the buckets" ); +#endif + + +static void SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating ) +{ + pBaseAnimating->SetupBones( NULL, -1, -1, gpGlobals->curtime ); +} + + +static void DrawOpaqueRenderables_DrawBrushModels( CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, ERenderDepthMode DepthMode ) +{ + for( CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity ) + { + Assert( !itEntity->m_TwoPass ); + DrawOpaqueRenderable( itEntity->m_pRenderable, false, DepthMode ); + } +} + +static void DrawOpaqueRenderables_DrawStaticProps( CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, ERenderDepthMode DepthMode ) +{ + if ( pEntitiesEnd == pEntitiesBegin ) + return; + + float one[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + render->SetColorModulation( one ); + render->SetBlend( 1.0f ); + + const int MAX_STATICS_PER_BATCH = 512; + IClientRenderable *pStatics[ MAX_STATICS_PER_BATCH ]; + + int numScheduled = 0, numAvailable = MAX_STATICS_PER_BATCH; + + for( CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity ) + { + if ( itEntity->m_pRenderable ) + /**/; + else + continue; + + if ( g_pStudioStatsEntity != NULL && g_CurrentViewID == VIEW_MAIN && itEntity->m_pRenderable == g_pStudioStatsEntity ) + { + DrawOpaqueRenderable( itEntity->m_pRenderable, false, DepthMode, STUDIO_GENERATE_STATS ); + continue; + } + + pStatics[ numScheduled ++ ] = itEntity->m_pRenderable; + if ( -- numAvailable > 0 ) + continue; // place a hint for compiler to predict more common case in the loop + + staticpropmgr->DrawStaticProps( pStatics, numScheduled, DepthMode, vcollide_wireframe.GetBool() ); + numScheduled = 0; + numAvailable = MAX_STATICS_PER_BATCH; + } + + if ( numScheduled ) + staticpropmgr->DrawStaticProps( pStatics, numScheduled, DepthMode, vcollide_wireframe.GetBool() ); +} + +static void DrawOpaqueRenderables_Range( CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, ERenderDepthMode DepthMode ) +{ + for( CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity ) + { + if ( itEntity->m_pRenderable ) + DrawOpaqueRenderable( itEntity->m_pRenderable, ( itEntity->m_TwoPass != 0 ), DepthMode ); + } +} + +void CRendering3dView::DrawOpaqueRenderables( ERenderDepthMode DepthMode ) +{ + VPROF_BUDGET("CViewRender::DrawOpaqueRenderables", "DrawOpaqueRenderables" ); + + if( !r_drawopaquerenderables.GetBool() ) + return; + + if( !m_pMainView->ShouldDrawEntities() ) + return; + + render->SetBlend( 1 ); + + // + // Prepare to iterate over all leaves that were visible, and draw opaque things in them. + // + RopeManager()->ResetRenderCache(); + g_pParticleSystemMgr->ResetRenderCache(); + + //bool const bDrawopaquestaticpropslast = r_drawopaquestaticpropslast.GetBool(); + + + // + // First do the brush models + // + { + CClientRenderablesList::CEntry *pEntitiesBegin, *pEntitiesEnd; + pEntitiesBegin = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_OPAQUE_BRUSH]; + pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE_BRUSH]; + DrawOpaqueRenderables_DrawBrushModels( pEntitiesBegin, pEntitiesEnd, DepthMode ); + } + + + +#if DEBUG_BUCKETS + { + con_nprint_s nxPrn = { 0 }; + nxPrn.index = 16; + nxPrn.time_to_live = -1; + nxPrn.color[0] = 0.9f, nxPrn.color[1] = 1.0f, nxPrn.color[2] = 0.9f; + nxPrn.fixed_width_font = true; + + engine->Con_NXPrintf( &nxPrn, "Draw Opaque Technique : NEW" ); + if ( r_drawopaque_old.GetBool() ) + { + + engine->Con_NXPrintf( &nxPrn, "Draw Opaque Technique : OLD" ); + + // now the static props + { + for ( int bucket = RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS - 1; bucket -- > 0; ) + { + CClientRenderablesList::CEntry + * const pEntitiesBegin = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ], + * const pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ]; + DrawOpaqueRenderables_DrawStaticProps( pEntitiesBegin, pEntitiesEnd, bShadowDepth ); + } + } + + // now the other opaque entities + for ( int bucket = RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS - 1; bucket -- > 0; ) + { + CClientRenderablesList::CEntry + * const pEntitiesBegin = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ], + * const pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ]; + DrawOpaqueRenderables_Range( pEntitiesBegin, pEntitiesEnd, bShadowDepth ); + } + + // + // Ropes and particles + // + RopeManager()->DrawRenderCache( bShadowDepth ); + g_pParticleSystemMgr->DrawRenderCache( bShadowDepth ); + + return; + } + } +#endif + + + + // + // Sort everything that's not a static prop + // + int numOpaqueEnts = 0; + for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket ) + numOpaqueEnts += m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ]; + + CUtlVector< C_BaseAnimating * > arrBoneSetupNpcsLast( (C_BaseAnimating **)_alloca( numOpaqueEnts * sizeof( C_BaseAnimating * ) ), numOpaqueEnts, numOpaqueEnts ); + CUtlVector< CClientRenderablesList::CEntry > arrRenderEntsNpcsFirst( (CClientRenderablesList::CEntry *)_alloca( numOpaqueEnts * sizeof( CClientRenderablesList::CEntry ) ), numOpaqueEnts, numOpaqueEnts ); + int numNpcs = 0, numNonNpcsAnimating = 0; + + for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket ) + { + for( CClientRenderablesList::CEntry + * const pEntitiesBegin = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ], + * const pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ], + *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity ) + { + C_BaseEntity *pEntity = itEntity->m_pRenderable ? itEntity->m_pRenderable->GetIClientUnknown()->GetBaseEntity() : NULL; + if ( pEntity ) + { + if ( pEntity->IsNPC() ) + { + C_BaseAnimating *pba = assert_cast( pEntity ); + arrRenderEntsNpcsFirst[ numNpcs ++ ] = *itEntity; + arrBoneSetupNpcsLast[ numOpaqueEnts - numNpcs ] = pba; + + itEntity->m_pRenderable = NULL; // We will render NPCs separately + itEntity->m_RenderHandle = NULL; + + continue; + } + else if ( pEntity->GetBaseAnimating() ) + { + C_BaseAnimating *pba = assert_cast( pEntity ); + arrBoneSetupNpcsLast[ numNonNpcsAnimating ++ ] = pba; + // fall through + } + } + } + } + + if ( 0 && r_threaded_renderables.GetBool() ) + { + ParallelProcess( "BoneSetupNpcsLast", arrBoneSetupNpcsLast.Base() + numOpaqueEnts - numNpcs, numNpcs, &SetupBonesOnBaseAnimating ); + ParallelProcess( "BoneSetupNpcsLast NonNPCs", arrBoneSetupNpcsLast.Base(), numNonNpcsAnimating, &SetupBonesOnBaseAnimating ); + } + + + // + // Draw static props + opaque entities from the biggest bucket to the smallest + // + { + CClientRenderablesList::CEntry * pEnts[ RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ][2]; + CClientRenderablesList::CEntry * pProps[ RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ][2]; + + for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket ) + { + pEnts[bucket][0] = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ]; + pEnts[bucket][1] = pEnts[bucket][0] + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ]; + + pProps[bucket][0] = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ]; + pProps[bucket][1] = pProps[bucket][0] + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ]; + + // Render sequence debugging + #if DEBUG_BUCKETS + if ( r_drawopaquesbucket_stats.GetBool() ) + { + con_nprint_s nxPrn = { 0 }; + nxPrn.index = 20 + bucket * 3; + nxPrn.time_to_live = -1; + nxPrn.color[0] = 0.9f, nxPrn.color[1] = 1.0f, nxPrn.color[2] = 0.9f; + nxPrn.fixed_width_font = true; + + if ( bDrawopaquestaticpropslast ) + engine->Con_NXPrintf( &nxPrn, "[ %2d ] Ents : %3d", bucket + 1, pEnts[bucket][1] - pEnts[bucket][0] ), + ++ nxPrn.index, + engine->Con_NXPrintf( &nxPrn, "[ %2d ] Props: %3d", bucket + 1, pProps[bucket][1] - pProps[bucket][0] ); + else + engine->Con_NXPrintf( &nxPrn, "[ %2d ] Props: %3d", bucket + 1, pProps[bucket][1] - pProps[bucket][0] ), + ++ nxPrn.index, + engine->Con_NXPrintf( &nxPrn, "[ %2d ] Ents : %3d", bucket + 1, pEnts[bucket][1] - pEnts[bucket][0] ); + } + #endif + } + + +#if DEBUG_BUCKETS + if ( int iBucket = r_drawopaquesbucket.GetInt() ) + { + if ( iBucket > 0 && iBucket <= RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ) + { + DrawOpaqueRenderables_Range( pEnts[iBucket - 1][0], pEnts[iBucket - 1][1], bShadowDepth ); + } + if ( iBucket < 0 && iBucket >= -RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ) + { + DrawOpaqueRenderables_DrawStaticProps( pProps[- 1 - iBucket][0], pProps[- 1 - iBucket][1], bShadowDepth ); + } + } + else +#endif + + for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket ) + { + // PVS-Studio pointed out that the two sides of the if/else were identical. Fixing + // this long-broken behavior would change rendering, so I fixed the code but + // commented out the new behavior. Uncomment the if statement and else block + // when needed. + //if ( bDrawopaquestaticpropslast ) + { + DrawOpaqueRenderables_Range( pEnts[bucket][0], pEnts[bucket][1], DepthMode ); + DrawOpaqueRenderables_DrawStaticProps( pProps[bucket][0], pProps[bucket][1], DepthMode ); + } + /*else + { + DrawOpaqueRenderables_DrawStaticProps( pProps[bucket][0], pProps[bucket][1], DepthMode ); + DrawOpaqueRenderables_Range( pEnts[bucket][0], pEnts[bucket][1], DepthMode ); + }*/ + } + + + } + + // + // Draw NPCs now + // + DrawOpaqueRenderables_Range( arrRenderEntsNpcsFirst.Base(), arrRenderEntsNpcsFirst.Base() + numNpcs, DepthMode ); + + // + // Ropes and particles + // + RopeManager()->DrawRenderCache( DepthMode ); + g_pParticleSystemMgr->DrawRenderCache( DepthMode ); +} + + +//----------------------------------------------------------------------------- +// Renders all translucent world + detail objects in a particular set of leaves +//----------------------------------------------------------------------------- +void CRendering3dView::DrawTranslucentWorldInLeaves( bool bShadowDepth ) +{ + VPROF_BUDGET( "CViewRender::DrawTranslucentWorldInLeaves", VPROF_BUDGETGROUP_WORLD_RENDERING ); + const ClientWorldListInfo_t& info = *m_pWorldListInfo; + for( int iCurLeafIndex = info.m_LeafCount - 1; iCurLeafIndex >= 0; iCurLeafIndex-- ) + { + int nActualLeafIndex = info.m_pActualLeafIndex ? info.m_pActualLeafIndex[ iCurLeafIndex ] : iCurLeafIndex; + Assert( nActualLeafIndex != INVALID_LEAF_INDEX ); + if ( render->LeafContainsTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, m_DrawFlags ) ) + { + // Now draw the surfaces in this leaf + render->DrawTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, m_DrawFlags, bShadowDepth ); + } + } +} + + +//----------------------------------------------------------------------------- +// Renders all translucent world + detail objects in a particular set of leaves +//----------------------------------------------------------------------------- +void CRendering3dView::DrawTranslucentWorldAndDetailPropsInLeaves( int iCurLeafIndex, int iFinalLeafIndex, int nEngineDrawFlags, int &nDetailLeafCount, LeafIndex_t* pDetailLeafList, bool bShadowDepth ) +{ + VPROF_BUDGET( "CViewRender::DrawTranslucentWorldAndDetailPropsInLeaves", VPROF_BUDGETGROUP_WORLD_RENDERING ); + const ClientWorldListInfo_t& info = *m_pWorldListInfo; + for( ; iCurLeafIndex >= iFinalLeafIndex; iCurLeafIndex-- ) + { + int nActualLeafIndex = info.m_pActualLeafIndex ? info.m_pActualLeafIndex[ iCurLeafIndex ] : iCurLeafIndex; + Assert( nActualLeafIndex != INVALID_LEAF_INDEX ); + if ( render->LeafContainsTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, nEngineDrawFlags ) ) + { + // First draw any queued-up detail props from previously visited leaves + DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList ); + nDetailLeafCount = 0; + + // Now draw the surfaces in this leaf + render->DrawTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, nEngineDrawFlags, bShadowDepth ); + } + + // Queue up detail props that existed in this leaf + if ( ClientLeafSystem()->ShouldDrawDetailObjectsInLeaf( info.m_pLeafList[iCurLeafIndex], m_pMainView->BuildWorldListsNumber() ) ) + { + pDetailLeafList[nDetailLeafCount] = info.m_pLeafList[iCurLeafIndex]; + ++nDetailLeafCount; + } + } +} + + +//----------------------------------------------------------------------------- +// Renders all translucent entities in the render list +//----------------------------------------------------------------------------- +static inline void DrawTranslucentRenderable( IClientRenderable *pEnt, bool twoPass, bool bShadowDepth, bool bIgnoreDepth ) +{ + // Determine blending amount and tell engine + float blend = (float)( pEnt->GetFxBlend() / 255.0f ); + + // Totally gone + if ( blend <= 0.0f ) + return; + + if ( pEnt->IgnoresZBuffer() != bIgnoreDepth ) + return; + + // Tell engine + render->SetBlend( blend ); + + float color[3]; + pEnt->GetColorModulation( color ); + render->SetColorModulation( color ); + + int flags = STUDIO_RENDER | STUDIO_TRANSPARENCY; + if ( twoPass ) + flags |= STUDIO_TWOPASS; + + if ( bShadowDepth ) + flags |= STUDIO_SHADOWDEPTHTEXTURE; + + float *pRenderClipPlane = NULL; + if( r_entityclips.GetBool() ) + pRenderClipPlane = pEnt->GetRenderClipPlane(); + + if( pRenderClipPlane ) + { + CMatRenderContextPtr pRenderContext( materials ); + if( !materials->UsingFastClipping() ) //do NOT change the fast clip plane mid-scene, depth problems result. Regular user clip planes are fine though + pRenderContext->PushCustomClipPlane( pRenderClipPlane ); + else + DrawClippedDepthBox( pEnt, pRenderClipPlane ); + Assert( view->GetCurrentlyDrawingEntity() == NULL ); + view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() ); + pEnt->DrawModel( flags ); + view->SetCurrentlyDrawingEntity( NULL ); + + if( pRenderClipPlane && !materials->UsingFastClipping() ) + pRenderContext->PopCustomClipPlane(); + } + else + { + Assert( view->GetCurrentlyDrawingEntity() == NULL ); + view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() ); + pEnt->DrawModel( flags ); + view->SetCurrentlyDrawingEntity( NULL ); + } +} + + +//----------------------------------------------------------------------------- +// Renders all translucent entities in the render list +//----------------------------------------------------------------------------- +void CRendering3dView::DrawTranslucentRenderablesNoWorld( bool bInSkybox ) +{ + VPROF( "CViewRender::DrawTranslucentRenderablesNoWorld" ); + + if ( !m_pMainView->ShouldDrawEntities() || !r_drawtranslucentrenderables.GetBool() ) + return; + + // Draw the particle singletons. + DrawParticleSingletons( bInSkybox ); + + bool bShadowDepth = (m_DrawFlags & ( DF_SHADOW_DEPTH_MAP | DF_SSAO_DEPTH_PASS ) ) != 0; + + CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; + int iCurTranslucentEntity = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - 1; + + while( iCurTranslucentEntity >= 0 ) + { + IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable; + if ( pRenderable->UsesPowerOfTwoFrameBufferTexture() ) + { + UpdateRefractTexture(); + } + + if ( pRenderable->UsesFullFrameBufferTexture() ) + { + UpdateScreenEffectTexture(); + } + + DrawTranslucentRenderable( pRenderable, pEntities[iCurTranslucentEntity].m_TwoPass != 0, bShadowDepth, false ); + --iCurTranslucentEntity; + } + + // Reset the blend state. + render->SetBlend( 1 ); +} + + +//----------------------------------------------------------------------------- +// Renders all translucent entities in the render list that ignore the Z buffer +//----------------------------------------------------------------------------- +void CRendering3dView::DrawNoZBufferTranslucentRenderables( void ) +{ + VPROF( "CViewRender::DrawNoZBufferTranslucentRenderables" ); + + if ( !m_pMainView->ShouldDrawEntities() || !r_drawtranslucentrenderables.GetBool() ) + return; + + bool bShadowDepth = (m_DrawFlags & ( DF_SHADOW_DEPTH_MAP | DF_SSAO_DEPTH_PASS ) ) != 0; + + CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; + int iCurTranslucentEntity = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - 1; + + while( iCurTranslucentEntity >= 0 ) + { + IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable; + if ( pRenderable->UsesPowerOfTwoFrameBufferTexture() ) + { + UpdateRefractTexture(); + } + + if ( pRenderable->UsesFullFrameBufferTexture() ) + { + UpdateScreenEffectTexture(); + } + + DrawTranslucentRenderable( pRenderable, pEntities[iCurTranslucentEntity].m_TwoPass != 0, bShadowDepth, true ); + --iCurTranslucentEntity; + } + + // Reset the blend state. + render->SetBlend( 1 ); +} + + + +//----------------------------------------------------------------------------- +// Renders all translucent world, entities, and detail objects in a particular set of leaves +//----------------------------------------------------------------------------- +void CRendering3dView::DrawTranslucentRenderables( bool bInSkybox, bool bShadowDepth ) +{ + const ClientWorldListInfo_t& info = *m_pWorldListInfo; + +#ifdef PORTAL //if we're in the portal mod, we need to make a detour so we can render portal views using stencil areas + if( ShouldDrawPortals() ) //no recursive stencil views during skybox rendering (although we might be drawing a skybox while already in a recursive stencil view) + { + int iDrawFlagsBackup = m_DrawFlags; + + if( g_pPortalRender->DrawPortalsUsingStencils( (CViewRender *)m_pMainView ) )// @MULTICORE (toml 8/10/2006): remove this hack cast + { + m_DrawFlags = iDrawFlagsBackup; + + //reset visibility + unsigned int iVisFlags = 0; + m_pMainView->SetupVis( *this, iVisFlags, m_pCustomVisibility ); + + //recreate drawlists (since I can't find an easy way to backup the originals) + { + SafeRelease( m_pWorldRenderList ); + SafeRelease( m_pWorldListInfo ); + BuildWorldRenderLists( ((m_DrawFlags & DF_DRAW_ENTITITES) != 0), m_pCustomVisibility ? m_pCustomVisibility->m_iForceViewLeaf : -1, false ); + + AssertMsg( m_DrawFlags & DF_DRAW_ENTITITES, "It shouldn't be possible to get here if this wasn't set, needs special case investigation" ); + for( int i = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY]; --i >= 0; ) + { + m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY][i].m_pRenderable->ComputeFxBlend(); + } + } + + if( r_depthoverlay.GetBool() ) + { + CMatRenderContextPtr pRenderContext( materials ); + ITexture *pDepthTex = GetFullFrameDepthTexture(); + + IMaterial *pMaterial = materials->FindMaterial( "debug/showz", TEXTURE_GROUP_OTHER, true ); + pMaterial->IncrementReferenceCount(); + IMaterialVar *BaseTextureVar = pMaterial->FindVar( "$basetexture", NULL, false ); + IMaterialVar *pDepthInAlpha = NULL; + if( IsPC() ) + { + pDepthInAlpha = pMaterial->FindVar( "$ALPHADEPTH", NULL, false ); + pDepthInAlpha->SetIntValue( 1 ); + } + + BaseTextureVar->SetTextureValue( pDepthTex ); + + pRenderContext->OverrideDepthEnable( true, false ); //don't write to depth, or else we'll never see translucents + pRenderContext->DrawScreenSpaceQuad( pMaterial ); + pRenderContext->OverrideDepthEnable( false, true ); + pMaterial->DecrementReferenceCount(); + } + } + else + { + //done recursing in, time to go back out and do translucents + CMatRenderContextPtr pRenderContext( materials ); + + UpdateFullScreenDepthTexture(); + } + } +#else + { + //opaques generally write depth, and translucents generally don't. + //So immediately after opaques are done is the best time to snap off the depth buffer to a texture. + switch ( g_CurrentViewID ) + { + case VIEW_MAIN: +#ifdef _X360 + case VIEW_INTRO_CAMERA: + case VIEW_INTRO_PLAYER: +#endif + UpdateFullScreenDepthTexture(); + break; + + default: + materials->GetRenderContext()->SetFullScreenDepthTextureValidityFlag( false ); + break; + } + } +#endif + + if ( !r_drawtranslucentworld.GetBool() ) + { + DrawTranslucentRenderablesNoWorld( bInSkybox ); + return; + } + + VPROF_BUDGET( "CViewRender::DrawTranslucentRenderables", "DrawTranslucentRenderables" ); + int iPrevLeaf = info.m_LeafCount - 1; + int nDetailLeafCount = 0; + LeafIndex_t *pDetailLeafList = (LeafIndex_t*)stackalloc( info.m_LeafCount * sizeof(LeafIndex_t) ); + +// bool bDrawUnderWater = (nFlags & DF_RENDER_UNDERWATER) != 0; +// bool bDrawAboveWater = (nFlags & DF_RENDER_ABOVEWATER) != 0; +// bool bDrawWater = (nFlags & DF_RENDER_WATER) != 0; +// bool bClipSkybox = (nFlags & DF_CLIP_SKYBOX ) != 0; + unsigned long nEngineDrawFlags = BuildEngineDrawWorldListFlags( m_DrawFlags & ~DF_DRAWSKYBOX ); + + DetailObjectSystem()->BeginTranslucentDetailRendering(); + + if ( m_pMainView->ShouldDrawEntities() && r_drawtranslucentrenderables.GetBool() ) + { + MDLCACHE_CRITICAL_SECTION(); + // Draw the particle singletons. + DrawParticleSingletons( bInSkybox ); + + CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY]; + int iCurTranslucentEntity = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - 1; + + bool bRenderingWaterRenderTargets = m_DrawFlags & ( DF_RENDER_REFRACTION | DF_RENDER_REFLECTION ); + + while( iCurTranslucentEntity >= 0 ) + { + // Seek the current leaf up to our current translucent-entity leaf. + int iThisLeaf = pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf; + + // First draw the translucent parts of the world up to and including those in this leaf + DrawTranslucentWorldAndDetailPropsInLeaves( iPrevLeaf, iThisLeaf, nEngineDrawFlags, nDetailLeafCount, pDetailLeafList, bShadowDepth ); + + // We're traversing the leaf list backwards to get the appropriate sort ordering (back to front) + iPrevLeaf = iThisLeaf - 1; + + // Draw all the translucent entities with this leaf. + int nLeaf = info.m_pLeafList[iThisLeaf]; + + bool bDrawDetailProps = ClientLeafSystem()->ShouldDrawDetailObjectsInLeaf( nLeaf, m_pMainView->BuildWorldListsNumber() ); + if ( bDrawDetailProps ) + { + // Draw detail props up to but not including this leaf + Assert( nDetailLeafCount > 0 ); + --nDetailLeafCount; + Assert( pDetailLeafList[nDetailLeafCount] == nLeaf ); + DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList ); + + // Draw translucent renderables in the leaf interspersed with detail props + for( ;pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf == iThisLeaf && iCurTranslucentEntity >= 0; --iCurTranslucentEntity ) + { + IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable; + + // Draw any detail props in this leaf that's farther than the entity + const Vector &vecRenderOrigin = pRenderable->GetRenderOrigin(); + DetailObjectSystem()->RenderTranslucentDetailObjectsInLeaf( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nLeaf, &vecRenderOrigin ); + + bool bUsesPowerOfTwoFB = pRenderable->UsesPowerOfTwoFrameBufferTexture(); + bool bUsesFullFB = pRenderable->UsesFullFrameBufferTexture(); + + if ( ( bUsesPowerOfTwoFB || bUsesFullFB )&& !bShadowDepth ) + { + if( bRenderingWaterRenderTargets ) + { + continue; + } + + CMatRenderContextPtr pRenderContext( materials ); + ITexture *rt = pRenderContext->GetRenderTarget(); + + if ( rt && bUsesFullFB ) + { + UpdateScreenEffectTexture( 0, 0, 0, rt->GetActualWidth(), rt->GetActualHeight(), true ); + } + else if ( bUsesPowerOfTwoFB ) + { + UpdateRefractTexture(); + } + + pRenderContext.SafeRelease(); + } + + // Then draw the translucent renderable + DrawTranslucentRenderable( pRenderable, (pEntities[iCurTranslucentEntity].m_TwoPass != 0), bShadowDepth, false ); + } + + // Draw all remaining props in this leaf + DetailObjectSystem()->RenderTranslucentDetailObjectsInLeaf( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nLeaf, NULL ); + } + else + { + // Draw queued up detail props (we know that the list of detail leaves won't include this leaf, since ShouldDrawDetailObjectsInLeaf is false) + // Therefore no fixup on nDetailLeafCount is required as in the above section + DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList ); + + for( ;pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf == iThisLeaf && iCurTranslucentEntity >= 0; --iCurTranslucentEntity ) + { + IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable; + + bool bUsesPowerOfTwoFB = pRenderable->UsesPowerOfTwoFrameBufferTexture(); + bool bUsesFullFB = pRenderable->UsesFullFrameBufferTexture(); + + if ( ( bUsesPowerOfTwoFB || bUsesFullFB )&& !bShadowDepth ) + { + if( bRenderingWaterRenderTargets ) + { + continue; + } + + CMatRenderContextPtr pRenderContext( materials ); + ITexture *rt = pRenderContext->GetRenderTarget(); + + if ( rt ) + { + if ( bUsesFullFB ) + { + UpdateScreenEffectTexture( 0, 0, 0, rt->GetActualWidth(), rt->GetActualHeight(), true ); + } + else if ( bUsesPowerOfTwoFB ) + { + UpdateRefractTexture(0, 0, rt->GetActualWidth(), rt->GetActualHeight()); + } + } + else + { + if ( bUsesPowerOfTwoFB ) + { + UpdateRefractTexture(); + } + } + + pRenderContext.SafeRelease(); + } + + DrawTranslucentRenderable( pRenderable, (pEntities[iCurTranslucentEntity].m_TwoPass != 0), bShadowDepth, false ); + } + } + + nDetailLeafCount = 0; + } + } + + // Draw the rest of the surfaces in world leaves + DrawTranslucentWorldAndDetailPropsInLeaves( iPrevLeaf, 0, nEngineDrawFlags, nDetailLeafCount, pDetailLeafList, bShadowDepth ); + + // Draw any queued-up detail props from previously visited leaves + DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList ); + + // Reset the blend state. + render->SetBlend( 1 ); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CRendering3dView::EnableWorldFog( void ) +{ + VPROF("CViewRender::EnableWorldFog"); + CMatRenderContextPtr pRenderContext( materials ); + + fogparams_t *pFogParams = NULL; + C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); + if ( pbp ) + { + pFogParams = pbp->GetFogParams(); + } + + if( GetFogEnable( pFogParams ) ) + { + float fogColor[3]; + GetFogColor( pFogParams, fogColor ); + pRenderContext->FogMode( MATERIAL_FOG_LINEAR ); + pRenderContext->FogColor3fv( fogColor ); + pRenderContext->FogStart( GetFogStart( pFogParams ) ); + pRenderContext->FogEnd( GetFogEnd( pFogParams ) ); + pRenderContext->FogMaxDensity( GetFogMaxDensity( pFogParams ) ); + } + else + { + pRenderContext->FogMode( MATERIAL_FOG_NONE ); + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +int CRendering3dView::GetDrawFlags() +{ + return m_DrawFlags; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CRendering3dView::SetFogVolumeState( const VisibleFogVolumeInfo_t &fogInfo, bool bUseHeightFog ) +{ + render->SetFogVolumeState( fogInfo.m_nVisibleFogVolume, bUseHeightFog ); + +#ifdef PORTAL + + //the idea behind fog shifting is this... + //Normal fog simulates the effect of countless tiny particles between your viewpoint and whatever geometry is rendering. + //But, when rendering to a portal view, there's a large space between the virtual camera and the portal exit surface. + //This space isn't supposed to exist, and therefore has none of the tiny particles that make up fog. + //So, we have to shift fog start/end out to align the distances with the portal exit surface instead of the virtual camera to eliminate fog simulation in the non-space + if( g_pPortalRender->GetViewRecursionLevel() == 0 ) + return; //rendering one of the primary views, do nothing + + g_pPortalRender->ShiftFogForExitPortalView(); + +#endif //#ifdef PORTAL +} + + +//----------------------------------------------------------------------------- +// Standard 3d skybox view +//----------------------------------------------------------------------------- +SkyboxVisibility_t CSkyboxView::ComputeSkyboxVisibility() +{ + return engine->IsSkyboxVisibleFromPoint( origin ); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +bool CSkyboxView::GetSkyboxFogEnable() +{ + C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); + if( !pbp ) + { + return false; + } + CPlayerLocalData *local = &pbp->m_Local; + + if( fog_override.GetInt() ) + { + if( fog_enableskybox.GetInt() ) + { + return true; + } + else + { + return false; + } + } + else + { + return !!local->m_skybox3d.fog.enable; + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CSkyboxView::Enable3dSkyboxFog( void ) +{ + C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); + if( !pbp ) + { + return; + } + CPlayerLocalData *local = &pbp->m_Local; + + CMatRenderContextPtr pRenderContext( materials ); + + if( GetSkyboxFogEnable() ) + { + float fogColor[3]; + GetSkyboxFogColor( fogColor ); + float scale = 1.0f; + if ( local->m_skybox3d.scale > 0.0f ) + { + scale = 1.0f / local->m_skybox3d.scale; + } + pRenderContext->FogMode( MATERIAL_FOG_LINEAR ); + pRenderContext->FogColor3fv( fogColor ); + pRenderContext->FogStart( GetSkyboxFogStart() * scale ); + pRenderContext->FogEnd( GetSkyboxFogEnd() * scale ); + pRenderContext->FogMaxDensity( GetSkyboxFogMaxDensity() ); + } + else + { + pRenderContext->FogMode( MATERIAL_FOG_NONE ); + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +sky3dparams_t *CSkyboxView::PreRender3dSkyboxWorld( SkyboxVisibility_t nSkyboxVisible ) +{ + if ( ( nSkyboxVisible != SKYBOX_3DSKYBOX_VISIBLE ) && r_3dsky.GetInt() != 2 ) + return NULL; + + // render the 3D skybox + if ( !r_3dsky.GetInt() ) + return NULL; + + C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer(); + + // No local player object yet... + if ( !pbp ) + return NULL; + + CPlayerLocalData* local = &pbp->m_Local; + if ( local->m_skybox3d.area == 255 ) + return NULL; + + return &local->m_skybox3d; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CSkyboxView::DrawInternal( view_id_t iSkyBoxViewID, bool bInvokePreAndPostRender, ITexture *pRenderTarget, ITexture *pDepthTarget ) +{ + unsigned char **areabits = render->GetAreaBits(); + unsigned char *savebits; + unsigned char tmpbits[ 32 ]; + savebits = *areabits; + memset( tmpbits, 0, sizeof(tmpbits) ); + + // set the sky area bit + tmpbits[m_pSky3dParams->area>>3] |= 1 << (m_pSky3dParams->area&7); + + *areabits = tmpbits; + + // if you can get really close to the skybox geometry it's possible that you'll be able to clip into it + // with this near plane. If so, move it in a bit. It's at 2.0 to give us more precision. That means you + // need to keep the eye position at least 2 * scale away from the geometry in the skybox + zNear = 2.0; + zFar = MAX_TRACE_LENGTH; + + // scale origin by sky scale + if ( m_pSky3dParams->scale > 0 ) + { + float scale = 1.0f / m_pSky3dParams->scale; + VectorScale( origin, scale, origin ); + } + Enable3dSkyboxFog(); + VectorAdd( origin, m_pSky3dParams->origin, origin ); + + // BUGBUG: Fix this!!! We shouldn't need to call setup vis for the sky if we're connecting + // the areas. We'd have to mark all the clusters in the skybox area in the PVS of any + // cluster with sky. Then we could just connect the areas to do our vis. + //m_bOverrideVisOrigin could hose us here, so call direct + render->ViewSetupVis( false, 1, &m_pSky3dParams->origin.Get() ); + render->Push3DView( (*this), m_ClearFlags, pRenderTarget, GetFrustum(), pDepthTarget ); + + // Store off view origin and angles + SetupCurrentView( origin, angles, iSkyBoxViewID ); + +#if defined( _X360 ) + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->PushVertexShaderGPRAllocation( 32 ); + pRenderContext.SafeRelease(); +#endif + + // Invoke pre-render methods + if ( bInvokePreAndPostRender ) + { + IGameSystem::PreRenderAllSystems(); + } + + render->BeginUpdateLightmaps(); + BuildWorldRenderLists( true, true, -1 ); + BuildRenderableRenderLists( iSkyBoxViewID ); + render->EndUpdateLightmaps(); + + g_pClientShadowMgr->ComputeShadowTextures( (*this), m_pWorldListInfo->m_LeafCount, m_pWorldListInfo->m_pLeafList ); + + DrawWorld( 0.0f ); + + // Iterate over all leaves and render objects in those leaves + DrawOpaqueRenderables( DEPTH_MODE_NORMAL ); + + // Iterate over all leaves and render objects in those leaves + DrawTranslucentRenderables( true, false ); + DrawNoZBufferTranslucentRenderables(); + + m_pMainView->DisableFog(); + + CGlowOverlay::UpdateSkyOverlays( zFar, m_bCacheFullSceneState ); + + PixelVisibility_EndCurrentView(); + + // restore old area bits + *areabits = savebits; + + // Invoke post-render methods + if( bInvokePreAndPostRender ) + { + IGameSystem::PostRenderAllSystems(); + FinishCurrentView(); + } + + render->PopView( GetFrustum() ); + +#if defined( _X360 ) + pRenderContext.GetFrom( materials ); + pRenderContext->PopVertexShaderGPRAllocation(); +#endif +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +bool CSkyboxView::Setup( const CViewSetup &view, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible ) +{ + BaseClass::Setup( view ); + + // The skybox might not be visible from here + *pSkyboxVisible = ComputeSkyboxVisibility(); + m_pSky3dParams = PreRender3dSkyboxWorld( *pSkyboxVisible ); + + if ( !m_pSky3dParams ) + { + return false; + } + + // At this point, we've cleared everything we need to clear + // The next path will need to clear depth, though. + m_ClearFlags = *pClearFlags; + *pClearFlags &= ~( VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH | VIEW_CLEAR_STENCIL | VIEW_CLEAR_FULL_TARGET ); + *pClearFlags |= VIEW_CLEAR_DEPTH; // Need to clear depth after rednering the skybox + + m_DrawFlags = DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER | DF_RENDER_WATER; + if( r_skybox.GetBool() ) + { + m_DrawFlags |= DF_DRAWSKYBOX; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CSkyboxView::Draw() +{ + VPROF_BUDGET( "CViewRender::Draw3dSkyboxworld", "3D Skybox" ); + + ITexture *pRTColor = NULL; + ITexture *pRTDepth = NULL; + if( m_eStereoEye != STEREO_EYE_MONO ) + { + pRTColor = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(m_eStereoEye-1), ISourceVirtualReality::RT_Color ); + pRTDepth = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(m_eStereoEye-1), ISourceVirtualReality::RT_Depth ); + } + + DrawInternal(VIEW_3DSKY, true, pRTColor, pRTDepth ); +} + + +#ifdef PORTAL +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +bool CPortalSkyboxView::Setup( const CViewSetup &view, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible, ITexture *pRenderTarget ) +{ + if ( !BaseClass::Setup( view, pClearFlags, pSkyboxVisible ) ) + return false; + + m_pRenderTarget = pRenderTarget; + return true; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +SkyboxVisibility_t CPortalSkyboxView::ComputeSkyboxVisibility() +{ + return g_pPortalRender->IsSkyboxVisibleFromExitPortal(); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CPortalSkyboxView::Draw() +{ + AssertMsg( (g_pPortalRender->GetViewRecursionLevel() != 0) && g_pPortalRender->IsRenderingPortal(), "This is designed for through-portal views. Use the regular skybox drawing code for primary views" ); + + VPROF_BUDGET( "CViewRender::Draw3dSkyboxworld_Portal", "3D Skybox (portal view)" ); + + int iCurrentViewID = g_CurrentViewID; + + Frustum FrustumBackup; + memcpy( FrustumBackup, GetFrustum(), sizeof( Frustum ) ); + + CMatRenderContextPtr pRenderContext( materials ); + + bool bClippingEnabled = pRenderContext->EnableClipping( false ); + + //NOTE: doesn't magically map to VIEW_3DSKY at (0,0) like PORTAL_VIEWID maps to VIEW_MAIN + view_id_t iSkyBoxViewID = (view_id_t)g_pPortalRender->GetCurrentSkyboxViewId(); + + bool bInvokePreAndPostRender = ( g_pPortalRender->ShouldUseStencilsToRenderPortals() == false ); + + DrawInternal( iSkyBoxViewID, bInvokePreAndPostRender, m_pRenderTarget, NULL ); + + pRenderContext->EnableClipping( bClippingEnabled ); + + memcpy( GetFrustum(), FrustumBackup, sizeof( Frustum ) ); + render->OverrideViewFrustum( FrustumBackup ); + + g_CurrentViewID = iCurrentViewID; +} +#endif // PORTAL + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CShadowDepthView::Setup( const CViewSetup &shadowViewIn, ITexture *pRenderTarget, ITexture *pDepthTexture ) +{ + BaseClass::Setup( shadowViewIn ); + m_pRenderTarget = pRenderTarget; + m_pDepthTexture = pDepthTexture; +} + + +bool DrawingShadowDepthView( void ) //for easy externing +{ + return (CurrentViewID() == VIEW_SHADOW_DEPTH_TEXTURE); +} + +bool DrawingMainView() //for easy externing +{ + return (CurrentViewID() == VIEW_MAIN); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CShadowDepthView::Draw() +{ + VPROF_BUDGET( "CShadowDepthView::Draw", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + + // Start view + unsigned int visFlags; + m_pMainView->SetupVis( (*this), visFlags ); // @MULTICORE (toml 8/9/2006): Portal problem, not sending custom vis down + + CMatRenderContextPtr pRenderContext( materials ); + + pRenderContext->ClearColor3ub(0xFF, 0xFF, 0xFF); + +#if defined( _X360 ) + pRenderContext->PushVertexShaderGPRAllocation( 112 ); //almost all work is done in vertex shaders for depth rendering, max out their threads +#endif + + pRenderContext.SafeRelease(); + + if( IsPC() ) + { + render->Push3DView( (*this), VIEW_CLEAR_DEPTH, m_pRenderTarget, GetFrustum(), m_pDepthTexture ); + } + else if( IsX360() ) + { + //for the 360, the dummy render target has a separate depth buffer which we Resolve() from afterward + render->Push3DView( (*this), VIEW_CLEAR_DEPTH, m_pRenderTarget, GetFrustum() ); + } + + SetupCurrentView( origin, angles, VIEW_SHADOW_DEPTH_TEXTURE ); + + MDLCACHE_CRITICAL_SECTION(); + + { + VPROF_BUDGET( "BuildWorldRenderLists", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + BuildWorldRenderLists( true, -1, true, true ); // @MULTICORE (toml 8/9/2006): Portal problem, not sending custom vis down + } + + { + VPROF_BUDGET( "BuildRenderableRenderLists", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + BuildRenderableRenderLists( CurrentViewID() ); + } + + engine->Sound_ExtraUpdate(); // Make sure sound doesn't stutter + + m_DrawFlags = m_pMainView->GetBaseDrawFlags() | DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER | DF_SHADOW_DEPTH_MAP; // Don't draw water surface... + + { + VPROF_BUDGET( "DrawWorld", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + DrawWorld( 0.0f ); + } + + // Draw opaque and translucent renderables with appropriate override materials + // OVERRIDE_DEPTH_WRITE is OK with a NULL material pointer + modelrender->ForcedMaterialOverride( NULL, OVERRIDE_DEPTH_WRITE ); + + { + VPROF_BUDGET( "DrawOpaqueRenderables", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + DrawOpaqueRenderables( DEPTH_MODE_SHADOW ); + } + + modelrender->ForcedMaterialOverride( 0 ); + + m_DrawFlags = 0; + + pRenderContext.GetFrom( materials ); + + if( IsX360() ) + { + //Resolve() the depth texture here. Before the pop so the copy will recognize that the resolutions are the same + pRenderContext->CopyRenderTargetToTextureEx( m_pDepthTexture, -1, NULL, NULL ); + } + + render->PopView( GetFrustum() ); + +#if defined( _X360 ) + pRenderContext->PopVertexShaderGPRAllocation(); +#endif +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CFreezeFrameView::Setup( const CViewSetup &shadowViewIn ) +{ + BaseClass::Setup( shadowViewIn ); + + KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); + pVMTKeyValues->SetString( "$basetexture", IsX360() ? "_rt_FullFrameFB1" : "_rt_FullScreen" ); + pVMTKeyValues->SetInt( "$nocull", 1 ); + pVMTKeyValues->SetInt( "$nofog", 1 ); + pVMTKeyValues->SetInt( "$ignorez", 1 ); + m_pFreezeFrame.Init( "FreezeFrame_FullScreen", TEXTURE_GROUP_OTHER, pVMTKeyValues ); + m_pFreezeFrame->Refresh(); + + m_TranslucentSingleColor.Init( "debug/debugtranslucentsinglecolor", TEXTURE_GROUP_OTHER ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CFreezeFrameView::Draw( void ) +{ + CMatRenderContextPtr pRenderContext( materials ); + +#if defined( _X360 ) + pRenderContext->PushVertexShaderGPRAllocation( 16 ); //max out pixel shader threads +#endif + + // we might only need half of the texture if we're rendering in stereo + int nTexX0 = 0, nTexY0 = 0; + int nTexX1 = width, nTexY1 = height; + int nTexWidth = width, nTexHeight = height; + + switch( m_eStereoEye ) + { + case STEREO_EYE_LEFT: + nTexX1 = width; + nTexWidth *= 2; + break; + + case STEREO_EYE_RIGHT: + nTexX0 = width; + nTexX1 = width*2; + nTexWidth *= 2; + break; + } + + pRenderContext->DrawScreenSpaceRectangle( m_pFreezeFrame, x, y, width, height, + nTexX0, nTexY0, nTexX1-1, nTexY1-1, nTexWidth, nTexHeight ); + + //Fake a fade during freezeframe view. + if ( g_flFreezeFlash >= gpGlobals->curtime && engine->IsTakingScreenshot() == false ) + { + // Overlay screen fade on entire screen + IMaterial* pMaterial = m_TranslucentSingleColor; + + int iFadeAlpha = FREEZECAM_SNAPSHOT_FADE_SPEED * ( g_flFreezeFlash - gpGlobals->curtime ); + + iFadeAlpha = MIN( iFadeAlpha, 255 ); + iFadeAlpha = MAX( 0, iFadeAlpha ); + + pMaterial->AlphaModulate( iFadeAlpha * ( 1.0f / 255.0f ) ); + pMaterial->ColorModulate( 1.0f, 1.0f, 1.0f ); + pMaterial->SetMaterialVarFlag( MATERIAL_VAR_IGNOREZ, true ); + + pRenderContext->DrawScreenSpaceRectangle( pMaterial, x, y, width, height, 0, 0, width-1, height-1, width, height ); + } + +#if defined( _X360 ) + pRenderContext->PopVertexShaderGPRAllocation(); +#endif +} + +//----------------------------------------------------------------------------- +// Pops a water render target +//----------------------------------------------------------------------------- +bool CBaseWorldView::AdjustView( float waterHeight ) +{ + if( m_DrawFlags & DF_RENDER_REFRACTION ) + { + ITexture *pTexture = GetWaterRefractionTexture(); + + // Use the aspect ratio of the main view! So, don't recompute it here + x = y = 0; + width = pTexture->GetActualWidth(); + height = pTexture->GetActualHeight(); + + return true; + } + + if( m_DrawFlags & DF_RENDER_REFLECTION ) + { + ITexture *pTexture = GetWaterReflectionTexture(); + + // If the main view is overriding the projection matrix (for Stereo or + // some other nefarious purpose) make sure to include any Y offset in + // the custom projection matrix in our reflected overridden projection + // matrix. + if( m_bViewToProjectionOverride ) + { + m_ViewToProjection[1][2] = -m_ViewToProjection[1][2]; + } + + // Use the aspect ratio of the main view! So, don't recompute it here + x = y = 0; + width = pTexture->GetActualWidth(); + height = pTexture->GetActualHeight(); + angles[0] = -angles[0]; + angles[2] = -angles[2]; + origin[2] -= 2.0f * ( origin[2] - (waterHeight)); + return true; + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Pops a water render target +//----------------------------------------------------------------------------- +void CBaseWorldView::PushView( float waterHeight ) +{ + float spread = 2.0f; + if( m_DrawFlags & DF_FUDGE_UP ) + { + waterHeight += spread; + } + else + { + waterHeight -= spread; + } + + MaterialHeightClipMode_t clipMode = MATERIAL_HEIGHTCLIPMODE_DISABLE; + if ( ( m_DrawFlags & DF_CLIP_Z ) && mat_clipz.GetBool() ) + { + if( m_DrawFlags & DF_CLIP_BELOW ) + { + clipMode = MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT; + } + else + { + clipMode = MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT; + } + } + + CMatRenderContextPtr pRenderContext( materials ); + + if( m_DrawFlags & DF_RENDER_REFRACTION ) + { + pRenderContext->SetFogZ( waterHeight ); + pRenderContext->SetHeightClipZ( waterHeight ); + pRenderContext->SetHeightClipMode( clipMode ); + + // Have to re-set up the view since we reset the size + render->Push3DView( *this, m_ClearFlags, GetWaterRefractionTexture(), GetFrustum() ); + + return; + } + + if( m_DrawFlags & DF_RENDER_REFLECTION ) + { + ITexture *pTexture = GetWaterReflectionTexture(); + + pRenderContext->SetFogZ( waterHeight ); + + bool bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping(); + if( bSoftwareUserClipPlane && ( origin[2] > waterHeight - r_eyewaterepsilon.GetFloat() ) ) + { + waterHeight = origin[2] + r_eyewaterepsilon.GetFloat(); + } + + pRenderContext->SetHeightClipZ( waterHeight ); + pRenderContext->SetHeightClipMode( clipMode ); + + render->Push3DView( *this, m_ClearFlags, pTexture, GetFrustum() ); + + SetLightmapScaleForWater(); + return; + } + + if ( m_ClearFlags & ( VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_STENCIL ) ) + { + if ( m_ClearFlags & VIEW_CLEAR_OBEY_STENCIL ) + { + pRenderContext->ClearBuffersObeyStencil( m_ClearFlags & VIEW_CLEAR_COLOR, m_ClearFlags & VIEW_CLEAR_DEPTH ); + } + else + { + pRenderContext->ClearBuffers( m_ClearFlags & VIEW_CLEAR_COLOR, m_ClearFlags & VIEW_CLEAR_DEPTH, m_ClearFlags & VIEW_CLEAR_STENCIL ); + } + } + + pRenderContext->SetHeightClipMode( clipMode ); + if ( clipMode != MATERIAL_HEIGHTCLIPMODE_DISABLE ) + { + pRenderContext->SetHeightClipZ( waterHeight ); + } +} + + +//----------------------------------------------------------------------------- +// Pops a water render target +//----------------------------------------------------------------------------- +void CBaseWorldView::PopView() +{ + CMatRenderContextPtr pRenderContext( materials ); + + pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE ); + if( m_DrawFlags & (DF_RENDER_REFRACTION | DF_RENDER_REFLECTION) ) + { + if ( IsX360() ) + { + // these renders paths used their surfaces, so blit their results + if ( m_DrawFlags & DF_RENDER_REFRACTION ) + { + pRenderContext->CopyRenderTargetToTextureEx( GetWaterRefractionTexture(), NULL, NULL ); + } + if ( m_DrawFlags & DF_RENDER_REFLECTION ) + { + pRenderContext->CopyRenderTargetToTextureEx( GetWaterReflectionTexture(), NULL, NULL ); + } + } + + render->PopView( GetFrustum() ); + if (SavedLinearLightMapScale.x>=0) + { + pRenderContext->SetToneMappingScaleLinear(SavedLinearLightMapScale); + SavedLinearLightMapScale.x=-1; + } + } +} + + +//----------------------------------------------------------------------------- +// Draws the world + entities +//----------------------------------------------------------------------------- +void CBaseWorldView::DrawSetup( float waterHeight, int nSetupFlags, float waterZAdjust, int iForceViewLeaf ) +{ + int savedViewID = g_CurrentViewID; + g_CurrentViewID = VIEW_ILLEGAL; + + bool bViewChanged = AdjustView( waterHeight ); + + if ( bViewChanged ) + { + render->Push3DView( *this, 0, NULL, GetFrustum() ); + } + + render->BeginUpdateLightmaps(); + + bool bDrawEntities = ( nSetupFlags & DF_DRAW_ENTITITES ) != 0; + bool bDrawReflection = ( nSetupFlags & DF_RENDER_REFLECTION ) != 0; + BuildWorldRenderLists( bDrawEntities, iForceViewLeaf, true, false, bDrawReflection ? &waterHeight : NULL ); + + PruneWorldListInfo(); + + if ( bDrawEntities ) + { + BuildRenderableRenderLists( savedViewID ); + } + + render->EndUpdateLightmaps(); + + if ( bViewChanged ) + { + render->PopView( GetFrustum() ); + } + +#ifdef TF_CLIENT_DLL + bool bVisionOverride = ( localplayer_visionflags.GetInt() & ( 0x01 ) ); // Pyro-vision Goggles + + if ( savedViewID == VIEW_MAIN && bVisionOverride && pyro_dof.GetBool() ) + { + SSAO_DepthPass(); + } +#endif + + g_CurrentViewID = savedViewID; +} + + +void MaybeInvalidateLocalPlayerAnimation() +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( ( pPlayer != NULL ) && pPlayer->InFirstPersonView() ) + { + // We sometimes need different animation for the main view versus the shadow rendering, + // so we need to reset the cache to ensure this actually happens. + pPlayer->InvalidateBoneCache(); + + C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); + if ( pWeapon != NULL ) + { + pWeapon->InvalidateBoneCache(); + } + +#if defined USES_ECON_ITEMS + // ...and all the things you're wearing/holding/etc + int NumWearables = pPlayer->GetNumWearables(); + for ( int i = 0; i < NumWearables; ++i ) + { + CEconWearable* pItem = pPlayer->GetWearable ( i ); + if ( pItem != NULL ) + { + pItem->InvalidateBoneCache(); + } + } +#endif // USES_ECON_ITEMS + + } +} + +void CBaseWorldView::DrawExecute( float waterHeight, view_id_t viewID, float waterZAdjust ) +{ + int savedViewID = g_CurrentViewID; + + // @MULTICORE (toml 8/16/2006): rethink how, where, and when this is done... + g_CurrentViewID = VIEW_SHADOW_DEPTH_TEXTURE; + MaybeInvalidateLocalPlayerAnimation(); + g_pClientShadowMgr->ComputeShadowTextures( *this, m_pWorldListInfo->m_LeafCount, m_pWorldListInfo->m_pLeafList ); + MaybeInvalidateLocalPlayerAnimation(); + + // Make sure sound doesn't stutter + engine->Sound_ExtraUpdate(); + + g_CurrentViewID = viewID; + + // Update our render view flags. + int iDrawFlagsBackup = m_DrawFlags; + m_DrawFlags |= m_pMainView->GetBaseDrawFlags(); + + PushView( waterHeight ); + + CMatRenderContextPtr pRenderContext( materials ); + +#if defined( _X360 ) + pRenderContext->PushVertexShaderGPRAllocation( 32 ); +#endif + + ITexture *pSaveFrameBufferCopyTexture = pRenderContext->GetFrameBufferCopyTexture( 0 ); + if ( engine->GetDXSupportLevel() >= 80 ) + { + pRenderContext->SetFrameBufferCopyTexture( GetPowerOfTwoFrameBufferTexture() ); + } + + pRenderContext.SafeRelease(); + + ERenderDepthMode DepthMode = DEPTH_MODE_NORMAL; + + if ( m_DrawFlags & DF_DRAW_ENTITITES ) + { + DrawWorld( waterZAdjust ); + DrawOpaqueRenderables( DepthMode ); + +#ifdef TF_CLIENT_DLL + bool bVisionOverride = ( localplayer_visionflags.GetInt() & ( 0x01 ) ); // Pyro-vision Goggles + + if ( g_CurrentViewID == VIEW_MAIN && bVisionOverride && pyro_dof.GetBool() ) // Pyro-vision Goggles + { + DrawDepthOfField(); + } +#endif + DrawTranslucentRenderables( false, false ); + DrawNoZBufferTranslucentRenderables(); + } + else + { + DrawWorld( waterZAdjust ); + +#ifdef TF_CLIENT_DLL + bool bVisionOverride = ( localplayer_visionflags.GetInt() & ( 0x01 ) ); // Pyro-vision Goggles + + if ( g_CurrentViewID == VIEW_MAIN && bVisionOverride && pyro_dof.GetBool() ) // Pyro-vision Goggles + { + DrawDepthOfField(); + } +#endif + // Draw translucent world brushes only, no entities + DrawTranslucentWorldInLeaves( false ); + } + + // issue the pixel visibility tests for sub-views + if ( !IsMainView( CurrentViewID() ) && CurrentViewID() != VIEW_INTRO_CAMERA ) + { + PixelVisibility_EndCurrentView(); + } + + pRenderContext.GetFrom( materials ); + pRenderContext->SetFrameBufferCopyTexture( pSaveFrameBufferCopyTexture ); + PopView(); + + m_DrawFlags = iDrawFlagsBackup; + + g_CurrentViewID = savedViewID; + +#if defined( _X360 ) + pRenderContext->PopVertexShaderGPRAllocation(); +#endif +} + + +void CBaseWorldView::SSAO_DepthPass() +{ + if ( !g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_0() ) + { + return; + } + +#if 1 + VPROF_BUDGET( "CSimpleWorldView::SSAO_DepthPass", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + + int savedViewID = g_CurrentViewID; + g_CurrentViewID = VIEW_SSAO; + + ITexture *pSSAO = materials->FindTexture( "_rt_ResolvedFullFrameDepth", TEXTURE_GROUP_RENDER_TARGET ); + + CMatRenderContextPtr pRenderContext( materials ); + + pRenderContext->ClearColor4ub( 255, 255, 255, 255 ); + +#if defined( _X360 ) + Assert(0); // rebalance this if we ever use this on 360 + pRenderContext->PushVertexShaderGPRAllocation( 112 ); //almost all work is done in vertex shaders for depth rendering, max out their threads +#endif + + pRenderContext.SafeRelease(); + + if( IsPC() ) + { + render->Push3DView( (*this), VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, pSSAO, GetFrustum() ); + } + else if( IsX360() ) + { + render->Push3DView( (*this), VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, pSSAO, GetFrustum() ); + } + + MDLCACHE_CRITICAL_SECTION(); + + engine->Sound_ExtraUpdate(); // Make sure sound doesn't stutter + + m_DrawFlags |= DF_SSAO_DEPTH_PASS; + + { + VPROF_BUDGET( "DrawWorld", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + DrawWorld( 0.0f ); + } + + // Draw opaque and translucent renderables with appropriate override materials + // OVERRIDE_SSAO_DEPTH_WRITE is OK with a NULL material pointer + modelrender->ForcedMaterialOverride( NULL, OVERRIDE_SSAO_DEPTH_WRITE ); + + { + VPROF_BUDGET( "DrawOpaqueRenderables", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + DrawOpaqueRenderables( DEPTH_MODE_SSA0 ); + } + +#if 0 + if ( m_bRenderFlashlightDepthTranslucents || r_flashlightdepth_drawtranslucents.GetBool() ) + { + VPROF_BUDGET( "DrawTranslucentRenderables", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING ); + DrawTranslucentRenderables( false, true ); + } +#endif + + modelrender->ForcedMaterialOverride( 0 ); + + m_DrawFlags &= ~DF_SSAO_DEPTH_PASS; + + pRenderContext.GetFrom( materials ); + + if( IsX360() ) + { + //Resolve() the depth texture here. Before the pop so the copy will recognize that the resolutions are the same + pRenderContext->CopyRenderTargetToTextureEx( NULL, -1, NULL, NULL ); + } + + render->PopView( GetFrustum() ); + +#if defined( _X360 ) + pRenderContext->PopVertexShaderGPRAllocation(); +#endif + + pRenderContext.SafeRelease(); + + g_CurrentViewID = savedViewID; +#endif +} + + +void CBaseWorldView::DrawDepthOfField( ) +{ + if ( !g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_0() ) + { + return; + } + + CMatRenderContextPtr pRenderContext( materials ); + + ITexture *pSmallFB0 = materials->FindTexture( "_rt_smallfb0", TEXTURE_GROUP_RENDER_TARGET ); + ITexture *pSmallFB1 = materials->FindTexture( "_rt_smallfb1", TEXTURE_GROUP_RENDER_TARGET ); + + Rect_t DestRect; + int w = pSmallFB0->GetActualWidth(); + int h = pSmallFB0->GetActualHeight(); + DestRect.x = 0; + DestRect.y = 0; + DestRect.width = w; + DestRect.height = h; + + pRenderContext->CopyRenderTargetToTextureEx( pSmallFB0, 0, NULL, &DestRect ); + + IMaterial *pPyroBlurXMaterial = materials->FindMaterial( "dev/pyro_blur_filter_x", TEXTURE_GROUP_OTHER ); + IMaterial *pPyroBlurYMaterial = materials->FindMaterial( "dev/pyro_blur_filter_y", TEXTURE_GROUP_OTHER ); + + pRenderContext->PushRenderTargetAndViewport( pSmallFB1, 0, 0, w, h ); + pRenderContext->DrawScreenSpaceRectangle( pPyroBlurYMaterial, 0, 0, w, h, 0, 0, w - 1, h - 1, w, h ); + pRenderContext->PopRenderTargetAndViewport(); + + pRenderContext->PushRenderTargetAndViewport( pSmallFB0, 0, 0, w, h ); + pRenderContext->DrawScreenSpaceRectangle( pPyroBlurXMaterial, 0, 0, w, h, 0, 0, w - 1, h - 1, w, h ); + pRenderContext->PopRenderTargetAndViewport(); + + IMaterial *pPyroDepthOfFieldMaterial = materials->FindMaterial( "dev/pyro_dof", TEXTURE_GROUP_OTHER ); + + pRenderContext->DrawScreenSpaceRectangle( pPyroDepthOfFieldMaterial, x, y, width, height, 0, 0, width-1, height-1, width, height ); +} + +//----------------------------------------------------------------------------- +// Draws the scene when there's no water or only cheap water +//----------------------------------------------------------------------------- +void CSimpleWorldView::Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, ViewCustomVisibility_t *pCustomVisibility ) +{ + BaseClass::Setup( view ); + + m_ClearFlags = nClearFlags; + m_DrawFlags = DF_DRAW_ENTITITES; + + if ( !waterInfo.m_bOpaqueWater ) + { + m_DrawFlags |= DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER; + } + else + { + bool bViewIntersectsWater = DoesViewPlaneIntersectWater( fogInfo.m_flWaterHeight, fogInfo.m_nVisibleFogVolume ); + if( bViewIntersectsWater ) + { + // have to draw both sides if we can see both. + m_DrawFlags |= DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER; + } + else if ( fogInfo.m_bEyeInFogVolume ) + { + m_DrawFlags |= DF_RENDER_UNDERWATER; + } + else + { + m_DrawFlags |= DF_RENDER_ABOVEWATER; + } + } + if ( waterInfo.m_bDrawWaterSurface ) + { + m_DrawFlags |= DF_RENDER_WATER; + } + + if ( !fogInfo.m_bEyeInFogVolume && bDrawSkybox ) + { + m_DrawFlags |= DF_DRAWSKYBOX; + } + + m_pCustomVisibility = pCustomVisibility; + m_fogInfo = fogInfo; +} + + +//----------------------------------------------------------------------------- +// Draws the scene when there's no water or only cheap water +//----------------------------------------------------------------------------- +void CSimpleWorldView::Draw() +{ + VPROF( "CViewRender::ViewDrawScene_NoWater" ); + + CMatRenderContextPtr pRenderContext( materials ); + PIXEVENT( pRenderContext, "CSimpleWorldView::Draw" ); + +#if defined( _X360 ) + pRenderContext->PushVertexShaderGPRAllocation( 32 ); //lean toward pixel shader threads +#endif + + pRenderContext.SafeRelease(); + + DrawSetup( 0, m_DrawFlags, 0 ); + + if ( !m_fogInfo.m_bEyeInFogVolume ) + { + EnableWorldFog(); + } + else + { + m_ClearFlags |= VIEW_CLEAR_COLOR; + + SetFogVolumeState( m_fogInfo, false ); + + pRenderContext.GetFrom( materials ); + + unsigned char ucFogColor[3]; + pRenderContext->GetFogColor( ucFogColor ); + pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); + } + + pRenderContext.SafeRelease(); + + DrawExecute( 0, CurrentViewID(), 0 ); + + pRenderContext.GetFrom( materials ); + pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); + +#if defined( _X360 ) + pRenderContext->PopVertexShaderGPRAllocation(); +#endif +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CBaseWaterView::CalcWaterEyeAdjustments( const VisibleFogVolumeInfo_t &fogInfo, + float &newWaterHeight, float &waterZAdjust, bool bSoftwareUserClipPlane ) +{ + if( !bSoftwareUserClipPlane ) + { + newWaterHeight = fogInfo.m_flWaterHeight; + waterZAdjust = 0.0f; + return; + } + + newWaterHeight = fogInfo.m_flWaterHeight; + float eyeToWaterZDelta = origin[2] - fogInfo.m_flWaterHeight; + float epsilon = r_eyewaterepsilon.GetFloat(); + waterZAdjust = 0.0f; + if( fabs( eyeToWaterZDelta ) < epsilon ) + { + if( eyeToWaterZDelta > 0 ) + { + newWaterHeight = origin[2] - epsilon; + } + else + { + newWaterHeight = origin[2] + epsilon; + } + waterZAdjust = newWaterHeight - fogInfo.m_flWaterHeight; + } + + // Warning( "view.origin[2]: %f newWaterHeight: %f fogInfo.m_flWaterHeight: %f waterZAdjust: %f\n", + // ( float )view.origin[2], newWaterHeight, fogInfo.m_flWaterHeight, waterZAdjust ); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CBaseWaterView::CSoftwareIntersectionView::Setup( bool bAboveWater ) +{ + BaseClass::Setup( *GetOuter() ); + + m_DrawFlags = 0; + m_DrawFlags = ( bAboveWater ) ? DF_RENDER_UNDERWATER : DF_RENDER_ABOVEWATER; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CBaseWaterView::CSoftwareIntersectionView::Draw() +{ + DrawSetup( GetOuter()->m_waterHeight, m_DrawFlags, GetOuter()->m_waterZAdjust ); + DrawExecute( GetOuter()->m_waterHeight, CurrentViewID(), GetOuter()->m_waterZAdjust ); +} + +//----------------------------------------------------------------------------- +// Draws the scene when the view point is above the level of the water +//----------------------------------------------------------------------------- +void CAboveWaterView::Setup( const CViewSetup &view, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo ) +{ + BaseClass::Setup( view ); + + m_bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping(); + + CalcWaterEyeAdjustments( fogInfo, m_waterHeight, m_waterZAdjust, m_bSoftwareUserClipPlane ); + + // BROKEN STUFF! + if ( m_waterZAdjust == 0.0f ) + { + m_bSoftwareUserClipPlane = false; + } + + m_DrawFlags = DF_RENDER_ABOVEWATER | DF_DRAW_ENTITITES; + m_ClearFlags = VIEW_CLEAR_DEPTH; + +#ifdef PORTAL + if( g_pPortalRender->ShouldObeyStencilForClears() ) + m_ClearFlags |= VIEW_CLEAR_OBEY_STENCIL; +#endif + + if ( bDrawSkybox ) + { + m_DrawFlags |= DF_DRAWSKYBOX; + } + + if ( waterInfo.m_bDrawWaterSurface ) + { + m_DrawFlags |= DF_RENDER_WATER; + } + if ( !waterInfo.m_bRefract && !waterInfo.m_bOpaqueWater ) + { + m_DrawFlags |= DF_RENDER_UNDERWATER; + } + + m_fogInfo = fogInfo; + m_waterInfo = waterInfo; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CAboveWaterView::Draw() +{ + VPROF( "CViewRender::ViewDrawScene_EyeAboveWater" ); + + // eye is outside of water + + CMatRenderContextPtr pRenderContext( materials ); + + // render the reflection + if( m_waterInfo.m_bReflect ) + { + m_ReflectionView.Setup( m_waterInfo.m_bReflectEntities ); + m_pMainView->AddViewToScene( &m_ReflectionView ); + } + + bool bViewIntersectsWater = false; + + // render refraction + if ( m_waterInfo.m_bRefract ) + { + m_RefractionView.Setup(); + m_pMainView->AddViewToScene( &m_RefractionView ); + + if( !m_bSoftwareUserClipPlane ) + { + bViewIntersectsWater = DoesViewPlaneIntersectWater( m_fogInfo.m_flWaterHeight, m_fogInfo.m_nVisibleFogVolume ); + } + } + else if ( !( m_DrawFlags & DF_DRAWSKYBOX ) ) + { + m_ClearFlags |= VIEW_CLEAR_COLOR; + } + +#ifdef PORTAL + if( g_pPortalRender->ShouldObeyStencilForClears() ) + m_ClearFlags |= VIEW_CLEAR_OBEY_STENCIL; +#endif + + // NOTE!!!!! YOU CAN ONLY DO THIS IF YOU HAVE HARDWARE USER CLIP PLANES!!!!!! + bool bHardwareUserClipPlanes = !g_pMaterialSystemHardwareConfig->UseFastClipping(); + if( bViewIntersectsWater && bHardwareUserClipPlanes ) + { + // This is necessary to keep the non-water fogged world from drawing underwater in + // the case where we want to partially see into the water. + m_DrawFlags |= DF_CLIP_Z | DF_CLIP_BELOW; + } + + // render the world + DrawSetup( m_waterHeight, m_DrawFlags, m_waterZAdjust ); + EnableWorldFog(); + DrawExecute( m_waterHeight, CurrentViewID(), m_waterZAdjust ); + + if ( m_waterInfo.m_bRefract ) + { + if ( m_bSoftwareUserClipPlane ) + { + m_SoftwareIntersectionView.Setup( true ); + m_SoftwareIntersectionView.Draw( ); + } + else if ( bViewIntersectsWater ) + { + m_IntersectionView.Setup(); + m_pMainView->AddViewToScene( &m_IntersectionView ); + } + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CAboveWaterView::CReflectionView::Setup( bool bReflectEntities ) +{ + BaseClass::Setup( *GetOuter() ); + + m_ClearFlags = VIEW_CLEAR_DEPTH; + + // NOTE: Clearing the color is unnecessary since we're drawing the skybox + // and dest-alpha is never used in the reflection + m_DrawFlags = DF_RENDER_REFLECTION | DF_CLIP_Z | DF_CLIP_BELOW | + DF_RENDER_ABOVEWATER; + + // NOTE: This will cause us to draw the 2d skybox in the reflection + // (which we want to do instead of drawing the 3d skybox) + m_DrawFlags |= DF_DRAWSKYBOX; + + if( bReflectEntities ) + { + m_DrawFlags |= DF_DRAW_ENTITITES; + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CAboveWaterView::CReflectionView::Draw() +{ +#ifdef PORTAL + g_pPortalRender->WaterRenderingHandler_PreReflection(); +#endif + + // Store off view origin and angles and set the new view + int nSaveViewID = CurrentViewID(); + SetupCurrentView( origin, angles, VIEW_REFLECTION ); + + // Disable occlusion visualization in reflection + bool bVisOcclusion = r_visocclusion.GetInt(); + r_visocclusion.SetValue( 0 ); + + DrawSetup( GetOuter()->m_fogInfo.m_flWaterHeight, m_DrawFlags, 0.0f, GetOuter()->m_fogInfo.m_nVisibleFogVolumeLeaf ); + + EnableWorldFog(); + DrawExecute( GetOuter()->m_fogInfo.m_flWaterHeight, VIEW_REFLECTION, 0.0f ); + + r_visocclusion.SetValue( bVisOcclusion ); + +#ifdef PORTAL + // deal with stencil + g_pPortalRender->WaterRenderingHandler_PostReflection(); +#endif + + // finish off the view and restore the previous view. + SetupCurrentView( origin, angles, ( view_id_t )nSaveViewID ); + + // This is here for multithreading + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Flush(); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CAboveWaterView::CRefractionView::Setup() +{ + BaseClass::Setup( *GetOuter() ); + + m_ClearFlags = VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH; + + m_DrawFlags = DF_RENDER_REFRACTION | DF_CLIP_Z | + DF_RENDER_UNDERWATER | DF_FUDGE_UP | + DF_DRAW_ENTITITES ; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CAboveWaterView::CRefractionView::Draw() +{ +#ifdef PORTAL + g_pPortalRender->WaterRenderingHandler_PreRefraction(); +#endif + + // Store off view origin and angles and set the new view + int nSaveViewID = CurrentViewID(); + SetupCurrentView( origin, angles, VIEW_REFRACTION ); + + DrawSetup( GetOuter()->m_waterHeight, m_DrawFlags, GetOuter()->m_waterZAdjust ); + + SetFogVolumeState( GetOuter()->m_fogInfo, true ); + SetClearColorToFogColor(); + DrawExecute( GetOuter()->m_waterHeight, VIEW_REFRACTION, GetOuter()->m_waterZAdjust ); + +#ifdef PORTAL + // deal with stencil + g_pPortalRender->WaterRenderingHandler_PostRefraction(); +#endif + + // finish off the view. restore the previous view. + SetupCurrentView( origin, angles, ( view_id_t )nSaveViewID ); + + // This is here for multithreading + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); + pRenderContext->Flush(); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CAboveWaterView::CIntersectionView::Setup() +{ + BaseClass::Setup( *GetOuter() ); + m_DrawFlags = DF_RENDER_UNDERWATER | DF_CLIP_Z | DF_DRAW_ENTITITES; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CAboveWaterView::CIntersectionView::Draw() +{ + DrawSetup( GetOuter()->m_fogInfo.m_flWaterHeight, m_DrawFlags, 0 ); + + SetFogVolumeState( GetOuter()->m_fogInfo, true ); + SetClearColorToFogColor( ); + DrawExecute( GetOuter()->m_fogInfo.m_flWaterHeight, VIEW_NONE, 0 ); + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); +} + + +//----------------------------------------------------------------------------- +// Draws the scene when the view point is under the level of the water +//----------------------------------------------------------------------------- +void CUnderWaterView::Setup( const CViewSetup &view, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo ) +{ + BaseClass::Setup( view ); + + m_bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping(); + + CalcWaterEyeAdjustments( fogInfo, m_waterHeight, m_waterZAdjust, m_bSoftwareUserClipPlane ); + + IMaterial *pWaterMaterial = fogInfo.m_pFogVolumeMaterial; + if (engine->GetDXSupportLevel() >= 90 ) // screen voerlays underwater are a dx9 feature + { + IMaterialVar *pScreenOverlayVar = pWaterMaterial->FindVar( "$underwateroverlay", NULL, false ); + if ( pScreenOverlayVar && ( pScreenOverlayVar->IsDefined() ) ) + { + char const *pOverlayName = pScreenOverlayVar->GetStringValue(); + if ( pOverlayName[0] != '0' ) // fixme!!! + { + IMaterial *pOverlayMaterial = materials->FindMaterial( pOverlayName, TEXTURE_GROUP_OTHER ); + m_pMainView->SetWaterOverlayMaterial( pOverlayMaterial ); + } + } + } + // NOTE: We're not drawing the 2d skybox under water since it's assumed to not be visible. + + // render the world underwater + // Clear the color to get the appropriate underwater fog color + m_DrawFlags = DF_FUDGE_UP | DF_RENDER_UNDERWATER | DF_DRAW_ENTITITES; + m_ClearFlags = VIEW_CLEAR_DEPTH; + + if( !m_bSoftwareUserClipPlane ) + { + m_DrawFlags |= DF_CLIP_Z; + } + if ( waterInfo.m_bDrawWaterSurface ) + { + m_DrawFlags |= DF_RENDER_WATER; + } + if ( !waterInfo.m_bRefract && !waterInfo.m_bOpaqueWater ) + { + m_DrawFlags |= DF_RENDER_ABOVEWATER; + } + + m_fogInfo = fogInfo; + m_waterInfo = waterInfo; + m_bDrawSkybox = bDrawSkybox; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CUnderWaterView::Draw() +{ + // FIXME: The 3d skybox shouldn't be drawn when the eye is under water + + VPROF( "CViewRender::ViewDrawScene_EyeUnderWater" ); + + CMatRenderContextPtr pRenderContext( materials ); + + // render refraction (out of water) + if ( m_waterInfo.m_bRefract ) + { + m_RefractionView.Setup( ); + m_pMainView->AddViewToScene( &m_RefractionView ); + } + + if ( !m_waterInfo.m_bRefract ) + { + SetFogVolumeState( m_fogInfo, true ); + unsigned char ucFogColor[3]; + pRenderContext->GetFogColor( ucFogColor ); + pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); + } + + DrawSetup( m_waterHeight, m_DrawFlags, m_waterZAdjust ); + SetFogVolumeState( m_fogInfo, false ); + DrawExecute( m_waterHeight, CurrentViewID(), m_waterZAdjust ); + m_ClearFlags = 0; + + if( m_waterZAdjust != 0.0f && m_bSoftwareUserClipPlane && m_waterInfo.m_bRefract ) + { + m_SoftwareIntersectionView.Setup( false ); + m_SoftwareIntersectionView.Draw( ); + } + pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); + +} + + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CUnderWaterView::CRefractionView::Setup() +{ + BaseClass::Setup( *GetOuter() ); + // NOTE: Refraction renders into the back buffer, over the top of the 3D skybox + // It is then blitted out into the refraction target. This is so that + // we only have to set up 3d sky vis once, and only render it once also! + m_DrawFlags = DF_CLIP_Z | + DF_CLIP_BELOW | DF_RENDER_ABOVEWATER | + DF_DRAW_ENTITITES; + + m_ClearFlags = VIEW_CLEAR_DEPTH; + if ( GetOuter()->m_bDrawSkybox ) + { + m_ClearFlags |= VIEW_CLEAR_COLOR; + m_DrawFlags |= DF_DRAWSKYBOX | DF_CLIP_SKYBOX; + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CUnderWaterView::CRefractionView::Draw() +{ + CMatRenderContextPtr pRenderContext( materials ); + SetFogVolumeState( GetOuter()->m_fogInfo, true ); + unsigned char ucFogColor[3]; + pRenderContext->GetFogColor( ucFogColor ); + pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 ); + + DrawSetup( GetOuter()->m_waterHeight, m_DrawFlags, GetOuter()->m_waterZAdjust ); + + EnableWorldFog(); + DrawExecute( GetOuter()->m_waterHeight, VIEW_REFRACTION, GetOuter()->m_waterZAdjust ); + + Rect_t srcRect; + srcRect.x = x; + srcRect.y = y; + srcRect.width = width; + srcRect.height = height; + + // Optionally write the rendered image to a debug texture + if ( g_bDumpRenderTargets ) + { + DumpTGAofRenderTarget( width, height, "WaterRefract" ); + } + + ITexture *pTexture = GetWaterRefractionTexture(); + pRenderContext->CopyRenderTargetToTextureEx( pTexture, 0, &srcRect, NULL ); +} + + +//----------------------------------------------------------------------------- +// +// Reflective glass view starts here +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Draws the scene when the view contains reflective glass +//----------------------------------------------------------------------------- +void CReflectiveGlassView::Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, + const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane ) +{ + BaseClass::Setup( view, nClearFlags, bDrawSkybox, fogInfo, waterInfo, NULL ); + m_ReflectionPlane = reflectionPlane; +} + + +bool CReflectiveGlassView::AdjustView( float flWaterHeight ) +{ + ITexture *pTexture = GetWaterReflectionTexture(); + + // Use the aspect ratio of the main view! So, don't recompute it here + x = y = 0; + width = pTexture->GetActualWidth(); + height = pTexture->GetActualHeight(); + + // Reflect the camera origin + vectors around the reflection plane + float flDist = DotProduct( origin, m_ReflectionPlane.normal ) - m_ReflectionPlane.dist; + VectorMA( origin, - 2.0f * flDist, m_ReflectionPlane.normal, origin ); + + Vector vecForward, vecUp; + AngleVectors( angles, &vecForward, NULL, &vecUp ); + + float flDot = DotProduct( vecForward, m_ReflectionPlane.normal ); + VectorMA( vecForward, - 2.0f * flDot, m_ReflectionPlane.normal, vecForward ); + + flDot = DotProduct( vecUp, m_ReflectionPlane.normal ); + VectorMA( vecUp, - 2.0f * flDot, m_ReflectionPlane.normal, vecUp ); + + VectorAngles( vecForward, vecUp, angles ); + return true; +} + +void CReflectiveGlassView::PushView( float waterHeight ) +{ + render->Push3DView( *this, m_ClearFlags, GetWaterReflectionTexture(), GetFrustum() ); + + Vector4D plane; + VectorCopy( m_ReflectionPlane.normal, plane.AsVector3D() ); + plane.w = m_ReflectionPlane.dist + 0.1f; + + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->PushCustomClipPlane( plane.Base() ); +} + +void CReflectiveGlassView::PopView( ) +{ + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->PopCustomClipPlane( ); + render->PopView( GetFrustum() ); +} + + +//----------------------------------------------------------------------------- +// Renders reflective or refractive parts of glass +//----------------------------------------------------------------------------- +void CReflectiveGlassView::Draw() +{ + VPROF( "CReflectiveGlassView::Draw" ); + + CMatRenderContextPtr pRenderContext( materials ); + PIXEVENT( pRenderContext, "CReflectiveGlassView::Draw" ); + + // Disable occlusion visualization in reflection + bool bVisOcclusion = r_visocclusion.GetInt(); + r_visocclusion.SetValue( 0 ); + + BaseClass::Draw(); + + r_visocclusion.SetValue( bVisOcclusion ); + + pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); + pRenderContext->Flush(); +} + + + +//----------------------------------------------------------------------------- +// Draws the scene when the view contains reflective glass +//----------------------------------------------------------------------------- +void CRefractiveGlassView::Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, + const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane ) +{ + BaseClass::Setup( view, nClearFlags, bDrawSkybox, fogInfo, waterInfo, NULL ); + m_ReflectionPlane = reflectionPlane; +} + + +bool CRefractiveGlassView::AdjustView( float flWaterHeight ) +{ + ITexture *pTexture = GetWaterRefractionTexture(); + + // Use the aspect ratio of the main view! So, don't recompute it here + x = y = 0; + width = pTexture->GetActualWidth(); + height = pTexture->GetActualHeight(); + return true; +} + + +void CRefractiveGlassView::PushView( float waterHeight ) +{ + render->Push3DView( *this, m_ClearFlags, GetWaterRefractionTexture(), GetFrustum() ); + + Vector4D plane; + VectorMultiply( m_ReflectionPlane.normal, -1, plane.AsVector3D() ); + plane.w = -m_ReflectionPlane.dist + 0.1f; + + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->PushCustomClipPlane( plane.Base() ); +} + + +void CRefractiveGlassView::PopView( ) +{ + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->PopCustomClipPlane( ); + render->PopView( GetFrustum() ); +} + + + +//----------------------------------------------------------------------------- +// Renders reflective or refractive parts of glass +//----------------------------------------------------------------------------- +void CRefractiveGlassView::Draw() +{ + VPROF( "CRefractiveGlassView::Draw" ); + + CMatRenderContextPtr pRenderContext( materials ); + PIXEVENT( pRenderContext, "CRefractiveGlassView::Draw" ); + + BaseClass::Draw(); + + pRenderContext->ClearColor4ub( 0, 0, 0, 255 ); + pRenderContext->Flush(); +} diff --git a/mp/src/public/vgui/ISurface.h b/mp/src/public/vgui/ISurface.h index 0ccc8157..ddac7c9c 100644 --- a/mp/src/public/vgui/ISurface.h +++ b/mp/src/public/vgui/ISurface.h @@ -1,410 +1,410 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -//===========================================================================// - -#ifndef ISURFACE_H -#define ISURFACE_H - -#ifdef _WIN32 -#pragma once -#endif - -#include -#include // CreateHTML, PaintHTML -#include "tier1/interface.h" -#include "bitmap/imageformat.h" - -#include "appframework/IAppSystem.h" -#include "mathlib/vector2d.h" // must be before the namespace line -#include - -#include "IVguiMatInfo.h" - -#ifdef CreateFont -#undef CreateFont -#endif - -#ifdef PlaySound -#undef PlaySound -#endif - -class Color; -class ITexture; - -namespace vgui -{ - -class IImage; -class Image; -class Point; - -// handles -typedef unsigned long HCursor; -typedef unsigned long HTexture; -typedef unsigned long HFont; - - -//SRC only defines - - -struct Vertex_t -{ - Vertex_t() {} - Vertex_t( const Vector2D &pos, const Vector2D &coord = Vector2D( 0, 0 ) ) - { - m_Position = pos; - m_TexCoord = coord; - } - void Init( const Vector2D &pos, const Vector2D &coord = Vector2D( 0, 0 ) ) - { - m_Position = pos; - m_TexCoord = coord; - } - - Vector2D m_Position; - Vector2D m_TexCoord; -}; - - -enum FontDrawType_t -{ - // Use the "additive" value from the scheme file - FONT_DRAW_DEFAULT = 0, - - // Overrides - FONT_DRAW_NONADDITIVE, - FONT_DRAW_ADDITIVE, - - FONT_DRAW_TYPE_COUNT = 2, -}; - - -// Refactor these two -struct CharRenderInfo -{ - // Text pos - int x, y; - // Top left and bottom right - // This is now a pointer to an array maintained by the surface, to avoid copying the data on the 360 - Vertex_t *verts; - int textureId; - int abcA; - int abcB; - int abcC; - int fontTall; - HFont currentFont; - // In: - FontDrawType_t drawType; - wchar_t ch; - - // Out - bool valid; - // In/Out (true by default) - bool shouldclip; -}; - - -struct IntRect -{ - int x0; - int y0; - int x1; - int y1; -}; - -//----------------------------------------------------------------------------- -// Purpose: Wraps contextless windows system functions -//----------------------------------------------------------------------------- -class ISurface : public IAppSystem -{ -public: - // call to Shutdown surface; surface can no longer be used after this is called - virtual void Shutdown() = 0; - - // frame - virtual void RunFrame() = 0; - - // hierarchy root - virtual VPANEL GetEmbeddedPanel() = 0; - virtual void SetEmbeddedPanel( VPANEL pPanel ) = 0; - - // drawing context - virtual void PushMakeCurrent(VPANEL panel, bool useInsets) = 0; - virtual void PopMakeCurrent(VPANEL panel) = 0; - - // rendering functions - virtual void DrawSetColor(int r, int g, int b, int a) = 0; - virtual void DrawSetColor(Color col) = 0; - - virtual void DrawFilledRect(int x0, int y0, int x1, int y1) = 0; - virtual void DrawFilledRectArray( IntRect *pRects, int numRects ) = 0; - virtual void DrawOutlinedRect(int x0, int y0, int x1, int y1) = 0; - - virtual void DrawLine(int x0, int y0, int x1, int y1) = 0; - virtual void DrawPolyLine(int *px, int *py, int numPoints) = 0; - - virtual void DrawSetTextFont(HFont font) = 0; - virtual void DrawSetTextColor(int r, int g, int b, int a) = 0; - virtual void DrawSetTextColor(Color col) = 0; - virtual void DrawSetTextPos(int x, int y) = 0; - virtual void DrawGetTextPos(int& x,int& y) = 0; - virtual void DrawPrintText(const wchar_t *text, int textLen, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; - virtual void DrawUnicodeChar(wchar_t wch, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; - - virtual void DrawFlushText() = 0; // flushes any buffered text (for rendering optimizations) - virtual IHTML *CreateHTMLWindow(vgui::IHTMLEvents *events,VPANEL context)=0; - virtual void PaintHTMLWindow(vgui::IHTML *htmlwin) =0; - virtual void DeleteHTMLWindow(IHTML *htmlwin)=0; - - enum ETextureFormat - { - eTextureFormat_RGBA, - eTextureFormat_BGRA, - eTextureFormat_BGRA_Opaque, // bgra format but alpha is always 255, CEF does this, we can use this fact for better perf on win32 gdi - }; - - virtual int DrawGetTextureId( char const *filename ) = 0; - virtual bool DrawGetTextureFile(int id, char *filename, int maxlen ) = 0; - virtual void DrawSetTextureFile(int id, const char *filename, int hardwareFilter, bool forceReload) = 0; - virtual void DrawSetTextureRGBA(int id, const unsigned char *rgba, int wide, int tall, int hardwareFilter, bool forceReload)=0; - virtual void DrawSetTexture(int id) = 0; - virtual void DrawGetTextureSize(int id, int &wide, int &tall) = 0; - virtual void DrawTexturedRect(int x0, int y0, int x1, int y1) = 0; - virtual bool IsTextureIDValid(int id) = 0; - virtual bool DeleteTextureByID(int id) = 0; - - virtual int CreateNewTextureID( bool procedural = false ) = 0; - - virtual void GetScreenSize(int &wide, int &tall) = 0; - virtual void SetAsTopMost(VPANEL panel, bool state) = 0; - virtual void BringToFront(VPANEL panel) = 0; - virtual void SetForegroundWindow (VPANEL panel) = 0; - virtual void SetPanelVisible(VPANEL panel, bool state) = 0; - virtual void SetMinimized(VPANEL panel, bool state) = 0; - virtual bool IsMinimized(VPANEL panel) = 0; - virtual void FlashWindow(VPANEL panel, bool state) = 0; - virtual void SetTitle(VPANEL panel, const wchar_t *title) = 0; - virtual void SetAsToolBar(VPANEL panel, bool state) = 0; // removes the window's task bar entry (for context menu's, etc.) - - // windows stuff - virtual void CreatePopup(VPANEL panel, bool minimised, bool showTaskbarIcon = true, bool disabled = false, bool mouseInput = true , bool kbInput = true) = 0; - virtual void SwapBuffers(VPANEL panel) = 0; - virtual void Invalidate(VPANEL panel) = 0; - virtual void SetCursor(HCursor cursor) = 0; - virtual void SetCursorAlwaysVisible( bool visible ) = 0; - virtual bool IsCursorVisible() = 0; - virtual void ApplyChanges() = 0; - virtual bool IsWithin(int x, int y) = 0; - virtual bool HasFocus() = 0; - - // returns true if the surface supports minimize & maximize capabilities - enum SurfaceFeature_e - { - ANTIALIASED_FONTS = 1, - DROPSHADOW_FONTS = 2, - ESCAPE_KEY = 3, - OPENING_NEW_HTML_WINDOWS = 4, - FRAME_MINIMIZE_MAXIMIZE = 5, - OUTLINE_FONTS = 6, - DIRECT_HWND_RENDER = 7, - }; - virtual bool SupportsFeature(SurfaceFeature_e feature) = 0; - - // restricts what gets drawn to one panel and it's children - // currently only works in the game - virtual void RestrictPaintToSinglePanel(VPANEL panel) = 0; - - // these two functions obselete, use IInput::SetAppModalSurface() instead - virtual void SetModalPanel(VPANEL ) = 0; - virtual VPANEL GetModalPanel() = 0; - - virtual void UnlockCursor() = 0; - virtual void LockCursor() = 0; - virtual void SetTranslateExtendedKeys(bool state) = 0; - virtual VPANEL GetTopmostPopup() = 0; - - // engine-only focus handling (replacing WM_FOCUS windows handling) - virtual void SetTopLevelFocus(VPANEL panel) = 0; - - // fonts - // creates an empty handle to a vgui font. windows fonts can be add to this via SetFontGlyphSet(). - virtual HFont CreateFont() = 0; - - // adds to the font - enum EFontFlags - { - FONTFLAG_NONE, - FONTFLAG_ITALIC = 0x001, - FONTFLAG_UNDERLINE = 0x002, - FONTFLAG_STRIKEOUT = 0x004, - FONTFLAG_SYMBOL = 0x008, - FONTFLAG_ANTIALIAS = 0x010, - FONTFLAG_GAUSSIANBLUR = 0x020, - FONTFLAG_ROTARY = 0x040, - FONTFLAG_DROPSHADOW = 0x080, - FONTFLAG_ADDITIVE = 0x100, - FONTFLAG_OUTLINE = 0x200, - FONTFLAG_CUSTOM = 0x400, // custom generated font - never fall back to asian compatibility mode - FONTFLAG_BITMAP = 0x800, // compiled bitmap font - no fallbacks - }; - - virtual bool SetFontGlyphSet(HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int nRangeMin = 0, int nRangeMax = 0) = 0; - - // adds a custom font file (only supports true type font files (.ttf) for now) - virtual bool AddCustomFontFile(const char *fontName, const char *fontFileName) = 0; - - // returns the details about the font - virtual int GetFontTall(HFont font) = 0; - virtual int GetFontTallRequested(HFont font) = 0; - virtual int GetFontAscent(HFont font, wchar_t wch) = 0; - virtual bool IsFontAdditive(HFont font) = 0; - virtual void GetCharABCwide(HFont font, int ch, int &a, int &b, int &c) = 0; - virtual int GetCharacterWidth(HFont font, int ch) = 0; - virtual void GetTextSize(HFont font, const wchar_t *text, int &wide, int &tall) = 0; - - // notify icons?!? - virtual VPANEL GetNotifyPanel() = 0; - virtual void SetNotifyIcon(VPANEL context, HTexture icon, VPANEL panelToReceiveMessages, const char *text) = 0; - - // plays a sound - virtual void PlaySound(const char *fileName) = 0; - - //!! these functions should not be accessed directly, but only through other vgui items - //!! need to move these to seperate interface - virtual int GetPopupCount() = 0; - virtual VPANEL GetPopup(int index) = 0; - virtual bool ShouldPaintChildPanel(VPANEL childPanel) = 0; - virtual bool RecreateContext(VPANEL panel) = 0; - virtual void AddPanel(VPANEL panel) = 0; - virtual void ReleasePanel(VPANEL panel) = 0; - virtual void MovePopupToFront(VPANEL panel) = 0; - virtual void MovePopupToBack(VPANEL panel) = 0; - - virtual void SolveTraverse(VPANEL panel, bool forceApplySchemeSettings = false) = 0; - virtual void PaintTraverse(VPANEL panel) = 0; - - virtual void EnableMouseCapture(VPANEL panel, bool state) = 0; - - // returns the size of the workspace - virtual void GetWorkspaceBounds(int &x, int &y, int &wide, int &tall) = 0; - - // gets the absolute coordinates of the screen (in windows space) - virtual void GetAbsoluteWindowBounds(int &x, int &y, int &wide, int &tall) = 0; - - // gets the base resolution used in proportional mode - virtual void GetProportionalBase( int &width, int &height ) = 0; - - virtual void CalculateMouseVisible() = 0; - virtual bool NeedKBInput() = 0; - - virtual bool HasCursorPosFunctions() = 0; - virtual void SurfaceGetCursorPos(int &x, int &y) = 0; - virtual void SurfaceSetCursorPos(int x, int y) = 0; - - // SRC only functions!!! - virtual void DrawTexturedLine( const Vertex_t &a, const Vertex_t &b ) = 0; - virtual void DrawOutlinedCircle(int x, int y, int radius, int segments) = 0; - virtual void DrawTexturedPolyLine( const Vertex_t *p,int n ) = 0; // (Note: this connects the first and last points). - virtual void DrawTexturedSubRect( int x0, int y0, int x1, int y1, float texs0, float text0, float texs1, float text1 ) = 0; - virtual void DrawTexturedPolygon(int n, Vertex_t *pVertice, bool bClipVertices = true ) = 0; - virtual const wchar_t *GetTitle(VPANEL panel) = 0; - virtual bool IsCursorLocked( void ) const = 0; - virtual void SetWorkspaceInsets( int left, int top, int right, int bottom ) = 0; - - // Lower level char drawing code, call DrawGet then pass in info to DrawRender - virtual bool DrawGetUnicodeCharRenderInfo( wchar_t ch, CharRenderInfo& info ) = 0; - virtual void DrawRenderCharFromInfo( const CharRenderInfo& info ) = 0; - - // global alpha setting functions - // affect all subsequent draw calls - shouldn't normally be used directly, only in Panel::PaintTraverse() - virtual void DrawSetAlphaMultiplier( float alpha /* [0..1] */ ) = 0; - virtual float DrawGetAlphaMultiplier() = 0; - - // web browser - virtual void SetAllowHTMLJavaScript( bool state ) = 0; - - // video mode changing - virtual void OnScreenSizeChanged( int nOldWidth, int nOldHeight ) = 0; - - virtual vgui::HCursor CreateCursorFromFile( char const *curOrAniFile, char const *pPathID = 0 ) = 0; - - // create IVguiMatInfo object ( IMaterial wrapper in VguiMatSurface, NULL in CWin32Surface ) - virtual IVguiMatInfo *DrawGetTextureMatInfoFactory( int id ) = 0; - - virtual void PaintTraverseEx(VPANEL panel, bool paintPopups = false ) = 0; - - virtual float GetZPos() const = 0; - - // From the Xbox - virtual void SetPanelForInput( VPANEL vpanel ) = 0; - virtual void DrawFilledRectFastFade( int x0, int y0, int x1, int y1, int fadeStartPt, int fadeEndPt, unsigned int alpha0, unsigned int alpha1, bool bHorizontal ) = 0; - virtual void DrawFilledRectFade( int x0, int y0, int x1, int y1, unsigned int alpha0, unsigned int alpha1, bool bHorizontal ) = 0; - virtual void DrawSetTextureRGBAEx(int id, const unsigned char *rgba, int wide, int tall, ImageFormat imageFormat ) = 0; - virtual void DrawSetTextScale(float sx, float sy) = 0; - virtual bool SetBitmapFontGlyphSet(HFont font, const char *windowsFontName, float scalex, float scaley, int flags) = 0; - // adds a bitmap font file - virtual bool AddBitmapFontFile(const char *fontFileName) = 0; - // sets a symbol for the bitmap font - virtual void SetBitmapFontName( const char *pName, const char *pFontFilename ) = 0; - // gets the bitmap font filename - virtual const char *GetBitmapFontName( const char *pName ) = 0; - virtual void ClearTemporaryFontCache( void ) = 0; - - virtual IImage *GetIconImageForFullPath( char const *pFullPath ) = 0; - virtual void DrawUnicodeString( const wchar_t *pwString, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; - virtual void PrecacheFontCharacters(HFont font, const wchar_t *pCharacters) = 0; - // Console-only. Get the string to use for the current video mode for layout files. - virtual const char *GetResolutionKey( void ) const = 0; - - virtual const char *GetFontName( HFont font ) = 0; - virtual const char *GetFontFamilyName( HFont font ) = 0; - virtual void GetKernedCharWidth( HFont font, wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA ) = 0; - - virtual bool ForceScreenSizeOverride( bool bState, int wide, int tall ) = 0; - // LocalToScreen, ParentLocalToScreen fixups for explicit PaintTraverse calls on Panels not at 0, 0 position - virtual bool ForceScreenPosOffset( bool bState, int x, int y ) = 0; - virtual void OffsetAbsPos( int &x, int &y ) = 0; - - - // Causes fonts to get reloaded, etc. - virtual void ResetFontCaches() = 0; - - virtual int GetTextureNumFrames( int id ) = 0; - virtual void DrawSetTextureFrame( int id, int nFrame, unsigned int *pFrameCache ) = 0; - virtual bool IsScreenSizeOverrideActive( void ) = 0; - virtual bool IsScreenPosOverrideActive( void ) = 0; - - virtual void DestroyTextureID( int id ) = 0; - - virtual void DrawUpdateRegionTextureRGBA( int nTextureID, int x, int y, const unsigned char *pchData, int wide, int tall, ImageFormat imageFormat ) = 0; - virtual bool BHTMLWindowNeedsPaint(IHTML *htmlwin) = 0 ; - - virtual const char *GetWebkitHTMLUserAgentString() = 0; - - virtual IHTMLChromeController *AccessChromeHTMLController() = 0; - - // the origin of the viewport on the framebuffer (Which might not be 0,0 for stereo) - virtual void SetFullscreenViewportAndRenderTarget( int x, int y, int w, int h, ITexture *pRenderTarget ) = 0; - virtual void GetFullscreenViewport( int & x, int & y, int & w, int & h ) = 0; - virtual void PushFullscreenViewport() = 0; - virtual void PopFullscreenViewport() = 0; - - // handles support for software cursors - virtual void SetSoftwareCursor( bool bUseSoftwareCursor ) = 0; - virtual void PaintSoftwareCursor() = 0; - - - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // !! WARNING! YOU MUST NOT ADD YOUR NEW METHOD HERE OR YOU WILL BREAK MODS !! - // !! Add your new stuff to the bottom of IMatSystemSurface instead. !! - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -}; - -} - -#define VGUI_SURFACE_INTERFACE_VERSION "VGUI_Surface030" - -#endif // ISURFACE_H +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#ifndef ISURFACE_H +#define ISURFACE_H + +#ifdef _WIN32 +#pragma once +#endif + +#include +#include // CreateHTML, PaintHTML +#include "tier1/interface.h" +#include "bitmap/imageformat.h" + +#include "appframework/IAppSystem.h" +#include "mathlib/vector2d.h" // must be before the namespace line +#include + +#include "IVguiMatInfo.h" + +#ifdef CreateFont +#undef CreateFont +#endif + +#ifdef PlaySound +#undef PlaySound +#endif + +class Color; +class ITexture; + +namespace vgui +{ + +class IImage; +class Image; +class Point; + +// handles +typedef unsigned long HCursor; +typedef unsigned long HTexture; +typedef unsigned long HFont; + + +//SRC only defines + + +struct Vertex_t +{ + Vertex_t() {} + Vertex_t( const Vector2D &pos, const Vector2D &coord = Vector2D( 0, 0 ) ) + { + m_Position = pos; + m_TexCoord = coord; + } + void Init( const Vector2D &pos, const Vector2D &coord = Vector2D( 0, 0 ) ) + { + m_Position = pos; + m_TexCoord = coord; + } + + Vector2D m_Position; + Vector2D m_TexCoord; +}; + + +enum FontDrawType_t +{ + // Use the "additive" value from the scheme file + FONT_DRAW_DEFAULT = 0, + + // Overrides + FONT_DRAW_NONADDITIVE, + FONT_DRAW_ADDITIVE, + + FONT_DRAW_TYPE_COUNT = 2, +}; + + +// Refactor these two +struct CharRenderInfo +{ + // Text pos + int x, y; + // Top left and bottom right + // This is now a pointer to an array maintained by the surface, to avoid copying the data on the 360 + Vertex_t *verts; + int textureId; + int abcA; + int abcB; + int abcC; + int fontTall; + HFont currentFont; + // In: + FontDrawType_t drawType; + wchar_t ch; + + // Out + bool valid; + // In/Out (true by default) + bool shouldclip; +}; + + +struct IntRect +{ + int x0; + int y0; + int x1; + int y1; +}; + +//----------------------------------------------------------------------------- +// Purpose: Wraps contextless windows system functions +//----------------------------------------------------------------------------- +class ISurface : public IAppSystem +{ +public: + // call to Shutdown surface; surface can no longer be used after this is called + virtual void Shutdown() = 0; + + // frame + virtual void RunFrame() = 0; + + // hierarchy root + virtual VPANEL GetEmbeddedPanel() = 0; + virtual void SetEmbeddedPanel( VPANEL pPanel ) = 0; + + // drawing context + virtual void PushMakeCurrent(VPANEL panel, bool useInsets) = 0; + virtual void PopMakeCurrent(VPANEL panel) = 0; + + // rendering functions + virtual void DrawSetColor(int r, int g, int b, int a) = 0; + virtual void DrawSetColor(Color col) = 0; + + virtual void DrawFilledRect(int x0, int y0, int x1, int y1) = 0; + virtual void DrawFilledRectArray( IntRect *pRects, int numRects ) = 0; + virtual void DrawOutlinedRect(int x0, int y0, int x1, int y1) = 0; + + virtual void DrawLine(int x0, int y0, int x1, int y1) = 0; + virtual void DrawPolyLine(int *px, int *py, int numPoints) = 0; + + virtual void DrawSetTextFont(HFont font) = 0; + virtual void DrawSetTextColor(int r, int g, int b, int a) = 0; + virtual void DrawSetTextColor(Color col) = 0; + virtual void DrawSetTextPos(int x, int y) = 0; + virtual void DrawGetTextPos(int& x,int& y) = 0; + virtual void DrawPrintText(const wchar_t *text, int textLen, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; + virtual void DrawUnicodeChar(wchar_t wch, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; + + virtual void DrawFlushText() = 0; // flushes any buffered text (for rendering optimizations) + virtual IHTML *CreateHTMLWindow(vgui::IHTMLEvents *events,VPANEL context)=0; + virtual void PaintHTMLWindow(vgui::IHTML *htmlwin) =0; + virtual void DeleteHTMLWindow(IHTML *htmlwin)=0; + + enum ETextureFormat + { + eTextureFormat_RGBA, + eTextureFormat_BGRA, + eTextureFormat_BGRA_Opaque, // bgra format but alpha is always 255, CEF does this, we can use this fact for better perf on win32 gdi + }; + + virtual int DrawGetTextureId( char const *filename ) = 0; + virtual bool DrawGetTextureFile(int id, char *filename, int maxlen ) = 0; + virtual void DrawSetTextureFile(int id, const char *filename, int hardwareFilter, bool forceReload) = 0; + virtual void DrawSetTextureRGBA(int id, const unsigned char *rgba, int wide, int tall, int hardwareFilter, bool forceReload)=0; + virtual void DrawSetTexture(int id) = 0; + virtual void DrawGetTextureSize(int id, int &wide, int &tall) = 0; + virtual void DrawTexturedRect(int x0, int y0, int x1, int y1) = 0; + virtual bool IsTextureIDValid(int id) = 0; + virtual bool DeleteTextureByID(int id) = 0; + + virtual int CreateNewTextureID( bool procedural = false ) = 0; + + virtual void GetScreenSize(int &wide, int &tall) = 0; + virtual void SetAsTopMost(VPANEL panel, bool state) = 0; + virtual void BringToFront(VPANEL panel) = 0; + virtual void SetForegroundWindow (VPANEL panel) = 0; + virtual void SetPanelVisible(VPANEL panel, bool state) = 0; + virtual void SetMinimized(VPANEL panel, bool state) = 0; + virtual bool IsMinimized(VPANEL panel) = 0; + virtual void FlashWindow(VPANEL panel, bool state) = 0; + virtual void SetTitle(VPANEL panel, const wchar_t *title) = 0; + virtual void SetAsToolBar(VPANEL panel, bool state) = 0; // removes the window's task bar entry (for context menu's, etc.) + + // windows stuff + virtual void CreatePopup(VPANEL panel, bool minimised, bool showTaskbarIcon = true, bool disabled = false, bool mouseInput = true , bool kbInput = true) = 0; + virtual void SwapBuffers(VPANEL panel) = 0; + virtual void Invalidate(VPANEL panel) = 0; + virtual void SetCursor(HCursor cursor) = 0; + virtual void SetCursorAlwaysVisible( bool visible ) = 0; + virtual bool IsCursorVisible() = 0; + virtual void ApplyChanges() = 0; + virtual bool IsWithin(int x, int y) = 0; + virtual bool HasFocus() = 0; + + // returns true if the surface supports minimize & maximize capabilities + enum SurfaceFeature_e + { + ANTIALIASED_FONTS = 1, + DROPSHADOW_FONTS = 2, + ESCAPE_KEY = 3, + OPENING_NEW_HTML_WINDOWS = 4, + FRAME_MINIMIZE_MAXIMIZE = 5, + OUTLINE_FONTS = 6, + DIRECT_HWND_RENDER = 7, + }; + virtual bool SupportsFeature(SurfaceFeature_e feature) = 0; + + // restricts what gets drawn to one panel and it's children + // currently only works in the game + virtual void RestrictPaintToSinglePanel(VPANEL panel) = 0; + + // these two functions obselete, use IInput::SetAppModalSurface() instead + virtual void SetModalPanel(VPANEL ) = 0; + virtual VPANEL GetModalPanel() = 0; + + virtual void UnlockCursor() = 0; + virtual void LockCursor() = 0; + virtual void SetTranslateExtendedKeys(bool state) = 0; + virtual VPANEL GetTopmostPopup() = 0; + + // engine-only focus handling (replacing WM_FOCUS windows handling) + virtual void SetTopLevelFocus(VPANEL panel) = 0; + + // fonts + // creates an empty handle to a vgui font. windows fonts can be add to this via SetFontGlyphSet(). + virtual HFont CreateFont() = 0; + + // adds to the font + enum EFontFlags + { + FONTFLAG_NONE, + FONTFLAG_ITALIC = 0x001, + FONTFLAG_UNDERLINE = 0x002, + FONTFLAG_STRIKEOUT = 0x004, + FONTFLAG_SYMBOL = 0x008, + FONTFLAG_ANTIALIAS = 0x010, + FONTFLAG_GAUSSIANBLUR = 0x020, + FONTFLAG_ROTARY = 0x040, + FONTFLAG_DROPSHADOW = 0x080, + FONTFLAG_ADDITIVE = 0x100, + FONTFLAG_OUTLINE = 0x200, + FONTFLAG_CUSTOM = 0x400, // custom generated font - never fall back to asian compatibility mode + FONTFLAG_BITMAP = 0x800, // compiled bitmap font - no fallbacks + }; + + virtual bool SetFontGlyphSet(HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int nRangeMin = 0, int nRangeMax = 0) = 0; + + // adds a custom font file (only supports true type font files (.ttf) for now) + virtual bool AddCustomFontFile(const char *fontName, const char *fontFileName) = 0; + + // returns the details about the font + virtual int GetFontTall(HFont font) = 0; + virtual int GetFontTallRequested(HFont font) = 0; + virtual int GetFontAscent(HFont font, wchar_t wch) = 0; + virtual bool IsFontAdditive(HFont font) = 0; + virtual void GetCharABCwide(HFont font, int ch, int &a, int &b, int &c) = 0; + virtual int GetCharacterWidth(HFont font, int ch) = 0; + virtual void GetTextSize(HFont font, const wchar_t *text, int &wide, int &tall) = 0; + + // notify icons?!? + virtual VPANEL GetNotifyPanel() = 0; + virtual void SetNotifyIcon(VPANEL context, HTexture icon, VPANEL panelToReceiveMessages, const char *text) = 0; + + // plays a sound + virtual void PlaySound(const char *fileName) = 0; + + //!! these functions should not be accessed directly, but only through other vgui items + //!! need to move these to seperate interface + virtual int GetPopupCount() = 0; + virtual VPANEL GetPopup(int index) = 0; + virtual bool ShouldPaintChildPanel(VPANEL childPanel) = 0; + virtual bool RecreateContext(VPANEL panel) = 0; + virtual void AddPanel(VPANEL panel) = 0; + virtual void ReleasePanel(VPANEL panel) = 0; + virtual void MovePopupToFront(VPANEL panel) = 0; + virtual void MovePopupToBack(VPANEL panel) = 0; + + virtual void SolveTraverse(VPANEL panel, bool forceApplySchemeSettings = false) = 0; + virtual void PaintTraverse(VPANEL panel) = 0; + + virtual void EnableMouseCapture(VPANEL panel, bool state) = 0; + + // returns the size of the workspace + virtual void GetWorkspaceBounds(int &x, int &y, int &wide, int &tall) = 0; + + // gets the absolute coordinates of the screen (in windows space) + virtual void GetAbsoluteWindowBounds(int &x, int &y, int &wide, int &tall) = 0; + + // gets the base resolution used in proportional mode + virtual void GetProportionalBase( int &width, int &height ) = 0; + + virtual void CalculateMouseVisible() = 0; + virtual bool NeedKBInput() = 0; + + virtual bool HasCursorPosFunctions() = 0; + virtual void SurfaceGetCursorPos(int &x, int &y) = 0; + virtual void SurfaceSetCursorPos(int x, int y) = 0; + + // SRC only functions!!! + virtual void DrawTexturedLine( const Vertex_t &a, const Vertex_t &b ) = 0; + virtual void DrawOutlinedCircle(int x, int y, int radius, int segments) = 0; + virtual void DrawTexturedPolyLine( const Vertex_t *p,int n ) = 0; // (Note: this connects the first and last points). + virtual void DrawTexturedSubRect( int x0, int y0, int x1, int y1, float texs0, float text0, float texs1, float text1 ) = 0; + virtual void DrawTexturedPolygon(int n, Vertex_t *pVertice, bool bClipVertices = true ) = 0; + virtual const wchar_t *GetTitle(VPANEL panel) = 0; + virtual bool IsCursorLocked( void ) const = 0; + virtual void SetWorkspaceInsets( int left, int top, int right, int bottom ) = 0; + + // Lower level char drawing code, call DrawGet then pass in info to DrawRender + virtual bool DrawGetUnicodeCharRenderInfo( wchar_t ch, CharRenderInfo& info ) = 0; + virtual void DrawRenderCharFromInfo( const CharRenderInfo& info ) = 0; + + // global alpha setting functions + // affect all subsequent draw calls - shouldn't normally be used directly, only in Panel::PaintTraverse() + virtual void DrawSetAlphaMultiplier( float alpha /* [0..1] */ ) = 0; + virtual float DrawGetAlphaMultiplier() = 0; + + // web browser + virtual void SetAllowHTMLJavaScript( bool state ) = 0; + + // video mode changing + virtual void OnScreenSizeChanged( int nOldWidth, int nOldHeight ) = 0; + + virtual vgui::HCursor CreateCursorFromFile( char const *curOrAniFile, char const *pPathID = 0 ) = 0; + + // create IVguiMatInfo object ( IMaterial wrapper in VguiMatSurface, NULL in CWin32Surface ) + virtual IVguiMatInfo *DrawGetTextureMatInfoFactory( int id ) = 0; + + virtual void PaintTraverseEx(VPANEL panel, bool paintPopups = false ) = 0; + + virtual float GetZPos() const = 0; + + // From the Xbox + virtual void SetPanelForInput( VPANEL vpanel ) = 0; + virtual void DrawFilledRectFastFade( int x0, int y0, int x1, int y1, int fadeStartPt, int fadeEndPt, unsigned int alpha0, unsigned int alpha1, bool bHorizontal ) = 0; + virtual void DrawFilledRectFade( int x0, int y0, int x1, int y1, unsigned int alpha0, unsigned int alpha1, bool bHorizontal ) = 0; + virtual void DrawSetTextureRGBAEx(int id, const unsigned char *rgba, int wide, int tall, ImageFormat imageFormat ) = 0; + virtual void DrawSetTextScale(float sx, float sy) = 0; + virtual bool SetBitmapFontGlyphSet(HFont font, const char *windowsFontName, float scalex, float scaley, int flags) = 0; + // adds a bitmap font file + virtual bool AddBitmapFontFile(const char *fontFileName) = 0; + // sets a symbol for the bitmap font + virtual void SetBitmapFontName( const char *pName, const char *pFontFilename ) = 0; + // gets the bitmap font filename + virtual const char *GetBitmapFontName( const char *pName ) = 0; + virtual void ClearTemporaryFontCache( void ) = 0; + + virtual IImage *GetIconImageForFullPath( char const *pFullPath ) = 0; + virtual void DrawUnicodeString( const wchar_t *pwString, FontDrawType_t drawType = FONT_DRAW_DEFAULT ) = 0; + virtual void PrecacheFontCharacters(HFont font, const wchar_t *pCharacters) = 0; + // Console-only. Get the string to use for the current video mode for layout files. + virtual const char *GetResolutionKey( void ) const = 0; + + virtual const char *GetFontName( HFont font ) = 0; + virtual const char *GetFontFamilyName( HFont font ) = 0; + virtual void GetKernedCharWidth( HFont font, wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA ) = 0; + + virtual bool ForceScreenSizeOverride( bool bState, int wide, int tall ) = 0; + // LocalToScreen, ParentLocalToScreen fixups for explicit PaintTraverse calls on Panels not at 0, 0 position + virtual bool ForceScreenPosOffset( bool bState, int x, int y ) = 0; + virtual void OffsetAbsPos( int &x, int &y ) = 0; + + + // Causes fonts to get reloaded, etc. + virtual void ResetFontCaches() = 0; + + virtual int GetTextureNumFrames( int id ) = 0; + virtual void DrawSetTextureFrame( int id, int nFrame, unsigned int *pFrameCache ) = 0; + virtual bool IsScreenSizeOverrideActive( void ) = 0; + virtual bool IsScreenPosOverrideActive( void ) = 0; + + virtual void DestroyTextureID( int id ) = 0; + + virtual void DrawUpdateRegionTextureRGBA( int nTextureID, int x, int y, const unsigned char *pchData, int wide, int tall, ImageFormat imageFormat ) = 0; + virtual bool BHTMLWindowNeedsPaint(IHTML *htmlwin) = 0 ; + + virtual const char *GetWebkitHTMLUserAgentString() = 0; + + virtual IHTMLChromeController *AccessChromeHTMLController() = 0; + + // the origin of the viewport on the framebuffer (Which might not be 0,0 for stereo) + virtual void SetFullscreenViewport( int x, int y, int w, int h ) = 0; // this uses NULL for the render target. + virtual void GetFullscreenViewport( int & x, int & y, int & w, int & h ) = 0; + virtual void PushFullscreenViewport() = 0; + virtual void PopFullscreenViewport() = 0; + + // handles support for software cursors + virtual void SetSoftwareCursor( bool bUseSoftwareCursor ) = 0; + virtual void PaintSoftwareCursor() = 0; + + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // !! WARNING! YOU MUST NOT ADD YOUR NEW METHOD HERE OR YOU WILL BREAK MODS !! + // !! Add your new stuff to the bottom of IMatSystemSurface instead. !! + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +}; + +} + +#define VGUI_SURFACE_INTERFACE_VERSION "VGUI_Surface030" + +#endif // ISURFACE_H