aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/viewrender.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/viewrender.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/viewrender.cpp')
-rw-r--r--mp/src/game/client/viewrender.cpp12454
1 files changed, 6227 insertions, 6227 deletions
diff --git a/mp/src/game/client/viewrender.cpp b/mp/src/game/client/viewrender.cpp
index 1bc3a904..7422479b 100644
--- a/mp/src/game/client/viewrender.cpp
+++ b/mp/src/game/client/viewrender.cpp
@@ -1,6227 +1,6227 @@
-//========= 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 "headtrack/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"
-
-// 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<WorldListInfo_t>
-{
- 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<ClientWorldListInfo_t> 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<Entry_t *, unsigned short, CEntryComparator> 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 = VIEW_3DSKY, bool bInvokePreAndPostRender = true, ITexture *pRenderTarget = NULL );
-
- 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
-
-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();
-
- render->Push3DView( viewModelSetup, 0, NULL, GetFrustum() );
-
-#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<CShadowDepthView> 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 );
-
- // 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
- {
- render->Push3DView( view, nClearFlags, NULL, GetFrustum() );
- }
-
- // 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<CFreezeFrameView> 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 );
- }
- 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 );
-
- 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();
- }
-
- // 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();
- }
-
- // 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 = view.m_eStereoEye == STEREO_EYE_RIGHT ? viewFramebufferWidth : 0;
- 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()->SetFullscreenViewport( viewFramebufferX, viewFramebufferY, viewFramebufferWidth, viewFramebufferHeight );
- }
-
- // 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<CReflectiveGlassView> pGlassReflectionView = new CReflectiveGlassView( this );
- pGlassReflectionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, bDrawSkybox, fogVolumeInfo, info, glassReflectionPlane );
- AddViewToScene( pGlassReflectionView );
-
- CRefPtr<CRefractiveGlassView> pGlassRefractionView = new CRefractiveGlassView( this );
- pGlassRefractionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, bDrawSkybox, fogVolumeInfo, info, glassReflectionPlane );
- AddViewToScene( pGlassRefractionView );
- }
-
- CRefPtr<CSimpleWorldView> 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<CAboveWaterView> pAboveWaterView = new CAboveWaterView( this );
- pAboveWaterView->Setup( viewIn, bDrawSkybox, fogVolumeInfo, info );
- AddViewToScene( pAboveWaterView );
- }
- else
- {
- tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CUnderWaterView" );
- CRefPtr<CUnderWaterView> 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<CReflectiveGlassView> pGlassReflectionView = new CReflectiveGlassView( this );
- pGlassReflectionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, glassReflectionPlane );
- AddViewToScene( pGlassReflectionView );
-
- CRefPtr<CRefractiveGlassView> 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<CAboveWaterView> pAboveWaterView = new CAboveWaterView( this );
- pAboveWaterView->Setup( viewIn, drawSkybox, fogInfo, waterInfo );
- AddViewToScene( pAboveWaterView );
- }
- else
- {
- CRefPtr<CUnderWaterView> 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<CPortalSkyboxView> 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> 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<CViewSetup *>(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<C_BaseAnimating *>( 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<C_BaseAnimating *>( 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 )
-{
- 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() );
-
- // 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" );
-
- DrawInternal();
-}
-
-
-#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 );
-
- 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 "headtrack/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"
+
+// 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<WorldListInfo_t>
+{
+ 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<ClientWorldListInfo_t> 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<Entry_t *, unsigned short, CEntryComparator> 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 = VIEW_3DSKY, bool bInvokePreAndPostRender = true, ITexture *pRenderTarget = NULL );
+
+ 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
+
+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();
+
+ render->Push3DView( viewModelSetup, 0, NULL, GetFrustum() );
+
+#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<CShadowDepthView> 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 );
+
+ // 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
+ {
+ render->Push3DView( view, nClearFlags, NULL, GetFrustum() );
+ }
+
+ // 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<CFreezeFrameView> 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 );
+ }
+ 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 );
+
+ 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();
+ }
+
+ // 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();
+ }
+
+ // 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 = view.m_eStereoEye == STEREO_EYE_RIGHT ? viewFramebufferWidth : 0;
+ 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()->SetFullscreenViewport( viewFramebufferX, viewFramebufferY, viewFramebufferWidth, viewFramebufferHeight );
+ }
+
+ // 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<CReflectiveGlassView> pGlassReflectionView = new CReflectiveGlassView( this );
+ pGlassReflectionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, bDrawSkybox, fogVolumeInfo, info, glassReflectionPlane );
+ AddViewToScene( pGlassReflectionView );
+
+ CRefPtr<CRefractiveGlassView> pGlassRefractionView = new CRefractiveGlassView( this );
+ pGlassRefractionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, bDrawSkybox, fogVolumeInfo, info, glassReflectionPlane );
+ AddViewToScene( pGlassRefractionView );
+ }
+
+ CRefPtr<CSimpleWorldView> 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<CAboveWaterView> pAboveWaterView = new CAboveWaterView( this );
+ pAboveWaterView->Setup( viewIn, bDrawSkybox, fogVolumeInfo, info );
+ AddViewToScene( pAboveWaterView );
+ }
+ else
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CUnderWaterView" );
+ CRefPtr<CUnderWaterView> 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<CReflectiveGlassView> pGlassReflectionView = new CReflectiveGlassView( this );
+ pGlassReflectionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, glassReflectionPlane );
+ AddViewToScene( pGlassReflectionView );
+
+ CRefPtr<CRefractiveGlassView> 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<CAboveWaterView> pAboveWaterView = new CAboveWaterView( this );
+ pAboveWaterView->Setup( viewIn, drawSkybox, fogInfo, waterInfo );
+ AddViewToScene( pAboveWaterView );
+ }
+ else
+ {
+ CRefPtr<CUnderWaterView> 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<CPortalSkyboxView> 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> 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<CViewSetup *>(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<C_BaseAnimating *>( 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<C_BaseAnimating *>( 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 )
+{
+ 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() );
+
+ // 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" );
+
+ DrawInternal();
+}
+
+
+#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 );
+
+ 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();
+}