391 lines
11 KiB
C++
391 lines
11 KiB
C++
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: master for refresh, status bar, console, chat, notify, etc
|
|
//
|
|
//=====================================================================================//
|
|
|
|
|
|
#include "render_pch.h"
|
|
#include "client.h"
|
|
#include "console.h"
|
|
#include "screen.h"
|
|
#include "sound.h"
|
|
#include "sbar.h"
|
|
#include "debugoverlay.h"
|
|
#include "cdll_int.h"
|
|
#include "gl_matsysiface.h"
|
|
#include "cdll_engine_int.h"
|
|
#include "demo.h"
|
|
#include "cl_main.h"
|
|
#include "vgui_baseui_interface.h"
|
|
#include "con_nprint.h"
|
|
#include "sys_mainwind.h"
|
|
#include "ivideomode.h"
|
|
#include "lightcache.h"
|
|
#include "toolframework/itoolframework.h"
|
|
#include "datacache/idatacache.h"
|
|
#include "sys_dll.h"
|
|
#include "host.h"
|
|
#include "MapReslistGenerator.h"
|
|
#include "tier1/callqueue.h"
|
|
#include "tier0/icommandline.h"
|
|
#include "matchmaking/imatchframework.h"
|
|
#include "cl_steamauth.h"
|
|
|
|
#include "scaleformui/scaleformui.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
ConVar g_cv_miniprofiler_dump( "miniprofiler_dump", "0" );
|
|
#if defined( _X360 )
|
|
ConVar g_cv_frame_pcm( "frame_pcm", "0" );
|
|
bool g_started_frame_pcm = false;
|
|
#endif
|
|
DLL_IMPORT void PublishAllMiniProfilers(int nHistoryMax);
|
|
|
|
// In other C files.
|
|
extern bool V_CheckGamma( void );
|
|
extern void V_RenderView( void );
|
|
extern void V_RenderVGuiOnly( void );
|
|
|
|
extern bool HostState_IsTransitioningToLoad();
|
|
|
|
bool scr_initialized; // ready to draw
|
|
bool scr_disabled_for_loading;
|
|
bool scr_drawloading;
|
|
int scr_nextdrawtick; // A hack to let things settle on reload/reconnect
|
|
float scr_loadingStartTime;
|
|
|
|
static bool scr_engineevent_loadingstarted; // whether OnEngineLevelLoadingStarted has been fired
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void SCR_Init (void)
|
|
{
|
|
scr_initialized = true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void SCR_Shutdown( void )
|
|
{
|
|
scr_initialized = false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: starts loading
|
|
//-----------------------------------------------------------------------------
|
|
void SCR_BeginLoadingPlaque( const char *levelName /*= NULL*/ )
|
|
{
|
|
if ( !scr_drawloading )
|
|
{
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
#if defined( _DEMO ) && defined( _X360 )
|
|
// disable demo timeouts during loading
|
|
Host_EnableDemoTimeout( false );
|
|
#endif
|
|
|
|
scr_loadingStartTime = Plat_FloatTime();
|
|
|
|
// make sure game UI is allowed to show (gets disabled if chat window is up)
|
|
EngineVGui()->SetNotAllowedToShowGameUI( false );
|
|
|
|
// force QMS to serialize during loading
|
|
Host_AllowQueuedMaterialSystem( false );
|
|
|
|
scr_drawloading = true;
|
|
|
|
S_StopAllSounds( true );
|
|
S_PreventSound( true ); //this will stop audio from reaching the mixer until SCR_EndLoadingPlaque is called.
|
|
S_OnLoadScreen( true );
|
|
|
|
g_pFileSystem->AsyncFinishAll();
|
|
g_pMDLCache->FinishPendingLoads();
|
|
|
|
// redraw with no console and the loading plaque
|
|
Con_ClearNotify();
|
|
|
|
// NULL HudText clears HudMessage system
|
|
if ( g_ClientDLL )
|
|
{
|
|
g_ClientDLL->CenterStringOff();
|
|
g_ClientDLL->HudText( NULL );
|
|
}
|
|
|
|
// let everybody know we're starting loading
|
|
EngineVGui()->OnLevelLoadingStarted( levelName, HostState_IsTransitioningToLoad() );
|
|
scr_engineevent_loadingstarted = true;
|
|
g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
|
|
"OnEngineLevelLoadingStarted", "name", levelName ) );
|
|
|
|
// Don't run any more simulation on the client!!!
|
|
g_ClientGlobalVariables.frametime = 0.0f;
|
|
|
|
host_framecount++;
|
|
g_ClientGlobalVariables.framecount = host_framecount;
|
|
// Ensure the screen is painted to reflect the loading state
|
|
SCR_UpdateScreen();
|
|
host_framecount++;
|
|
g_ClientGlobalVariables.framecount = host_framecount;
|
|
SCR_UpdateScreen();
|
|
|
|
g_ClientGlobalVariables.frametime = GetBaseLocalClient().GetFrameTime();
|
|
|
|
scr_disabled_for_loading = true;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: finished loading
|
|
//-----------------------------------------------------------------------------
|
|
void SCR_EndLoadingPlaque( void )
|
|
{
|
|
// MATCHMAKING:UNDONE: This pattern came over from l4d but needed to change since the new clients don't have the same mission/game structure
|
|
if ( scr_drawloading )
|
|
{
|
|
#if defined( _DEMO ) && defined( _X360 )
|
|
// allow demo timeouts
|
|
Host_EnableDemoTimeout( true );
|
|
#endif
|
|
|
|
scr_engineevent_loadingstarted = false;
|
|
|
|
EngineVGui()->HideLoadingPlaque();
|
|
|
|
if ( g_pMatchFramework )
|
|
{
|
|
scr_engineevent_loadingstarted = false;
|
|
EngineVGui()->HideLoadingPlaque();
|
|
|
|
KeyValues *kv = new KeyValues( "OnEngineLevelLoadingFinished" );
|
|
if ( gfExtendedError )
|
|
{
|
|
kv->SetInt( "error", gfExtendedError );
|
|
kv->SetString( "reason", gszDisconnectReason );
|
|
}
|
|
|
|
#ifndef NO_TOOLFRAMEWORK
|
|
if ( toolframework->InToolMode() )
|
|
{
|
|
// Make a copy of the message to send to the tools framework
|
|
KeyValues *pToolMsg = kv->MakeCopy();
|
|
|
|
// Notify the active tool that the level has finished loading
|
|
toolframework->PostMessage( pToolMsg );
|
|
pToolMsg->deleteThis();
|
|
}
|
|
#endif
|
|
|
|
g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( kv );
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
else if ( gfExtendedError )
|
|
{
|
|
#if !defined( CSTRIKE15 )
|
|
if ( IsPC() )
|
|
{
|
|
EngineVGui()->ShowErrorMessage();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if ( scr_engineevent_loadingstarted )
|
|
{
|
|
// Keep firing Tick event only between LoadingStarted and LoadingFinished
|
|
g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnEngineLevelLoadingTick" ) );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: This is called every frame, and can also be called explicitly to flush
|
|
// text to the screen.
|
|
//-----------------------------------------------------------------------------
|
|
void SCR_UpdateScreen( void )
|
|
{
|
|
R_StudioCheckReinitLightingCache();
|
|
|
|
// Always force the Gamma Table to be rebuilt. Otherwise,
|
|
// we'll load textures with an all white gamma lookup table.
|
|
V_CheckGamma();
|
|
|
|
// This is a HACK to let things settle for a bit on level start
|
|
// NOTE: If you remove scr_nextdrawtick, remove it from enginetool.cpp too
|
|
if ( scr_nextdrawtick != 0 )
|
|
{
|
|
if ( host_tickcount < scr_nextdrawtick )
|
|
return;
|
|
|
|
scr_nextdrawtick = 0;
|
|
}
|
|
|
|
if ( scr_disabled_for_loading )
|
|
{
|
|
if ( !Host_IsSinglePlayerGame() )
|
|
{
|
|
V_RenderVGuiOnly();
|
|
}
|
|
|
|
// Put this here to avoid a crappy alt+tab situation:
|
|
// 1. g_LostVideoMemory is only cleared if we can call CheckDeviceLost
|
|
// 2. CheckDeviceLost can only get called if we present
|
|
// 3. Present can only get called in SCR_UpdateScreen if scr_disabled_for_loading is cleared
|
|
// 4. scr_disabled_for_loading can only be cleared if we disable the loading plaque
|
|
// 5. The loading plaque can only be disabled if we get a call to CL_FullyConnected
|
|
// 6. CL_FullyConnected only gets called if we get a snapshot from the server
|
|
// 7. In single player we only send snapshots if g_LostVideoMemory is cleared
|
|
// 8. goto step 1
|
|
if ( !IsGameConsole() && g_LostVideoMemory )
|
|
{
|
|
Shader_SwapBuffers();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( !scr_initialized || !con_initialized )
|
|
{
|
|
// not initialized yet
|
|
return;
|
|
}
|
|
|
|
// Let demo system overwrite view origin/angles during playback
|
|
if ( demoplayer->IsPlayingBack() )
|
|
{
|
|
demoplayer->InterpolateViewpoint();
|
|
}
|
|
|
|
materials->BeginFrame( host_frametime );
|
|
|
|
CMatRenderContextPtr pRenderContext;
|
|
pRenderContext.GetFrom( materials );
|
|
|
|
pRenderContext->RenderScaleformSlot(SF_RESERVED_BEGINFRAME_SLOT);
|
|
|
|
|
|
if( EngineVGui()->IsGameUIVisible() || IsSteam3ClientGameOverlayActive() )
|
|
{
|
|
pRenderContext->AntiAliasingHint( AA_HINT_MENU );
|
|
}
|
|
|
|
if ( pRenderContext->GetCallQueue() )
|
|
{
|
|
pRenderContext->GetCallQueue()->QueueCall( g_pMDLCache, &IMDLCache::BeginCoarseLock );
|
|
}
|
|
pRenderContext.SafeRelease();
|
|
|
|
EngineVGui()->Simulate();
|
|
|
|
{
|
|
CMatRenderContextPtr pRenderContext( materials );
|
|
PIXEVENT( pRenderContext, "framestagenotify" );
|
|
ClientDLL_FrameStageNotify( FRAME_RENDER_START );
|
|
}
|
|
|
|
Host_BeginThreadedSound();
|
|
|
|
// Simulation meant to occur before any views are rendered
|
|
// This needs to happen before the client DLL is called because the client DLL depends on
|
|
// some of the setup in FRAME_RENDER_START.
|
|
g_EngineRenderer->FrameBegin();
|
|
toolframework->RenderFrameBegin();
|
|
|
|
GetBaseLocalClient().UpdateAreaBits_BackwardsCompatible();
|
|
|
|
Shader_BeginRendering();
|
|
|
|
// Draw world, etc.
|
|
V_RenderView();
|
|
|
|
pRenderContext.GetFrom( materials );
|
|
pRenderContext->RenderScaleformSlot(SF_RESERVED_ENDFRAME_SLOT);
|
|
pRenderContext.SafeRelease();
|
|
|
|
CL_TakeSnapshotAndSwap();
|
|
|
|
ClientDLL_FrameStageNotify( FRAME_RENDER_END );
|
|
|
|
toolframework->RenderFrameEnd();
|
|
|
|
g_EngineRenderer->FrameEnd();
|
|
|
|
pRenderContext.GetFrom( materials );
|
|
if ( pRenderContext->GetCallQueue() )
|
|
{
|
|
pRenderContext->GetCallQueue()->QueueCall( g_pMDLCache, &IMDLCache::EndCoarseLock );
|
|
}
|
|
pRenderContext.SafeRelease();
|
|
|
|
materials->EndFrame();
|
|
|
|
#if !defined( _CERT )
|
|
PublishAllMiniProfilers( g_cv_miniprofiler_dump.GetInt() );
|
|
#if defined( _X360 )
|
|
if ( g_started_frame_pcm )
|
|
{
|
|
g_started_frame_pcm = false;
|
|
PMCStopAndReport();
|
|
}
|
|
if ( g_cv_frame_pcm.GetInt() )
|
|
{
|
|
g_cv_frame_pcm.SetValue("0");
|
|
g_started_frame_pcm = true;
|
|
PMCInstallAndStart(ePMCSetup(PMC_SETUP_OVERVIEW_PB0T0 + GetCurrentProcessorNumber()));
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
// NOTE: It isn't super awesome to do this here, but it has to occur after
|
|
// the client DLL where it knows its read in all entities, which happens in
|
|
// ClientDLL_FrameStageNotify( FRAME_RENDER_START )
|
|
#ifndef DEDICATED
|
|
if ( IsPC() )
|
|
{
|
|
static bool s_bTestedBuildCubemaps = false;
|
|
CClientState &cl = GetBaseLocalClient();
|
|
if ( !s_bTestedBuildCubemaps && cl.IsActive() )
|
|
{
|
|
s_bTestedBuildCubemaps = true;
|
|
|
|
int i;
|
|
if( (i = CommandLine()->FindParm( "-buildcubemaps" )) != 0 )
|
|
{
|
|
int numIterations = 1;
|
|
if( CommandLine()->ParmCount() > i + 1 )
|
|
{
|
|
numIterations = atoi( CommandLine()->GetParm(i+1) );
|
|
}
|
|
if( numIterations == 0 )
|
|
{
|
|
numIterations = 1;
|
|
}
|
|
char cmd[ 1024 ] = { 0 };
|
|
V_snprintf( cmd, sizeof( cmd ), "buildcubemaps %u;quit\n", numIterations );
|
|
Cbuf_AddText( Cbuf_GetCurrentPlayer(), cmd );
|
|
}
|
|
else if( CommandLine()->FindParm( "-buildmodelforworld" ) )
|
|
{
|
|
Cbuf_AddText( Cbuf_GetCurrentPlayer(), "buildmodelforworld;quit\n" );
|
|
}
|
|
else if( CommandLine()->FindParm( "-navanalyze" ) )
|
|
{
|
|
Cbuf_AddText( Cbuf_GetCurrentPlayer(), "sv_cheats 1;nav_edit 1;nav_analyze_scripted\n" );
|
|
}
|
|
else if( CommandLine()->FindParm( "-navforceanalyze" ) )
|
|
{
|
|
Cbuf_AddText( Cbuf_GetCurrentPlayer(), "sv_cheats 1;nav_edit 1;nav_analyze_scripted force\n" );
|
|
}
|
|
else if ( CommandLine()->FindParm("-exit") )
|
|
{
|
|
Cbuf_AddText( Cbuf_GetCurrentPlayer(), "quit\n" );
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|