//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Implements all the functions exported by the GameUI dll // // $NoKeywords: $ //===========================================================================// #include "client_pch.h" #include "tier0/platform.h" #ifdef IS_WINDOWS_PC #include "winlite.h" #endif #include "appframework/ilaunchermgr.h" #include #include #include #include #include #include "keys.h" #include "console.h" #include "gl_matsysiface.h" #include "cdll_engine_int.h" #include "demo.h" #include "sys_dll.h" #include "sound.h" #include "soundflags.h" #include "filesystem_engine.h" #include "igame.h" #include "con_nprint.h" #include "vgui_DebugSystemPanel.h" #include "tier0/vprof.h" #include "cl_demoactionmanager.h" #include "enginebugreporter.h" #include "engineperftools.h" #include "icolorcorrectiontools.h" #include "tier0/icommandline.h" #include "client.h" #include "server.h" #include "sys.h" // Sys_GetRegKeyValue() #include "vgui_drawtreepanel.h" #include "vgui_vprofpanel.h" #include "vgui/VGUI.h" #include "vgui/IInput.h" #include #include "vgui_controls/AnimationController.h" #include "vgui_vprofgraphpanel.h" #include "vgui_texturebudgetpanel.h" #include "vgui_budgetpanel.h" #include "ivideomode.h" #include "sourcevr/isourcevirtualreality.h" #include "cl_pluginhelpers.h" #include "cl_main.h" // CL_IsHL2Demo() #include "cl_steamauth.h" // interface to gameui dll #include #include // interface to expose vgui root panels #include #include "VGuiMatSurface/IMatSystemSurface.h" #include "cl_texturelistpanel.h" #include "cl_demouipanel.h" #include "cl_foguipanel.h" #include "cl_txviewpanel.h" // vgui2 interface // note that GameUI project uses ..\public\vgui and ..\public\vgui_controls, not ..\utils\vgui\include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "IVguiModule.h" #include "vgui_baseui_interface.h" #include "vgui_DebugSystemPanel.h" #include "toolframework/itoolframework.h" #include "filesystem/IQueuedLoader.h" #if defined( _X360 ) #include "xbox/xbox_win32stubs.h" #endif #include "vgui_askconnectpanel.h" #if defined( REPLAY_ENABLED ) #include "replay_internal.h" #endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" #ifndef USE_SDL extern HWND *pmainwindow; #endif extern IVEngineClient *engineClient; extern bool g_bTextMode; static int g_syncReportLevel = -1; void VGui_ActivateMouse(); extern CreateInterfaceFn g_AppSystemFactory; // functions to reference GameUI and GameConsole functions, from GameUI.dll IGameUI *staticGameUIFuncs = NULL; IGameConsole *staticGameConsole = NULL; // cache some of the state we pass through to matsystemsurface, for visibility bool s_bWindowsInputEnabled = true; ConVar r_drawvgui( "r_drawvgui", "1", FCVAR_CHEAT, "Enable the rendering of vgui panels" ); ConVar gameui_xbox( "gameui_xbox", "0", 0 ); void Con_CreateConsolePanel( vgui::Panel *parent ); void CL_CreateEntityReportPanel( vgui::Panel *parent ); void ClearIOStates( void ); // turn this on if you're tuning progress bars //#define ENABLE_LOADING_PROGRESS_PROFILING //----------------------------------------------------------------------------- // Purpose: Console command to hide the gameUI, most commonly called from gameUI.dll //----------------------------------------------------------------------------- CON_COMMAND( gameui_hide, "Hides the game UI" ) { EngineVGui()->HideGameUI(); } //----------------------------------------------------------------------------- // Purpose: Console command to activate the gameUI, most commonly called from gameUI.dll //----------------------------------------------------------------------------- CON_COMMAND( gameui_activate, "Shows the game UI" ) { EngineVGui()->ActivateGameUI(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CON_COMMAND( gameui_preventescape, "Escape key doesn't hide game UI" ) { EngineVGui()->SetNotAllowedToHideGameUI( true ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CON_COMMAND( gameui_allowescapetoshow, "Escape key allowed to show game UI" ) { EngineVGui()->SetNotAllowedToShowGameUI( false ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CON_COMMAND( gameui_preventescapetoshow, "Escape key doesn't show game UI" ) { EngineVGui()->SetNotAllowedToShowGameUI( true ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CON_COMMAND( gameui_allowescape, "Escape key allowed to hide game UI" ) { EngineVGui()->SetNotAllowedToHideGameUI( false ); } //----------------------------------------------------------------------------- // Purpose: Console command to enable progress bar for next load //----------------------------------------------------------------------------- void BaseUI_ProgressEnabled_f() { EngineVGui()->EnabledProgressBarForNextLoad(); } static ConCommand progress_enable("progress_enable", &BaseUI_ProgressEnabled_f ); //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class CEnginePanel : public vgui::EditablePanel { typedef vgui::EditablePanel BaseClass; public: CEnginePanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName ) { //m_bCanFocus = true; SetMouseInputEnabled( true ); SetKeyBoardInputEnabled( true ); } void EnableMouseFocus( bool state ) { //m_bCanFocus = state; SetMouseInputEnabled( state ); SetKeyBoardInputEnabled( state ); } /* virtual vgui::VPANEL IsWithinTraverse(int x, int y, bool traversePopups) { if ( !m_bCanFocus ) return NULL; vgui::VPANEL retval = BaseClass::IsWithinTraverse( x, y, traversePopups ); if ( retval == GetVPanel() ) return NULL; return retval; }*/ //private: // bool m_bCanFocus; }; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class CStaticPanel : public vgui::Panel { typedef vgui::Panel BaseClass; public: CStaticPanel( vgui::Panel *pParent, const char *pName ) : vgui::Panel( pParent, pName ) { SetCursor( vgui::dc_none ); SetKeyBoardInputEnabled( false ); SetMouseInputEnabled( false ); } }; vgui::VPanelHandle g_DrawTreeSelectedPanel; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class CFocusOverlayPanel : public vgui::Panel { typedef vgui::Panel BaseClass; public: CFocusOverlayPanel( vgui::Panel *pParent, const char *pName ); virtual void PostChildPaint( void ); static void GetColorForSlot( int slot, int& r, int& g, int& b ) { r = (int)( 124.0 + slot * 47.3 ) & 255; g = (int)( 63.78 - slot * 71.4 ) & 255; b = (int)( 188.42 + slot * 13.57 ) & 255; } bool DrawTitleSafeOverlay( void ); bool DrawFocusPanelList( void ); }; //----------------------------------------------------------------------------- // // Purpose: Centerpoint for handling all user interface in the engine // //----------------------------------------------------------------------------- class CEngineVGui : public IEngineVGuiInternal { public: CEngineVGui(); ~CEngineVGui(); // Methods of IEngineVGui virtual vgui::VPANEL GetPanel( VGuiPanel_t type ); // Methods of IEngineVGuiInternal virtual void Init(); virtual void Connect(); virtual void Shutdown(); virtual bool SetVGUIDirectories(); virtual bool IsInitialized() const; virtual bool Key_Event( const InputEvent_t &event ); virtual void UpdateButtonState( const InputEvent_t &event ); virtual void BackwardCompatibility_Paint(); virtual void Paint( PaintMode_t mode ); virtual void PostInit(); CreateInterfaceFn GetGameUIFactory() { return m_GameUIFactory; } // handlers for game UI (main menu) virtual void ActivateGameUI(); virtual bool HideGameUI(); virtual bool IsGameUIVisible(); // console virtual void ShowConsole(); virtual void HideConsole(); virtual bool IsConsoleVisible(); virtual void ClearConsole(); // level loading virtual void OnLevelLoadingStarted(); virtual void OnLevelLoadingFinished(); virtual void NotifyOfServerConnect(const char *game, int IP, int connectionPort, int queryPort); virtual void NotifyOfServerDisconnect(); virtual void UpdateProgressBar(LevelLoadingProgress_e progress); virtual void UpdateCustomProgressBar( float progress, const wchar_t *desc ); virtual void StartCustomProgress(); virtual void FinishCustomProgress(); virtual void EnabledProgressBarForNextLoad() { m_bShowProgressDialog = true; } // Should pause? virtual bool ShouldPause(); virtual void ShowErrorMessage(); virtual void SetNotAllowedToHideGameUI( bool bNotAllowedToHide ) { m_bNotAllowedToHideGameUI = bNotAllowedToHide; } virtual void SetNotAllowedToShowGameUI( bool bNotAllowedToShow ) { m_bNotAllowedToShowGameUI = bNotAllowedToShow; } void SetGameDLLPanelsVisible( bool show ) { if ( !staticGameDLLPanel ) { return; } staticGameDLLPanel->SetVisible( show ); } virtual void ShowNewGameDialog( int chapter = -1 ); // -1 means just keep the currently select chapter // Xbox 360 virtual void SessionNotification( const int notification, const int param = 0 ); virtual void SystemNotification( const int notification ); virtual void ShowMessageDialog( const uint nType, vgui::Panel *pOwner = NULL ); virtual void UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost ); virtual void SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping ); virtual void OnCreditsFinished( void ); // Storage device validation: // returns true right away if storage device has been previously selected. // otherwise returns false and will set the variable pointed by pStorageDeviceValidated to 1 // once the storage device is selected by user. virtual bool ValidateStorageDevice( int *pStorageDeviceValidated ); void SetProgressBias( float bias ); void UpdateProgressBar( float progress ); virtual void ConfirmQuit( void ); private: vgui::Panel *GetRootPanel( VGuiPanel_t type ); void SetEngineVisible( bool state ); void DrawMouseFocus( void ); void CreateVProfPanels( vgui::Panel *pParent ); void DestroyVProfPanels( ); virtual void Simulate(); // debug overlays bool IsDebugSystemVisible(); void HideDebugSystem(); bool IsShiftKeyDown(); bool IsAltKeyDown(); bool IsCtrlKeyDown(); CON_COMMAND_MEMBER_F( CEngineVGui, "debugsystemui", ToggleDebugSystemUI, "Show/hide the debug system UI.", FCVAR_CHEAT ); private: enum { MAX_NUM_FACTORIES = 5 }; CreateInterfaceFn m_FactoryList[MAX_NUM_FACTORIES]; int m_iNumFactories; CSysModule *m_hStaticGameUIModule; CreateInterfaceFn m_GameUIFactory; // top level VGUI2 panel CStaticPanel *staticPanel; // base level panels for other subsystems, rooted on staticPanel CEnginePanel *staticClientDLLPanel; CEnginePanel *staticClientDLLToolsPanel; CEnginePanel *staticGameUIPanel; CEnginePanel *staticGameDLLPanel; // Want engine tools to be on top of other engine panels CEnginePanel *staticEngineToolsPanel; CDebugSystemPanel *staticDebugSystemPanel; CFocusOverlayPanel *staticFocusOverlayPanel; #ifdef VPROF_ENABLED CVProfPanel *m_pVProfPanel; CBudgetPanelEngine *m_pBudgetPanel; CTextureBudgetPanel *m_pTextureBudgetPanel; #endif // progress bar bool m_bShowProgressDialog; LevelLoadingProgress_e m_eLastProgressPoint; // progress bar debugging int m_nLastProgressPointRepeatCount; double m_flLoadingStartTime; struct LoadingProgressEntry_t { double flTime; LevelLoadingProgress_e eProgress; }; CUtlVector m_LoadingProgress; bool m_bSaveProgress : 1; bool m_bNoShaderAPI : 1; // game ui hiding control bool m_bNotAllowedToHideGameUI : 1; bool m_bNotAllowedToShowGameUI : 1; vgui::IInputInternal *m_pInputInternal; // used to start the progress from an arbitrary position float m_ProgressBias; }; //----------------------------------------------------------------------------- // Purpose: singleton accessor //----------------------------------------------------------------------------- static CEngineVGui g_EngineVGuiImp; EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineVGui, IEngineVGui, VENGINE_VGUI_VERSION, g_EngineVGuiImp ); IEngineVGuiInternal *EngineVGui() { return &g_EngineVGuiImp; } //----------------------------------------------------------------------------- // The loader progress is updated by the queued loader. It uses an initial // reserved portion of the bar. //----------------------------------------------------------------------------- #define PROGRESS_RESERVE 0.50f class CLoaderProgress : public ILoaderProgress { public: CLoaderProgress() { // initialize to disabled state m_SnappedProgress = -1; } void BeginProgress() { g_EngineVGuiImp.SetProgressBias( 0 ); m_SnappedProgress = 0; } void UpdateProgress( float progress ) { if ( m_SnappedProgress == - 1 ) { // not enabled return; } int snappedProgress = progress * 15; // Need excessive updates on the 360 to keep the XBox slider inny bar active if ( !IsX360() && ( snappedProgress <= m_SnappedProgress ) ) { // prevent excessive updates return; } m_SnappedProgress = snappedProgress; // up to reserved g_EngineVGuiImp.UpdateProgressBar( PROGRESS_RESERVE * progress ); } void EndProgress() { // the normal legacy bar now picks up after reserved region g_EngineVGuiImp.SetProgressBias( PROGRESS_RESERVE ); m_SnappedProgress = -1; } private: int m_SnappedProgress; }; static CLoaderProgress s_LoaderProgress; //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- CEngineVGui::CEngineVGui() { staticPanel = NULL; staticClientDLLToolsPanel = NULL; staticClientDLLPanel = NULL; staticGameDLLPanel = NULL; staticGameUIPanel = NULL; staticEngineToolsPanel = NULL; staticDebugSystemPanel = NULL; staticFocusOverlayPanel = NULL; m_hStaticGameUIModule = NULL; m_GameUIFactory = NULL; #ifdef VPROF_ENABLED m_pVProfPanel = NULL; #endif m_bShowProgressDialog = false; m_bSaveProgress = false; m_bNoShaderAPI = false; m_bNotAllowedToHideGameUI = false; m_bNotAllowedToShowGameUI = false; m_pInputInternal = NULL; m_ProgressBias = 0; } //----------------------------------------------------------------------------- // Purpose: Destructor //----------------------------------------------------------------------------- CEngineVGui::~CEngineVGui() { } //----------------------------------------------------------------------------- // add all the base search paths used by VGUI (platform, skins directory, language dirs) //----------------------------------------------------------------------------- bool CEngineVGui::SetVGUIDirectories() { // Legacy, not supported anymore return true; } //----------------------------------------------------------------------------- // Setup the base vgui panels //----------------------------------------------------------------------------- void CEngineVGui::Init() { COM_TimestampedLog( "Loading gameui.dll" ); // load the GameUI dll const char *szDllName = "GameUI"; m_hStaticGameUIModule = g_pFileSystem->LoadModule(szDllName, "EXECUTABLE_PATH", true); // LoadModule() does a GetLocalCopy() call m_GameUIFactory = Sys_GetFactory(m_hStaticGameUIModule); if ( !m_GameUIFactory ) { Error( "Could not load: %s\n", szDllName ); } // get the initialization func staticGameUIFuncs = (IGameUI *)m_GameUIFactory(GAMEUI_INTERFACE_VERSION, NULL); if (!staticGameUIFuncs ) { Error( "Could not get IGameUI interface %s from %s\n", GAMEUI_INTERFACE_VERSION, szDllName ); } if ( IsPC() ) { staticGameConsole = (IGameConsole *)m_GameUIFactory(GAMECONSOLE_INTERFACE_VERSION, NULL); if ( !staticGameConsole ) { Sys_Error( "Could not get IGameConsole interface %s from %s\n", GAMECONSOLE_INTERFACE_VERSION, szDllName ); } } vgui::VGui_InitMatSysInterfacesList( "BaseUI", &g_AppSystemFactory, 1 ); // Get our langauge string char lang[ 64 ]; lang[0] = 0; engineClient->GetUILanguage( lang, sizeof( lang ) ); if ( lang[0] ) vgui::system()->SetRegistryString( "HKEY_CURRENT_USER\\Software\\Valve\\Source\\Language", lang ); COM_TimestampedLog( "AttachToWindow" ); // Need to be able to play sounds through vgui g_pMatSystemSurface->InstallPlaySoundFunc( VGui_PlaySound ); COM_TimestampedLog( "Load Scheme File" ); // load scheme const char *pStr = "Resource/SourceScheme.res"; if ( !vgui::scheme()->LoadSchemeFromFile( pStr, "Tracker" )) { Sys_Error( "Error loading file %s\n", pStr ); return; } if ( IsX360() ) { CCommand ccommand; if ( CL_ShouldLoadBackgroundLevel( ccommand ) ) { // Must be before the game ui base panel starts up // This is a hint to avoid the menu pop due to the impending background map // that the game ui is not aware of until 1 frame later. staticGameUIFuncs->SetProgressOnStart(); } } COM_TimestampedLog( "vgui::ivgui()->Start()" ); // Start the App running vgui::ivgui()->Start(); vgui::ivgui()->SetSleep(false); // setup base panel for the whole VGUI System // The root panel for everything ( NULL parent makes it a child of the embedded panel ) // Ideal hierarchy: COM_TimestampedLog( "Building Panels (staticPanel)" ); // Root -- staticPanel // staticBackgroundImagePanel (from gamui) zpos == 0 // staticClientDLLPanel ( zpos == 25 ) // staticClientDLLToolsPanel ( zpos == 28 // staticGameDLLPanel ( zpos == 30 ) // staticEngineToolsPanel ( zpos == 75 ) // staticGameUIPanel ( GameUI stuff ) ( zpos == 100 ) // staticDebugSystemPanel ( Engine debug stuff ) zpos == 125 ) staticPanel = new CStaticPanel( NULL, "staticPanel" ); staticPanel->SetBounds( 0, 0, videomode->GetModeUIWidth(), videomode->GetModeUIHeight() ); staticPanel->SetPaintBorderEnabled(false); staticPanel->SetPaintBackgroundEnabled(false); staticPanel->SetPaintEnabled(false); staticPanel->SetVisible(true); staticPanel->SetCursor( vgui::dc_none ); staticPanel->SetZPos(0); staticPanel->SetVisible(true); staticPanel->SetParent( vgui::surface()->GetEmbeddedPanel() ); COM_TimestampedLog( "Building Panels (staticClientDLLPanel)" ); staticClientDLLPanel = new CEnginePanel( staticPanel, "staticClientDLLPanel" ); staticClientDLLPanel->SetBounds( 0, 0, videomode->GetModeUIWidth(), videomode->GetModeUIHeight() ); staticClientDLLPanel->SetPaintBorderEnabled(false); staticClientDLLPanel->SetPaintBackgroundEnabled(false); staticClientDLLPanel->SetKeyBoardInputEnabled( false ); // popups in the client DLL can enable this. staticClientDLLPanel->SetPaintEnabled(false); staticClientDLLPanel->SetVisible( false ); staticClientDLLPanel->SetCursor( vgui::dc_none ); staticClientDLLPanel->SetZPos( 25 ); CreateAskConnectPanel( staticPanel->GetVPanel() ); COM_TimestampedLog( "Building Panels (staticClientDLLToolsPanel)" ); staticClientDLLToolsPanel = new CEnginePanel( staticPanel, "staticClientDLLToolsPanel" ); staticClientDLLToolsPanel->SetBounds( 0, 0, videomode->GetModeUIWidth(), videomode->GetModeUIHeight() ); staticClientDLLToolsPanel->SetPaintBorderEnabled(false); staticClientDLLToolsPanel->SetPaintBackgroundEnabled(false); staticClientDLLToolsPanel->SetKeyBoardInputEnabled( false ); // popups in the client DLL can enable this. staticClientDLLToolsPanel->SetPaintEnabled(false); staticClientDLLToolsPanel->SetVisible( true ); staticClientDLLToolsPanel->SetCursor( vgui::dc_none ); staticClientDLLToolsPanel->SetZPos( 28 ); staticEngineToolsPanel = new CEnginePanel( staticPanel, "Engine Tools" ); staticEngineToolsPanel->SetBounds( 0, 0, videomode->GetModeUIWidth(), videomode->GetModeUIHeight() ); staticEngineToolsPanel->SetPaintBorderEnabled(false); staticEngineToolsPanel->SetPaintBackgroundEnabled(false); staticEngineToolsPanel->SetPaintEnabled(false); staticEngineToolsPanel->SetVisible( true ); staticEngineToolsPanel->SetCursor( vgui::dc_none ); staticEngineToolsPanel->SetZPos( 75 ); COM_TimestampedLog( "Building Panels (staticGameUIPanel)" ); staticGameUIPanel = new CEnginePanel( staticPanel, "GameUI Panel" ); staticGameUIPanel->SetBounds( 0, 0, videomode->GetModeUIWidth(), videomode->GetModeUIHeight() ); staticGameUIPanel->SetPaintBorderEnabled(false); staticGameUIPanel->SetPaintBackgroundEnabled(false); staticGameUIPanel->SetPaintEnabled(false); staticGameUIPanel->SetVisible( true ); staticGameUIPanel->SetCursor( vgui::dc_none ); staticGameUIPanel->SetZPos( 100 ); staticGameDLLPanel = new CEnginePanel( staticPanel, "staticGameDLLPanel" ); staticGameDLLPanel->SetBounds( 0, 0, videomode->GetModeUIWidth(), videomode->GetModeUIHeight() ); staticGameDLLPanel->SetPaintBorderEnabled(false); staticGameDLLPanel->SetPaintBackgroundEnabled(false); staticGameDLLPanel->SetKeyBoardInputEnabled( false ); // popups in the game DLL can enable this. staticGameDLLPanel->SetPaintEnabled(false); staticGameDLLPanel->SetCursor( vgui::dc_none ); staticGameDLLPanel->SetZPos( 135 ); if ( CommandLine()->CheckParm( "-tools" ) != NULL ) { staticGameDLLPanel->SetVisible( true ); } else { staticGameDLLPanel->SetVisible( false ); } if ( IsPC() ) { COM_TimestampedLog( "Building Panels (staticDebugSystemPanel)" ); staticDebugSystemPanel = new CDebugSystemPanel( staticPanel, "Engine Debug System" ); staticDebugSystemPanel->SetZPos( 125 ); // Install demo playback/editing UI CDemoUIPanel::InstallDemoUI( staticEngineToolsPanel ); CDemoUIPanel2::Install( staticClientDLLPanel, staticEngineToolsPanel, true ); // Install fog control panel UI CFogUIPanel::InstallFogUI( staticEngineToolsPanel ); // Install texture view panel TxViewPanel::Install( staticEngineToolsPanel ); COM_TimestampedLog( "Install bug reporter" ); // Create and initialize bug reporting system bugreporter->InstallBugReportingUI( staticGameUIPanel, IEngineBugReporter::BR_AUTOSELECT ); bugreporter->Init(); COM_TimestampedLog( "Install perf tools" ); // Create a performance toolkit system perftools->InstallPerformanceToolsUI( staticEngineToolsPanel ); perftools->Init(); // Create a color correction UI colorcorrectiontools->InstallColorCorrectionUI( staticEngineToolsPanel ); colorcorrectiontools->Init(); } // Make sure this is on top of everything staticFocusOverlayPanel = new CFocusOverlayPanel( staticPanel, "FocusOverlayPanel" ); staticFocusOverlayPanel->SetBounds( 0, 0, videomode->GetModeUIWidth(), videomode->GetModeUIHeight() ); staticFocusOverlayPanel->SetZPos( 150 ); staticFocusOverlayPanel->MoveToFront(); // Create engine vgui panels if ( IsPC() ) { Con_CreateConsolePanel( staticEngineToolsPanel ); CL_CreateEntityReportPanel( staticEngineToolsPanel ); VGui_CreateDrawTreePanel( staticEngineToolsPanel ); CL_CreateTextureListPanel( staticEngineToolsPanel ); CreateVProfPanels( staticEngineToolsPanel ); } staticEngineToolsPanel->LoadControlSettings( "scripts/EngineVGuiLayout.res" ); COM_TimestampedLog( "materials->CacheUsedMaterials()" ); // Make sure that these materials are in the materials cache materials->CacheUsedMaterials(); COM_TimestampedLog( "g_pVGuiLocalize->AddFile" ); // load the base localization file g_pVGuiLocalize->AddFile( "Resource/valve_%language%.txt" ); COM_TimestampedLog( "staticGameUIFuncs->Initialize" ); staticGameUIFuncs->Initialize( g_AppSystemFactory ); COM_TimestampedLog( "staticGameUIFuncs->Start" ); staticGameUIFuncs->Start(); // don't need to load the "valve" localization file twice // Each mod acn have its own language.txt in addition to the valve_%%langauge%%.txt file under defaultgamedir. // load mod-specific localization file for kb_act.lst, user.scr, settings.scr, etc. char szFileName[MAX_PATH]; Q_snprintf( szFileName, sizeof( szFileName ) - 1, "resource/%s_%%language%%.txt", GetCurrentMod() ); szFileName[ sizeof( szFileName ) - 1 ] = '\0'; g_pVGuiLocalize->AddFile( szFileName ); // setup console if ( staticGameConsole ) { staticGameConsole->Initialize(); staticGameConsole->SetParent(staticGameUIPanel->GetVPanel()); } if ( IsX360() ) { // provide an interface for loader to send progress notifications g_pQueuedLoader->InstallProgress( &s_LoaderProgress ); } // show the game UI COM_TimestampedLog( "ActivateGameUI()" ); ActivateGameUI(); if ( staticGameConsole && !CommandLine()->CheckParm( "-forcestartupmenu" ) && !CommandLine()->CheckParm( "-hideconsole" ) && ( CommandLine()->FindParm( "-toconsole" ) || CommandLine()->FindParm( "-console" ) || CommandLine()->FindParm( "-rpt" ) || CommandLine()->FindParm( "-allowdebug" ) ) ) { // activate the console staticGameConsole->Activate(); } m_bNoShaderAPI = CommandLine()->FindParm( "-noshaderapi" ); } void CEngineVGui::PostInit() { staticGameUIFuncs->PostInit(); #if defined( _X360 ) g_pMatSystemSurface->ClearTemporaryFontCache(); #endif } //----------------------------------------------------------------------------- // Purpose: connects interfaces in gameui //----------------------------------------------------------------------------- void CEngineVGui::Connect() { m_pInputInternal = (vgui::IInputInternal *)g_GameSystemFactory( VGUI_INPUTINTERNAL_INTERFACE_VERSION, NULL ); staticGameUIFuncs->Connect( g_GameSystemFactory ); } //----------------------------------------------------------------------------- // Create/destroy the vprof panels //----------------------------------------------------------------------------- void CEngineVGui::CreateVProfPanels( vgui::Panel *pParent ) { if ( IsX360() ) return; #ifdef VPROF_ENABLED m_pVProfPanel = new CVProfPanel( pParent, "VProfPanel" ); m_pBudgetPanel = new CBudgetPanelEngine( pParent, "BudgetPanel" ); CreateVProfGraphPanel( pParent ); m_pTextureBudgetPanel = new CTextureBudgetPanel( pParent, "TextureBudgetPanel" ); #endif } void CEngineVGui::DestroyVProfPanels( ) { if ( IsX360() ) return; #ifdef VPROF_ENABLED if ( m_pVProfPanel ) { delete m_pVProfPanel; m_pVProfPanel = NULL; } if ( m_pBudgetPanel ) { delete m_pBudgetPanel; m_pBudgetPanel = NULL; } DestroyVProfGraphPanel(); if ( m_pTextureBudgetPanel ) { delete m_pTextureBudgetPanel; m_pTextureBudgetPanel = NULL; } #endif } //----------------------------------------------------------------------------- // Are we initialized? //----------------------------------------------------------------------------- bool CEngineVGui::IsInitialized() const { return staticPanel != NULL; } extern bool g_bUsingLegacyAppSystems; //----------------------------------------------------------------------------- // Purpose: Called to Shutdown the game UI system //----------------------------------------------------------------------------- void CEngineVGui::Shutdown() { if ( IsPC() && CL_IsHL2Demo() ) // if they are playing the demo then open the storefront on shutdown { vgui::system()->ShellExecute("open", "steam://store_demo/220"); } if ( IsPC() && CL_IsPortalDemo() ) // if they are playing the demo then open the storefront on shutdown { vgui::system()->ShellExecute("open", "steam://store_demo/400"); } DestroyVProfPanels(); bugreporter->Shutdown(); colorcorrectiontools->Shutdown(); perftools->Shutdown(); demoaction->Shutdown(); if ( g_PluginManager ) { g_PluginManager->Shutdown(); } // HACK HACK: There was a bug in the old versions of the viewport which would crash in the case where the client .dll hadn't been fully unloaded, so // we'll leak this panel here instead!!! if ( g_bUsingLegacyAppSystems ) { staticClientDLLPanel->SetParent( (vgui::VPANEL)0 ); } // This will delete the engine subpanel since it's a child delete staticPanel; staticPanel = NULL; staticClientDLLToolsPanel = NULL; staticClientDLLPanel = NULL; staticEngineToolsPanel = NULL; staticDebugSystemPanel = NULL; staticFocusOverlayPanel = NULL; staticGameDLLPanel = NULL; // Give panels a chance to settle so things // Marked for deletion will actually get deleted vgui::ivgui()->RunFrame(); // unload the gameUI staticGameUIFuncs->Shutdown(); staticGameUIFuncs = NULL; staticGameConsole = NULL; staticGameUIPanel = NULL; // stop the App running vgui::ivgui()->Stop(); // unload the dll Sys_UnloadModule(m_hStaticGameUIModule); m_hStaticGameUIModule = NULL; m_GameUIFactory = NULL; m_pInputInternal = NULL; } //----------------------------------------------------------------------------- // Purpose: Retrieve specified root panel //----------------------------------------------------------------------------- inline vgui::Panel *CEngineVGui::GetRootPanel( VGuiPanel_t type ) { if ( sv.IsDedicated() ) { return NULL; } switch ( type ) { default: case PANEL_ROOT: return staticPanel; case PANEL_CLIENTDLL: return staticClientDLLPanel; case PANEL_GAMEUIDLL: return staticGameUIPanel; case PANEL_TOOLS: return staticEngineToolsPanel; case PANEL_GAMEDLL: return staticGameDLLPanel; case PANEL_CLIENTDLL_TOOLS: return staticClientDLLToolsPanel; } } vgui::VPANEL CEngineVGui::GetPanel( VGuiPanel_t type ) { return GetRootPanel( type )->GetVPanel(); } //----------------------------------------------------------------------------- // Purpose: Toggle engine panel active/inactive //----------------------------------------------------------------------------- void CEngineVGui::SetEngineVisible( bool state ) { if ( staticClientDLLPanel ) { staticClientDLLPanel->SetVisible( state ); } } //----------------------------------------------------------------------------- // Should pause? //----------------------------------------------------------------------------- bool CEngineVGui::ShouldPause() { if ( IsPC() ) { return bugreporter->ShouldPause() || perftools->ShouldPause(); } return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CEngineVGui::ConfirmQuit() { ActivateGameUI(); staticGameUIFuncs->OnConfirmQuit(); } //----------------------------------------------------------------------------- // Purpose: Shows any GameUI related panels //----------------------------------------------------------------------------- void CEngineVGui::ActivateGameUI() { if ( m_bNotAllowedToShowGameUI ) return; if (!staticGameUIFuncs) return; #if defined( REPLAY_ENABLED ) // Don't allow the game UI to be activated when a replay is being rendered if ( g_pReplayMovieManager && g_pReplayMovieManager->IsRendering() ) return; #endif // clear any keys that might be stuck down ClearIOStates(); staticGameUIPanel->SetVisible(true); staticGameUIPanel->MoveToFront(); staticClientDLLPanel->SetVisible(false); staticClientDLLPanel->SetMouseInputEnabled(false); vgui::surface()->SetCursor( vgui::dc_arrow ); //staticGameDLLPanel->SetVisible( true ); //staticGameDLLPanel->SetMouseInputEnabled( true ); SetEngineVisible( false ); staticGameUIFuncs->OnGameUIActivated(); } //----------------------------------------------------------------------------- // Purpose: Hides an Game UI related features (not client UI stuff tho!) //----------------------------------------------------------------------------- bool CEngineVGui::HideGameUI() { if ( m_bNotAllowedToHideGameUI ) return false; const char *levelName = engineClient->GetLevelName(); bool bInNonBgLevel = levelName && levelName[0] && !engineClient->IsLevelMainMenuBackground(); if ( bInNonBgLevel ) { staticGameUIPanel->SetVisible(false); staticGameUIPanel->SetPaintBackgroundEnabled(false); staticClientDLLPanel->SetVisible(true); staticClientDLLPanel->MoveToFront(); staticClientDLLPanel->SetMouseInputEnabled(true); //staticGameDLLPanel->SetVisible( false ); //staticGameDLLPanel->SetMouseInputEnabled(false); SetEngineVisible( true ); staticGameUIFuncs->OnGameUIHidden(); } else { // Tracker 18820: Pulling up options/console was perma-pausing the background levels, now we // unpause them when you hit the Esc key even though the UI remains... if ( levelName && levelName[0] && ( engineClient->GetMaxClients() <= 1 ) && engineClient->IsPaused() ) { Cbuf_AddText("unpause\n"); } } VGui_MoveDrawTreePanelToFront(); return true; } //----------------------------------------------------------------------------- // Purpose: Hides the game console (but not the complete GameUI!) //----------------------------------------------------------------------------- void CEngineVGui::HideConsole() { if ( IsX360() ) return; if ( staticGameConsole ) { staticGameConsole->Hide(); } } //----------------------------------------------------------------------------- // Purpose: shows the console //----------------------------------------------------------------------------- void CEngineVGui::ShowConsole() { if ( IsX360() ) return; ActivateGameUI(); if ( staticGameConsole ) { staticGameConsole->Activate(); } } //----------------------------------------------------------------------------- // Purpose: returns true if the console is currently open //----------------------------------------------------------------------------- bool CEngineVGui::IsConsoleVisible() { if ( IsPC() ) { return IsGameUIVisible() && staticGameConsole && staticGameConsole->IsConsoleVisible(); } else { // xbox has no drop down console return false; } } //----------------------------------------------------------------------------- // Purpose: clears all text from the console //----------------------------------------------------------------------------- void CEngineVGui::ClearConsole() { if ( staticGameConsole ) { staticGameConsole->Clear(); } } //----------------------------------------------------------------------------- // Purpose: data accessor //----------------------------------------------------------------------------- bool CEngineVGui::IsGameUIVisible() { return staticGameUIPanel && staticGameUIPanel->IsVisible(); } // list of progress bar strings struct LoadingProgressDescription_t { LevelLoadingProgress_e eProgress; // current progress int nPercent; // % of the total time this is at int nRepeat; // number of times this is expected to repeat (usually 0) const char *pszDesc; // user description of progress }; LoadingProgressDescription_t g_ListenServerLoadingProgressDescriptions[] = { { PROGRESS_NONE, 0, 0, NULL }, { PROGRESS_SPAWNSERVER, 2, 0, "#LoadingProgress_SpawningServer" }, { PROGRESS_LOADWORLDMODEL, 4, 7, "#LoadingProgress_LoadMap" }, { PROGRESS_CREATENETWORKSTRINGTABLES, 23, 0, NULL }, { PROGRESS_PRECACHEWORLD, 23, 0, "#LoadingProgress_PrecacheWorld" }, { PROGRESS_CLEARWORLD, 23, 0, NULL }, { PROGRESS_LEVELINIT, 34, 0, "#LoadingProgress_LoadResources" }, { PROGRESS_PRECACHE, 35, 239, NULL }, { PROGRESS_ACTIVATESERVER, 68, 0, NULL }, { PROGRESS_SIGNONCHALLENGE, 68, 0, NULL }, { PROGRESS_SIGNONCONNECT, 70, 0, NULL }, { PROGRESS_SIGNONCONNECTED, 73, 0, "#LoadingProgress_SignonLocal" }, { PROGRESS_PROCESSSERVERINFO, 75, 0, NULL }, { PROGRESS_PROCESSSTRINGTABLE, 77, 12, NULL }, // 16 { PROGRESS_SIGNONNEW, 84, 0, NULL }, { PROGRESS_SENDCLIENTINFO, 88, 0, NULL }, { PROGRESS_SENDSIGNONDATA, 91, 0, "#LoadingProgress_SignonDataLocal" }, { PROGRESS_SIGNONSPAWN, 94, 0, NULL }, { PROGRESS_FULLYCONNECTED, 97, 0, NULL }, { PROGRESS_READYTOPLAY, 99, 0, NULL }, { PROGRESS_HIGHESTITEM, 100, 0, NULL }, }; LoadingProgressDescription_t g_RemoteConnectLoadingProgressDescriptions[] = { { PROGRESS_NONE, 0, 0, NULL }, { PROGRESS_CHANGELEVEL, 1, 0, "#LoadingProgress_Changelevel" }, { PROGRESS_BEGINCONNECT, 5, 0, "#LoadingProgress_BeginConnect" }, { PROGRESS_SIGNONCHALLENGE, 10, 0, "#LoadingProgress_Connecting" }, { PROGRESS_SIGNONCONNECTED, 15, 0, NULL }, { PROGRESS_PROCESSSERVERINFO, 20, 0, "#LoadingProgress_ProcessServerInfo" }, { PROGRESS_PROCESSSTRINGTABLE, 25, 11, NULL }, { PROGRESS_LOADWORLDMODEL, 45, 7, "#LoadingProgress_LoadMap" }, { PROGRESS_SIGNONNEW, 75, 0, NULL }, { PROGRESS_SENDCLIENTINFO, 80, 0, "#LoadingProgress_SendClientInfo" }, { PROGRESS_SENDSIGNONDATA, 85, 0, "#LoadingProgress_SignonData" }, { PROGRESS_SIGNONSPAWN, 90, 0, NULL }, { PROGRESS_FULLYCONNECTED, 95, 0, NULL }, { PROGRESS_READYTOPLAY, 99, 0, NULL }, { PROGRESS_HIGHESTITEM, 100, 0, NULL }, }; static LoadingProgressDescription_t *g_pLoadingProgressDescriptions = NULL; //----------------------------------------------------------------------------- // Purpose: returns current progress point description //----------------------------------------------------------------------------- LoadingProgressDescription_t &GetProgressDescription(int eProgress) { // search for the item in the current list int i = 0; while (g_pLoadingProgressDescriptions[i].eProgress != PROGRESS_HIGHESTITEM) { // find the closest match if (g_pLoadingProgressDescriptions[i].eProgress >= eProgress) return g_pLoadingProgressDescriptions[i]; ++i; } // not found return g_pLoadingProgressDescriptions[0]; } //----------------------------------------------------------------------------- // Purpose: transition handler //----------------------------------------------------------------------------- void CEngineVGui::OnLevelLoadingStarted() { if (!staticGameUIFuncs) return; ConVar *pSyncReportConVar = g_pCVar->FindVar( "fs_report_sync_opens" ); if ( pSyncReportConVar ) { // If convar is set to 2, suppress warnings during level load g_syncReportLevel = pSyncReportConVar->GetInt(); if ( g_syncReportLevel > 1 ) { pSyncReportConVar->SetValue( 0 ); } } if ( IsX360() ) { // TCR requirement, always!!! m_bShowProgressDialog = true; } // we've starting loading a level/connecting to a server staticGameUIFuncs->OnLevelLoadingStarted( m_bShowProgressDialog ); // reset progress bar timers m_flLoadingStartTime = Plat_FloatTime(); m_LoadingProgress.RemoveAll(); m_eLastProgressPoint = PROGRESS_NONE; m_nLastProgressPointRepeatCount = 0; m_ProgressBias = 0; // choose which progress bar to use if (NET_IsMultiplayer()) { // we're connecting g_pLoadingProgressDescriptions = g_RemoteConnectLoadingProgressDescriptions; } else { g_pLoadingProgressDescriptions = g_ListenServerLoadingProgressDescriptions; } if ( m_bShowProgressDialog ) { ActivateGameUI(); } m_bShowProgressDialog = false; } //----------------------------------------------------------------------------- // Purpose: transition handler //----------------------------------------------------------------------------- void CEngineVGui::OnLevelLoadingFinished() { if (!staticGameUIFuncs) return; staticGameUIFuncs->OnLevelLoadingFinished( gfExtendedError, gszDisconnectReason, gszExtendedDisconnectReason ); m_eLastProgressPoint = PROGRESS_NONE; // clear any error message gfExtendedError = false; gszDisconnectReason[0] = 0; gszExtendedDisconnectReason[0] = 0; #if defined(ENABLE_LOADING_PROGRESS_PROFILING) // display progress bar stats (for debugging/tuning progress bar) float flEndTime = (float)Plat_FloatTime(); // add a finished entry LoadingProgressEntry_t &entry = m_LoadingProgress[m_LoadingProgress.AddToTail()]; entry.flTime = flEndTime - m_flLoadingStartTime; entry.eProgress = PROGRESS_HIGHESTITEM; // dump the info Msg("Level load timings:\n"); float flTotalTime = flEndTime - m_flLoadingStartTime; int nRepeatCount = 0; float flTimeTaken = 0.0f; float flFirstLoadProgressTime = 0.0f; for (int i = 0; i < m_LoadingProgress.Count() - 1; i++) { // keep track of time flTimeTaken += (float)m_LoadingProgress[i+1].flTime - m_LoadingProgress[i].flTime; // keep track of how often something is repeated if (m_LoadingProgress[i+1].eProgress == m_LoadingProgress[i].eProgress) { if (nRepeatCount == 0) { flFirstLoadProgressTime = m_LoadingProgress[i].flTime; } ++nRepeatCount; continue; } // work out the time it took to do this if (nRepeatCount == 0) { flFirstLoadProgressTime = m_LoadingProgress[i].flTime; } int nPerc = (int)(100 * (flFirstLoadProgressTime / flTotalTime)); int nTickPerc = (int)(100 * ((float)m_LoadingProgress[i].eProgress / (float)PROGRESS_HIGHESTITEM)); // interpolated percentage is in between the real times and the most ticks int nInterpPerc = (nPerc + nTickPerc) / 2; Msg("\t%d\t%.3f\t\ttime: %d%%\t\tinterp: %d%%\t\trepeat: %d\n", m_LoadingProgress[i].eProgress, flTimeTaken, nPerc, nInterpPerc, nRepeatCount); // reset accumlated vars nRepeatCount = 0; flTimeTaken = 0.0f; } #endif // ENABLE_LOADING_PROGRESS_PROFILING HideGameUI(); // Restore convar setting after level load if ( g_syncReportLevel > 1 ) { ConVar *pSyncReportConVar = g_pCVar->FindVar( "fs_report_sync_opens" ); if ( pSyncReportConVar ) { pSyncReportConVar->SetValue( g_syncReportLevel ); } } } //----------------------------------------------------------------------------- // Purpose: transition handler //----------------------------------------------------------------------------- void CEngineVGui::ShowErrorMessage() { if (!staticGameUIFuncs || !gfExtendedError) return; staticGameUIFuncs->OnLevelLoadingFinished( gfExtendedError, gszDisconnectReason, gszExtendedDisconnectReason ); m_eLastProgressPoint = PROGRESS_NONE; // clear any error message gfExtendedError = false; gszDisconnectReason[0] = 0; gszExtendedDisconnectReason[0] = 0; HideGameUI(); } //----------------------------------------------------------------------------- // Purpose: Updates progress //----------------------------------------------------------------------------- void CEngineVGui::UpdateProgressBar(LevelLoadingProgress_e progress) { if (!staticGameUIFuncs) return; if ( !ThreadInMainThread() ) return; #if defined(ENABLE_LOADING_PROGRESS_PROFILING) // track the progress times, for debugging & tuning LoadingProgressEntry_t &entry = m_LoadingProgress[m_LoadingProgress.AddToTail()]; entry.flTime = Plat_FloatTime() - m_flLoadingStartTime; entry.eProgress = progress; #endif if (!g_pLoadingProgressDescriptions) return; // don't go backwards if (progress < m_eLastProgressPoint) return; // count progress repeats if (progress == m_eLastProgressPoint) { ++m_nLastProgressPointRepeatCount; } else { m_nLastProgressPointRepeatCount = 0; } // construct a string describing it LoadingProgressDescription_t &desc = GetProgressDescription(progress); // calculate partial progress float flPerc = desc.nPercent / 100.0f; if ( desc.nRepeat > 1 && m_nLastProgressPointRepeatCount ) { // cap the repeat count m_nLastProgressPointRepeatCount = min(m_nLastProgressPointRepeatCount, desc.nRepeat); // next progress point float flNextPerc = GetProgressDescription(progress + 1).nPercent / 100.0f; // move along partially towards the next tick flPerc += (flNextPerc - flPerc) * ((float)m_nLastProgressPointRepeatCount / desc.nRepeat); } // the bias allows the loading bar to have an optional reserved initial band // isolated from the normal progress descriptions flPerc = flPerc * ( 1.0f - m_ProgressBias ) + m_ProgressBias; if ( staticGameUIFuncs->UpdateProgressBar( flPerc, desc.pszDesc ) ) { // re-render vgui on screen extern void V_RenderVGuiOnly(); V_RenderVGuiOnly(); } m_eLastProgressPoint = progress; } //----------------------------------------------------------------------------- // Purpose: Updates progress //----------------------------------------------------------------------------- void CEngineVGui::UpdateCustomProgressBar( float progress, const wchar_t *desc ) { if (!staticGameUIFuncs) return; char ansi[1024]; g_pVGuiLocalize->ConvertUnicodeToANSI( desc, ansi, sizeof( ansi ) ); if ( staticGameUIFuncs->UpdateProgressBar( progress, ansi ) ) { // re-render vgui on screen extern void V_RenderVGuiOnly(); V_RenderVGuiOnly(); } } void CEngineVGui::StartCustomProgress() { if (!staticGameUIFuncs) return; // we've starting loading a level/connecting to a server staticGameUIFuncs->OnLevelLoadingStarted(true); m_bSaveProgress = staticGameUIFuncs->SetShowProgressText( true ); } void CEngineVGui::FinishCustomProgress() { if (!staticGameUIFuncs) return; staticGameUIFuncs->SetShowProgressText( m_bSaveProgress ); staticGameUIFuncs->OnLevelLoadingFinished( false, "", "" ); } void CEngineVGui::SetProgressBias( float bias ) { m_ProgressBias = bias; } void CEngineVGui::UpdateProgressBar( float progress ) { if ( !staticGameUIFuncs ) return; if ( staticGameUIFuncs->UpdateProgressBar( progress, "" ) ) { // re-render vgui on screen extern void V_RenderVGuiOnly(); V_RenderVGuiOnly(); } } //----------------------------------------------------------------------------- // Purpose: Returns 1 if the key event is handled, 0 if the engine should handle it //----------------------------------------------------------------------------- void CEngineVGui::UpdateButtonState( const InputEvent_t &event ) { m_pInputInternal->UpdateButtonState( event ); } //----------------------------------------------------------------------------- // Purpose: Returns 1 if the key event is handled, 0 if the engine should handle it //----------------------------------------------------------------------------- bool CEngineVGui::Key_Event( const InputEvent_t &event ) { bool bDown = event.m_nType != IE_ButtonReleased; ButtonCode_t code = (ButtonCode_t)event.m_nData; if ( IsPC() && IsShiftKeyDown() ) { switch( code ) { case KEY_F1: if ( bDown ) { Cbuf_AddText( "debugsystemui" ); } return true; case KEY_F2: if ( bDown ) { Cbuf_AddText( "demoui" ); } return true; } } #if defined( _WIN32 ) // Ignore alt tilde, since the Japanese IME uses this to toggle itself on/off if ( IsPC() && code == KEY_BACKQUOTE && ( IsAltKeyDown() || IsCtrlKeyDown() ) ) return true; #endif // ESCAPE toggles game ui if ( bDown && ( code == KEY_ESCAPE || code == KEY_XBUTTON_START || code == STEAMCONTROLLER_START) && !g_ClientDLL->HandleUiToggle() ) { if ( IsPC() ) { if ( IsGameUIVisible() ) { // Don't allow hiding of the game ui if there's no level const char *pLevelName = engineClient->GetLevelName(); if ( pLevelName && pLevelName[0] ) { Cbuf_AddText( "gameui_hide" ); if ( IsDebugSystemVisible() ) { Cbuf_AddText( "debugsystemui 0" ); } } } else { Cbuf_AddText( "gameui_activate" ); } return true; } if ( IsX360() && !IsGameUIVisible() ) { // 360 UI does not toggle, engine does "show", but UI needs to handle "hide" Cbuf_AddText( "gameui_activate" ); return true; } } if ( g_pMatSystemSurface && g_pMatSystemSurface->HandleInputEvent( event ) ) { // always let the engine handle the console keys // FIXME: Do a lookup of the key bound to toggleconsole // want to cache it off so the lookup happens only when keys are bound? if ( IsPC() && ( code == KEY_BACKQUOTE ) ) return false; return true; } return false; } void CEngineVGui::Simulate() { toolframework->VGui_PreSimulateAllTools(); if ( staticPanel ) { VPROF_BUDGET( "CEngineVGui::Simulate", VPROF_BUDGETGROUP_OTHER_VGUI ); // update vgui animations //!! currently this has to be done once per dll, because the anim controller object is in a lib; //!! need to make it globally pumped (gameUI.dll has it's own version of this) vgui::GetAnimationController()->UpdateAnimations( Sys_FloatTime() ); int w, h; #if defined( USE_SDL ) uint width,height; g_pLauncherMgr->RenderedSize( width, height, false ); // false = get w = width; h = height; #else if ( ::IsIconic( *pmainwindow ) ) { w = videomode->GetModeWidth(); h = videomode->GetModeHeight(); } else { RECT rect; ::GetClientRect(*pmainwindow, &rect); w = rect.right; h = rect.bottom; } #endif // don't hold this reference over RunFrame() { CMatRenderContextPtr pRenderContext( materials ); pRenderContext->Viewport( 0, 0, w, h ); } staticGameUIFuncs->RunFrame(); vgui::ivgui()->RunFrame(); // Some debugging helpers DrawMouseFocus(); VGui_UpdateDrawTreePanel(); VGui_UpdateTextureListPanel(); vgui::surface()->CalculateMouseVisible(); VGui_ActivateMouse(); } // if ( !vgui::ivgui()->IsRunning() ) // Cbuf_AddText( "quit\n" ); toolframework->VGui_PostSimulateAllTools(); } void CEngineVGui::BackwardCompatibility_Paint() { Paint( (PaintMode_t)(PAINT_UIPANELS | PAINT_INGAMEPANELS) ); } //----------------------------------------------------------------------------- // Purpose: paints all the vgui elements //----------------------------------------------------------------------------- void CEngineVGui::Paint( PaintMode_t mode ) { VPROF_BUDGET( "CEngineVGui::Paint", VPROF_BUDGETGROUP_OTHER_VGUI ); if ( !staticPanel ) return; // setup the base panel to cover the screen vgui::VPANEL pVPanel = vgui::surface()->GetEmbeddedPanel(); if ( !pVPanel ) return; bool drawVgui = r_drawvgui.GetBool(); // Don't draw the console at all if vgui is off during a time demo if ( demoplayer->IsPlayingTimeDemo() && !drawVgui ) { return; } if ( !drawVgui || m_bNoShaderAPI ) { return; } // draw from the main panel down vgui::Panel *panel = staticPanel; // Force engine's root panel (staticPanel) to be full screen size { int x, y, w, h; CMatRenderContextPtr pRenderContext( materials ); pRenderContext->GetViewport( x, y, w, h ); panel->SetBounds(0, 0, w, h); // ignore x and y here because the viewport takes care of that } panel->Repaint(); toolframework->VGui_PreRenderAllTools( mode ); // Paint both ( backward compatibility support ) // It's either the full screen, or just the client .dll stuff if ( mode & PAINT_UIPANELS ) { // Hide the client .dll, and paint everything else bool saveVisible = staticClientDLLPanel->IsVisible(); bool saveToolsVisible = staticClientDLLToolsPanel->IsVisible(); staticClientDLLPanel->SetVisible( false ); staticClientDLLToolsPanel->SetVisible( false ); vgui::surface()->PaintTraverseEx(pVPanel, true ); staticClientDLLPanel->SetVisible( saveVisible ); staticClientDLLToolsPanel->SetVisible( saveToolsVisible ); } if ( mode & PAINT_INGAMEPANELS ) { bool bSaveVisible = vgui::ipanel()->IsVisible( pVPanel ); vgui::ipanel()->SetVisible( pVPanel, false ); // Remove the client .dll from the main hierarchy so that popups will only paint for the client .dll here // NOTE: Disconnect each surface one at a time so that we don't draw popups twice // Paint the client .dll only vgui::VPANEL ingameRoot = staticClientDLLPanel->GetVPanel(); vgui::VPANEL saveParent = vgui::ipanel()->GetParent( ingameRoot ); vgui::ipanel()->SetParent( ingameRoot, 0 ); vgui::surface()->PaintTraverseEx( ingameRoot, true ); vgui::ipanel()->SetParent( ingameRoot, saveParent ); // Overlay the client .dll tools next vgui::VPANEL ingameToolsRoot = staticClientDLLToolsPanel->GetVPanel(); vgui::VPANEL saveToolParent = vgui::ipanel()->GetParent( ingameToolsRoot ); vgui::ipanel()->SetParent( ingameToolsRoot, 0 ); vgui::surface()->PaintTraverseEx( ingameToolsRoot, true ); vgui::ipanel()->SetParent( ingameToolsRoot, saveToolParent ); vgui::ipanel()->SetVisible( pVPanel, bSaveVisible ); } if ( mode & PAINT_CURSOR ) { vgui::surface()->PaintSoftwareCursor(); } toolframework->VGui_PostRenderAllTools( mode ); } bool CEngineVGui::IsDebugSystemVisible( void ) { return staticDebugSystemPanel ? staticDebugSystemPanel->IsVisible() : false; } void CEngineVGui::HideDebugSystem( void ) { if ( staticDebugSystemPanel ) { staticDebugSystemPanel->SetVisible( false ); SetEngineVisible( true ); } } void CEngineVGui::ToggleDebugSystemUI( const CCommand &args ) { if ( !staticDebugSystemPanel ) return; bool bVisible; if ( args.ArgC() == 1 ) { // toggle the game UI bVisible = !IsDebugSystemVisible(); } else { bVisible = atoi( args[1] ) != 0; } if ( !bVisible ) { staticDebugSystemPanel->SetVisible( false ); SetEngineVisible( true ); } else { // clear any keys that might be stuck down ClearIOStates(); staticDebugSystemPanel->SetVisible( true ); SetEngineVisible( false ); } } bool CEngineVGui::IsShiftKeyDown( void ) { if ( !vgui::input() ) return false; return vgui::input()->IsKeyDown( KEY_LSHIFT ) || vgui::input()->IsKeyDown( KEY_RSHIFT ); } bool CEngineVGui::IsAltKeyDown( void ) { if ( !vgui::input() ) return false; return vgui::input()->IsKeyDown( KEY_LALT ) || vgui::input()->IsKeyDown( KEY_RALT ); } bool CEngineVGui::IsCtrlKeyDown( void ) { if ( !vgui::input() ) return false; return vgui::input()->IsKeyDown( KEY_LCONTROL ) || vgui::input()->IsKeyDown( KEY_RCONTROL ); } //----------------------------------------------------------------------------- // Purpose: notification //----------------------------------------------------------------------------- void CEngineVGui::NotifyOfServerConnect(const char *pchGame, int IP, int connectionPort, int queryPort) { if (!staticGameUIFuncs) return; staticGameUIFuncs->OnConnectToServer2( pchGame, IP, connectionPort, queryPort); } //----------------------------------------------------------------------------- // Purpose: notification //----------------------------------------------------------------------------- void CEngineVGui::NotifyOfServerDisconnect() { if (!staticGameUIFuncs) return; staticGameUIFuncs->OnDisconnectFromServer( g_eSteamLoginFailure ); g_eSteamLoginFailure = 0; } //----------------------------------------------------------------------------- // Xbox 360: Matchmaking sessions send progress notifications to GameUI //----------------------------------------------------------------------------- void CEngineVGui::SessionNotification( const int notification, const int param ) { staticGameUIFuncs->SessionNotification( notification, param ); } void CEngineVGui::SystemNotification( const int notification ) { staticGameUIFuncs->SystemNotification( notification ); } //----------------------------------------------------------------------------- // Xbox 360: Show a message/error dialog //----------------------------------------------------------------------------- void CEngineVGui::ShowMessageDialog( const uint nType, vgui::Panel *pOwner ) { ActivateGameUI(); staticGameUIFuncs->ShowMessageDialog( nType, pOwner ); } void CEngineVGui::UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost ) { staticGameUIFuncs->UpdatePlayerInfo( nPlayerId, pName, nTeam, cVoiceState, nPlayersNeeded, bHost ); } void CEngineVGui::SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping ) { staticGameUIFuncs->SessionSearchResult( searchIdx, pHostData, pResult, ping ); } //----------------------------------------------------------------------------- // A helper to play sounds through vgui //----------------------------------------------------------------------------- void VGui_PlaySound( const char *pFileName ) { // Point at origin if they didn't specify a sound source. Vector vDummyOrigin; vDummyOrigin.Init(); CSfxTable *pSound = (CSfxTable*)S_PrecacheSound(pFileName); if ( pSound ) { S_MarkUISound( pSound ); StartSoundParams_t params; params.staticsound = IsX360() ? true : false; params.soundsource = cl.m_nViewEntity; params.entchannel = CHAN_AUTO; params.pSfx = pSound; params.origin = vDummyOrigin; params.pitch = PITCH_NORM; params.soundlevel = SNDLVL_IDLE; params.flags = 0; params.fvol = 1.0f; S_StartSound( params ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void VGui_ActivateMouse() { if ( !g_ClientDLL ) return; // Don't mess with mouse if not active if ( !game->IsActiveApp() ) { g_ClientDLL->IN_DeactivateMouse (); return; } /* // // MIKE AND ALFRED: these panels should expose whether they want mouse input or not and // CalculateMouseVisible will take them into account. // // If showing game ui, make sure nothing else is hooking it if ( Base().IsGameUIVisible() || Base().IsDebugSystemVisible() ) { g_ClientDLL->IN_DeactivateMouse(); return; } */ if ( vgui::surface()->IsCursorLocked() && !g_bTextMode ) { g_ClientDLL->IN_ActivateMouse (); } else { g_ClientDLL->IN_DeactivateMouse (); } } static ConVar mat_drawTitleSafe( "mat_drawTitleSafe", "0", 0, "Enable title safe overlay" ); CUtlVector< vgui::VPANEL > g_FocusPanelList; ConVar vgui_drawfocus( "vgui_drawfocus", "0", 0, "Report which panel is under the mouse." ); CFocusOverlayPanel::CFocusOverlayPanel( vgui::Panel *pParent, const char *pName ) : vgui::Panel( pParent, pName ) { SetPaintEnabled( false ); SetPaintBorderEnabled( false ); SetPaintBackgroundEnabled( false ); MakePopup(); SetPostChildPaintEnabled( true ); SetKeyBoardInputEnabled( false ); SetMouseInputEnabled( false ); } bool CFocusOverlayPanel::DrawTitleSafeOverlay( void ) { if ( !mat_drawTitleSafe.GetBool() ) return false; int backBufferWidth, backBufferHeight; materials->GetBackBufferDimensions( backBufferWidth, backBufferHeight ); int x, y, x1, y1; // Required Title safe is TCR documented at inner 90% (RED) int insetX = 0.05f * backBufferWidth; int insetY = 0.05f * backBufferHeight; x = insetX; y = insetY; x1 = backBufferWidth - insetX; y1 = backBufferHeight - insetY; vgui::surface()->DrawSetColor( 255, 0, 0, 255 ); vgui::surface()->DrawOutlinedRect( x, y, x1, y1 ); // Suggested Title Safe is TCR documented at inner 85% (YELLOW) insetX = 0.075f * backBufferWidth; insetY = 0.075f * backBufferHeight; x = insetX; y = insetY; x1 = backBufferWidth - insetX; y1 = backBufferHeight - insetY; vgui::surface()->DrawSetColor( 255, 255, 0, 255 ); vgui::surface()->DrawOutlinedRect( x, y, x1, y1 ); return true; } void CFocusOverlayPanel::PostChildPaint( void ) { BaseClass::PostChildPaint(); bool bNeedsMoveToFront = false; if ( g_DrawTreeSelectedPanel ) { int x, y, x1, y1; vgui::ipanel()->GetClipRect( g_DrawTreeSelectedPanel, x, y, x1, y1 ); vgui::surface()->DrawSetColor( Color( 255, 0, 0, 255 ) ); vgui::surface()->DrawOutlinedRect( x, y, x1, y1 ); bNeedsMoveToFront = true; } if ( DrawTitleSafeOverlay() ) { bNeedsMoveToFront = true; } if ( DrawFocusPanelList() ) { bNeedsMoveToFront = true; } if ( bNeedsMoveToFront ) { // will be valid for the next frame MoveToFront(); } } bool CFocusOverlayPanel::DrawFocusPanelList( void ) { if( !vgui_drawfocus.GetBool() ) return false; int c = g_FocusPanelList.Size(); if ( c <= 0 ) return false; int slot = 0; int fullscreeninset = 0; for ( int i = 0; i < c; i++ ) { if ( slot > 31 ) break; vgui::VPANEL vpanel = g_FocusPanelList[ i ]; if ( !vpanel ) continue; if ( !vgui::ipanel()->IsVisible( vpanel ) ) return false; // Convert panel bounds to screen space int r, g, b; GetColorForSlot( slot, r, g, b ); int x, y, x1, y1; vgui::ipanel()->GetClipRect( vpanel, x, y, x1, y1 ); if ( (x1 - x) == videomode->GetModeUIWidth() && (y1 - y) == videomode->GetModeUIHeight() ) { x += fullscreeninset; y += fullscreeninset; x1 -= fullscreeninset; y1 -= fullscreeninset; fullscreeninset++; } vgui::surface()->DrawSetColor( Color( r, g, b, 255 ) ); vgui::surface()->DrawOutlinedRect( x, y, x1, y1 ); slot++; } return true; } static void VGui_RecursiveFindPanels( CUtlVector< vgui::VPANEL >& panelList, vgui::VPANEL check, char const *panelname ) { vgui::Panel *panel = vgui::ipanel()->GetPanel( check, "ENGINE" ); if ( !panel ) return; if ( !Q_strncmp( panel->GetName(), panelname, strlen( panelname ) ) ) { panelList.AddToTail( panel->GetVPanel() ); } int childcount = panel->GetChildCount(); for ( int i = 0; i < childcount; i++ ) { vgui::Panel *child = panel->GetChild( i ); VGui_RecursiveFindPanels( panelList, child->GetVPanel(), panelname ); } } void VGui_FindNamedPanels( CUtlVector< vgui::VPANEL >& panelList, char const *panelname ) { vgui::VPANEL embedded = vgui::surface()->GetEmbeddedPanel(); // faster version of code below // checks through each popup in order, top to bottom windows int c = vgui::surface()->GetPopupCount(); for (int i = c - 1; i >= 0; i--) { vgui::VPANEL popup = vgui::surface()->GetPopup(i); if ( !popup ) continue; if ( embedded == popup ) continue; VGui_RecursiveFindPanels( panelList, popup, panelname ); } VGui_RecursiveFindPanels( panelList, embedded, panelname ); } CON_COMMAND( vgui_togglepanel, "show/hide vgui panel by name." ) { if ( args.ArgC() < 2 ) { ConMsg( "Usage: vgui_showpanel panelname\n" ); return; } bool flip = false; bool fg = true; bool bg = true; if ( args.ArgC() == 5 ) { flip = atoi( args[ 2 ] ) ? true : false; fg = atoi( args[ 3 ] ) ? true : false; bg = atoi( args[ 4 ] ) ? true : false; } char const *panelname = args[ 1 ]; if ( !panelname || !panelname[ 0 ] ) return; CUtlVector< vgui::VPANEL > panelList; VGui_FindNamedPanels( panelList, panelname ); if ( !panelList.Size() ) { ConMsg( "No panels starting with %s\n", panelname ); return; } for ( int i = 0; i < panelList.Size(); i++ ) { vgui::VPANEL p = panelList[ i ]; if ( !p ) continue; vgui::Panel *panel = vgui::ipanel()->GetPanel( p, "ENGINE"); if ( !panel ) continue; Msg( "Toggling %s\n", panel->GetName() ); if ( fg ) { panel->SetPaintEnabled( flip ); } if ( bg ) { panel->SetPaintBackgroundEnabled( flip ); } } } static void VGui_RecursePanel( CUtlVector< vgui::VPANEL >& panelList, int x, int y, vgui::VPANEL check, bool include_hidden ) { if( !include_hidden && !vgui::ipanel()->IsVisible( check ) ) { return; } if ( vgui::ipanel()->IsWithinTraverse( check, x, y, false ) ) { panelList.AddToTail( check ); } int childcount = vgui::ipanel()->GetChildCount( check ); for ( int i = 0; i < childcount; i++ ) { vgui::VPANEL child = vgui::ipanel()->GetChild( check, i ); VGui_RecursePanel( panelList, x, y, child, include_hidden ); } } void CEngineVGui::DrawMouseFocus( void ) { VPROF( "CEngineVGui::DrawMouseFocus" ); g_FocusPanelList.RemoveAll(); if ( !vgui_drawfocus.GetBool() ) return; staticFocusOverlayPanel->MoveToFront(); bool include_hidden = vgui_drawfocus.GetInt() == 2; int x, y; vgui::input()->GetCursorPos( x, y ); vgui::VPANEL embedded = vgui::surface()->GetEmbeddedPanel(); if ( vgui::surface()->IsCursorVisible() && vgui::surface()->IsWithin(x, y) ) { // faster version of code below // checks through each popup in order, top to bottom windows int c = vgui::surface()->GetPopupCount(); for (int i = c - 1; i >= 0; i--) { vgui::VPANEL popup = vgui::surface()->GetPopup(i); if ( !popup ) continue; if ( popup == embedded ) continue; if ( !vgui::ipanel()->IsVisible( popup ) ) continue; VGui_RecursePanel( g_FocusPanelList, x, y, popup, include_hidden ); } VGui_RecursePanel( g_FocusPanelList, x, y, embedded, include_hidden ); } // Now draw them con_nprint_t np; np.time_to_live = 1.0f; int c = g_FocusPanelList.Size(); int slot = 0; for ( int i = 0; i < c; i++ ) { if ( slot > 31 ) break; vgui::VPANEL vpanel = g_FocusPanelList[ i ]; if ( !vpanel ) continue; np.index = slot; int r, g, b; CFocusOverlayPanel::GetColorForSlot( slot, r, g, b ); np.color[ 0 ] = r / 255.0f; np.color[ 1 ] = g / 255.0f; np.color[ 2 ] = b / 255.0f; Con_NXPrintf( &np, "%3i: %s\n", slot + 1, vgui::ipanel()->GetName(vpanel) ); slot++; } while ( slot <= 31 ) { Con_NPrintf( slot, "" ); slot++; } } void VGui_SetGameDLLPanelsVisible( bool show ) { EngineVGui()->SetGameDLLPanelsVisible( show ); } void CEngineVGui::ShowNewGameDialog( int chapter ) { staticGameUIFuncs->ShowNewGameDialog( chapter ); } void CEngineVGui::OnCreditsFinished( void ) { staticGameUIFuncs->OnCreditsFinished(); } bool CEngineVGui::ValidateStorageDevice(int *pStorageDeviceValidated) { return staticGameUIFuncs->ValidateStorageDevice( pStorageDeviceValidated ); } //----------------------------------------------------------------------------- // Dump the panel hierarchy //----------------------------------------------------------------------------- void DumpPanels_r( vgui::VPANEL panel, int level ) { int i; vgui::IPanel *ipanel = vgui::ipanel(); const char *pName = ipanel->GetName( panel ); char indentBuff[32]; for (i=0; iGetChildCount( panel ); for ( i = 0; i < childcount; i++ ) { vgui::VPANEL child = ipanel->GetChild( panel, i ); DumpPanels_r( child, level+1 ); } } void DumpPanels_f() { vgui::VPANEL embedded = vgui::surface()->GetEmbeddedPanel(); DumpPanels_r( embedded, 0 ); } ConCommand DumpPanels("dump_panels", DumpPanels_f, "Dump Panel Tree" ); #if defined( _X360 ) //----------------------------------------------------------------------------- // Purpose: For testing message dialogs //----------------------------------------------------------------------------- #include "vgui_controls/MessageDialog.h" CON_COMMAND( dlg_normal, "Display a sample message dialog" ) { EngineVGui()->ShowMessageDialog( MD_STANDARD_SAMPLE ); } CON_COMMAND( dlg_warning, "Display a sample warning message dialog" ) { EngineVGui()->ShowMessageDialog( MD_WARNING_SAMPLE ); } CON_COMMAND( dlg_error, "Display a sample error message dialog" ) { EngineVGui()->ShowMessageDialog( MD_ERROR_SAMPLE ); } #endif