summaryrefslogtreecommitdiff
path: root/engine/gl_rmain.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/gl_rmain.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'engine/gl_rmain.cpp')
-rw-r--r--engine/gl_rmain.cpp1254
1 files changed, 1254 insertions, 0 deletions
diff --git a/engine/gl_rmain.cpp b/engine/gl_rmain.cpp
new file mode 100644
index 0000000..63707e4
--- /dev/null
+++ b/engine/gl_rmain.cpp
@@ -0,0 +1,1254 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+
+#include "render_pch.h"
+#include "client.h"
+#include "sound.h"
+#include "debug_leafvis.h"
+#include "cdll_int.h"
+#include "enginestats.h"
+#include "ivrenderview.h"
+#include "studio.h"
+#include "l_studio.h"
+#include "r_areaportal.h"
+#include "materialsystem/materialsystem_config.h"
+#include "materialsystem/itexture.h"
+#include "cdll_engine_int.h"
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "istudiorender.h"
+#include "staticpropmgr.h"
+#include "tier0/vprof.h"
+#include "IOcclusionSystem.h"
+#include "con_nprint.h"
+#include "debugoverlay.h"
+#include "demo.h"
+#include "ivideomode.h"
+#include "sys_dll.h"
+#include "collisionutils.h"
+#include "tier1/utlstack.h"
+#include "r_decal.h"
+#include "cl_main.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#ifndef _X360
+extern ConVar r_waterforceexpensive;
+#endif
+
+ConVar r_aspectratio( "r_aspectratio", "0"
+#if !defined( _X360 )
+ , FCVAR_CHEAT
+#endif
+ );
+ConVar r_dynamiclighting( "r_dynamiclighting", "1", FCVAR_CHEAT );
+extern ConVar building_cubemaps;
+extern float scr_demo_override_fov;
+
+extern colorVec R_LightPoint (Vector& p);
+
+CEngineStats g_EngineStats;
+
+//-----------------------------------------------------------------------------
+// view origin
+//-----------------------------------------------------------------------------
+extern Vector g_CurrentViewOrigin, g_CurrentViewForward, g_CurrentViewRight, g_CurrentViewUp;
+extern Vector g_MainViewOrigin, g_MainViewForward, g_MainViewRight, g_MainViewUp;
+bool g_bCanAccessCurrentView = false;
+
+int d_lightstyleframe[256];
+
+void ProjectPointOnPlane( Vector& dst, const Vector& p, const Vector& normal )
+{
+ float d;
+ Vector n;
+ float inv_denom;
+
+ inv_denom = 1.0F / DotProduct( normal, normal );
+
+ d = DotProduct( normal, p ) * inv_denom;
+
+ n[0] = normal[0] * inv_denom;
+ n[1] = normal[1] * inv_denom;
+ n[2] = normal[2] * inv_denom;
+
+ dst[0] = p[0] - d * n[0];
+ dst[1] = p[1] - d * n[1];
+ dst[2] = p[2] - d * n[2];
+}
+
+/*
+** assumes "src" is normalized
+*/
+void PerpendicularVector( Vector& dst, const Vector& src )
+{
+ int pos;
+ int i;
+ float minelem = 1.0F;
+ Vector tempvec;
+
+ /*
+ ** find the smallest magnitude axially aligned vector
+ */
+ for ( pos = 0, i = 0; i < 3; i++ )
+ {
+ if ( fabs( src[i] ) < minelem )
+ {
+ pos = i;
+ minelem = fabs( src[i] );
+ }
+ }
+ tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
+ tempvec[pos] = 1.0F;
+
+ /*
+ ** project the point onto the plane defined by src
+ */
+ ProjectPointOnPlane( dst, tempvec, src );
+
+ /*
+ ** normalize the result
+ */
+ VectorNormalize( dst );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the aspect ratio of the screen
+//-----------------------------------------------------------------------------
+float GetScreenAspect( )
+{
+ // use the override if set
+ if ( r_aspectratio.GetFloat() > 0.0f )
+ return r_aspectratio.GetFloat();
+
+ // mikesart: This is just sticking in unnecessary BeginRender/EndRender calls to the queue.
+ // CMatRenderContextPtr pRenderContext( materials );
+ IMatRenderContext *pRenderContext = g_pMaterialSystem->GetRenderContext();
+
+ int width, height;
+ pRenderContext->GetRenderTargetDimensions( width, height );
+ return (height != 0) ? ( (float)width / (float)height ) : 1.0f;
+}
+
+
+/*
+====================
+CalcFov
+====================
+*/
+void R_DrawScreenRect( float left, float top, float right, float bottom )
+{
+ CMatRenderContextPtr pRenderContext( materials );
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+
+ IMaterial *pMaterial = materials->FindMaterial( "debug/debugportals", TEXTURE_GROUP_OTHER );
+ IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial );
+
+ CMeshBuilder builder;
+ builder.Begin( pMesh, MATERIAL_LINE_LOOP, 4 );
+
+ Vector v1( left, bottom, 0.5 );
+ Vector v2( left, top, 0.5 );
+ Vector v3( right, top, 0.5 );
+ Vector v4( right, bottom, 0.5 );
+
+ builder.Position3fv( v1.Base() ); builder.AdvanceVertex();
+ builder.Position3fv( v2.Base() ); builder.AdvanceVertex();
+ builder.Position3fv( v3.Base() ); builder.AdvanceVertex();
+ builder.Position3fv( v4.Base() ); builder.AdvanceVertex();
+
+ builder.End( false, true );
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->PopMatrix();
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PopMatrix();
+}
+
+
+void R_DrawPortals()
+{
+ // Draw the portals.
+ if( !r_DrawPortals.GetInt() )
+ return;
+
+ IMaterial *pMaterial = materials->FindMaterial( "debug/debugportals", TEXTURE_GROUP_OTHER );
+ CMatRenderContextPtr pRenderContext( materials );
+ IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial );
+
+ worldbrushdata_t *pBrushData = host_state.worldbrush;
+ for( int i=0; i < pBrushData->m_nAreaPortals; i++ )
+ {
+ dareaportal_t *pAreaPortal = &pBrushData->m_pAreaPortals[i];
+
+ if( !R_IsAreaVisible( pAreaPortal->otherarea ) )
+ continue;
+
+ CMeshBuilder builder;
+ builder.Begin( pMesh, MATERIAL_LINES, pAreaPortal->m_nClipPortalVerts );
+
+ for( int j=0; j < pAreaPortal->m_nClipPortalVerts; j++ )
+ {
+ unsigned short iVert;
+
+ iVert = pAreaPortal->m_FirstClipPortalVert + j;
+ builder.Position3f( VectorExpand( pBrushData->m_pClipPortalVerts[iVert] ) );
+ builder.Color4f( 0, 0, 0, 1 );
+ builder.AdvanceVertex();
+
+ iVert = pAreaPortal->m_FirstClipPortalVert + (j+1) % pAreaPortal->m_nClipPortalVerts;
+ builder.Position3f( VectorExpand( pBrushData->m_pClipPortalVerts[iVert] ) );
+ builder.Color4f( 0, 0, 0, 1 );
+ builder.AdvanceVertex();
+ }
+
+ builder.End( false, true );
+ }
+
+ // Draw the clip rectangles.
+ for( int i=0; i < g_PortalRects.Size(); i++ )
+ {
+ CPortalRect *pRect = &g_PortalRects[i];
+ R_DrawScreenRect( pRect->left, pRect->top, pRect->right, pRect->bottom );
+ }
+ g_PortalRects.Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Loose collection of functions related to rendering the world in a particular view
+//
+//-----------------------------------------------------------------------------
+class CRender : public IRender
+{
+public:
+ CRender();
+
+ void FrameBegin( void );
+ void FrameEnd( void );
+
+ void ViewSetupVis( bool novis, int numorigins, const Vector origin[] );
+ void ViewSetupVisEx( bool novis, int numorigins, const Vector origin[], unsigned int &returnFlags );
+
+ void ViewEnd( void );
+
+ void ViewDrawFade( byte *color, IMaterial* pMaterial );
+
+ IWorldRenderList * CreateWorldList();
+ void BuildWorldLists( IWorldRenderList *pList, WorldListInfo_t* pInfo, int iForceViewLeaf, const VisOverrideData_t* pVisData, bool bShadowDepth, float *pWaterReflectionHeight );
+ void DrawWorldLists( IWorldRenderList *pList, unsigned long flags, float waterZAdjust );
+
+ void DrawSceneBegin( void );
+ void DrawSceneEnd( void );
+
+ // utility functions
+ void ExtractMatrices( void );
+ void ExtractFrustumPlanes( Frustum frustumPlanes );
+ void OrthoExtractFrustumPlanes( Frustum frustumPlanes );
+ void OverrideViewFrustum( Frustum custom );
+
+ void SetViewport( int x, int y, int w, int h );
+ // UNDONE: these are temporary functions that will end up on the other
+ // side of this interface
+ const Vector &ViewOrigin( ) { return CurrentView().origin; }
+ const QAngle &ViewAngles( ) { return CurrentView().angles; }
+ const CViewSetup &ViewGetCurrent( void ) { return CurrentView(); }
+ const VMatrix &ViewMatrix( void );
+ const VMatrix &WorldToScreenMatrix( void );
+
+ float GetFramerate( void ) { return m_framerate; }
+ virtual float GetZNear( void ) { return m_zNear; }
+ virtual float GetZFar( void ) { return m_zFar; }
+
+ // Query current fov and view model fov
+ float GetFov( void ) { return CurrentView().fov; };
+ float GetFovY( void ) { return m_yFOV; };
+ float GetFovViewmodel( void ) { return CurrentView().fovViewmodel; };
+
+ virtual bool ClipTransformWithProjection ( const VMatrix& worldToScreen, const Vector& point, Vector* pClip );
+ virtual bool ClipTransform( const Vector& point, Vector* pClip );
+ virtual bool ScreenTransform( const Vector& point, Vector* pScreen );
+
+ virtual void Push3DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes );
+ virtual void Push3DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes, ITexture* pDepthTexture );
+ virtual void Push2DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes );
+ virtual void PopView( Frustum frustumPlanes );
+ virtual void SetMainView( const Vector &vecOrigin, const QAngle &angles );
+
+ virtual void UpdateBrushModelLightmap( model_t *model, IClientRenderable *Renderable );
+ virtual void BeginUpdateLightmaps( void );
+ virtual void EndUpdateLightmaps( void );
+ virtual bool InLightmapUpdate( void ) const;
+
+private:
+ // Called when a particular view becomes active
+ void OnViewActive( Frustum frustumPlanes );
+
+ // Clear the view (assumes the render target has already been pushed)
+ void ClearView( CViewSetup &view, int nFlags, ITexture* pRenderTarget, ITexture* pDepthTexture = NULL );
+
+ const CViewSetup &CurrentView() const { return m_ViewStack.Top().m_View; }
+ CViewSetup &CurrentView() { return m_ViewStack.Top().m_View; }
+
+ // Stack of view info
+ struct ViewStack_t
+ {
+ CViewSetup m_View;
+
+ // matrices
+ VMatrix m_matrixView;
+ VMatrix m_matrixProjection;
+ VMatrix m_matrixWorldToScreen;
+
+ bool m_bIs2DView;
+ bool m_bNoDraw;
+ };
+
+
+ // Y field of view, calculated from X FOV and screen aspect ratio.
+ float m_yFOV;
+
+ // timing
+ double m_frameStartTime;
+ float m_framerate;
+
+ float m_zNear;
+ float m_zFar;
+
+ // matrices
+ VMatrix m_matrixView;
+ VMatrix m_matrixProjection;
+ VMatrix m_matrixWorldToScreen;
+
+ CUtlStack< ViewStack_t > m_ViewStack;
+ int m_iLightmapUpdateDepth;
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+static CRender gRender;
+IRender *g_EngineRenderer = &gRender;
+
+
+//-----------------------------------------------------------------------------
+// Called when the engine is about to begin rendering for any reason
+//-----------------------------------------------------------------------------
+CRender::CRender()
+{
+ // Make sure the stack isn't empty
+ int i = m_ViewStack.Push();
+ memset( &m_ViewStack[i], 0, sizeof( CViewSetup ) );
+ m_ViewStack[i].m_bIs2DView = true;
+ m_iLightmapUpdateDepth = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the engine is about to begin rendering for any reason
+//-----------------------------------------------------------------------------
+void CRender::FrameBegin( void )
+{
+ if ( host_state.worldmodel )
+ {
+ // This has to be before R_AnimateLight because it uses it to
+ // set the frame number of changed lightstyles
+
+ // FIXME: Why isn't this being done in DrawSceneBegin
+ // or some other client-side simulation of state?
+ r_framecount++;
+ R_AnimateLight ();
+ R_PushDlights();
+
+ if (!r_norefresh.GetInt())
+ {
+ m_frameStartTime = Sys_FloatTime ();
+ }
+ }
+
+ UpdateStudioRenderConfig();
+ g_pStudioRender->BeginFrame();
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the engine has finished rendering
+//-----------------------------------------------------------------------------
+void CRender::FrameEnd( void )
+{
+ // A debugging overlay that renders all raycasts.
+ // Why, or why is this being done here instead of
+ // where all the other debug overlays are being done in the client DLL?
+ EngineTraceRenderRayCasts();
+
+ m_framerate = cl.GetFrameTime();
+ if ( m_framerate > 0 )
+ {
+ m_framerate = 1 / m_framerate;
+ }
+
+ g_pStudioRender->EndFrame();
+}
+
+
+const VMatrix &CRender::ViewMatrix( )
+{
+ // If we aren't in a valid view, then use the last value cached off into the global variable instead
+ if ( m_ViewStack.Count() > 1 )
+ {
+ return m_ViewStack.Top().m_matrixView;
+ }
+ return m_matrixView;
+}
+
+const VMatrix &CRender::WorldToScreenMatrix( void )
+{
+ // If we aren't in a valid view, then use the last value cached off into the global variable instead
+ if ( m_ViewStack.Count() > 1 )
+ {
+ return m_ViewStack.Top().m_matrixWorldToScreen;
+ }
+ return m_matrixWorldToScreen;
+}
+
+void CRender::ViewSetupVis( bool novis, int numorigins, const Vector origin[] )
+{
+ unsigned int returnFlags = 0;
+ ViewSetupVisEx( novis, numorigins, origin, returnFlags );
+}
+
+void CRender::ViewSetupVisEx( bool novis, int numorigins, const Vector origin[], unsigned int &returnFlags )
+{
+ Map_VisSetup( host_state.worldmodel, numorigins, origin, novis, returnFlags );
+}
+
+//-----------------------------------------------------------------------------
+// Called when a particular view becomes active
+//-----------------------------------------------------------------------------
+void CRender::OnViewActive( Frustum frustumPlanes )
+{
+ const CViewSetup &view = CurrentView();
+
+ m_yFOV = CalcFovY( view.fov, view.m_flAspectRatio );
+
+ // build the transformation matrix for the given view angles
+ VectorCopy( view.origin, g_CurrentViewOrigin );
+ AngleVectors( view.angles, &g_CurrentViewForward, &g_CurrentViewRight, &g_CurrentViewUp );
+// g_CurrentViewUp = -g_CurrentViewUp;
+ g_bCanAccessCurrentView = true;
+
+ if ( frustumPlanes )
+ {
+ if ( view.m_bOrtho )
+ {
+ OrthoExtractFrustumPlanes( frustumPlanes );
+ }
+ else
+ {
+ ExtractFrustumPlanes( frustumPlanes );
+ }
+
+ OcclusionSystem()->SetView( view.origin, view.fov, m_matrixView, m_matrixProjection, frustumPlanes[ FRUSTUM_NEARZ ] );
+ }
+
+ if ( !m_ViewStack.Top().m_bNoDraw )
+ {
+ R_SceneBegin( );
+ }
+
+ // debug, build leaf volume
+ // NOTE: This is pretty hacky, but I want the leaf based on the main view. The skybox view is reseting
+ // the g_LeafVis here because it is global. This need to be resolved more correctly some other way!
+ if ( VectorCompare( g_MainViewOrigin, view.origin ) )
+ {
+ LeafVisBuild( view.origin );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Clear the view (assumes the render target has already been pushed)
+//-----------------------------------------------------------------------------
+void CRender::ClearView( CViewSetup &view, int nFlags, ITexture* pRenderTarget, ITexture* pDepthTexture /* = NULL */ )
+{
+ bool bClearColor = (nFlags & VIEW_CLEAR_COLOR) != 0;
+ bool bClearDepth = (nFlags & VIEW_CLEAR_DEPTH) != 0;
+ bool bClearStencil = (nFlags & VIEW_CLEAR_STENCIL) != 0;
+ bool bForceClearWholeRenderTarget = (nFlags & VIEW_CLEAR_FULL_TARGET) != 0;
+ bool bObeyStencil = (nFlags & VIEW_CLEAR_OBEY_STENCIL) != 0;
+
+ // Handle an initial clear request if asked for
+ if ( !bClearColor && !bClearDepth && !bClearStencil )
+ return;
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ if ( !bForceClearWholeRenderTarget )
+ {
+ if( bObeyStencil )
+ pRenderContext->ClearBuffersObeyStencil( bClearColor, bClearDepth );
+ else
+ pRenderContext->ClearBuffers( bClearColor, bClearDepth, bClearStencil );
+ }
+ else
+ {
+ // Get the render target dimensions
+ int nWidth, nHeight;
+ if ( pRenderTarget )
+ {
+ nWidth = pRenderTarget->GetActualWidth();
+ nHeight = pRenderTarget->GetActualHeight();
+ }
+ else
+ {
+ materials->GetBackBufferDimensions( nWidth, nHeight );
+ }
+
+ pRenderContext->PushRenderTargetAndViewport( pRenderTarget, pDepthTexture, 0, 0, nWidth, nHeight );
+
+ if( bObeyStencil )
+ pRenderContext->ClearBuffersObeyStencil( bClearColor, bClearDepth );
+ else
+ pRenderContext->ClearBuffers( bClearColor, bClearDepth, bClearStencil );
+
+ pRenderContext->PopRenderTargetAndViewport( );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Push, pop views
+//-----------------------------------------------------------------------------
+void CRender::Push3DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes )
+{
+ Push3DView( view, nFlags, pRenderTarget, frustumPlanes, NULL );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Computes view matrices
+//-----------------------------------------------------------------------------
+float ComputeViewMatrices( VMatrix *pWorldToView, VMatrix *pViewToProjection, VMatrix *pWorldToProjection, const CViewSetup &viewSetup )
+{
+ float flAspectRatio = viewSetup.m_flAspectRatio;
+ if ( flAspectRatio == 0.0f )
+ {
+ flAspectRatio = (viewSetup.height != 0) ? ( (float)viewSetup.width / (float)viewSetup.height ) : 1.0f;
+ }
+
+ ComputeViewMatrix( pWorldToView, viewSetup.origin, viewSetup.angles );
+
+ if ( viewSetup.m_bOrtho )
+ {
+ MatrixBuildOrtho( *pViewToProjection, viewSetup.m_OrthoLeft, viewSetup.m_OrthoTop,
+ viewSetup.m_OrthoRight, viewSetup.m_OrthoBottom, viewSetup.zNear, viewSetup.zFar );
+ }
+ else if ( viewSetup.m_bOffCenter ) // Off-center projection, useful for AA jitter and tiled output of posters
+ {
+ MatrixBuildPerspectiveOffCenterX( *pViewToProjection, viewSetup.fov, flAspectRatio,
+ viewSetup.zNear, viewSetup.zFar, viewSetup.m_flOffCenterBottom, viewSetup.m_flOffCenterTop,
+ viewSetup.m_flOffCenterLeft, viewSetup.m_flOffCenterRight );
+ }
+ else if ( viewSetup.m_bViewToProjectionOverride )
+ {
+ *pViewToProjection = viewSetup.m_ViewToProjection;
+ // ...but then override the Z range (needed for correct skybox rendering, etc).
+ MatrixBuildPerspectiveZRange ( *pViewToProjection, viewSetup.zNear, viewSetup.zFar );
+ }
+ else
+ {
+ MatrixBuildPerspectiveX( *pViewToProjection, viewSetup.fov, flAspectRatio, viewSetup.zNear, viewSetup.zFar );
+ }
+
+ MatrixMultiply( *pViewToProjection, *pWorldToView, *pWorldToProjection );
+
+ return flAspectRatio;
+}
+
+
+
+// Flip y, screen y goes down
+static VMatrix g_ProjectionToOffset( 0.5f, 0.0f, 0.0f, 0.5f,
+ 0.0f, -0.5f, 0.0f, 0.5f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f );
+
+// NOTE: Screen coordinates go from 0->w, 0->h
+void ComputeWorldToScreenMatrix( VMatrix *pWorldToScreen, const VMatrix &worldToProjection, const CViewSetup &viewSetup )
+{
+ // First need to transform -1 -> 1 to 0 -> 1 in x and y
+ // Then transform from 0->1 to x->w+x in x, and 0->1 to y->y+h in y.
+ VMatrix offsetToPixels( viewSetup.width, 0.0f, 0.0f, viewSetup.x,
+ 0.0f, viewSetup.height, 0.0f, viewSetup.y,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f );
+
+ VMatrix projectionToPixels;
+ MatrixMultiply( offsetToPixels, g_ProjectionToOffset, projectionToPixels );
+ MatrixMultiply( projectionToPixels, worldToProjection, *pWorldToScreen );
+}
+
+
+//-----------------------------------------------------------------------------
+// Push, pop views
+//-----------------------------------------------------------------------------
+void CRender::Push3DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes, ITexture* pDepthTexture )
+{
+ 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()
+
+ int i = m_ViewStack.Push( );
+ m_ViewStack[i].m_View = view;
+ m_ViewStack[i].m_bIs2DView = false;
+ m_ViewStack[i].m_bNoDraw = ( ( nFlags & VIEW_NO_DRAW ) != 0 );
+
+ CViewSetup &topView = m_ViewStack[i].m_View;
+
+ // Compute aspect ratio if asked for
+ if ( topView.m_flAspectRatio == 0.0f )
+ {
+ topView.m_flAspectRatio = (topView.height != 0) ? ( (float)topView.width / (float)topView.height ) : 1.0f;
+ }
+
+ ViewStack_t &viewStack = m_ViewStack.Top();
+ topView.m_flAspectRatio = ComputeViewMatrices( &viewStack.m_matrixView,
+ &viewStack.m_matrixProjection, &viewStack.m_matrixWorldToScreen, topView );
+
+ m_zNear = topView.zNear;
+ m_zFar = topView.zFar; // cache this for queries
+
+ ExtractMatrices();
+
+ if ( !m_ViewStack[i].m_bNoDraw )
+ {
+ CMatRenderContextPtr pRenderContext( materials );
+
+ if ( !pRenderTarget )
+ {
+ pRenderTarget = pRenderContext->GetRenderTarget();
+ }
+
+ // Push render target and viewport
+ pRenderContext->PushRenderTargetAndViewport( pRenderTarget, pDepthTexture, topView.x, topView.y, topView.width, topView.height );
+
+ // Handle an initial clear request if asked for
+ ClearView( topView, nFlags, pRenderTarget, pDepthTexture );
+
+ pRenderContext->DepthRange( 0, 1 );
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadMatrix( m_matrixProjection );
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadMatrix( m_matrixView );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+
+ OnViewActive( frustumPlanes );
+ }
+}
+
+void CRender::Push2DView( const CViewSetup &view, int nFlags, ITexture* pRenderTarget, Frustum frustumPlanes )
+{
+ int i = m_ViewStack.Push( );
+ m_ViewStack[i].m_View = view;
+ m_ViewStack[i].m_bIs2DView = true;
+ m_ViewStack[i].m_bNoDraw = ( ( nFlags & VIEW_NO_DRAW ) != 0 );
+ m_ViewStack[i].m_matrixView = m_matrixView;
+ m_ViewStack[i].m_matrixProjection = m_matrixProjection;
+ m_ViewStack[i].m_matrixWorldToScreen = m_matrixWorldToScreen;
+
+ CViewSetup &topView = m_ViewStack[i].m_View;
+ g_bCanAccessCurrentView = false;
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ if ( !pRenderContext )
+ {
+ pRenderTarget = pRenderContext->GetRenderTarget();
+ }
+
+ // Push render target and viewport
+ pRenderContext->PushRenderTargetAndViewport( pRenderTarget, topView.x, topView.y, topView.width, topView.height );
+
+ // Handle an initial clear request if asked for
+ ClearView( topView, nFlags, pRenderTarget );
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+ pRenderContext->Scale( 1, -1, 1 );
+ pRenderContext->Ortho( 0, 0, topView.width, topView.height, -99999, 99999 );
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+}
+
+void CRender::PopView( Frustum frustumPlanes )
+{
+ if ( !m_ViewStack.Top().m_bNoDraw )
+ {
+ CMatRenderContextPtr pRenderContext( materials );
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PopMatrix();
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->PopMatrix();
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+
+ pRenderContext->PopRenderTargetAndViewport( );
+ }
+
+ bool bReset = ( m_ViewStack.Count() > 1 ) ? true : false;
+ m_ViewStack.Pop();
+
+ // Don't pop off the very last view
+ g_bCanAccessCurrentView = false;
+
+ if ( bReset )
+ {
+ if ( !m_ViewStack.Top().m_bIs2DView )
+ {
+ ExtractMatrices();
+ OnViewActive( frustumPlanes );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the main 3D view (for console commands, sound, etc.)
+//-----------------------------------------------------------------------------
+void CRender::SetMainView( const Vector &vecOrigin, const QAngle &angles )
+{
+ VectorCopy( vecOrigin, g_MainViewOrigin );
+ AngleVectors( angles, &g_MainViewForward, &g_MainViewRight, &g_MainViewUp );
+}
+
+CUtlVector<LightmapUpdateInfo_t> g_LightmapUpdateList;
+CUtlVector<LightmapTransformInfo_t> g_LightmapTransformList;
+
+int __cdecl LightmapPageCompareFunc( const void *pElem0, const void *pElem1 )
+{
+ const LightmapUpdateInfo_t *pSurf0 = (const LightmapUpdateInfo_t *)pElem0;
+ const LightmapUpdateInfo_t *pSurf1 = (const LightmapUpdateInfo_t *)pElem1;
+ int page0 = materialSortInfoArray[MSurf_MaterialSortID( (pSurf0->m_SurfHandle) )].lightmapPageID;
+ int page1 = materialSortInfoArray[MSurf_MaterialSortID( (pSurf1->m_SurfHandle) )].lightmapPageID;
+ return page0 - page1;
+}
+
+void CRender::BeginUpdateLightmaps( void )
+{
+ if ( ++m_iLightmapUpdateDepth == 1)
+ {
+ Assert( g_LightmapUpdateList.Count() == 0 );
+ materials->BeginUpdateLightmaps();
+ // UNDONE: Move this to an init or constructor?
+ g_LightmapTransformList.RemoveAll();
+ int index = g_LightmapTransformList.AddToTail();
+ g_LightmapTransformList[index].pModel = host_state.worldmodel;
+ SetIdentityMatrix( g_LightmapTransformList[index].xform );
+ }
+}
+
+void CRender::UpdateBrushModelLightmap( model_t *model, IClientRenderable *pRenderable )
+{
+ AssertOnce( m_iLightmapUpdateDepth );
+
+ if( !r_drawbrushmodels.GetBool() || !m_iLightmapUpdateDepth )
+ return;
+
+ R_MarkDlightsOnBrushModel( model, pRenderable );
+ if ( model->flags & MODELFLAG_HAS_DLIGHT )
+ {
+ int transformIndex = g_LightmapTransformList.AddToTail();
+ LightmapTransformInfo_t &transform = g_LightmapTransformList[transformIndex];
+ transform.pModel = model;
+ AngleMatrix( pRenderable->GetRenderAngles(), pRenderable->GetRenderOrigin(), transform.xform );
+ SurfaceHandle_t surfID = SurfaceHandleFromIndex( model->brush.firstmodelsurface, model->brush.pShared );
+ bool bLight = false;
+ for (int i=0 ; i<model->brush.nummodelsurfaces ; i++, surfID++)
+ {
+ if ( MSurf_Flags(surfID) & (SURFDRAW_HASDLIGHT|SURFDRAW_HASLIGHTSYTLES) )
+ {
+ LightmapUpdateInfo_t tmp;
+ tmp.m_SurfHandle = surfID;
+ tmp.transformIndex = transformIndex;
+ g_LightmapUpdateList.AddToTail( tmp );
+ bLight = true;
+ }
+ }
+ if ( !bLight )
+ {
+ model->flags &= ~MODELFLAG_HAS_DLIGHT; // don't need to check again unless a dlight hits us
+ }
+ }
+}
+
+void CRender::EndUpdateLightmaps( void )
+{
+ Assert( m_iLightmapUpdateDepth > 0 );
+ if ( --m_iLightmapUpdateDepth == 0 )
+ {
+ VPROF_BUDGET( "EndUpdateLightmaps", VPROF_BUDGETGROUP_DLIGHT_RENDERING );
+ if ( g_LightmapUpdateList.Count() && r_dynamiclighting.GetBool() && !r_unloadlightmaps.GetBool() )
+ {
+ CMatRenderContextPtr pRenderContext( materials );
+ ICallQueue *pCallQueue = pRenderContext->GetCallQueue();
+ dlight_t *pLights = &cl_dlights[0];
+ // only do the copy when there are valid dlights to process and threading is on
+ if ( g_bActiveDlights && pCallQueue )
+ {
+ // keep a copy of the current dlight state around for the thread to work on
+ // in parallel. This way the main thread can continue to modify this state without
+ // generating any bad results
+ static dlight_t threadDlights[MAX_DLIGHTS*2];
+ static int threadFrameCount = 0;
+ pLights = &threadDlights[MAX_DLIGHTS*threadFrameCount];
+ Q_memcpy( pLights, cl_dlights, sizeof(dlight_t) * MAX_DLIGHTS );
+ threadFrameCount = (threadFrameCount+1) & 1;
+ }
+
+ qsort( g_LightmapUpdateList.Base(), g_LightmapUpdateList.Count(), sizeof(g_LightmapUpdateList.Element(0)), LightmapPageCompareFunc );
+ int i;
+ for ( i = g_LightmapUpdateList.Count()-1; i >= 0; --i )
+ {
+ const LightmapUpdateInfo_t &lightmapUpdateInfo = g_LightmapUpdateList.Element(i);
+ // a surface can get queued more than once if it's visible in multiple views (e.g. water reflection can do this)
+ // so check frame to make sure we only recompute once
+ if ( SurfaceLighting(lightmapUpdateInfo.m_SurfHandle)->m_nLastComputedFrame != r_framecount )
+ {
+ R_RenderDynamicLightmaps( pLights, pCallQueue, lightmapUpdateInfo.m_SurfHandle, g_LightmapTransformList[lightmapUpdateInfo.transformIndex].xform );
+ }
+ }
+ }
+ materials->EndUpdateLightmaps();
+ g_LightmapUpdateList.RemoveAll();
+ g_LightmapTransformList.RemoveAll();
+ }
+}
+
+bool CRender::InLightmapUpdate( void ) const
+{
+ return ( m_iLightmapUpdateDepth != 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Compute the scene coordinates of a point in 3D
+//-----------------------------------------------------------------------------
+bool CRender::ClipTransformWithProjection ( const VMatrix& worldToScreen, const Vector& point, Vector* pClip )
+{
+// UNDONE: Clean this up some, handle off-screen vertices
+ float w;
+
+ pClip->x = worldToScreen[0][0] * point[0] + worldToScreen[0][1] * point[1] + worldToScreen[0][2] * point[2] + worldToScreen[0][3];
+ pClip->y = worldToScreen[1][0] * point[0] + worldToScreen[1][1] * point[1] + worldToScreen[1][2] * point[2] + worldToScreen[1][3];
+// z = worldToScreen[2][0] * point[0] + worldToScreen[2][1] * point[1] + worldToScreen[2][2] * point[2] + worldToScreen[2][3];
+ w = worldToScreen[3][0] * point[0] + worldToScreen[3][1] * point[1] + worldToScreen[3][2] * point[2] + worldToScreen[3][3];
+
+ // Just so we have something valid here
+ pClip->z = 0.0f;
+
+ bool behind;
+ if( w < 0.001f )
+ {
+ behind = true;
+ pClip->x *= 100000;
+ pClip->y *= 100000;
+ }
+ else
+ {
+ behind = false;
+ float invw = 1.0f / w;
+ pClip->x *= invw;
+ pClip->y *= invw;
+ }
+
+ return behind;
+}
+
+//-----------------------------------------------------------------------------
+// Compute the scene coordinates of a point in 3D using the current engine's projection
+//-----------------------------------------------------------------------------
+bool CRender::ClipTransform ( const Vector& point, Vector* pClip )
+{
+ const VMatrix &worldToScreen = g_EngineRenderer->WorldToScreenMatrix();
+ return CRender::ClipTransformWithProjection ( worldToScreen, point, pClip );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Given a point, return the screen position in pixels
+//-----------------------------------------------------------------------------
+bool CRender::ScreenTransform( const Vector& point, Vector* pScreen )
+{
+ bool retval = ClipTransform( point, pScreen );
+
+ pScreen->x = 0.5f * ( pScreen->x + 1.0f ) * CurrentView().width + CurrentView().x;
+ pScreen->y = 0.5f * ( pScreen->y + 1.0f ) * CurrentView().height + CurrentView().y;
+
+ return retval;
+}
+
+void CRender::ViewDrawFade( byte *color, IMaterial* pFadeMaterial )
+{
+ if ( !color || !color[3] )
+ return;
+
+ if( !pFadeMaterial )
+ return;
+
+ const CViewSetup &view = CurrentView();
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ pRenderContext->Bind( pFadeMaterial );
+ pFadeMaterial->AlphaModulate( color[3] * ( 1.0f / 255.0f ) );
+ pFadeMaterial->ColorModulate( color[0] * ( 1.0f / 255.0f ),
+ color[1] * ( 1.0f / 255.0f ),
+ color[2] * ( 1.0f / 255.0f ) );
+
+ bool bOldIgnoreZ = pFadeMaterial->GetMaterialVarFlag( MATERIAL_VAR_IGNOREZ );
+ pFadeMaterial->SetMaterialVarFlag( MATERIAL_VAR_IGNOREZ, true );
+
+ int nTexWidth, nTexHeight;
+ nTexWidth = pFadeMaterial->GetMappingWidth();
+ nTexHeight = pFadeMaterial->GetMappingHeight();
+ float flUOffset = 0.5f / nTexWidth;
+ float flVOffset = 0.5f / nTexHeight;
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ pRenderContext->Scale( 1, -1, 1 );
+ pRenderContext->Ortho( 0, 0, view.width, view.height, -99999, 99999 );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ float flOffset = 0.5f;
+
+ // Note - the viewport has already adjusted the origin
+ float x1=0.0f - flOffset;
+ float x2=view.width - flOffset;
+ float y1=0.0f - flOffset;
+ float y2=view.height - flOffset;
+
+ // adjust nominal uvs to reflect adjusted xys
+ float u1=FLerp(flUOffset, 1-flUOffset,view.x,view.x+view.width,x1);
+ float u2=FLerp(flUOffset, 1-flUOffset,view.x,view.x+view.width,x2);
+ float v1=FLerp(flVOffset, 1-flVOffset,view.y,view.y+view.height,y1);
+ float v2=FLerp(flVOffset, 1-flVOffset,view.y,view.y+view.height,y2);
+
+ for ( int corner=0; corner<4; corner++ )
+ {
+ bool left=(corner==0) || (corner==3);
+ meshBuilder.Position3f( (left) ? x1 : x2, (corner & 2) ? y2 : y1, 0.0f );
+ meshBuilder.TexCoord2f( 0, (left) ? u1 : u2, (corner & 2) ? v2 : v1 );
+ meshBuilder.AdvanceVertex();
+ }
+ meshBuilder.End();
+ pMesh->Draw();
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->PopMatrix();
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PopMatrix();
+
+ pFadeMaterial->SetMaterialVarFlag( MATERIAL_VAR_IGNOREZ, bOldIgnoreZ );
+}
+
+void CRender::ExtractFrustumPlanes( Frustum frustumPlanes )
+{
+ const CViewSetup &view = CurrentView();
+
+ GeneratePerspectiveFrustum( CurrentViewOrigin(),
+ CurrentViewForward(), CurrentViewRight(), CurrentViewUp(),
+ view.zNear, view.zFar, view.fov, m_yFOV, g_Frustum );
+
+ // Copy out to the planes that the engine renderer uses.
+ for( int i=0; i < FRUSTUM_NUMPLANES; i++ )
+ {
+ frustumPlanes[i].m_Normal = g_Frustum.GetPlane(i)->normal;
+ frustumPlanes[i].m_Dist = g_Frustum.GetPlane(i)->dist;
+ }
+}
+
+void CRender::OrthoExtractFrustumPlanes( Frustum frustumPlanes )
+{
+ const CViewSetup &view = CurrentView();
+
+ // Setup the near and far planes.
+ float orgOffset = DotProduct(CurrentViewOrigin(), CurrentViewForward());
+ frustumPlanes[FRUSTUM_FARZ].m_Normal = -CurrentViewForward();
+ frustumPlanes[FRUSTUM_FARZ].m_Dist = -view.zFar - orgOffset;
+
+ frustumPlanes[FRUSTUM_NEARZ].m_Normal = CurrentViewForward();
+ frustumPlanes[FRUSTUM_NEARZ].m_Dist = view.zNear + orgOffset;
+
+ // Left and right planes...
+ orgOffset = DotProduct(CurrentViewOrigin(), CurrentViewRight());
+ frustumPlanes[FRUSTUM_LEFT].m_Normal = CurrentViewRight();
+ frustumPlanes[FRUSTUM_LEFT].m_Dist = view.m_OrthoLeft + orgOffset;
+
+ frustumPlanes[FRUSTUM_RIGHT].m_Normal = -CurrentViewRight();
+ frustumPlanes[FRUSTUM_RIGHT].m_Dist = -view.m_OrthoRight - orgOffset;
+
+ // Top and buttom planes...
+ orgOffset = DotProduct(CurrentViewOrigin(), CurrentViewUp());
+ frustumPlanes[FRUSTUM_TOP].m_Normal = CurrentViewUp();
+ frustumPlanes[FRUSTUM_TOP].m_Dist = view.m_OrthoTop + orgOffset;
+
+ frustumPlanes[FRUSTUM_BOTTOM].m_Normal = -CurrentViewUp();
+ frustumPlanes[FRUSTUM_BOTTOM].m_Dist = -view.m_OrthoBottom - orgOffset;
+
+ // Copy out to the planes that the engine renderer uses.
+ for(int i=0; i < FRUSTUM_NUMPLANES; i++)
+ {
+ /*
+ if (fabs(frustumPlanes[i].m_Normal.x) - 1.0f > -1e-3)
+ frustum[i].type = PLANE_X;
+ else if (fabs(frustumPlanes[i].m_Normal.y) - 1.0f > -1e-3)
+ frustum[i].type = PLANE_Y;
+ else if (fabs(frustumPlanes[i].m_Normal.z) - 1.0f > -1e-3)
+ frustum[i].type = PLANE_Z;
+ else
+ */
+ g_Frustum.SetPlane( i, PLANE_ANYZ, frustumPlanes[i].m_Normal, frustumPlanes[i].m_Dist );
+ }
+}
+
+void CRender::OverrideViewFrustum( Frustum custom )
+{
+ // Copy out to the planes that the engine renderer uses.
+ for( int i = 0; i != FRUSTUM_NUMPLANES; ++i )
+ {
+ g_Frustum.SetPlane( i, PLANE_ANYZ, custom[i].m_Normal, custom[i].m_Dist );
+ }
+}
+
+void CRender::ExtractMatrices( void )
+{
+ m_matrixView = m_ViewStack.Top().m_matrixView;
+ m_matrixProjection = m_ViewStack.Top().m_matrixProjection;
+ m_matrixWorldToScreen = m_ViewStack.Top().m_matrixWorldToScreen;
+}
+
+void ComputeViewMatrix( VMatrix *pViewMatrix, const Vector &origin, const QAngle &angles )
+{
+ static VMatrix baseRotation;
+ static bool bDidInit;
+
+ if ( !bDidInit )
+ {
+ MatrixBuildRotationAboutAxis( baseRotation, Vector( 1, 0, 0 ), -90 );
+ MatrixRotate( baseRotation, Vector( 0, 0, 1 ), 90 );
+ bDidInit = true;
+ }
+
+ *pViewMatrix = baseRotation;
+ MatrixRotate( *pViewMatrix, Vector( 1, 0, 0 ), -angles[2] );
+ MatrixRotate( *pViewMatrix, Vector( 0, 1, 0 ), -angles[0] );
+ MatrixRotate( *pViewMatrix, Vector( 0, 0, 1 ), -angles[1] );
+
+ MatrixTranslate( *pViewMatrix, -origin );
+}
+
+void CRender::SetViewport( int x, int y, int w, int h )
+{
+ int x2, y2;
+ int windowWidth = w, windowHeight = h;
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ // set the viewport to be out to the size of the render target, unless explicitly told not to
+ if (!CurrentView().m_bRenderToSubrectOfLargerScreen)
+ {
+ pRenderContext->GetRenderTargetDimensions( windowWidth, windowHeight );
+ }
+
+ x2 = (x + w);
+ y2 = (windowHeight - (y + h));
+ y = (windowHeight - y);
+
+ // fudge around because of frac screen scale
+ if (x > 0)
+ x--;
+ if (x2 < windowWidth)
+ x2++;
+ if (y2 < 0)
+ y2--;
+ if (y < windowHeight)
+ y++;
+
+ w = x2 - x;
+ h = y - y2;
+
+ pRenderContext->Viewport( x, y2, w, h );
+}
+
+void DrawLightmapPage( int lightmapPageID )
+{
+ // assumes that we are already in ortho mode.
+ int lightmapPageWidth, lightmapPageHeight;
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, g_materialDebugLightmap );
+// pRenderContext->Bind( g_materialWireframe );
+// IMesh* pMesh = pRenderContext->GetDynamicMesh( g_materialWireframe );
+
+ materials->GetLightmapPageSize( lightmapPageID, &lightmapPageWidth, &lightmapPageHeight );
+ pRenderContext->BindLightmapPage( lightmapPageID );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+#ifndef _XBOX
+ int x = 0;
+ int y = 0;
+#else
+ // xboxissue - border safe
+ int x = 32;
+ int y = 32;
+#endif
+ float s = 1.0f;
+ float t = 1.0f;
+
+ // texcoord 1 is lightmaptexcoord for fixed function.
+ meshBuilder.TexCoord2f( 1, 0.0f, 0.0f );
+ meshBuilder.Position3f( x, y, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.TexCoord2f( 1, s, 0.0f );
+ meshBuilder.Position3f( x+lightmapPageWidth, y, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.TexCoord2f( 1, s, t );
+ meshBuilder.Position3f( x+lightmapPageWidth, y+lightmapPageHeight, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.TexCoord2f( 1, 0.0f, t );
+ meshBuilder.Position3f( x, y+lightmapPageHeight, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+//hack
+extern void DebugDrawLightmapAtCrossHair();
+
+void R_DrawLightmaps( IWorldRenderList *pList, int pageId )
+{
+#ifdef USE_CONVARS
+ if ( pageId != -1 )
+ {
+ DrawLightmapPage( pageId );
+ Shader_DrawLightmapPageChains( pList, pageId );
+ }
+#endif
+}
+
+void R_CheckForLightingConfigChanges()
+{
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
+
+ UpdateStudioRenderConfig();
+ UpdateMaterialSystemConfig();
+ if( MaterialConfigLightingChanged() || g_RebuildLightmaps )
+ {
+ ClearMaterialConfigLightingChanged();
+ ConMsg( "Redownloading all lightmaps\n" );
+ BuildGammaTable( 2.2f, 2.2f, 0.0f, OVERBRIGHT );
+ R_RedownloadAllLightmaps();
+ StaticPropMgr()->RecomputeStaticLighting();
+ }
+}
+
+void CRender::DrawSceneBegin( void )
+{
+ R_CheckForLightingConfigChanges();
+}
+
+void CRender::DrawSceneEnd( void )
+{
+ R_SceneEnd();
+ LeafVisDraw();
+}
+
+IWorldRenderList * CRender::CreateWorldList()
+{
+ return AllocWorldRenderList();
+}
+
+
+// JasonM TODO: optimize in the case of shadow depth mapping (i.e. don't update lightmaps)
+void CRender::BuildWorldLists( IWorldRenderList *pList, WorldListInfo_t* pInfo, int iForceViewLeaf, const VisOverrideData_t* pVisData, bool bShadowDepth, float *pWaterReflectionHeight )
+{
+ Assert( pList );
+ Assert( m_iLightmapUpdateDepth > 0 || g_LightmapUpdateList.Count() == 0 );
+
+ if ( !bShadowDepth )
+ {
+ BeginUpdateLightmaps();
+ }
+
+ R_BuildWorldLists( pList, pInfo, iForceViewLeaf, pVisData, bShadowDepth, pWaterReflectionHeight );
+
+ if ( !bShadowDepth )
+ {
+ EndUpdateLightmaps();
+ }
+
+ Assert( m_iLightmapUpdateDepth > 0 || g_LightmapUpdateList.Count() == 0 );
+}
+
+void CRender::DrawWorldLists( IWorldRenderList *pList, unsigned long flags, float flWaterZAdjust )
+{
+ Assert( pList );
+ R_DrawWorldLists( pList, flags, flWaterZAdjust );
+}