//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// // // hud.cpp // // implementation of CHud class // #include "cbase.h" #include "hud_macros.h" #include "history_resource.h" #include "iinput.h" #include "clientmode.h" #include "in_buttons.h" #include #include #include #include "itextmessage.h" #include "mempool.h" #include #include "filesystem.h" #include #include #include "hud_lcd.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" static CClassMemoryPool< CHudTexture > g_HudTextureMemoryPool( 128 ); //----------------------------------------------------------------------------- // Purpose: Parses the weapon txt files to get the sprites needed. //----------------------------------------------------------------------------- struct HudTextureFileRef { HudTextureFileRef ( const char *cszFileKey, const char *cszHudTexturePrefix ) { Q_strncpy( m_cszFileKey, cszFileKey, kcszFileKeyLength ); Q_strncpy( m_cszHudTexturePrefix, cszHudTexturePrefix, kcszHudTexturePrefix ); m_uiPrefixLength = Q_strlen( cszHudTexturePrefix ); m_fileKeySymbol = KeyValuesSystem()->GetSymbolForString( m_cszFileKey ); Assert( m_fileKeySymbol != INVALID_KEY_SYMBOL ); } enum { kcszFileKeyLength = 64, }; enum { kcszHudTexturePrefix = 16, }; char m_cszFileKey[kcszFileKeyLength]; char m_cszHudTexturePrefix[kcszHudTexturePrefix]; unsigned int m_uiPrefixLength; HKeySymbol m_fileKeySymbol; }; void LoadHudTextures( CUtlDict< CHudTexture *, int >& list, const char *szFilenameWithoutExtension, const unsigned char *pICEKey ) { KeyValues *pTemp, *pTextureSection; KeyValues *pKeyValuesData = ReadEncryptedKVFile( filesystem, szFilenameWithoutExtension, pICEKey ); if ( pKeyValuesData ) { CUtlVector hudTextureFileRefs; // By default, add a default entry mapping "file" to no prefix. This will allow earlier-version files // to work with no modification. hudTextureFileRefs.AddToTail( HudTextureFileRef( "file", "" ) ); // Read "*file"-to-prefix mapping. KeyValues *pTextureFileRefs = pKeyValuesData->FindKey( "TextureFileRefs" ); if ( pTextureFileRefs ) { pTemp = pTextureFileRefs->GetFirstSubKey(); while ( pTemp ) { hudTextureFileRefs.AddToTail( HudTextureFileRef( pTemp->GetName(), pTemp->GetString( "prefix", "" ) ) ); pTemp = pTemp->GetNextKey(); } } // Read our individual HUD texture data blocks. pTextureSection = pKeyValuesData->FindKey( "TextureData" ); if ( pTextureSection ) { // Read the sprite data pTemp = pTextureSection->GetFirstSubKey(); while ( pTemp ) { if ( pTemp->GetString( "font", NULL ) ) { CHudTexture *tex = new CHudTexture(); // Key Name is the sprite name Q_strncpy( tex->szShortName, pTemp->GetName(), sizeof( tex->szShortName ) ); // it's a font-based icon tex->bRenderUsingFont = true; tex->cCharacterInFont = *(pTemp->GetString("character", "")); Q_strncpy( tex->szTextureFile, pTemp->GetString( "font" ), sizeof( tex->szTextureFile ) ); list.Insert( tex->szShortName, tex ); } else { int iTexLeft = pTemp->GetInt( "x", 0 ), iTexTop = pTemp->GetInt( "y", 0 ), iTexRight = pTemp->GetInt( "width", 0 ) + iTexLeft, iTexBottom = pTemp->GetInt( "height", 0 ) + iTexTop; for ( int i = 0; i < hudTextureFileRefs.Size(); i++ ) { const char *cszFilename = pTemp->GetString( hudTextureFileRefs[i].m_fileKeySymbol, NULL ); if ( cszFilename ) { CHudTexture *tex = new CHudTexture(); tex->bRenderUsingFont = false; tex->rc.left = iTexLeft; tex->rc.top = iTexTop; tex->rc.right = iTexRight; tex->rc.bottom = iTexBottom; Q_strncpy( tex->szShortName, hudTextureFileRefs[i].m_cszHudTexturePrefix, sizeof( tex->szShortName ) ); Q_strncpy( tex->szShortName + hudTextureFileRefs[i].m_uiPrefixLength, pTemp->GetName(), sizeof( tex->szShortName ) - hudTextureFileRefs[i].m_uiPrefixLength ); Q_strncpy( tex->szTextureFile, cszFilename, sizeof( tex->szTextureFile ) ); list.Insert( tex->szShortName, tex ); } } } pTemp = pTemp->GetNextKey(); } } // Failed for some reason. Delete the Key data and abort. pKeyValuesData->deleteThis(); } } //----------------------------------------------------------------------------- // Purpose: // Input : * - // list - //----------------------------------------------------------------------------- void FreeHudTextureList( CUtlDict< CHudTexture *, int >& list ) { int c = list.Count(); for ( int i = 0; i < c; i++ ) { CHudTexture *tex = list[ i ]; delete tex; } list.RemoveAll(); } // Globally-used fonts vgui::HFont g_hFontTrebuchet24 = vgui::INVALID_FONT; //======================================================================================================================= // Hud Element Visibility handling //======================================================================================================================= typedef struct hudelement_hidden_s { char *sElementName; int iHiddenBits; // Bits in which this hud element is hidden } hudelement_hidden_t; ConVar hidehud( "hidehud", "0", FCVAR_CHEAT ); CHudTexture::CHudTexture() { Q_memset( szShortName, 0, sizeof( szShortName ) ); Q_memset( szTextureFile, 0, sizeof( szTextureFile ) ); Q_memset( texCoords, 0, sizeof( texCoords ) ); Q_memset( &rc, 0, sizeof( rc ) ); textureId = -1; bRenderUsingFont = false; bPrecached = false; cCharacterInFont = 0; hFont = ( vgui::HFont )NULL; } CHudTexture& CHudTexture::operator =( const CHudTexture& src ) { if ( this == &src ) return *this; Q_strncpy( szShortName, src.szShortName, sizeof( szShortName ) ); Q_strncpy( szTextureFile, src.szTextureFile, sizeof( szTextureFile ) ); Q_memcpy( texCoords, src.texCoords, sizeof( texCoords ) ); if ( src.textureId == -1 ) { // Didn't have a texture ID set textureId = -1; } else { // Make a new texture ID that uses the same texture textureId = vgui::surface()->CreateNewTextureID(); vgui::surface()->DrawSetTextureFile( textureId, src.szTextureFile, false, false ); } rc = src.rc; bRenderUsingFont = src.bRenderUsingFont; cCharacterInFont = src.cCharacterInFont; hFont = src.hFont; return *this; } CHudTexture::~CHudTexture() { if ( vgui::surface() && textureId != -1 ) { vgui::surface()->DestroyTextureID( textureId ); textureId = -1; } } //======================================================================================================================= // CHudElement // All hud elements are derived from this class. //======================================================================================================================= //----------------------------------------------------------------------------- // Purpose: Registers the hud element in a global list, in CHud //----------------------------------------------------------------------------- CHudElement::CHudElement( const char *pElementName ) { m_bActive = false; m_iHiddenBits = 0; m_pElementName = pElementName; SetNeedsRemove( false ); m_bIsParentedToClientDLLRootPanel = false; // Make this for all hud elements, but when its a bit safer #if defined( TF_CLIENT_DLL ) || defined( DOD_DLL ) RegisterForRenderGroup( "global" ); #endif } //----------------------------------------------------------------------------- // Purpose: Remove this hud element from the global list in CHUD //----------------------------------------------------------------------------- CHudElement::~CHudElement() { if ( m_bNeedsRemove ) { gHUD.RemoveHudElement( this ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHudElement::SetActive( bool bActive ) { m_bActive = bActive; } //----------------------------------------------------------------------------- // Purpose: // Input : needsremove - //----------------------------------------------------------------------------- void CHudElement::SetNeedsRemove( bool needsremove ) { m_bNeedsRemove = needsremove; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHudElement::SetHiddenBits( int iBits ) { m_iHiddenBits = iBits; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CHudElement::ShouldDraw( void ) { bool bShouldDraw = ( !gHUD.IsHidden( m_iHiddenBits ) ); if ( bShouldDraw ) { // for each render group int iNumGroups = m_HudRenderGroups.Count(); for ( int iGroupIndex = 0; iGroupIndex < iNumGroups; iGroupIndex++ ) { if ( gHUD.IsRenderGroupLockedFor( this, m_HudRenderGroups.Element(iGroupIndex ) ) ) return false; } } return bShouldDraw; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CHudElement::IsParentedToClientDLLRootPanel() const { return m_bIsParentedToClientDLLRootPanel; } //----------------------------------------------------------------------------- // Purpose: // Input : parented - //----------------------------------------------------------------------------- void CHudElement::SetParentedToClientDLLRootPanel( bool parented ) { m_bIsParentedToClientDLLRootPanel = parented; } //----------------------------------------------------------------------------- // Purpose: We can register to be affected by multiple hud render groups //----------------------------------------------------------------------------- void CHudElement::RegisterForRenderGroup( const char *pszGroupName ) { int iGroupIndex = gHUD.RegisterForRenderGroup( pszGroupName ); // add group index to our list of registered groups if ( m_HudRenderGroups.Find( iGroupIndex ) == m_HudRenderGroups.InvalidIndex() ) { m_HudRenderGroups.AddToTail( iGroupIndex ); } } void CHudElement::UnregisterForRenderGroup( const char *pszGroupName ) { int iGroupIndex = gHUD.RegisterForRenderGroup( pszGroupName ); m_HudRenderGroups.FindAndRemove( iGroupIndex ); } //----------------------------------------------------------------------------- // Purpose: We want to obscure other elements in this group //----------------------------------------------------------------------------- void CHudElement::HideLowerPriorityHudElementsInGroup( const char *pszGroupName ) { // look up the render group int iGroupIndex = gHUD.LookupRenderGroupIndexByName( pszGroupName ); // lock the group gHUD.LockRenderGroup( iGroupIndex, this ); } //----------------------------------------------------------------------------- // Purpose: Stop obscuring other elements in this group //----------------------------------------------------------------------------- void CHudElement::UnhideLowerPriorityHudElementsInGroup( const char *pszGroupName ) { // look up the render group int iGroupIndex = gHUD.LookupRenderGroupIndexByName( pszGroupName ); // unlock the group gHUD.UnlockRenderGroup( iGroupIndex, this ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CHudElement::GetRenderGroupPriority( void ) { return 0; } CHud gHUD; // global HUD object DECLARE_MESSAGE(gHUD, ResetHUD); #ifdef CSTRIKE_DLL DECLARE_MESSAGE(gHUD, SendAudio); #endif CHud::CHud() { SetDefLessFunc( m_RenderGroups ); m_flScreenShotTime = -1; } //----------------------------------------------------------------------------- // Purpose: This is called every time the DLL is loaded //----------------------------------------------------------------------------- void CHud::Init( void ) { HOOK_HUD_MESSAGE( gHUD, ResetHUD ); #ifdef CSTRIKE_DLL HOOK_HUD_MESSAGE( gHUD, SendAudio ); #endif InitFonts(); // Create all the Hud elements CHudElementHelper::CreateAllElements(); gLCD.Init(); // Initialize all created elements for ( int i = 0; i < m_HudList.Size(); i++ ) { m_HudList[i]->Init(); } m_bHudTexturesLoaded = false; KeyValues *kv = new KeyValues( "layout" ); if ( kv ) { if ( kv->LoadFromFile( filesystem, "scripts/HudLayout.res" ) ) { int numelements = m_HudList.Size(); for ( int i = 0; i < numelements; i++ ) { CHudElement *element = m_HudList[i]; vgui::Panel *pPanel = dynamic_cast(element); if ( !pPanel ) { Msg( "Non-vgui hud element %s\n", m_HudList[i]->GetName() ); continue; } KeyValues *key = kv->FindKey( pPanel->GetName(), false ); if ( !key ) { Msg( "Hud element '%s' doesn't have an entry '%s' in scripts/HudLayout.res\n", m_HudList[i]->GetName(), pPanel->GetName() ); } // Note: When a panel is parented to the module root, it's "parent" is returned as NULL. if ( !element->IsParentedToClientDLLRootPanel() && !pPanel->GetParent() ) { DevMsg( "Hud element '%s'/'%s' doesn't have a parent\n", m_HudList[i]->GetName(), pPanel->GetName() ); } } } kv->deleteThis(); } if ( m_bHudTexturesLoaded ) return; m_bHudTexturesLoaded = true; CUtlDict< CHudTexture *, int > textureList; // check to see if we have sprites for this res; if not, step down LoadHudTextures( textureList, "scripts/hud_textures", NULL ); LoadHudTextures( textureList, "scripts/mod_textures", NULL ); int c = textureList.Count(); for ( int index = 0; index < c; index++ ) { CHudTexture* tex = textureList[ index ]; AddSearchableHudIconToList( *tex ); } FreeHudTextureList( textureList ); } //----------------------------------------------------------------------------- // Purpose: Init Hud global colors // Input : *scheme - //----------------------------------------------------------------------------- void CHud::InitColors( vgui::IScheme *scheme ) { m_clrNormal = scheme->GetColor( "Normal", Color( 255, 208, 64 ,255 ) ); m_clrCaution = scheme->GetColor( "Caution", Color( 255, 48, 0, 255 ) ); m_clrYellowish = scheme->GetColor( "Yellowish", Color( 255, 160, 0, 255 ) ); } //----------------------------------------------------------------------------- // Initializes fonts //----------------------------------------------------------------------------- void CHud::InitFonts() { vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( scheme ); g_hFontTrebuchet24 = pScheme->GetFont("CenterPrintText", true); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHud::Shutdown( void ) { gLCD.Shutdown(); // Deleting hudlist items can result in them being removed from the same hudlist (m_bNeedsRemove). // So go through and kill the last item until the array is empty. while ( m_HudList.Size() > 0 ) { delete m_HudList.Tail(); } m_HudList.Purge(); m_bHudTexturesLoaded = false; } //----------------------------------------------------------------------------- // Purpose: LevelInit's called whenever a new level is starting //----------------------------------------------------------------------------- void CHud::LevelInit( void ) { // Tell all the registered hud elements to LevelInit for ( int i = 0; i < m_HudList.Size(); i++ ) { m_HudList[i]->LevelInit(); } // Unhide all render groups int iCount = m_RenderGroups.Count(); for ( int i = 0; i < iCount; i++ ) { CHudRenderGroup *group = m_RenderGroups[ i ]; group->bHidden = false; group->m_pLockingElements.Purge(); } } //----------------------------------------------------------------------------- // Purpose: LevelShutdown's called whenever a level is finishing //----------------------------------------------------------------------------- void CHud::LevelShutdown( void ) { // Tell all the registered hud elements to LevelShutdown for ( int i = 0; i < m_HudList.Size(); i++ ) { m_HudList[i]->LevelShutdown(); } } //----------------------------------------------------------------------------- // Purpose: cleans up memory allocated for m_rg* arrays //----------------------------------------------------------------------------- CHud::~CHud() { int c = m_Icons.Count(); for ( int i = c - 1; i >= 0; i-- ) { CHudTexture *tex = m_Icons[ i ]; g_HudTextureMemoryPool.Free( tex ); } m_Icons.Purge(); c = m_RenderGroups.Count(); for ( int i = c - 1; i >= 0; i-- ) { CHudRenderGroup *group = m_RenderGroups[ i ]; m_RenderGroups.RemoveAt(i); delete group; } } void CHudTexture::Precache( void ) { // costly function, used selectively on specific hud elements to get font pages built out at load time if ( IsX360() && bRenderUsingFont && !bPrecached && hFont != vgui::INVALID_FONT ) { wchar_t wideChars[2]; wideChars[0] = (wchar_t)cCharacterInFont; wideChars[1] = 0; vgui::surface()->PrecacheFontCharacters( hFont, wideChars ); bPrecached = true; } } void CHudTexture::DrawSelf( int x, int y, const Color& clr ) const { DrawSelf( x, y, Width(), Height(), clr ); } void CHudTexture::DrawSelf( int x, int y, int w, int h, const Color& clr ) const { if ( bRenderUsingFont ) { vgui::surface()->DrawSetTextFont( hFont ); vgui::surface()->DrawSetTextColor( clr ); vgui::surface()->DrawSetTextPos( x, y ); vgui::surface()->DrawUnicodeChar( cCharacterInFont ); } else { if ( textureId == -1 ) return; vgui::surface()->DrawSetTexture( textureId ); vgui::surface()->DrawSetColor( clr ); vgui::surface()->DrawTexturedSubRect( x, y, x + w, y + h, texCoords[ 0 ], texCoords[ 1 ], texCoords[ 2 ], texCoords[ 3 ] ); } } void CHudTexture::DrawSelfCropped( int x, int y, int cropx, int cropy, int cropw, int croph, int finalWidth, int finalHeight, Color clr ) const { if ( bRenderUsingFont ) { // work out how much we've been cropped int height = vgui::surface()->GetFontTall( hFont ); float frac = (height - croph) / (float)height; y -= cropy; vgui::surface()->DrawSetTextFont( hFont ); vgui::surface()->DrawSetTextColor( clr ); vgui::surface()->DrawSetTextPos( x, y ); vgui::CharRenderInfo info; if ( vgui::surface()->DrawGetUnicodeCharRenderInfo( cCharacterInFont, info ) ) { if ( cropy ) { info.verts[0].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y ); info.verts[0].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y ); } else if ( croph != height ) { info.verts[1].m_Position.y = Lerp( 1.0f - frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y ); info.verts[1].m_TexCoord.y = Lerp( 1.0f - frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y ); } vgui::surface()->DrawRenderCharFromInfo(info); } } else { if ( textureId == -1 ) return; float fw = (float)Width(); float fh = (float)Height(); float twidth = texCoords[ 2 ] - texCoords[ 0 ]; float theight = texCoords[ 3 ] - texCoords[ 1 ]; // Interpolate coords float tCoords[ 4 ]; tCoords[ 0 ] = texCoords[ 0 ] + ( (float)cropx / fw ) * twidth; tCoords[ 1 ] = texCoords[ 1 ] + ( (float)cropy / fh ) * theight; tCoords[ 2 ] = texCoords[ 0 ] + ( (float)(cropx + cropw ) / fw ) * twidth; tCoords[ 3 ] = texCoords[ 1 ] + ( (float)(cropy + croph ) / fh ) * theight; vgui::surface()->DrawSetTexture( textureId ); vgui::surface()->DrawSetColor( clr ); vgui::surface()->DrawTexturedSubRect( x, y, x + finalWidth, y + finalHeight, tCoords[ 0 ], tCoords[ 1 ], tCoords[ 2 ], tCoords[ 3 ] ); } } void CHudTexture::DrawSelfCropped( int x, int y, int cropx, int cropy, int cropw, int croph, Color clr ) const { DrawSelfCropped( x, y, cropx, cropy, cropw, croph, cropw, croph, clr ); } //----------------------------------------------------------------------------- // Purpose: returns width of texture with scale factor applied. (If rendered // using font, scale factor is ignored.) //----------------------------------------------------------------------------- int CHudTexture::EffectiveWidth( float flScale ) const { if ( !bRenderUsingFont ) { return (int) ( Width() * flScale ); } else { return vgui::surface()->GetCharacterWidth( hFont, cCharacterInFont ); } } //----------------------------------------------------------------------------- // Purpose: returns height of texture with scale factor applied. (If rendered // using font, scale factor is ignored.) //----------------------------------------------------------------------------- int CHudTexture::EffectiveHeight( float flScale ) const { if ( !bRenderUsingFont ) { return (int) ( Height() * flScale ); } else { return vgui::surface()->GetFontAscent( hFont, cCharacterInFont ); } } //----------------------------------------------------------------------------- // Purpose: Gets texture handles for the hud icon //----------------------------------------------------------------------------- void CHud::SetupNewHudTexture( CHudTexture *t ) { if ( t->bRenderUsingFont ) { vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); t->hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( t->szTextureFile, true ); t->rc.top = 0; t->rc.left = 0; t->rc.right = vgui::surface()->GetCharacterWidth( t->hFont, t->cCharacterInFont ); t->rc.bottom = vgui::surface()->GetFontTall( t->hFont ); } else { // Set up texture id and texture coordinates t->textureId = vgui::surface()->CreateNewTextureID(); vgui::surface()->DrawSetTextureFile( t->textureId, t->szTextureFile, false, false ); int wide, tall; vgui::surface()->DrawGetTextureSize( t->textureId, wide, tall ); t->texCoords[ 0 ] = (float)(t->rc.left + 0.5f) / (float)wide; t->texCoords[ 1 ] = (float)(t->rc.top + 0.5f) / (float)tall; t->texCoords[ 2 ] = (float)(t->rc.right - 0.5f) / (float)wide; t->texCoords[ 3 ] = (float)(t->rc.bottom - 0.5f) / (float)tall; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CHudTexture *CHud::AddUnsearchableHudIconToList( CHudTexture& texture ) { // These names are composed based on the texture file name char composedName[ 512 ]; if ( texture.bRenderUsingFont ) { Q_snprintf( composedName, sizeof( composedName ), "%s_c%i", texture.szTextureFile, texture.cCharacterInFont ); } else { Q_snprintf( composedName, sizeof( composedName ), "%s_%i_%i_%i_%i", texture.szTextureFile, texture.rc.left, texture.rc.top, texture.rc.right, texture.rc.bottom ); } CHudTexture *icon = GetIcon( composedName ); if ( icon ) { return icon; } CHudTexture *newTexture = ( CHudTexture * )g_HudTextureMemoryPool.Alloc(); *newTexture = texture; SetupNewHudTexture( newTexture ); int idx = m_Icons.Insert( composedName, newTexture ); return m_Icons[ idx ]; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CHudTexture *CHud::AddSearchableHudIconToList( CHudTexture& texture ) { CHudTexture *icon = GetIcon( texture.szShortName ); if ( icon ) { return icon; } CHudTexture *newTexture = ( CHudTexture * )g_HudTextureMemoryPool.Alloc(); *newTexture = texture; SetupNewHudTexture( newTexture ); int idx = m_Icons.Insert( texture.szShortName, newTexture ); return m_Icons[ idx ]; } //----------------------------------------------------------------------------- // Purpose: returns a pointer to an icon in the list //----------------------------------------------------------------------------- CHudTexture *CHud::GetIcon( const char *szIcon ) { int i = m_Icons.Find( szIcon ); if ( i == m_Icons.InvalidIndex() ) return NULL; return m_Icons[ i ]; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHud::RefreshHudTextures() { if ( !m_bHudTexturesLoaded ) { Assert( 0 ); return; } CUtlDict< CHudTexture *, int > textureList; // check to see if we have sprites for this res; if not, step down LoadHudTextures( textureList, "scripts/hud_textures", NULL ); LoadHudTextures( textureList, "scripts/mod_textures", NULL ); // fix up all the texture icons first int c = textureList.Count(); for ( int index = 0; index < c; index++ ) { CHudTexture *tex = textureList[ index ]; Assert( tex ); CHudTexture *icon = GetIcon( tex->szShortName ); if ( !icon ) continue; // Update file Q_strncpy( icon->szTextureFile, tex->szTextureFile, sizeof( icon->szTextureFile ) ); if ( !icon->bRenderUsingFont ) { // Update subrect icon->rc = tex->rc; // Keep existing texture id, but now update texture file and texture coordinates vgui::surface()->DrawSetTextureFile( icon->textureId, icon->szTextureFile, false, false ); // Get new texture dimensions in case it changed int wide, tall; vgui::surface()->DrawGetTextureSize( icon->textureId, wide, tall ); // Assign coords icon->texCoords[ 0 ] = (float)(icon->rc.left + 0.5f) / (float)wide; icon->texCoords[ 1 ] = (float)(icon->rc.top + 0.5f) / (float)tall; icon->texCoords[ 2 ] = (float)(icon->rc.right - 0.5f) / (float)wide; icon->texCoords[ 3 ] = (float)(icon->rc.bottom - 0.5f) / (float)tall; } } FreeHudTextureList( textureList ); // fixup all the font icons vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); for (int i = m_Icons.First(); m_Icons.IsValidIndex(i); i = m_Icons.Next(i)) { CHudTexture *icon = m_Icons[i]; if ( !icon ) continue; // Update file if ( icon->bRenderUsingFont ) { icon->hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( icon->szTextureFile, true ); icon->rc.top = 0; icon->rc.left = 0; icon->rc.right = vgui::surface()->GetCharacterWidth( icon->hFont, icon->cCharacterInFont ); icon->rc.bottom = vgui::surface()->GetFontTall( icon->hFont ); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHud::OnRestore() { ResetHUD(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHud::VidInit( void ) { for ( int i = 0; i < m_HudList.Size(); i++ ) { m_HudList[i]->VidInit(); } ResetHUD(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CHudElement *CHud::FindElement( const char *pName ) { for ( int i = 0; i < m_HudList.Size(); i++ ) { if ( V_stricmp( m_HudList[i]->GetName(), pName ) == 0 ) return m_HudList[i]; } DevWarning(1, "Could not find Hud Element: %s\n", pName ); Assert(0); return NULL; } //----------------------------------------------------------------------------- // Purpose: Adds a member to the HUD //----------------------------------------------------------------------------- void CHud::AddHudElement( CHudElement *pHudElement ) { // Add the hud element to the end of the array m_HudList.AddToTail( pHudElement ); pHudElement->SetNeedsRemove( true ); } //----------------------------------------------------------------------------- // Purpose: Remove an element from the HUD //----------------------------------------------------------------------------- void CHud::RemoveHudElement( CHudElement *pHudElement ) { m_HudList.FindAndRemove( pHudElement ); } //----------------------------------------------------------------------------- // Purpose: Returns current mouse sensitivity setting // Output : float - the return value //----------------------------------------------------------------------------- float CHud::GetSensitivity( void ) { #ifndef _X360 return m_flMouseSensitivity; #else return 1.0f; #endif } float CHud::GetFOVSensitivityAdjust() { return m_flFOVSensitivityAdjust; } //----------------------------------------------------------------------------- // Purpose: Return true if the passed in sections of the HUD shouldn't be drawn //----------------------------------------------------------------------------- bool CHud::IsHidden( int iHudFlags ) { // Not in game? if ( !engine->IsInGame() ) return true; // No local player yet? C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pPlayer ) return true; // Get current hidden flags int iHideHud = pPlayer->m_Local.m_iHideHUD; if ( hidehud.GetInt() ) { iHideHud = hidehud.GetInt(); } // Everything hidden? if ( iHideHud & HIDEHUD_ALL ) return true; // Local player dead? if ( ( iHudFlags & HIDEHUD_PLAYERDEAD ) && ( pPlayer->GetHealth() <= 0 && !pPlayer->IsAlive() ) ) return true; // Need the HEV suit ( HL2 ) if ( ( iHudFlags & HIDEHUD_NEEDSUIT ) && ( !pPlayer->IsSuitEquipped() ) ) return true; // Hide all HUD elements during screenshot if the user's set hud_freezecamhide ( TF2 ) #if defined( TF_CLIENT_DLL ) extern bool IsTakingAFreezecamScreenshot(); extern ConVar hud_freezecamhide; if ( IsTakingAFreezecamScreenshot() && hud_freezecamhide.GetBool() ) return true; #endif return ( ( iHudFlags & iHideHud ) != 0); } //----------------------------------------------------------------------------- // Purpose: Allows HUD to modify input data //----------------------------------------------------------------------------- void CHud::ProcessInput( bool bActive ) { if ( bActive ) { m_iKeyBits = input->GetButtonBits( 0 ); // Weaponbits need to be sent down as a UserMsg now. gHUD.Think(); } } int CHud::LookupRenderGroupIndexByName( const char *pszGroupName ) { return m_RenderGroupNames.Find( pszGroupName ); } //----------------------------------------------------------------------------- // Purpose: A hud element wants to lock this render group so other panels in the // group do not draw //----------------------------------------------------------------------------- bool CHud::LockRenderGroup( int iGroupIndex, CHudElement *pLocker /* = NULL */ ) { // does this index exist? if ( !DoesRenderGroupExist(iGroupIndex) ) return false; int i = m_RenderGroups.Find( iGroupIndex ); Assert( m_RenderGroups.IsValidIndex(i) ); CHudRenderGroup *group = m_RenderGroups.Element(i); Assert( group ); if ( group ) { // NULL pLocker means some higher power is globally hiding this group if ( pLocker == NULL ) { group->bHidden = true; } else { bool bFound = false; // See if we have it locked already int iNumLockers = group->m_pLockingElements.Count(); for ( int i=0;im_pLockingElements.Element(i) ) { bFound = true; break; } } // otherwise lock us if ( !bFound ) group->m_pLockingElements.Insert( pLocker ); } return true; } return false; } //----------------------------------------------------------------------------- // Purpose: A hud element wants to release the lock on this render group //----------------------------------------------------------------------------- bool CHud::UnlockRenderGroup( int iGroupIndex, CHudElement *pLocker /* = NULL */ ) { // does this index exist? if ( !DoesRenderGroupExist(iGroupIndex) ) return false; int i = m_RenderGroups.Find( iGroupIndex ); Assert( m_RenderGroups.IsValidIndex(i) ); CHudRenderGroup *group = m_RenderGroups.Element(i); if ( group ) { // NULL pLocker means some higher power is globally hiding this group if ( group->bHidden && pLocker == NULL ) { group->bHidden = false; return true; } int iNumLockers = group->m_pLockingElements.Count(); for ( int i=0;im_pLockingElements.Element(i) ) { group->m_pLockingElements.RemoveAt( i ); return true; } } } return false; } //----------------------------------------------------------------------------- // Purpose: See if we should draw based on a hud render group // Return true if this group is locked, hud elem will be hidden //----------------------------------------------------------------------------- bool CHud::IsRenderGroupLockedFor( CHudElement *pHudElement, int iGroupIndex ) { // does this index exist? if ( !DoesRenderGroupExist(iGroupIndex) ) return false; int i = m_RenderGroups.Find( iGroupIndex ); Assert( m_RenderGroups.IsValidIndex(i) ); CHudRenderGroup *group = m_RenderGroups.Element(i); if ( !group ) return false; // hidden for everyone! if ( group->bHidden ) return true; if ( group->m_pLockingElements.Count() == 0 ) return false; if ( !pHudElement ) return true; CHudElement *pLocker = group->m_pLockingElements.ElementAtHead(); return ( pLocker != pHudElement && pLocker->GetRenderGroupPriority() > pHudElement->GetRenderGroupPriority() ); } //----------------------------------------------------------------------------- // Purpose: CHudElements can ask for the index of hud element render groups // returns a group index //----------------------------------------------------------------------------- int CHud::RegisterForRenderGroup( const char *pszGroupName ) { int iGroupNameIndex = m_RenderGroupNames.Find( pszGroupName ); if ( iGroupNameIndex != m_RenderGroupNames.InvalidIndex() ) { return iGroupNameIndex; } // otherwise add the group return AddHudRenderGroup( pszGroupName ); } //----------------------------------------------------------------------------- // Purpose: Create a new hud render group // returns a group index //----------------------------------------------------------------------------- int CHud::AddHudRenderGroup( const char *pszGroupName ) { // we tried to register for a group but didn't find it, add a new one int iGroupNameIndex = m_RenderGroupNames.AddToTail( pszGroupName ); CHudRenderGroup *group = new CHudRenderGroup(); return m_RenderGroups.Insert( iGroupNameIndex, group ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CHud::DoesRenderGroupExist( int iGroupIndex ) { return ( m_RenderGroups.Find( iGroupIndex ) != m_RenderGroups.InvalidIndex() ); } //----------------------------------------------------------------------------- // Purpose: Allows HUD to Think and modify input data // Input : *cdata - // time - // Output : int - 1 if there were changes, 0 otherwise //----------------------------------------------------------------------------- void CHud::UpdateHud( bool bActive ) { // clear the weapon bits. gHUD.m_iKeyBits &= (~(IN_WEAPON1|IN_WEAPON2)); g_pClientMode->Update(); gLCD.Update(); } //----------------------------------------------------------------------------- // Purpose: Force a Hud UI anim to play //----------------------------------------------------------------------------- CON_COMMAND_F( testhudanim, "Test a hud element animation.\n\tArguments: \n", FCVAR_CHEAT ) { if ( args.ArgC() != 2 ) { Msg("Usage:\n testhudanim \n"); return; } g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( args[1] ); }