|
|
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "vgui_int.h"
#include "ienginevgui.h"
#include "itextmessage.h"
#include "vguicenterprint.h"
#include "iloadingdisc.h"
#include "ifpspanel.h"
#include "imessagechars.h"
#include "inetgraphpanel.h"
#include "idebugoverlaypanel.h"
#include <vgui/ISurface.h>
#include <vgui/IVGui.h>
#include <vgui/IInput.h>
#include "tier0/vprof.h"
#include "iclientmode.h"
#include <vgui_controls/Panel.h>
#include <keyvalues.h>
#include "filesystem.h"
#include "matsys_controls/matsyscontrols.h"
#ifdef SIXENSE
#include "sixense/in_sixense.h"
#endif
#ifdef _PS3
#include "ps3/ps3_core.h"
#endif
using namespace vgui;
#ifndef _GAMECONSOLE
void MP3Player_Create( vgui::VPANEL parent ); void MP3Player_Destroy(); #endif
#include <vgui/IInputInternal.h>
vgui::IInputInternal *g_InputInternal = NULL;
#include <vgui_controls/Controls.h>
#include "cstrike15/gameui/cstrike15/steamoverlay/isteamoverlaymgr.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
bool IsWidescreen( void );
void ss_pipsplit_changed( IConVar *pConVar, const char *pOldString, float flOldValue ) { VGui_OnSplitScreenStateChanged(); } static ConVar ss_pipsplit( "ss_pipsplit", "1", 0, "If enabled, use PIP instead of splitscreen. (Only works for 2 players)", ss_pipsplit_changed ); static ConVar ss_pipscale( "ss_pipscale", "0.3f", 0, "Scale of the PIP aspect ratio to our resolution.", ss_pipsplit_changed ); static ConVar ss_pip_right_offset( "ss_pip_right_offset", "25", 0, "PIP offset vector from the right of the screen", ss_pipsplit_changed ); static ConVar ss_pip_bottom_offset( "ss_pip_bottom_offset", "25", 0, "PIP offset vector from the bottom of the screen", ss_pipsplit_changed ); static ConVar ss_force_primary_fullscreen( "ss_force_primary_fullscreen", "0", 0, "If enabled, all splitscreen users will only see the first user's screen full screen", ss_pipsplit_changed ); bool VGui_UsePipSplit();
void ss_verticalsplit_changed( IConVar *pConVar, const char *pOldString, float flOldValue ) { ConVarRef var( pConVar ); if ( var.GetBool() != !!(int)flOldValue ) { VGui_OnSplitScreenStateChanged();
if ( GetFullscreenClientMode() ) { // we have to force re-layout, because the screen dimensions haven't changed,
// but our layout is going to be different.
GetFullscreenClientMode()->Layout( true ); }
FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) { ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( i ); GetClientMode()->Layout(); GetHud().OnSplitScreenStateChanged(); } } } static ConVar ss_verticalsplit( "ss_verticalsplit", "0", 0, "Two player split screen uses vertical split (do not set this directly, use ss_splitmode instead).", ss_verticalsplit_changed );
void ss_splitmode_changed( IConVar *pConVar, const char *pOldString, float flOldValue ) { ConVarRef var( pConVar );
if ( !IsWidescreen() ) { // Non-widescreen is alway horizontal
ss_verticalsplit.SetValue( 0 ); } else { if ( var.GetInt() == 1 ) { // Horizontal
ss_verticalsplit.SetValue( 0 ); } else if ( var.GetInt() == 2 ) { // Vertical
ss_verticalsplit.SetValue( 1 ); } else { // Vertical is default for widescreen
ss_verticalsplit.SetValue( 1 ); } } } static ConVar ss_splitmode( "ss_splitmode", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_GAMECONSOLE, "Two player split screen mode (0 - recommended settings base on the width, 1 - horizontal, 2 - vertical (only allowed in widescreen)", ss_splitmode_changed ); static ConVar ss_enable( "ss_enable", "0", FCVAR_RELEASE, "Enables Split Screen support. Play Single Player now launches into split screen mode. NO ONLINE SUPPORT" );
void GetVGUICursorPos( int& x, int& y ) { vgui::input()->GetCursorPos(x, y); }
void SetVGUICursorPos( int x, int y ) { if ( !g_bTextMode ) { vgui::input()->SetCursorPos(x, y); } }
class CHudTextureHandleProperty : public vgui::IPanelAnimationPropertyConverter { public: virtual void GetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); CHudTextureHandle *pHandle = ( CHudTextureHandle * )data;
// lookup texture name for id
if ( pHandle->Get() ) { kv->SetString( entry->name(), pHandle->Get()->szShortName ); } else { kv->SetString( entry->name(), "" ); } } virtual void SetData( Panel *panel, KeyValues *kv, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) ); CHudTextureHandle *pHandle = ( CHudTextureHandle * )data;
const char *texturename = kv->GetString( entry->name() ); if ( texturename && texturename[ 0 ] ) { CHudTexture *currentTexture = HudIcons().GetIcon( texturename ); pHandle->Set( currentTexture ); } else { pHandle->Set( NULL ); } }
virtual void InitFromDefault( Panel *panel, PanelAnimationMapEntry *entry ) { void *data = ( void * )( (*entry->m_pfnLookup)( panel ) );
CHudTextureHandle *pHandle = ( CHudTextureHandle * )data;
const char *texturename = entry->defaultvalue(); if ( texturename && texturename[ 0 ] ) { CHudTexture *currentTexture = HudIcons().GetIcon( texturename ); pHandle->Set( currentTexture ); } else { pHandle->Set( NULL ); } } };
class CSplitScreenLetterBox { public:
enum { SPLITSCREEN_NONWIDESCREEN_HORIZONTAL_SPLIT = 0, SPLITSCREEN_WIDESCREEN_HORIZONTAL_SPLIT, SPLITSCREEN_WIDESCREEN_VERTICAL_SPLIT,
NUM_SPLITSCREEN_TYPES, };
void Init();
void SetNumSplitScreenPlayers( int nPlayers );
bool GetSettings( bool *pbInsetHud, float *pflAspect, float *pFOV, float *pViewmodelFOV );
private:
struct LetterBox_t { LetterBox_t() : m_flAspectRatio( 4.0f / 3.0f ), m_bInsetHud( false ) {} float m_flAspectRatio; bool m_bInsetHud; float m_flFOV; float m_flViewModelFOV; };
bool m_bValid; LetterBox_t m_Settings[ NUM_SPLITSCREEN_TYPES ]; int m_nSplitScreenPlayers; };
void CSplitScreenLetterBox::Init() { m_nSplitScreenPlayers = 1; char const *pchSlotNames[] = { "nonwidescreen", "widescreen_horizontal_split", "widescreen_vertical_split" }; char const *pchConfigFile = "splitscreen_config.txt";
m_bValid = true; KeyValues *kv = new KeyValues( "splitscreen" ); if ( kv->LoadFromFile( g_pFullFileSystem, pchConfigFile, "MOD" ) ) { for ( int i = 0; i < NUM_SPLITSCREEN_TYPES && m_bValid; ++i ) { KeyValues *settings = kv->FindKey( pchSlotNames[ i ], false ); if ( settings ) { // Get settings
char const *pchAspect = settings->GetString( "aspect", "4 by 3" ); if ( pchAspect ) { // Allowable syntax is "16 by 9" or "16 x 9" or "1.77"
if ( Q_stristr( pchAspect, " by " ) ) { float f1, f2; if ( 2 == sscanf( pchAspect, "%f by %f", &f1, &f2 ) && f2 > 0.001f ) { m_Settings[ i ].m_flAspectRatio = f1 / f2; } else { Error( "%s: Invalid aspect ratio string '%s'\n", pchConfigFile, pchAspect ); m_bValid = false; } } else if ( Q_stristr( pchAspect, " x " ) ) { float f1, f2; if ( 2 == sscanf( pchAspect, "%f x %f", &f1, &f2 ) && f2 > 0.001f ) { m_Settings[ i ].m_flAspectRatio = f1 / f2; } else { Error( "%s: Invalid aspect ratio string '%s'\n", pchConfigFile, pchAspect ); m_bValid = false; } } else if ( Q_atof( pchAspect ) > 0.1f ) { m_Settings[ i ].m_flAspectRatio = Q_atof( pchAspect ); } else { Error( "%s: Invalid aspect ratio string '%s'\n", pchConfigFile, pchAspect ); m_bValid = false; } }
// Get inset for hud
m_Settings[ i ].m_bInsetHud = settings->GetBool( "insethud", false );
// Get FOV
m_Settings[ i ].m_flFOV = settings->GetFloat( "fov", 90.0f );
// Get viewmodel FOVs
m_Settings[ i ].m_flViewModelFOV = settings->GetFloat( "viewmodelfov", 50.0f ); } else { Error( "%s: Missing settings block for split screen mode '%s'\n", pchConfigFile, pchSlotNames[ i ] ); m_bValid = false; break; } } } else { Msg( "No split screen config file '%s', using defaults\n", pchConfigFile ); m_bValid = false; } kv->deleteThis(); }
void CSplitScreenLetterBox::SetNumSplitScreenPlayers( int nPlayers ) { m_nSplitScreenPlayers = nPlayers; }
bool IsWidescreen( void ) { const AspectRatioInfo_t &aspectRatioInfo = materials->GetAspectRatioInfo(); return aspectRatioInfo.m_bIsWidescreen; }
bool CSplitScreenLetterBox::GetSettings( bool *pbInsetHud, float *pflAspect, float *pFOV, float *pViewModelFOV ) { Assert( pbInsetHud ); Assert( pflAspect ); Assert( pFOV ); Assert( pViewModelFOV ); static bool bUsedDefaultsLastTime = false; if ( !m_bValid || m_nSplitScreenPlayers == 1 || VGui_UsePipSplit() || ss_force_primary_fullscreen.GetBool() ) { if ( !bUsedDefaultsLastTime ) { bUsedDefaultsLastTime = true; } *pbInsetHud = false; *pflAspect = 4.0f / 3.0f; // FIXME: These are the non-splitscreen defaults for L4D. This code needs to be sanitized for other games.
*pFOV = 90.0f; *pViewModelFOV = 50.0f; return false; }
// Figure out which splitscreen mode to use based on current configuration.
int slot; if ( IsWidescreen() ) { if ( ss_verticalsplit.GetBool() ) { slot = SPLITSCREEN_WIDESCREEN_VERTICAL_SPLIT; } else { slot = SPLITSCREEN_WIDESCREEN_HORIZONTAL_SPLIT; } } else { slot = SPLITSCREEN_NONWIDESCREEN_HORIZONTAL_SPLIT; }
bUsedDefaultsLastTime = false;
const LetterBox_t &lb = m_Settings[ slot ];
*pbInsetHud = lb.m_bInsetHud; *pflAspect = lb.m_flAspectRatio; *pFOV = lb.m_flFOV; *pViewModelFOV = lb.m_flViewModelFOV; return true; }
static CSplitScreenLetterBox g_LetterBox;
CON_COMMAND( ss_reloadletterbox, "ss_reloadletterbox" ) { g_LetterBox.Init(); VGui_OnSplitScreenStateChanged();
FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) { ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( i ); GetClientMode()->Layout(); GetHud().OnSplitScreenStateChanged(); } }
static CHudTextureHandleProperty textureHandleConverter;
static void VGui_OneTimeInit() { static bool initialized = false; if ( initialized ) return; initialized = true;
vgui::Panel::AddPropertyConverter( "CHudTextureHandle", &textureHandleConverter );
g_LetterBox.Init(); }
bool VGui_Startup( CreateInterfaceFn appSystemFactory ) { if ( !vgui::VGui_InitInterfacesList( "CLIENT", &appSystemFactory, 1 ) ) return false;
if ( !vgui::VGui_InitMatSysInterfacesList( "CLIENT", &appSystemFactory, 1 ) ) return false;
g_InputInternal = (IInputInternal *)appSystemFactory( VGUI_INPUTINTERNAL_INTERFACE_VERSION, NULL ); if ( !g_InputInternal ) { return false; // c_vguiscreen.cpp needs this!
}
VGui_OneTimeInit();
// Create any root panels for .dll
VGUI_CreateClientDLLRootPanel();
// Make sure we have a panel
for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) { ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); VPANEL root = VGui_GetClientDLLRootPanel(); if ( !root ) { return false; } }
CUtlVector< Panel * > list; VGui_GetPanelList( list );
for ( int i = 0; i < list.Count(); ++i ) { list[ i ]->SetMessageContextId_R( (uint32)i ); }
VGui_GetFullscreenRootPanel()->SetMessageContextId_R( (uint32)0 );
VGui_OnSplitScreenStateChanged();
return true; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void VGui_CreateGlobalPanels( void ) { VPANEL gameToolParent = enginevgui->GetPanel( PANEL_CLIENTDLL_TOOLS ); VPANEL toolParent = enginevgui->GetPanel( PANEL_TOOLS ); #if defined( TRACK_BLOCKING_IO )
VPANEL gameDLLPanel = enginevgui->GetPanel( PANEL_GAMEDLL ); #endif
// Part of game
for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) { ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); VPANEL root = VGui_GetClientDLLRootPanel(); GetCenterPrint()->Create( root ); } loadingdisc->Create( gameToolParent ); messagechars->Create( gameToolParent );
// Debugging or related tool
fps->Create( toolParent ); #if defined( TRACK_BLOCKING_IO )
iopanel->Create( gameDLLPanel ); #endif
netgraphpanel->Create( toolParent ); debugoverlaypanel->Create( gameToolParent );
#ifndef _GAMECONSOLE
// Create mp3 player off of tool parent panel
MP3Player_Create( toolParent ); #endif
// Create Steam overlay
if ( IsPS3() && g_pISteamOverlayMgr ) g_pISteamOverlayMgr->Create( enginevgui->GetPanel( PANEL_STEAMOVERLAY ) ); #ifdef SIXENSE
g_pSixenseInput->CreateGUI( gameToolParent ); #endif
}
void VGui_Shutdown() { // Destroy Steam overlay
if ( IsPS3() && g_pISteamOverlayMgr ) g_pISteamOverlayMgr->Destroy();
#ifndef _GAMECONSOLE
MP3Player_Destroy(); #endif
netgraphpanel->Destroy(); debugoverlaypanel->Destroy(); #if defined( TRACK_BLOCKING_IO )
iopanel->Destroy(); #endif
fps->Destroy();
messagechars->Destroy(); loadingdisc->Destroy(); for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) { ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); GetCenterPrint()->Destroy(); }
for ( int hh = 0; hh < MAX_SPLITSCREEN_PLAYERS; ++hh ) { ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( hh ); if ( GetClientMode() ) { GetClientMode()->VGui_Shutdown();
if ( hh == 0 ) { GetFullscreenClientMode()->VGui_Shutdown(); } } }
VGUI_DestroyClientDLLRootPanel();
// Make sure anything "marked for deletion"
// actually gets deleted before this dll goes away
vgui::ivgui()->RunFrame(); }
static ConVar cl_showpausedimage( "cl_showpausedimage", "1", 0, "Show the 'Paused' image when game is paused." );
//-----------------------------------------------------------------------------
// Things to do before rendering vgui stuff...
//-----------------------------------------------------------------------------
void VGui_PreRender() { ASSERT_LOCAL_PLAYER_RESOLVABLE(); VPROF( "VGui_PreRender" );
// 360 does not use these plaques
#if !defined( PORTAL2 )
if ( IsPC() ) { loadingdisc->SetLoadingVisible( engine->IsDrawingLoadingImage() && !engine->IsPlayingDemo() ); loadingdisc->SetPausedVisible( !enginevgui->IsGameUIVisible() && cl_showpausedimage.GetBool() && engine->IsPaused() && !engine->IsTakingScreenshot() && !engine->IsPlayingDemo() ); } #endif
int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
CUtlVector< Panel * > list; VGui_GetPanelList( list ); for ( int i = 0; i < list.Count() ; ++i ) { list[ i ]->SetVisible( i == nSlot ); }
VGui_GetFullscreenRootPanel()->SetVisible( true ); }
void VGui_PostRender() { int w, h; CUtlVector< Panel * > list; VGui_GetPanelList( list ); FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) { int x, y; VGui_GetHudBounds( i, x, y, w, h); list[ i ]->SetVisible( true ); list[ i ]->SetBounds( x, y, w, h );
surface()->SetAbsPosForContext( i, x, y ); }
VGui_GetTrueScreenSize( w, h ); VGui_GetFullscreenRootPanel()->SetVisible( true ); VGui_GetFullscreenRootPanel()->SetBounds( 0, 0, w, h ); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : cl_panelanimation -
//-----------------------------------------------------------------------------
CON_COMMAND( cl_panelanimation, "Shows panel animation variables: <panelname | blank for all panels>." ) { if ( args.ArgC() == 2 ) { PanelAnimationDumpVars( args[1] ); } else { PanelAnimationDumpVars( NULL ); } }
void GetHudSize( int& w, int &h ) { vgui::surface()->GetScreenSize( w, h ); }
static vrect_t g_TrueScreenSize; static vrect_t g_ScreenSpaceBounds[ MAX_SPLITSCREEN_CLIENTS ];
void VGui_GetTrueScreenSize( int &w, int &h ) { w = g_TrueScreenSize.width; h = g_TrueScreenSize.height; }
void VGUI_SetScreenSpaceBounds( int slot, int x, int y, int w, int h ) { vrect_t &r = g_ScreenSpaceBounds[ slot ]; r.x = x; r.y = y; r.width = w; r.height = h; }
void VGUI_UpdateScreenSpaceBounds( int nNumSplits, int sx, int sy, int sw, int sh ) { g_TrueScreenSize.x = sx; g_TrueScreenSize.y = sy; g_TrueScreenSize.width = sw; g_TrueScreenSize.height = sh;
CUtlVector< int > validSlots; FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) { validSlots.AddToTail( i ); }
Assert( validSlots.Count() == nNumSplits );
switch ( nNumSplits ) { default: case 1: // Make it screen sized
{ VGUI_SetScreenSpaceBounds( validSlots[ 0 ], sx, sy, sw, sh ); } break; case 2: { if ( ss_force_primary_fullscreen.GetBool() ) { // fullscreen
VGUI_SetScreenSpaceBounds( validSlots[ 0 ], 0, 0, sw, sh ); VGUI_SetScreenSpaceBounds( validSlots[ 1 ], sw, sh, 1, 1 ); } else if ( VGui_UsePipSplit() ) { VGUI_SetScreenSpaceBounds( validSlots[ 0 ], sx, sy, sw, sh ); // scale with PIP resolution
float flPIPScale = ss_pipscale.GetFloat(); int pipWidth = sw * flPIPScale; int pipHeight = sh * flPIPScale; int x = sw - pipWidth - ss_pip_right_offset.GetInt(); int y = sh - pipHeight - ss_pip_bottom_offset.GetInt(); // round upper left corner down to the nearest multiple of 8 for X360 (resolve alignment requirements)
if ( IsX360() ) { x &= (~7); y &= (~7); } VGUI_SetScreenSpaceBounds( validSlots[ 1 ], x, y, pipWidth, pipHeight ); } else if ( ss_verticalsplit.GetBool() ) { sw /= 2; // Stack two horiz, side by side
VGUI_SetScreenSpaceBounds( validSlots[ 0 ], sx, sy, sw, sh ); VGUI_SetScreenSpaceBounds( validSlots[ 1 ], sx + sw, sy, sw, sh ); } else { sh /= 2; // Stack two wide on top of one another
VGUI_SetScreenSpaceBounds( validSlots[ 0 ], sx, sy, sw, sh ); VGUI_SetScreenSpaceBounds( validSlots[ 1 ], sx, sy + sh, sw, sh ); } } break; case 3: { int fullw = sw;
sw /= 2; sh /= 2;
VGUI_SetScreenSpaceBounds( validSlots[ 0 ], sx + ( fullw - sw ) / 2, sy, sw, sh ); VGUI_SetScreenSpaceBounds( validSlots[ 1 ], sx, sy + sh, sw, sh ); VGUI_SetScreenSpaceBounds( validSlots[ 2 ], sx + sw, sy + sh, sw, sh ); } break; case 4: { sw /= 2; sh /= 2;
// Stack two wide on top of one another
VGUI_SetScreenSpaceBounds( validSlots[ 0 ], sx, sy, sw, sh ); VGUI_SetScreenSpaceBounds( validSlots[ 1 ], sx + sw, sy, sw, sh ); VGUI_SetScreenSpaceBounds( validSlots[ 2 ], sx, sy + sh, sw, sh ); VGUI_SetScreenSpaceBounds( validSlots[ 3 ], sx + sw, sy + sh, sw, sh ); } break; } }
CBitVec< MAX_SPLITSCREEN_PLAYERS > g_SplitScreenPlayers;
bool g_bIterateRemoteSplitScreenPlayers = false; C_BasePlayer *g_RemoteSplitScreenPlayers[MAX_SPLITSCREEN_PLAYERS];
void AddRemoteSplitScreenViewPlayer( C_BasePlayer *pPlayer ) { for( int i = 0; i != MAX_SPLITSCREEN_PLAYERS; ++i ) { if( g_RemoteSplitScreenPlayers[i] == pPlayer ) return; //don't add it twice
}
for( int i = 0; i != MAX_SPLITSCREEN_PLAYERS; ++i ) { if( !g_SplitScreenPlayers.IsBitSet( i ) && (g_RemoteSplitScreenPlayers[i] == NULL) ) { g_RemoteSplitScreenPlayers[i] = pPlayer; VGui_OnSplitScreenStateChanged(); return; } } }
void RemoveRemoteSplitScreenViewPlayer( C_BasePlayer *pPlayer ) { for( int i = 0; i != MAX_SPLITSCREEN_PLAYERS; ++i ) { if( g_RemoteSplitScreenPlayers[i] == pPlayer ) { g_RemoteSplitScreenPlayers[i] = NULL; VGui_OnSplitScreenStateChanged(); return; } } }
C_BasePlayer *GetSplitScreenViewPlayer( int nSlot ) { return g_SplitScreenPlayers.IsBitSet( nSlot ) ? C_BasePlayer::GetLocalPlayer( nSlot ) : g_RemoteSplitScreenPlayers[nSlot]; }
void cl_enable_remote_splitscreen_callback_f( IConVar *var, const char *pOldValue, float flOldValue ) { VGui_OnSplitScreenStateChanged(); }
ConVar cl_enable_remote_splitscreen( "cl_enable_remote_splitscreen", "0", 0, "Allows viewing of nonlocal players in a split screen fashion", cl_enable_remote_splitscreen_callback_f ); static CUtlVector<bool> s_IterateNetworkedSplitScreenSlotsPushedValues; void IterateRemoteSplitScreenViewSlots_Push( bool bSet ) { if( !cl_enable_remote_splitscreen.GetBool() ) { bSet = false; }
s_IterateNetworkedSplitScreenSlotsPushedValues.AddToTail( g_bIterateRemoteSplitScreenPlayers ); g_bIterateRemoteSplitScreenPlayers = bSet; }
void IterateRemoteSplitScreenViewSlots_Pop( void ) { Assert( s_IterateNetworkedSplitScreenSlotsPushedValues.Count() > 0 ); g_bIterateRemoteSplitScreenPlayers = s_IterateNetworkedSplitScreenSlotsPushedValues.Tail(); s_IterateNetworkedSplitScreenSlotsPushedValues.RemoveMultipleFromTail( 1 ); }
bool IsLocalSplitScreenPlayer( int nSlot ) { return g_SplitScreenPlayers.IsBitSet( nSlot ); }
int FirstValidSplitScreenSlot() { return 0; }
int NextValidSplitScreenSlot( int i ) { ++i; while ( i< MAX_SPLITSCREEN_PLAYERS ) { if ( g_SplitScreenPlayers.IsBitSet( i ) ) return i;
if( g_bIterateRemoteSplitScreenPlayers && cl_enable_remote_splitscreen.GetBool() && (g_RemoteSplitScreenPlayers[i] != NULL) ) return i;
++i; } return -1; }
bool IsValidSplitScreenSlot( int i ) { return g_SplitScreenPlayers.IsBitSet( i ) || (g_bIterateRemoteSplitScreenPlayers && (g_RemoteSplitScreenPlayers[i] != NULL)); }
static int g_nCachedScreenSize[ 2 ] = { -1, -1 };
void VGui_OnScreenSizeChanged() { vgui::surface()->GetScreenSize( g_nCachedScreenSize[ 0 ], g_nCachedScreenSize[ 1 ] );
VGui_OnSplitScreenStateChanged(); }
static int g_nNumSplits = 1; //number of logical splits (local players + remote splits)
static int g_nNumLocalSplits = 1; //number of local players sitting at this computer
bool VGui_IsSplitScreen() { return g_nNumSplits >= 2; }
bool VGui_IsSplitScreenPIP() { return VGui_IsSplitScreen() && g_nNumLocalSplits == ss_pipsplit.GetInt(); }
bool VGui_UsePipSplit() { return g_nNumLocalSplits <= ss_pipsplit.GetInt(); //ss_pipsplit 1 for remote splitscreen pip, ss_pipsplit 2 to use pip even with 2 local players
}
bool g_bSuppressConfigSystemLevelDueToPIPTransitions; void VGui_OnSplitScreenStateChanged() { CUtlVector< Panel * > list; VGui_GetPanelList( list );
g_SplitScreenPlayers.ClearAll(); g_nNumSplits = 0; g_nNumLocalSplits = 0; for ( int i = engine->FirstValidSplitScreenSlot(); i != -1; i = engine->NextValidSplitScreenSlot( i ) ) { g_SplitScreenPlayers.Set( i ); g_RemoteSplitScreenPlayers[i] = NULL; //actual splitscreen players nuke networked splitscreen players
++g_nNumSplits; ++g_nNumLocalSplits; }
if( cl_enable_remote_splitscreen.GetBool() ) { for( int i = 0; i != MAX_SPLITSCREEN_PLAYERS; ++i ) { if( g_RemoteSplitScreenPlayers[i] != NULL ) { ++g_nNumSplits; } } }
IterateRemoteSplitScreenViewSlots_Push( true ); g_LetterBox.SetNumSplitScreenPlayers( g_nNumSplits );
for ( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i ) { list[ i ]->SetVisible( IsValidSplitScreenSlot( i ) ); }
// Now tile, etc. the rest of them
int sw, sh; if ( g_nCachedScreenSize[ 0 ] == -1 ) { vgui::surface()->GetScreenSize( g_nCachedScreenSize[ 0 ], g_nCachedScreenSize[ 1 ] ); }
sw = g_nCachedScreenSize[ 0 ]; sh = g_nCachedScreenSize[ 1 ];
VGUI_UpdateScreenSpaceBounds( g_nNumSplits, 0, 0, sw, sh );
// get the current splitscreen/letterbox settings. We only care about fov and viewmodelfov.
bool bDummy; float flDummy, flFOV, flViewModelFOV; g_LetterBox.GetSettings( &bDummy, &flDummy, &flFOV, &flViewModelFOV );
static SplitScreenConVarRef fov_desired( "fov_desired", true );
FOR_EACH_VALID_SPLITSCREEN_PLAYER( i ) { if ( fov_desired.IsValid() ) { fov_desired.SetValue( i, flFOV ); }
// The actual viewport panels are all at the top left of the screen, but sized appropriately
int x, y, w, h; VGui_GetHudBounds( i, x, y, w, h); list[ i ]->SetBounds( x, y, w, h );
surface()->SetAbsPosForContext( i, x, y ); }
// This is a hack to prevent changing the current system level during PIP mode transitions. Otherwise, on the next frame mat queue mode will be disabled for
// a frame and then re-enabled, which causes various known rendering problems and a noticeable hitch.
// I would have loved to plumb this down in a cleaner way, but this function is a convar change callback.
if ( !g_bSuppressConfigSystemLevelDueToPIPTransitions ) { ConfigureCurrentSystemLevel( ); }
IterateRemoteSplitScreenViewSlots_Pop(); C_BaseEntity::UpdateVisibilityAllEntities(); }
void VGui_GetPanelBounds( int slot, int &x, int &y, int &w, int &h ) { if ( !IsValidSplitScreenSlot( slot ) || g_nNumSplits == 1 ) { x = y = 0; vgui::surface()->GetScreenSize( w, h ); return; }
vrect_t &r = g_ScreenSpaceBounds[ slot ]; x = r.x; y = r.y; w = r.width; h = r.height; }
void VGui_GetEngineRenderBounds( int slot, int &x, int &y, int &w, int &h, int &insetX, int &insetY ) { insetX = insetY = 0;
if ( !IsValidSplitScreenSlot( slot ) || g_nNumSplits == 1 ) { x = y = 0; vgui::surface()->GetScreenSize( w, h ); return; }
VGui_GetPanelBounds( slot, x, y, w, h );
bool bDummy = false; float flDummy = 0; float flAspect = 1.0f; if ( !g_LetterBox.GetSettings( &bDummy, &flAspect, &flDummy, &flDummy ) ) { return; }
// Need to convert from physical to pixel aspect ratio. These aren't the same when using non-square pixels.
const AspectRatioInfo_t &aspectRatioInfo = materials->GetAspectRatioInfo(); flAspect *= aspectRatioInfo.m_flPhysicalToFrameBufferScalar;
// Figure out current aspect ratio
float flCurrentAspect = (float)w / (float)h; float ratio = flAspect / flCurrentAspect;
if ( ratio > 1.0f ) { // Screen is wider, need bars at top and bottom
int usetall = (float)w / flAspect; if ( IsPC() ) { insetY = ( h - usetall ) / 2; y += insetY; h = usetall; } else { // hopefully it centers, but it might not
usetall = AlignValue( usetall, 2 * GPU_RESOLVE_ALIGNMENT ); insetY = ( h - usetall ) / 2; y += insetY; y = AlignValue( y, GPU_RESOLVE_ALIGNMENT ); insetY = AlignValue( insetY, GPU_RESOLVE_ALIGNMENT ); h = usetall; } } else { // Screen is narrower, need bars at left/right
int usewide = (float)h * flAspect; if ( IsPC() ) { insetX = ( w - usewide ) / 2; x += insetX; w = usewide; } else { // hopefully it centers, but it might not
usewide = AlignValue( usewide, 2 * GPU_RESOLVE_ALIGNMENT ); insetX = ( w - usewide ) / 2; x += insetX; x = AlignValue( x, GPU_RESOLVE_ALIGNMENT ); insetX = AlignValue( insetX, GPU_RESOLVE_ALIGNMENT ); w = usewide; } } }
void VGui_GetHudBounds( int slot, int &x, int &y, int &w, int &h ) { if ( !IsValidSplitScreenSlot( slot ) || g_nNumSplits == 1 ) { x = y = 0; vgui::surface()->GetScreenSize( w, h ); return; }
bool bInset = false; float dummy = 1.0f;
if ( !g_LetterBox.GetSettings( &bInset, &dummy, &dummy, &dummy ) || !bInset ) { // Use entire bounds for HUD
VGui_GetPanelBounds( slot, x, y, w, h ); return; }
int insetX = 0, insetY = 0; VGui_GetEngineRenderBounds( slot, x, y, w, h, insetX, insetY ); }
int VGUI_FindSlotForRootPanel( vgui::Panel *pRoot ) { CUtlVector< Panel * > list; VGui_GetPanelList( list ); int slot = list.Find( pRoot ) ; if ( slot == list.InvalidIndex() ) return 0; return slot; }
|