Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6263 lines
198 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Responsible for drawing the scene
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include "view.h"
  8. #include "iviewrender.h"
  9. #include "view_shared.h"
  10. #include "ivieweffects.h"
  11. #include "iinput.h"
  12. #include "model_types.h"
  13. #include "clientsideeffects.h"
  14. #include "particlemgr.h"
  15. #include "viewrender.h"
  16. #include "iclientmode.h"
  17. #include "voice_status.h"
  18. #include "glow_overlay.h"
  19. #include "materialsystem/imesh.h"
  20. #include "materialsystem/itexture.h"
  21. #include "materialsystem/imaterial.h"
  22. #include "materialsystem/imaterialvar.h"
  23. #include "materialsystem/imaterialsystem.h"
  24. #include "detailobjectsystem.h"
  25. #include "tier0/vprof.h"
  26. #include "tier1/mempool.h"
  27. #include "vstdlib/jobthread.h"
  28. #include "datacache/imdlcache.h"
  29. #include "engine/IEngineTrace.h"
  30. #include "engine/ivmodelinfo.h"
  31. #include "tier0/icommandline.h"
  32. #include "view_scene.h"
  33. #include "particles_ez.h"
  34. #include "engine/IStaticPropMgr.h"
  35. #include "engine/ivdebugoverlay.h"
  36. #include "c_pixel_visibility.h"
  37. #include "clienteffectprecachesystem.h"
  38. #include "c_rope.h"
  39. #include "c_effects.h"
  40. #include "smoke_fog_overlay.h"
  41. #include "materialsystem/imaterialsystemhardwareconfig.h"
  42. #include "VGuiMatSurface/IMatSystemSurface.h"
  43. #include "vgui_int.h"
  44. #include "ienginevgui.h"
  45. #include "ScreenSpaceEffects.h"
  46. #include "toolframework_client.h"
  47. #include "c_func_reflective_glass.h"
  48. #include "KeyValues.h"
  49. #include "renderparm.h"
  50. #include "studio_stats.h"
  51. #include "con_nprint.h"
  52. #include "clientmode_shared.h"
  53. #include "sourcevr/isourcevirtualreality.h"
  54. #include "client_virtualreality.h"
  55. #ifdef PORTAL
  56. //#include "C_Portal_Player.h"
  57. #include "portal_render_targets.h"
  58. #include "PortalRender.h"
  59. #endif
  60. #if defined( HL2_CLIENT_DLL ) || defined( CSTRIKE_DLL )
  61. #define USE_MONITORS
  62. #endif
  63. #include "rendertexture.h"
  64. #include "viewpostprocess.h"
  65. #include "viewdebug.h"
  66. #if defined USES_ECON_ITEMS
  67. #include "econ_wearable.h"
  68. #endif
  69. #ifdef USE_MONITORS
  70. #include "c_point_camera.h"
  71. #endif // USE_MONITORS
  72. // Projective textures
  73. #include "C_Env_Projected_Texture.h"
  74. // memdbgon must be the last include file in a .cpp file!!!
  75. #include "tier0/memdbgon.h"
  76. static void testfreezeframe_f( void )
  77. {
  78. view->FreezeFrame( 3.0 );
  79. }
  80. static ConCommand test_freezeframe( "test_freezeframe", testfreezeframe_f, "Test the freeze frame code.", FCVAR_CHEAT );
  81. //-----------------------------------------------------------------------------
  82. static ConVar r_visocclusion( "r_visocclusion", "0", FCVAR_CHEAT );
  83. extern ConVar r_flashlightdepthtexture;
  84. extern ConVar vcollide_wireframe;
  85. extern ConVar r_depthoverlay;
  86. extern ConVar mat_viewportscale;
  87. extern ConVar mat_viewportupscale;
  88. extern bool g_bDumpRenderTargets;
  89. //-----------------------------------------------------------------------------
  90. // Convars related to controlling rendering
  91. //-----------------------------------------------------------------------------
  92. static ConVar cl_maxrenderable_dist("cl_maxrenderable_dist", "3000", FCVAR_CHEAT, "Max distance from the camera at which things will be rendered" );
  93. 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?
  94. // Matches the version in the engine
  95. static ConVar r_drawopaqueworld( "r_drawopaqueworld", "1", FCVAR_CHEAT );
  96. static ConVar r_drawtranslucentworld( "r_drawtranslucentworld", "1", FCVAR_CHEAT );
  97. static ConVar r_3dsky( "r_3dsky","1", 0, "Enable the rendering of 3d sky boxes" );
  98. static ConVar r_skybox( "r_skybox","1", FCVAR_CHEAT, "Enable the rendering of sky boxes" );
  99. #ifdef TF_CLIENT_DLL
  100. ConVar r_drawviewmodel( "r_drawviewmodel","1", FCVAR_DONTRECORD );
  101. #else
  102. ConVar r_drawviewmodel( "r_drawviewmodel","1", FCVAR_CHEAT );
  103. #endif
  104. static ConVar r_drawtranslucentrenderables( "r_drawtranslucentrenderables", "1", FCVAR_CHEAT );
  105. static ConVar r_drawopaquerenderables( "r_drawopaquerenderables", "1", FCVAR_CHEAT );
  106. static ConVar r_threaded_renderables( "r_threaded_renderables", "0" );
  107. // FIXME: This is not static because we needed to turn it off for TF2 playtests
  108. ConVar r_DrawDetailProps( "r_DrawDetailProps", "1", FCVAR_NONE, "0=Off, 1=Normal, 2=Wireframe" );
  109. ConVar r_worldlistcache( "r_worldlistcache", "1" );
  110. //-----------------------------------------------------------------------------
  111. // Convars related to fog color
  112. //-----------------------------------------------------------------------------
  113. static ConVar fog_override( "fog_override", "0", FCVAR_CHEAT );
  114. // set any of these to use the maps fog
  115. static ConVar fog_start( "fog_start", "-1", FCVAR_CHEAT );
  116. static ConVar fog_end( "fog_end", "-1", FCVAR_CHEAT );
  117. static ConVar fog_color( "fog_color", "-1 -1 -1", FCVAR_CHEAT );
  118. static ConVar fog_enable( "fog_enable", "1", FCVAR_CHEAT );
  119. static ConVar fog_startskybox( "fog_startskybox", "-1", FCVAR_CHEAT );
  120. static ConVar fog_endskybox( "fog_endskybox", "-1", FCVAR_CHEAT );
  121. static ConVar fog_maxdensityskybox( "fog_maxdensityskybox", "-1", FCVAR_CHEAT );
  122. static ConVar fog_colorskybox( "fog_colorskybox", "-1 -1 -1", FCVAR_CHEAT );
  123. static ConVar fog_enableskybox( "fog_enableskybox", "1", FCVAR_CHEAT );
  124. static ConVar fog_maxdensity( "fog_maxdensity", "-1", FCVAR_CHEAT );
  125. //-----------------------------------------------------------------------------
  126. // Water-related convars
  127. //-----------------------------------------------------------------------------
  128. static ConVar r_debugcheapwater( "r_debugcheapwater", "0", FCVAR_CHEAT );
  129. #ifndef _X360
  130. static ConVar r_waterforceexpensive( "r_waterforceexpensive", "0", FCVAR_ARCHIVE );
  131. #endif
  132. static ConVar r_waterforcereflectentities( "r_waterforcereflectentities", "0", FCVAR_ALLOWED_IN_COMPETITIVE );
  133. static ConVar r_WaterDrawRefraction( "r_WaterDrawRefraction", "1", 0, "Enable water refraction" );
  134. static ConVar r_WaterDrawReflection( "r_WaterDrawReflection", "1", 0, "Enable water reflection" );
  135. static ConVar r_ForceWaterLeaf( "r_ForceWaterLeaf", "1", 0, "Enable for optimization to water - considers view in leaf under water for purposes of culling" );
  136. static ConVar mat_drawwater( "mat_drawwater", "1", FCVAR_CHEAT );
  137. static ConVar mat_clipz( "mat_clipz", "1" );
  138. //-----------------------------------------------------------------------------
  139. // Other convars
  140. //-----------------------------------------------------------------------------
  141. static ConVar r_screenfademinsize( "r_screenfademinsize", "0" );
  142. static ConVar r_screenfademaxsize( "r_screenfademaxsize", "0" );
  143. static ConVar cl_drawmonitors( "cl_drawmonitors", "1" );
  144. static ConVar r_eyewaterepsilon( "r_eyewaterepsilon", "10.0f", FCVAR_CHEAT );
  145. #ifdef TF_CLIENT_DLL
  146. static ConVar pyro_dof( "pyro_dof", "1", FCVAR_ARCHIVE );
  147. #endif
  148. extern ConVar cl_leveloverview;
  149. extern ConVar localplayer_visionflags;
  150. //-----------------------------------------------------------------------------
  151. // Globals
  152. //-----------------------------------------------------------------------------
  153. static Vector g_vecCurrentRenderOrigin(0,0,0);
  154. static QAngle g_vecCurrentRenderAngles(0,0,0);
  155. static Vector g_vecCurrentVForward(0,0,0), g_vecCurrentVRight(0,0,0), g_vecCurrentVUp(0,0,0);
  156. static VMatrix g_matCurrentCamInverse;
  157. bool s_bCanAccessCurrentView = false;
  158. IntroData_t *g_pIntroData = NULL;
  159. static bool g_bRenderingView = false; // For debugging...
  160. static int g_CurrentViewID = VIEW_NONE;
  161. bool g_bRenderingScreenshot = false;
  162. #define FREEZECAM_SNAPSHOT_FADE_SPEED 340
  163. float g_flFreezeFlash = 0.0f;
  164. //-----------------------------------------------------------------------------
  165. CON_COMMAND( r_cheapwaterstart, "" )
  166. {
  167. if( args.ArgC() == 2 )
  168. {
  169. float dist = atof( args[ 1 ] );
  170. view->SetCheapWaterStartDistance( dist );
  171. }
  172. else
  173. {
  174. float start, end;
  175. view->GetWaterLODParams( start, end );
  176. Warning( "r_cheapwaterstart: %f\n", start );
  177. }
  178. }
  179. CON_COMMAND( r_cheapwaterend, "" )
  180. {
  181. if( args.ArgC() == 2 )
  182. {
  183. float dist = atof( args[ 1 ] );
  184. view->SetCheapWaterEndDistance( dist );
  185. }
  186. else
  187. {
  188. float start, end;
  189. view->GetWaterLODParams( start, end );
  190. Warning( "r_cheapwaterend: %f\n", end );
  191. }
  192. }
  193. //-----------------------------------------------------------------------------
  194. // Describes a pruned set of leaves to be rendered this view. Reference counted
  195. // because potentially shared by a number of views
  196. //-----------------------------------------------------------------------------
  197. struct ClientWorldListInfo_t : public CRefCounted1<WorldListInfo_t>
  198. {
  199. ClientWorldListInfo_t()
  200. {
  201. memset( (WorldListInfo_t *)this, 0, sizeof(WorldListInfo_t) );
  202. m_pActualLeafIndex = NULL;
  203. m_bPooledAlloc = false;
  204. }
  205. // Allocate a list intended for pruning
  206. static ClientWorldListInfo_t *AllocPooled( const ClientWorldListInfo_t &exemplar );
  207. // Because we remap leaves to eliminate unused leaves, we need a remap
  208. // when drawing translucent surfaces, which requires the *original* leaf index
  209. // using m_pActualLeafMap[ remapped leaf index ] == actual leaf index
  210. LeafIndex_t *m_pActualLeafIndex;
  211. private:
  212. virtual bool OnFinalRelease();
  213. bool m_bPooledAlloc;
  214. static CObjectPool<ClientWorldListInfo_t> gm_Pool;
  215. };
  216. //-----------------------------------------------------------------------------
  217. //
  218. //-----------------------------------------------------------------------------
  219. class CWorldListCache
  220. {
  221. public:
  222. CWorldListCache()
  223. {
  224. }
  225. void Flush()
  226. {
  227. for ( int i = m_Entries.FirstInorder(); i != m_Entries.InvalidIndex(); i = m_Entries.NextInorder( i ) )
  228. {
  229. delete m_Entries[i];
  230. }
  231. m_Entries.RemoveAll();
  232. }
  233. bool Find( const CViewSetup &viewSetup, IWorldRenderList **ppList, ClientWorldListInfo_t **ppListInfo )
  234. {
  235. Entry_t lookup( viewSetup );
  236. int i = m_Entries.Find( &lookup );
  237. if ( i != m_Entries.InvalidIndex() )
  238. {
  239. Entry_t *pEntry = m_Entries[i];
  240. *ppList = InlineAddRef( pEntry->pList );
  241. *ppListInfo = InlineAddRef( pEntry->pListInfo );
  242. return true;
  243. }
  244. return false;
  245. }
  246. void Add( const CViewSetup &viewSetup, IWorldRenderList *pList, ClientWorldListInfo_t *pListInfo )
  247. {
  248. m_Entries.Insert( new Entry_t( viewSetup, pList, pListInfo ) );
  249. }
  250. private:
  251. struct Entry_t
  252. {
  253. Entry_t( const CViewSetup &viewSetup, IWorldRenderList *pList = NULL, ClientWorldListInfo_t *pListInfo = NULL ) :
  254. pList( ( pList ) ? InlineAddRef( pList ) : NULL ),
  255. pListInfo( ( pListInfo ) ? InlineAddRef( pListInfo ) : NULL )
  256. {
  257. // @NOTE (toml 8/18/2006): because doing memcmp, need to fill all of the fields and the padding!
  258. memset( &m_bOrtho, 0, offsetof(Entry_t, pList ) - offsetof(Entry_t, m_bOrtho ) );
  259. m_bOrtho = viewSetup.m_bOrtho;
  260. m_OrthoLeft = viewSetup.m_OrthoLeft;
  261. m_OrthoTop = viewSetup.m_OrthoTop;
  262. m_OrthoRight = viewSetup.m_OrthoRight;
  263. m_OrthoBottom = viewSetup.m_OrthoBottom;
  264. fov = viewSetup.fov;
  265. origin = viewSetup.origin;
  266. angles = viewSetup.angles;
  267. zNear = viewSetup.zNear;
  268. zFar = viewSetup.zFar;
  269. m_flAspectRatio = viewSetup.m_flAspectRatio;
  270. m_bOffCenter = viewSetup.m_bOffCenter;
  271. m_flOffCenterTop = viewSetup.m_flOffCenterTop;
  272. m_flOffCenterBottom = viewSetup.m_flOffCenterBottom;
  273. m_flOffCenterLeft = viewSetup.m_flOffCenterLeft;
  274. m_flOffCenterRight = viewSetup.m_flOffCenterRight;
  275. }
  276. ~Entry_t()
  277. {
  278. if ( pList )
  279. pList->Release();
  280. if ( pListInfo )
  281. pListInfo->Release();
  282. }
  283. // The fields from CViewSetup that would actually affect the list
  284. float m_OrthoLeft;
  285. float m_OrthoTop;
  286. float m_OrthoRight;
  287. float m_OrthoBottom;
  288. float fov;
  289. Vector origin;
  290. QAngle angles;
  291. float zNear;
  292. float zFar;
  293. float m_flAspectRatio;
  294. float m_flOffCenterTop;
  295. float m_flOffCenterBottom;
  296. float m_flOffCenterLeft;
  297. float m_flOffCenterRight;
  298. bool m_bOrtho;
  299. bool m_bOffCenter;
  300. IWorldRenderList *pList;
  301. ClientWorldListInfo_t *pListInfo;
  302. };
  303. class CEntryComparator
  304. {
  305. public:
  306. CEntryComparator( int ) {}
  307. bool operator!() const { return false; }
  308. bool operator()( const Entry_t *lhs, const Entry_t *rhs ) const
  309. {
  310. return ( memcmp( lhs, rhs, sizeof(Entry_t) - ( sizeof(Entry_t) - offsetof(Entry_t, pList ) ) ) < 0 );
  311. }
  312. };
  313. CUtlRBTree<Entry_t *, unsigned short, CEntryComparator> m_Entries;
  314. };
  315. CWorldListCache g_WorldListCache;
  316. //-----------------------------------------------------------------------------
  317. // Standard 3d skybox view
  318. //-----------------------------------------------------------------------------
  319. class CSkyboxView : public CRendering3dView
  320. {
  321. DECLARE_CLASS( CSkyboxView, CRendering3dView );
  322. public:
  323. CSkyboxView(CViewRender *pMainView) :
  324. CRendering3dView( pMainView ),
  325. m_pSky3dParams( NULL )
  326. {
  327. }
  328. bool Setup( const CViewSetup &view, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible );
  329. void Draw();
  330. protected:
  331. #ifdef PORTAL
  332. virtual bool ShouldDrawPortals() { return false; }
  333. #endif
  334. virtual SkyboxVisibility_t ComputeSkyboxVisibility();
  335. bool GetSkyboxFogEnable();
  336. void Enable3dSkyboxFog( void );
  337. void DrawInternal( view_id_t iSkyBoxViewID, bool bInvokePreAndPostRender, ITexture *pRenderTarget, ITexture *pDepthTarget );
  338. sky3dparams_t * PreRender3dSkyboxWorld( SkyboxVisibility_t nSkyboxVisible );
  339. sky3dparams_t *m_pSky3dParams;
  340. };
  341. //-----------------------------------------------------------------------------
  342. // 3d skybox view when drawing portals
  343. //-----------------------------------------------------------------------------
  344. #ifdef PORTAL
  345. class CPortalSkyboxView : public CSkyboxView
  346. {
  347. DECLARE_CLASS( CPortalSkyboxView, CSkyboxView );
  348. public:
  349. CPortalSkyboxView(CViewRender *pMainView) :
  350. CSkyboxView( pMainView ),
  351. m_pRenderTarget( NULL )
  352. {}
  353. bool Setup( const CViewSetup &view, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible, ITexture *pRenderTarget = NULL );
  354. //Skybox drawing through portals with workarounds to fix area bits, position/scaling, view id's..........
  355. void Draw();
  356. private:
  357. virtual SkyboxVisibility_t ComputeSkyboxVisibility();
  358. ITexture *m_pRenderTarget;
  359. };
  360. #endif
  361. //-----------------------------------------------------------------------------
  362. // Shadow depth texture
  363. //-----------------------------------------------------------------------------
  364. class CShadowDepthView : public CRendering3dView
  365. {
  366. DECLARE_CLASS( CShadowDepthView, CRendering3dView );
  367. public:
  368. CShadowDepthView(CViewRender *pMainView) : CRendering3dView( pMainView ) {}
  369. void Setup( const CViewSetup &shadowViewIn, ITexture *pRenderTarget, ITexture *pDepthTexture );
  370. void Draw();
  371. private:
  372. ITexture *m_pRenderTarget;
  373. ITexture *m_pDepthTexture;
  374. };
  375. //-----------------------------------------------------------------------------
  376. // Freeze frame. Redraws the frame at which it was enabled.
  377. //-----------------------------------------------------------------------------
  378. class CFreezeFrameView : public CRendering3dView
  379. {
  380. DECLARE_CLASS( CFreezeFrameView, CRendering3dView );
  381. public:
  382. CFreezeFrameView(CViewRender *pMainView) : CRendering3dView( pMainView ) {}
  383. void Setup( const CViewSetup &view );
  384. void Draw();
  385. private:
  386. CMaterialReference m_pFreezeFrame;
  387. CMaterialReference m_TranslucentSingleColor;
  388. };
  389. //-----------------------------------------------------------------------------
  390. //
  391. //-----------------------------------------------------------------------------
  392. class CBaseWorldView : public CRendering3dView
  393. {
  394. DECLARE_CLASS( CBaseWorldView, CRendering3dView );
  395. protected:
  396. CBaseWorldView(CViewRender *pMainView) : CRendering3dView( pMainView ) {}
  397. virtual bool AdjustView( float waterHeight );
  398. void DrawSetup( float waterHeight, int flags, float waterZAdjust, int iForceViewLeaf = -1 );
  399. void DrawExecute( float waterHeight, view_id_t viewID, float waterZAdjust );
  400. virtual void PushView( float waterHeight );
  401. virtual void PopView();
  402. void SSAO_DepthPass();
  403. void DrawDepthOfField();
  404. };
  405. //-----------------------------------------------------------------------------
  406. // Draws the scene when there's no water or only cheap water
  407. //-----------------------------------------------------------------------------
  408. class CSimpleWorldView : public CBaseWorldView
  409. {
  410. DECLARE_CLASS( CSimpleWorldView, CBaseWorldView );
  411. public:
  412. CSimpleWorldView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {}
  413. void Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& info, ViewCustomVisibility_t *pCustomVisibility = NULL );
  414. void Draw();
  415. private:
  416. VisibleFogVolumeInfo_t m_fogInfo;
  417. };
  418. //-----------------------------------------------------------------------------
  419. // Base class for scenes with water
  420. //-----------------------------------------------------------------------------
  421. class CBaseWaterView : public CBaseWorldView
  422. {
  423. DECLARE_CLASS( CBaseWaterView, CBaseWorldView );
  424. public:
  425. CBaseWaterView(CViewRender *pMainView) :
  426. CBaseWorldView( pMainView ),
  427. m_SoftwareIntersectionView( pMainView )
  428. {}
  429. // void Setup( const CViewSetup &, const WaterRenderInfo_t& info );
  430. protected:
  431. void CalcWaterEyeAdjustments( const VisibleFogVolumeInfo_t &fogInfo, float &newWaterHeight, float &waterZAdjust, bool bSoftwareUserClipPlane );
  432. class CSoftwareIntersectionView : public CBaseWorldView
  433. {
  434. DECLARE_CLASS( CSoftwareIntersectionView, CBaseWorldView );
  435. public:
  436. CSoftwareIntersectionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {}
  437. void Setup( bool bAboveWater );
  438. void Draw();
  439. private:
  440. CBaseWaterView *GetOuter() { return GET_OUTER( CBaseWaterView, m_SoftwareIntersectionView ); }
  441. };
  442. friend class CSoftwareIntersectionView;
  443. CSoftwareIntersectionView m_SoftwareIntersectionView;
  444. WaterRenderInfo_t m_waterInfo;
  445. float m_waterHeight;
  446. float m_waterZAdjust;
  447. bool m_bSoftwareUserClipPlane;
  448. VisibleFogVolumeInfo_t m_fogInfo;
  449. };
  450. //-----------------------------------------------------------------------------
  451. // Scenes above water
  452. //-----------------------------------------------------------------------------
  453. class CAboveWaterView : public CBaseWaterView
  454. {
  455. DECLARE_CLASS( CAboveWaterView, CBaseWaterView );
  456. public:
  457. CAboveWaterView(CViewRender *pMainView) :
  458. CBaseWaterView( pMainView ),
  459. m_ReflectionView( pMainView ),
  460. m_RefractionView( pMainView ),
  461. m_IntersectionView( pMainView )
  462. {}
  463. void Setup( const CViewSetup &view, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo );
  464. void Draw();
  465. class CReflectionView : public CBaseWorldView
  466. {
  467. DECLARE_CLASS( CReflectionView, CBaseWorldView );
  468. public:
  469. CReflectionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {}
  470. void Setup( bool bReflectEntities );
  471. void Draw();
  472. private:
  473. CAboveWaterView *GetOuter() { return GET_OUTER( CAboveWaterView, m_ReflectionView ); }
  474. };
  475. class CRefractionView : public CBaseWorldView
  476. {
  477. DECLARE_CLASS( CRefractionView, CBaseWorldView );
  478. public:
  479. CRefractionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {}
  480. void Setup();
  481. void Draw();
  482. private:
  483. CAboveWaterView *GetOuter() { return GET_OUTER( CAboveWaterView, m_RefractionView ); }
  484. };
  485. class CIntersectionView : public CBaseWorldView
  486. {
  487. DECLARE_CLASS( CIntersectionView, CBaseWorldView );
  488. public:
  489. CIntersectionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {}
  490. void Setup();
  491. void Draw();
  492. private:
  493. CAboveWaterView *GetOuter() { return GET_OUTER( CAboveWaterView, m_IntersectionView ); }
  494. };
  495. friend class CRefractionView;
  496. friend class CReflectionView;
  497. friend class CIntersectionView;
  498. bool m_bViewIntersectsWater;
  499. CReflectionView m_ReflectionView;
  500. CRefractionView m_RefractionView;
  501. CIntersectionView m_IntersectionView;
  502. };
  503. //-----------------------------------------------------------------------------
  504. // Scenes below water
  505. //-----------------------------------------------------------------------------
  506. class CUnderWaterView : public CBaseWaterView
  507. {
  508. DECLARE_CLASS( CUnderWaterView, CBaseWaterView );
  509. public:
  510. CUnderWaterView(CViewRender *pMainView) :
  511. CBaseWaterView( pMainView ),
  512. m_RefractionView( pMainView )
  513. {}
  514. void Setup( const CViewSetup &view, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& info );
  515. void Draw();
  516. class CRefractionView : public CBaseWorldView
  517. {
  518. DECLARE_CLASS( CRefractionView, CBaseWorldView );
  519. public:
  520. CRefractionView(CViewRender *pMainView) : CBaseWorldView( pMainView ) {}
  521. void Setup();
  522. void Draw();
  523. private:
  524. CUnderWaterView *GetOuter() { return GET_OUTER( CUnderWaterView, m_RefractionView ); }
  525. };
  526. friend class CRefractionView;
  527. bool m_bDrawSkybox; // @MULTICORE (toml 8/17/2006): remove after setup hoisted
  528. CRefractionView m_RefractionView;
  529. };
  530. //-----------------------------------------------------------------------------
  531. // Scenes containing reflective glass
  532. //-----------------------------------------------------------------------------
  533. class CReflectiveGlassView : public CSimpleWorldView
  534. {
  535. DECLARE_CLASS( CReflectiveGlassView, CSimpleWorldView );
  536. public:
  537. CReflectiveGlassView( CViewRender *pMainView ) : BaseClass( pMainView )
  538. {
  539. }
  540. virtual bool AdjustView( float flWaterHeight );
  541. virtual void PushView( float waterHeight );
  542. virtual void PopView( );
  543. void Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane );
  544. void Draw();
  545. cplane_t m_ReflectionPlane;
  546. };
  547. class CRefractiveGlassView : public CSimpleWorldView
  548. {
  549. DECLARE_CLASS( CRefractiveGlassView, CSimpleWorldView );
  550. public:
  551. CRefractiveGlassView( CViewRender *pMainView ) : BaseClass( pMainView )
  552. {
  553. }
  554. virtual bool AdjustView( float flWaterHeight );
  555. virtual void PushView( float waterHeight );
  556. virtual void PopView( );
  557. void Setup( const CViewSetup &view, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane );
  558. void Draw();
  559. cplane_t m_ReflectionPlane;
  560. };
  561. //-----------------------------------------------------------------------------
  562. // Computes draw flags for the engine to build its world surface lists
  563. //-----------------------------------------------------------------------------
  564. static inline unsigned long BuildEngineDrawWorldListFlags( unsigned nDrawFlags )
  565. {
  566. unsigned long nEngineFlags = 0;
  567. if ( nDrawFlags & DF_DRAWSKYBOX )
  568. {
  569. nEngineFlags |= DRAWWORLDLISTS_DRAW_SKYBOX;
  570. }
  571. if ( nDrawFlags & DF_RENDER_ABOVEWATER )
  572. {
  573. nEngineFlags |= DRAWWORLDLISTS_DRAW_STRICTLYABOVEWATER;
  574. nEngineFlags |= DRAWWORLDLISTS_DRAW_INTERSECTSWATER;
  575. }
  576. if ( nDrawFlags & DF_RENDER_UNDERWATER )
  577. {
  578. nEngineFlags |= DRAWWORLDLISTS_DRAW_STRICTLYUNDERWATER;
  579. nEngineFlags |= DRAWWORLDLISTS_DRAW_INTERSECTSWATER;
  580. }
  581. if ( nDrawFlags & DF_RENDER_WATER )
  582. {
  583. nEngineFlags |= DRAWWORLDLISTS_DRAW_WATERSURFACE;
  584. }
  585. if( nDrawFlags & DF_CLIP_SKYBOX )
  586. {
  587. nEngineFlags |= DRAWWORLDLISTS_DRAW_CLIPSKYBOX;
  588. }
  589. if( nDrawFlags & DF_SHADOW_DEPTH_MAP )
  590. {
  591. nEngineFlags |= DRAWWORLDLISTS_DRAW_SHADOWDEPTH;
  592. }
  593. if( nDrawFlags & DF_RENDER_REFRACTION )
  594. {
  595. nEngineFlags |= DRAWWORLDLISTS_DRAW_REFRACTION;
  596. }
  597. if( nDrawFlags & DF_RENDER_REFLECTION )
  598. {
  599. nEngineFlags |= DRAWWORLDLISTS_DRAW_REFLECTION;
  600. }
  601. if( nDrawFlags & DF_SSAO_DEPTH_PASS )
  602. {
  603. nEngineFlags |= DRAWWORLDLISTS_DRAW_SSAO | DRAWWORLDLISTS_DRAW_STRICTLYUNDERWATER | DRAWWORLDLISTS_DRAW_INTERSECTSWATER | DRAWWORLDLISTS_DRAW_STRICTLYABOVEWATER ;
  604. nEngineFlags &= ~( DRAWWORLDLISTS_DRAW_WATERSURFACE | DRAWWORLDLISTS_DRAW_REFRACTION | DRAWWORLDLISTS_DRAW_REFLECTION );
  605. }
  606. return nEngineFlags;
  607. }
  608. //-----------------------------------------------------------------------------
  609. //
  610. //-----------------------------------------------------------------------------
  611. static void SetClearColorToFogColor()
  612. {
  613. unsigned char ucFogColor[3];
  614. CMatRenderContextPtr pRenderContext( materials );
  615. pRenderContext->GetFogColor( ucFogColor );
  616. if( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER )
  617. {
  618. // @MULTICORE (toml 8/16/2006): Find a way to not do this twice in eye above water case
  619. float scale = LinearToGammaFullRange( pRenderContext->GetToneMappingScaleLinear().x );
  620. ucFogColor[0] *= scale;
  621. ucFogColor[1] *= scale;
  622. ucFogColor[2] *= scale;
  623. }
  624. pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 );
  625. }
  626. //-----------------------------------------------------------------------------
  627. // Precache of necessary materials
  628. //-----------------------------------------------------------------------------
  629. #ifdef HL2_CLIENT_DLL
  630. CLIENTEFFECT_REGISTER_BEGIN( PrecacheViewRender )
  631. CLIENTEFFECT_MATERIAL( "scripted/intro_screenspaceeffect" )
  632. CLIENTEFFECT_REGISTER_END()
  633. #endif
  634. CLIENTEFFECT_REGISTER_BEGIN( PrecachePostProcessingEffects )
  635. CLIENTEFFECT_MATERIAL( "dev/blurfiltery_and_add_nohdr" )
  636. CLIENTEFFECT_MATERIAL( "dev/blurfilterx" )
  637. CLIENTEFFECT_MATERIAL( "dev/blurfilterx_nohdr" )
  638. CLIENTEFFECT_MATERIAL( "dev/blurfiltery" )
  639. CLIENTEFFECT_MATERIAL( "dev/blurfiltery_nohdr" )
  640. CLIENTEFFECT_MATERIAL( "dev/bloomadd" )
  641. CLIENTEFFECT_MATERIAL( "dev/downsample" )
  642. #ifdef CSTRIKE_DLL
  643. CLIENTEFFECT_MATERIAL( "dev/downsample_non_hdr_cstrike" )
  644. #else
  645. CLIENTEFFECT_MATERIAL( "dev/downsample_non_hdr" )
  646. #endif
  647. CLIENTEFFECT_MATERIAL( "dev/no_pixel_write" )
  648. CLIENTEFFECT_MATERIAL( "dev/lumcompare" )
  649. CLIENTEFFECT_MATERIAL( "dev/floattoscreen_combine" )
  650. CLIENTEFFECT_MATERIAL( "dev/copyfullframefb_vanilla" )
  651. CLIENTEFFECT_MATERIAL( "dev/copyfullframefb" )
  652. CLIENTEFFECT_MATERIAL( "dev/engine_post" )
  653. CLIENTEFFECT_MATERIAL( "dev/motion_blur" )
  654. CLIENTEFFECT_MATERIAL( "dev/upscale" )
  655. #ifdef TF_CLIENT_DLL
  656. CLIENTEFFECT_MATERIAL( "dev/pyro_blur_filter_y" )
  657. CLIENTEFFECT_MATERIAL( "dev/pyro_blur_filter_x" )
  658. CLIENTEFFECT_MATERIAL( "dev/pyro_dof" )
  659. CLIENTEFFECT_MATERIAL( "dev/pyro_vignette_border" )
  660. CLIENTEFFECT_MATERIAL( "dev/pyro_vignette" )
  661. CLIENTEFFECT_MATERIAL( "dev/pyro_post" )
  662. #endif
  663. CLIENTEFFECT_REGISTER_END_CONDITIONAL( engine->GetDXSupportLevel() >= 90 )
  664. //-----------------------------------------------------------------------------
  665. // Accessors to return the current view being rendered
  666. //-----------------------------------------------------------------------------
  667. const Vector &CurrentViewOrigin()
  668. {
  669. Assert( s_bCanAccessCurrentView );
  670. return g_vecCurrentRenderOrigin;
  671. }
  672. const QAngle &CurrentViewAngles()
  673. {
  674. Assert( s_bCanAccessCurrentView );
  675. return g_vecCurrentRenderAngles;
  676. }
  677. const Vector &CurrentViewForward()
  678. {
  679. Assert( s_bCanAccessCurrentView );
  680. return g_vecCurrentVForward;
  681. }
  682. const Vector &CurrentViewRight()
  683. {
  684. Assert( s_bCanAccessCurrentView );
  685. return g_vecCurrentVRight;
  686. }
  687. const Vector &CurrentViewUp()
  688. {
  689. Assert( s_bCanAccessCurrentView );
  690. return g_vecCurrentVUp;
  691. }
  692. const VMatrix &CurrentWorldToViewMatrix()
  693. {
  694. Assert( s_bCanAccessCurrentView );
  695. return g_matCurrentCamInverse;
  696. }
  697. //-----------------------------------------------------------------------------
  698. // Methods to set the current view/guard access to view parameters
  699. //-----------------------------------------------------------------------------
  700. void AllowCurrentViewAccess( bool allow )
  701. {
  702. s_bCanAccessCurrentView = allow;
  703. }
  704. bool IsCurrentViewAccessAllowed()
  705. {
  706. return s_bCanAccessCurrentView;
  707. }
  708. void SetupCurrentView( const Vector &vecOrigin, const QAngle &angles, view_id_t viewID )
  709. {
  710. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  711. // Store off view origin and angles
  712. g_vecCurrentRenderOrigin = vecOrigin;
  713. g_vecCurrentRenderAngles = angles;
  714. // Compute the world->main camera transform
  715. ComputeCameraVariables( vecOrigin, angles,
  716. &g_vecCurrentVForward, &g_vecCurrentVRight, &g_vecCurrentVUp, &g_matCurrentCamInverse );
  717. g_CurrentViewID = viewID;
  718. s_bCanAccessCurrentView = true;
  719. // Cache off fade distances
  720. float flScreenFadeMinSize, flScreenFadeMaxSize;
  721. view->GetScreenFadeDistances( &flScreenFadeMinSize, &flScreenFadeMaxSize );
  722. modelinfo->SetViewScreenFadeRange( flScreenFadeMinSize, flScreenFadeMaxSize );
  723. CMatRenderContextPtr pRenderContext( materials );
  724. #ifdef PORTAL
  725. if ( g_pPortalRender->GetViewRecursionLevel() == 0 )
  726. {
  727. pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, ((viewID == VIEW_MAIN) || (viewID == VIEW_3DSKY)) ? 1 : 0 );
  728. }
  729. #else
  730. pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, ((viewID == VIEW_MAIN) || (viewID == VIEW_3DSKY)) ? 1 : 0 );
  731. #endif
  732. }
  733. view_id_t CurrentViewID()
  734. {
  735. Assert( g_CurrentViewID != VIEW_ILLEGAL );
  736. return ( view_id_t )g_CurrentViewID;
  737. }
  738. //-----------------------------------------------------------------------------
  739. // Purpose: Portal views are considered 'Main' views. This function tests a view id
  740. // against all view ids used by portal renderables, as well as the main view.
  741. //-----------------------------------------------------------------------------
  742. bool IsMainView ( view_id_t id )
  743. {
  744. #if defined(PORTAL)
  745. return ( (id == VIEW_MAIN) || g_pPortalRender->IsPortalViewID( id ) );
  746. #else
  747. return (id == VIEW_MAIN);
  748. #endif
  749. }
  750. void FinishCurrentView()
  751. {
  752. s_bCanAccessCurrentView = false;
  753. }
  754. //-----------------------------------------------------------------------------
  755. // Constructor
  756. //-----------------------------------------------------------------------------
  757. void CSimpleRenderExecutor::AddView( CRendering3dView *pView )
  758. {
  759. CBase3dView *pPrevRenderer = m_pMainView->SetActiveRenderer( pView );
  760. pView->Draw();
  761. m_pMainView->SetActiveRenderer( pPrevRenderer );
  762. }
  763. //-----------------------------------------------------------------------------
  764. // Constructor
  765. //-----------------------------------------------------------------------------
  766. CViewRender::CViewRender()
  767. : m_SimpleExecutor( this )
  768. {
  769. m_flCheapWaterStartDistance = 0.0f;
  770. m_flCheapWaterEndDistance = 0.1f;
  771. m_BaseDrawFlags = 0;
  772. m_pActiveRenderer = NULL;
  773. m_pCurrentlyDrawingEntity = NULL;
  774. }
  775. //-----------------------------------------------------------------------------
  776. // Purpose:
  777. // Output : Returns true on success, false on failure.
  778. //-----------------------------------------------------------------------------
  779. inline bool CViewRender::ShouldDrawEntities( void )
  780. {
  781. return ( !m_pDrawEntities || (m_pDrawEntities->GetInt() != 0) );
  782. }
  783. //-----------------------------------------------------------------------------
  784. // Purpose: Check all conditions which would prevent drawing the view model
  785. // Input : drawViewmodel -
  786. // *viewmodel -
  787. // Output : Returns true on success, false on failure.
  788. //-----------------------------------------------------------------------------
  789. bool CViewRender::ShouldDrawViewModel( bool bDrawViewmodel )
  790. {
  791. if ( !bDrawViewmodel )
  792. return false;
  793. if ( !r_drawviewmodel.GetBool() )
  794. return false;
  795. if ( C_BasePlayer::ShouldDrawLocalPlayer() )
  796. return false;
  797. if ( !ShouldDrawEntities() )
  798. return false;
  799. if ( render->GetViewEntity() > gpGlobals->maxClients )
  800. return false;
  801. return true;
  802. }
  803. //-----------------------------------------------------------------------------
  804. // Purpose:
  805. //-----------------------------------------------------------------------------
  806. bool CViewRender::UpdateRefractIfNeededByList( CUtlVector< IClientRenderable * > &list )
  807. {
  808. int nCount = list.Count();
  809. for( int i=0; i < nCount; ++i )
  810. {
  811. IClientUnknown *pUnk = list[i]->GetIClientUnknown();
  812. Assert( pUnk );
  813. IClientRenderable *pRenderable = pUnk->GetClientRenderable();
  814. Assert( pRenderable );
  815. if ( pRenderable->UsesPowerOfTwoFrameBufferTexture() )
  816. {
  817. UpdateRefractTexture();
  818. return true;
  819. }
  820. }
  821. return false;
  822. }
  823. //-----------------------------------------------------------------------------
  824. // Purpose:
  825. //-----------------------------------------------------------------------------
  826. void CViewRender::DrawRenderablesInList( CUtlVector< IClientRenderable * > &list, int flags )
  827. {
  828. Assert( m_pCurrentlyDrawingEntity == NULL );
  829. int nCount = list.Count();
  830. for( int i=0; i < nCount; ++i )
  831. {
  832. IClientUnknown *pUnk = list[i]->GetIClientUnknown();
  833. Assert( pUnk );
  834. IClientRenderable *pRenderable = pUnk->GetClientRenderable();
  835. Assert( pRenderable );
  836. // Non-view models wanting to render in view model list...
  837. if ( pRenderable->ShouldDraw() )
  838. {
  839. m_pCurrentlyDrawingEntity = pUnk->GetBaseEntity();
  840. pRenderable->DrawModel( STUDIO_RENDER | flags );
  841. }
  842. }
  843. m_pCurrentlyDrawingEntity = NULL;
  844. }
  845. //-----------------------------------------------------------------------------
  846. // Purpose: Actually draw the view model
  847. // Input : drawViewModel -
  848. //-----------------------------------------------------------------------------
  849. void CViewRender::DrawViewModels( const CViewSetup &viewRender, bool drawViewmodel )
  850. {
  851. VPROF( "CViewRender::DrawViewModel" );
  852. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  853. #ifdef PORTAL //in portal, we'd like a copy of the front buffer without the gun in it for use with the depth doubler
  854. g_pPortalRender->UpdateDepthDoublerTexture( viewRender );
  855. #endif
  856. bool bShouldDrawPlayerViewModel = ShouldDrawViewModel( drawViewmodel );
  857. bool bShouldDrawToolViewModels = ToolsEnabled();
  858. CMatRenderContextPtr pRenderContext( materials );
  859. PIXEVENT( pRenderContext, "DrawViewModels" );
  860. // Restore the matrices
  861. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  862. pRenderContext->PushMatrix();
  863. CViewSetup viewModelSetup( viewRender );
  864. viewModelSetup.zNear = viewRender.zNearViewmodel;
  865. viewModelSetup.zFar = viewRender.zFarViewmodel;
  866. viewModelSetup.fov = viewRender.fovViewmodel;
  867. viewModelSetup.m_flAspectRatio = engine->GetScreenAspectRatio();
  868. ITexture *pRTColor = NULL;
  869. ITexture *pRTDepth = NULL;
  870. if( viewRender.m_eStereoEye != STEREO_EYE_MONO )
  871. {
  872. pRTColor = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(viewRender.m_eStereoEye-1), ISourceVirtualReality::RT_Color );
  873. pRTDepth = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(viewRender.m_eStereoEye-1), ISourceVirtualReality::RT_Depth );
  874. }
  875. render->Push3DView( viewModelSetup, 0, pRTColor, GetFrustum(), pRTDepth );
  876. #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)
  877. //step up to a full depth clear if we're extremely close to a portal (in a portal environment)
  878. 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
  879. bool bUseDepthHack = !LocalPlayerIsCloseToPortal();
  880. if( !bUseDepthHack )
  881. pRenderContext->ClearBuffers( false, true, false );
  882. #else
  883. const bool bUseDepthHack = true;
  884. #endif
  885. // FIXME: Add code to read the current depth range
  886. float depthmin = 0.0f;
  887. float depthmax = 1.0f;
  888. // HACK HACK: Munge the depth range to prevent view model from poking into walls, etc.
  889. // Force clipped down range
  890. if( bUseDepthHack )
  891. pRenderContext->DepthRange( 0.0f, 0.1f );
  892. if ( bShouldDrawPlayerViewModel || bShouldDrawToolViewModels )
  893. {
  894. CUtlVector< IClientRenderable * > opaqueViewModelList( 32 );
  895. CUtlVector< IClientRenderable * > translucentViewModelList( 32 );
  896. ClientLeafSystem()->CollateViewModelRenderables( opaqueViewModelList, translucentViewModelList );
  897. if ( ToolsEnabled() && ( !bShouldDrawPlayerViewModel || !bShouldDrawToolViewModels ) )
  898. {
  899. int nOpaque = opaqueViewModelList.Count();
  900. for ( int i = nOpaque-1; i >= 0; --i )
  901. {
  902. IClientRenderable *pRenderable = opaqueViewModelList[ i ];
  903. bool bEntity = pRenderable->GetIClientUnknown()->GetBaseEntity();
  904. if ( ( bEntity && !bShouldDrawPlayerViewModel ) || ( !bEntity && !bShouldDrawToolViewModels ) )
  905. {
  906. opaqueViewModelList.FastRemove( i );
  907. }
  908. }
  909. int nTranslucent = translucentViewModelList.Count();
  910. for ( int i = nTranslucent-1; i >= 0; --i )
  911. {
  912. IClientRenderable *pRenderable = translucentViewModelList[ i ];
  913. bool bEntity = pRenderable->GetIClientUnknown()->GetBaseEntity();
  914. if ( ( bEntity && !bShouldDrawPlayerViewModel ) || ( !bEntity && !bShouldDrawToolViewModels ) )
  915. {
  916. translucentViewModelList.FastRemove( i );
  917. }
  918. }
  919. }
  920. if ( !UpdateRefractIfNeededByList( opaqueViewModelList ) )
  921. {
  922. UpdateRefractIfNeededByList( translucentViewModelList );
  923. }
  924. DrawRenderablesInList( opaqueViewModelList );
  925. DrawRenderablesInList( translucentViewModelList, STUDIO_TRANSPARENCY );
  926. }
  927. // Reset the depth range to the original values
  928. if( bUseDepthHack )
  929. pRenderContext->DepthRange( depthmin, depthmax );
  930. render->PopView( GetFrustum() );
  931. // Restore the matrices
  932. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  933. pRenderContext->PopMatrix();
  934. }
  935. //-----------------------------------------------------------------------------
  936. // Purpose:
  937. // Output : Returns true on success, false on failure.
  938. //-----------------------------------------------------------------------------
  939. bool CViewRender::ShouldDrawBrushModels( void )
  940. {
  941. if ( m_pDrawBrushModels && !m_pDrawBrushModels->GetInt() )
  942. return false;
  943. return true;
  944. }
  945. //-----------------------------------------------------------------------------
  946. // Purpose: Performs screen space effects, if any
  947. //-----------------------------------------------------------------------------
  948. void CViewRender::PerformScreenSpaceEffects( int x, int y, int w, int h )
  949. {
  950. VPROF("CViewRender::PerformScreenSpaceEffects()");
  951. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  952. // FIXME: Screen-space effects are busted in the editor
  953. if ( engine->IsHammerRunning() )
  954. return;
  955. g_pScreenSpaceEffects->RenderEffects( x, y, w, h );
  956. }
  957. //-----------------------------------------------------------------------------
  958. // Purpose: Sets the screen space effect material (can't be done during rendering)
  959. //-----------------------------------------------------------------------------
  960. void CViewRender::SetScreenOverlayMaterial( IMaterial *pMaterial )
  961. {
  962. m_ScreenOverlayMaterial.Init( pMaterial );
  963. }
  964. //-----------------------------------------------------------------------------
  965. //
  966. //-----------------------------------------------------------------------------
  967. IMaterial *CViewRender::GetScreenOverlayMaterial( )
  968. {
  969. return m_ScreenOverlayMaterial;
  970. }
  971. //-----------------------------------------------------------------------------
  972. // Purpose: Performs screen space effects, if any
  973. //-----------------------------------------------------------------------------
  974. void CViewRender::PerformScreenOverlay( int x, int y, int w, int h )
  975. {
  976. VPROF("CViewRender::PerformScreenOverlay()");
  977. if (m_ScreenOverlayMaterial)
  978. {
  979. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  980. if ( m_ScreenOverlayMaterial->NeedsFullFrameBufferTexture() )
  981. {
  982. // FIXME: check with multi/sub-rect renders. Should this be 0,0,w,h instead?
  983. DrawScreenEffectMaterial( m_ScreenOverlayMaterial, x, y, w, h );
  984. }
  985. else if ( m_ScreenOverlayMaterial->NeedsPowerOfTwoFrameBufferTexture() )
  986. {
  987. // First copy the FB off to the offscreen texture
  988. UpdateRefractTexture( x, y, w, h, true );
  989. // Now draw the entire screen using the material...
  990. CMatRenderContextPtr pRenderContext( materials );
  991. ITexture *pTexture = GetPowerOfTwoFrameBufferTexture( );
  992. int sw = pTexture->GetActualWidth();
  993. int sh = pTexture->GetActualHeight();
  994. // Note - don't offset by x,y - already done by the viewport.
  995. pRenderContext->DrawScreenSpaceRectangle( m_ScreenOverlayMaterial, 0, 0, w, h,
  996. 0, 0, sw-1, sh-1, sw, sh );
  997. }
  998. else
  999. {
  1000. byte color[4] = { 255, 255, 255, 255 };
  1001. render->ViewDrawFade( color, m_ScreenOverlayMaterial );
  1002. }
  1003. }
  1004. }
  1005. void CViewRender::DrawUnderwaterOverlay( void )
  1006. {
  1007. IMaterial *pOverlayMat = m_UnderWaterOverlayMaterial;
  1008. if ( pOverlayMat )
  1009. {
  1010. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1011. CMatRenderContextPtr pRenderContext( materials );
  1012. int x, y, w, h;
  1013. pRenderContext->GetViewport( x, y, w, h );
  1014. if ( pOverlayMat->NeedsFullFrameBufferTexture() )
  1015. {
  1016. // FIXME: check with multi/sub-rect renders. Should this be 0,0,w,h instead?
  1017. DrawScreenEffectMaterial( pOverlayMat, x, y, w, h );
  1018. }
  1019. else if ( pOverlayMat->NeedsPowerOfTwoFrameBufferTexture() )
  1020. {
  1021. // First copy the FB off to the offscreen texture
  1022. UpdateRefractTexture( x, y, w, h, true );
  1023. // Now draw the entire screen using the material...
  1024. CMatRenderContextPtr pRenderContextMat( materials );
  1025. ITexture *pTexture = GetPowerOfTwoFrameBufferTexture( );
  1026. int sw = pTexture->GetActualWidth();
  1027. int sh = pTexture->GetActualHeight();
  1028. // Note - don't offset by x,y - already done by the viewport.
  1029. pRenderContextMat->DrawScreenSpaceRectangle( pOverlayMat, 0, 0, w, h,
  1030. 0, 0, sw-1, sh-1, sw, sh );
  1031. }
  1032. else
  1033. {
  1034. // Note - don't offset by x,y - already done by the viewport.
  1035. // FIXME: actually test this code path.
  1036. pRenderContext->DrawScreenSpaceRectangle( pOverlayMat, 0, 0, w, h,
  1037. 0, 0, 1, 1, 1, 1 );
  1038. }
  1039. }
  1040. }
  1041. //-----------------------------------------------------------------------------
  1042. // Purpose: Returns the min/max fade distances
  1043. //-----------------------------------------------------------------------------
  1044. void CViewRender::GetScreenFadeDistances( float *min, float *max )
  1045. {
  1046. if ( min )
  1047. {
  1048. *min = r_screenfademinsize.GetFloat();
  1049. }
  1050. if ( max )
  1051. {
  1052. *max = r_screenfademaxsize.GetFloat();
  1053. }
  1054. }
  1055. C_BaseEntity *CViewRender::GetCurrentlyDrawingEntity()
  1056. {
  1057. return m_pCurrentlyDrawingEntity;
  1058. }
  1059. void CViewRender::SetCurrentlyDrawingEntity( C_BaseEntity *pEnt )
  1060. {
  1061. m_pCurrentlyDrawingEntity = pEnt;
  1062. }
  1063. bool CViewRender::UpdateShadowDepthTexture( ITexture *pRenderTarget, ITexture *pDepthTexture, const CViewSetup &shadowViewIn )
  1064. {
  1065. VPROF_INCREMENT_COUNTER( "shadow depth textures rendered", 1 );
  1066. CMatRenderContextPtr pRenderContext( materials );
  1067. char szPIXEventName[128];
  1068. sprintf( szPIXEventName, "UpdateShadowDepthTexture (%s)", pDepthTexture->GetName() );
  1069. PIXEVENT( pRenderContext, szPIXEventName );
  1070. CRefPtr<CShadowDepthView> pShadowDepthView = new CShadowDepthView( this );
  1071. pShadowDepthView->Setup( shadowViewIn, pRenderTarget, pDepthTexture );
  1072. AddViewToScene( pShadowDepthView );
  1073. return true;
  1074. }
  1075. //-----------------------------------------------------------------------------
  1076. // Purpose: Renders world and all entities, etc.
  1077. //-----------------------------------------------------------------------------
  1078. void CViewRender::ViewDrawScene( bool bDrew3dSkybox, SkyboxVisibility_t nSkyboxVisible, const CViewSetup &viewRender,
  1079. int nClearFlags, view_id_t viewID, bool bDrawViewModel, int baseDrawFlags, ViewCustomVisibility_t *pCustomVisibility )
  1080. {
  1081. VPROF( "CViewRender::ViewDrawScene" );
  1082. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1083. // this allows the refract texture to be updated once per *scene* on 360
  1084. // (e.g. once for a monitor scene and once for the main scene)
  1085. g_viewscene_refractUpdateFrame = gpGlobals->framecount - 1;
  1086. g_pClientShadowMgr->PreRender();
  1087. // Shadowed flashlights supported on ps_2_b and up...
  1088. if ( r_flashlightdepthtexture.GetBool() && (viewID == VIEW_MAIN) )
  1089. {
  1090. g_pClientShadowMgr->ComputeShadowDepthTextures( viewRender );
  1091. }
  1092. m_BaseDrawFlags = baseDrawFlags;
  1093. SetupCurrentView( viewRender.origin, viewRender.angles, viewID );
  1094. // Invoke pre-render methods
  1095. IGameSystem::PreRenderAllSystems();
  1096. // Start view
  1097. unsigned int visFlags;
  1098. SetupVis( viewRender, visFlags, pCustomVisibility );
  1099. if ( !bDrew3dSkybox &&
  1100. ( nSkyboxVisible == SKYBOX_NOT_VISIBLE ) && ( visFlags & IVRenderView::VIEW_SETUP_VIS_EX_RETURN_FLAGS_USES_RADIAL_VIS ) )
  1101. {
  1102. // This covers the case where we don't see a 3dskybox, yet radial vis is clipping
  1103. // the far plane. Need to clear to fog color in this case.
  1104. nClearFlags |= VIEW_CLEAR_COLOR;
  1105. SetClearColorToFogColor( );
  1106. }
  1107. bool drawSkybox = r_skybox.GetBool();
  1108. if ( bDrew3dSkybox || ( nSkyboxVisible == SKYBOX_NOT_VISIBLE ) )
  1109. {
  1110. drawSkybox = false;
  1111. }
  1112. ParticleMgr()->IncrementFrameCode();
  1113. DrawWorldAndEntities( drawSkybox, viewRender, nClearFlags, pCustomVisibility );
  1114. // Disable fog for the rest of the stuff
  1115. DisableFog();
  1116. // UNDONE: Don't do this with masked brush models, they should probably be in a separate list
  1117. // render->DrawMaskEntities()
  1118. // Here are the overlays...
  1119. CGlowOverlay::DrawOverlays( viewRender.m_bCacheFullSceneState );
  1120. // issue the pixel visibility tests
  1121. if ( IsMainView( CurrentViewID() ) )
  1122. {
  1123. PixelVisibility_EndCurrentView();
  1124. }
  1125. // Draw rain..
  1126. DrawPrecipitation();
  1127. // Make sure sound doesn't stutter
  1128. engine->Sound_ExtraUpdate();
  1129. // Debugging info goes over the top
  1130. CDebugViewRender::Draw3DDebuggingInfo( viewRender );
  1131. // Draw client side effects
  1132. // NOTE: These are not sorted against the rest of the frame
  1133. clienteffects->DrawEffects( gpGlobals->frametime );
  1134. // Mark the frame as locked down for client fx additions
  1135. SetFXCreationAllowed( false );
  1136. // Invoke post-render methods
  1137. IGameSystem::PostRenderAllSystems();
  1138. FinishCurrentView();
  1139. // Free shadow depth textures for use in future view
  1140. if ( r_flashlightdepthtexture.GetBool() )
  1141. {
  1142. g_pClientShadowMgr->UnlockAllShadowDepthTextures();
  1143. }
  1144. }
  1145. void CheckAndTransitionColor( float flPercent, float *pColor, float *pLerpToColor )
  1146. {
  1147. if ( pLerpToColor[0] != pColor[0] || pLerpToColor[1] != pColor[1] || pLerpToColor[2] != pColor[2] )
  1148. {
  1149. float flDestColor[3];
  1150. flDestColor[0] = pLerpToColor[0];
  1151. flDestColor[1] = pLerpToColor[1];
  1152. flDestColor[2] = pLerpToColor[2];
  1153. pColor[0] = FLerp( pColor[0], flDestColor[0], flPercent );
  1154. pColor[1] = FLerp( pColor[1], flDestColor[1], flPercent );
  1155. pColor[2] = FLerp( pColor[2], flDestColor[2], flPercent );
  1156. }
  1157. else
  1158. {
  1159. pColor[0] = pLerpToColor[0];
  1160. pColor[1] = pLerpToColor[1];
  1161. pColor[2] = pLerpToColor[2];
  1162. }
  1163. }
  1164. static void GetFogColorTransition( fogparams_t *pFogParams, float *pColorPrimary, float *pColorSecondary )
  1165. {
  1166. if ( !pFogParams )
  1167. return;
  1168. if ( pFogParams->lerptime >= gpGlobals->curtime )
  1169. {
  1170. float flPercent = 1.0f - (( pFogParams->lerptime - gpGlobals->curtime ) / pFogParams->duration );
  1171. float flPrimaryColorLerp[3] = { (float)pFogParams->colorPrimaryLerpTo.GetR(), (float)pFogParams->colorPrimaryLerpTo.GetG(), (float)pFogParams->colorPrimaryLerpTo.GetB() };
  1172. float flSecondaryColorLerp[3] = { (float)pFogParams->colorSecondaryLerpTo.GetR(), (float)pFogParams->colorSecondaryLerpTo.GetG(), (float)pFogParams->colorSecondaryLerpTo.GetB() };
  1173. CheckAndTransitionColor( flPercent, pColorPrimary, flPrimaryColorLerp );
  1174. CheckAndTransitionColor( flPercent, pColorSecondary, flSecondaryColorLerp );
  1175. }
  1176. }
  1177. //-----------------------------------------------------------------------------
  1178. // Purpose: Returns the fog color to use in rendering the current frame.
  1179. //-----------------------------------------------------------------------------
  1180. static void GetFogColor( fogparams_t *pFogParams, float *pColor )
  1181. {
  1182. C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
  1183. if ( !pbp || !pFogParams )
  1184. return;
  1185. const char *fogColorString = fog_color.GetString();
  1186. if( fog_override.GetInt() && fogColorString )
  1187. {
  1188. sscanf( fogColorString, "%f%f%f", pColor, pColor+1, pColor+2 );
  1189. }
  1190. else
  1191. {
  1192. float flPrimaryColor[3] = { (float)pFogParams->colorPrimary.GetR(), (float)pFogParams->colorPrimary.GetG(), (float)pFogParams->colorPrimary.GetB() };
  1193. float flSecondaryColor[3] = { (float)pFogParams->colorSecondary.GetR(), (float)pFogParams->colorSecondary.GetG(), (float)pFogParams->colorSecondary.GetB() };
  1194. GetFogColorTransition( pFogParams, flPrimaryColor, flSecondaryColor );
  1195. if( pFogParams->blend )
  1196. {
  1197. //
  1198. // Blend between two fog colors based on viewing angle.
  1199. // The secondary fog color is at 180 degrees to the primary fog color.
  1200. //
  1201. Vector forward;
  1202. pbp->EyeVectors( &forward, NULL, NULL );
  1203. Vector vNormalized = pFogParams->dirPrimary;
  1204. VectorNormalize( vNormalized );
  1205. pFogParams->dirPrimary = vNormalized;
  1206. float flBlendFactor = 0.5 * forward.Dot( pFogParams->dirPrimary ) + 0.5;
  1207. // FIXME: convert to linear colorspace
  1208. pColor[0] = flPrimaryColor[0] * flBlendFactor + flSecondaryColor[0] * ( 1 - flBlendFactor );
  1209. pColor[1] = flPrimaryColor[1] * flBlendFactor + flSecondaryColor[1] * ( 1 - flBlendFactor );
  1210. pColor[2] = flPrimaryColor[2] * flBlendFactor + flSecondaryColor[2] * ( 1 - flBlendFactor );
  1211. }
  1212. else
  1213. {
  1214. pColor[0] = flPrimaryColor[0];
  1215. pColor[1] = flPrimaryColor[1];
  1216. pColor[2] = flPrimaryColor[2];
  1217. }
  1218. }
  1219. VectorScale( pColor, 1.0f / 255.0f, pColor );
  1220. }
  1221. static float GetFogStart( fogparams_t *pFogParams )
  1222. {
  1223. if( !pFogParams )
  1224. return 0.0f;
  1225. if( fog_override.GetInt() )
  1226. {
  1227. if( fog_start.GetFloat() == -1.0f )
  1228. {
  1229. return pFogParams->start;
  1230. }
  1231. else
  1232. {
  1233. return fog_start.GetFloat();
  1234. }
  1235. }
  1236. else
  1237. {
  1238. if ( pFogParams->lerptime > gpGlobals->curtime )
  1239. {
  1240. if ( pFogParams->start != pFogParams->startLerpTo )
  1241. {
  1242. if ( pFogParams->lerptime > gpGlobals->curtime )
  1243. {
  1244. float flPercent = 1.0f - (( pFogParams->lerptime - gpGlobals->curtime ) / pFogParams->duration );
  1245. return FLerp( pFogParams->start, pFogParams->startLerpTo, flPercent );
  1246. }
  1247. else
  1248. {
  1249. if ( pFogParams->start != pFogParams->startLerpTo )
  1250. {
  1251. pFogParams->start = pFogParams->startLerpTo;
  1252. }
  1253. }
  1254. }
  1255. }
  1256. return pFogParams->start;
  1257. }
  1258. }
  1259. static float GetFogEnd( fogparams_t *pFogParams )
  1260. {
  1261. if( !pFogParams )
  1262. return 0.0f;
  1263. if( fog_override.GetInt() )
  1264. {
  1265. if( fog_end.GetFloat() == -1.0f )
  1266. {
  1267. return pFogParams->end;
  1268. }
  1269. else
  1270. {
  1271. return fog_end.GetFloat();
  1272. }
  1273. }
  1274. else
  1275. {
  1276. if ( pFogParams->lerptime > gpGlobals->curtime )
  1277. {
  1278. if ( pFogParams->end != pFogParams->endLerpTo )
  1279. {
  1280. if ( pFogParams->lerptime > gpGlobals->curtime )
  1281. {
  1282. float flPercent = 1.0f - (( pFogParams->lerptime - gpGlobals->curtime ) / pFogParams->duration );
  1283. return FLerp( pFogParams->end, pFogParams->endLerpTo, flPercent );
  1284. }
  1285. else
  1286. {
  1287. if ( pFogParams->end != pFogParams->endLerpTo )
  1288. {
  1289. pFogParams->end = pFogParams->endLerpTo;
  1290. }
  1291. }
  1292. }
  1293. }
  1294. return pFogParams->end;
  1295. }
  1296. }
  1297. static bool GetFogEnable( fogparams_t *pFogParams )
  1298. {
  1299. if ( cl_leveloverview.GetFloat() > 0 )
  1300. return false;
  1301. // Ask the clientmode
  1302. if ( g_pClientMode->ShouldDrawFog() == false )
  1303. return false;
  1304. if( fog_override.GetInt() )
  1305. {
  1306. if( fog_enable.GetInt() )
  1307. {
  1308. return true;
  1309. }
  1310. else
  1311. {
  1312. return false;
  1313. }
  1314. }
  1315. else
  1316. {
  1317. if( pFogParams )
  1318. return pFogParams->enable != false;
  1319. return false;
  1320. }
  1321. }
  1322. static float GetFogMaxDensity( fogparams_t *pFogParams )
  1323. {
  1324. if( !pFogParams )
  1325. return 1.0f;
  1326. if ( cl_leveloverview.GetFloat() > 0 )
  1327. return 1.0f;
  1328. // Ask the clientmode
  1329. if ( !g_pClientMode->ShouldDrawFog() )
  1330. return 1.0f;
  1331. if ( fog_override.GetInt() )
  1332. {
  1333. if ( fog_maxdensity.GetFloat() == -1.0f )
  1334. return pFogParams->maxdensity;
  1335. else
  1336. return fog_maxdensity.GetFloat();
  1337. }
  1338. else
  1339. return pFogParams->maxdensity;
  1340. }
  1341. //-----------------------------------------------------------------------------
  1342. // Purpose: Returns the skybox fog color to use in rendering the current frame.
  1343. //-----------------------------------------------------------------------------
  1344. static void GetSkyboxFogColor( float *pColor )
  1345. {
  1346. C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
  1347. if( !pbp )
  1348. {
  1349. return;
  1350. }
  1351. CPlayerLocalData *local = &pbp->m_Local;
  1352. const char *fogColorString = fog_colorskybox.GetString();
  1353. if( fog_override.GetInt() && fogColorString )
  1354. {
  1355. sscanf( fogColorString, "%f%f%f", pColor, pColor+1, pColor+2 );
  1356. }
  1357. else
  1358. {
  1359. if( local->m_skybox3d.fog.blend )
  1360. {
  1361. //
  1362. // Blend between two fog colors based on viewing angle.
  1363. // The secondary fog color is at 180 degrees to the primary fog color.
  1364. //
  1365. Vector forward;
  1366. pbp->EyeVectors( &forward, NULL, NULL );
  1367. Vector vNormalized = local->m_skybox3d.fog.dirPrimary;
  1368. VectorNormalize( vNormalized );
  1369. local->m_skybox3d.fog.dirPrimary = vNormalized;
  1370. float flBlendFactor = 0.5 * forward.Dot( local->m_skybox3d.fog.dirPrimary ) + 0.5;
  1371. // FIXME: convert to linear colorspace
  1372. pColor[0] = local->m_skybox3d.fog.colorPrimary.GetR() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetR() * ( 1 - flBlendFactor );
  1373. pColor[1] = local->m_skybox3d.fog.colorPrimary.GetG() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetG() * ( 1 - flBlendFactor );
  1374. pColor[2] = local->m_skybox3d.fog.colorPrimary.GetB() * flBlendFactor + local->m_skybox3d.fog.colorSecondary.GetB() * ( 1 - flBlendFactor );
  1375. }
  1376. else
  1377. {
  1378. pColor[0] = local->m_skybox3d.fog.colorPrimary.GetR();
  1379. pColor[1] = local->m_skybox3d.fog.colorPrimary.GetG();
  1380. pColor[2] = local->m_skybox3d.fog.colorPrimary.GetB();
  1381. }
  1382. }
  1383. VectorScale( pColor, 1.0f / 255.0f, pColor );
  1384. }
  1385. static float GetSkyboxFogStart( void )
  1386. {
  1387. C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
  1388. if( !pbp )
  1389. {
  1390. return 0.0f;
  1391. }
  1392. CPlayerLocalData *local = &pbp->m_Local;
  1393. if( fog_override.GetInt() )
  1394. {
  1395. if( fog_startskybox.GetFloat() == -1.0f )
  1396. {
  1397. return local->m_skybox3d.fog.start;
  1398. }
  1399. else
  1400. {
  1401. return fog_startskybox.GetFloat();
  1402. }
  1403. }
  1404. else
  1405. {
  1406. return local->m_skybox3d.fog.start;
  1407. }
  1408. }
  1409. static float GetSkyboxFogEnd( void )
  1410. {
  1411. C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
  1412. if( !pbp )
  1413. {
  1414. return 0.0f;
  1415. }
  1416. CPlayerLocalData *local = &pbp->m_Local;
  1417. if( fog_override.GetInt() )
  1418. {
  1419. if( fog_endskybox.GetFloat() == -1.0f )
  1420. {
  1421. return local->m_skybox3d.fog.end;
  1422. }
  1423. else
  1424. {
  1425. return fog_endskybox.GetFloat();
  1426. }
  1427. }
  1428. else
  1429. {
  1430. return local->m_skybox3d.fog.end;
  1431. }
  1432. }
  1433. static float GetSkyboxFogMaxDensity()
  1434. {
  1435. C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
  1436. if ( !pbp )
  1437. return 1.0f;
  1438. CPlayerLocalData *local = &pbp->m_Local;
  1439. if ( cl_leveloverview.GetFloat() > 0 )
  1440. return 1.0f;
  1441. // Ask the clientmode
  1442. if ( !g_pClientMode->ShouldDrawFog() )
  1443. return 1.0f;
  1444. if ( fog_override.GetInt() )
  1445. {
  1446. if ( fog_maxdensityskybox.GetFloat() == -1.0f )
  1447. return local->m_skybox3d.fog.maxdensity;
  1448. else
  1449. return fog_maxdensityskybox.GetFloat();
  1450. }
  1451. else
  1452. return local->m_skybox3d.fog.maxdensity;
  1453. }
  1454. void CViewRender::DisableFog( void )
  1455. {
  1456. VPROF("CViewRander::DisableFog()");
  1457. CMatRenderContextPtr pRenderContext( materials );
  1458. pRenderContext->FogMode( MATERIAL_FOG_NONE );
  1459. }
  1460. //-----------------------------------------------------------------------------
  1461. // Purpose:
  1462. //-----------------------------------------------------------------------------
  1463. void CViewRender::SetupVis( const CViewSetup& viewRender, unsigned int &visFlags, ViewCustomVisibility_t *pCustomVisibility )
  1464. {
  1465. VPROF( "CViewRender::SetupVis" );
  1466. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1467. if ( pCustomVisibility && pCustomVisibility->m_nNumVisOrigins )
  1468. {
  1469. // Pass array or vis origins to merge
  1470. render->ViewSetupVisEx( ShouldForceNoVis(), pCustomVisibility->m_nNumVisOrigins, pCustomVisibility->m_rgVisOrigins, visFlags );
  1471. }
  1472. else
  1473. {
  1474. // Use render origin as vis origin by default
  1475. render->ViewSetupVisEx( ShouldForceNoVis(), 1, &viewRender.origin, visFlags );
  1476. }
  1477. }
  1478. //-----------------------------------------------------------------------------
  1479. // Purpose: Renders voice feedback and other sprites attached to players
  1480. // Input : none
  1481. //-----------------------------------------------------------------------------
  1482. void CViewRender::RenderPlayerSprites()
  1483. {
  1484. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1485. GetClientVoiceMgr()->DrawHeadLabels();
  1486. }
  1487. //-----------------------------------------------------------------------------
  1488. // Sets up, cleans up the main 3D view
  1489. //-----------------------------------------------------------------------------
  1490. void CViewRender::SetupMain3DView( const CViewSetup &viewRender, int &nClearFlags )
  1491. {
  1492. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1493. // FIXME: I really want these fields removed from CViewSetup
  1494. // and passed in as independent flags
  1495. // Clear the color here if requested.
  1496. int nDepthStencilFlags = nClearFlags & ( VIEW_CLEAR_DEPTH | VIEW_CLEAR_STENCIL );
  1497. nClearFlags &= ~( nDepthStencilFlags ); // Clear these flags
  1498. if ( nClearFlags & VIEW_CLEAR_COLOR )
  1499. {
  1500. nClearFlags |= nDepthStencilFlags; // Add them back in if we're clearing color
  1501. }
  1502. // If we are using HDR, we render to the HDR full frame buffer texture
  1503. // instead of whatever was previously the render target
  1504. if( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_FLOAT )
  1505. {
  1506. render->Push3DView( viewRender, nClearFlags, GetFullFrameFrameBufferTexture( 0 ), GetFrustum() );
  1507. }
  1508. else
  1509. {
  1510. ITexture *pRTColor = NULL;
  1511. ITexture *pRTDepth = NULL;
  1512. if( viewRender.m_eStereoEye != STEREO_EYE_MONO )
  1513. {
  1514. pRTColor = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(viewRender.m_eStereoEye-1), ISourceVirtualReality::RT_Color );
  1515. pRTDepth = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(viewRender.m_eStereoEye-1), ISourceVirtualReality::RT_Depth );
  1516. }
  1517. render->Push3DView( viewRender, nClearFlags, pRTColor, GetFrustum(), pRTDepth );
  1518. }
  1519. // If we didn't clear the depth here, we'll need to clear it later
  1520. nClearFlags ^= nDepthStencilFlags; // Toggle these bits
  1521. if ( nClearFlags & VIEW_CLEAR_COLOR )
  1522. {
  1523. // If we cleared the color here, we don't need to clear it later
  1524. nClearFlags &= ~( VIEW_CLEAR_COLOR | VIEW_CLEAR_FULL_TARGET );
  1525. }
  1526. }
  1527. void CViewRender::CleanupMain3DView( const CViewSetup &viewRender )
  1528. {
  1529. render->PopView( GetFrustum() );
  1530. }
  1531. //-----------------------------------------------------------------------------
  1532. // Queues up an overlay rendering
  1533. //-----------------------------------------------------------------------------
  1534. void CViewRender::QueueOverlayRenderView( const CViewSetup &viewRender, int nClearFlags, int whatToDraw )
  1535. {
  1536. // Can't have 2 in a single scene
  1537. Assert( !m_bDrawOverlay );
  1538. m_bDrawOverlay = true;
  1539. m_OverlayViewSetup = viewRender;
  1540. m_OverlayClearFlags = nClearFlags;
  1541. m_OverlayDrawFlags = whatToDraw;
  1542. }
  1543. //-----------------------------------------------------------------------------
  1544. // Purpose: Force the view to freeze on the next frame for the specified time
  1545. //-----------------------------------------------------------------------------
  1546. void CViewRender::FreezeFrame( float flFreezeTime )
  1547. {
  1548. if ( flFreezeTime == 0 )
  1549. {
  1550. m_flFreezeFrameUntil = 0;
  1551. for( int i=0; i < STEREO_EYE_MAX; i++ )
  1552. {
  1553. m_rbTakeFreezeFrame[ i ] = false;
  1554. }
  1555. }
  1556. else
  1557. {
  1558. if ( m_flFreezeFrameUntil > gpGlobals->curtime )
  1559. {
  1560. m_flFreezeFrameUntil += flFreezeTime;
  1561. }
  1562. else
  1563. {
  1564. m_flFreezeFrameUntil = gpGlobals->curtime + flFreezeTime;
  1565. for( int i=GetFirstEye(); i <= GetLastEye(); i++ )
  1566. {
  1567. m_rbTakeFreezeFrame[ i ] = true;
  1568. }
  1569. }
  1570. }
  1571. }
  1572. const char *COM_GetModDirectory();
  1573. //-----------------------------------------------------------------------------
  1574. // Purpose: This renders the entire 3D view and the in-game hud/viewmodel
  1575. // Input : &view -
  1576. // whatToDraw -
  1577. //-----------------------------------------------------------------------------
  1578. // This renders the entire 3D view.
  1579. void CViewRender::RenderView( const CViewSetup &viewRender, int nClearFlags, int whatToDraw )
  1580. {
  1581. m_UnderWaterOverlayMaterial.Shutdown(); // underwater view will set
  1582. m_CurrentView = viewRender;
  1583. C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true );
  1584. VPROF( "CViewRender::RenderView" );
  1585. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1586. // Don't want TF2 running less than DX 8
  1587. if ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 )
  1588. {
  1589. // We know they were running at least 8.0 when the game started...we check the
  1590. // value in ClientDLL_Init()...so they must be messing with their DirectX settings.
  1591. if ( ( Q_stricmp( COM_GetModDirectory(), "tf" ) == 0 ) || ( Q_stricmp( COM_GetModDirectory(), "tf_beta" ) == 0 ) )
  1592. {
  1593. static bool bFirstTime = true;
  1594. if ( bFirstTime )
  1595. {
  1596. bFirstTime = false;
  1597. Msg( "This game has a minimum requirement of DirectX 8.0 to run properly.\n" );
  1598. }
  1599. return;
  1600. }
  1601. }
  1602. CMatRenderContextPtr pRenderContext( materials );
  1603. ITexture *saveRenderTarget = pRenderContext->GetRenderTarget();
  1604. pRenderContext.SafeRelease(); // don't want to hold for long periods in case in a locking active share thread mode
  1605. if ( !m_rbTakeFreezeFrame[viewRender.m_eStereoEye ] && m_flFreezeFrameUntil > gpGlobals->curtime )
  1606. {
  1607. CRefPtr<CFreezeFrameView> pFreezeFrameView = new CFreezeFrameView( this );
  1608. pFreezeFrameView->Setup( viewRender );
  1609. AddViewToScene( pFreezeFrameView );
  1610. g_bRenderingView = true;
  1611. s_bCanAccessCurrentView = true;
  1612. }
  1613. else
  1614. {
  1615. g_flFreezeFlash = 0.0f;
  1616. g_pClientShadowMgr->AdvanceFrame();
  1617. #ifdef USE_MONITORS
  1618. if ( cl_drawmonitors.GetBool() &&
  1619. ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 70 ) &&
  1620. ( ( whatToDraw & RENDERVIEW_SUPPRESSMONITORRENDERING ) == 0 ) )
  1621. {
  1622. CViewSetup viewMiddle = GetView( STEREO_EYE_MONO );
  1623. DrawMonitors( viewMiddle );
  1624. }
  1625. #endif
  1626. g_bRenderingView = true;
  1627. // Must be first
  1628. render->SceneBegin();
  1629. pRenderContext.GetFrom( materials );
  1630. pRenderContext->TurnOnToneMapping();
  1631. pRenderContext.SafeRelease();
  1632. // clear happens here probably
  1633. SetupMain3DView( viewRender, nClearFlags );
  1634. bool bDrew3dSkybox = false;
  1635. SkyboxVisibility_t nSkyboxVisible = SKYBOX_NOT_VISIBLE;
  1636. // if the 3d skybox world is drawn, then don't draw the normal skybox
  1637. CSkyboxView *pSkyView = new CSkyboxView( this );
  1638. if ( ( bDrew3dSkybox = pSkyView->Setup( viewRender, &nClearFlags, &nSkyboxVisible ) ) != false )
  1639. {
  1640. AddViewToScene( pSkyView );
  1641. }
  1642. SafeRelease( pSkyView );
  1643. // Force it to clear the framebuffer if they're in solid space.
  1644. if ( ( nClearFlags & VIEW_CLEAR_COLOR ) == 0 )
  1645. {
  1646. if ( enginetrace->GetPointContents( viewRender.origin ) == CONTENTS_SOLID )
  1647. {
  1648. nClearFlags |= VIEW_CLEAR_COLOR;
  1649. }
  1650. }
  1651. // Render world and all entities, particles, etc.
  1652. if( !g_pIntroData )
  1653. {
  1654. ViewDrawScene( bDrew3dSkybox, nSkyboxVisible, viewRender, nClearFlags, VIEW_MAIN, whatToDraw & RENDERVIEW_DRAWVIEWMODEL );
  1655. }
  1656. else
  1657. {
  1658. ViewDrawScene_Intro( viewRender, nClearFlags, *g_pIntroData );
  1659. }
  1660. // We can still use the 'current view' stuff set up in ViewDrawScene
  1661. s_bCanAccessCurrentView = true;
  1662. engine->DrawPortals();
  1663. DisableFog();
  1664. // Finish scene
  1665. render->SceneEnd();
  1666. // Draw lightsources if enabled
  1667. render->DrawLights();
  1668. RenderPlayerSprites();
  1669. // Image-space motion blur
  1670. if ( !building_cubemaps.GetBool() && viewRender.m_bDoBloomAndToneMapping ) // We probably should use a different view. variable here
  1671. {
  1672. static ConVarRef mat_motion_blur_enabled( "mat_motion_blur_enabled" );
  1673. if ( ( mat_motion_blur_enabled.GetInt() ) && ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() >= 90 ) )
  1674. {
  1675. pRenderContext.GetFrom( materials );
  1676. {
  1677. PIXEVENT( pRenderContext, "DoImageSpaceMotionBlur" );
  1678. DoImageSpaceMotionBlur( viewRender, viewRender.x, viewRender.y, viewRender.width, viewRender.height );
  1679. }
  1680. pRenderContext.SafeRelease();
  1681. }
  1682. }
  1683. GetClientModeNormal()->DoPostScreenSpaceEffects( &viewRender );
  1684. // Now actually draw the viewmodel
  1685. DrawViewModels( viewRender, whatToDraw & RENDERVIEW_DRAWVIEWMODEL );
  1686. DrawUnderwaterOverlay();
  1687. PixelVisibility_EndScene();
  1688. // Draw fade over entire screen if needed
  1689. byte color[4];
  1690. bool blend;
  1691. vieweffects->GetFadeParams( &color[0], &color[1], &color[2], &color[3], &blend );
  1692. // Draw an overlay to make it even harder to see inside smoke particle systems.
  1693. DrawSmokeFogOverlay();
  1694. // Overlay screen fade on entire screen
  1695. IMaterial* pMaterial = blend ? m_ModulateSingleColor : m_TranslucentSingleColor;
  1696. render->ViewDrawFade( color, pMaterial );
  1697. PerformScreenOverlay( viewRender.x, viewRender.y, viewRender.width, viewRender.height );
  1698. // Prevent sound stutter if going slow
  1699. engine->Sound_ExtraUpdate();
  1700. if ( !building_cubemaps.GetBool() && viewRender.m_bDoBloomAndToneMapping )
  1701. {
  1702. pRenderContext.GetFrom( materials );
  1703. {
  1704. PIXEVENT( pRenderContext, "DoEnginePostProcessing" );
  1705. bool bFlashlightIsOn = false;
  1706. C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer();
  1707. if ( pLocal )
  1708. {
  1709. bFlashlightIsOn = pLocal->IsEffectActive( EF_DIMLIGHT );
  1710. }
  1711. DoEnginePostProcessing( viewRender.x, viewRender.y, viewRender.width, viewRender.height, bFlashlightIsOn );
  1712. }
  1713. pRenderContext.SafeRelease();
  1714. }
  1715. // And here are the screen-space effects
  1716. if ( IsPC() )
  1717. {
  1718. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "GrabPreColorCorrectedFrame" );
  1719. // Grab the pre-color corrected frame for editing purposes
  1720. engine->GrabPreColorCorrectedFrame( viewRender.x, viewRender.y, viewRender.width, viewRender.height );
  1721. }
  1722. PerformScreenSpaceEffects( 0, 0, viewRender.width, viewRender.height );
  1723. if ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER )
  1724. {
  1725. pRenderContext.GetFrom( materials );
  1726. pRenderContext->SetToneMappingScaleLinear(Vector(1,1,1));
  1727. pRenderContext.SafeRelease();
  1728. }
  1729. CleanupMain3DView( viewRender );
  1730. if ( m_rbTakeFreezeFrame[viewRender.m_eStereoEye ] )
  1731. {
  1732. Rect_t rect;
  1733. rect.x = viewRender.x;
  1734. rect.y = viewRender.y;
  1735. rect.width = viewRender.width;
  1736. rect.height = viewRender.height;
  1737. pRenderContext = materials->GetRenderContext();
  1738. if ( IsX360() )
  1739. {
  1740. // 360 doesn't create the Fullscreen texture
  1741. pRenderContext->CopyRenderTargetToTextureEx( GetFullFrameFrameBufferTexture( 1 ), 0, &rect, &rect );
  1742. }
  1743. else
  1744. {
  1745. pRenderContext->CopyRenderTargetToTextureEx( GetFullscreenTexture(), 0, &rect, &rect );
  1746. }
  1747. pRenderContext.SafeRelease();
  1748. m_rbTakeFreezeFrame[viewRender.m_eStereoEye ] = false;
  1749. }
  1750. pRenderContext = materials->GetRenderContext();
  1751. pRenderContext->SetRenderTarget( saveRenderTarget );
  1752. pRenderContext.SafeRelease();
  1753. // Draw the overlay
  1754. if ( m_bDrawOverlay )
  1755. {
  1756. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DrawOverlay" );
  1757. // This allows us to be ok if there are nested overlay views
  1758. CViewSetup currentView = m_CurrentView;
  1759. CViewSetup tempView = m_OverlayViewSetup;
  1760. tempView.fov = ScaleFOVByWidthRatio( tempView.fov, tempView.m_flAspectRatio / ( 4.0f / 3.0f ) );
  1761. tempView.m_bDoBloomAndToneMapping = false; // FIXME: Hack to get Mark up and running
  1762. m_bDrawOverlay = false;
  1763. RenderView( tempView, m_OverlayClearFlags, m_OverlayDrawFlags );
  1764. m_CurrentView = currentView;
  1765. }
  1766. }
  1767. if ( mat_viewportupscale.GetBool() && mat_viewportscale.GetFloat() < 1.0f )
  1768. {
  1769. CMatRenderContextPtr pRenderContextUpscale( materials );
  1770. ITexture *pFullFrameFB1 = materials->FindTexture( "_rt_FullFrameFB1", TEXTURE_GROUP_RENDER_TARGET );
  1771. IMaterial *pCopyMaterial = materials->FindMaterial( "dev/upscale", TEXTURE_GROUP_OTHER );
  1772. pCopyMaterial->IncrementReferenceCount();
  1773. Rect_t DownscaleRect, UpscaleRect;
  1774. DownscaleRect.x = viewRender.x;
  1775. DownscaleRect.y = viewRender.y;
  1776. DownscaleRect.width = viewRender.width;
  1777. DownscaleRect.height = viewRender.height;
  1778. UpscaleRect.x = viewRender.m_nUnscaledX;
  1779. UpscaleRect.y = viewRender.m_nUnscaledY;
  1780. UpscaleRect.width = viewRender.m_nUnscaledWidth;
  1781. UpscaleRect.height = viewRender.m_nUnscaledHeight;
  1782. pRenderContextUpscale->CopyRenderTargetToTextureEx( pFullFrameFB1, 0, &DownscaleRect, &DownscaleRect );
  1783. pRenderContextUpscale->DrawScreenSpaceRectangle( pCopyMaterial, UpscaleRect.x, UpscaleRect.y, UpscaleRect.width, UpscaleRect.height,
  1784. DownscaleRect.x, DownscaleRect.y, DownscaleRect.x+DownscaleRect.width-1, DownscaleRect.y+DownscaleRect.height-1,
  1785. pFullFrameFB1->GetActualWidth(), pFullFrameFB1->GetActualHeight() );
  1786. pCopyMaterial->DecrementReferenceCount();
  1787. }
  1788. // if we're in VR mode we might need to override the render target
  1789. if( UseVR() )
  1790. {
  1791. saveRenderTarget = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(viewRender.m_eStereoEye - 1), ISourceVirtualReality::RT_Color );
  1792. }
  1793. // Draw the 2D graphics
  1794. render->Push2DView( viewRender, 0, saveRenderTarget, GetFrustum() );
  1795. Render2DEffectsPreHUD( viewRender );
  1796. if ( whatToDraw & RENDERVIEW_DRAWHUD )
  1797. {
  1798. VPROF_BUDGET( "VGui_DrawHud", VPROF_BUDGETGROUP_OTHER_VGUI );
  1799. int viewWidth = viewRender.m_nUnscaledWidth;
  1800. int viewHeight = viewRender.m_nUnscaledHeight;
  1801. int viewActualWidth = viewRender.m_nUnscaledWidth;
  1802. int viewActualHeight = viewRender.m_nUnscaledHeight;
  1803. int viewX = viewRender.m_nUnscaledX;
  1804. int viewY = viewRender.m_nUnscaledY;
  1805. int viewFramebufferX = 0;
  1806. int viewFramebufferY = 0;
  1807. int viewFramebufferWidth = viewWidth;
  1808. int viewFramebufferHeight = viewHeight;
  1809. bool bClear = false;
  1810. bool bPaintMainMenu = false;
  1811. ITexture *pTexture = NULL;
  1812. if( UseVR() )
  1813. {
  1814. if( g_ClientVirtualReality.ShouldRenderHUDInWorld() )
  1815. {
  1816. pTexture = materials->FindTexture( "_rt_gui", NULL, false );
  1817. if( pTexture )
  1818. {
  1819. bPaintMainMenu = true;
  1820. bClear = true;
  1821. viewX = 0;
  1822. viewY = 0;
  1823. viewActualWidth = pTexture->GetActualWidth();
  1824. viewActualHeight = pTexture->GetActualHeight();
  1825. vgui::surface()->GetScreenSize( viewWidth, viewHeight );
  1826. viewFramebufferX = 0;
  1827. if( viewRender.m_eStereoEye == STEREO_EYE_RIGHT && !saveRenderTarget )
  1828. viewFramebufferX = viewFramebufferWidth;
  1829. viewFramebufferY = 0;
  1830. }
  1831. }
  1832. else
  1833. {
  1834. viewFramebufferX = viewRender.m_eStereoEye == STEREO_EYE_RIGHT ? viewWidth : 0;
  1835. viewFramebufferY = 0;
  1836. }
  1837. }
  1838. // Get the render context out of materials to avoid some debug stuff.
  1839. // WARNING THIS REQUIRES THE .SafeRelease below or it'll never release the ref
  1840. pRenderContext = materials->GetRenderContext();
  1841. // clear depth in the backbuffer before we push the render target
  1842. if( bClear )
  1843. {
  1844. pRenderContext->ClearBuffers( false, true, true );
  1845. }
  1846. // constrain where VGUI can render to the view
  1847. pRenderContext->PushRenderTargetAndViewport( pTexture, NULL, viewX, viewY, viewActualWidth, viewActualHeight );
  1848. // If drawing off-screen, force alpha for that pass
  1849. if (pTexture)
  1850. {
  1851. pRenderContext->OverrideAlphaWriteEnable( true, true );
  1852. }
  1853. // let vgui know where to render stuff for the forced-to-framebuffer panels
  1854. if( UseVR() )
  1855. {
  1856. g_pMatSystemSurface->SetFullscreenViewportAndRenderTarget( viewFramebufferX, viewFramebufferY, viewFramebufferWidth, viewFramebufferHeight, saveRenderTarget );
  1857. }
  1858. // clear the render target if we need to
  1859. if( bClear )
  1860. {
  1861. pRenderContext->ClearColor4ub( 0, 0, 0, 0 );
  1862. pRenderContext->ClearBuffers( true, false );
  1863. }
  1864. pRenderContext.SafeRelease();
  1865. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "VGui_DrawHud", __FUNCTION__ );
  1866. // paint the vgui screen
  1867. VGui_PreRender();
  1868. // Make sure the client .dll root panel is at the proper point before doing the "SolveTraverse" calls
  1869. vgui::VPANEL root = enginevgui->GetPanel( PANEL_CLIENTDLL );
  1870. if ( root != 0 )
  1871. {
  1872. vgui::ipanel()->SetSize( root, viewWidth, viewHeight );
  1873. }
  1874. // Same for client .dll tools
  1875. root = enginevgui->GetPanel( PANEL_CLIENTDLL_TOOLS );
  1876. if ( root != 0 )
  1877. {
  1878. vgui::ipanel()->SetSize( root, viewWidth, viewHeight );
  1879. }
  1880. // The crosshair, etc. needs to get at the current setup stuff
  1881. AllowCurrentViewAccess( true );
  1882. // Draw the in-game stuff based on the actual viewport being used
  1883. render->VGui_Paint( PAINT_INGAMEPANELS );
  1884. // maybe paint the main menu and cursor too if we're in stereo hud mode
  1885. if( bPaintMainMenu )
  1886. render->VGui_Paint( PAINT_UIPANELS | PAINT_CURSOR );
  1887. AllowCurrentViewAccess( false );
  1888. VGui_PostRender();
  1889. g_pClientMode->PostRenderVGui();
  1890. pRenderContext = materials->GetRenderContext();
  1891. if (pTexture)
  1892. {
  1893. pRenderContext->OverrideAlphaWriteEnable( false, true );
  1894. }
  1895. pRenderContext->PopRenderTargetAndViewport();
  1896. if ( UseVR() )
  1897. {
  1898. // figure out if we really want to draw the HUD based on freeze cam
  1899. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1900. bool bInFreezeCam = ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM );
  1901. // draw the HUD after the view model so its "I'm closer" depth queues work right.
  1902. if( !bInFreezeCam && g_ClientVirtualReality.ShouldRenderHUDInWorld() )
  1903. {
  1904. // Now we've rendered the HUD to its texture, actually get it on the screen.
  1905. // Since we're drawing it as a 3D object, we need correctly set up frustum, etc.
  1906. int ClearFlags = 0;
  1907. SetupMain3DView( viewRender, ClearFlags );
  1908. // TODO - a bit of a shonky test - basically trying to catch the main menu, the briefing screen, the loadout screen, etc.
  1909. bool bTranslucent = !g_pMatSystemSurface->IsCursorVisible();
  1910. g_ClientVirtualReality.RenderHUDQuad( g_pClientMode->ShouldBlackoutAroundHUD(), bTranslucent );
  1911. CleanupMain3DView( viewRender );
  1912. }
  1913. }
  1914. pRenderContext->Flush();
  1915. pRenderContext.SafeRelease();
  1916. }
  1917. CDebugViewRender::Draw2DDebuggingInfo( viewRender );
  1918. Render2DEffectsPostHUD( viewRender );
  1919. g_bRenderingView = false;
  1920. // We can no longer use the 'current view' stuff set up in ViewDrawScene
  1921. s_bCanAccessCurrentView = false;
  1922. if ( IsPC() )
  1923. {
  1924. CDebugViewRender::GenerateOverdrawForTesting();
  1925. }
  1926. render->PopView( GetFrustum() );
  1927. g_WorldListCache.Flush();
  1928. }
  1929. //-----------------------------------------------------------------------------
  1930. // Purpose: Renders extra 2D effects in derived classes while the 2D view is on the stack
  1931. //-----------------------------------------------------------------------------
  1932. void CViewRender::Render2DEffectsPreHUD( const CViewSetup &viewRender )
  1933. {
  1934. }
  1935. //-----------------------------------------------------------------------------
  1936. // Purpose: Renders extra 2D effects in derived classes while the 2D view is on the stack
  1937. //-----------------------------------------------------------------------------
  1938. void CViewRender::Render2DEffectsPostHUD( const CViewSetup &viewRender )
  1939. {
  1940. }
  1941. //-----------------------------------------------------------------------------
  1942. //
  1943. // NOTE: Below here is all of the stuff that needs to be done for water rendering
  1944. //
  1945. //-----------------------------------------------------------------------------
  1946. //-----------------------------------------------------------------------------
  1947. // Determines what kind of water we're going to use
  1948. //-----------------------------------------------------------------------------
  1949. void CViewRender::DetermineWaterRenderInfo( const VisibleFogVolumeInfo_t &fogVolumeInfo, WaterRenderInfo_t &info )
  1950. {
  1951. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  1952. // By default, assume cheap water (even if there's no water in the scene!)
  1953. info.m_bCheapWater = true;
  1954. info.m_bRefract = false;
  1955. info.m_bReflect = false;
  1956. info.m_bReflectEntities = false;
  1957. info.m_bDrawWaterSurface = false;
  1958. info.m_bOpaqueWater = true;
  1959. IMaterial *pWaterMaterial = fogVolumeInfo.m_pFogVolumeMaterial;
  1960. if (( fogVolumeInfo.m_nVisibleFogVolume == -1 ) || !pWaterMaterial )
  1961. return;
  1962. // Use cheap water if mat_drawwater is set
  1963. info.m_bDrawWaterSurface = mat_drawwater.GetBool();
  1964. if ( !info.m_bDrawWaterSurface )
  1965. {
  1966. info.m_bOpaqueWater = false;
  1967. return;
  1968. }
  1969. #ifdef _X360
  1970. bool bForceExpensive = false;
  1971. #else
  1972. bool bForceExpensive = r_waterforceexpensive.GetBool();
  1973. #endif
  1974. bool bForceReflectEntities = r_waterforcereflectentities.GetBool();
  1975. #ifdef PORTAL
  1976. switch( g_pPortalRender->ShouldForceCheaperWaterLevel() )
  1977. {
  1978. case 0: //force cheap water
  1979. info.m_bCheapWater = true;
  1980. return;
  1981. case 1: //downgrade level to "simple reflection"
  1982. bForceExpensive = false;
  1983. case 2: //downgrade level to "reflect world"
  1984. bForceReflectEntities = false;
  1985. default:
  1986. break;
  1987. };
  1988. #endif
  1989. // Determine if the water surface is opaque or not
  1990. info.m_bOpaqueWater = !pWaterMaterial->IsTranslucent();
  1991. // DX level 70 can't handle anything but cheap water
  1992. if (engine->GetDXSupportLevel() < 80)
  1993. return;
  1994. bool bForceCheap = false;
  1995. // The material can override the default settings though
  1996. IMaterialVar *pForceCheapVar = pWaterMaterial->FindVar( "$forcecheap", NULL, false );
  1997. IMaterialVar *pForceExpensiveVar = pWaterMaterial->FindVar( "$forceexpensive", NULL, false );
  1998. if ( pForceCheapVar && pForceCheapVar->IsDefined() )
  1999. {
  2000. bForceCheap = ( pForceCheapVar->GetIntValueFast() != 0 );
  2001. if ( bForceCheap )
  2002. {
  2003. bForceExpensive = false;
  2004. }
  2005. }
  2006. if ( !bForceCheap && pForceExpensiveVar && pForceExpensiveVar->IsDefined() )
  2007. {
  2008. bForceExpensive = bForceExpensive || ( pForceExpensiveVar->GetIntValueFast() != 0 );
  2009. }
  2010. bool bDebugCheapWater = r_debugcheapwater.GetBool();
  2011. if( bDebugCheapWater )
  2012. {
  2013. Msg( "Water material: %s dist to water: %f\nforcecheap: %s forceexpensive: %s\n",
  2014. pWaterMaterial->GetName(), fogVolumeInfo.m_flDistanceToWater,
  2015. bForceCheap ? "true" : "false", bForceExpensive ? "true" : "false" );
  2016. }
  2017. // Unless expensive water is active, reflections are off.
  2018. bool bLocalReflection;
  2019. #ifdef _X360
  2020. if( !r_WaterDrawReflection.GetBool() )
  2021. #else
  2022. if( !bForceExpensive || !r_WaterDrawReflection.GetBool() )
  2023. #endif
  2024. {
  2025. bLocalReflection = false;
  2026. }
  2027. else
  2028. {
  2029. IMaterialVar *pReflectTextureVar = pWaterMaterial->FindVar( "$reflecttexture", NULL, false );
  2030. bLocalReflection = pReflectTextureVar && (pReflectTextureVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE);
  2031. }
  2032. // Brian says FIXME: I disabled cheap water LOD when local specular is specified.
  2033. // There are very few places that appear to actually
  2034. // take advantage of it (places where water is in the PVS, but outside of LOD range).
  2035. // It was 2 hours before code lock, and I had the choice of either doubling fill-rate everywhere
  2036. // by making cheap water lod actually work (the water LOD wasn't actually rendering!!!)
  2037. // or to just always render the reflection + refraction if there's a local specular specified.
  2038. // Note that water LOD *does* work with refract-only water
  2039. // Gary says: I'm reverting this change so that water LOD works on dx9 for ep2.
  2040. // Check if the water is out of the cheap water LOD range; if so, use cheap water
  2041. #ifdef _X360
  2042. if ( !bForceExpensive && ( bForceCheap || ( fogVolumeInfo.m_flDistanceToWater >= m_flCheapWaterEndDistance ) ) )
  2043. {
  2044. return;
  2045. }
  2046. #else
  2047. if ( ( (fogVolumeInfo.m_flDistanceToWater >= m_flCheapWaterEndDistance) && !bLocalReflection ) || bForceCheap )
  2048. return;
  2049. #endif
  2050. // Get the material that is for the water surface that is visible and check to see
  2051. // what render targets need to be rendered, if any.
  2052. if ( !r_WaterDrawRefraction.GetBool() )
  2053. {
  2054. info.m_bRefract = false;
  2055. }
  2056. else
  2057. {
  2058. IMaterialVar *pRefractTextureVar = pWaterMaterial->FindVar( "$refracttexture", NULL, false );
  2059. info.m_bRefract = pRefractTextureVar && (pRefractTextureVar->GetType() == MATERIAL_VAR_TYPE_TEXTURE);
  2060. // Refractive water can be seen through
  2061. if ( info.m_bRefract )
  2062. {
  2063. info.m_bOpaqueWater = false;
  2064. }
  2065. }
  2066. info.m_bReflect = bLocalReflection;
  2067. if ( info.m_bReflect )
  2068. {
  2069. if( bForceReflectEntities )
  2070. {
  2071. info.m_bReflectEntities = true;
  2072. }
  2073. else
  2074. {
  2075. IMaterialVar *pReflectEntitiesVar = pWaterMaterial->FindVar( "$reflectentities", NULL, false );
  2076. info.m_bReflectEntities = pReflectEntitiesVar && (pReflectEntitiesVar->GetIntValueFast() != 0);
  2077. }
  2078. }
  2079. info.m_bCheapWater = !info.m_bReflect && !info.m_bRefract;
  2080. if( bDebugCheapWater )
  2081. {
  2082. Warning( "refract: %s reflect: %s\n", info.m_bRefract ? "true" : "false", info.m_bReflect ? "true" : "false" );
  2083. }
  2084. }
  2085. //-----------------------------------------------------------------------------
  2086. // Draws the world and all entities
  2087. //-----------------------------------------------------------------------------
  2088. void CViewRender::DrawWorldAndEntities( bool bDrawSkybox, const CViewSetup &viewIn, int nClearFlags, ViewCustomVisibility_t *pCustomVisibility )
  2089. {
  2090. MDLCACHE_CRITICAL_SECTION();
  2091. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2092. VisibleFogVolumeInfo_t fogVolumeInfo;
  2093. #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
  2094. if( g_pPortalRender->GetViewRecursionLevel() == 0 )
  2095. {
  2096. render->GetVisibleFogVolume( viewIn.origin, &fogVolumeInfo );
  2097. }
  2098. else
  2099. {
  2100. render->GetVisibleFogVolume( g_pPortalRender->GetExitPortalFogOrigin(), &fogVolumeInfo );
  2101. }
  2102. #else
  2103. render->GetVisibleFogVolume( viewIn.origin, &fogVolumeInfo );
  2104. #endif
  2105. WaterRenderInfo_t info;
  2106. DetermineWaterRenderInfo( fogVolumeInfo, info );
  2107. if ( info.m_bCheapWater )
  2108. {
  2109. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "bCheapWater" );
  2110. cplane_t glassReflectionPlane;
  2111. if ( IsReflectiveGlassInView( viewIn, glassReflectionPlane ) )
  2112. {
  2113. CRefPtr<CReflectiveGlassView> pGlassReflectionView = new CReflectiveGlassView( this );
  2114. pGlassReflectionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, bDrawSkybox, fogVolumeInfo, info, glassReflectionPlane );
  2115. AddViewToScene( pGlassReflectionView );
  2116. CRefPtr<CRefractiveGlassView> pGlassRefractionView = new CRefractiveGlassView( this );
  2117. pGlassRefractionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, bDrawSkybox, fogVolumeInfo, info, glassReflectionPlane );
  2118. AddViewToScene( pGlassRefractionView );
  2119. }
  2120. CRefPtr<CSimpleWorldView> pNoWaterView = new CSimpleWorldView( this );
  2121. pNoWaterView->Setup( viewIn, nClearFlags, bDrawSkybox, fogVolumeInfo, info, pCustomVisibility );
  2122. AddViewToScene( pNoWaterView );
  2123. return;
  2124. }
  2125. Assert( !pCustomVisibility );
  2126. // Blat out the visible fog leaf if we're not going to use it
  2127. if ( !r_ForceWaterLeaf.GetBool() )
  2128. {
  2129. fogVolumeInfo.m_nVisibleFogVolumeLeaf = -1;
  2130. }
  2131. // We can see water of some sort
  2132. if ( !fogVolumeInfo.m_bEyeInFogVolume )
  2133. {
  2134. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CAboveWaterView" );
  2135. CRefPtr<CAboveWaterView> pAboveWaterView = new CAboveWaterView( this );
  2136. pAboveWaterView->Setup( viewIn, bDrawSkybox, fogVolumeInfo, info );
  2137. AddViewToScene( pAboveWaterView );
  2138. }
  2139. else
  2140. {
  2141. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CUnderWaterView" );
  2142. CRefPtr<CUnderWaterView> pUnderWaterView = new CUnderWaterView( this );
  2143. pUnderWaterView->Setup( viewIn, bDrawSkybox, fogVolumeInfo, info );
  2144. AddViewToScene( pUnderWaterView );
  2145. }
  2146. }
  2147. //-----------------------------------------------------------------------------
  2148. // Pushes a water render target
  2149. //-----------------------------------------------------------------------------
  2150. static Vector SavedLinearLightMapScale(-1,-1,-1); // x<0 = no saved scale
  2151. static void SetLightmapScaleForWater(void)
  2152. {
  2153. if (g_pMaterialSystemHardwareConfig->GetHDRType()==HDR_TYPE_INTEGER)
  2154. {
  2155. CMatRenderContextPtr pRenderContext( materials );
  2156. SavedLinearLightMapScale=pRenderContext->GetToneMappingScaleLinear();
  2157. Vector t25=SavedLinearLightMapScale;
  2158. t25*=0.25;
  2159. pRenderContext->SetToneMappingScaleLinear(t25);
  2160. }
  2161. }
  2162. //-----------------------------------------------------------------------------
  2163. // Returns true if the view plane intersects the water
  2164. //-----------------------------------------------------------------------------
  2165. bool DoesViewPlaneIntersectWater( float waterZ, int leafWaterDataID )
  2166. {
  2167. if ( leafWaterDataID == -1 )
  2168. return false;
  2169. #ifdef PORTAL //when rendering portal views point/plane intersections just don't cut it.
  2170. if( g_pPortalRender->GetViewRecursionLevel() != 0 )
  2171. return g_pPortalRender->DoesExitPortalViewIntersectWaterPlane( waterZ, leafWaterDataID );
  2172. #endif
  2173. CMatRenderContextPtr pRenderContext( materials );
  2174. VMatrix viewMatrix, projectionMatrix, viewProjectionMatrix, inverseViewProjectionMatrix;
  2175. pRenderContext->GetMatrix( MATERIAL_VIEW, &viewMatrix );
  2176. pRenderContext->GetMatrix( MATERIAL_PROJECTION, &projectionMatrix );
  2177. MatrixMultiply( projectionMatrix, viewMatrix, viewProjectionMatrix );
  2178. MatrixInverseGeneral( viewProjectionMatrix, inverseViewProjectionMatrix );
  2179. Vector mins, maxs;
  2180. ClearBounds( mins, maxs );
  2181. Vector testPoint[4];
  2182. testPoint[0].Init( -1.0f, -1.0f, 0.0f );
  2183. testPoint[1].Init( -1.0f, 1.0f, 0.0f );
  2184. testPoint[2].Init( 1.0f, -1.0f, 0.0f );
  2185. testPoint[3].Init( 1.0f, 1.0f, 0.0f );
  2186. int i;
  2187. bool bAbove = false;
  2188. bool bBelow = false;
  2189. float fudge = 7.0f;
  2190. for( i = 0; i < 4; i++ )
  2191. {
  2192. Vector worldPos;
  2193. Vector3DMultiplyPositionProjective( inverseViewProjectionMatrix, testPoint[i], worldPos );
  2194. AddPointToBounds( worldPos, mins, maxs );
  2195. // Warning( "viewplanez: %f waterZ: %f\n", worldPos.z, waterZ );
  2196. if( worldPos.z + fudge > waterZ )
  2197. {
  2198. bAbove = true;
  2199. }
  2200. if( worldPos.z - fudge < waterZ )
  2201. {
  2202. bBelow = true;
  2203. }
  2204. }
  2205. // early out if the near plane doesn't cross the z plane of the water.
  2206. if( !( bAbove && bBelow ) )
  2207. return false;
  2208. Vector vecFudge( fudge, fudge, fudge );
  2209. mins -= vecFudge;
  2210. maxs += vecFudge;
  2211. // the near plane does cross the z value for the visible water volume. Call into
  2212. // the engine to find out if the near plane intersects the water volume.
  2213. return render->DoesBoxIntersectWaterVolume( mins, maxs, leafWaterDataID );
  2214. }
  2215. #ifdef PORTAL
  2216. //-----------------------------------------------------------------------------
  2217. // Purpose: Draw the scene during another draw scene call. We must draw our portals
  2218. // after opaques but before translucents, so this ViewDrawScene resets the view
  2219. // and doesn't flag the rendering as ended when it ends.
  2220. // Input : bDrawSkybox - do we draw the skybox
  2221. // &view - the camera view to render from
  2222. // nClearFlags - how to clear the buffer
  2223. //-----------------------------------------------------------------------------
  2224. void CViewRender::ViewDrawScene_PortalStencil( const CViewSetup &viewIn, ViewCustomVisibility_t *pCustomVisibility )
  2225. {
  2226. VPROF( "CViewRender::ViewDrawScene_PortalStencil" );
  2227. CViewSetup view( viewIn );
  2228. // Record old view stats
  2229. Vector vecOldOrigin = CurrentViewOrigin();
  2230. QAngle vecOldAngles = CurrentViewAngles();
  2231. int iCurrentViewID = g_CurrentViewID;
  2232. int iRecursionLevel = g_pPortalRender->GetViewRecursionLevel();
  2233. Assert( iRecursionLevel > 0 );
  2234. //get references to reflection textures
  2235. CTextureReference pPrimaryWaterReflectionTexture;
  2236. pPrimaryWaterReflectionTexture.Init( GetWaterReflectionTexture() );
  2237. CTextureReference pReplacementWaterReflectionTexture;
  2238. pReplacementWaterReflectionTexture.Init( portalrendertargets->GetWaterReflectionTextureForStencilDepth( iRecursionLevel ) );
  2239. //get references to refraction textures
  2240. CTextureReference pPrimaryWaterRefractionTexture;
  2241. pPrimaryWaterRefractionTexture.Init( GetWaterRefractionTexture() );
  2242. CTextureReference pReplacementWaterRefractionTexture;
  2243. pReplacementWaterRefractionTexture.Init( portalrendertargets->GetWaterRefractionTextureForStencilDepth( iRecursionLevel ) );
  2244. //swap texture contents for the primary render targets with those we set aside for this recursion level
  2245. if( pReplacementWaterReflectionTexture != NULL )
  2246. pPrimaryWaterReflectionTexture->SwapContents( pReplacementWaterReflectionTexture );
  2247. if( pReplacementWaterRefractionTexture != NULL )
  2248. pPrimaryWaterRefractionTexture->SwapContents( pReplacementWaterRefractionTexture );
  2249. bool bDrew3dSkybox = false;
  2250. SkyboxVisibility_t nSkyboxVisible = SKYBOX_NOT_VISIBLE;
  2251. int iClearFlags = 0;
  2252. Draw3dSkyboxworld_Portal( view, iClearFlags, bDrew3dSkybox, nSkyboxVisible );
  2253. bool drawSkybox = r_skybox.GetBool();
  2254. if ( bDrew3dSkybox || ( nSkyboxVisible == SKYBOX_NOT_VISIBLE ) )
  2255. {
  2256. drawSkybox = false;
  2257. }
  2258. //generate unique view ID's for each stencil view
  2259. view_id_t iNewViewID = (view_id_t)g_pPortalRender->GetCurrentViewId();
  2260. SetupCurrentView( view.origin, view.angles, (view_id_t)iNewViewID );
  2261. // update vis data
  2262. unsigned int visFlags;
  2263. SetupVis( view, visFlags, pCustomVisibility );
  2264. VisibleFogVolumeInfo_t fogInfo;
  2265. if( g_pPortalRender->GetViewRecursionLevel() == 0 )
  2266. {
  2267. render->GetVisibleFogVolume( view.origin, &fogInfo );
  2268. }
  2269. else
  2270. {
  2271. render->GetVisibleFogVolume( g_pPortalRender->GetExitPortalFogOrigin(), &fogInfo );
  2272. }
  2273. WaterRenderInfo_t waterInfo;
  2274. DetermineWaterRenderInfo( fogInfo, waterInfo );
  2275. if ( waterInfo.m_bCheapWater )
  2276. {
  2277. cplane_t glassReflectionPlane;
  2278. if ( IsReflectiveGlassInView( viewIn, glassReflectionPlane ) )
  2279. {
  2280. CRefPtr<CReflectiveGlassView> pGlassReflectionView = new CReflectiveGlassView( this );
  2281. pGlassReflectionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, glassReflectionPlane );
  2282. AddViewToScene( pGlassReflectionView );
  2283. CRefPtr<CRefractiveGlassView> pGlassRefractionView = new CRefractiveGlassView( this );
  2284. pGlassRefractionView->Setup( viewIn, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, glassReflectionPlane );
  2285. AddViewToScene( pGlassRefractionView );
  2286. }
  2287. CSimpleWorldView *pClientView = new CSimpleWorldView( this );
  2288. pClientView->Setup( view, VIEW_CLEAR_OBEY_STENCIL, drawSkybox, fogInfo, waterInfo, pCustomVisibility );
  2289. AddViewToScene( pClientView );
  2290. SafeRelease( pClientView );
  2291. }
  2292. else
  2293. {
  2294. // We can see water of some sort
  2295. if ( !fogInfo.m_bEyeInFogVolume )
  2296. {
  2297. CRefPtr<CAboveWaterView> pAboveWaterView = new CAboveWaterView( this );
  2298. pAboveWaterView->Setup( viewIn, drawSkybox, fogInfo, waterInfo );
  2299. AddViewToScene( pAboveWaterView );
  2300. }
  2301. else
  2302. {
  2303. CRefPtr<CUnderWaterView> pUnderWaterView = new CUnderWaterView( this );
  2304. pUnderWaterView->Setup( viewIn, drawSkybox, fogInfo, waterInfo );
  2305. AddViewToScene( pUnderWaterView );
  2306. }
  2307. }
  2308. // Disable fog for the rest of the stuff
  2309. DisableFog();
  2310. CGlowOverlay::DrawOverlays( view.m_bCacheFullSceneState );
  2311. // Draw rain..
  2312. DrawPrecipitation();
  2313. //prerender version only
  2314. // issue the pixel visibility tests
  2315. PixelVisibility_EndCurrentView();
  2316. // Make sure sound doesn't stutter
  2317. engine->Sound_ExtraUpdate();
  2318. // Debugging info goes over the top
  2319. CDebugViewRender::Draw3DDebuggingInfo( view );
  2320. // Return to the previous view
  2321. SetupCurrentView( vecOldOrigin, vecOldAngles, (view_id_t)iCurrentViewID );
  2322. g_CurrentViewID = iCurrentViewID; //just in case the cast to view_id_t screwed up the id #
  2323. //swap back the water render targets
  2324. if( pReplacementWaterReflectionTexture != NULL )
  2325. pPrimaryWaterReflectionTexture->SwapContents( pReplacementWaterReflectionTexture );
  2326. if( pReplacementWaterRefractionTexture != NULL )
  2327. pPrimaryWaterRefractionTexture->SwapContents( pReplacementWaterRefractionTexture );
  2328. }
  2329. void CViewRender::Draw3dSkyboxworld_Portal( const CViewSetup &view, int &nClearFlags, bool &bDrew3dSkybox, SkyboxVisibility_t &nSkyboxVisible, ITexture *pRenderTarget )
  2330. {
  2331. CRefPtr<CPortalSkyboxView> pSkyView = new CPortalSkyboxView( this );
  2332. if ( ( bDrew3dSkybox = pSkyView->Setup( view, &nClearFlags, &nSkyboxVisible, pRenderTarget ) ) == true )
  2333. {
  2334. AddViewToScene( pSkyView );
  2335. }
  2336. }
  2337. #endif //PORTAL
  2338. //-----------------------------------------------------------------------------
  2339. // Methods related to controlling the cheap water distance
  2340. //-----------------------------------------------------------------------------
  2341. void CViewRender::SetCheapWaterStartDistance( float flCheapWaterStartDistance )
  2342. {
  2343. m_flCheapWaterStartDistance = flCheapWaterStartDistance;
  2344. }
  2345. void CViewRender::SetCheapWaterEndDistance( float flCheapWaterEndDistance )
  2346. {
  2347. m_flCheapWaterEndDistance = flCheapWaterEndDistance;
  2348. }
  2349. void CViewRender::GetWaterLODParams( float &flCheapWaterStartDistance, float &flCheapWaterEndDistance )
  2350. {
  2351. flCheapWaterStartDistance = m_flCheapWaterStartDistance;
  2352. flCheapWaterEndDistance = m_flCheapWaterEndDistance;
  2353. }
  2354. //-----------------------------------------------------------------------------
  2355. // Purpose:
  2356. // Input : &view -
  2357. // &introData -
  2358. //-----------------------------------------------------------------------------
  2359. void CViewRender::ViewDrawScene_Intro( const CViewSetup &viewRender, int nClearFlags, const IntroData_t &introData )
  2360. {
  2361. VPROF( "CViewRender::ViewDrawScene" );
  2362. CMatRenderContextPtr pRenderContext( materials );
  2363. // this allows the refract texture to be updated once per *scene* on 360
  2364. // (e.g. once for a monitor scene and once for the main scene)
  2365. g_viewscene_refractUpdateFrame = gpGlobals->framecount - 1;
  2366. // -----------------------------------------------------------------------
  2367. // Set the clear color to black since we are going to be adding up things
  2368. // in the frame buffer.
  2369. // -----------------------------------------------------------------------
  2370. // Clear alpha to 255 so that masking with the vortigaunts (0) works properly.
  2371. pRenderContext->ClearColor4ub( 0, 0, 0, 255 );
  2372. // -----------------------------------------------------------------------
  2373. // Draw the primary scene and copy it to the first framebuffer texture
  2374. // -----------------------------------------------------------------------
  2375. unsigned int visFlags;
  2376. // NOTE: We only increment this once since time doesn't move forward.
  2377. ParticleMgr()->IncrementFrameCode();
  2378. if( introData.m_bDrawPrimary )
  2379. {
  2380. CViewSetup playerView( viewRender );
  2381. playerView.origin = introData.m_vecCameraView;
  2382. playerView.angles = introData.m_vecCameraViewAngles;
  2383. if ( introData.m_playerViewFOV )
  2384. {
  2385. playerView.fov = ScaleFOVByWidthRatio( introData.m_playerViewFOV, engine->GetScreenAspectRatio() / ( 4.0f / 3.0f ) );
  2386. }
  2387. g_pClientShadowMgr->PreRender();
  2388. // Shadowed flashlights supported on ps_2_b and up...
  2389. if ( r_flashlightdepthtexture.GetBool() )
  2390. {
  2391. g_pClientShadowMgr->ComputeShadowDepthTextures( playerView );
  2392. }
  2393. SetupCurrentView( playerView.origin, playerView.angles, VIEW_INTRO_PLAYER );
  2394. // Invoke pre-render methods
  2395. IGameSystem::PreRenderAllSystems();
  2396. // Start view, clear frame/z buffer if necessary
  2397. SetupVis( playerView, visFlags );
  2398. render->Push3DView( playerView, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH, NULL, GetFrustum() );
  2399. DrawWorldAndEntities( true /* drawSkybox */, playerView, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH );
  2400. render->PopView( GetFrustum() );
  2401. // Free shadow depth textures for use in future view
  2402. if ( r_flashlightdepthtexture.GetBool() )
  2403. {
  2404. g_pClientShadowMgr->UnlockAllShadowDepthTextures();
  2405. }
  2406. }
  2407. else
  2408. {
  2409. pRenderContext->ClearBuffers( true, true );
  2410. }
  2411. Rect_t actualRect;
  2412. UpdateScreenEffectTexture( 0, viewRender.x, viewRender.y, viewRender.width, viewRender.height, false, &actualRect );
  2413. g_pClientShadowMgr->PreRender();
  2414. // Shadowed flashlights supported on ps_2_b and up...
  2415. if ( r_flashlightdepthtexture.GetBool() )
  2416. {
  2417. g_pClientShadowMgr->ComputeShadowDepthTextures( viewRender );
  2418. }
  2419. // -----------------------------------------------------------------------
  2420. // Draw the secondary scene and copy it to the second framebuffer texture
  2421. // -----------------------------------------------------------------------
  2422. SetupCurrentView( viewRender.origin, viewRender.angles, VIEW_INTRO_CAMERA );
  2423. // Invoke pre-render methods
  2424. IGameSystem::PreRenderAllSystems();
  2425. // Start view, clear frame/z buffer if necessary
  2426. SetupVis( viewRender, visFlags );
  2427. // Clear alpha to 255 so that masking with the vortigaunts (0) works properly.
  2428. pRenderContext->ClearColor4ub( 0, 0, 0, 255 );
  2429. DrawWorldAndEntities( true /* drawSkybox */, viewRender, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH );
  2430. UpdateScreenEffectTexture( 1, viewRender.x, viewRender.y, viewRender.width, viewRender.height );
  2431. // -----------------------------------------------------------------------
  2432. // Draw quads on the screen for each screenspace pass.
  2433. // -----------------------------------------------------------------------
  2434. // Find the material that we use to render the overlays
  2435. IMaterial *pOverlayMaterial = materials->FindMaterial( "scripted/intro_screenspaceeffect", TEXTURE_GROUP_OTHER );
  2436. IMaterialVar *pModeVar = pOverlayMaterial->FindVar( "$mode", NULL );
  2437. IMaterialVar *pAlphaVar = pOverlayMaterial->FindVar( "$alpha", NULL );
  2438. pRenderContext->ClearBuffers( true, true );
  2439. pRenderContext->MatrixMode( MATERIAL_VIEW );
  2440. pRenderContext->PushMatrix();
  2441. pRenderContext->LoadIdentity();
  2442. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  2443. pRenderContext->PushMatrix();
  2444. pRenderContext->LoadIdentity();
  2445. int passID;
  2446. for( passID = 0; passID < introData.m_Passes.Count(); passID++ )
  2447. {
  2448. const IntroDataBlendPass_t& pass = introData.m_Passes[passID];
  2449. if ( pass.m_Alpha == 0 )
  2450. continue;
  2451. // Pick one of the blend modes for the material.
  2452. if ( pass.m_BlendMode >= 0 && pass.m_BlendMode <= 9 )
  2453. {
  2454. pModeVar->SetIntValue( pass.m_BlendMode );
  2455. }
  2456. else
  2457. {
  2458. Assert(0);
  2459. }
  2460. // Set the alpha value for the material.
  2461. pAlphaVar->SetFloatValue( pass.m_Alpha );
  2462. // Draw a quad for this pass.
  2463. ITexture *pTexture = GetFullFrameFrameBufferTexture( 0 );
  2464. pRenderContext->DrawScreenSpaceRectangle( pOverlayMaterial, 0, 0, viewRender.width, viewRender.height,
  2465. actualRect.x, actualRect.y, actualRect.x+actualRect.width-1, actualRect.y+actualRect.height-1,
  2466. pTexture->GetActualWidth(), pTexture->GetActualHeight() );
  2467. }
  2468. pRenderContext->MatrixMode( MATERIAL_VIEW );
  2469. pRenderContext->PopMatrix();
  2470. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  2471. pRenderContext->PopMatrix();
  2472. // Draw the starfield
  2473. // FIXME
  2474. // blur?
  2475. // Disable fog for the rest of the stuff
  2476. DisableFog();
  2477. // Here are the overlays...
  2478. CGlowOverlay::DrawOverlays( viewRender.m_bCacheFullSceneState );
  2479. // issue the pixel visibility tests
  2480. PixelVisibility_EndCurrentView();
  2481. // And here are the screen-space effects
  2482. PerformScreenSpaceEffects( 0, 0, viewRender.width, viewRender.height );
  2483. // Make sure sound doesn't stutter
  2484. engine->Sound_ExtraUpdate();
  2485. // Debugging info goes over the top
  2486. CDebugViewRender::Draw3DDebuggingInfo( viewRender );
  2487. // Let the particle manager simulate things that haven't been simulated.
  2488. ParticleMgr()->PostRender();
  2489. FinishCurrentView();
  2490. // Free shadow depth textures for use in future view
  2491. if ( r_flashlightdepthtexture.GetBool() )
  2492. {
  2493. g_pClientShadowMgr->UnlockAllShadowDepthTextures();
  2494. }
  2495. }
  2496. //-----------------------------------------------------------------------------
  2497. // Purpose: Sets up scene and renders camera view
  2498. // Input : cameraNum -
  2499. // &cameraView
  2500. // *localPlayer -
  2501. // x -
  2502. // y -
  2503. // width -
  2504. // height -
  2505. // highend -
  2506. // Output : Returns true on success, false on failure.
  2507. //-----------------------------------------------------------------------------
  2508. bool CViewRender::DrawOneMonitor( ITexture *pRenderTarget, int cameraNum, C_PointCamera *pCameraEnt,
  2509. const CViewSetup &cameraView, C_BasePlayer *localPlayer, int x, int y, int width, int height )
  2510. {
  2511. #ifdef USE_MONITORS
  2512. VPROF_INCREMENT_COUNTER( "cameras rendered", 1 );
  2513. // Setup fog state for the camera.
  2514. fogparams_t oldFogParams;
  2515. float flOldZFar = 0.0f;
  2516. bool fogEnabled = pCameraEnt->IsFogEnabled();
  2517. CViewSetup monitorView = cameraView;
  2518. fogparams_t *pFogParams = NULL;
  2519. if ( fogEnabled )
  2520. {
  2521. if ( !localPlayer )
  2522. return false;
  2523. pFogParams = localPlayer->GetFogParams();
  2524. // Save old fog data.
  2525. oldFogParams = *pFogParams;
  2526. flOldZFar = cameraView.zFar;
  2527. pFogParams->enable = true;
  2528. pFogParams->start = pCameraEnt->GetFogStart();
  2529. pFogParams->end = pCameraEnt->GetFogEnd();
  2530. pFogParams->farz = pCameraEnt->GetFogEnd();
  2531. pFogParams->maxdensity = pCameraEnt->GetFogMaxDensity();
  2532. unsigned char r, g, b;
  2533. pCameraEnt->GetFogColor( r, g, b );
  2534. pFogParams->colorPrimary.SetR( r );
  2535. pFogParams->colorPrimary.SetG( g );
  2536. pFogParams->colorPrimary.SetB( b );
  2537. monitorView.zFar = pCameraEnt->GetFogEnd();
  2538. }
  2539. monitorView.width = width;
  2540. monitorView.height = height;
  2541. monitorView.x = x;
  2542. monitorView.y = y;
  2543. monitorView.origin = pCameraEnt->GetAbsOrigin();
  2544. monitorView.angles = pCameraEnt->GetAbsAngles();
  2545. monitorView.fov = pCameraEnt->GetFOV();
  2546. monitorView.m_bOrtho = false;
  2547. monitorView.m_flAspectRatio = pCameraEnt->UseScreenAspectRatio() ? 0.0f : 1.0f;
  2548. monitorView.m_bViewToProjectionOverride = false;
  2549. // @MULTICORE (toml 8/11/2006): this should be a renderer....
  2550. Frustum frustum;
  2551. render->Push3DView( monitorView, VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, pRenderTarget, (VPlane *)frustum );
  2552. ViewDrawScene( false, SKYBOX_2DSKYBOX_VISIBLE, monitorView, 0, VIEW_MONITOR );
  2553. render->PopView( frustum );
  2554. // Reset the world fog parameters.
  2555. if ( fogEnabled )
  2556. {
  2557. if ( pFogParams )
  2558. {
  2559. *pFogParams = oldFogParams;
  2560. }
  2561. monitorView.zFar = flOldZFar;
  2562. }
  2563. #endif // USE_MONITORS
  2564. return true;
  2565. }
  2566. void CViewRender::DrawMonitors( const CViewSetup &cameraView )
  2567. {
  2568. #ifdef PORTAL
  2569. g_pPortalRender->DrawPortalsToTextures( this, cameraView );
  2570. #endif
  2571. #ifdef USE_MONITORS
  2572. // Early out if no cameras
  2573. C_PointCamera *pCameraEnt = GetPointCameraList();
  2574. if ( !pCameraEnt )
  2575. return;
  2576. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  2577. #ifdef _DEBUG
  2578. g_bRenderingCameraView = true;
  2579. #endif
  2580. // FIXME: this should check for the ability to do a render target maybe instead.
  2581. // FIXME: shouldn't have to truck through all of the visible entities for this!!!!
  2582. ITexture *pCameraTarget = GetCameraTexture();
  2583. int width = pCameraTarget->GetActualWidth();
  2584. int height = pCameraTarget->GetActualHeight();
  2585. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  2586. int cameraNum;
  2587. for ( cameraNum = 0; pCameraEnt != NULL; pCameraEnt = pCameraEnt->m_pNext )
  2588. {
  2589. if ( !pCameraEnt->IsActive() || pCameraEnt->IsDormant() )
  2590. continue;
  2591. if ( !DrawOneMonitor( pCameraTarget, cameraNum, pCameraEnt, cameraView, player, 0, 0, width, height ) )
  2592. continue;
  2593. ++cameraNum;
  2594. }
  2595. if ( IsX360() && cameraNum > 0 )
  2596. {
  2597. // resolve render target to system memory texture
  2598. // resolving *after* all monitors drawn to ensure a single blit using fastest resolve path
  2599. CMatRenderContextPtr pRenderContext( materials );
  2600. pRenderContext->PushRenderTargetAndViewport( pCameraTarget );
  2601. pRenderContext->CopyRenderTargetToTextureEx( pCameraTarget, 0, NULL, NULL );
  2602. pRenderContext->PopRenderTargetAndViewport();
  2603. }
  2604. #ifdef _DEBUG
  2605. g_bRenderingCameraView = false;
  2606. #endif
  2607. #endif // USE_MONITORS
  2608. }
  2609. //-----------------------------------------------------------------------------
  2610. //
  2611. //-----------------------------------------------------------------------------
  2612. ClientWorldListInfo_t *ClientWorldListInfo_t::AllocPooled( const ClientWorldListInfo_t &exemplar )
  2613. {
  2614. size_t nBytes = AlignValue( ( exemplar.m_LeafCount * ((sizeof(LeafIndex_t) * 2) + sizeof(LeafFogVolume_t)) ), 4096 );
  2615. ClientWorldListInfo_t *pResult = gm_Pool.GetObject();
  2616. byte *pMemory = (byte *)pResult->m_pLeafList;
  2617. if ( pMemory )
  2618. {
  2619. // Previously allocated, add a reference. Otherwise comes out of GetObject as a new object with a refcount of 1
  2620. pResult->AddRef();
  2621. }
  2622. if ( !pMemory || _msize( pMemory ) < nBytes )
  2623. {
  2624. pMemory = (byte *)realloc( pMemory, nBytes );
  2625. }
  2626. pResult->m_pLeafList = (LeafIndex_t*)pMemory;
  2627. pResult->m_pLeafFogVolume = (LeafFogVolume_t*)( pMemory + exemplar.m_LeafCount * sizeof(LeafIndex_t) );
  2628. pResult->m_pActualLeafIndex = (LeafIndex_t*)( (byte *)( pResult->m_pLeafFogVolume ) + exemplar.m_LeafCount * sizeof(LeafFogVolume_t) );
  2629. pResult->m_bPooledAlloc = true;
  2630. return pResult;
  2631. }
  2632. bool ClientWorldListInfo_t::OnFinalRelease()
  2633. {
  2634. if ( m_bPooledAlloc )
  2635. {
  2636. Assert( m_pLeafList );
  2637. gm_Pool.PutObject( this );
  2638. return false;
  2639. }
  2640. return true;
  2641. }
  2642. //-----------------------------------------------------------------------------
  2643. // Constructor
  2644. //-----------------------------------------------------------------------------
  2645. CBase3dView::CBase3dView( CViewRender *pMainView ) :
  2646. m_pMainView( pMainView ),
  2647. m_Frustum( pMainView->m_Frustum )
  2648. {
  2649. }
  2650. //-----------------------------------------------------------------------------
  2651. // Purpose:
  2652. // Input : *pEnt -
  2653. // Output : int
  2654. //-----------------------------------------------------------------------------
  2655. VPlane* CBase3dView::GetFrustum()
  2656. {
  2657. // The frustum is only valid while in a RenderView call.
  2658. // @MULTICORE (toml 8/11/2006): reimplement this when ready -- Assert(g_bRenderingView || g_bRenderingCameraView || g_bRenderingScreenshot);
  2659. return m_Frustum;
  2660. }
  2661. CObjectPool<ClientWorldListInfo_t> ClientWorldListInfo_t::gm_Pool;
  2662. //-----------------------------------------------------------------------------
  2663. // Base class for 3d views
  2664. //-----------------------------------------------------------------------------
  2665. CRendering3dView::CRendering3dView(CViewRender *pMainView) :
  2666. CBase3dView( pMainView ),
  2667. m_pWorldRenderList( NULL ),
  2668. m_pRenderablesList( NULL ),
  2669. m_pWorldListInfo( NULL ),
  2670. m_pCustomVisibility( NULL ),
  2671. m_DrawFlags( 0 ),
  2672. m_ClearFlags( 0 )
  2673. {
  2674. }
  2675. //-----------------------------------------------------------------------------
  2676. // Sort entities in a back-to-front ordering
  2677. //-----------------------------------------------------------------------------
  2678. void CRendering3dView::Setup( const CViewSetup &setup )
  2679. {
  2680. // @MULTICORE (toml 8/15/2006): don't reset if parameters don't require it. For now, just reset
  2681. memcpy( static_cast<CViewSetup *>(this), &setup, sizeof( setup ) );
  2682. ReleaseLists();
  2683. m_pRenderablesList = new CClientRenderablesList;
  2684. m_pCustomVisibility = NULL;
  2685. }
  2686. //-----------------------------------------------------------------------------
  2687. // Sort entities in a back-to-front ordering
  2688. //-----------------------------------------------------------------------------
  2689. void CRendering3dView::ReleaseLists()
  2690. {
  2691. SafeRelease( m_pWorldRenderList );
  2692. SafeRelease( m_pRenderablesList );
  2693. SafeRelease( m_pWorldListInfo );
  2694. m_pCustomVisibility = NULL;
  2695. }
  2696. //-----------------------------------------------------------------------------
  2697. //
  2698. //-----------------------------------------------------------------------------
  2699. void CRendering3dView::SetupRenderablesList( int viewID )
  2700. {
  2701. VPROF( "CViewRender::SetupRenderablesList" );
  2702. // Clear the list.
  2703. int i;
  2704. for( i=0; i < RENDER_GROUP_COUNT; i++ )
  2705. {
  2706. m_pRenderablesList->m_RenderGroupCounts[i] = 0;
  2707. }
  2708. // Now collate the entities in the leaves.
  2709. if( m_pMainView->ShouldDrawEntities() )
  2710. {
  2711. // Precache information used commonly in CollateRenderables
  2712. SetupRenderInfo_t setupInfo;
  2713. setupInfo.m_pWorldListInfo = m_pWorldListInfo;
  2714. setupInfo.m_nRenderFrame = m_pMainView->BuildRenderablesListsNumber(); // only one incremented?
  2715. setupInfo.m_nDetailBuildFrame = m_pMainView->BuildWorldListsNumber(); //
  2716. setupInfo.m_pRenderList = m_pRenderablesList;
  2717. setupInfo.m_bDrawDetailObjects = g_pClientMode->ShouldDrawDetailObjects() && r_DrawDetailProps.GetInt();
  2718. setupInfo.m_bDrawTranslucentObjects = (viewID != VIEW_SHADOW_DEPTH_TEXTURE);
  2719. setupInfo.m_vecRenderOrigin = origin;
  2720. setupInfo.m_vecRenderForward = CurrentViewForward();
  2721. float fMaxDist = cl_maxrenderable_dist.GetFloat();
  2722. // Shadowing light typically has a smaller farz than cl_maxrenderable_dist
  2723. setupInfo.m_flRenderDistSq = (viewID == VIEW_SHADOW_DEPTH_TEXTURE) ? MIN(zFar, fMaxDist) : fMaxDist;
  2724. setupInfo.m_flRenderDistSq *= setupInfo.m_flRenderDistSq;
  2725. ClientLeafSystem()->BuildRenderablesList( setupInfo );
  2726. }
  2727. }
  2728. //-----------------------------------------------------------------------------
  2729. // Purpose: Builds lists of things to render in the world, called once per view
  2730. //-----------------------------------------------------------------------------
  2731. void CRendering3dView::UpdateRenderablesOpacity()
  2732. {
  2733. // Compute the prop opacity based on the view position and fov zoom scale
  2734. float flFactor = 1.0f;
  2735. C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer();
  2736. if ( pLocal )
  2737. {
  2738. flFactor = pLocal->GetFOVDistanceAdjustFactor();
  2739. }
  2740. if ( cl_leveloverview.GetFloat() > 0 )
  2741. {
  2742. // disable prop fading
  2743. flFactor = -1;
  2744. }
  2745. // When zoomed in, tweak the opacity to stay visible from further away
  2746. staticpropmgr->ComputePropOpacity( origin, flFactor );
  2747. // Build a list of detail props to render
  2748. DetailObjectSystem()->BuildDetailObjectRenderLists( origin );
  2749. }
  2750. //-----------------------------------------------------------------------------
  2751. //
  2752. //-----------------------------------------------------------------------------
  2753. // Kinda awkward...three optional parameters at the end...
  2754. void CRendering3dView::BuildWorldRenderLists( bool bDrawEntities, int iForceViewLeaf /* = -1 */,
  2755. bool bUseCacheIfEnabled /* = true */, bool bShadowDepth /* = false */, float *pReflectionWaterHeight /*= NULL*/ )
  2756. {
  2757. VPROF_BUDGET( "BuildWorldRenderLists", VPROF_BUDGETGROUP_WORLD_RENDERING );
  2758. // @MULTICORE (toml 8/18/2006): to address....
  2759. extern void UpdateClientRenderableInPVSStatus();
  2760. UpdateClientRenderableInPVSStatus();
  2761. Assert( !m_pWorldRenderList && !m_pWorldListInfo);
  2762. m_pMainView->IncWorldListsNumber();
  2763. // Override vis data if specified this render, otherwise use default behavior with NULL
  2764. VisOverrideData_t* pVisData = ( m_pCustomVisibility && m_pCustomVisibility->m_VisData.m_fDistToAreaPortalTolerance != FLT_MAX ) ? &m_pCustomVisibility->m_VisData : NULL;
  2765. bool bUseCache = ( bUseCacheIfEnabled && r_worldlistcache.GetBool() );
  2766. if ( !bUseCache || pVisData || !g_WorldListCache.Find( *this, &m_pWorldRenderList, &m_pWorldListInfo ) )
  2767. {
  2768. // @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
  2769. m_pWorldRenderList = render->CreateWorldList();
  2770. m_pWorldListInfo = new ClientWorldListInfo_t;
  2771. render->BuildWorldLists( m_pWorldRenderList, m_pWorldListInfo,
  2772. ( m_pCustomVisibility ) ? m_pCustomVisibility->m_iForceViewLeaf : iForceViewLeaf,
  2773. pVisData, bShadowDepth, pReflectionWaterHeight );
  2774. if ( bUseCache && !pVisData )
  2775. {
  2776. g_WorldListCache.Add( *this, m_pWorldRenderList, m_pWorldListInfo );
  2777. }
  2778. }
  2779. if ( bDrawEntities )
  2780. {
  2781. UpdateRenderablesOpacity();
  2782. }
  2783. }
  2784. //-----------------------------------------------------------------------------
  2785. // Purpose: Computes the actual world list info based on the render flags
  2786. //-----------------------------------------------------------------------------
  2787. void CRendering3dView::PruneWorldListInfo()
  2788. {
  2789. // Drawing everything? Just return the world list info as-is
  2790. int nWaterDrawFlags = m_DrawFlags & (DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER);
  2791. if ( nWaterDrawFlags == (DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER) )
  2792. {
  2793. return;
  2794. }
  2795. ClientWorldListInfo_t *pNewInfo;
  2796. // Only allocate memory if actually will draw something
  2797. if ( m_pWorldListInfo->m_LeafCount > 0 && nWaterDrawFlags )
  2798. {
  2799. pNewInfo = ClientWorldListInfo_t::AllocPooled( *m_pWorldListInfo );
  2800. }
  2801. else
  2802. {
  2803. pNewInfo = new ClientWorldListInfo_t;
  2804. }
  2805. pNewInfo->m_ViewFogVolume = m_pWorldListInfo->m_ViewFogVolume;
  2806. pNewInfo->m_LeafCount = 0;
  2807. // Not drawing anything? Then don't bother with renderable lists
  2808. if ( nWaterDrawFlags != 0 )
  2809. {
  2810. // Create a sub-list based on the actual leaves being rendered
  2811. bool bRenderingUnderwater = (nWaterDrawFlags & DF_RENDER_UNDERWATER) != 0;
  2812. for ( int i = 0; i < m_pWorldListInfo->m_LeafCount; ++i )
  2813. {
  2814. bool bLeafIsUnderwater = ( m_pWorldListInfo->m_pLeafFogVolume[i] != -1 );
  2815. if ( bRenderingUnderwater == bLeafIsUnderwater )
  2816. {
  2817. pNewInfo->m_pLeafList[ pNewInfo->m_LeafCount ] = m_pWorldListInfo->m_pLeafList[ i ];
  2818. pNewInfo->m_pLeafFogVolume[ pNewInfo->m_LeafCount ] = m_pWorldListInfo->m_pLeafFogVolume[ i ];
  2819. pNewInfo->m_pActualLeafIndex[ pNewInfo->m_LeafCount ] = i;
  2820. ++pNewInfo->m_LeafCount;
  2821. }
  2822. }
  2823. }
  2824. m_pWorldListInfo->Release();
  2825. m_pWorldListInfo = pNewInfo;
  2826. }
  2827. //-----------------------------------------------------------------------------
  2828. // Purpose:
  2829. //-----------------------------------------------------------------------------
  2830. static inline void UpdateBrushModelLightmap( IClientRenderable *pEnt )
  2831. {
  2832. model_t *pModel = ( model_t * )pEnt->GetModel();
  2833. render->UpdateBrushModelLightmap( pModel, pEnt );
  2834. }
  2835. void CRendering3dView::BuildRenderableRenderLists( int viewID )
  2836. {
  2837. MDLCACHE_CRITICAL_SECTION();
  2838. if ( viewID != VIEW_SHADOW_DEPTH_TEXTURE )
  2839. {
  2840. render->BeginUpdateLightmaps();
  2841. }
  2842. m_pMainView->IncRenderablesListsNumber();
  2843. ClientWorldListInfo_t& info = *m_pWorldListInfo;
  2844. // For better sorting, find out the leaf *nearest* to the camera
  2845. // and render translucent objects as if they are in that leaf.
  2846. if( m_pMainView->ShouldDrawEntities() && ( viewID != VIEW_SHADOW_DEPTH_TEXTURE ) )
  2847. {
  2848. ClientLeafSystem()->ComputeTranslucentRenderLeaf(
  2849. info.m_LeafCount, info.m_pLeafList, info.m_pLeafFogVolume, m_pMainView->BuildRenderablesListsNumber(), viewID );
  2850. }
  2851. SetupRenderablesList( viewID );
  2852. if ( viewID == VIEW_MAIN )
  2853. {
  2854. StudioStats_FindClosestEntity( m_pRenderablesList );
  2855. }
  2856. if ( viewID != VIEW_SHADOW_DEPTH_TEXTURE )
  2857. {
  2858. // update lightmap on brush models if necessary
  2859. CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_OPAQUE_BRUSH];
  2860. int nOpaque = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE_BRUSH];
  2861. int i;
  2862. for( i=0; i < nOpaque; ++i )
  2863. {
  2864. Assert(pEntities[i].m_TwoPass==0);
  2865. UpdateBrushModelLightmap( pEntities[i].m_pRenderable );
  2866. }
  2867. // update lightmap on brush models if necessary
  2868. pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY];
  2869. int nTranslucent = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY];
  2870. for( i=0; i < nTranslucent; ++i )
  2871. {
  2872. const model_t *pModel = pEntities[i].m_pRenderable->GetModel();
  2873. if( pModel )
  2874. {
  2875. int nModelType = modelinfo->GetModelType( pModel );
  2876. if( nModelType == mod_brush )
  2877. {
  2878. UpdateBrushModelLightmap( pEntities[i].m_pRenderable );
  2879. }
  2880. }
  2881. }
  2882. render->EndUpdateLightmaps();
  2883. }
  2884. }
  2885. //-----------------------------------------------------------------------------
  2886. //
  2887. //-----------------------------------------------------------------------------
  2888. void CRendering3dView::DrawWorld( float waterZAdjust )
  2889. {
  2890. VPROF_INCREMENT_COUNTER( "RenderWorld", 1 );
  2891. VPROF_BUDGET( "DrawWorld", VPROF_BUDGETGROUP_WORLD_RENDERING );
  2892. if( !r_drawopaqueworld.GetBool() )
  2893. {
  2894. return;
  2895. }
  2896. unsigned long engineFlags = BuildEngineDrawWorldListFlags( m_DrawFlags );
  2897. render->DrawWorldLists( m_pWorldRenderList, engineFlags, waterZAdjust );
  2898. }
  2899. CMaterialReference g_material_WriteZ; //init'ed on by CViewRender::Init()
  2900. //-----------------------------------------------------------------------------
  2901. // Fakes per-entity clip planes on cards that don't support user clip planes.
  2902. // Achieves the effect by drawing an invisible box that writes to the depth buffer
  2903. // around the clipped area. It's not perfect, but better than nothing.
  2904. //-----------------------------------------------------------------------------
  2905. static void DrawClippedDepthBox( IClientRenderable *pEnt, float *pClipPlane )
  2906. {
  2907. //#define DEBUG_DRAWCLIPPEDDEPTHBOX //uncomment to draw the depth box as a colorful box
  2908. 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
  2909. { 3, 7, 5, 1, 3 },
  2910. { 1, 5, 4, 0, 1 },
  2911. { 2, 6, 7, 3, 2 },
  2912. { 0, 2, 3, 1, 0 },
  2913. { 5, 7, 6, 4, 5 } };
  2914. static const int iLines[12][2] = { { 0, 1 },
  2915. { 0, 2 },
  2916. { 0, 4 },
  2917. { 1, 3 },
  2918. { 1, 5 },
  2919. { 2, 3 },
  2920. { 2, 6 },
  2921. { 3, 7 },
  2922. { 4, 6 },
  2923. { 4, 5 },
  2924. { 5, 7 },
  2925. { 6, 7 } };
  2926. #ifdef DEBUG_DRAWCLIPPEDDEPTHBOX
  2927. static const float fColors[6][3] = { { 1.0f, 0.0f, 0.0f },
  2928. { 0.0f, 1.0f, 1.0f },
  2929. { 0.0f, 1.0f, 0.0f },
  2930. { 1.0f, 0.0f, 1.0f },
  2931. { 0.0f, 0.0f, 1.0f },
  2932. { 1.0f, 1.0f, 0.0f } };
  2933. #endif
  2934. Vector vNormal = *(Vector *)pClipPlane;
  2935. float fPlaneDist = pClipPlane[3];
  2936. Vector vMins, vMaxs;
  2937. pEnt->GetRenderBounds( vMins, vMaxs );
  2938. Vector vOrigin = pEnt->GetRenderOrigin();
  2939. QAngle qAngles = pEnt->GetRenderAngles();
  2940. Vector vForward, vUp, vRight;
  2941. AngleVectors( qAngles, &vForward, &vRight, &vUp );
  2942. Vector vPoints[8];
  2943. vPoints[0] = vOrigin + (vForward * vMins.x) + (vRight * vMins.y) + (vUp * vMins.z);
  2944. vPoints[1] = vOrigin + (vForward * vMaxs.x) + (vRight * vMins.y) + (vUp * vMins.z);
  2945. vPoints[2] = vOrigin + (vForward * vMins.x) + (vRight * vMaxs.y) + (vUp * vMins.z);
  2946. vPoints[3] = vOrigin + (vForward * vMaxs.x) + (vRight * vMaxs.y) + (vUp * vMins.z);
  2947. vPoints[4] = vOrigin + (vForward * vMins.x) + (vRight * vMins.y) + (vUp * vMaxs.z);
  2948. vPoints[5] = vOrigin + (vForward * vMaxs.x) + (vRight * vMins.y) + (vUp * vMaxs.z);
  2949. vPoints[6] = vOrigin + (vForward * vMins.x) + (vRight * vMaxs.y) + (vUp * vMaxs.z);
  2950. vPoints[7] = vOrigin + (vForward * vMaxs.x) + (vRight * vMaxs.y) + (vUp * vMaxs.z);
  2951. int iClipped[8];
  2952. float fDists[8];
  2953. for( int i = 0; i != 8; ++i )
  2954. {
  2955. fDists[i] = vPoints[i].Dot( vNormal ) - fPlaneDist;
  2956. iClipped[i] = (fDists[i] > 0.0f) ? 1 : 0;
  2957. }
  2958. 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
  2959. int iLineStates[8][8]; //0 = unclipped, 2 = wholly clipped, 3 = first point clipped, 4 = second point clipped
  2960. //categorize lines and generate split points where needed
  2961. for( int i = 0; i != 12; ++i )
  2962. {
  2963. const int *pPoints = iLines[i];
  2964. int iLineState = (iClipped[pPoints[0]] + iClipped[pPoints[1]]);
  2965. if( iLineState != 1 ) //either both points are clipped, or neither are clipped
  2966. {
  2967. iLineStates[pPoints[0]][pPoints[1]] =
  2968. iLineStates[pPoints[1]][pPoints[0]] =
  2969. iLineState;
  2970. }
  2971. else
  2972. {
  2973. //one point is clipped, the other is not
  2974. if( iClipped[pPoints[0]] == 1 )
  2975. {
  2976. //first point was clipped, index 1 has the negative distance
  2977. float fInvTotalDist = 1.0f / (fDists[pPoints[0]] - fDists[pPoints[1]]);
  2978. vSplitPoints[pPoints[0]][pPoints[1]] =
  2979. vSplitPoints[pPoints[1]][pPoints[0]] =
  2980. (vPoints[pPoints[1]] * (fDists[pPoints[0]] * fInvTotalDist)) - (vPoints[pPoints[0]] * (fDists[pPoints[1]] * fInvTotalDist));
  2981. Assert( fabs( vNormal.Dot( vSplitPoints[pPoints[0]][pPoints[1]] ) - fPlaneDist ) < 0.01f );
  2982. iLineStates[pPoints[0]][pPoints[1]] = 3;
  2983. iLineStates[pPoints[1]][pPoints[0]] = 4;
  2984. }
  2985. else
  2986. {
  2987. //second point was clipped, index 0 has the negative distance
  2988. float fInvTotalDist = 1.0f / (fDists[pPoints[1]] - fDists[pPoints[0]]);
  2989. vSplitPoints[pPoints[0]][pPoints[1]] =
  2990. vSplitPoints[pPoints[1]][pPoints[0]] =
  2991. (vPoints[pPoints[0]] * (fDists[pPoints[1]] * fInvTotalDist)) - (vPoints[pPoints[1]] * (fDists[pPoints[0]] * fInvTotalDist));
  2992. Assert( fabs( vNormal.Dot( vSplitPoints[pPoints[0]][pPoints[1]] ) - fPlaneDist ) < 0.01f );
  2993. iLineStates[pPoints[0]][pPoints[1]] = 4;
  2994. iLineStates[pPoints[1]][pPoints[0]] = 3;
  2995. }
  2996. }
  2997. }
  2998. CMatRenderContextPtr pRenderContext( materials );
  2999. #ifdef DEBUG_DRAWCLIPPEDDEPTHBOX
  3000. pRenderContext->Bind( materials->FindMaterial( "debug/debugvertexcolor", TEXTURE_GROUP_OTHER ), NULL );
  3001. #else
  3002. pRenderContext->Bind( g_material_WriteZ, NULL );
  3003. #endif
  3004. CMeshBuilder meshBuilder;
  3005. IMesh* pMesh = pRenderContext->GetDynamicMesh( false );
  3006. 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
  3007. //going to draw as a collection of triangles, arranged as a triangle fan on each side
  3008. for( int i = 0; i != 6; ++i )
  3009. {
  3010. const int *pPoints = iQuads[i];
  3011. //can't start the fan on a wholly clipped line, so seek to one that isn't
  3012. int j = 0;
  3013. do
  3014. {
  3015. if( iLineStates[pPoints[j]][pPoints[j+1]] != 2 ) //at least part of this line will be drawn
  3016. break;
  3017. ++j;
  3018. } while( j != 3 );
  3019. if( j == 3 ) //not enough lines to even form a triangle
  3020. continue;
  3021. float *pStartPoint = 0;
  3022. float *pTriangleFanPoints[4]; //at most, one of our fans will have 5 points total, with the first point being stored separately as pStartPoint
  3023. int iTriangleFanPointCount = 1; //the switch below creates the first for sure
  3024. //figure out how to start the fan
  3025. switch( iLineStates[pPoints[j]][pPoints[j+1]] )
  3026. {
  3027. case 0: //uncut
  3028. pStartPoint = &vPoints[pPoints[j]].x;
  3029. pTriangleFanPoints[0] = &vPoints[pPoints[j+1]].x;
  3030. break;
  3031. case 4: //second index was clipped
  3032. pStartPoint = &vPoints[pPoints[j]].x;
  3033. pTriangleFanPoints[0] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x;
  3034. break;
  3035. case 3: //first index was clipped
  3036. pStartPoint = &vSplitPoints[pPoints[j]][pPoints[j+1]].x;
  3037. pTriangleFanPoints[0] = &vPoints[pPoints[j + 1]].x;
  3038. break;
  3039. default:
  3040. Assert( false );
  3041. break;
  3042. };
  3043. for( ++j; j != 3; ++j ) //add end points for the rest of the indices, we're assembling a triangle fan
  3044. {
  3045. switch( iLineStates[pPoints[j]][pPoints[j+1]] )
  3046. {
  3047. case 0: //uncut line, normal endpoint
  3048. pTriangleFanPoints[iTriangleFanPointCount] = &vPoints[pPoints[j+1]].x;
  3049. ++iTriangleFanPointCount;
  3050. break;
  3051. case 2: //wholly cut line, no endpoint
  3052. break;
  3053. case 3: //first point is clipped, normal endpoint
  3054. //special case, adds start and end point
  3055. pTriangleFanPoints[iTriangleFanPointCount] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x;
  3056. ++iTriangleFanPointCount;
  3057. pTriangleFanPoints[iTriangleFanPointCount] = &vPoints[pPoints[j+1]].x;
  3058. ++iTriangleFanPointCount;
  3059. break;
  3060. case 4: //second point is clipped
  3061. pTriangleFanPoints[iTriangleFanPointCount] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x;
  3062. ++iTriangleFanPointCount;
  3063. break;
  3064. default:
  3065. Assert( false );
  3066. break;
  3067. };
  3068. }
  3069. //special case endpoints, half-clipped lines have a connecting line between them and the next line (first line in this case)
  3070. switch( iLineStates[pPoints[j]][pPoints[j+1]] )
  3071. {
  3072. case 3:
  3073. case 4:
  3074. pTriangleFanPoints[iTriangleFanPointCount] = &vSplitPoints[pPoints[j]][pPoints[j+1]].x;
  3075. ++iTriangleFanPointCount;
  3076. break;
  3077. };
  3078. Assert( iTriangleFanPointCount <= 4 );
  3079. //add the fan to the mesh
  3080. int iLoopStop = iTriangleFanPointCount - 1;
  3081. for( int k = 0; k != iLoopStop; ++k )
  3082. {
  3083. meshBuilder.Position3fv( pStartPoint );
  3084. #ifdef DEBUG_DRAWCLIPPEDDEPTHBOX
  3085. float fHalfColors[3] = { fColors[i][0] * 0.5f, fColors[i][1] * 0.5f, fColors[i][2] * 0.5f };
  3086. meshBuilder.Color3fv( fHalfColors );
  3087. #endif
  3088. meshBuilder.AdvanceVertex();
  3089. meshBuilder.Position3fv( pTriangleFanPoints[k] );
  3090. #ifdef DEBUG_DRAWCLIPPEDDEPTHBOX
  3091. meshBuilder.Color3fv( fColors[i] );
  3092. #endif
  3093. meshBuilder.AdvanceVertex();
  3094. meshBuilder.Position3fv( pTriangleFanPoints[k+1] );
  3095. #ifdef DEBUG_DRAWCLIPPEDDEPTHBOX
  3096. meshBuilder.Color3fv( fColors[i] );
  3097. #endif
  3098. meshBuilder.AdvanceVertex();
  3099. }
  3100. }
  3101. meshBuilder.End();
  3102. pMesh->Draw();
  3103. pRenderContext->Flush( false );
  3104. }
  3105. //-----------------------------------------------------------------------------
  3106. // Draws all opaque renderables in leaves that were rendered
  3107. //-----------------------------------------------------------------------------
  3108. static inline void DrawOpaqueRenderable( IClientRenderable *pEnt, bool bTwoPass, ERenderDepthMode DepthMode, int nDefaultFlags = 0 )
  3109. {
  3110. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  3111. float color[3];
  3112. pEnt->GetColorModulation( color );
  3113. render->SetColorModulation( color );
  3114. int flags = nDefaultFlags | STUDIO_RENDER;
  3115. if ( bTwoPass )
  3116. {
  3117. flags |= STUDIO_TWOPASS;
  3118. }
  3119. if ( DepthMode == DEPTH_MODE_SHADOW )
  3120. {
  3121. flags |= STUDIO_SHADOWDEPTHTEXTURE;
  3122. }
  3123. else if ( DepthMode == DEPTH_MODE_SSA0 )
  3124. {
  3125. flags |= STUDIO_SSAODEPTHTEXTURE;
  3126. }
  3127. float *pRenderClipPlane = NULL;
  3128. if( r_entityclips.GetBool() )
  3129. pRenderClipPlane = pEnt->GetRenderClipPlane();
  3130. if( pRenderClipPlane )
  3131. {
  3132. CMatRenderContextPtr pRenderContext( materials );
  3133. if( !materials->UsingFastClipping() ) //do NOT change the fast clip plane mid-scene, depth problems result. Regular user clip planes are fine though
  3134. pRenderContext->PushCustomClipPlane( pRenderClipPlane );
  3135. else
  3136. DrawClippedDepthBox( pEnt, pRenderClipPlane );
  3137. Assert( view->GetCurrentlyDrawingEntity() == NULL );
  3138. view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() );
  3139. pEnt->DrawModel( flags );
  3140. view->SetCurrentlyDrawingEntity( NULL );
  3141. if( pRenderClipPlane && !materials->UsingFastClipping() )
  3142. pRenderContext->PopCustomClipPlane();
  3143. }
  3144. else
  3145. {
  3146. Assert( view->GetCurrentlyDrawingEntity() == NULL );
  3147. view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() );
  3148. pEnt->DrawModel( flags );
  3149. view->SetCurrentlyDrawingEntity( NULL );
  3150. }
  3151. }
  3152. //-------------------------------------
  3153. ConVar r_drawopaquestaticpropslast( "r_drawopaquestaticpropslast", "0", 0, "Whether opaque static props are rendered after non-npcs" );
  3154. #define DEBUG_BUCKETS 0
  3155. #if DEBUG_BUCKETS
  3156. ConVar r_drawopaque_old( "r_drawopaque_old", "0", 0, "Whether old unbucketed technique is used" );
  3157. ConVar r_drawopaquesbucket( "r_drawopaquesbucket", "0", FCVAR_CHEAT, "Draw only specific bucket: positive - props, negative - ents" );
  3158. ConVar r_drawopaquesbucket_stats( "r_drawopaquesbucket_stats", "0", FCVAR_CHEAT, "Draw distribution of props/ents in the buckets" );
  3159. #endif
  3160. static void SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating )
  3161. {
  3162. pBaseAnimating->SetupBones( NULL, -1, -1, gpGlobals->curtime );
  3163. }
  3164. static void DrawOpaqueRenderables_DrawBrushModels( CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, ERenderDepthMode DepthMode )
  3165. {
  3166. for( CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity )
  3167. {
  3168. Assert( !itEntity->m_TwoPass );
  3169. DrawOpaqueRenderable( itEntity->m_pRenderable, false, DepthMode );
  3170. }
  3171. }
  3172. static void DrawOpaqueRenderables_DrawStaticProps( CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, ERenderDepthMode DepthMode )
  3173. {
  3174. if ( pEntitiesEnd == pEntitiesBegin )
  3175. return;
  3176. float one[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
  3177. render->SetColorModulation( one );
  3178. render->SetBlend( 1.0f );
  3179. const int MAX_STATICS_PER_BATCH = 512;
  3180. IClientRenderable *pStatics[ MAX_STATICS_PER_BATCH ];
  3181. int numScheduled = 0, numAvailable = MAX_STATICS_PER_BATCH;
  3182. for( CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity )
  3183. {
  3184. if ( itEntity->m_pRenderable )
  3185. /**/;
  3186. else
  3187. continue;
  3188. if ( g_pStudioStatsEntity != NULL && g_CurrentViewID == VIEW_MAIN && itEntity->m_pRenderable == g_pStudioStatsEntity )
  3189. {
  3190. DrawOpaqueRenderable( itEntity->m_pRenderable, false, DepthMode, STUDIO_GENERATE_STATS );
  3191. continue;
  3192. }
  3193. pStatics[ numScheduled ++ ] = itEntity->m_pRenderable;
  3194. if ( -- numAvailable > 0 )
  3195. continue; // place a hint for compiler to predict more common case in the loop
  3196. staticpropmgr->DrawStaticProps( pStatics, numScheduled, DepthMode, vcollide_wireframe.GetBool() );
  3197. numScheduled = 0;
  3198. numAvailable = MAX_STATICS_PER_BATCH;
  3199. }
  3200. if ( numScheduled )
  3201. staticpropmgr->DrawStaticProps( pStatics, numScheduled, DepthMode, vcollide_wireframe.GetBool() );
  3202. }
  3203. static void DrawOpaqueRenderables_Range( CClientRenderablesList::CEntry *pEntitiesBegin, CClientRenderablesList::CEntry *pEntitiesEnd, ERenderDepthMode DepthMode )
  3204. {
  3205. for( CClientRenderablesList::CEntry *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity )
  3206. {
  3207. if ( itEntity->m_pRenderable )
  3208. DrawOpaqueRenderable( itEntity->m_pRenderable, ( itEntity->m_TwoPass != 0 ), DepthMode );
  3209. }
  3210. }
  3211. void CRendering3dView::DrawOpaqueRenderables( ERenderDepthMode DepthMode )
  3212. {
  3213. VPROF_BUDGET("CViewRender::DrawOpaqueRenderables", "DrawOpaqueRenderables" );
  3214. if( !r_drawopaquerenderables.GetBool() )
  3215. return;
  3216. if( !m_pMainView->ShouldDrawEntities() )
  3217. return;
  3218. render->SetBlend( 1 );
  3219. //
  3220. // Prepare to iterate over all leaves that were visible, and draw opaque things in them.
  3221. //
  3222. RopeManager()->ResetRenderCache();
  3223. g_pParticleSystemMgr->ResetRenderCache();
  3224. //bool const bDrawopaquestaticpropslast = r_drawopaquestaticpropslast.GetBool();
  3225. //
  3226. // First do the brush models
  3227. //
  3228. {
  3229. CClientRenderablesList::CEntry *pEntitiesBegin, *pEntitiesEnd;
  3230. pEntitiesBegin = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_OPAQUE_BRUSH];
  3231. pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_OPAQUE_BRUSH];
  3232. DrawOpaqueRenderables_DrawBrushModels( pEntitiesBegin, pEntitiesEnd, DepthMode );
  3233. }
  3234. #if DEBUG_BUCKETS
  3235. {
  3236. con_nprint_s nxPrn = { 0 };
  3237. nxPrn.index = 16;
  3238. nxPrn.time_to_live = -1;
  3239. nxPrn.color[0] = 0.9f, nxPrn.color[1] = 1.0f, nxPrn.color[2] = 0.9f;
  3240. nxPrn.fixed_width_font = true;
  3241. engine->Con_NXPrintf( &nxPrn, "Draw Opaque Technique : NEW" );
  3242. if ( r_drawopaque_old.GetBool() )
  3243. {
  3244. engine->Con_NXPrintf( &nxPrn, "Draw Opaque Technique : OLD" );
  3245. // now the static props
  3246. {
  3247. for ( int bucket = RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS - 1; bucket -- > 0; )
  3248. {
  3249. CClientRenderablesList::CEntry
  3250. * const pEntitiesBegin = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ],
  3251. * const pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ];
  3252. DrawOpaqueRenderables_DrawStaticProps( pEntitiesBegin, pEntitiesEnd, bShadowDepth );
  3253. }
  3254. }
  3255. // now the other opaque entities
  3256. for ( int bucket = RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS - 1; bucket -- > 0; )
  3257. {
  3258. CClientRenderablesList::CEntry
  3259. * const pEntitiesBegin = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ],
  3260. * const pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ];
  3261. DrawOpaqueRenderables_Range( pEntitiesBegin, pEntitiesEnd, bShadowDepth );
  3262. }
  3263. //
  3264. // Ropes and particles
  3265. //
  3266. RopeManager()->DrawRenderCache( bShadowDepth );
  3267. g_pParticleSystemMgr->DrawRenderCache( bShadowDepth );
  3268. return;
  3269. }
  3270. }
  3271. #endif
  3272. //
  3273. // Sort everything that's not a static prop
  3274. //
  3275. int numOpaqueEnts = 0;
  3276. for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket )
  3277. numOpaqueEnts += m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ];
  3278. CUtlVector< C_BaseAnimating * > arrBoneSetupNpcsLast( (C_BaseAnimating **)_alloca( numOpaqueEnts * sizeof( C_BaseAnimating * ) ), numOpaqueEnts, numOpaqueEnts );
  3279. CUtlVector< CClientRenderablesList::CEntry > arrRenderEntsNpcsFirst( (CClientRenderablesList::CEntry *)_alloca( numOpaqueEnts * sizeof( CClientRenderablesList::CEntry ) ), numOpaqueEnts, numOpaqueEnts );
  3280. int numNpcs = 0, numNonNpcsAnimating = 0;
  3281. for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket )
  3282. {
  3283. for( CClientRenderablesList::CEntry
  3284. * const pEntitiesBegin = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ],
  3285. * const pEntitiesEnd = pEntitiesBegin + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ],
  3286. *itEntity = pEntitiesBegin; itEntity < pEntitiesEnd; ++ itEntity )
  3287. {
  3288. C_BaseEntity *pEntity = itEntity->m_pRenderable ? itEntity->m_pRenderable->GetIClientUnknown()->GetBaseEntity() : NULL;
  3289. if ( pEntity )
  3290. {
  3291. if ( pEntity->IsNPC() )
  3292. {
  3293. C_BaseAnimating *pba = assert_cast<C_BaseAnimating *>( pEntity );
  3294. arrRenderEntsNpcsFirst[ numNpcs ++ ] = *itEntity;
  3295. arrBoneSetupNpcsLast[ numOpaqueEnts - numNpcs ] = pba;
  3296. itEntity->m_pRenderable = NULL; // We will render NPCs separately
  3297. itEntity->m_RenderHandle = NULL;
  3298. continue;
  3299. }
  3300. else if ( pEntity->GetBaseAnimating() )
  3301. {
  3302. C_BaseAnimating *pba = assert_cast<C_BaseAnimating *>( pEntity );
  3303. arrBoneSetupNpcsLast[ numNonNpcsAnimating ++ ] = pba;
  3304. // fall through
  3305. }
  3306. }
  3307. }
  3308. }
  3309. if ( 0 && r_threaded_renderables.GetBool() )
  3310. {
  3311. ParallelProcess( "BoneSetupNpcsLast", arrBoneSetupNpcsLast.Base() + numOpaqueEnts - numNpcs, numNpcs, &SetupBonesOnBaseAnimating );
  3312. ParallelProcess( "BoneSetupNpcsLast NonNPCs", arrBoneSetupNpcsLast.Base(), numNonNpcsAnimating, &SetupBonesOnBaseAnimating );
  3313. }
  3314. //
  3315. // Draw static props + opaque entities from the biggest bucket to the smallest
  3316. //
  3317. {
  3318. CClientRenderablesList::CEntry * pEnts[ RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ][2];
  3319. CClientRenderablesList::CEntry * pProps[ RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS ][2];
  3320. for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket )
  3321. {
  3322. pEnts[bucket][0] = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ];
  3323. pEnts[bucket][1] = pEnts[bucket][0] + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_ENTITY_HUGE + 2 * bucket ];
  3324. pProps[bucket][0] = m_pRenderablesList->m_RenderGroups[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ];
  3325. pProps[bucket][1] = pProps[bucket][0] + m_pRenderablesList->m_RenderGroupCounts[ RENDER_GROUP_OPAQUE_STATIC_HUGE + 2 * bucket ];
  3326. // Render sequence debugging
  3327. #if DEBUG_BUCKETS
  3328. if ( r_drawopaquesbucket_stats.GetBool() )
  3329. {
  3330. con_nprint_s nxPrn = { 0 };
  3331. nxPrn.index = 20 + bucket * 3;
  3332. nxPrn.time_to_live = -1;
  3333. nxPrn.color[0] = 0.9f, nxPrn.color[1] = 1.0f, nxPrn.color[2] = 0.9f;
  3334. nxPrn.fixed_width_font = true;
  3335. if ( bDrawopaquestaticpropslast )
  3336. engine->Con_NXPrintf( &nxPrn, "[ %2d ] Ents : %3d", bucket + 1, pEnts[bucket][1] - pEnts[bucket][0] ),
  3337. ++ nxPrn.index,
  3338. engine->Con_NXPrintf( &nxPrn, "[ %2d ] Props: %3d", bucket + 1, pProps[bucket][1] - pProps[bucket][0] );
  3339. else
  3340. engine->Con_NXPrintf( &nxPrn, "[ %2d ] Props: %3d", bucket + 1, pProps[bucket][1] - pProps[bucket][0] ),
  3341. ++ nxPrn.index,
  3342. engine->Con_NXPrintf( &nxPrn, "[ %2d ] Ents : %3d", bucket + 1, pEnts[bucket][1] - pEnts[bucket][0] );
  3343. }
  3344. #endif
  3345. }
  3346. #if DEBUG_BUCKETS
  3347. if ( int iBucket = r_drawopaquesbucket.GetInt() )
  3348. {
  3349. if ( iBucket > 0 && iBucket <= RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS )
  3350. {
  3351. DrawOpaqueRenderables_Range( pEnts[iBucket - 1][0], pEnts[iBucket - 1][1], bShadowDepth );
  3352. }
  3353. if ( iBucket < 0 && iBucket >= -RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS )
  3354. {
  3355. DrawOpaqueRenderables_DrawStaticProps( pProps[- 1 - iBucket][0], pProps[- 1 - iBucket][1], bShadowDepth );
  3356. }
  3357. }
  3358. else
  3359. #endif
  3360. for ( int bucket = 0; bucket < RENDER_GROUP_CFG_NUM_OPAQUE_ENT_BUCKETS; ++ bucket )
  3361. {
  3362. // PVS-Studio pointed out that the two sides of the if/else were identical. Fixing
  3363. // this long-broken behavior would change rendering, so I fixed the code but
  3364. // commented out the new behavior. Uncomment the if statement and else block
  3365. // when needed.
  3366. //if ( bDrawopaquestaticpropslast )
  3367. {
  3368. DrawOpaqueRenderables_Range( pEnts[bucket][0], pEnts[bucket][1], DepthMode );
  3369. DrawOpaqueRenderables_DrawStaticProps( pProps[bucket][0], pProps[bucket][1], DepthMode );
  3370. }
  3371. /*else
  3372. {
  3373. DrawOpaqueRenderables_DrawStaticProps( pProps[bucket][0], pProps[bucket][1], DepthMode );
  3374. DrawOpaqueRenderables_Range( pEnts[bucket][0], pEnts[bucket][1], DepthMode );
  3375. }*/
  3376. }
  3377. }
  3378. //
  3379. // Draw NPCs now
  3380. //
  3381. DrawOpaqueRenderables_Range( arrRenderEntsNpcsFirst.Base(), arrRenderEntsNpcsFirst.Base() + numNpcs, DepthMode );
  3382. //
  3383. // Ropes and particles
  3384. //
  3385. RopeManager()->DrawRenderCache( DepthMode );
  3386. g_pParticleSystemMgr->DrawRenderCache( DepthMode );
  3387. }
  3388. //-----------------------------------------------------------------------------
  3389. // Renders all translucent world + detail objects in a particular set of leaves
  3390. //-----------------------------------------------------------------------------
  3391. void CRendering3dView::DrawTranslucentWorldInLeaves( bool bShadowDepth )
  3392. {
  3393. VPROF_BUDGET( "CViewRender::DrawTranslucentWorldInLeaves", VPROF_BUDGETGROUP_WORLD_RENDERING );
  3394. const ClientWorldListInfo_t& info = *m_pWorldListInfo;
  3395. for( int iCurLeafIndex = info.m_LeafCount - 1; iCurLeafIndex >= 0; iCurLeafIndex-- )
  3396. {
  3397. int nActualLeafIndex = info.m_pActualLeafIndex ? info.m_pActualLeafIndex[ iCurLeafIndex ] : iCurLeafIndex;
  3398. Assert( nActualLeafIndex != INVALID_LEAF_INDEX );
  3399. if ( render->LeafContainsTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, m_DrawFlags ) )
  3400. {
  3401. // Now draw the surfaces in this leaf
  3402. render->DrawTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, m_DrawFlags, bShadowDepth );
  3403. }
  3404. }
  3405. }
  3406. //-----------------------------------------------------------------------------
  3407. // Renders all translucent world + detail objects in a particular set of leaves
  3408. //-----------------------------------------------------------------------------
  3409. void CRendering3dView::DrawTranslucentWorldAndDetailPropsInLeaves( int iCurLeafIndex, int iFinalLeafIndex, int nEngineDrawFlags, int &nDetailLeafCount, LeafIndex_t* pDetailLeafList, bool bShadowDepth )
  3410. {
  3411. VPROF_BUDGET( "CViewRender::DrawTranslucentWorldAndDetailPropsInLeaves", VPROF_BUDGETGROUP_WORLD_RENDERING );
  3412. const ClientWorldListInfo_t& info = *m_pWorldListInfo;
  3413. for( ; iCurLeafIndex >= iFinalLeafIndex; iCurLeafIndex-- )
  3414. {
  3415. int nActualLeafIndex = info.m_pActualLeafIndex ? info.m_pActualLeafIndex[ iCurLeafIndex ] : iCurLeafIndex;
  3416. Assert( nActualLeafIndex != INVALID_LEAF_INDEX );
  3417. if ( render->LeafContainsTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, nEngineDrawFlags ) )
  3418. {
  3419. // First draw any queued-up detail props from previously visited leaves
  3420. DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList );
  3421. nDetailLeafCount = 0;
  3422. // Now draw the surfaces in this leaf
  3423. render->DrawTranslucentSurfaces( m_pWorldRenderList, nActualLeafIndex, nEngineDrawFlags, bShadowDepth );
  3424. }
  3425. // Queue up detail props that existed in this leaf
  3426. if ( ClientLeafSystem()->ShouldDrawDetailObjectsInLeaf( info.m_pLeafList[iCurLeafIndex], m_pMainView->BuildWorldListsNumber() ) )
  3427. {
  3428. pDetailLeafList[nDetailLeafCount] = info.m_pLeafList[iCurLeafIndex];
  3429. ++nDetailLeafCount;
  3430. }
  3431. }
  3432. }
  3433. //-----------------------------------------------------------------------------
  3434. // Renders all translucent entities in the render list
  3435. //-----------------------------------------------------------------------------
  3436. static inline void DrawTranslucentRenderable( IClientRenderable *pEnt, bool twoPass, bool bShadowDepth, bool bIgnoreDepth )
  3437. {
  3438. // Determine blending amount and tell engine
  3439. float blend = (float)( pEnt->GetFxBlend() / 255.0f );
  3440. // Totally gone
  3441. if ( blend <= 0.0f )
  3442. return;
  3443. if ( pEnt->IgnoresZBuffer() != bIgnoreDepth )
  3444. return;
  3445. // Tell engine
  3446. render->SetBlend( blend );
  3447. float color[3];
  3448. pEnt->GetColorModulation( color );
  3449. render->SetColorModulation( color );
  3450. int flags = STUDIO_RENDER | STUDIO_TRANSPARENCY;
  3451. if ( twoPass )
  3452. flags |= STUDIO_TWOPASS;
  3453. if ( bShadowDepth )
  3454. flags |= STUDIO_SHADOWDEPTHTEXTURE;
  3455. float *pRenderClipPlane = NULL;
  3456. if( r_entityclips.GetBool() )
  3457. pRenderClipPlane = pEnt->GetRenderClipPlane();
  3458. if( pRenderClipPlane )
  3459. {
  3460. CMatRenderContextPtr pRenderContext( materials );
  3461. if( !materials->UsingFastClipping() ) //do NOT change the fast clip plane mid-scene, depth problems result. Regular user clip planes are fine though
  3462. pRenderContext->PushCustomClipPlane( pRenderClipPlane );
  3463. else
  3464. DrawClippedDepthBox( pEnt, pRenderClipPlane );
  3465. Assert( view->GetCurrentlyDrawingEntity() == NULL );
  3466. view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() );
  3467. pEnt->DrawModel( flags );
  3468. view->SetCurrentlyDrawingEntity( NULL );
  3469. if( pRenderClipPlane && !materials->UsingFastClipping() )
  3470. pRenderContext->PopCustomClipPlane();
  3471. }
  3472. else
  3473. {
  3474. Assert( view->GetCurrentlyDrawingEntity() == NULL );
  3475. view->SetCurrentlyDrawingEntity( pEnt->GetIClientUnknown()->GetBaseEntity() );
  3476. pEnt->DrawModel( flags );
  3477. view->SetCurrentlyDrawingEntity( NULL );
  3478. }
  3479. }
  3480. //-----------------------------------------------------------------------------
  3481. // Renders all translucent entities in the render list
  3482. //-----------------------------------------------------------------------------
  3483. void CRendering3dView::DrawTranslucentRenderablesNoWorld( bool bInSkybox )
  3484. {
  3485. VPROF( "CViewRender::DrawTranslucentRenderablesNoWorld" );
  3486. if ( !m_pMainView->ShouldDrawEntities() || !r_drawtranslucentrenderables.GetBool() )
  3487. return;
  3488. // Draw the particle singletons.
  3489. DrawParticleSingletons( bInSkybox );
  3490. bool bShadowDepth = (m_DrawFlags & ( DF_SHADOW_DEPTH_MAP | DF_SSAO_DEPTH_PASS ) ) != 0;
  3491. CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY];
  3492. int iCurTranslucentEntity = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - 1;
  3493. while( iCurTranslucentEntity >= 0 )
  3494. {
  3495. IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable;
  3496. if ( pRenderable->UsesPowerOfTwoFrameBufferTexture() )
  3497. {
  3498. UpdateRefractTexture();
  3499. }
  3500. if ( pRenderable->UsesFullFrameBufferTexture() )
  3501. {
  3502. UpdateScreenEffectTexture();
  3503. }
  3504. DrawTranslucentRenderable( pRenderable, pEntities[iCurTranslucentEntity].m_TwoPass != 0, bShadowDepth, false );
  3505. --iCurTranslucentEntity;
  3506. }
  3507. // Reset the blend state.
  3508. render->SetBlend( 1 );
  3509. }
  3510. //-----------------------------------------------------------------------------
  3511. // Renders all translucent entities in the render list that ignore the Z buffer
  3512. //-----------------------------------------------------------------------------
  3513. void CRendering3dView::DrawNoZBufferTranslucentRenderables( void )
  3514. {
  3515. VPROF( "CViewRender::DrawNoZBufferTranslucentRenderables" );
  3516. if ( !m_pMainView->ShouldDrawEntities() || !r_drawtranslucentrenderables.GetBool() )
  3517. return;
  3518. bool bShadowDepth = (m_DrawFlags & ( DF_SHADOW_DEPTH_MAP | DF_SSAO_DEPTH_PASS ) ) != 0;
  3519. CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY];
  3520. int iCurTranslucentEntity = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - 1;
  3521. while( iCurTranslucentEntity >= 0 )
  3522. {
  3523. IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable;
  3524. if ( pRenderable->UsesPowerOfTwoFrameBufferTexture() )
  3525. {
  3526. UpdateRefractTexture();
  3527. }
  3528. if ( pRenderable->UsesFullFrameBufferTexture() )
  3529. {
  3530. UpdateScreenEffectTexture();
  3531. }
  3532. DrawTranslucentRenderable( pRenderable, pEntities[iCurTranslucentEntity].m_TwoPass != 0, bShadowDepth, true );
  3533. --iCurTranslucentEntity;
  3534. }
  3535. // Reset the blend state.
  3536. render->SetBlend( 1 );
  3537. }
  3538. //-----------------------------------------------------------------------------
  3539. // Renders all translucent world, entities, and detail objects in a particular set of leaves
  3540. //-----------------------------------------------------------------------------
  3541. void CRendering3dView::DrawTranslucentRenderables( bool bInSkybox, bool bShadowDepth )
  3542. {
  3543. const ClientWorldListInfo_t& info = *m_pWorldListInfo;
  3544. #ifdef PORTAL //if we're in the portal mod, we need to make a detour so we can render portal views using stencil areas
  3545. if( ShouldDrawPortals() ) //no recursive stencil views during skybox rendering (although we might be drawing a skybox while already in a recursive stencil view)
  3546. {
  3547. int iDrawFlagsBackup = m_DrawFlags;
  3548. if( g_pPortalRender->DrawPortalsUsingStencils( (CViewRender *)m_pMainView ) )// @MULTICORE (toml 8/10/2006): remove this hack cast
  3549. {
  3550. m_DrawFlags = iDrawFlagsBackup;
  3551. //reset visibility
  3552. unsigned int iVisFlags = 0;
  3553. m_pMainView->SetupVis( *this, iVisFlags, m_pCustomVisibility );
  3554. //recreate drawlists (since I can't find an easy way to backup the originals)
  3555. {
  3556. SafeRelease( m_pWorldRenderList );
  3557. SafeRelease( m_pWorldListInfo );
  3558. BuildWorldRenderLists( ((m_DrawFlags & DF_DRAW_ENTITITES) != 0), m_pCustomVisibility ? m_pCustomVisibility->m_iForceViewLeaf : -1, false );
  3559. AssertMsg( m_DrawFlags & DF_DRAW_ENTITITES, "It shouldn't be possible to get here if this wasn't set, needs special case investigation" );
  3560. for( int i = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY]; --i >= 0; )
  3561. {
  3562. m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY][i].m_pRenderable->ComputeFxBlend();
  3563. }
  3564. }
  3565. if( r_depthoverlay.GetBool() )
  3566. {
  3567. CMatRenderContextPtr pRenderContext( materials );
  3568. ITexture *pDepthTex = GetFullFrameDepthTexture();
  3569. IMaterial *pMaterial = materials->FindMaterial( "debug/showz", TEXTURE_GROUP_OTHER, true );
  3570. pMaterial->IncrementReferenceCount();
  3571. IMaterialVar *BaseTextureVar = pMaterial->FindVar( "$basetexture", NULL, false );
  3572. IMaterialVar *pDepthInAlpha = NULL;
  3573. if( IsPC() )
  3574. {
  3575. pDepthInAlpha = pMaterial->FindVar( "$ALPHADEPTH", NULL, false );
  3576. pDepthInAlpha->SetIntValue( 1 );
  3577. }
  3578. BaseTextureVar->SetTextureValue( pDepthTex );
  3579. pRenderContext->OverrideDepthEnable( true, false ); //don't write to depth, or else we'll never see translucents
  3580. pRenderContext->DrawScreenSpaceQuad( pMaterial );
  3581. pRenderContext->OverrideDepthEnable( false, true );
  3582. pMaterial->DecrementReferenceCount();
  3583. }
  3584. }
  3585. else
  3586. {
  3587. //done recursing in, time to go back out and do translucents
  3588. CMatRenderContextPtr pRenderContext( materials );
  3589. UpdateFullScreenDepthTexture();
  3590. }
  3591. }
  3592. #else
  3593. {
  3594. //opaques generally write depth, and translucents generally don't.
  3595. //So immediately after opaques are done is the best time to snap off the depth buffer to a texture.
  3596. switch ( g_CurrentViewID )
  3597. {
  3598. case VIEW_MAIN:
  3599. #ifdef _X360
  3600. case VIEW_INTRO_CAMERA:
  3601. case VIEW_INTRO_PLAYER:
  3602. #endif
  3603. UpdateFullScreenDepthTexture();
  3604. break;
  3605. default:
  3606. materials->GetRenderContext()->SetFullScreenDepthTextureValidityFlag( false );
  3607. break;
  3608. }
  3609. }
  3610. #endif
  3611. if ( !r_drawtranslucentworld.GetBool() )
  3612. {
  3613. DrawTranslucentRenderablesNoWorld( bInSkybox );
  3614. return;
  3615. }
  3616. VPROF_BUDGET( "CViewRender::DrawTranslucentRenderables", "DrawTranslucentRenderables" );
  3617. int iPrevLeaf = info.m_LeafCount - 1;
  3618. int nDetailLeafCount = 0;
  3619. LeafIndex_t *pDetailLeafList = (LeafIndex_t*)stackalloc( info.m_LeafCount * sizeof(LeafIndex_t) );
  3620. // bool bDrawUnderWater = (nFlags & DF_RENDER_UNDERWATER) != 0;
  3621. // bool bDrawAboveWater = (nFlags & DF_RENDER_ABOVEWATER) != 0;
  3622. // bool bDrawWater = (nFlags & DF_RENDER_WATER) != 0;
  3623. // bool bClipSkybox = (nFlags & DF_CLIP_SKYBOX ) != 0;
  3624. unsigned long nEngineDrawFlags = BuildEngineDrawWorldListFlags( m_DrawFlags & ~DF_DRAWSKYBOX );
  3625. DetailObjectSystem()->BeginTranslucentDetailRendering();
  3626. if ( m_pMainView->ShouldDrawEntities() && r_drawtranslucentrenderables.GetBool() )
  3627. {
  3628. MDLCACHE_CRITICAL_SECTION();
  3629. // Draw the particle singletons.
  3630. DrawParticleSingletons( bInSkybox );
  3631. CClientRenderablesList::CEntry *pEntities = m_pRenderablesList->m_RenderGroups[RENDER_GROUP_TRANSLUCENT_ENTITY];
  3632. int iCurTranslucentEntity = m_pRenderablesList->m_RenderGroupCounts[RENDER_GROUP_TRANSLUCENT_ENTITY] - 1;
  3633. bool bRenderingWaterRenderTargets = m_DrawFlags & ( DF_RENDER_REFRACTION | DF_RENDER_REFLECTION );
  3634. while( iCurTranslucentEntity >= 0 )
  3635. {
  3636. // Seek the current leaf up to our current translucent-entity leaf.
  3637. int iThisLeaf = pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf;
  3638. // First draw the translucent parts of the world up to and including those in this leaf
  3639. DrawTranslucentWorldAndDetailPropsInLeaves( iPrevLeaf, iThisLeaf, nEngineDrawFlags, nDetailLeafCount, pDetailLeafList, bShadowDepth );
  3640. // We're traversing the leaf list backwards to get the appropriate sort ordering (back to front)
  3641. iPrevLeaf = iThisLeaf - 1;
  3642. // Draw all the translucent entities with this leaf.
  3643. int nLeaf = info.m_pLeafList[iThisLeaf];
  3644. bool bDrawDetailProps = ClientLeafSystem()->ShouldDrawDetailObjectsInLeaf( nLeaf, m_pMainView->BuildWorldListsNumber() );
  3645. if ( bDrawDetailProps )
  3646. {
  3647. // Draw detail props up to but not including this leaf
  3648. Assert( nDetailLeafCount > 0 );
  3649. --nDetailLeafCount;
  3650. Assert( pDetailLeafList[nDetailLeafCount] == nLeaf );
  3651. DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList );
  3652. // Draw translucent renderables in the leaf interspersed with detail props
  3653. for( ;pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf == iThisLeaf && iCurTranslucentEntity >= 0; --iCurTranslucentEntity )
  3654. {
  3655. IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable;
  3656. // Draw any detail props in this leaf that's farther than the entity
  3657. const Vector &vecRenderOrigin = pRenderable->GetRenderOrigin();
  3658. DetailObjectSystem()->RenderTranslucentDetailObjectsInLeaf( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nLeaf, &vecRenderOrigin );
  3659. bool bUsesPowerOfTwoFB = pRenderable->UsesPowerOfTwoFrameBufferTexture();
  3660. bool bUsesFullFB = pRenderable->UsesFullFrameBufferTexture();
  3661. if ( ( bUsesPowerOfTwoFB || bUsesFullFB )&& !bShadowDepth )
  3662. {
  3663. if( bRenderingWaterRenderTargets )
  3664. {
  3665. continue;
  3666. }
  3667. CMatRenderContextPtr pRenderContext( materials );
  3668. ITexture *rt = pRenderContext->GetRenderTarget();
  3669. if ( rt && bUsesFullFB )
  3670. {
  3671. UpdateScreenEffectTexture( 0, 0, 0, rt->GetActualWidth(), rt->GetActualHeight(), true );
  3672. }
  3673. else if ( bUsesPowerOfTwoFB )
  3674. {
  3675. UpdateRefractTexture();
  3676. }
  3677. pRenderContext.SafeRelease();
  3678. }
  3679. // Then draw the translucent renderable
  3680. DrawTranslucentRenderable( pRenderable, (pEntities[iCurTranslucentEntity].m_TwoPass != 0), bShadowDepth, false );
  3681. }
  3682. // Draw all remaining props in this leaf
  3683. DetailObjectSystem()->RenderTranslucentDetailObjectsInLeaf( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nLeaf, NULL );
  3684. }
  3685. else
  3686. {
  3687. // Draw queued up detail props (we know that the list of detail leaves won't include this leaf, since ShouldDrawDetailObjectsInLeaf is false)
  3688. // Therefore no fixup on nDetailLeafCount is required as in the above section
  3689. DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList );
  3690. for( ;pEntities[iCurTranslucentEntity].m_iWorldListInfoLeaf == iThisLeaf && iCurTranslucentEntity >= 0; --iCurTranslucentEntity )
  3691. {
  3692. IClientRenderable *pRenderable = pEntities[iCurTranslucentEntity].m_pRenderable;
  3693. bool bUsesPowerOfTwoFB = pRenderable->UsesPowerOfTwoFrameBufferTexture();
  3694. bool bUsesFullFB = pRenderable->UsesFullFrameBufferTexture();
  3695. if ( ( bUsesPowerOfTwoFB || bUsesFullFB )&& !bShadowDepth )
  3696. {
  3697. if( bRenderingWaterRenderTargets )
  3698. {
  3699. continue;
  3700. }
  3701. CMatRenderContextPtr pRenderContext( materials );
  3702. ITexture *rt = pRenderContext->GetRenderTarget();
  3703. if ( rt )
  3704. {
  3705. if ( bUsesFullFB )
  3706. {
  3707. UpdateScreenEffectTexture( 0, 0, 0, rt->GetActualWidth(), rt->GetActualHeight(), true );
  3708. }
  3709. else if ( bUsesPowerOfTwoFB )
  3710. {
  3711. UpdateRefractTexture(0, 0, rt->GetActualWidth(), rt->GetActualHeight());
  3712. }
  3713. }
  3714. else
  3715. {
  3716. if ( bUsesPowerOfTwoFB )
  3717. {
  3718. UpdateRefractTexture();
  3719. }
  3720. }
  3721. pRenderContext.SafeRelease();
  3722. }
  3723. DrawTranslucentRenderable( pRenderable, (pEntities[iCurTranslucentEntity].m_TwoPass != 0), bShadowDepth, false );
  3724. }
  3725. }
  3726. nDetailLeafCount = 0;
  3727. }
  3728. }
  3729. // Draw the rest of the surfaces in world leaves
  3730. DrawTranslucentWorldAndDetailPropsInLeaves( iPrevLeaf, 0, nEngineDrawFlags, nDetailLeafCount, pDetailLeafList, bShadowDepth );
  3731. // Draw any queued-up detail props from previously visited leaves
  3732. DetailObjectSystem()->RenderTranslucentDetailObjects( CurrentViewOrigin(), CurrentViewForward(), CurrentViewRight(), CurrentViewUp(), nDetailLeafCount, pDetailLeafList );
  3733. // Reset the blend state.
  3734. render->SetBlend( 1 );
  3735. }
  3736. //-----------------------------------------------------------------------------
  3737. //
  3738. //-----------------------------------------------------------------------------
  3739. void CRendering3dView::EnableWorldFog( void )
  3740. {
  3741. VPROF("CViewRender::EnableWorldFog");
  3742. CMatRenderContextPtr pRenderContext( materials );
  3743. fogparams_t *pFogParams = NULL;
  3744. C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
  3745. if ( pbp )
  3746. {
  3747. pFogParams = pbp->GetFogParams();
  3748. }
  3749. if( GetFogEnable( pFogParams ) )
  3750. {
  3751. float fogColor[3];
  3752. GetFogColor( pFogParams, fogColor );
  3753. pRenderContext->FogMode( MATERIAL_FOG_LINEAR );
  3754. pRenderContext->FogColor3fv( fogColor );
  3755. pRenderContext->FogStart( GetFogStart( pFogParams ) );
  3756. pRenderContext->FogEnd( GetFogEnd( pFogParams ) );
  3757. pRenderContext->FogMaxDensity( GetFogMaxDensity( pFogParams ) );
  3758. }
  3759. else
  3760. {
  3761. pRenderContext->FogMode( MATERIAL_FOG_NONE );
  3762. }
  3763. }
  3764. //-----------------------------------------------------------------------------
  3765. //
  3766. //-----------------------------------------------------------------------------
  3767. int CRendering3dView::GetDrawFlags()
  3768. {
  3769. return m_DrawFlags;
  3770. }
  3771. //-----------------------------------------------------------------------------
  3772. //
  3773. //-----------------------------------------------------------------------------
  3774. void CRendering3dView::SetFogVolumeState( const VisibleFogVolumeInfo_t &fogInfo, bool bUseHeightFog )
  3775. {
  3776. render->SetFogVolumeState( fogInfo.m_nVisibleFogVolume, bUseHeightFog );
  3777. #ifdef PORTAL
  3778. //the idea behind fog shifting is this...
  3779. //Normal fog simulates the effect of countless tiny particles between your viewpoint and whatever geometry is rendering.
  3780. //But, when rendering to a portal view, there's a large space between the virtual camera and the portal exit surface.
  3781. //This space isn't supposed to exist, and therefore has none of the tiny particles that make up fog.
  3782. //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
  3783. if( g_pPortalRender->GetViewRecursionLevel() == 0 )
  3784. return; //rendering one of the primary views, do nothing
  3785. g_pPortalRender->ShiftFogForExitPortalView();
  3786. #endif //#ifdef PORTAL
  3787. }
  3788. //-----------------------------------------------------------------------------
  3789. // Standard 3d skybox view
  3790. //-----------------------------------------------------------------------------
  3791. SkyboxVisibility_t CSkyboxView::ComputeSkyboxVisibility()
  3792. {
  3793. return engine->IsSkyboxVisibleFromPoint( origin );
  3794. }
  3795. //-----------------------------------------------------------------------------
  3796. //
  3797. //-----------------------------------------------------------------------------
  3798. bool CSkyboxView::GetSkyboxFogEnable()
  3799. {
  3800. C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
  3801. if( !pbp )
  3802. {
  3803. return false;
  3804. }
  3805. CPlayerLocalData *local = &pbp->m_Local;
  3806. if( fog_override.GetInt() )
  3807. {
  3808. if( fog_enableskybox.GetInt() )
  3809. {
  3810. return true;
  3811. }
  3812. else
  3813. {
  3814. return false;
  3815. }
  3816. }
  3817. else
  3818. {
  3819. return !!local->m_skybox3d.fog.enable;
  3820. }
  3821. }
  3822. //-----------------------------------------------------------------------------
  3823. //
  3824. //-----------------------------------------------------------------------------
  3825. void CSkyboxView::Enable3dSkyboxFog( void )
  3826. {
  3827. C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
  3828. if( !pbp )
  3829. {
  3830. return;
  3831. }
  3832. CPlayerLocalData *local = &pbp->m_Local;
  3833. CMatRenderContextPtr pRenderContext( materials );
  3834. if( GetSkyboxFogEnable() )
  3835. {
  3836. float fogColor[3];
  3837. GetSkyboxFogColor( fogColor );
  3838. float scale = 1.0f;
  3839. if ( local->m_skybox3d.scale > 0.0f )
  3840. {
  3841. scale = 1.0f / local->m_skybox3d.scale;
  3842. }
  3843. pRenderContext->FogMode( MATERIAL_FOG_LINEAR );
  3844. pRenderContext->FogColor3fv( fogColor );
  3845. pRenderContext->FogStart( GetSkyboxFogStart() * scale );
  3846. pRenderContext->FogEnd( GetSkyboxFogEnd() * scale );
  3847. pRenderContext->FogMaxDensity( GetSkyboxFogMaxDensity() );
  3848. }
  3849. else
  3850. {
  3851. pRenderContext->FogMode( MATERIAL_FOG_NONE );
  3852. }
  3853. }
  3854. //-----------------------------------------------------------------------------
  3855. //
  3856. //-----------------------------------------------------------------------------
  3857. sky3dparams_t *CSkyboxView::PreRender3dSkyboxWorld( SkyboxVisibility_t nSkyboxVisible )
  3858. {
  3859. if ( ( nSkyboxVisible != SKYBOX_3DSKYBOX_VISIBLE ) && r_3dsky.GetInt() != 2 )
  3860. return NULL;
  3861. // render the 3D skybox
  3862. if ( !r_3dsky.GetInt() )
  3863. return NULL;
  3864. C_BasePlayer *pbp = C_BasePlayer::GetLocalPlayer();
  3865. // No local player object yet...
  3866. if ( !pbp )
  3867. return NULL;
  3868. CPlayerLocalData* local = &pbp->m_Local;
  3869. if ( local->m_skybox3d.area == 255 )
  3870. return NULL;
  3871. return &local->m_skybox3d;
  3872. }
  3873. //-----------------------------------------------------------------------------
  3874. //
  3875. //-----------------------------------------------------------------------------
  3876. void CSkyboxView::DrawInternal( view_id_t iSkyBoxViewID, bool bInvokePreAndPostRender, ITexture *pRenderTarget, ITexture *pDepthTarget )
  3877. {
  3878. unsigned char **areabits = render->GetAreaBits();
  3879. unsigned char *savebits;
  3880. unsigned char tmpbits[ 32 ];
  3881. savebits = *areabits;
  3882. memset( tmpbits, 0, sizeof(tmpbits) );
  3883. // set the sky area bit
  3884. tmpbits[m_pSky3dParams->area>>3] |= 1 << (m_pSky3dParams->area&7);
  3885. *areabits = tmpbits;
  3886. // if you can get really close to the skybox geometry it's possible that you'll be able to clip into it
  3887. // with this near plane. If so, move it in a bit. It's at 2.0 to give us more precision. That means you
  3888. // need to keep the eye position at least 2 * scale away from the geometry in the skybox
  3889. zNear = 2.0;
  3890. zFar = MAX_TRACE_LENGTH;
  3891. // scale origin by sky scale
  3892. if ( m_pSky3dParams->scale > 0 )
  3893. {
  3894. float scale = 1.0f / m_pSky3dParams->scale;
  3895. VectorScale( origin, scale, origin );
  3896. }
  3897. Enable3dSkyboxFog();
  3898. VectorAdd( origin, m_pSky3dParams->origin, origin );
  3899. // BUGBUG: Fix this!!! We shouldn't need to call setup vis for the sky if we're connecting
  3900. // the areas. We'd have to mark all the clusters in the skybox area in the PVS of any
  3901. // cluster with sky. Then we could just connect the areas to do our vis.
  3902. //m_bOverrideVisOrigin could hose us here, so call direct
  3903. render->ViewSetupVis( false, 1, &m_pSky3dParams->origin.Get() );
  3904. render->Push3DView( (*this), m_ClearFlags, pRenderTarget, GetFrustum(), pDepthTarget );
  3905. // Store off view origin and angles
  3906. SetupCurrentView( origin, angles, iSkyBoxViewID );
  3907. #if defined( _X360 )
  3908. CMatRenderContextPtr pRenderContext( materials );
  3909. pRenderContext->PushVertexShaderGPRAllocation( 32 );
  3910. pRenderContext.SafeRelease();
  3911. #endif
  3912. // Invoke pre-render methods
  3913. if ( bInvokePreAndPostRender )
  3914. {
  3915. IGameSystem::PreRenderAllSystems();
  3916. }
  3917. render->BeginUpdateLightmaps();
  3918. BuildWorldRenderLists( true, true, -1 );
  3919. BuildRenderableRenderLists( iSkyBoxViewID );
  3920. render->EndUpdateLightmaps();
  3921. g_pClientShadowMgr->ComputeShadowTextures( (*this), m_pWorldListInfo->m_LeafCount, m_pWorldListInfo->m_pLeafList );
  3922. DrawWorld( 0.0f );
  3923. // Iterate over all leaves and render objects in those leaves
  3924. DrawOpaqueRenderables( DEPTH_MODE_NORMAL );
  3925. // Iterate over all leaves and render objects in those leaves
  3926. DrawTranslucentRenderables( true, false );
  3927. DrawNoZBufferTranslucentRenderables();
  3928. m_pMainView->DisableFog();
  3929. CGlowOverlay::UpdateSkyOverlays( zFar, m_bCacheFullSceneState );
  3930. PixelVisibility_EndCurrentView();
  3931. // restore old area bits
  3932. *areabits = savebits;
  3933. // Invoke post-render methods
  3934. if( bInvokePreAndPostRender )
  3935. {
  3936. IGameSystem::PostRenderAllSystems();
  3937. FinishCurrentView();
  3938. }
  3939. render->PopView( GetFrustum() );
  3940. #if defined( _X360 )
  3941. pRenderContext.GetFrom( materials );
  3942. pRenderContext->PopVertexShaderGPRAllocation();
  3943. #endif
  3944. }
  3945. //-----------------------------------------------------------------------------
  3946. //
  3947. //-----------------------------------------------------------------------------
  3948. bool CSkyboxView::Setup( const CViewSetup &viewRender, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible )
  3949. {
  3950. BaseClass::Setup( viewRender );
  3951. // The skybox might not be visible from here
  3952. *pSkyboxVisible = ComputeSkyboxVisibility();
  3953. m_pSky3dParams = PreRender3dSkyboxWorld( *pSkyboxVisible );
  3954. if ( !m_pSky3dParams )
  3955. {
  3956. return false;
  3957. }
  3958. // At this point, we've cleared everything we need to clear
  3959. // The next path will need to clear depth, though.
  3960. m_ClearFlags = *pClearFlags;
  3961. *pClearFlags &= ~( VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH | VIEW_CLEAR_STENCIL | VIEW_CLEAR_FULL_TARGET );
  3962. *pClearFlags |= VIEW_CLEAR_DEPTH; // Need to clear depth after rednering the skybox
  3963. m_DrawFlags = DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER | DF_RENDER_WATER;
  3964. if( r_skybox.GetBool() )
  3965. {
  3966. m_DrawFlags |= DF_DRAWSKYBOX;
  3967. }
  3968. return true;
  3969. }
  3970. //-----------------------------------------------------------------------------
  3971. //
  3972. //-----------------------------------------------------------------------------
  3973. void CSkyboxView::Draw()
  3974. {
  3975. VPROF_BUDGET( "CViewRender::Draw3dSkyboxworld", "3D Skybox" );
  3976. ITexture *pRTColor = NULL;
  3977. ITexture *pRTDepth = NULL;
  3978. if( m_eStereoEye != STEREO_EYE_MONO )
  3979. {
  3980. pRTColor = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(m_eStereoEye-1), ISourceVirtualReality::RT_Color );
  3981. pRTDepth = g_pSourceVR->GetRenderTarget( (ISourceVirtualReality::VREye)(m_eStereoEye-1), ISourceVirtualReality::RT_Depth );
  3982. }
  3983. DrawInternal(VIEW_3DSKY, true, pRTColor, pRTDepth );
  3984. }
  3985. #ifdef PORTAL
  3986. //-----------------------------------------------------------------------------
  3987. //
  3988. //-----------------------------------------------------------------------------
  3989. bool CPortalSkyboxView::Setup( const CViewSetup &view, int *pClearFlags, SkyboxVisibility_t *pSkyboxVisible, ITexture *pRenderTarget )
  3990. {
  3991. if ( !BaseClass::Setup( view, pClearFlags, pSkyboxVisible ) )
  3992. return false;
  3993. m_pRenderTarget = pRenderTarget;
  3994. return true;
  3995. }
  3996. //-----------------------------------------------------------------------------
  3997. //
  3998. //-----------------------------------------------------------------------------
  3999. SkyboxVisibility_t CPortalSkyboxView::ComputeSkyboxVisibility()
  4000. {
  4001. return g_pPortalRender->IsSkyboxVisibleFromExitPortal();
  4002. }
  4003. //-----------------------------------------------------------------------------
  4004. //
  4005. //-----------------------------------------------------------------------------
  4006. void CPortalSkyboxView::Draw()
  4007. {
  4008. AssertMsg( (g_pPortalRender->GetViewRecursionLevel() != 0) && g_pPortalRender->IsRenderingPortal(), "This is designed for through-portal views. Use the regular skybox drawing code for primary views" );
  4009. VPROF_BUDGET( "CViewRender::Draw3dSkyboxworld_Portal", "3D Skybox (portal view)" );
  4010. int iCurrentViewID = g_CurrentViewID;
  4011. Frustum FrustumBackup;
  4012. memcpy( FrustumBackup, GetFrustum(), sizeof( Frustum ) );
  4013. CMatRenderContextPtr pRenderContext( materials );
  4014. bool bClippingEnabled = pRenderContext->EnableClipping( false );
  4015. //NOTE: doesn't magically map to VIEW_3DSKY at (0,0) like PORTAL_VIEWID maps to VIEW_MAIN
  4016. view_id_t iSkyBoxViewID = (view_id_t)g_pPortalRender->GetCurrentSkyboxViewId();
  4017. bool bInvokePreAndPostRender = ( g_pPortalRender->ShouldUseStencilsToRenderPortals() == false );
  4018. DrawInternal( iSkyBoxViewID, bInvokePreAndPostRender, m_pRenderTarget, NULL );
  4019. pRenderContext->EnableClipping( bClippingEnabled );
  4020. memcpy( GetFrustum(), FrustumBackup, sizeof( Frustum ) );
  4021. render->OverrideViewFrustum( FrustumBackup );
  4022. g_CurrentViewID = iCurrentViewID;
  4023. }
  4024. #endif // PORTAL
  4025. //-----------------------------------------------------------------------------
  4026. //
  4027. //-----------------------------------------------------------------------------
  4028. void CShadowDepthView::Setup( const CViewSetup &shadowViewIn, ITexture *pRenderTarget, ITexture *pDepthTexture )
  4029. {
  4030. BaseClass::Setup( shadowViewIn );
  4031. m_pRenderTarget = pRenderTarget;
  4032. m_pDepthTexture = pDepthTexture;
  4033. }
  4034. bool DrawingShadowDepthView( void ) //for easy externing
  4035. {
  4036. return (CurrentViewID() == VIEW_SHADOW_DEPTH_TEXTURE);
  4037. }
  4038. bool DrawingMainView() //for easy externing
  4039. {
  4040. return (CurrentViewID() == VIEW_MAIN);
  4041. }
  4042. //-----------------------------------------------------------------------------
  4043. //
  4044. //-----------------------------------------------------------------------------
  4045. void CShadowDepthView::Draw()
  4046. {
  4047. VPROF_BUDGET( "CShadowDepthView::Draw", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4048. // Start view
  4049. unsigned int visFlags;
  4050. m_pMainView->SetupVis( (*this), visFlags ); // @MULTICORE (toml 8/9/2006): Portal problem, not sending custom vis down
  4051. CMatRenderContextPtr pRenderContext( materials );
  4052. pRenderContext->ClearColor3ub(0xFF, 0xFF, 0xFF);
  4053. #if defined( _X360 )
  4054. pRenderContext->PushVertexShaderGPRAllocation( 112 ); //almost all work is done in vertex shaders for depth rendering, max out their threads
  4055. #endif
  4056. pRenderContext.SafeRelease();
  4057. if( IsPC() )
  4058. {
  4059. render->Push3DView( (*this), VIEW_CLEAR_DEPTH, m_pRenderTarget, GetFrustum(), m_pDepthTexture );
  4060. }
  4061. else if( IsX360() )
  4062. {
  4063. //for the 360, the dummy render target has a separate depth buffer which we Resolve() from afterward
  4064. render->Push3DView( (*this), VIEW_CLEAR_DEPTH, m_pRenderTarget, GetFrustum() );
  4065. }
  4066. SetupCurrentView( origin, angles, VIEW_SHADOW_DEPTH_TEXTURE );
  4067. MDLCACHE_CRITICAL_SECTION();
  4068. {
  4069. VPROF_BUDGET( "BuildWorldRenderLists", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4070. BuildWorldRenderLists( true, -1, true, true ); // @MULTICORE (toml 8/9/2006): Portal problem, not sending custom vis down
  4071. }
  4072. {
  4073. VPROF_BUDGET( "BuildRenderableRenderLists", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4074. BuildRenderableRenderLists( CurrentViewID() );
  4075. }
  4076. engine->Sound_ExtraUpdate(); // Make sure sound doesn't stutter
  4077. m_DrawFlags = m_pMainView->GetBaseDrawFlags() | DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER | DF_SHADOW_DEPTH_MAP; // Don't draw water surface...
  4078. {
  4079. VPROF_BUDGET( "DrawWorld", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4080. DrawWorld( 0.0f );
  4081. }
  4082. // Draw opaque and translucent renderables with appropriate override materials
  4083. // OVERRIDE_DEPTH_WRITE is OK with a NULL material pointer
  4084. modelrender->ForcedMaterialOverride( NULL, OVERRIDE_DEPTH_WRITE );
  4085. {
  4086. VPROF_BUDGET( "DrawOpaqueRenderables", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4087. DrawOpaqueRenderables( DEPTH_MODE_SHADOW );
  4088. }
  4089. modelrender->ForcedMaterialOverride( 0 );
  4090. m_DrawFlags = 0;
  4091. pRenderContext.GetFrom( materials );
  4092. if( IsX360() )
  4093. {
  4094. //Resolve() the depth texture here. Before the pop so the copy will recognize that the resolutions are the same
  4095. pRenderContext->CopyRenderTargetToTextureEx( m_pDepthTexture, -1, NULL, NULL );
  4096. }
  4097. render->PopView( GetFrustum() );
  4098. #if defined( _X360 )
  4099. pRenderContext->PopVertexShaderGPRAllocation();
  4100. #endif
  4101. }
  4102. //-----------------------------------------------------------------------------
  4103. //
  4104. //-----------------------------------------------------------------------------
  4105. void CFreezeFrameView::Setup( const CViewSetup &shadowViewIn )
  4106. {
  4107. BaseClass::Setup( shadowViewIn );
  4108. KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  4109. pVMTKeyValues->SetString( "$basetexture", IsX360() ? "_rt_FullFrameFB1" : "_rt_FullScreen" );
  4110. pVMTKeyValues->SetInt( "$nocull", 1 );
  4111. pVMTKeyValues->SetInt( "$nofog", 1 );
  4112. pVMTKeyValues->SetInt( "$ignorez", 1 );
  4113. m_pFreezeFrame.Init( "FreezeFrame_FullScreen", TEXTURE_GROUP_OTHER, pVMTKeyValues );
  4114. m_pFreezeFrame->Refresh();
  4115. m_TranslucentSingleColor.Init( "debug/debugtranslucentsinglecolor", TEXTURE_GROUP_OTHER );
  4116. }
  4117. //-----------------------------------------------------------------------------
  4118. // Purpose:
  4119. //-----------------------------------------------------------------------------
  4120. void CFreezeFrameView::Draw( void )
  4121. {
  4122. CMatRenderContextPtr pRenderContext( materials );
  4123. #if defined( _X360 )
  4124. pRenderContext->PushVertexShaderGPRAllocation( 16 ); //max out pixel shader threads
  4125. #endif
  4126. // we might only need half of the texture if we're rendering in stereo
  4127. int nTexX0 = 0, nTexY0 = 0;
  4128. int nTexX1 = width, nTexY1 = height;
  4129. int nTexWidth = width, nTexHeight = height;
  4130. switch( m_eStereoEye )
  4131. {
  4132. case STEREO_EYE_LEFT:
  4133. nTexX1 = width;
  4134. nTexWidth *= 2;
  4135. break;
  4136. case STEREO_EYE_RIGHT:
  4137. nTexX0 = width;
  4138. nTexX1 = width*2;
  4139. nTexWidth *= 2;
  4140. break;
  4141. }
  4142. pRenderContext->DrawScreenSpaceRectangle( m_pFreezeFrame, x, y, width, height,
  4143. nTexX0, nTexY0, nTexX1-1, nTexY1-1, nTexWidth, nTexHeight );
  4144. //Fake a fade during freezeframe view.
  4145. if ( g_flFreezeFlash >= gpGlobals->curtime && engine->IsTakingScreenshot() == false )
  4146. {
  4147. // Overlay screen fade on entire screen
  4148. IMaterial* pMaterial = m_TranslucentSingleColor;
  4149. int iFadeAlpha = FREEZECAM_SNAPSHOT_FADE_SPEED * ( g_flFreezeFlash - gpGlobals->curtime );
  4150. iFadeAlpha = MIN( iFadeAlpha, 255 );
  4151. iFadeAlpha = MAX( 0, iFadeAlpha );
  4152. pMaterial->AlphaModulate( iFadeAlpha * ( 1.0f / 255.0f ) );
  4153. pMaterial->ColorModulate( 1.0f, 1.0f, 1.0f );
  4154. pMaterial->SetMaterialVarFlag( MATERIAL_VAR_IGNOREZ, true );
  4155. pRenderContext->DrawScreenSpaceRectangle( pMaterial, x, y, width, height, 0, 0, width-1, height-1, width, height );
  4156. }
  4157. #if defined( _X360 )
  4158. pRenderContext->PopVertexShaderGPRAllocation();
  4159. #endif
  4160. }
  4161. //-----------------------------------------------------------------------------
  4162. // Pops a water render target
  4163. //-----------------------------------------------------------------------------
  4164. bool CBaseWorldView::AdjustView( float waterHeight )
  4165. {
  4166. if( m_DrawFlags & DF_RENDER_REFRACTION )
  4167. {
  4168. ITexture *pTexture = GetWaterRefractionTexture();
  4169. // Use the aspect ratio of the main view! So, don't recompute it here
  4170. x = y = 0;
  4171. width = pTexture->GetActualWidth();
  4172. height = pTexture->GetActualHeight();
  4173. return true;
  4174. }
  4175. if( m_DrawFlags & DF_RENDER_REFLECTION )
  4176. {
  4177. ITexture *pTexture = GetWaterReflectionTexture();
  4178. // If the main view is overriding the projection matrix (for Stereo or
  4179. // some other nefarious purpose) make sure to include any Y offset in
  4180. // the custom projection matrix in our reflected overridden projection
  4181. // matrix.
  4182. if( m_bViewToProjectionOverride )
  4183. {
  4184. m_ViewToProjection[1][2] = -m_ViewToProjection[1][2];
  4185. }
  4186. // Use the aspect ratio of the main view! So, don't recompute it here
  4187. x = y = 0;
  4188. width = pTexture->GetActualWidth();
  4189. height = pTexture->GetActualHeight();
  4190. angles[0] = -angles[0];
  4191. angles[2] = -angles[2];
  4192. origin[2] -= 2.0f * ( origin[2] - (waterHeight));
  4193. return true;
  4194. }
  4195. return false;
  4196. }
  4197. //-----------------------------------------------------------------------------
  4198. // Pops a water render target
  4199. //-----------------------------------------------------------------------------
  4200. void CBaseWorldView::PushView( float waterHeight )
  4201. {
  4202. float spread = 2.0f;
  4203. if( m_DrawFlags & DF_FUDGE_UP )
  4204. {
  4205. waterHeight += spread;
  4206. }
  4207. else
  4208. {
  4209. waterHeight -= spread;
  4210. }
  4211. MaterialHeightClipMode_t clipMode = MATERIAL_HEIGHTCLIPMODE_DISABLE;
  4212. if ( ( m_DrawFlags & DF_CLIP_Z ) && mat_clipz.GetBool() )
  4213. {
  4214. if( m_DrawFlags & DF_CLIP_BELOW )
  4215. {
  4216. clipMode = MATERIAL_HEIGHTCLIPMODE_RENDER_ABOVE_HEIGHT;
  4217. }
  4218. else
  4219. {
  4220. clipMode = MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT;
  4221. }
  4222. }
  4223. CMatRenderContextPtr pRenderContext( materials );
  4224. if( m_DrawFlags & DF_RENDER_REFRACTION )
  4225. {
  4226. pRenderContext->SetFogZ( waterHeight );
  4227. pRenderContext->SetHeightClipZ( waterHeight );
  4228. pRenderContext->SetHeightClipMode( clipMode );
  4229. // Have to re-set up the view since we reset the size
  4230. render->Push3DView( *this, m_ClearFlags, GetWaterRefractionTexture(), GetFrustum() );
  4231. return;
  4232. }
  4233. if( m_DrawFlags & DF_RENDER_REFLECTION )
  4234. {
  4235. ITexture *pTexture = GetWaterReflectionTexture();
  4236. pRenderContext->SetFogZ( waterHeight );
  4237. bool bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping();
  4238. if( bSoftwareUserClipPlane && ( origin[2] > waterHeight - r_eyewaterepsilon.GetFloat() ) )
  4239. {
  4240. waterHeight = origin[2] + r_eyewaterepsilon.GetFloat();
  4241. }
  4242. pRenderContext->SetHeightClipZ( waterHeight );
  4243. pRenderContext->SetHeightClipMode( clipMode );
  4244. render->Push3DView( *this, m_ClearFlags, pTexture, GetFrustum() );
  4245. SetLightmapScaleForWater();
  4246. return;
  4247. }
  4248. if ( m_ClearFlags & ( VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_STENCIL ) )
  4249. {
  4250. if ( m_ClearFlags & VIEW_CLEAR_OBEY_STENCIL )
  4251. {
  4252. pRenderContext->ClearBuffersObeyStencil( m_ClearFlags & VIEW_CLEAR_COLOR, m_ClearFlags & VIEW_CLEAR_DEPTH );
  4253. }
  4254. else
  4255. {
  4256. pRenderContext->ClearBuffers( m_ClearFlags & VIEW_CLEAR_COLOR, m_ClearFlags & VIEW_CLEAR_DEPTH, m_ClearFlags & VIEW_CLEAR_STENCIL );
  4257. }
  4258. }
  4259. pRenderContext->SetHeightClipMode( clipMode );
  4260. if ( clipMode != MATERIAL_HEIGHTCLIPMODE_DISABLE )
  4261. {
  4262. pRenderContext->SetHeightClipZ( waterHeight );
  4263. }
  4264. }
  4265. //-----------------------------------------------------------------------------
  4266. // Pops a water render target
  4267. //-----------------------------------------------------------------------------
  4268. void CBaseWorldView::PopView()
  4269. {
  4270. CMatRenderContextPtr pRenderContext( materials );
  4271. pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
  4272. if( m_DrawFlags & (DF_RENDER_REFRACTION | DF_RENDER_REFLECTION) )
  4273. {
  4274. if ( IsX360() )
  4275. {
  4276. // these renders paths used their surfaces, so blit their results
  4277. if ( m_DrawFlags & DF_RENDER_REFRACTION )
  4278. {
  4279. pRenderContext->CopyRenderTargetToTextureEx( GetWaterRefractionTexture(), NULL, NULL );
  4280. }
  4281. if ( m_DrawFlags & DF_RENDER_REFLECTION )
  4282. {
  4283. pRenderContext->CopyRenderTargetToTextureEx( GetWaterReflectionTexture(), NULL, NULL );
  4284. }
  4285. }
  4286. render->PopView( GetFrustum() );
  4287. if (SavedLinearLightMapScale.x>=0)
  4288. {
  4289. pRenderContext->SetToneMappingScaleLinear(SavedLinearLightMapScale);
  4290. SavedLinearLightMapScale.x=-1;
  4291. }
  4292. }
  4293. }
  4294. //-----------------------------------------------------------------------------
  4295. // Draws the world + entities
  4296. //-----------------------------------------------------------------------------
  4297. void CBaseWorldView::DrawSetup( float waterHeight, int nSetupFlags, float waterZAdjust, int iForceViewLeaf )
  4298. {
  4299. int savedViewID = g_CurrentViewID;
  4300. g_CurrentViewID = VIEW_ILLEGAL;
  4301. bool bViewChanged = AdjustView( waterHeight );
  4302. if ( bViewChanged )
  4303. {
  4304. render->Push3DView( *this, 0, NULL, GetFrustum() );
  4305. }
  4306. render->BeginUpdateLightmaps();
  4307. bool bDrawEntities = ( nSetupFlags & DF_DRAW_ENTITITES ) != 0;
  4308. bool bDrawReflection = ( nSetupFlags & DF_RENDER_REFLECTION ) != 0;
  4309. BuildWorldRenderLists( bDrawEntities, iForceViewLeaf, true, false, bDrawReflection ? &waterHeight : NULL );
  4310. PruneWorldListInfo();
  4311. if ( bDrawEntities )
  4312. {
  4313. BuildRenderableRenderLists( savedViewID );
  4314. }
  4315. render->EndUpdateLightmaps();
  4316. if ( bViewChanged )
  4317. {
  4318. render->PopView( GetFrustum() );
  4319. }
  4320. #ifdef TF_CLIENT_DLL
  4321. bool bVisionOverride = ( localplayer_visionflags.GetInt() & ( 0x01 ) ); // Pyro-vision Goggles
  4322. if ( savedViewID == VIEW_MAIN && bVisionOverride && pyro_dof.GetBool() )
  4323. {
  4324. SSAO_DepthPass();
  4325. }
  4326. #endif
  4327. g_CurrentViewID = savedViewID;
  4328. }
  4329. void MaybeInvalidateLocalPlayerAnimation()
  4330. {
  4331. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  4332. if ( ( pPlayer != NULL ) && pPlayer->InFirstPersonView() )
  4333. {
  4334. // We sometimes need different animation for the main view versus the shadow rendering,
  4335. // so we need to reset the cache to ensure this actually happens.
  4336. pPlayer->InvalidateBoneCache();
  4337. C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
  4338. if ( pWeapon != NULL )
  4339. {
  4340. pWeapon->InvalidateBoneCache();
  4341. }
  4342. #if defined USES_ECON_ITEMS
  4343. // ...and all the things you're wearing/holding/etc
  4344. int NumWearables = pPlayer->GetNumWearables();
  4345. for ( int i = 0; i < NumWearables; ++i )
  4346. {
  4347. CEconWearable* pItem = pPlayer->GetWearable ( i );
  4348. if ( pItem != NULL )
  4349. {
  4350. pItem->InvalidateBoneCache();
  4351. }
  4352. }
  4353. #endif // USES_ECON_ITEMS
  4354. }
  4355. }
  4356. void CBaseWorldView::DrawExecute( float waterHeight, view_id_t viewID, float waterZAdjust )
  4357. {
  4358. int savedViewID = g_CurrentViewID;
  4359. // @MULTICORE (toml 8/16/2006): rethink how, where, and when this is done...
  4360. g_CurrentViewID = VIEW_SHADOW_DEPTH_TEXTURE;
  4361. MaybeInvalidateLocalPlayerAnimation();
  4362. g_pClientShadowMgr->ComputeShadowTextures( *this, m_pWorldListInfo->m_LeafCount, m_pWorldListInfo->m_pLeafList );
  4363. MaybeInvalidateLocalPlayerAnimation();
  4364. // Make sure sound doesn't stutter
  4365. engine->Sound_ExtraUpdate();
  4366. g_CurrentViewID = viewID;
  4367. // Update our render view flags.
  4368. int iDrawFlagsBackup = m_DrawFlags;
  4369. m_DrawFlags |= m_pMainView->GetBaseDrawFlags();
  4370. PushView( waterHeight );
  4371. CMatRenderContextPtr pRenderContext( materials );
  4372. #if defined( _X360 )
  4373. pRenderContext->PushVertexShaderGPRAllocation( 32 );
  4374. #endif
  4375. ITexture *pSaveFrameBufferCopyTexture = pRenderContext->GetFrameBufferCopyTexture( 0 );
  4376. if ( engine->GetDXSupportLevel() >= 80 )
  4377. {
  4378. pRenderContext->SetFrameBufferCopyTexture( GetPowerOfTwoFrameBufferTexture() );
  4379. }
  4380. pRenderContext.SafeRelease();
  4381. ERenderDepthMode DepthMode = DEPTH_MODE_NORMAL;
  4382. if ( m_DrawFlags & DF_DRAW_ENTITITES )
  4383. {
  4384. DrawWorld( waterZAdjust );
  4385. DrawOpaqueRenderables( DepthMode );
  4386. #ifdef TF_CLIENT_DLL
  4387. bool bVisionOverride = ( localplayer_visionflags.GetInt() & ( 0x01 ) ); // Pyro-vision Goggles
  4388. if ( g_CurrentViewID == VIEW_MAIN && bVisionOverride && pyro_dof.GetBool() ) // Pyro-vision Goggles
  4389. {
  4390. DrawDepthOfField();
  4391. }
  4392. #endif
  4393. DrawTranslucentRenderables( false, false );
  4394. DrawNoZBufferTranslucentRenderables();
  4395. }
  4396. else
  4397. {
  4398. DrawWorld( waterZAdjust );
  4399. #ifdef TF_CLIENT_DLL
  4400. bool bVisionOverride = ( localplayer_visionflags.GetInt() & ( 0x01 ) ); // Pyro-vision Goggles
  4401. if ( g_CurrentViewID == VIEW_MAIN && bVisionOverride && pyro_dof.GetBool() ) // Pyro-vision Goggles
  4402. {
  4403. DrawDepthOfField();
  4404. }
  4405. #endif
  4406. // Draw translucent world brushes only, no entities
  4407. DrawTranslucentWorldInLeaves( false );
  4408. }
  4409. // issue the pixel visibility tests for sub-views
  4410. if ( !IsMainView( CurrentViewID() ) && CurrentViewID() != VIEW_INTRO_CAMERA )
  4411. {
  4412. PixelVisibility_EndCurrentView();
  4413. }
  4414. pRenderContext.GetFrom( materials );
  4415. pRenderContext->SetFrameBufferCopyTexture( pSaveFrameBufferCopyTexture );
  4416. PopView();
  4417. m_DrawFlags = iDrawFlagsBackup;
  4418. g_CurrentViewID = savedViewID;
  4419. #if defined( _X360 )
  4420. pRenderContext->PopVertexShaderGPRAllocation();
  4421. #endif
  4422. }
  4423. void CBaseWorldView::SSAO_DepthPass()
  4424. {
  4425. if ( !g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_0() )
  4426. {
  4427. return;
  4428. }
  4429. #if 1
  4430. VPROF_BUDGET( "CSimpleWorldView::SSAO_DepthPass", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4431. int savedViewID = g_CurrentViewID;
  4432. g_CurrentViewID = VIEW_SSAO;
  4433. ITexture *pSSAO = materials->FindTexture( "_rt_ResolvedFullFrameDepth", TEXTURE_GROUP_RENDER_TARGET );
  4434. CMatRenderContextPtr pRenderContext( materials );
  4435. pRenderContext->ClearColor4ub( 255, 255, 255, 255 );
  4436. #if defined( _X360 )
  4437. Assert(0); // rebalance this if we ever use this on 360
  4438. pRenderContext->PushVertexShaderGPRAllocation( 112 ); //almost all work is done in vertex shaders for depth rendering, max out their threads
  4439. #endif
  4440. pRenderContext.SafeRelease();
  4441. if( IsPC() )
  4442. {
  4443. render->Push3DView( (*this), VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, pSSAO, GetFrustum() );
  4444. }
  4445. else if( IsX360() )
  4446. {
  4447. render->Push3DView( (*this), VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR, pSSAO, GetFrustum() );
  4448. }
  4449. MDLCACHE_CRITICAL_SECTION();
  4450. engine->Sound_ExtraUpdate(); // Make sure sound doesn't stutter
  4451. m_DrawFlags |= DF_SSAO_DEPTH_PASS;
  4452. {
  4453. VPROF_BUDGET( "DrawWorld", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4454. DrawWorld( 0.0f );
  4455. }
  4456. // Draw opaque and translucent renderables with appropriate override materials
  4457. // OVERRIDE_SSAO_DEPTH_WRITE is OK with a NULL material pointer
  4458. modelrender->ForcedMaterialOverride( NULL, OVERRIDE_SSAO_DEPTH_WRITE );
  4459. {
  4460. VPROF_BUDGET( "DrawOpaqueRenderables", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4461. DrawOpaqueRenderables( DEPTH_MODE_SSA0 );
  4462. }
  4463. #if 0
  4464. if ( m_bRenderFlashlightDepthTranslucents || r_flashlightdepth_drawtranslucents.GetBool() )
  4465. {
  4466. VPROF_BUDGET( "DrawTranslucentRenderables", VPROF_BUDGETGROUP_SHADOW_DEPTH_TEXTURING );
  4467. DrawTranslucentRenderables( false, true );
  4468. }
  4469. #endif
  4470. modelrender->ForcedMaterialOverride( 0 );
  4471. m_DrawFlags &= ~DF_SSAO_DEPTH_PASS;
  4472. pRenderContext.GetFrom( materials );
  4473. if( IsX360() )
  4474. {
  4475. //Resolve() the depth texture here. Before the pop so the copy will recognize that the resolutions are the same
  4476. pRenderContext->CopyRenderTargetToTextureEx( NULL, -1, NULL, NULL );
  4477. }
  4478. render->PopView( GetFrustum() );
  4479. #if defined( _X360 )
  4480. pRenderContext->PopVertexShaderGPRAllocation();
  4481. #endif
  4482. pRenderContext.SafeRelease();
  4483. g_CurrentViewID = savedViewID;
  4484. #endif
  4485. }
  4486. void CBaseWorldView::DrawDepthOfField( )
  4487. {
  4488. if ( !g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_0() )
  4489. {
  4490. return;
  4491. }
  4492. CMatRenderContextPtr pRenderContext( materials );
  4493. ITexture *pSmallFB0 = materials->FindTexture( "_rt_smallfb0", TEXTURE_GROUP_RENDER_TARGET );
  4494. ITexture *pSmallFB1 = materials->FindTexture( "_rt_smallfb1", TEXTURE_GROUP_RENDER_TARGET );
  4495. Rect_t DestRect;
  4496. int w = pSmallFB0->GetActualWidth();
  4497. int h = pSmallFB0->GetActualHeight();
  4498. DestRect.x = 0;
  4499. DestRect.y = 0;
  4500. DestRect.width = w;
  4501. DestRect.height = h;
  4502. pRenderContext->CopyRenderTargetToTextureEx( pSmallFB0, 0, NULL, &DestRect );
  4503. IMaterial *pPyroBlurXMaterial = materials->FindMaterial( "dev/pyro_blur_filter_x", TEXTURE_GROUP_OTHER );
  4504. IMaterial *pPyroBlurYMaterial = materials->FindMaterial( "dev/pyro_blur_filter_y", TEXTURE_GROUP_OTHER );
  4505. pRenderContext->PushRenderTargetAndViewport( pSmallFB1, 0, 0, w, h );
  4506. pRenderContext->DrawScreenSpaceRectangle( pPyroBlurYMaterial, 0, 0, w, h, 0, 0, w - 1, h - 1, w, h );
  4507. pRenderContext->PopRenderTargetAndViewport();
  4508. pRenderContext->PushRenderTargetAndViewport( pSmallFB0, 0, 0, w, h );
  4509. pRenderContext->DrawScreenSpaceRectangle( pPyroBlurXMaterial, 0, 0, w, h, 0, 0, w - 1, h - 1, w, h );
  4510. pRenderContext->PopRenderTargetAndViewport();
  4511. IMaterial *pPyroDepthOfFieldMaterial = materials->FindMaterial( "dev/pyro_dof", TEXTURE_GROUP_OTHER );
  4512. pRenderContext->DrawScreenSpaceRectangle( pPyroDepthOfFieldMaterial, x, y, width, height, 0, 0, width-1, height-1, width, height );
  4513. }
  4514. //-----------------------------------------------------------------------------
  4515. // Draws the scene when there's no water or only cheap water
  4516. //-----------------------------------------------------------------------------
  4517. void CSimpleWorldView::Setup( const CViewSetup &simpleView, int nClearFlags, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, ViewCustomVisibility_t *pCustomVisibility )
  4518. {
  4519. BaseClass::Setup( simpleView );
  4520. m_ClearFlags = nClearFlags;
  4521. m_DrawFlags = DF_DRAW_ENTITITES;
  4522. if ( !waterInfo.m_bOpaqueWater )
  4523. {
  4524. m_DrawFlags |= DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER;
  4525. }
  4526. else
  4527. {
  4528. bool bViewIntersectsWater = DoesViewPlaneIntersectWater( fogInfo.m_flWaterHeight, fogInfo.m_nVisibleFogVolume );
  4529. if( bViewIntersectsWater )
  4530. {
  4531. // have to draw both sides if we can see both.
  4532. m_DrawFlags |= DF_RENDER_UNDERWATER | DF_RENDER_ABOVEWATER;
  4533. }
  4534. else if ( fogInfo.m_bEyeInFogVolume )
  4535. {
  4536. m_DrawFlags |= DF_RENDER_UNDERWATER;
  4537. }
  4538. else
  4539. {
  4540. m_DrawFlags |= DF_RENDER_ABOVEWATER;
  4541. }
  4542. }
  4543. if ( waterInfo.m_bDrawWaterSurface )
  4544. {
  4545. m_DrawFlags |= DF_RENDER_WATER;
  4546. }
  4547. if ( !fogInfo.m_bEyeInFogVolume && bDrawSkybox )
  4548. {
  4549. m_DrawFlags |= DF_DRAWSKYBOX;
  4550. }
  4551. m_pCustomVisibility = pCustomVisibility;
  4552. m_fogInfo = fogInfo;
  4553. }
  4554. //-----------------------------------------------------------------------------
  4555. // Draws the scene when there's no water or only cheap water
  4556. //-----------------------------------------------------------------------------
  4557. void CSimpleWorldView::Draw()
  4558. {
  4559. VPROF( "CViewRender::ViewDrawScene_NoWater" );
  4560. CMatRenderContextPtr pRenderContext( materials );
  4561. PIXEVENT( pRenderContext, "CSimpleWorldView::Draw" );
  4562. #if defined( _X360 )
  4563. pRenderContext->PushVertexShaderGPRAllocation( 32 ); //lean toward pixel shader threads
  4564. #endif
  4565. pRenderContext.SafeRelease();
  4566. DrawSetup( 0, m_DrawFlags, 0 );
  4567. if ( !m_fogInfo.m_bEyeInFogVolume )
  4568. {
  4569. EnableWorldFog();
  4570. }
  4571. else
  4572. {
  4573. m_ClearFlags |= VIEW_CLEAR_COLOR;
  4574. SetFogVolumeState( m_fogInfo, false );
  4575. pRenderContext.GetFrom( materials );
  4576. unsigned char ucFogColor[3];
  4577. pRenderContext->GetFogColor( ucFogColor );
  4578. pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 );
  4579. }
  4580. pRenderContext.SafeRelease();
  4581. DrawExecute( 0, CurrentViewID(), 0 );
  4582. pRenderContext.GetFrom( materials );
  4583. pRenderContext->ClearColor4ub( 0, 0, 0, 255 );
  4584. #if defined( _X360 )
  4585. pRenderContext->PopVertexShaderGPRAllocation();
  4586. #endif
  4587. }
  4588. //-----------------------------------------------------------------------------
  4589. //
  4590. //-----------------------------------------------------------------------------
  4591. void CBaseWaterView::CalcWaterEyeAdjustments( const VisibleFogVolumeInfo_t &fogInfo,
  4592. float &newWaterHeight, float &waterZAdjust, bool bSoftwareUserClipPlane )
  4593. {
  4594. if( !bSoftwareUserClipPlane )
  4595. {
  4596. newWaterHeight = fogInfo.m_flWaterHeight;
  4597. waterZAdjust = 0.0f;
  4598. return;
  4599. }
  4600. newWaterHeight = fogInfo.m_flWaterHeight;
  4601. float eyeToWaterZDelta = origin[2] - fogInfo.m_flWaterHeight;
  4602. float epsilon = r_eyewaterepsilon.GetFloat();
  4603. waterZAdjust = 0.0f;
  4604. if( fabs( eyeToWaterZDelta ) < epsilon )
  4605. {
  4606. if( eyeToWaterZDelta > 0 )
  4607. {
  4608. newWaterHeight = origin[2] - epsilon;
  4609. }
  4610. else
  4611. {
  4612. newWaterHeight = origin[2] + epsilon;
  4613. }
  4614. waterZAdjust = newWaterHeight - fogInfo.m_flWaterHeight;
  4615. }
  4616. // Warning( "view.origin[2]: %f newWaterHeight: %f fogInfo.m_flWaterHeight: %f waterZAdjust: %f\n",
  4617. // ( float )view.origin[2], newWaterHeight, fogInfo.m_flWaterHeight, waterZAdjust );
  4618. }
  4619. //-----------------------------------------------------------------------------
  4620. //
  4621. //-----------------------------------------------------------------------------
  4622. void CBaseWaterView::CSoftwareIntersectionView::Setup( bool bAboveWater )
  4623. {
  4624. BaseClass::Setup( *GetOuter() );
  4625. m_DrawFlags = 0;
  4626. m_DrawFlags = ( bAboveWater ) ? DF_RENDER_UNDERWATER : DF_RENDER_ABOVEWATER;
  4627. }
  4628. //-----------------------------------------------------------------------------
  4629. //
  4630. //-----------------------------------------------------------------------------
  4631. void CBaseWaterView::CSoftwareIntersectionView::Draw()
  4632. {
  4633. DrawSetup( GetOuter()->m_waterHeight, m_DrawFlags, GetOuter()->m_waterZAdjust );
  4634. DrawExecute( GetOuter()->m_waterHeight, CurrentViewID(), GetOuter()->m_waterZAdjust );
  4635. }
  4636. //-----------------------------------------------------------------------------
  4637. // Draws the scene when the view point is above the level of the water
  4638. //-----------------------------------------------------------------------------
  4639. void CAboveWaterView::Setup( const CViewSetup &viewRender, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo )
  4640. {
  4641. BaseClass::Setup( viewRender );
  4642. m_bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping();
  4643. CalcWaterEyeAdjustments( fogInfo, m_waterHeight, m_waterZAdjust, m_bSoftwareUserClipPlane );
  4644. // BROKEN STUFF!
  4645. if ( m_waterZAdjust == 0.0f )
  4646. {
  4647. m_bSoftwareUserClipPlane = false;
  4648. }
  4649. m_DrawFlags = DF_RENDER_ABOVEWATER | DF_DRAW_ENTITITES;
  4650. m_ClearFlags = VIEW_CLEAR_DEPTH;
  4651. #ifdef PORTAL
  4652. if( g_pPortalRender->ShouldObeyStencilForClears() )
  4653. m_ClearFlags |= VIEW_CLEAR_OBEY_STENCIL;
  4654. #endif
  4655. if ( bDrawSkybox )
  4656. {
  4657. m_DrawFlags |= DF_DRAWSKYBOX;
  4658. }
  4659. if ( waterInfo.m_bDrawWaterSurface )
  4660. {
  4661. m_DrawFlags |= DF_RENDER_WATER;
  4662. }
  4663. if ( !waterInfo.m_bRefract && !waterInfo.m_bOpaqueWater )
  4664. {
  4665. m_DrawFlags |= DF_RENDER_UNDERWATER;
  4666. }
  4667. m_fogInfo = fogInfo;
  4668. m_waterInfo = waterInfo;
  4669. }
  4670. //-----------------------------------------------------------------------------
  4671. //
  4672. //-----------------------------------------------------------------------------
  4673. void CAboveWaterView::Draw()
  4674. {
  4675. VPROF( "CViewRender::ViewDrawScene_EyeAboveWater" );
  4676. // eye is outside of water
  4677. CMatRenderContextPtr pRenderContext( materials );
  4678. // render the reflection
  4679. if( m_waterInfo.m_bReflect )
  4680. {
  4681. m_ReflectionView.Setup( m_waterInfo.m_bReflectEntities );
  4682. m_pMainView->AddViewToScene( &m_ReflectionView );
  4683. }
  4684. bool bViewIntersectsWater = false;
  4685. // render refraction
  4686. if ( m_waterInfo.m_bRefract )
  4687. {
  4688. m_RefractionView.Setup();
  4689. m_pMainView->AddViewToScene( &m_RefractionView );
  4690. if( !m_bSoftwareUserClipPlane )
  4691. {
  4692. bViewIntersectsWater = DoesViewPlaneIntersectWater( m_fogInfo.m_flWaterHeight, m_fogInfo.m_nVisibleFogVolume );
  4693. }
  4694. }
  4695. else if ( !( m_DrawFlags & DF_DRAWSKYBOX ) )
  4696. {
  4697. m_ClearFlags |= VIEW_CLEAR_COLOR;
  4698. }
  4699. #ifdef PORTAL
  4700. if( g_pPortalRender->ShouldObeyStencilForClears() )
  4701. m_ClearFlags |= VIEW_CLEAR_OBEY_STENCIL;
  4702. #endif
  4703. // NOTE!!!!! YOU CAN ONLY DO THIS IF YOU HAVE HARDWARE USER CLIP PLANES!!!!!!
  4704. bool bHardwareUserClipPlanes = !g_pMaterialSystemHardwareConfig->UseFastClipping();
  4705. if( bViewIntersectsWater && bHardwareUserClipPlanes )
  4706. {
  4707. // This is necessary to keep the non-water fogged world from drawing underwater in
  4708. // the case where we want to partially see into the water.
  4709. m_DrawFlags |= DF_CLIP_Z | DF_CLIP_BELOW;
  4710. }
  4711. // render the world
  4712. DrawSetup( m_waterHeight, m_DrawFlags, m_waterZAdjust );
  4713. EnableWorldFog();
  4714. DrawExecute( m_waterHeight, CurrentViewID(), m_waterZAdjust );
  4715. if ( m_waterInfo.m_bRefract )
  4716. {
  4717. if ( m_bSoftwareUserClipPlane )
  4718. {
  4719. m_SoftwareIntersectionView.Setup( true );
  4720. m_SoftwareIntersectionView.Draw( );
  4721. }
  4722. else if ( bViewIntersectsWater )
  4723. {
  4724. m_IntersectionView.Setup();
  4725. m_pMainView->AddViewToScene( &m_IntersectionView );
  4726. }
  4727. }
  4728. }
  4729. //-----------------------------------------------------------------------------
  4730. //
  4731. //-----------------------------------------------------------------------------
  4732. void CAboveWaterView::CReflectionView::Setup( bool bReflectEntities )
  4733. {
  4734. BaseClass::Setup( *GetOuter() );
  4735. m_ClearFlags = VIEW_CLEAR_DEPTH;
  4736. // NOTE: Clearing the color is unnecessary since we're drawing the skybox
  4737. // and dest-alpha is never used in the reflection
  4738. m_DrawFlags = DF_RENDER_REFLECTION | DF_CLIP_Z | DF_CLIP_BELOW |
  4739. DF_RENDER_ABOVEWATER;
  4740. // NOTE: This will cause us to draw the 2d skybox in the reflection
  4741. // (which we want to do instead of drawing the 3d skybox)
  4742. m_DrawFlags |= DF_DRAWSKYBOX;
  4743. if( bReflectEntities )
  4744. {
  4745. m_DrawFlags |= DF_DRAW_ENTITITES;
  4746. }
  4747. }
  4748. //-----------------------------------------------------------------------------
  4749. //
  4750. //-----------------------------------------------------------------------------
  4751. void CAboveWaterView::CReflectionView::Draw()
  4752. {
  4753. #ifdef PORTAL
  4754. g_pPortalRender->WaterRenderingHandler_PreReflection();
  4755. #endif
  4756. // Store off view origin and angles and set the new view
  4757. int nSaveViewID = CurrentViewID();
  4758. SetupCurrentView( origin, angles, VIEW_REFLECTION );
  4759. // Disable occlusion visualization in reflection
  4760. bool bVisOcclusion = r_visocclusion.GetInt();
  4761. r_visocclusion.SetValue( 0 );
  4762. DrawSetup( GetOuter()->m_fogInfo.m_flWaterHeight, m_DrawFlags, 0.0f, GetOuter()->m_fogInfo.m_nVisibleFogVolumeLeaf );
  4763. EnableWorldFog();
  4764. DrawExecute( GetOuter()->m_fogInfo.m_flWaterHeight, VIEW_REFLECTION, 0.0f );
  4765. r_visocclusion.SetValue( bVisOcclusion );
  4766. #ifdef PORTAL
  4767. // deal with stencil
  4768. g_pPortalRender->WaterRenderingHandler_PostReflection();
  4769. #endif
  4770. // finish off the view and restore the previous view.
  4771. SetupCurrentView( origin, angles, ( view_id_t )nSaveViewID );
  4772. // This is here for multithreading
  4773. CMatRenderContextPtr pRenderContext( materials );
  4774. pRenderContext->Flush();
  4775. }
  4776. //-----------------------------------------------------------------------------
  4777. //
  4778. //-----------------------------------------------------------------------------
  4779. void CAboveWaterView::CRefractionView::Setup()
  4780. {
  4781. BaseClass::Setup( *GetOuter() );
  4782. m_ClearFlags = VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH;
  4783. m_DrawFlags = DF_RENDER_REFRACTION | DF_CLIP_Z |
  4784. DF_RENDER_UNDERWATER | DF_FUDGE_UP |
  4785. DF_DRAW_ENTITITES ;
  4786. }
  4787. //-----------------------------------------------------------------------------
  4788. //
  4789. //-----------------------------------------------------------------------------
  4790. void CAboveWaterView::CRefractionView::Draw()
  4791. {
  4792. #ifdef PORTAL
  4793. g_pPortalRender->WaterRenderingHandler_PreRefraction();
  4794. #endif
  4795. // Store off view origin and angles and set the new view
  4796. int nSaveViewID = CurrentViewID();
  4797. SetupCurrentView( origin, angles, VIEW_REFRACTION );
  4798. DrawSetup( GetOuter()->m_waterHeight, m_DrawFlags, GetOuter()->m_waterZAdjust );
  4799. SetFogVolumeState( GetOuter()->m_fogInfo, true );
  4800. SetClearColorToFogColor();
  4801. DrawExecute( GetOuter()->m_waterHeight, VIEW_REFRACTION, GetOuter()->m_waterZAdjust );
  4802. #ifdef PORTAL
  4803. // deal with stencil
  4804. g_pPortalRender->WaterRenderingHandler_PostRefraction();
  4805. #endif
  4806. // finish off the view. restore the previous view.
  4807. SetupCurrentView( origin, angles, ( view_id_t )nSaveViewID );
  4808. // This is here for multithreading
  4809. CMatRenderContextPtr pRenderContext( materials );
  4810. pRenderContext->ClearColor4ub( 0, 0, 0, 255 );
  4811. pRenderContext->Flush();
  4812. }
  4813. //-----------------------------------------------------------------------------
  4814. //
  4815. //-----------------------------------------------------------------------------
  4816. void CAboveWaterView::CIntersectionView::Setup()
  4817. {
  4818. BaseClass::Setup( *GetOuter() );
  4819. m_DrawFlags = DF_RENDER_UNDERWATER | DF_CLIP_Z | DF_DRAW_ENTITITES;
  4820. }
  4821. //-----------------------------------------------------------------------------
  4822. //
  4823. //-----------------------------------------------------------------------------
  4824. void CAboveWaterView::CIntersectionView::Draw()
  4825. {
  4826. DrawSetup( GetOuter()->m_fogInfo.m_flWaterHeight, m_DrawFlags, 0 );
  4827. SetFogVolumeState( GetOuter()->m_fogInfo, true );
  4828. SetClearColorToFogColor( );
  4829. DrawExecute( GetOuter()->m_fogInfo.m_flWaterHeight, VIEW_NONE, 0 );
  4830. CMatRenderContextPtr pRenderContext( materials );
  4831. pRenderContext->ClearColor4ub( 0, 0, 0, 255 );
  4832. }
  4833. //-----------------------------------------------------------------------------
  4834. // Draws the scene when the view point is under the level of the water
  4835. //-----------------------------------------------------------------------------
  4836. void CUnderWaterView::Setup( const CViewSetup &underView, bool bDrawSkybox, const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t& waterInfo )
  4837. {
  4838. BaseClass::Setup( underView );
  4839. m_bSoftwareUserClipPlane = g_pMaterialSystemHardwareConfig->UseFastClipping();
  4840. CalcWaterEyeAdjustments( fogInfo, m_waterHeight, m_waterZAdjust, m_bSoftwareUserClipPlane );
  4841. IMaterial *pWaterMaterial = fogInfo.m_pFogVolumeMaterial;
  4842. if (engine->GetDXSupportLevel() >= 90 ) // screen voerlays underwater are a dx9 feature
  4843. {
  4844. IMaterialVar *pScreenOverlayVar = pWaterMaterial->FindVar( "$underwateroverlay", NULL, false );
  4845. if ( pScreenOverlayVar && ( pScreenOverlayVar->IsDefined() ) )
  4846. {
  4847. char const *pOverlayName = pScreenOverlayVar->GetStringValue();
  4848. if ( pOverlayName[0] != '0' ) // fixme!!!
  4849. {
  4850. IMaterial *pOverlayMaterial = materials->FindMaterial( pOverlayName, TEXTURE_GROUP_OTHER );
  4851. m_pMainView->SetWaterOverlayMaterial( pOverlayMaterial );
  4852. }
  4853. }
  4854. }
  4855. // NOTE: We're not drawing the 2d skybox under water since it's assumed to not be visible.
  4856. // render the world underwater
  4857. // Clear the color to get the appropriate underwater fog color
  4858. m_DrawFlags = DF_FUDGE_UP | DF_RENDER_UNDERWATER | DF_DRAW_ENTITITES;
  4859. m_ClearFlags = VIEW_CLEAR_DEPTH;
  4860. if( !m_bSoftwareUserClipPlane )
  4861. {
  4862. m_DrawFlags |= DF_CLIP_Z;
  4863. }
  4864. if ( waterInfo.m_bDrawWaterSurface )
  4865. {
  4866. m_DrawFlags |= DF_RENDER_WATER;
  4867. }
  4868. if ( !waterInfo.m_bRefract && !waterInfo.m_bOpaqueWater )
  4869. {
  4870. m_DrawFlags |= DF_RENDER_ABOVEWATER;
  4871. }
  4872. m_fogInfo = fogInfo;
  4873. m_waterInfo = waterInfo;
  4874. m_bDrawSkybox = bDrawSkybox;
  4875. }
  4876. //-----------------------------------------------------------------------------
  4877. //
  4878. //-----------------------------------------------------------------------------
  4879. void CUnderWaterView::Draw()
  4880. {
  4881. // FIXME: The 3d skybox shouldn't be drawn when the eye is under water
  4882. VPROF( "CViewRender::ViewDrawScene_EyeUnderWater" );
  4883. CMatRenderContextPtr pRenderContext( materials );
  4884. // render refraction (out of water)
  4885. if ( m_waterInfo.m_bRefract )
  4886. {
  4887. m_RefractionView.Setup( );
  4888. m_pMainView->AddViewToScene( &m_RefractionView );
  4889. }
  4890. if ( !m_waterInfo.m_bRefract )
  4891. {
  4892. SetFogVolumeState( m_fogInfo, true );
  4893. unsigned char ucFogColor[3];
  4894. pRenderContext->GetFogColor( ucFogColor );
  4895. pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 );
  4896. }
  4897. DrawSetup( m_waterHeight, m_DrawFlags, m_waterZAdjust );
  4898. SetFogVolumeState( m_fogInfo, false );
  4899. DrawExecute( m_waterHeight, CurrentViewID(), m_waterZAdjust );
  4900. m_ClearFlags = 0;
  4901. if( m_waterZAdjust != 0.0f && m_bSoftwareUserClipPlane && m_waterInfo.m_bRefract )
  4902. {
  4903. m_SoftwareIntersectionView.Setup( false );
  4904. m_SoftwareIntersectionView.Draw( );
  4905. }
  4906. pRenderContext->ClearColor4ub( 0, 0, 0, 255 );
  4907. }
  4908. //-----------------------------------------------------------------------------
  4909. //
  4910. //-----------------------------------------------------------------------------
  4911. void CUnderWaterView::CRefractionView::Setup()
  4912. {
  4913. BaseClass::Setup( *GetOuter() );
  4914. // NOTE: Refraction renders into the back buffer, over the top of the 3D skybox
  4915. // It is then blitted out into the refraction target. This is so that
  4916. // we only have to set up 3d sky vis once, and only render it once also!
  4917. m_DrawFlags = DF_CLIP_Z |
  4918. DF_CLIP_BELOW | DF_RENDER_ABOVEWATER |
  4919. DF_DRAW_ENTITITES;
  4920. m_ClearFlags = VIEW_CLEAR_DEPTH;
  4921. if ( GetOuter()->m_bDrawSkybox )
  4922. {
  4923. m_ClearFlags |= VIEW_CLEAR_COLOR;
  4924. m_DrawFlags |= DF_DRAWSKYBOX | DF_CLIP_SKYBOX;
  4925. }
  4926. }
  4927. //-----------------------------------------------------------------------------
  4928. //
  4929. //-----------------------------------------------------------------------------
  4930. void CUnderWaterView::CRefractionView::Draw()
  4931. {
  4932. CMatRenderContextPtr pRenderContext( materials );
  4933. SetFogVolumeState( GetOuter()->m_fogInfo, true );
  4934. unsigned char ucFogColor[3];
  4935. pRenderContext->GetFogColor( ucFogColor );
  4936. pRenderContext->ClearColor4ub( ucFogColor[0], ucFogColor[1], ucFogColor[2], 255 );
  4937. DrawSetup( GetOuter()->m_waterHeight, m_DrawFlags, GetOuter()->m_waterZAdjust );
  4938. EnableWorldFog();
  4939. DrawExecute( GetOuter()->m_waterHeight, VIEW_REFRACTION, GetOuter()->m_waterZAdjust );
  4940. Rect_t srcRect;
  4941. srcRect.x = x;
  4942. srcRect.y = y;
  4943. srcRect.width = width;
  4944. srcRect.height = height;
  4945. // Optionally write the rendered image to a debug texture
  4946. if ( g_bDumpRenderTargets )
  4947. {
  4948. DumpTGAofRenderTarget( width, height, "WaterRefract" );
  4949. }
  4950. ITexture *pTexture = GetWaterRefractionTexture();
  4951. pRenderContext->CopyRenderTargetToTextureEx( pTexture, 0, &srcRect, NULL );
  4952. }
  4953. //-----------------------------------------------------------------------------
  4954. //
  4955. // Reflective glass view starts here
  4956. //
  4957. //-----------------------------------------------------------------------------
  4958. //-----------------------------------------------------------------------------
  4959. // Draws the scene when the view contains reflective glass
  4960. //-----------------------------------------------------------------------------
  4961. void CReflectiveGlassView::Setup( const CViewSetup &viewRender, int nClearFlags, bool bDrawSkybox,
  4962. const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane )
  4963. {
  4964. BaseClass::Setup( viewRender, nClearFlags, bDrawSkybox, fogInfo, waterInfo, NULL );
  4965. m_ReflectionPlane = reflectionPlane;
  4966. }
  4967. bool CReflectiveGlassView::AdjustView( float flWaterHeight )
  4968. {
  4969. ITexture *pTexture = GetWaterReflectionTexture();
  4970. // Use the aspect ratio of the main view! So, don't recompute it here
  4971. x = y = 0;
  4972. width = pTexture->GetActualWidth();
  4973. height = pTexture->GetActualHeight();
  4974. // Reflect the camera origin + vectors around the reflection plane
  4975. float flDist = DotProduct( origin, m_ReflectionPlane.normal ) - m_ReflectionPlane.dist;
  4976. VectorMA( origin, - 2.0f * flDist, m_ReflectionPlane.normal, origin );
  4977. Vector vecForward, vecUp;
  4978. AngleVectors( angles, &vecForward, NULL, &vecUp );
  4979. float flDot = DotProduct( vecForward, m_ReflectionPlane.normal );
  4980. VectorMA( vecForward, - 2.0f * flDot, m_ReflectionPlane.normal, vecForward );
  4981. flDot = DotProduct( vecUp, m_ReflectionPlane.normal );
  4982. VectorMA( vecUp, - 2.0f * flDot, m_ReflectionPlane.normal, vecUp );
  4983. VectorAngles( vecForward, vecUp, angles );
  4984. return true;
  4985. }
  4986. void CReflectiveGlassView::PushView( float waterHeight )
  4987. {
  4988. render->Push3DView( *this, m_ClearFlags, GetWaterReflectionTexture(), GetFrustum() );
  4989. Vector4D plane;
  4990. VectorCopy( m_ReflectionPlane.normal, plane.AsVector3D() );
  4991. plane.w = m_ReflectionPlane.dist + 0.1f;
  4992. CMatRenderContextPtr pRenderContext( materials );
  4993. pRenderContext->PushCustomClipPlane( plane.Base() );
  4994. }
  4995. void CReflectiveGlassView::PopView( )
  4996. {
  4997. CMatRenderContextPtr pRenderContext( materials );
  4998. pRenderContext->PopCustomClipPlane( );
  4999. render->PopView( GetFrustum() );
  5000. }
  5001. //-----------------------------------------------------------------------------
  5002. // Renders reflective or refractive parts of glass
  5003. //-----------------------------------------------------------------------------
  5004. void CReflectiveGlassView::Draw()
  5005. {
  5006. VPROF( "CReflectiveGlassView::Draw" );
  5007. CMatRenderContextPtr pRenderContext( materials );
  5008. PIXEVENT( pRenderContext, "CReflectiveGlassView::Draw" );
  5009. // Disable occlusion visualization in reflection
  5010. bool bVisOcclusion = r_visocclusion.GetInt();
  5011. r_visocclusion.SetValue( 0 );
  5012. BaseClass::Draw();
  5013. r_visocclusion.SetValue( bVisOcclusion );
  5014. pRenderContext->ClearColor4ub( 0, 0, 0, 255 );
  5015. pRenderContext->Flush();
  5016. }
  5017. //-----------------------------------------------------------------------------
  5018. // Draws the scene when the view contains reflective glass
  5019. //-----------------------------------------------------------------------------
  5020. void CRefractiveGlassView::Setup( const CViewSetup &viewRender, int nClearFlags, bool bDrawSkybox,
  5021. const VisibleFogVolumeInfo_t &fogInfo, const WaterRenderInfo_t &waterInfo, const cplane_t &reflectionPlane )
  5022. {
  5023. BaseClass::Setup( viewRender, nClearFlags, bDrawSkybox, fogInfo, waterInfo, NULL );
  5024. m_ReflectionPlane = reflectionPlane;
  5025. }
  5026. bool CRefractiveGlassView::AdjustView( float flWaterHeight )
  5027. {
  5028. ITexture *pTexture = GetWaterRefractionTexture();
  5029. // Use the aspect ratio of the main view! So, don't recompute it here
  5030. x = y = 0;
  5031. width = pTexture->GetActualWidth();
  5032. height = pTexture->GetActualHeight();
  5033. return true;
  5034. }
  5035. void CRefractiveGlassView::PushView( float waterHeight )
  5036. {
  5037. render->Push3DView( *this, m_ClearFlags, GetWaterRefractionTexture(), GetFrustum() );
  5038. Vector4D plane;
  5039. VectorMultiply( m_ReflectionPlane.normal, -1, plane.AsVector3D() );
  5040. plane.w = -m_ReflectionPlane.dist + 0.1f;
  5041. CMatRenderContextPtr pRenderContext( materials );
  5042. pRenderContext->PushCustomClipPlane( plane.Base() );
  5043. }
  5044. void CRefractiveGlassView::PopView( )
  5045. {
  5046. CMatRenderContextPtr pRenderContext( materials );
  5047. pRenderContext->PopCustomClipPlane( );
  5048. render->PopView( GetFrustum() );
  5049. }
  5050. //-----------------------------------------------------------------------------
  5051. // Renders reflective or refractive parts of glass
  5052. //-----------------------------------------------------------------------------
  5053. void CRefractiveGlassView::Draw()
  5054. {
  5055. VPROF( "CRefractiveGlassView::Draw" );
  5056. CMatRenderContextPtr pRenderContext( materials );
  5057. PIXEVENT( pRenderContext, "CRefractiveGlassView::Draw" );
  5058. BaseClass::Draw();
  5059. pRenderContext->ClearColor4ub( 0, 0, 0, 255 );
  5060. pRenderContext->Flush();
  5061. }