diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/viewrender.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-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.cpp | 12454 |
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(); +} |