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.

1254 lines
38 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "render_pch.h"
  9. #include "client.h"
  10. #include "sound.h"
  11. #include "debug_leafvis.h"
  12. #include "cdll_int.h"
  13. #include "enginestats.h"
  14. #include "ivrenderview.h"
  15. #include "studio.h"
  16. #include "l_studio.h"
  17. #include "r_areaportal.h"
  18. #include "materialsystem/materialsystem_config.h"
  19. #include "materialsystem/itexture.h"
  20. #include "cdll_engine_int.h"
  21. #include "materialsystem/imaterialsystemhardwareconfig.h"
  22. #include "istudiorender.h"
  23. #include "staticpropmgr.h"
  24. #include "tier0/vprof.h"
  25. #include "IOcclusionSystem.h"
  26. #include "con_nprint.h"
  27. #include "debugoverlay.h"
  28. #include "demo.h"
  29. #include "ivideomode.h"
  30. #include "sys_dll.h"
  31. #include "collisionutils.h"
  32. #include "tier1/utlstack.h"
  33. #include "r_decal.h"
  34. #include "cl_main.h"
  35. // memdbgon must be the last include file in a .cpp file!!!
  36. #include "tier0/memdbgon.h"
  37. #ifndef _X360
  38. extern ConVar r_waterforceexpensive;
  39. #endif
  40. ConVar r_aspectratio( "r_aspectratio", "0"
  41. #if !defined( _X360 )
  42. , FCVAR_CHEAT
  43. #endif
  44. );
  45. ConVar r_dynamiclighting( "r_dynamiclighting", "1", FCVAR_CHEAT );
  46. extern ConVar building_cubemaps;
  47. extern float scr_demo_override_fov;
  48. extern colorVec R_LightPoint (Vector& p);
  49. CEngineStats g_EngineStats;
  50. //-----------------------------------------------------------------------------
  51. // view origin
  52. //-----------------------------------------------------------------------------
  53. extern Vector g_CurrentViewOrigin, g_CurrentViewForward, g_CurrentViewRight, g_CurrentViewUp;
  54. extern Vector g_MainViewOrigin, g_MainViewForward, g_MainViewRight, g_MainViewUp;
  55. bool g_bCanAccessCurrentView = false;
  56. int d_lightstyleframe[256];
  57. void ProjectPointOnPlane( Vector& dst, const Vector& p, const Vector& normal )
  58. {
  59. float d;
  60. Vector n;
  61. float inv_denom;
  62. inv_denom = 1.0F / DotProduct( normal, normal );
  63. d = DotProduct( normal, p ) * inv_denom;
  64. n[0] = normal[0] * inv_denom;
  65. n[1] = normal[1] * inv_denom;
  66. n[2] = normal[2] * inv_denom;
  67. dst[0] = p[0] - d * n[0];
  68. dst[1] = p[1] - d * n[1];
  69. dst[2] = p[2] - d * n[2];
  70. }
  71. /*
  72. ** assumes "src" is normalized
  73. */
  74. void PerpendicularVector( Vector& dst, const Vector& src )
  75. {
  76. int pos;
  77. int i;
  78. float minelem = 1.0F;
  79. Vector tempvec;
  80. /*
  81. ** find the smallest magnitude axially aligned vector
  82. */
  83. for ( pos = 0, i = 0; i < 3; i++ )
  84. {
  85. if ( fabs( src[i] ) < minelem )
  86. {
  87. pos = i;
  88. minelem = fabs( src[i] );
  89. }
  90. }
  91. tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
  92. tempvec[pos] = 1.0F;
  93. /*
  94. ** project the point onto the plane defined by src
  95. */
  96. ProjectPointOnPlane( dst, tempvec, src );
  97. /*
  98. ** normalize the result
  99. */
  100. VectorNormalize( dst );
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Returns the aspect ratio of the screen
  104. //-----------------------------------------------------------------------------
  105. float GetScreenAspect( )
  106. {
  107. // use the override if set
  108. if ( r_aspectratio.GetFloat() > 0.0f )
  109. return r_aspectratio.GetFloat();
  110. // mikesart: This is just sticking in unnecessary BeginRender/EndRender calls to the queue.
  111. // CMatRenderContextPtr pRenderContext( materials );
  112. IMatRenderContext *pRenderContext = g_pMaterialSystem->GetRenderContext();
  113. int width, height;
  114. pRenderContext->GetRenderTargetDimensions( width, height );
  115. return (height != 0) ? ( (float)width / (float)height ) : 1.0f;
  116. }
  117. /*
  118. ====================
  119. CalcFov
  120. ====================
  121. */
  122. void R_DrawScreenRect( float left, float top, float right, float bottom )
  123. {
  124. CMatRenderContextPtr pRenderContext( materials );
  125. pRenderContext->MatrixMode( MATERIAL_VIEW );
  126. pRenderContext->PushMatrix();
  127. pRenderContext->LoadIdentity();
  128. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  129. pRenderContext->PushMatrix();
  130. pRenderContext->LoadIdentity();
  131. IMaterial *pMaterial = materials->FindMaterial( "debug/debugportals", TEXTURE_GROUP_OTHER );
  132. IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial );
  133. CMeshBuilder builder;
  134. builder.Begin( pMesh, MATERIAL_LINE_LOOP, 4 );
  135. Vector v1( left, bottom, 0.5 );
  136. Vector v2( left, top, 0.5 );
  137. Vector v3( right, top, 0.5 );
  138. Vector v4( right, bottom, 0.5 );
  139. builder.Position3fv( v1.Base() ); builder.AdvanceVertex();
  140. builder.Position3fv( v2.Base() ); builder.AdvanceVertex();
  141. builder.Position3fv( v3.Base() ); builder.AdvanceVertex();
  142. builder.Position3fv( v4.Base() ); builder.AdvanceVertex();
  143. builder.End( false, true );
  144. pRenderContext->MatrixMode( MATERIAL_VIEW );
  145. pRenderContext->PopMatrix();
  146. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  147. pRenderContext->PopMatrix();
  148. }
  149. void R_DrawPortals()
  150. {
  151. // Draw the portals.
  152. if( !r_DrawPortals.GetInt() )
  153. return;
  154. IMaterial *pMaterial = materials->FindMaterial( "debug/debugportals", TEXTURE_GROUP_OTHER );
  155. CMatRenderContextPtr pRenderContext( materials );
  156. IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial );
  157. worldbrushdata_t *pBrushData = host_state.worldbrush;
  158. for( int i=0; i < pBrushData->m_nAreaPortals; i++ )
  159. {
  160. dareaportal_t *pAreaPortal = &pBrushData->m_pAreaPortals[i];
  161. if( !R_IsAreaVisible( pAreaPortal->otherarea ) )
  162. continue;
  163. CMeshBuilder builder;
  164. builder.Begin( pMesh, MATERIAL_LINES, pAreaPortal->m_nClipPortalVerts );
  165. for( int j=0; j < pAreaPortal->m_nClipPortalVerts; j++ )
  166. {
  167. unsigned short iVert;
  168. iVert = pAreaPortal->m_FirstClipPortalVert + j;
  169. builder.Position3f( VectorExpand( pBrushData->m_pClipPortalVerts[iVert] ) );
  170. builder.Color4f( 0, 0, 0, 1 );
  171. builder.AdvanceVertex();
  172. iVert = pAreaPortal->m_FirstClipPortalVert + (j+1) % pAreaPortal->m_nClipPortalVerts;
  173. builder.Position3f( VectorExpand( pBrushData->m_pClipPortalVerts[iVert] ) );
  174. builder.Color4f( 0, 0, 0, 1 );
  175. builder.AdvanceVertex();
  176. }
  177. builder.End( false, true );
  178. }
  179. // Draw the clip rectangles.
  180. for( int i=0; i < g_PortalRects.Size(); i++ )
  181. {
  182. CPortalRect *pRect = &g_PortalRects[i];
  183. R_DrawScreenRect( pRect->left, pRect->top, pRect->right, pRect->bottom );
  184. }
  185. g_PortalRects.Purge();
  186. }
  187. //-----------------------------------------------------------------------------
  188. //
  189. // Loose collection of functions related to rendering the world in a particular view
  190. //
  191. //-----------------------------------------------------------------------------
  192. class CRender : public IRender
  193. {
  194. public:
  195. CRender();
  196. void FrameBegin( void );
  197. void FrameEnd( void );
  198. void ViewSetupVis( bool novis, int numorigins, const Vector origin[] );
  199. void ViewSetupVisEx( bool novis, int numorigins, const Vector origin[], unsigned int &returnFlags );
  200. void ViewEnd( void );
  201. void ViewDrawFade( byte *color, IMaterial* pMaterial );
  202. IWorldRenderList * CreateWorldList();
  203. void BuildWorldLists( IWorldRenderList *pList, WorldListInfo_t* pInfo, int iForceViewLeaf, const VisOverrideData_t* pVisData, bool bShadowDepth, float *pWaterReflectionHeight );
  204. void DrawWorldLists( IWorldRenderList *pList, unsigned long flags, float waterZAdjust );
  205. void DrawSceneBegin( void );
  206. void DrawSceneEnd( void );
  207. // utility functions
  208. void ExtractMatrices( void );
  209. void ExtractFrustumPlanes( Frustum frustumPlanes );
  210. void OrthoExtractFrustumPlanes( Frustum frustumPlanes );
  211. void OverrideViewFrustum( Frustum custom );
  212. void SetViewport( int x, int y, int w, int h );
  213. // UNDONE: these are temporary functions that will end up on the other
  214. // side of this interface
  215. const Vector &ViewOrigin( ) { return CurrentView().origin; }
  216. const QAngle &ViewAngles( ) { return CurrentView().angles; }
  217. const CViewSetup &ViewGetCurrent( void ) { return CurrentView(); }
  218. const VMatrix &ViewMatrix( void );
  219. const VMatrix &WorldToScreenMatrix( void );
  220. float GetFramerate( void ) { return m_framerate; }
  221. virtual float GetZNear( void ) { return m_zNear; }
  222. virtual float GetZFar( void ) { return m_zFar; }
  223. // Query current fov and view model fov
  224. float GetFov( void ) { return CurrentView().fov; };
  225. float GetFovY( void ) { return m_yFOV; };
  226. float GetFovViewmodel( void ) { return CurrentView().fovViewmodel; };
  227. virtual bool ClipTransformWithProjection ( const VMatrix& worldToScreen, const Vector& point, Vector* pClip );
  228. virtual bool ClipTransform( const Vector& point, Vector* pClip );
  229. virtual bool ScreenTransform( const Vector& point, Vector* pScreen );
  230. virtual void Push3DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes );
  231. virtual void Push3DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes, ITexture* pDepthTexture );
  232. virtual void Push2DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes );
  233. virtual void PopView( Frustum frustumPlanes );
  234. virtual void SetMainView( const Vector &vecOrigin, const QAngle &angles );
  235. virtual void UpdateBrushModelLightmap( model_t *model, IClientRenderable *Renderable );
  236. virtual void BeginUpdateLightmaps( void );
  237. virtual void EndUpdateLightmaps( void );
  238. virtual bool InLightmapUpdate( void ) const;
  239. private:
  240. // Called when a particular view becomes active
  241. void OnViewActive( Frustum frustumPlanes );
  242. // Clear the view (assumes the render target has already been pushed)
  243. void ClearView( CViewSetup &view, int nFlags, ITexture* pRenderTarget, ITexture* pDepthTexture = NULL );
  244. const CViewSetup &CurrentView() const { return m_ViewStack.Top().m_View; }
  245. CViewSetup &CurrentView() { return m_ViewStack.Top().m_View; }
  246. // Stack of view info
  247. struct ViewStack_t
  248. {
  249. CViewSetup m_View;
  250. // matrices
  251. VMatrix m_matrixView;
  252. VMatrix m_matrixProjection;
  253. VMatrix m_matrixWorldToScreen;
  254. bool m_bIs2DView;
  255. bool m_bNoDraw;
  256. };
  257. // Y field of view, calculated from X FOV and screen aspect ratio.
  258. float m_yFOV;
  259. // timing
  260. double m_frameStartTime;
  261. float m_framerate;
  262. float m_zNear;
  263. float m_zFar;
  264. // matrices
  265. VMatrix m_matrixView;
  266. VMatrix m_matrixProjection;
  267. VMatrix m_matrixWorldToScreen;
  268. CUtlStack< ViewStack_t > m_ViewStack;
  269. int m_iLightmapUpdateDepth;
  270. };
  271. //-----------------------------------------------------------------------------
  272. // Singleton
  273. //-----------------------------------------------------------------------------
  274. static CRender gRender;
  275. IRender *g_EngineRenderer = &gRender;
  276. //-----------------------------------------------------------------------------
  277. // Called when the engine is about to begin rendering for any reason
  278. //-----------------------------------------------------------------------------
  279. CRender::CRender()
  280. {
  281. // Make sure the stack isn't empty
  282. int i = m_ViewStack.Push();
  283. memset( &m_ViewStack[i], 0, sizeof( CViewSetup ) );
  284. m_ViewStack[i].m_bIs2DView = true;
  285. m_iLightmapUpdateDepth = 0;
  286. }
  287. //-----------------------------------------------------------------------------
  288. // Called when the engine is about to begin rendering for any reason
  289. //-----------------------------------------------------------------------------
  290. void CRender::FrameBegin( void )
  291. {
  292. if ( host_state.worldmodel )
  293. {
  294. // This has to be before R_AnimateLight because it uses it to
  295. // set the frame number of changed lightstyles
  296. // FIXME: Why isn't this being done in DrawSceneBegin
  297. // or some other client-side simulation of state?
  298. r_framecount++;
  299. R_AnimateLight ();
  300. R_PushDlights();
  301. if (!r_norefresh.GetInt())
  302. {
  303. m_frameStartTime = Sys_FloatTime ();
  304. }
  305. }
  306. UpdateStudioRenderConfig();
  307. g_pStudioRender->BeginFrame();
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Called when the engine has finished rendering
  311. //-----------------------------------------------------------------------------
  312. void CRender::FrameEnd( void )
  313. {
  314. // A debugging overlay that renders all raycasts.
  315. // Why, or why is this being done here instead of
  316. // where all the other debug overlays are being done in the client DLL?
  317. EngineTraceRenderRayCasts();
  318. m_framerate = cl.GetFrameTime();
  319. if ( m_framerate > 0 )
  320. {
  321. m_framerate = 1 / m_framerate;
  322. }
  323. g_pStudioRender->EndFrame();
  324. }
  325. const VMatrix &CRender::ViewMatrix( )
  326. {
  327. // If we aren't in a valid view, then use the last value cached off into the global variable instead
  328. if ( m_ViewStack.Count() > 1 )
  329. {
  330. return m_ViewStack.Top().m_matrixView;
  331. }
  332. return m_matrixView;
  333. }
  334. const VMatrix &CRender::WorldToScreenMatrix( void )
  335. {
  336. // If we aren't in a valid view, then use the last value cached off into the global variable instead
  337. if ( m_ViewStack.Count() > 1 )
  338. {
  339. return m_ViewStack.Top().m_matrixWorldToScreen;
  340. }
  341. return m_matrixWorldToScreen;
  342. }
  343. void CRender::ViewSetupVis( bool novis, int numorigins, const Vector origin[] )
  344. {
  345. unsigned int returnFlags = 0;
  346. ViewSetupVisEx( novis, numorigins, origin, returnFlags );
  347. }
  348. void CRender::ViewSetupVisEx( bool novis, int numorigins, const Vector origin[], unsigned int &returnFlags )
  349. {
  350. Map_VisSetup( host_state.worldmodel, numorigins, origin, novis, returnFlags );
  351. }
  352. //-----------------------------------------------------------------------------
  353. // Called when a particular view becomes active
  354. //-----------------------------------------------------------------------------
  355. void CRender::OnViewActive( Frustum frustumPlanes )
  356. {
  357. const CViewSetup &view = CurrentView();
  358. m_yFOV = CalcFovY( view.fov, view.m_flAspectRatio );
  359. // build the transformation matrix for the given view angles
  360. VectorCopy( view.origin, g_CurrentViewOrigin );
  361. AngleVectors( view.angles, &g_CurrentViewForward, &g_CurrentViewRight, &g_CurrentViewUp );
  362. // g_CurrentViewUp = -g_CurrentViewUp;
  363. g_bCanAccessCurrentView = true;
  364. if ( frustumPlanes )
  365. {
  366. if ( view.m_bOrtho )
  367. {
  368. OrthoExtractFrustumPlanes( frustumPlanes );
  369. }
  370. else
  371. {
  372. ExtractFrustumPlanes( frustumPlanes );
  373. }
  374. OcclusionSystem()->SetView( view.origin, view.fov, m_matrixView, m_matrixProjection, frustumPlanes[ FRUSTUM_NEARZ ] );
  375. }
  376. if ( !m_ViewStack.Top().m_bNoDraw )
  377. {
  378. R_SceneBegin( );
  379. }
  380. // debug, build leaf volume
  381. // NOTE: This is pretty hacky, but I want the leaf based on the main view. The skybox view is reseting
  382. // the g_LeafVis here because it is global. This need to be resolved more correctly some other way!
  383. if ( VectorCompare( g_MainViewOrigin, view.origin ) )
  384. {
  385. LeafVisBuild( view.origin );
  386. }
  387. }
  388. //-----------------------------------------------------------------------------
  389. // Clear the view (assumes the render target has already been pushed)
  390. //-----------------------------------------------------------------------------
  391. void CRender::ClearView( CViewSetup &view, int nFlags, ITexture* pRenderTarget, ITexture* pDepthTexture /* = NULL */ )
  392. {
  393. bool bClearColor = (nFlags & VIEW_CLEAR_COLOR) != 0;
  394. bool bClearDepth = (nFlags & VIEW_CLEAR_DEPTH) != 0;
  395. bool bClearStencil = (nFlags & VIEW_CLEAR_STENCIL) != 0;
  396. bool bForceClearWholeRenderTarget = (nFlags & VIEW_CLEAR_FULL_TARGET) != 0;
  397. bool bObeyStencil = (nFlags & VIEW_CLEAR_OBEY_STENCIL) != 0;
  398. // Handle an initial clear request if asked for
  399. if ( !bClearColor && !bClearDepth && !bClearStencil )
  400. return;
  401. CMatRenderContextPtr pRenderContext( materials );
  402. if ( !bForceClearWholeRenderTarget )
  403. {
  404. if( bObeyStencil )
  405. pRenderContext->ClearBuffersObeyStencil( bClearColor, bClearDepth );
  406. else
  407. pRenderContext->ClearBuffers( bClearColor, bClearDepth, bClearStencil );
  408. }
  409. else
  410. {
  411. // Get the render target dimensions
  412. int nWidth, nHeight;
  413. if ( pRenderTarget )
  414. {
  415. nWidth = pRenderTarget->GetActualWidth();
  416. nHeight = pRenderTarget->GetActualHeight();
  417. }
  418. else
  419. {
  420. materials->GetBackBufferDimensions( nWidth, nHeight );
  421. }
  422. pRenderContext->PushRenderTargetAndViewport( pRenderTarget, pDepthTexture, 0, 0, nWidth, nHeight );
  423. if( bObeyStencil )
  424. pRenderContext->ClearBuffersObeyStencil( bClearColor, bClearDepth );
  425. else
  426. pRenderContext->ClearBuffers( bClearColor, bClearDepth, bClearStencil );
  427. pRenderContext->PopRenderTargetAndViewport( );
  428. }
  429. }
  430. //-----------------------------------------------------------------------------
  431. // Push, pop views
  432. //-----------------------------------------------------------------------------
  433. void CRender::Push3DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes )
  434. {
  435. Push3DView( view, nFlags, pRenderTarget, frustumPlanes, NULL );
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Computes view matrices
  439. //-----------------------------------------------------------------------------
  440. float ComputeViewMatrices( VMatrix *pWorldToView, VMatrix *pViewToProjection, VMatrix *pWorldToProjection, const CViewSetup &viewSetup )
  441. {
  442. float flAspectRatio = viewSetup.m_flAspectRatio;
  443. if ( flAspectRatio == 0.0f )
  444. {
  445. flAspectRatio = (viewSetup.height != 0) ? ( (float)viewSetup.width / (float)viewSetup.height ) : 1.0f;
  446. }
  447. ComputeViewMatrix( pWorldToView, viewSetup.origin, viewSetup.angles );
  448. if ( viewSetup.m_bOrtho )
  449. {
  450. MatrixBuildOrtho( *pViewToProjection, viewSetup.m_OrthoLeft, viewSetup.m_OrthoTop,
  451. viewSetup.m_OrthoRight, viewSetup.m_OrthoBottom, viewSetup.zNear, viewSetup.zFar );
  452. }
  453. else if ( viewSetup.m_bOffCenter ) // Off-center projection, useful for AA jitter and tiled output of posters
  454. {
  455. MatrixBuildPerspectiveOffCenterX( *pViewToProjection, viewSetup.fov, flAspectRatio,
  456. viewSetup.zNear, viewSetup.zFar, viewSetup.m_flOffCenterBottom, viewSetup.m_flOffCenterTop,
  457. viewSetup.m_flOffCenterLeft, viewSetup.m_flOffCenterRight );
  458. }
  459. else if ( viewSetup.m_bViewToProjectionOverride )
  460. {
  461. *pViewToProjection = viewSetup.m_ViewToProjection;
  462. // ...but then override the Z range (needed for correct skybox rendering, etc).
  463. MatrixBuildPerspectiveZRange ( *pViewToProjection, viewSetup.zNear, viewSetup.zFar );
  464. }
  465. else
  466. {
  467. MatrixBuildPerspectiveX( *pViewToProjection, viewSetup.fov, flAspectRatio, viewSetup.zNear, viewSetup.zFar );
  468. }
  469. MatrixMultiply( *pViewToProjection, *pWorldToView, *pWorldToProjection );
  470. return flAspectRatio;
  471. }
  472. // Flip y, screen y goes down
  473. static VMatrix g_ProjectionToOffset( 0.5f, 0.0f, 0.0f, 0.5f,
  474. 0.0f, -0.5f, 0.0f, 0.5f,
  475. 0.0f, 0.0f, 1.0f, 0.0f,
  476. 0.0f, 0.0f, 0.0f, 1.0f );
  477. // NOTE: Screen coordinates go from 0->w, 0->h
  478. void ComputeWorldToScreenMatrix( VMatrix *pWorldToScreen, const VMatrix &worldToProjection, const CViewSetup &viewSetup )
  479. {
  480. // First need to transform -1 -> 1 to 0 -> 1 in x and y
  481. // Then transform from 0->1 to x->w+x in x, and 0->1 to y->y+h in y.
  482. VMatrix offsetToPixels( viewSetup.width, 0.0f, 0.0f, viewSetup.x,
  483. 0.0f, viewSetup.height, 0.0f, viewSetup.y,
  484. 0.0f, 0.0f, 1.0f, 0.0f,
  485. 0.0f, 0.0f, 0.0f, 1.0f );
  486. VMatrix projectionToPixels;
  487. MatrixMultiply( offsetToPixels, g_ProjectionToOffset, projectionToPixels );
  488. MatrixMultiply( projectionToPixels, worldToProjection, *pWorldToScreen );
  489. }
  490. //-----------------------------------------------------------------------------
  491. // Push, pop views
  492. //-----------------------------------------------------------------------------
  493. void CRender::Push3DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes, ITexture* pDepthTexture )
  494. {
  495. Assert( !IsX360() || (pDepthTexture == NULL) ); //Don't render to a depth texture on the 360. Instead, render using a normal depth buffer and use IDirect3DDevice9::Resolve()
  496. int i = m_ViewStack.Push( );
  497. m_ViewStack[i].m_View = view;
  498. m_ViewStack[i].m_bIs2DView = false;
  499. m_ViewStack[i].m_bNoDraw = ( ( nFlags & VIEW_NO_DRAW ) != 0 );
  500. CViewSetup &topView = m_ViewStack[i].m_View;
  501. // Compute aspect ratio if asked for
  502. if ( topView.m_flAspectRatio == 0.0f )
  503. {
  504. topView.m_flAspectRatio = (topView.height != 0) ? ( (float)topView.width / (float)topView.height ) : 1.0f;
  505. }
  506. ViewStack_t &viewStack = m_ViewStack.Top();
  507. topView.m_flAspectRatio = ComputeViewMatrices( &viewStack.m_matrixView,
  508. &viewStack.m_matrixProjection, &viewStack.m_matrixWorldToScreen, topView );
  509. m_zNear = topView.zNear;
  510. m_zFar = topView.zFar; // cache this for queries
  511. ExtractMatrices();
  512. if ( !m_ViewStack[i].m_bNoDraw )
  513. {
  514. CMatRenderContextPtr pRenderContext( materials );
  515. if ( !pRenderTarget )
  516. {
  517. pRenderTarget = pRenderContext->GetRenderTarget();
  518. }
  519. // Push render target and viewport
  520. pRenderContext->PushRenderTargetAndViewport( pRenderTarget, pDepthTexture, topView.x, topView.y, topView.width, topView.height );
  521. // Handle an initial clear request if asked for
  522. ClearView( topView, nFlags, pRenderTarget, pDepthTexture );
  523. pRenderContext->DepthRange( 0, 1 );
  524. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  525. pRenderContext->PushMatrix();
  526. pRenderContext->LoadMatrix( m_matrixProjection );
  527. pRenderContext->MatrixMode( MATERIAL_VIEW );
  528. pRenderContext->PushMatrix();
  529. pRenderContext->LoadMatrix( m_matrixView );
  530. pRenderContext->MatrixMode( MATERIAL_MODEL );
  531. pRenderContext->PushMatrix();
  532. OnViewActive( frustumPlanes );
  533. }
  534. }
  535. void CRender::Push2DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes )
  536. {
  537. int i = m_ViewStack.Push( );
  538. m_ViewStack[i].m_View = view;
  539. m_ViewStack[i].m_bIs2DView = true;
  540. m_ViewStack[i].m_bNoDraw = ( ( nFlags & VIEW_NO_DRAW ) != 0 );
  541. m_ViewStack[i].m_matrixView = m_matrixView;
  542. m_ViewStack[i].m_matrixProjection = m_matrixProjection;
  543. m_ViewStack[i].m_matrixWorldToScreen = m_matrixWorldToScreen;
  544. CViewSetup &topView = m_ViewStack[i].m_View;
  545. g_bCanAccessCurrentView = false;
  546. CMatRenderContextPtr pRenderContext( materials );
  547. if ( !pRenderContext )
  548. {
  549. pRenderTarget = pRenderContext->GetRenderTarget();
  550. }
  551. // Push render target and viewport
  552. pRenderContext->PushRenderTargetAndViewport( pRenderTarget, topView.x, topView.y, topView.width, topView.height );
  553. // Handle an initial clear request if asked for
  554. ClearView( topView, nFlags, pRenderTarget );
  555. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  556. pRenderContext->PushMatrix();
  557. pRenderContext->LoadIdentity();
  558. pRenderContext->Scale( 1, -1, 1 );
  559. pRenderContext->Ortho( 0, 0, topView.width, topView.height, -99999, 99999 );
  560. pRenderContext->MatrixMode( MATERIAL_VIEW );
  561. pRenderContext->PushMatrix();
  562. pRenderContext->LoadIdentity();
  563. pRenderContext->MatrixMode( MATERIAL_MODEL );
  564. pRenderContext->PushMatrix();
  565. pRenderContext->LoadIdentity();
  566. }
  567. void CRender::PopView( Frustum frustumPlanes )
  568. {
  569. if ( !m_ViewStack.Top().m_bNoDraw )
  570. {
  571. CMatRenderContextPtr pRenderContext( materials );
  572. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  573. pRenderContext->PopMatrix();
  574. pRenderContext->MatrixMode( MATERIAL_VIEW );
  575. pRenderContext->PopMatrix();
  576. pRenderContext->MatrixMode( MATERIAL_MODEL );
  577. pRenderContext->PopMatrix();
  578. pRenderContext->PopRenderTargetAndViewport( );
  579. }
  580. bool bReset = ( m_ViewStack.Count() > 1 ) ? true : false;
  581. m_ViewStack.Pop();
  582. // Don't pop off the very last view
  583. g_bCanAccessCurrentView = false;
  584. if ( bReset )
  585. {
  586. if ( !m_ViewStack.Top().m_bIs2DView )
  587. {
  588. ExtractMatrices();
  589. OnViewActive( frustumPlanes );
  590. }
  591. }
  592. }
  593. //-----------------------------------------------------------------------------
  594. // Sets the main 3D view (for console commands, sound, etc.)
  595. //-----------------------------------------------------------------------------
  596. void CRender::SetMainView( const Vector &vecOrigin, const QAngle &angles )
  597. {
  598. VectorCopy( vecOrigin, g_MainViewOrigin );
  599. AngleVectors( angles, &g_MainViewForward, &g_MainViewRight, &g_MainViewUp );
  600. }
  601. CUtlVector<LightmapUpdateInfo_t> g_LightmapUpdateList;
  602. CUtlVector<LightmapTransformInfo_t> g_LightmapTransformList;
  603. int __cdecl LightmapPageCompareFunc( const void *pElem0, const void *pElem1 )
  604. {
  605. const LightmapUpdateInfo_t *pSurf0 = (const LightmapUpdateInfo_t *)pElem0;
  606. const LightmapUpdateInfo_t *pSurf1 = (const LightmapUpdateInfo_t *)pElem1;
  607. int page0 = materialSortInfoArray[MSurf_MaterialSortID( (pSurf0->m_SurfHandle) )].lightmapPageID;
  608. int page1 = materialSortInfoArray[MSurf_MaterialSortID( (pSurf1->m_SurfHandle) )].lightmapPageID;
  609. return page0 - page1;
  610. }
  611. void CRender::BeginUpdateLightmaps( void )
  612. {
  613. if ( ++m_iLightmapUpdateDepth == 1)
  614. {
  615. Assert( g_LightmapUpdateList.Count() == 0 );
  616. materials->BeginUpdateLightmaps();
  617. // UNDONE: Move this to an init or constructor?
  618. g_LightmapTransformList.RemoveAll();
  619. int index = g_LightmapTransformList.AddToTail();
  620. g_LightmapTransformList[index].pModel = host_state.worldmodel;
  621. SetIdentityMatrix( g_LightmapTransformList[index].xform );
  622. }
  623. }
  624. void CRender::UpdateBrushModelLightmap( model_t *model, IClientRenderable *pRenderable )
  625. {
  626. AssertOnce( m_iLightmapUpdateDepth );
  627. if( !r_drawbrushmodels.GetBool() || !m_iLightmapUpdateDepth )
  628. return;
  629. R_MarkDlightsOnBrushModel( model, pRenderable );
  630. if ( model->flags & MODELFLAG_HAS_DLIGHT )
  631. {
  632. int transformIndex = g_LightmapTransformList.AddToTail();
  633. LightmapTransformInfo_t &transform = g_LightmapTransformList[transformIndex];
  634. transform.pModel = model;
  635. AngleMatrix( pRenderable->GetRenderAngles(), pRenderable->GetRenderOrigin(), transform.xform );
  636. SurfaceHandle_t surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
  637. bool bLight = false;
  638. for (int i=0 ; i<model->brush.nummodelsurfaces ; i++, surfID++)
  639. {
  640. if ( MSurf_Flags(surfID) & (SURFDRAW_HASDLIGHT|SURFDRAW_HASLIGHTSYTLES) )
  641. {
  642. LightmapUpdateInfo_t tmp;
  643. tmp.m_SurfHandle = surfID;
  644. tmp.transformIndex = transformIndex;
  645. g_LightmapUpdateList.AddToTail( tmp );
  646. bLight = true;
  647. }
  648. }
  649. if ( !bLight )
  650. {
  651. model->flags &= ~MODELFLAG_HAS_DLIGHT; // don't need to check again unless a dlight hits us
  652. }
  653. }
  654. }
  655. void CRender::EndUpdateLightmaps( void )
  656. {
  657. Assert( m_iLightmapUpdateDepth > 0 );
  658. if ( --m_iLightmapUpdateDepth == 0 )
  659. {
  660. VPROF_BUDGET( "EndUpdateLightmaps", VPROF_BUDGETGROUP_DLIGHT_RENDERING );
  661. if ( g_LightmapUpdateList.Count() && r_dynamiclighting.GetBool() && !r_unloadlightmaps.GetBool() )
  662. {
  663. CMatRenderContextPtr pRenderContext( materials );
  664. ICallQueue *pCallQueue = pRenderContext->GetCallQueue();
  665. dlight_t *pLights = &cl_dlights[0];
  666. // only do the copy when there are valid dlights to process and threading is on
  667. if ( g_bActiveDlights && pCallQueue )
  668. {
  669. // keep a copy of the current dlight state around for the thread to work on
  670. // in parallel. This way the main thread can continue to modify this state without
  671. // generating any bad results
  672. static dlight_t threadDlights[MAX_DLIGHTS*2];
  673. static int threadFrameCount = 0;
  674. pLights = &threadDlights[MAX_DLIGHTS*threadFrameCount];
  675. Q_memcpy( pLights, cl_dlights, sizeof(dlight_t) * MAX_DLIGHTS );
  676. threadFrameCount = (threadFrameCount+1) & 1;
  677. }
  678. qsort( g_LightmapUpdateList.Base(), g_LightmapUpdateList.Count(), sizeof(g_LightmapUpdateList.Element(0)), LightmapPageCompareFunc );
  679. int i;
  680. for ( i = g_LightmapUpdateList.Count()-1; i >= 0; --i )
  681. {
  682. const LightmapUpdateInfo_t &lightmapUpdateInfo = g_LightmapUpdateList.Element(i);
  683. // a surface can get queued more than once if it's visible in multiple views (e.g. water reflection can do this)
  684. // so check frame to make sure we only recompute once
  685. if ( SurfaceLighting(lightmapUpdateInfo.m_SurfHandle)->m_nLastComputedFrame != r_framecount )
  686. {
  687. R_RenderDynamicLightmaps( pLights, pCallQueue, lightmapUpdateInfo.m_SurfHandle, g_LightmapTransformList[lightmapUpdateInfo.transformIndex].xform );
  688. }
  689. }
  690. }
  691. materials->EndUpdateLightmaps();
  692. g_LightmapUpdateList.RemoveAll();
  693. g_LightmapTransformList.RemoveAll();
  694. }
  695. }
  696. bool CRender::InLightmapUpdate( void ) const
  697. {
  698. return ( m_iLightmapUpdateDepth != 0 );
  699. }
  700. //-----------------------------------------------------------------------------
  701. // Compute the scene coordinates of a point in 3D
  702. //-----------------------------------------------------------------------------
  703. bool CRender::ClipTransformWithProjection ( const VMatrix& worldToScreen, const Vector& point, Vector* pClip )
  704. {
  705. // UNDONE: Clean this up some, handle off-screen vertices
  706. float w;
  707. pClip->x = worldToScreen[0][0] * point[0] + worldToScreen[0][1] * point[1] + worldToScreen[0][2] * point[2] + worldToScreen[0][3];
  708. pClip->y = worldToScreen[1][0] * point[0] + worldToScreen[1][1] * point[1] + worldToScreen[1][2] * point[2] + worldToScreen[1][3];
  709. // z = worldToScreen[2][0] * point[0] + worldToScreen[2][1] * point[1] + worldToScreen[2][2] * point[2] + worldToScreen[2][3];
  710. w = worldToScreen[3][0] * point[0] + worldToScreen[3][1] * point[1] + worldToScreen[3][2] * point[2] + worldToScreen[3][3];
  711. // Just so we have something valid here
  712. pClip->z = 0.0f;
  713. bool behind;
  714. if( w < 0.001f )
  715. {
  716. behind = true;
  717. pClip->x *= 100000;
  718. pClip->y *= 100000;
  719. }
  720. else
  721. {
  722. behind = false;
  723. float invw = 1.0f / w;
  724. pClip->x *= invw;
  725. pClip->y *= invw;
  726. }
  727. return behind;
  728. }
  729. //-----------------------------------------------------------------------------
  730. // Compute the scene coordinates of a point in 3D using the current engine's projection
  731. //-----------------------------------------------------------------------------
  732. bool CRender::ClipTransform ( const Vector& point, Vector* pClip )
  733. {
  734. const VMatrix &worldToScreen = g_EngineRenderer->WorldToScreenMatrix();
  735. return CRender::ClipTransformWithProjection ( worldToScreen, point, pClip );
  736. }
  737. //-----------------------------------------------------------------------------
  738. // Purpose: Given a point, return the screen position in pixels
  739. //-----------------------------------------------------------------------------
  740. bool CRender::ScreenTransform( const Vector& point, Vector* pScreen )
  741. {
  742. bool retval = ClipTransform( point, pScreen );
  743. pScreen->x = 0.5f * ( pScreen->x + 1.0f ) * CurrentView().width + CurrentView().x;
  744. pScreen->y = 0.5f * ( pScreen->y + 1.0f ) * CurrentView().height + CurrentView().y;
  745. return retval;
  746. }
  747. void CRender::ViewDrawFade( byte *color, IMaterial* pFadeMaterial )
  748. {
  749. if ( !color || !color[3] )
  750. return;
  751. if( !pFadeMaterial )
  752. return;
  753. const CViewSetup &view = CurrentView();
  754. CMatRenderContextPtr pRenderContext( materials );
  755. pRenderContext->Bind( pFadeMaterial );
  756. pFadeMaterial->AlphaModulate( color[3] * ( 1.0f / 255.0f ) );
  757. pFadeMaterial->ColorModulate( color[0] * ( 1.0f / 255.0f ),
  758. color[1] * ( 1.0f / 255.0f ),
  759. color[2] * ( 1.0f / 255.0f ) );
  760. bool bOldIgnoreZ = pFadeMaterial->GetMaterialVarFlag( MATERIAL_VAR_IGNOREZ );
  761. pFadeMaterial->SetMaterialVarFlag( MATERIAL_VAR_IGNOREZ, true );
  762. int nTexWidth, nTexHeight;
  763. nTexWidth = pFadeMaterial->GetMappingWidth();
  764. nTexHeight = pFadeMaterial->GetMappingHeight();
  765. float flUOffset = 0.5f / nTexWidth;
  766. float flVOffset = 0.5f / nTexHeight;
  767. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  768. pRenderContext->PushMatrix();
  769. pRenderContext->LoadIdentity();
  770. pRenderContext->Scale( 1, -1, 1 );
  771. pRenderContext->Ortho( 0, 0, view.width, view.height, -99999, 99999 );
  772. pRenderContext->MatrixMode( MATERIAL_MODEL );
  773. pRenderContext->PushMatrix();
  774. pRenderContext->LoadIdentity();
  775. pRenderContext->MatrixMode( MATERIAL_VIEW );
  776. pRenderContext->PushMatrix();
  777. pRenderContext->LoadIdentity();
  778. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  779. CMeshBuilder meshBuilder;
  780. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  781. float flOffset = 0.5f;
  782. // Note - the viewport has already adjusted the origin
  783. float x1=0.0f - flOffset;
  784. float x2=view.width - flOffset;
  785. float y1=0.0f - flOffset;
  786. float y2=view.height - flOffset;
  787. // adjust nominal uvs to reflect adjusted xys
  788. float u1=FLerp(flUOffset, 1-flUOffset,view.x,view.x+view.width,x1);
  789. float u2=FLerp(flUOffset, 1-flUOffset,view.x,view.x+view.width,x2);
  790. float v1=FLerp(flVOffset, 1-flVOffset,view.y,view.y+view.height,y1);
  791. float v2=FLerp(flVOffset, 1-flVOffset,view.y,view.y+view.height,y2);
  792. for ( int corner=0; corner<4; corner++ )
  793. {
  794. bool left=(corner==0) || (corner==3);
  795. meshBuilder.Position3f( (left) ? x1 : x2, (corner & 2) ? y2 : y1, 0.0f );
  796. meshBuilder.TexCoord2f( 0, (left) ? u1 : u2, (corner & 2) ? v2 : v1 );
  797. meshBuilder.AdvanceVertex();
  798. }
  799. meshBuilder.End();
  800. pMesh->Draw();
  801. pRenderContext->MatrixMode( MATERIAL_MODEL );
  802. pRenderContext->PopMatrix();
  803. pRenderContext->MatrixMode( MATERIAL_VIEW );
  804. pRenderContext->PopMatrix();
  805. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  806. pRenderContext->PopMatrix();
  807. pFadeMaterial->SetMaterialVarFlag( MATERIAL_VAR_IGNOREZ, bOldIgnoreZ );
  808. }
  809. void CRender::ExtractFrustumPlanes( Frustum frustumPlanes )
  810. {
  811. const CViewSetup &view = CurrentView();
  812. GeneratePerspectiveFrustum( CurrentViewOrigin(),
  813. CurrentViewForward(), CurrentViewRight(), CurrentViewUp(),
  814. view.zNear, view.zFar, view.fov, m_yFOV, g_Frustum );
  815. // Copy out to the planes that the engine renderer uses.
  816. for( int i=0; i < FRUSTUM_NUMPLANES; i++ )
  817. {
  818. frustumPlanes[i].m_Normal = g_Frustum.GetPlane(i)->normal;
  819. frustumPlanes[i].m_Dist = g_Frustum.GetPlane(i)->dist;
  820. }
  821. }
  822. void CRender::OrthoExtractFrustumPlanes( Frustum frustumPlanes )
  823. {
  824. const CViewSetup &view = CurrentView();
  825. // Setup the near and far planes.
  826. float orgOffset = DotProduct(CurrentViewOrigin(), CurrentViewForward());
  827. frustumPlanes[FRUSTUM_FARZ].m_Normal = -CurrentViewForward();
  828. frustumPlanes[FRUSTUM_FARZ].m_Dist = -view.zFar - orgOffset;
  829. frustumPlanes[FRUSTUM_NEARZ].m_Normal = CurrentViewForward();
  830. frustumPlanes[FRUSTUM_NEARZ].m_Dist = view.zNear + orgOffset;
  831. // Left and right planes...
  832. orgOffset = DotProduct(CurrentViewOrigin(), CurrentViewRight());
  833. frustumPlanes[FRUSTUM_LEFT].m_Normal = CurrentViewRight();
  834. frustumPlanes[FRUSTUM_LEFT].m_Dist = view.m_OrthoLeft + orgOffset;
  835. frustumPlanes[FRUSTUM_RIGHT].m_Normal = -CurrentViewRight();
  836. frustumPlanes[FRUSTUM_RIGHT].m_Dist = -view.m_OrthoRight - orgOffset;
  837. // Top and buttom planes...
  838. orgOffset = DotProduct(CurrentViewOrigin(), CurrentViewUp());
  839. frustumPlanes[FRUSTUM_TOP].m_Normal = CurrentViewUp();
  840. frustumPlanes[FRUSTUM_TOP].m_Dist = view.m_OrthoTop + orgOffset;
  841. frustumPlanes[FRUSTUM_BOTTOM].m_Normal = -CurrentViewUp();
  842. frustumPlanes[FRUSTUM_BOTTOM].m_Dist = -view.m_OrthoBottom - orgOffset;
  843. // Copy out to the planes that the engine renderer uses.
  844. for(int i=0; i < FRUSTUM_NUMPLANES; i++)
  845. {
  846. /*
  847. if (fabs(frustumPlanes[i].m_Normal.x) - 1.0f > -1e-3)
  848. frustum[i].type = PLANE_X;
  849. else if (fabs(frustumPlanes[i].m_Normal.y) - 1.0f > -1e-3)
  850. frustum[i].type = PLANE_Y;
  851. else if (fabs(frustumPlanes[i].m_Normal.z) - 1.0f > -1e-3)
  852. frustum[i].type = PLANE_Z;
  853. else
  854. */
  855. g_Frustum.SetPlane( i, PLANE_ANYZ, frustumPlanes[i].m_Normal, frustumPlanes[i].m_Dist );
  856. }
  857. }
  858. void CRender::OverrideViewFrustum( Frustum custom )
  859. {
  860. // Copy out to the planes that the engine renderer uses.
  861. for( int i = 0; i != FRUSTUM_NUMPLANES; ++i )
  862. {
  863. g_Frustum.SetPlane( i, PLANE_ANYZ, custom[i].m_Normal, custom[i].m_Dist );
  864. }
  865. }
  866. void CRender::ExtractMatrices( void )
  867. {
  868. m_matrixView = m_ViewStack.Top().m_matrixView;
  869. m_matrixProjection = m_ViewStack.Top().m_matrixProjection;
  870. m_matrixWorldToScreen = m_ViewStack.Top().m_matrixWorldToScreen;
  871. }
  872. void ComputeViewMatrix( VMatrix *pViewMatrix, const Vector &origin, const QAngle &angles )
  873. {
  874. static VMatrix baseRotation;
  875. static bool bDidInit;
  876. if ( !bDidInit )
  877. {
  878. MatrixBuildRotationAboutAxis( baseRotation, Vector( 1, 0, 0 ), -90 );
  879. MatrixRotate( baseRotation, Vector( 0, 0, 1 ), 90 );
  880. bDidInit = true;
  881. }
  882. *pViewMatrix = baseRotation;
  883. MatrixRotate( *pViewMatrix, Vector( 1, 0, 0 ), -angles[2] );
  884. MatrixRotate( *pViewMatrix, Vector( 0, 1, 0 ), -angles[0] );
  885. MatrixRotate( *pViewMatrix, Vector( 0, 0, 1 ), -angles[1] );
  886. MatrixTranslate( *pViewMatrix, -origin );
  887. }
  888. void CRender::SetViewport( int x, int y, int w, int h )
  889. {
  890. int x2, y2;
  891. int windowWidth = w, windowHeight = h;
  892. CMatRenderContextPtr pRenderContext( materials );
  893. // set the viewport to be out to the size of the render target, unless explicitly told not to
  894. if (!CurrentView().m_bRenderToSubrectOfLargerScreen)
  895. {
  896. pRenderContext->GetRenderTargetDimensions( windowWidth, windowHeight );
  897. }
  898. x2 = (x + w);
  899. y2 = (windowHeight - (y + h));
  900. y = (windowHeight - y);
  901. // fudge around because of frac screen scale
  902. if (x > 0)
  903. x--;
  904. if (x2 < windowWidth)
  905. x2++;
  906. if (y2 < 0)
  907. y2--;
  908. if (y < windowHeight)
  909. y++;
  910. w = x2 - x;
  911. h = y - y2;
  912. pRenderContext->Viewport( x, y2, w, h );
  913. }
  914. void DrawLightmapPage( int lightmapPageID )
  915. {
  916. // assumes that we are already in ortho mode.
  917. int lightmapPageWidth, lightmapPageHeight;
  918. CMatRenderContextPtr pRenderContext( materials );
  919. IMesh* pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, g_materialDebugLightmap );
  920. // pRenderContext->Bind( g_materialWireframe );
  921. // IMesh* pMesh = pRenderContext->GetDynamicMesh( g_materialWireframe );
  922. materials->GetLightmapPageSize( lightmapPageID, &lightmapPageWidth, &lightmapPageHeight );
  923. pRenderContext->BindLightmapPage( lightmapPageID );
  924. CMeshBuilder meshBuilder;
  925. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  926. #ifndef _XBOX
  927. int x = 0;
  928. int y = 0;
  929. #else
  930. // xboxissue - border safe
  931. int x = 32;
  932. int y = 32;
  933. #endif
  934. float s = 1.0f;
  935. float t = 1.0f;
  936. // texcoord 1 is lightmaptexcoord for fixed function.
  937. meshBuilder.TexCoord2f( 1, 0.0f, 0.0f );
  938. meshBuilder.Position3f( x, y, 0.0f );
  939. meshBuilder.AdvanceVertex();
  940. meshBuilder.TexCoord2f( 1, s, 0.0f );
  941. meshBuilder.Position3f( x+lightmapPageWidth, y, 0.0f );
  942. meshBuilder.AdvanceVertex();
  943. meshBuilder.TexCoord2f( 1, s, t );
  944. meshBuilder.Position3f( x+lightmapPageWidth, y+lightmapPageHeight, 0.0f );
  945. meshBuilder.AdvanceVertex();
  946. meshBuilder.TexCoord2f( 1, 0.0f, t );
  947. meshBuilder.Position3f( x, y+lightmapPageHeight, 0.0f );
  948. meshBuilder.AdvanceVertex();
  949. meshBuilder.End();
  950. pMesh->Draw();
  951. }
  952. //hack
  953. extern void DebugDrawLightmapAtCrossHair();
  954. void R_DrawLightmaps( IWorldRenderList *pList, int pageId )
  955. {
  956. #ifdef USE_CONVARS
  957. if ( pageId != -1 )
  958. {
  959. DrawLightmapPage( pageId );
  960. Shader_DrawLightmapPageChains( pList, pageId );
  961. }
  962. #endif
  963. }
  964. void R_CheckForLightingConfigChanges()
  965. {
  966. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  967. UpdateStudioRenderConfig();
  968. UpdateMaterialSystemConfig();
  969. if( MaterialConfigLightingChanged() || g_RebuildLightmaps )
  970. {
  971. ClearMaterialConfigLightingChanged();
  972. ConMsg( "Redownloading all lightmaps\n" );
  973. BuildGammaTable( 2.2f, 2.2f, 0.0f, OVERBRIGHT );
  974. R_RedownloadAllLightmaps();
  975. StaticPropMgr()->RecomputeStaticLighting();
  976. }
  977. }
  978. void CRender::DrawSceneBegin( void )
  979. {
  980. R_CheckForLightingConfigChanges();
  981. }
  982. void CRender::DrawSceneEnd( void )
  983. {
  984. R_SceneEnd();
  985. LeafVisDraw();
  986. }
  987. IWorldRenderList * CRender::CreateWorldList()
  988. {
  989. return AllocWorldRenderList();
  990. }
  991. // JasonM TODO: optimize in the case of shadow depth mapping (i.e. don't update lightmaps)
  992. void CRender::BuildWorldLists( IWorldRenderList *pList, WorldListInfo_t* pInfo, int iForceViewLeaf, const VisOverrideData_t* pVisData, bool bShadowDepth, float *pWaterReflectionHeight )
  993. {
  994. Assert( pList );
  995. Assert( m_iLightmapUpdateDepth > 0 || g_LightmapUpdateList.Count() == 0 );
  996. if ( !bShadowDepth )
  997. {
  998. BeginUpdateLightmaps();
  999. }
  1000. R_BuildWorldLists( pList, pInfo, iForceViewLeaf, pVisData, bShadowDepth, pWaterReflectionHeight );
  1001. if ( !bShadowDepth )
  1002. {
  1003. EndUpdateLightmaps();
  1004. }
  1005. Assert( m_iLightmapUpdateDepth > 0 || g_LightmapUpdateList.Count() == 0 );
  1006. }
  1007. void CRender::DrawWorldLists( IWorldRenderList *pList, unsigned long flags, float flWaterZAdjust )
  1008. {
  1009. Assert( pList );
  1010. R_DrawWorldLists( pList, flags, flWaterZAdjust );
  1011. }