//========= Copyright 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 "ivguicenterprint.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 "tier0/vcrmode.h"
#include "con_nprint.h"
#include "sys_mainwind.h"
#include "ivideomode.h"
#include "lightcache.h"
#include "toolframework/itoolframework.h"
#include "matchmaking.h"
#include "datacache/idatacache.h"
#include "sys_dll.h"
#if defined( REPLAY_ENABLED )
#include "replay_internal.h"
#endif
#include "tier0/vprof.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

// In other C files.
extern bool V_CheckGamma( void );
extern void	V_RenderView( void );
extern void V_RenderVGuiOnly( void );

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

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void SCR_Init (void)
{
	scr_initialized = true;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void SCR_Shutdown( void )
{
	scr_initialized = false;
}

//-----------------------------------------------------------------------------
// Purpose: starts loading
//-----------------------------------------------------------------------------
void SCR_BeginLoadingPlaque( void )
{
	if ( !scr_drawloading )
	{
		// 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_OnLoadScreen( true );

		g_pFileSystem->AsyncFinishAll();
		g_pMDLCache->FinishPendingLoads();

		// redraw with no console and the loading plaque
		Con_ClearNotify();
		SCR_CenterStringOff();

		// NULL HudText clears HudMessage system
		if ( g_ClientDLL )
		{
			g_ClientDLL->HudText( NULL );
		}

		// let the UI know we're starting loading
		EngineVGui()->OnLevelLoadingStarted();

		// 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 = cl.GetFrameTime();

		scr_disabled_for_loading = true;
	}
}

//-----------------------------------------------------------------------------
// Purpose: finished loading
//-----------------------------------------------------------------------------
void SCR_EndLoadingPlaque( void )
{
	if ( scr_drawloading )
	{
		// let the UI know we're finished
		EngineVGui()->OnLevelLoadingFinished();
		S_OnLoadScreen( false );
	}
	else if ( gfExtendedError )
	{
		if ( IsPC() )
		{
			EngineVGui()->ShowErrorMessage();
		}
	}

	g_pMatchmaking->OnLevelLoadingFinished();

	scr_disabled_for_loading = false;
	scr_drawloading = false;
}

//-----------------------------------------------------------------------------
// Places TCR required defective media message and halts 
//-----------------------------------------------------------------------------
#ifdef _XBOX
void SCR_FatalDiskError()
{
	EngineVGui()->OnDiskError();
	while ( 1 )
	{
		// run the minimal frame to update and paint
		EngineVGui()->Simulate();
		V_RenderVGuiOnly();
	}
}
#endif

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void SCR_CenterPrint (char *str)
{
	if ( !centerprint )
		return;

	centerprint->ColorPrint( 255, 255, 255, 0, str );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void SCR_CenterStringOff( void )
{
	if ( !centerprint )
		return;

	centerprint->Clear();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
inline void SCR_ShowVCRPlaybackAmount()
{
	if ( VCRGetMode() != VCR_Playback || !g_bShowVCRPlaybackDisplay )
		return;

	con_nprint_t info;
	info.index = 20;
	info.time_to_live = 0.01;
	info.color[0] = info.color[1] = info.color[2] = 1;
	info.fixed_width_font = false;

	double flCurPercent = VCRGetPercentCompleted();
	Con_NXPrintf( &info, "VCR Playback: %.2f percent, frame %d", flCurPercent * 100.0, host_framecount );
	info.index++;

	Con_NXPrintf( &info, "'+' to speed up, '-' to slow down [current sleep: %d]", g_iVCRPlaybackSleepInterval );
	info.index++;
	
	Con_NXPrintf( &info, "'p' to pause, 's' to single step, 'r' to resume" );
	info.index++;
	
	Con_NXPrintf( &info, "'d' to toggle this display" );
	info.index++;
	
	Con_NXPrintf( &info, "'q' to quit" );
}

//-----------------------------------------------------------------------------
// Purpose: This is called every frame, and can also be called explicitly to flush
//  text to the screen.
//-----------------------------------------------------------------------------
void SCR_UpdateScreen( void )
{
	tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );

	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();
		}
		return;
	}

	if ( !scr_initialized || !con_initialized )
	{
		// not initialized yet
		return;				
	}

	SCR_ShowVCRPlaybackAmount();

	// Let demo system overwrite view origin/angles during playback
	if ( demoplayer->IsPlayingBack() )
	{
		demoplayer->InterpolateViewpoint();
	}

	materials->BeginFrame( host_frametime );
	{
		tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "EngineVGui_Simulate" );
		EngineVGui()->Simulate();
	}

	ClientDLL_FrameStageNotify( FRAME_RENDER_START );

	// 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.
	{
		tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "FrameBegin" );
	
		g_EngineRenderer->FrameBegin();
		toolframework->RenderFrameBegin();
	}

	cl.UpdateAreaBits_BackwardsCompatible();
	
	Shader_BeginRendering();
				
	// Draw world, etc.
	V_RenderView();

	CL_TakeSnapshotAndSwap();	   
	
#if defined( REPLAY_ENABLED )
	if ( g_pReplay )
	{
		g_pReplay->CL_Render();
	}
#endif

	ClientDLL_FrameStageNotify( FRAME_RENDER_END );

	{
		tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "FrameEnd" );

		toolframework->RenderFrameEnd();

		g_EngineRenderer->FrameEnd();
	}

	// moved dynamic model update here because this takes the materials lock
	// and materials->EndFrame() is where we will synchronize anyway.
	// Moved here to leave as much of the frame as possible to overlap threads in the case
	// where we actually have models to load here
	{
		tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "modelloader->UpdateDynamicModels" );
		VPROF( "UpdateDynamicModels" );
		CMDLCacheCriticalSection critsec( g_pMDLCache );
		modelloader->UpdateDynamicModels();
	}

	{
		tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "materials_EndFrame" );

		materials->EndFrame();
	}
}