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.

526 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "hud.h"
  8. #include "hudelement.h"
  9. #include "hud_macros.h"
  10. #include "hud_numericdisplay.h"
  11. #include "iclientmode.h"
  12. #include "c_tf_player.h"
  13. #include "VGuiMatSurface/IMatSystemSurface.h"
  14. #include "materialsystem/imaterial.h"
  15. #include "materialsystem/imesh.h"
  16. #include "materialsystem/imaterialvar.h"
  17. #include "client_virtualreality.h"
  18. #include "sourcevr/isourcevirtualreality.h"
  19. #include <vgui/IScheme.h>
  20. #include <vgui/ISurface.h>
  21. #include <KeyValues.h>
  22. #include <vgui_controls/AnimationController.h>
  23. //for screenfade
  24. #include "ivieweffects.h"
  25. #include "shake.h"
  26. #include "view_scene.h"
  27. #include "tf_weapon_sniperrifle.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include "tier0/memdbgon.h"
  30. //-----------------------------------------------------------------------------
  31. // Purpose: Figure out where the sniper scope should be drawn.
  32. //-----------------------------------------------------------------------------
  33. void WhereToDrawSniperScope ( int *pX, int *pY, int screenWide, int screenTall )
  34. {
  35. C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer();
  36. if ( pPlayer != NULL )
  37. {
  38. // These are the correct values to use, but they lag the high-speed view data...
  39. Vector vecStart = pPlayer->Weapon_ShootPosition();
  40. Vector vecAimDirection = pPlayer->GetAutoaimVector( 1.0f );
  41. // ...so in some aim modes, they get zapped by something completely up-to-date.
  42. g_ClientVirtualReality.OverrideWeaponHudAimVectors ( &vecStart, &vecAimDirection );
  43. Vector vAimPoint;
  44. // Here we just put the aim point a set distance from the viewer - same depth as the HUD.
  45. float fVrHudDistance = g_ClientVirtualReality.GetHUDDistance();
  46. vAimPoint = vecStart + vecAimDirection * fVrHudDistance;
  47. Vector screen;
  48. screen.Init();
  49. ScreenTransform(vAimPoint, screen);
  50. // screen[0][1] are in range (-1, 1)
  51. float x = 0.5 * ( 1.0f + screen[0] ) * screenWide + 0.5;
  52. float y = 0.5 * ( 1.0f - screen[1] ) * screenTall + 0.5;
  53. *pX = (int)( x + 0.5f );
  54. *pY = (int)( y + 0.5f );
  55. }
  56. }
  57. //-----------------------------------------------------------------------------
  58. // Purpose: Draws the sniper chargeup meter
  59. //-----------------------------------------------------------------------------
  60. class CHudScopeCharge : public vgui::Panel, public CHudElement
  61. {
  62. DECLARE_CLASS_SIMPLE( CHudScopeCharge, vgui::Panel );
  63. public:
  64. CHudScopeCharge( const char *pElementName );
  65. virtual ~CHudScopeCharge( void );
  66. void Init( void );
  67. protected:
  68. virtual void ApplySchemeSettings(vgui::IScheme *scheme);
  69. virtual void Paint( void );
  70. private:
  71. int m_iChargeupTexture;
  72. int m_iChargeupTextureWidth;
  73. CPanelAnimationVarAliasType( float, m_iChargeup_xpos, "chargeup_xpos", "0", "proportional_float" );
  74. CPanelAnimationVarAliasType( float, m_iChargeup_ypos, "chargeup_ypos", "0", "proportional_float" );
  75. CPanelAnimationVarAliasType( float, m_iChargeup_wide, "chargeup_wide", "0", "proportional_float" );
  76. CPanelAnimationVarAliasType( float, m_iChargeup_tall, "chargeup_tall", "0", "proportional_float" );
  77. bool m_bJarateMode;
  78. };
  79. DECLARE_HUDELEMENT_DEPTH( CHudScopeCharge, 100 );
  80. using namespace vgui;
  81. //-----------------------------------------------------------------------------
  82. // Purpose: Constructor
  83. //-----------------------------------------------------------------------------
  84. CHudScopeCharge::CHudScopeCharge( const char *pElementName ) : CHudElement(pElementName), BaseClass(NULL, "HudScopeCharge")
  85. {
  86. vgui::Panel *pParent = g_pClientMode->GetViewport();
  87. SetParent( pParent );
  88. SetHiddenBits( HIDEHUD_PLAYERDEAD );
  89. m_bJarateMode = false;
  90. m_iChargeupTexture = -1;
  91. }
  92. CHudScopeCharge::~CHudScopeCharge( void )
  93. {
  94. if ( vgui::surface() && m_iChargeupTexture != -1 )
  95. {
  96. vgui::surface()->DestroyTextureID( m_iChargeupTexture );
  97. m_iChargeupTexture = -1;
  98. }
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose: standard hud element init function
  102. //-----------------------------------------------------------------------------
  103. void CHudScopeCharge::Init( void )
  104. {
  105. if ( m_iChargeupTexture == -1 )
  106. {
  107. m_iChargeupTexture = vgui::surface()->CreateNewTextureID();
  108. vgui::surface()->DrawSetTextureFile(m_iChargeupTexture, "HUD/sniperscope_numbers", true, false);
  109. }
  110. // Get the texture size
  111. int ignored;
  112. surface()->DrawGetTextureSize( m_iChargeupTexture, m_iChargeupTextureWidth, ignored );
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose: sets scheme colors
  116. //-----------------------------------------------------------------------------
  117. void CHudScopeCharge::ApplySchemeSettings( vgui::IScheme *scheme )
  118. {
  119. BaseClass::ApplySchemeSettings(scheme);
  120. SetPaintBackgroundEnabled(false);
  121. SetPaintBorderEnabled(false);
  122. if ( UseVR() )
  123. {
  124. // Force it to go direct to the framebuffer.
  125. SetForceStereoRenderToFrameBuffer( true );
  126. }
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose: draws the zoom effect
  130. //-----------------------------------------------------------------------------
  131. void CHudScopeCharge::Paint( void )
  132. {
  133. C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  134. if ( GetSpectatorTarget() != 0 && GetSpectatorMode() == OBS_MODE_IN_EYE )
  135. {
  136. pPlayer = (C_TFPlayer *)UTIL_PlayerByIndex( GetSpectatorTarget() );
  137. }
  138. if ( !pPlayer )
  139. return;
  140. if ( !pPlayer->m_Shared.InCond( TF_COND_ZOOMED ) )
  141. return;
  142. // Make sure the current weapon is a sniper rifle
  143. CTFSniperRifle *pWeapon = assert_cast<CTFSniperRifle*>(pPlayer->GetActiveTFWeapon());
  144. if ( !pWeapon )
  145. return;
  146. if ( pWeapon->IsJarateRifle() && !m_bJarateMode )
  147. {
  148. vgui::surface()->DrawSetTextureFile(m_iChargeupTexture, "HUD/sniperscope_numbers_jar", true, false);
  149. m_bJarateMode = true;
  150. }
  151. else if ( !pWeapon->IsJarateRifle() && m_bJarateMode )
  152. {
  153. vgui::surface()->DrawSetTextureFile(m_iChargeupTexture, "HUD/sniperscope_numbers", true, false);
  154. m_bJarateMode = false;
  155. }
  156. // Actual charge value is set through a material proxy in the sniper rifle class
  157. int wide, tall;
  158. GetSize( wide, tall );
  159. int x = 0;
  160. int y = 0;
  161. bool bDisableClipping = false;
  162. if ( UseVR() )
  163. {
  164. int vx, vy, vw, vh;
  165. vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh );
  166. int screenWide = vw;
  167. int screenTall = vh;
  168. bDisableClipping = true;
  169. WhereToDrawSniperScope ( &x, &y, screenWide, screenTall );
  170. // The origin is wherever the property file put it, so (0,0) means "the right place, if the scope is in the middle of the screen"
  171. // So offset from there. But additional fun - the rendering coordinates are in the UI space, not the actual screen space.
  172. int UiScreenWide, UiScreenTall;
  173. GetHudSize(UiScreenWide, UiScreenTall);
  174. x -= ( UiScreenWide / 2 );
  175. y -= ( UiScreenTall / 2 );
  176. }
  177. if( bDisableClipping )
  178. g_pMatSystemSurface->DisableClipping( true );
  179. vgui::surface()->DrawSetColor(255,255,255,255);
  180. vgui::surface()->DrawSetTexture(m_iChargeupTexture);
  181. vgui::surface()->DrawTexturedRect( x, y, x+wide, y+tall );
  182. if( bDisableClipping )
  183. g_pMatSystemSurface->DisableClipping( false );
  184. }
  185. //-----------------------------------------------------------------------------
  186. // Purpose: Draws the zoom screen
  187. //-----------------------------------------------------------------------------
  188. class CHudScope : public vgui::Panel, public CHudElement
  189. {
  190. DECLARE_CLASS_SIMPLE( CHudScope, vgui::Panel );
  191. public:
  192. CHudScope( const char *pElementName );
  193. virtual ~CHudScope( void );
  194. void Init( void );
  195. protected:
  196. virtual void ApplySchemeSettings(vgui::IScheme *scheme);
  197. virtual void Paint( void );
  198. virtual bool ShouldDraw( void );
  199. private:
  200. int m_iScopeTexture[4];
  201. int m_iScopeTextureAlt[4];
  202. bool m_bAltScopeMode;
  203. };
  204. DECLARE_HUDELEMENT_DEPTH( CHudScope, 100 );
  205. using namespace vgui;
  206. //-----------------------------------------------------------------------------
  207. // Purpose: Constructor
  208. //-----------------------------------------------------------------------------
  209. CHudScope::CHudScope( const char *pElementName ) : CHudElement(pElementName), BaseClass(NULL, "HudScope")
  210. {
  211. vgui::Panel *pParent = g_pClientMode->GetViewport();
  212. SetParent( pParent );
  213. SetHiddenBits( HIDEHUD_PLAYERDEAD );
  214. for ( int i = 0; i < ARRAYSIZE( m_iScopeTexture ); i++ )
  215. {
  216. m_iScopeTexture[ i ] = -1;
  217. }
  218. for ( int i = 0; i < ARRAYSIZE( m_iScopeTextureAlt ); i++ )
  219. {
  220. m_iScopeTextureAlt[i] = -1;
  221. }
  222. m_bAltScopeMode = false;
  223. }
  224. CHudScope::~CHudScope( void )
  225. {
  226. if ( vgui::surface() )
  227. {
  228. for ( int i = 0; i < ARRAYSIZE( m_iScopeTexture ); i++ )
  229. {
  230. if ( m_iScopeTexture[ i ] != -1 )
  231. {
  232. vgui::surface()->DestroyTextureID( m_iScopeTexture[ i ] );
  233. m_iScopeTexture[ i ] = -1;
  234. }
  235. }
  236. for ( int i = 0; i < ARRAYSIZE( m_iScopeTextureAlt ); i++ )
  237. {
  238. if ( m_iScopeTextureAlt[i] != -1 )
  239. {
  240. vgui::surface()->DestroyTextureID( m_iScopeTextureAlt[i] );
  241. m_iScopeTextureAlt[i] = -1;
  242. }
  243. }
  244. }
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose: standard hud element init function
  248. //-----------------------------------------------------------------------------
  249. void CHudScope::Init( void )
  250. {
  251. for ( int i = 0; i < ARRAYSIZE( m_iScopeTexture ); i++ )
  252. {
  253. if ( m_iScopeTexture[ i ] == -1 )
  254. {
  255. m_iScopeTexture[ i ] = vgui::surface()->CreateNewTextureID();
  256. }
  257. }
  258. vgui::surface()->DrawSetTextureFile( m_iScopeTexture[0], "HUD/scope_sniper_ul", true, false );
  259. vgui::surface()->DrawSetTextureFile( m_iScopeTexture[1], "HUD/scope_sniper_ur", true, false );
  260. vgui::surface()->DrawSetTextureFile( m_iScopeTexture[2], "HUD/scope_sniper_lr", true, false );
  261. vgui::surface()->DrawSetTextureFile( m_iScopeTexture[3], "HUD/scope_sniper_ll", true, false );
  262. for ( int i = 0; i < ARRAYSIZE( m_iScopeTextureAlt ); i++ )
  263. {
  264. if ( m_iScopeTextureAlt[i] == -1 )
  265. {
  266. m_iScopeTextureAlt[i] = vgui::surface()->CreateNewTextureID();
  267. }
  268. }
  269. vgui::surface()->DrawSetTextureFile( m_iScopeTextureAlt[0], "HUD/scope_sniper_alt_ul", true, false );
  270. vgui::surface()->DrawSetTextureFile( m_iScopeTextureAlt[1], "HUD/scope_sniper_alt_ur", true, false );
  271. vgui::surface()->DrawSetTextureFile( m_iScopeTextureAlt[2], "HUD/scope_sniper_alt_lr", true, false );
  272. vgui::surface()->DrawSetTextureFile( m_iScopeTextureAlt[3], "HUD/scope_sniper_alt_ll", true, false );
  273. // remove ourselves from the global group so the scoreboard doesn't hide us
  274. UnregisterForRenderGroup( "global" );
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Purpose: sets scheme colors
  278. //-----------------------------------------------------------------------------
  279. void CHudScope::ApplySchemeSettings( vgui::IScheme *scheme )
  280. {
  281. BaseClass::ApplySchemeSettings(scheme);
  282. SetPaintBackgroundEnabled(false);
  283. SetPaintBorderEnabled(false);
  284. if ( UseVR() )
  285. {
  286. // Make it fill the screen.
  287. int iViewportWidth, iViewportHeight;
  288. g_pSourceVR->GetViewportBounds( ISourceVirtualReality::VREye_Left, NULL, NULL, &iViewportWidth, &iViewportHeight );
  289. SetSize ( iViewportWidth, iViewportHeight );
  290. SetBounds ( 0, 0, iViewportWidth, iViewportHeight );
  291. // Force it to go direct to the framebuffer.
  292. SetForceStereoRenderToFrameBuffer( true );
  293. }
  294. else
  295. {
  296. int screenWide, screenTall;
  297. GetHudSize(screenWide, screenTall);
  298. SetBounds(0, 0, screenWide, screenTall);
  299. }
  300. // Move behind the spectator GUI, so we can be visible at the same time.
  301. SetZPos( -1 );
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Purpose:
  305. //-----------------------------------------------------------------------------
  306. bool CHudScope::ShouldDraw( void )
  307. {
  308. C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  309. if ( GetSpectatorTarget() != 0 && GetSpectatorMode() == OBS_MODE_IN_EYE )
  310. {
  311. pPlayer = (C_TFPlayer *)UTIL_PlayerByIndex( GetSpectatorTarget() );
  312. }
  313. if ( !pPlayer || !pPlayer->m_Shared.InCond( TF_COND_ZOOMED ) )
  314. return false;
  315. if ( pPlayer->GetActiveTFWeapon() )
  316. {
  317. m_bAltScopeMode = ( pPlayer->GetActiveTFWeapon()->GetWeaponID() == TF_WEAPON_SNIPERRIFLE_CLASSIC );
  318. }
  319. return CHudElement::ShouldDraw();
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Purpose: draws the zoom effect
  323. //-----------------------------------------------------------------------------
  324. void CHudScope::Paint( void )
  325. {
  326. // We need to update the refraction texture so the scope can refract it
  327. UpdateRefractTexture();
  328. int screenWide;
  329. int screenTall;
  330. GetHudSize(screenWide, screenTall);
  331. // calculate the bounds in which we should draw the scope
  332. int xMid = screenWide / 2;
  333. int yMid = screenTall / 2;
  334. // width of the drawn scope. in widescreen, we draw the sides with primitives
  335. int wide, tall;
  336. if( screenWide > screenTall )
  337. {
  338. wide = ( screenTall * 4 ) / 3;
  339. tall = screenTall;
  340. }
  341. else
  342. {
  343. wide = screenWide;
  344. tall = ( screenWide * 3 ) / 4;
  345. }
  346. bool bDisableClipping = false;
  347. if ( UseVR() )
  348. {
  349. int vx, vy, vw, vh;
  350. vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh );
  351. screenWide = vw;
  352. screenTall = vh;
  353. // This is actually awful - the scope is drawn in HUD-space, which is this completely
  354. // artifical 640*480 space that we invent for VR and which doesn't even have square pixels. Ugh.
  355. // Hacked good enough to ship. TODO: don't hack it.
  356. float fMagnification = 1.0f / g_ClientVirtualReality.GetZoomedModeMagnification();
  357. wide = (int)( fMagnification * (float)screenWide );
  358. tall = ( wide * 3 ) / 4;
  359. bDisableClipping = true;
  360. WhereToDrawSniperScope ( &xMid, &yMid, screenWide, screenTall );
  361. }
  362. int xLeft = xMid - wide/2;
  363. int xRight = xMid + wide/2;
  364. int yTop = yMid - tall/2;
  365. int yBottom = yMid + tall/2;
  366. float uv1 = 0.5f / 256.0f, uv2 = 1.0f - uv1;
  367. vgui::Vertex_t vert[4];
  368. Vector2D uv11( uv1, uv1 );
  369. Vector2D uv12( uv1, uv2 );
  370. Vector2D uv21( uv2, uv1 );
  371. Vector2D uv22( uv2, uv2 );
  372. vgui::surface()->DrawSetColor(0,0,0,255);
  373. if( bDisableClipping )
  374. g_pMatSystemSurface->DisableClipping( true );
  375. //upper left
  376. vgui::surface()->DrawSetTexture( m_bAltScopeMode ? m_iScopeTextureAlt[0] : m_iScopeTexture[0] );
  377. vert[0].Init( Vector2D( xLeft, yTop ), uv11 );
  378. vert[1].Init( Vector2D( xMid, yTop ), uv21 );
  379. vert[2].Init( Vector2D( xMid, yMid ), uv22 );
  380. vert[3].Init( Vector2D( xLeft, yMid ), uv12 );
  381. vgui::surface()->DrawTexturedPolygon( 4, vert );
  382. // top right
  383. if ( m_bAltScopeMode )
  384. {
  385. vgui::surface()->DrawSetTexture( m_iScopeTextureAlt[1] );
  386. vert[0].Init( Vector2D( xMid, yTop ), uv11 );
  387. vert[1].Init( Vector2D( xRight, yTop ), uv21 );
  388. vert[2].Init( Vector2D( xRight, yMid ), uv22 );
  389. vert[3].Init( Vector2D( xMid, yMid ), uv12 );
  390. vgui::surface()->DrawTexturedPolygon( 4, vert );
  391. }
  392. else
  393. {
  394. vgui::surface()->DrawSetTexture( m_iScopeTexture[1] );
  395. vert[0].Init( Vector2D( xMid - 1, yTop ), uv11 );
  396. vert[1].Init( Vector2D( xRight, yTop ), uv21 );
  397. vert[2].Init( Vector2D( xRight, yMid + 1 ), uv22 );
  398. vert[3].Init( Vector2D( xMid - 1, yMid + 1 ), uv12 );
  399. vgui::surface()->DrawTexturedPolygon( 4, vert );
  400. }
  401. // bottom right
  402. vgui::surface()->DrawSetTexture( m_bAltScopeMode ? m_iScopeTextureAlt[2] : m_iScopeTexture[2] );
  403. vert[0].Init( Vector2D( xMid, yMid ), uv11 );
  404. vert[1].Init( Vector2D( xRight, yMid ), uv21 );
  405. vert[2].Init( Vector2D( xRight, yBottom ), uv22 );
  406. vert[3].Init( Vector2D( xMid, yBottom ), uv12 );
  407. vgui::surface()->DrawTexturedPolygon( 4, vert );
  408. // bottom left
  409. vgui::surface()->DrawSetTexture( m_bAltScopeMode ? m_iScopeTextureAlt[3] : m_iScopeTexture[3] );
  410. vert[0].Init( Vector2D( xLeft, yMid ), uv11 );
  411. vert[1].Init( Vector2D( xMid, yMid ), uv21 );
  412. vert[2].Init( Vector2D( xMid, yBottom ), uv22 );
  413. vert[3].Init( Vector2D( xLeft, yBottom), uv12 );
  414. vgui::surface()->DrawTexturedPolygon( 4, vert );
  415. if ( xLeft > 0 )
  416. {
  417. // Left block
  418. vgui::surface()->DrawFilledRect( 0, 0, xLeft, screenTall );
  419. }
  420. if ( screenWide > xRight )
  421. {
  422. // Right block
  423. vgui::surface()->DrawFilledRect( xRight, 0, screenWide, screenTall );
  424. }
  425. if ( yTop > 0 )
  426. {
  427. // top block
  428. vgui::surface()->DrawFilledRect( 0, 0, screenWide, yTop );
  429. }
  430. if ( screenTall > yBottom )
  431. {
  432. // bottom block
  433. vgui::surface()->DrawFilledRect( 0, yBottom, screenWide, screenTall );
  434. }
  435. if( bDisableClipping )
  436. g_pMatSystemSurface->DisableClipping( false );
  437. }