Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1199 lines
35 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. //
  9. // hud.cpp
  10. //
  11. // implementation of CHud class
  12. //
  13. #include "cbase.h"
  14. #include "hud_macros.h"
  15. #include "history_resource.h"
  16. #include "iinput.h"
  17. #include "clientmode.h"
  18. #include "in_buttons.h"
  19. #include <vgui_controls/Controls.h>
  20. #include <vgui/ISurface.h>
  21. #include <KeyValues.h>
  22. #include "itextmessage.h"
  23. #include "mempool.h"
  24. #include <KeyValues.h>
  25. #include "filesystem.h"
  26. #include <vgui_controls/AnimationController.h>
  27. #include <vgui/ISurface.h>
  28. #include "hud_lcd.h"
  29. // memdbgon must be the last include file in a .cpp file!!!
  30. #include "tier0/memdbgon.h"
  31. static CClassMemoryPool< CHudTexture > g_HudTextureMemoryPool( 128 );
  32. //-----------------------------------------------------------------------------
  33. // Purpose: Parses the weapon txt files to get the sprites needed.
  34. //-----------------------------------------------------------------------------
  35. struct HudTextureFileRef
  36. {
  37. HudTextureFileRef ( const char *cszFileKey, const char *cszHudTexturePrefix )
  38. {
  39. Q_strncpy( m_cszFileKey, cszFileKey, kcszFileKeyLength );
  40. Q_strncpy( m_cszHudTexturePrefix, cszHudTexturePrefix, kcszHudTexturePrefix );
  41. m_uiPrefixLength = Q_strlen( cszHudTexturePrefix );
  42. m_fileKeySymbol = KeyValuesSystem()->GetSymbolForString( m_cszFileKey );
  43. Assert( m_fileKeySymbol != INVALID_KEY_SYMBOL );
  44. }
  45. enum { kcszFileKeyLength = 64, };
  46. enum { kcszHudTexturePrefix = 16, };
  47. char m_cszFileKey[kcszFileKeyLength];
  48. char m_cszHudTexturePrefix[kcszHudTexturePrefix];
  49. unsigned int m_uiPrefixLength;
  50. HKeySymbol m_fileKeySymbol;
  51. };
  52. void LoadHudTextures( CUtlDict< CHudTexture *, int >& list, const char *szFilenameWithoutExtension, const unsigned char *pICEKey )
  53. {
  54. KeyValues *pTemp, *pTextureSection;
  55. KeyValues *pKeyValuesData = ReadEncryptedKVFile( filesystem, szFilenameWithoutExtension, pICEKey );
  56. if ( pKeyValuesData )
  57. {
  58. CUtlVector<HudTextureFileRef> hudTextureFileRefs;
  59. // By default, add a default entry mapping "file" to no prefix. This will allow earlier-version files
  60. // to work with no modification.
  61. hudTextureFileRefs.AddToTail( HudTextureFileRef( "file", "" ) );
  62. // Read "*file"-to-prefix mapping.
  63. KeyValues *pTextureFileRefs = pKeyValuesData->FindKey( "TextureFileRefs" );
  64. if ( pTextureFileRefs )
  65. {
  66. pTemp = pTextureFileRefs->GetFirstSubKey();
  67. while ( pTemp )
  68. {
  69. hudTextureFileRefs.AddToTail( HudTextureFileRef( pTemp->GetName(), pTemp->GetString( "prefix", "" ) ) );
  70. pTemp = pTemp->GetNextKey();
  71. }
  72. }
  73. // Read our individual HUD texture data blocks.
  74. pTextureSection = pKeyValuesData->FindKey( "TextureData" );
  75. if ( pTextureSection )
  76. {
  77. // Read the sprite data
  78. pTemp = pTextureSection->GetFirstSubKey();
  79. while ( pTemp )
  80. {
  81. if ( pTemp->GetString( "font", NULL ) )
  82. {
  83. CHudTexture *tex = new CHudTexture();
  84. // Key Name is the sprite name
  85. Q_strncpy( tex->szShortName, pTemp->GetName(), sizeof( tex->szShortName ) );
  86. // it's a font-based icon
  87. tex->bRenderUsingFont = true;
  88. tex->cCharacterInFont = *(pTemp->GetString("character", ""));
  89. Q_strncpy( tex->szTextureFile, pTemp->GetString( "font" ), sizeof( tex->szTextureFile ) );
  90. list.Insert( tex->szShortName, tex );
  91. }
  92. else
  93. {
  94. int iTexLeft = pTemp->GetInt( "x", 0 ),
  95. iTexTop = pTemp->GetInt( "y", 0 ),
  96. iTexRight = pTemp->GetInt( "width", 0 ) + iTexLeft,
  97. iTexBottom = pTemp->GetInt( "height", 0 ) + iTexTop;
  98. for ( int i = 0; i < hudTextureFileRefs.Size(); i++ )
  99. {
  100. const char *cszFilename = pTemp->GetString( hudTextureFileRefs[i].m_fileKeySymbol, NULL );
  101. if ( cszFilename )
  102. {
  103. CHudTexture *tex = new CHudTexture();
  104. tex->bRenderUsingFont = false;
  105. tex->rc.left = iTexLeft;
  106. tex->rc.top = iTexTop;
  107. tex->rc.right = iTexRight;
  108. tex->rc.bottom = iTexBottom;
  109. Q_strncpy( tex->szShortName, hudTextureFileRefs[i].m_cszHudTexturePrefix, sizeof( tex->szShortName ) );
  110. Q_strncpy( tex->szShortName + hudTextureFileRefs[i].m_uiPrefixLength, pTemp->GetName(), sizeof( tex->szShortName ) - hudTextureFileRefs[i].m_uiPrefixLength );
  111. Q_strncpy( tex->szTextureFile, cszFilename, sizeof( tex->szTextureFile ) );
  112. list.Insert( tex->szShortName, tex );
  113. }
  114. }
  115. }
  116. pTemp = pTemp->GetNextKey();
  117. }
  118. }
  119. }
  120. // Failed for some reason. Delete the Key data and abort.
  121. pKeyValuesData->deleteThis();
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose:
  125. // Input : * -
  126. // list -
  127. //-----------------------------------------------------------------------------
  128. void FreeHudTextureList( CUtlDict< CHudTexture *, int >& list )
  129. {
  130. int c = list.Count();
  131. for ( int i = 0; i < c; i++ )
  132. {
  133. CHudTexture *tex = list[ i ];
  134. delete tex;
  135. }
  136. list.RemoveAll();
  137. }
  138. // Globally-used fonts
  139. vgui::HFont g_hFontTrebuchet24 = vgui::INVALID_FONT;
  140. //=======================================================================================================================
  141. // Hud Element Visibility handling
  142. //=======================================================================================================================
  143. typedef struct hudelement_hidden_s
  144. {
  145. char *sElementName;
  146. int iHiddenBits; // Bits in which this hud element is hidden
  147. } hudelement_hidden_t;
  148. ConVar hidehud( "hidehud", "0", FCVAR_CHEAT );
  149. CHudTexture::CHudTexture()
  150. {
  151. Q_memset( szShortName, 0, sizeof( szShortName ) );
  152. Q_memset( szTextureFile, 0, sizeof( szTextureFile ) );
  153. Q_memset( texCoords, 0, sizeof( texCoords ) );
  154. Q_memset( &rc, 0, sizeof( rc ) );
  155. textureId = -1;
  156. bRenderUsingFont = false;
  157. bPrecached = false;
  158. cCharacterInFont = 0;
  159. hFont = ( vgui::HFont )NULL;
  160. }
  161. CHudTexture& CHudTexture::operator =( const CHudTexture& src )
  162. {
  163. if ( this == &src )
  164. return *this;
  165. Q_strncpy( szShortName, src.szShortName, sizeof( szShortName ) );
  166. Q_strncpy( szTextureFile, src.szTextureFile, sizeof( szTextureFile ) );
  167. Q_memcpy( texCoords, src.texCoords, sizeof( texCoords ) );
  168. if ( src.textureId == -1 )
  169. {
  170. // Didn't have a texture ID set
  171. textureId = -1;
  172. }
  173. else
  174. {
  175. // Make a new texture ID that uses the same texture
  176. textureId = vgui::surface()->CreateNewTextureID();
  177. vgui::surface()->DrawSetTextureFile( textureId, src.szTextureFile, false, false );
  178. }
  179. rc = src.rc;
  180. bRenderUsingFont = src.bRenderUsingFont;
  181. cCharacterInFont = src.cCharacterInFont;
  182. hFont = src.hFont;
  183. return *this;
  184. }
  185. CHudTexture::~CHudTexture()
  186. {
  187. if ( vgui::surface() && textureId != -1 )
  188. {
  189. vgui::surface()->DestroyTextureID( textureId );
  190. textureId = -1;
  191. }
  192. }
  193. //=======================================================================================================================
  194. // CHudElement
  195. // All hud elements are derived from this class.
  196. //=======================================================================================================================
  197. //-----------------------------------------------------------------------------
  198. // Purpose: Registers the hud element in a global list, in CHud
  199. //-----------------------------------------------------------------------------
  200. CHudElement::CHudElement( const char *pElementName )
  201. {
  202. m_bActive = false;
  203. m_iHiddenBits = 0;
  204. m_pElementName = pElementName;
  205. SetNeedsRemove( false );
  206. m_bIsParentedToClientDLLRootPanel = false;
  207. // Make this for all hud elements, but when its a bit safer
  208. #if defined( TF_CLIENT_DLL ) || defined( DOD_DLL )
  209. RegisterForRenderGroup( "global" );
  210. #endif
  211. }
  212. //-----------------------------------------------------------------------------
  213. // Purpose: Remove this hud element from the global list in CHUD
  214. //-----------------------------------------------------------------------------
  215. CHudElement::~CHudElement()
  216. {
  217. if ( m_bNeedsRemove )
  218. {
  219. gHUD.RemoveHudElement( this );
  220. }
  221. }
  222. //-----------------------------------------------------------------------------
  223. // Purpose:
  224. //-----------------------------------------------------------------------------
  225. void CHudElement::SetActive( bool bActive )
  226. {
  227. m_bActive = bActive;
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Purpose:
  231. // Input : needsremove -
  232. //-----------------------------------------------------------------------------
  233. void CHudElement::SetNeedsRemove( bool needsremove )
  234. {
  235. m_bNeedsRemove = needsremove;
  236. }
  237. //-----------------------------------------------------------------------------
  238. // Purpose:
  239. //-----------------------------------------------------------------------------
  240. void CHudElement::SetHiddenBits( int iBits )
  241. {
  242. m_iHiddenBits = iBits;
  243. }
  244. //-----------------------------------------------------------------------------
  245. // Purpose:
  246. //-----------------------------------------------------------------------------
  247. bool CHudElement::ShouldDraw( void )
  248. {
  249. bool bShouldDraw = ( !gHUD.IsHidden( m_iHiddenBits ) );
  250. if ( bShouldDraw )
  251. {
  252. // for each render group
  253. int iNumGroups = m_HudRenderGroups.Count();
  254. for ( int iGroupIndex = 0; iGroupIndex < iNumGroups; iGroupIndex++ )
  255. {
  256. if ( gHUD.IsRenderGroupLockedFor( this, m_HudRenderGroups.Element(iGroupIndex ) ) )
  257. return false;
  258. }
  259. }
  260. return bShouldDraw;
  261. }
  262. //-----------------------------------------------------------------------------
  263. // Purpose:
  264. // Output : Returns true on success, false on failure.
  265. //-----------------------------------------------------------------------------
  266. bool CHudElement::IsParentedToClientDLLRootPanel() const
  267. {
  268. return m_bIsParentedToClientDLLRootPanel;
  269. }
  270. //-----------------------------------------------------------------------------
  271. // Purpose:
  272. // Input : parented -
  273. //-----------------------------------------------------------------------------
  274. void CHudElement::SetParentedToClientDLLRootPanel( bool parented )
  275. {
  276. m_bIsParentedToClientDLLRootPanel = parented;
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Purpose: We can register to be affected by multiple hud render groups
  280. //-----------------------------------------------------------------------------
  281. void CHudElement::RegisterForRenderGroup( const char *pszGroupName )
  282. {
  283. int iGroupIndex = gHUD.RegisterForRenderGroup( pszGroupName );
  284. // add group index to our list of registered groups
  285. if ( m_HudRenderGroups.Find( iGroupIndex ) == m_HudRenderGroups.InvalidIndex() )
  286. {
  287. m_HudRenderGroups.AddToTail( iGroupIndex );
  288. }
  289. }
  290. void CHudElement::UnregisterForRenderGroup( const char *pszGroupName )
  291. {
  292. int iGroupIndex = gHUD.RegisterForRenderGroup( pszGroupName );
  293. m_HudRenderGroups.FindAndRemove( iGroupIndex );
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Purpose: We want to obscure other elements in this group
  297. //-----------------------------------------------------------------------------
  298. void CHudElement::HideLowerPriorityHudElementsInGroup( const char *pszGroupName )
  299. {
  300. // look up the render group
  301. int iGroupIndex = gHUD.LookupRenderGroupIndexByName( pszGroupName );
  302. // lock the group
  303. gHUD.LockRenderGroup( iGroupIndex, this );
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose: Stop obscuring other elements in this group
  307. //-----------------------------------------------------------------------------
  308. void CHudElement::UnhideLowerPriorityHudElementsInGroup( const char *pszGroupName )
  309. {
  310. // look up the render group
  311. int iGroupIndex = gHUD.LookupRenderGroupIndexByName( pszGroupName );
  312. // unlock the group
  313. gHUD.UnlockRenderGroup( iGroupIndex, this );
  314. }
  315. //-----------------------------------------------------------------------------
  316. // Purpose:
  317. //-----------------------------------------------------------------------------
  318. int CHudElement::GetRenderGroupPriority( void )
  319. {
  320. return 0;
  321. }
  322. CHud gHUD; // global HUD object
  323. DECLARE_MESSAGE(gHUD, ResetHUD);
  324. #ifdef CSTRIKE_DLL
  325. DECLARE_MESSAGE(gHUD, SendAudio);
  326. #endif
  327. CHud::CHud()
  328. {
  329. SetDefLessFunc( m_RenderGroups );
  330. m_flScreenShotTime = -1;
  331. }
  332. //-----------------------------------------------------------------------------
  333. // Purpose: This is called every time the DLL is loaded
  334. //-----------------------------------------------------------------------------
  335. void CHud::Init( void )
  336. {
  337. HOOK_HUD_MESSAGE( gHUD, ResetHUD );
  338. #ifdef CSTRIKE_DLL
  339. HOOK_HUD_MESSAGE( gHUD, SendAudio );
  340. #endif
  341. InitFonts();
  342. // Create all the Hud elements
  343. CHudElementHelper::CreateAllElements();
  344. gLCD.Init();
  345. // Initialize all created elements
  346. for ( int i = 0; i < m_HudList.Size(); i++ )
  347. {
  348. m_HudList[i]->Init();
  349. }
  350. m_bHudTexturesLoaded = false;
  351. KeyValues *kv = new KeyValues( "layout" );
  352. if ( kv )
  353. {
  354. if ( kv->LoadFromFile( filesystem, "scripts/HudLayout.res" ) )
  355. {
  356. int numelements = m_HudList.Size();
  357. for ( int i = 0; i < numelements; i++ )
  358. {
  359. CHudElement *element = m_HudList[i];
  360. vgui::Panel *pPanel = dynamic_cast<vgui::Panel*>(element);
  361. if ( !pPanel )
  362. {
  363. Msg( "Non-vgui hud element %s\n", m_HudList[i]->GetName() );
  364. continue;
  365. }
  366. KeyValues *key = kv->FindKey( pPanel->GetName(), false );
  367. if ( !key )
  368. {
  369. Msg( "Hud element '%s' doesn't have an entry '%s' in scripts/HudLayout.res\n", m_HudList[i]->GetName(), pPanel->GetName() );
  370. }
  371. // Note: When a panel is parented to the module root, it's "parent" is returned as NULL.
  372. if ( !element->IsParentedToClientDLLRootPanel() &&
  373. !pPanel->GetParent() )
  374. {
  375. DevMsg( "Hud element '%s'/'%s' doesn't have a parent\n", m_HudList[i]->GetName(), pPanel->GetName() );
  376. }
  377. }
  378. }
  379. kv->deleteThis();
  380. }
  381. if ( m_bHudTexturesLoaded )
  382. return;
  383. m_bHudTexturesLoaded = true;
  384. CUtlDict< CHudTexture *, int > textureList;
  385. // check to see if we have sprites for this res; if not, step down
  386. LoadHudTextures( textureList, "scripts/hud_textures", NULL );
  387. LoadHudTextures( textureList, "scripts/mod_textures", NULL );
  388. int c = textureList.Count();
  389. for ( int index = 0; index < c; index++ )
  390. {
  391. CHudTexture* tex = textureList[ index ];
  392. AddSearchableHudIconToList( *tex );
  393. }
  394. FreeHudTextureList( textureList );
  395. }
  396. //-----------------------------------------------------------------------------
  397. // Purpose: Init Hud global colors
  398. // Input : *scheme -
  399. //-----------------------------------------------------------------------------
  400. void CHud::InitColors( vgui::IScheme *scheme )
  401. {
  402. m_clrNormal = scheme->GetColor( "Normal", Color( 255, 208, 64 ,255 ) );
  403. m_clrCaution = scheme->GetColor( "Caution", Color( 255, 48, 0, 255 ) );
  404. m_clrYellowish = scheme->GetColor( "Yellowish", Color( 255, 160, 0, 255 ) );
  405. }
  406. //-----------------------------------------------------------------------------
  407. // Initializes fonts
  408. //-----------------------------------------------------------------------------
  409. void CHud::InitFonts()
  410. {
  411. vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" );
  412. vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( scheme );
  413. g_hFontTrebuchet24 = pScheme->GetFont("CenterPrintText", true);
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Purpose:
  417. //-----------------------------------------------------------------------------
  418. void CHud::Shutdown( void )
  419. {
  420. gLCD.Shutdown();
  421. // Deleting hudlist items can result in them being removed from the same hudlist (m_bNeedsRemove).
  422. // So go through and kill the last item until the array is empty.
  423. while ( m_HudList.Size() > 0 )
  424. {
  425. delete m_HudList.Tail();
  426. }
  427. m_HudList.Purge();
  428. m_bHudTexturesLoaded = false;
  429. }
  430. //-----------------------------------------------------------------------------
  431. // Purpose: LevelInit's called whenever a new level is starting
  432. //-----------------------------------------------------------------------------
  433. void CHud::LevelInit( void )
  434. {
  435. // Tell all the registered hud elements to LevelInit
  436. for ( int i = 0; i < m_HudList.Size(); i++ )
  437. {
  438. m_HudList[i]->LevelInit();
  439. }
  440. // Unhide all render groups
  441. int iCount = m_RenderGroups.Count();
  442. for ( int i = 0; i < iCount; i++ )
  443. {
  444. CHudRenderGroup *group = m_RenderGroups[ i ];
  445. group->bHidden = false;
  446. group->m_pLockingElements.Purge();
  447. }
  448. }
  449. //-----------------------------------------------------------------------------
  450. // Purpose: LevelShutdown's called whenever a level is finishing
  451. //-----------------------------------------------------------------------------
  452. void CHud::LevelShutdown( void )
  453. {
  454. // Tell all the registered hud elements to LevelShutdown
  455. for ( int i = 0; i < m_HudList.Size(); i++ )
  456. {
  457. m_HudList[i]->LevelShutdown();
  458. }
  459. }
  460. //-----------------------------------------------------------------------------
  461. // Purpose: cleans up memory allocated for m_rg* arrays
  462. //-----------------------------------------------------------------------------
  463. CHud::~CHud()
  464. {
  465. int c = m_Icons.Count();
  466. for ( int i = c - 1; i >= 0; i-- )
  467. {
  468. CHudTexture *tex = m_Icons[ i ];
  469. g_HudTextureMemoryPool.Free( tex );
  470. }
  471. m_Icons.Purge();
  472. c = m_RenderGroups.Count();
  473. for ( int i = c - 1; i >= 0; i-- )
  474. {
  475. CHudRenderGroup *group = m_RenderGroups[ i ];
  476. m_RenderGroups.RemoveAt(i);
  477. delete group;
  478. }
  479. }
  480. void CHudTexture::Precache( void )
  481. {
  482. // costly function, used selectively on specific hud elements to get font pages built out at load time
  483. if ( IsX360() && bRenderUsingFont && !bPrecached && hFont != vgui::INVALID_FONT )
  484. {
  485. wchar_t wideChars[2];
  486. wideChars[0] = (wchar_t)cCharacterInFont;
  487. wideChars[1] = 0;
  488. vgui::surface()->PrecacheFontCharacters( hFont, wideChars );
  489. bPrecached = true;
  490. }
  491. }
  492. void CHudTexture::DrawSelf( int x, int y, const Color& clr ) const
  493. {
  494. DrawSelf( x, y, Width(), Height(), clr );
  495. }
  496. void CHudTexture::DrawSelf( int x, int y, int w, int h, const Color& clr ) const
  497. {
  498. if ( bRenderUsingFont )
  499. {
  500. vgui::surface()->DrawSetTextFont( hFont );
  501. vgui::surface()->DrawSetTextColor( clr );
  502. vgui::surface()->DrawSetTextPos( x, y );
  503. vgui::surface()->DrawUnicodeChar( cCharacterInFont );
  504. }
  505. else
  506. {
  507. if ( textureId == -1 )
  508. return;
  509. vgui::surface()->DrawSetTexture( textureId );
  510. vgui::surface()->DrawSetColor( clr );
  511. vgui::surface()->DrawTexturedSubRect( x, y, x + w, y + h,
  512. texCoords[ 0 ], texCoords[ 1 ], texCoords[ 2 ], texCoords[ 3 ] );
  513. }
  514. }
  515. void CHudTexture::DrawSelfCropped( int x, int y, int cropx, int cropy, int cropw, int croph, int finalWidth, int finalHeight, Color clr ) const
  516. {
  517. if ( bRenderUsingFont )
  518. {
  519. // work out how much we've been cropped
  520. int height = vgui::surface()->GetFontTall( hFont );
  521. float frac = (height - croph) / (float)height;
  522. y -= cropy;
  523. vgui::surface()->DrawSetTextFont( hFont );
  524. vgui::surface()->DrawSetTextColor( clr );
  525. vgui::surface()->DrawSetTextPos( x, y );
  526. vgui::CharRenderInfo info;
  527. if ( vgui::surface()->DrawGetUnicodeCharRenderInfo( cCharacterInFont, info ) )
  528. {
  529. if ( cropy )
  530. {
  531. info.verts[0].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
  532. info.verts[0].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
  533. }
  534. else if ( croph != height )
  535. {
  536. info.verts[1].m_Position.y = Lerp( 1.0f - frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
  537. info.verts[1].m_TexCoord.y = Lerp( 1.0f - frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
  538. }
  539. vgui::surface()->DrawRenderCharFromInfo(info);
  540. }
  541. }
  542. else
  543. {
  544. if ( textureId == -1 )
  545. return;
  546. float fw = (float)Width();
  547. float fh = (float)Height();
  548. float twidth = texCoords[ 2 ] - texCoords[ 0 ];
  549. float theight = texCoords[ 3 ] - texCoords[ 1 ];
  550. // Interpolate coords
  551. float tCoords[ 4 ];
  552. tCoords[ 0 ] = texCoords[ 0 ] + ( (float)cropx / fw ) * twidth;
  553. tCoords[ 1 ] = texCoords[ 1 ] + ( (float)cropy / fh ) * theight;
  554. tCoords[ 2 ] = texCoords[ 0 ] + ( (float)(cropx + cropw ) / fw ) * twidth;
  555. tCoords[ 3 ] = texCoords[ 1 ] + ( (float)(cropy + croph ) / fh ) * theight;
  556. vgui::surface()->DrawSetTexture( textureId );
  557. vgui::surface()->DrawSetColor( clr );
  558. vgui::surface()->DrawTexturedSubRect(
  559. x, y,
  560. x + finalWidth, y + finalHeight,
  561. tCoords[ 0 ], tCoords[ 1 ],
  562. tCoords[ 2 ], tCoords[ 3 ] );
  563. }
  564. }
  565. void CHudTexture::DrawSelfCropped( int x, int y, int cropx, int cropy, int cropw, int croph, Color clr ) const
  566. {
  567. DrawSelfCropped( x, y, cropx, cropy, cropw, croph, cropw, croph, clr );
  568. }
  569. //-----------------------------------------------------------------------------
  570. // Purpose: returns width of texture with scale factor applied. (If rendered
  571. // using font, scale factor is ignored.)
  572. //-----------------------------------------------------------------------------
  573. int CHudTexture::EffectiveWidth( float flScale ) const
  574. {
  575. if ( !bRenderUsingFont )
  576. {
  577. return (int) ( Width() * flScale );
  578. }
  579. else
  580. {
  581. return vgui::surface()->GetCharacterWidth( hFont, cCharacterInFont );
  582. }
  583. }
  584. //-----------------------------------------------------------------------------
  585. // Purpose: returns height of texture with scale factor applied. (If rendered
  586. // using font, scale factor is ignored.)
  587. //-----------------------------------------------------------------------------
  588. int CHudTexture::EffectiveHeight( float flScale ) const
  589. {
  590. if ( !bRenderUsingFont )
  591. {
  592. return (int) ( Height() * flScale );
  593. }
  594. else
  595. {
  596. return vgui::surface()->GetFontAscent( hFont, cCharacterInFont );
  597. }
  598. }
  599. //-----------------------------------------------------------------------------
  600. // Purpose: Gets texture handles for the hud icon
  601. //-----------------------------------------------------------------------------
  602. void CHud::SetupNewHudTexture( CHudTexture *t )
  603. {
  604. if ( t->bRenderUsingFont )
  605. {
  606. vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" );
  607. t->hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( t->szTextureFile, true );
  608. t->rc.top = 0;
  609. t->rc.left = 0;
  610. t->rc.right = vgui::surface()->GetCharacterWidth( t->hFont, t->cCharacterInFont );
  611. t->rc.bottom = vgui::surface()->GetFontTall( t->hFont );
  612. }
  613. else
  614. {
  615. // Set up texture id and texture coordinates
  616. t->textureId = vgui::surface()->CreateNewTextureID();
  617. vgui::surface()->DrawSetTextureFile( t->textureId, t->szTextureFile, false, false );
  618. int wide, tall;
  619. vgui::surface()->DrawGetTextureSize( t->textureId, wide, tall );
  620. t->texCoords[ 0 ] = (float)(t->rc.left + 0.5f) / (float)wide;
  621. t->texCoords[ 1 ] = (float)(t->rc.top + 0.5f) / (float)tall;
  622. t->texCoords[ 2 ] = (float)(t->rc.right - 0.5f) / (float)wide;
  623. t->texCoords[ 3 ] = (float)(t->rc.bottom - 0.5f) / (float)tall;
  624. }
  625. }
  626. //-----------------------------------------------------------------------------
  627. // Purpose:
  628. //-----------------------------------------------------------------------------
  629. CHudTexture *CHud::AddUnsearchableHudIconToList( CHudTexture& texture )
  630. {
  631. // These names are composed based on the texture file name
  632. char composedName[ 512 ];
  633. if ( texture.bRenderUsingFont )
  634. {
  635. Q_snprintf( composedName, sizeof( composedName ), "%s_c%i",
  636. texture.szTextureFile, texture.cCharacterInFont );
  637. }
  638. else
  639. {
  640. Q_snprintf( composedName, sizeof( composedName ), "%s_%i_%i_%i_%i",
  641. texture.szTextureFile, texture.rc.left, texture.rc.top, texture.rc.right, texture.rc.bottom );
  642. }
  643. CHudTexture *icon = GetIcon( composedName );
  644. if ( icon )
  645. {
  646. return icon;
  647. }
  648. CHudTexture *newTexture = ( CHudTexture * )g_HudTextureMemoryPool.Alloc();
  649. *newTexture = texture;
  650. SetupNewHudTexture( newTexture );
  651. int idx = m_Icons.Insert( composedName, newTexture );
  652. return m_Icons[ idx ];
  653. }
  654. //-----------------------------------------------------------------------------
  655. // Purpose:
  656. //-----------------------------------------------------------------------------
  657. CHudTexture *CHud::AddSearchableHudIconToList( CHudTexture& texture )
  658. {
  659. CHudTexture *icon = GetIcon( texture.szShortName );
  660. if ( icon )
  661. {
  662. return icon;
  663. }
  664. CHudTexture *newTexture = ( CHudTexture * )g_HudTextureMemoryPool.Alloc();
  665. *newTexture = texture;
  666. SetupNewHudTexture( newTexture );
  667. int idx = m_Icons.Insert( texture.szShortName, newTexture );
  668. return m_Icons[ idx ];
  669. }
  670. //-----------------------------------------------------------------------------
  671. // Purpose: returns a pointer to an icon in the list
  672. //-----------------------------------------------------------------------------
  673. CHudTexture *CHud::GetIcon( const char *szIcon )
  674. {
  675. int i = m_Icons.Find( szIcon );
  676. if ( i == m_Icons.InvalidIndex() )
  677. return NULL;
  678. return m_Icons[ i ];
  679. }
  680. //-----------------------------------------------------------------------------
  681. // Purpose:
  682. //-----------------------------------------------------------------------------
  683. void CHud::RefreshHudTextures()
  684. {
  685. if ( !m_bHudTexturesLoaded )
  686. {
  687. Assert( 0 );
  688. return;
  689. }
  690. CUtlDict< CHudTexture *, int > textureList;
  691. // check to see if we have sprites for this res; if not, step down
  692. LoadHudTextures( textureList, "scripts/hud_textures", NULL );
  693. LoadHudTextures( textureList, "scripts/mod_textures", NULL );
  694. // fix up all the texture icons first
  695. int c = textureList.Count();
  696. for ( int index = 0; index < c; index++ )
  697. {
  698. CHudTexture *tex = textureList[ index ];
  699. Assert( tex );
  700. CHudTexture *icon = GetIcon( tex->szShortName );
  701. if ( !icon )
  702. continue;
  703. // Update file
  704. Q_strncpy( icon->szTextureFile, tex->szTextureFile, sizeof( icon->szTextureFile ) );
  705. if ( !icon->bRenderUsingFont )
  706. {
  707. // Update subrect
  708. icon->rc = tex->rc;
  709. // Keep existing texture id, but now update texture file and texture coordinates
  710. vgui::surface()->DrawSetTextureFile( icon->textureId, icon->szTextureFile, false, false );
  711. // Get new texture dimensions in case it changed
  712. int wide, tall;
  713. vgui::surface()->DrawGetTextureSize( icon->textureId, wide, tall );
  714. // Assign coords
  715. icon->texCoords[ 0 ] = (float)(icon->rc.left + 0.5f) / (float)wide;
  716. icon->texCoords[ 1 ] = (float)(icon->rc.top + 0.5f) / (float)tall;
  717. icon->texCoords[ 2 ] = (float)(icon->rc.right - 0.5f) / (float)wide;
  718. icon->texCoords[ 3 ] = (float)(icon->rc.bottom - 0.5f) / (float)tall;
  719. }
  720. }
  721. FreeHudTextureList( textureList );
  722. // fixup all the font icons
  723. vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" );
  724. for (int i = m_Icons.First(); m_Icons.IsValidIndex(i); i = m_Icons.Next(i))
  725. {
  726. CHudTexture *icon = m_Icons[i];
  727. if ( !icon )
  728. continue;
  729. // Update file
  730. if ( icon->bRenderUsingFont )
  731. {
  732. icon->hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( icon->szTextureFile, true );
  733. icon->rc.top = 0;
  734. icon->rc.left = 0;
  735. icon->rc.right = vgui::surface()->GetCharacterWidth( icon->hFont, icon->cCharacterInFont );
  736. icon->rc.bottom = vgui::surface()->GetFontTall( icon->hFont );
  737. }
  738. }
  739. }
  740. //-----------------------------------------------------------------------------
  741. // Purpose:
  742. //-----------------------------------------------------------------------------
  743. void CHud::OnRestore()
  744. {
  745. ResetHUD();
  746. }
  747. //-----------------------------------------------------------------------------
  748. // Purpose:
  749. //-----------------------------------------------------------------------------
  750. void CHud::VidInit( void )
  751. {
  752. for ( int i = 0; i < m_HudList.Size(); i++ )
  753. {
  754. m_HudList[i]->VidInit();
  755. }
  756. ResetHUD();
  757. }
  758. //-----------------------------------------------------------------------------
  759. // Purpose:
  760. //-----------------------------------------------------------------------------
  761. CHudElement *CHud::FindElement( const char *pName )
  762. {
  763. for ( int i = 0; i < m_HudList.Size(); i++ )
  764. {
  765. if ( V_stricmp( m_HudList[i]->GetName(), pName ) == 0 )
  766. return m_HudList[i];
  767. }
  768. DevWarning(1, "Could not find Hud Element: %s\n", pName );
  769. Assert(0);
  770. return NULL;
  771. }
  772. //-----------------------------------------------------------------------------
  773. // Purpose: Adds a member to the HUD
  774. //-----------------------------------------------------------------------------
  775. void CHud::AddHudElement( CHudElement *pHudElement )
  776. {
  777. // Add the hud element to the end of the array
  778. m_HudList.AddToTail( pHudElement );
  779. pHudElement->SetNeedsRemove( true );
  780. }
  781. //-----------------------------------------------------------------------------
  782. // Purpose: Remove an element from the HUD
  783. //-----------------------------------------------------------------------------
  784. void CHud::RemoveHudElement( CHudElement *pHudElement )
  785. {
  786. m_HudList.FindAndRemove( pHudElement );
  787. }
  788. //-----------------------------------------------------------------------------
  789. // Purpose: Returns current mouse sensitivity setting
  790. // Output : float - the return value
  791. //-----------------------------------------------------------------------------
  792. float CHud::GetSensitivity( void )
  793. {
  794. #ifndef _X360
  795. return m_flMouseSensitivity;
  796. #else
  797. return 1.0f;
  798. #endif
  799. }
  800. float CHud::GetFOVSensitivityAdjust()
  801. {
  802. return m_flFOVSensitivityAdjust;
  803. }
  804. //-----------------------------------------------------------------------------
  805. // Purpose: Return true if the passed in sections of the HUD shouldn't be drawn
  806. //-----------------------------------------------------------------------------
  807. bool CHud::IsHidden( int iHudFlags )
  808. {
  809. // Not in game?
  810. if ( !engine->IsInGame() )
  811. return true;
  812. // No local player yet?
  813. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  814. if ( !pPlayer )
  815. return true;
  816. // Get current hidden flags
  817. int iHideHud = pPlayer->m_Local.m_iHideHUD;
  818. if ( hidehud.GetInt() )
  819. {
  820. iHideHud = hidehud.GetInt();
  821. }
  822. // Everything hidden?
  823. if ( iHideHud & HIDEHUD_ALL )
  824. return true;
  825. // Local player dead?
  826. if ( ( iHudFlags & HIDEHUD_PLAYERDEAD ) && ( pPlayer->GetHealth() <= 0 && !pPlayer->IsAlive() ) )
  827. return true;
  828. // Need the HEV suit ( HL2 )
  829. if ( ( iHudFlags & HIDEHUD_NEEDSUIT ) && ( !pPlayer->IsSuitEquipped() ) )
  830. return true;
  831. // Hide all HUD elements during screenshot if the user's set hud_freezecamhide ( TF2 )
  832. #if defined( TF_CLIENT_DLL )
  833. extern bool IsTakingAFreezecamScreenshot();
  834. extern ConVar hud_freezecamhide;
  835. if ( IsTakingAFreezecamScreenshot() && hud_freezecamhide.GetBool() )
  836. return true;
  837. #endif
  838. return ( ( iHudFlags & iHideHud ) != 0);
  839. }
  840. //-----------------------------------------------------------------------------
  841. // Purpose: Allows HUD to modify input data
  842. //-----------------------------------------------------------------------------
  843. void CHud::ProcessInput( bool bActive )
  844. {
  845. if ( bActive )
  846. {
  847. m_iKeyBits = input->GetButtonBits( 0 );
  848. // Weaponbits need to be sent down as a UserMsg now.
  849. gHUD.Think();
  850. }
  851. }
  852. int CHud::LookupRenderGroupIndexByName( const char *pszGroupName )
  853. {
  854. return m_RenderGroupNames.Find( pszGroupName );
  855. }
  856. //-----------------------------------------------------------------------------
  857. // Purpose: A hud element wants to lock this render group so other panels in the
  858. // group do not draw
  859. //-----------------------------------------------------------------------------
  860. bool CHud::LockRenderGroup( int iGroupIndex, CHudElement *pLocker /* = NULL */ )
  861. {
  862. // does this index exist?
  863. if ( !DoesRenderGroupExist(iGroupIndex) )
  864. return false;
  865. int iRenderGroup = m_RenderGroups.Find( iGroupIndex );
  866. Assert( m_RenderGroups.IsValidIndex( iRenderGroup ) );
  867. CHudRenderGroup *group = m_RenderGroups.Element( iRenderGroup );
  868. Assert( group );
  869. if ( group )
  870. {
  871. // NULL pLocker means some higher power is globally hiding this group
  872. if ( pLocker == NULL )
  873. {
  874. group->bHidden = true;
  875. }
  876. else
  877. {
  878. bool bFound = false;
  879. // See if we have it locked already
  880. int iNumLockers = group->m_pLockingElements.Count();
  881. for ( int i=0;i<iNumLockers;i++ )
  882. {
  883. if ( pLocker == group->m_pLockingElements.Element(i) )
  884. {
  885. bFound = true;
  886. break;
  887. }
  888. }
  889. // otherwise lock us
  890. if ( !bFound )
  891. group->m_pLockingElements.Insert( pLocker );
  892. }
  893. return true;
  894. }
  895. return false;
  896. }
  897. //-----------------------------------------------------------------------------
  898. // Purpose: A hud element wants to release the lock on this render group
  899. //-----------------------------------------------------------------------------
  900. bool CHud::UnlockRenderGroup( int iGroupIndex, CHudElement *pLocker /* = NULL */ )
  901. {
  902. // does this index exist?
  903. if ( !DoesRenderGroupExist(iGroupIndex) )
  904. return false;
  905. int iRenderGroup = m_RenderGroups.Find( iGroupIndex );
  906. Assert( m_RenderGroups.IsValidIndex( iRenderGroup ) );
  907. CHudRenderGroup *group = m_RenderGroups.Element( iRenderGroup );
  908. if ( group )
  909. {
  910. // NULL pLocker means some higher power is globally hiding this group
  911. if ( group->bHidden && pLocker == NULL )
  912. {
  913. group->bHidden = false;
  914. return true;
  915. }
  916. int iNumLockers = group->m_pLockingElements.Count();
  917. for ( int i=0;i<iNumLockers;i++ )
  918. {
  919. if ( pLocker == group->m_pLockingElements.Element(i) )
  920. {
  921. group->m_pLockingElements.RemoveAt( i );
  922. return true;
  923. }
  924. }
  925. }
  926. return false;
  927. }
  928. //-----------------------------------------------------------------------------
  929. // Purpose: See if we should draw based on a hud render group
  930. // Return true if this group is locked, hud elem will be hidden
  931. //-----------------------------------------------------------------------------
  932. bool CHud::IsRenderGroupLockedFor( CHudElement *pHudElement, int iGroupIndex )
  933. {
  934. // does this index exist?
  935. if ( !DoesRenderGroupExist(iGroupIndex) )
  936. return false;
  937. int i = m_RenderGroups.Find( iGroupIndex );
  938. Assert( m_RenderGroups.IsValidIndex(i) );
  939. CHudRenderGroup *group = m_RenderGroups.Element(i);
  940. if ( !group )
  941. return false;
  942. // hidden for everyone!
  943. if ( group->bHidden )
  944. return true;
  945. if ( group->m_pLockingElements.Count() == 0 )
  946. return false;
  947. if ( !pHudElement )
  948. return true;
  949. CHudElement *pLocker = group->m_pLockingElements.ElementAtHead();
  950. return ( pLocker != pHudElement && pLocker->GetRenderGroupPriority() > pHudElement->GetRenderGroupPriority() );
  951. }
  952. //-----------------------------------------------------------------------------
  953. // Purpose: CHudElements can ask for the index of hud element render groups
  954. // returns a group index
  955. //-----------------------------------------------------------------------------
  956. int CHud::RegisterForRenderGroup( const char *pszGroupName )
  957. {
  958. int iGroupNameIndex = m_RenderGroupNames.Find( pszGroupName );
  959. if ( iGroupNameIndex != m_RenderGroupNames.InvalidIndex() )
  960. {
  961. return iGroupNameIndex;
  962. }
  963. // otherwise add the group
  964. return AddHudRenderGroup( pszGroupName );
  965. }
  966. //-----------------------------------------------------------------------------
  967. // Purpose: Create a new hud render group
  968. // returns a group index
  969. //-----------------------------------------------------------------------------
  970. int CHud::AddHudRenderGroup( const char *pszGroupName )
  971. {
  972. // we tried to register for a group but didn't find it, add a new one
  973. int iGroupNameIndex = m_RenderGroupNames.AddToTail( pszGroupName );
  974. CHudRenderGroup *group = new CHudRenderGroup();
  975. return m_RenderGroups.Insert( iGroupNameIndex, group );
  976. }
  977. //-----------------------------------------------------------------------------
  978. // Purpose:
  979. //-----------------------------------------------------------------------------
  980. bool CHud::DoesRenderGroupExist( int iGroupIndex )
  981. {
  982. return ( m_RenderGroups.Find( iGroupIndex ) != m_RenderGroups.InvalidIndex() );
  983. }
  984. //-----------------------------------------------------------------------------
  985. // Purpose: Allows HUD to Think and modify input data
  986. // Input : *cdata -
  987. // time -
  988. // Output : int - 1 if there were changes, 0 otherwise
  989. //-----------------------------------------------------------------------------
  990. void CHud::UpdateHud( bool bActive )
  991. {
  992. // clear the weapon bits.
  993. gHUD.m_iKeyBits &= (~(IN_WEAPON1|IN_WEAPON2));
  994. g_pClientMode->Update();
  995. gLCD.Update();
  996. }
  997. //-----------------------------------------------------------------------------
  998. // Purpose: Force a Hud UI anim to play
  999. //-----------------------------------------------------------------------------
  1000. CON_COMMAND_F( testhudanim, "Test a hud element animation.\n\tArguments: <anim name>\n", FCVAR_CHEAT )
  1001. {
  1002. if ( args.ArgC() != 2 )
  1003. {
  1004. Msg("Usage:\n testhudanim <anim name>\n");
  1005. return;
  1006. }
  1007. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( args[1] );
  1008. }