summaryrefslogtreecommitdiff
path: root/game/client/tf/tf_hud_scope.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf/tf_hud_scope.cpp')
-rw-r--r--game/client/tf/tf_hud_scope.cpp527
1 files changed, 527 insertions, 0 deletions
diff --git a/game/client/tf/tf_hud_scope.cpp b/game/client/tf/tf_hud_scope.cpp
new file mode 100644
index 0000000..686c68f
--- /dev/null
+++ b/game/client/tf/tf_hud_scope.cpp
@@ -0,0 +1,527 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "hud.h"
+#include "hudelement.h"
+#include "hud_macros.h"
+#include "hud_numericdisplay.h"
+#include "iclientmode.h"
+#include "c_tf_player.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imesh.h"
+#include "materialsystem/imaterialvar.h"
+#include "client_virtualreality.h"
+#include "sourcevr/isourcevirtualreality.h"
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+#include <KeyValues.h>
+#include <vgui_controls/AnimationController.h>
+
+//for screenfade
+#include "ivieweffects.h"
+#include "shake.h"
+#include "view_scene.h"
+
+#include "tf_weapon_sniperrifle.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Figure out where the sniper scope should be drawn.
+//-----------------------------------------------------------------------------
+void WhereToDrawSniperScope ( int *pX, int *pY, int screenWide, int screenTall )
+{
+ C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( pPlayer != NULL )
+ {
+ // These are the correct values to use, but they lag the high-speed view data...
+ Vector vecStart = pPlayer->Weapon_ShootPosition();
+ Vector vecAimDirection = pPlayer->GetAutoaimVector( 1.0f );
+ // ...so in some aim modes, they get zapped by something completely up-to-date.
+ g_ClientVirtualReality.OverrideWeaponHudAimVectors ( &vecStart, &vecAimDirection );
+
+ Vector vAimPoint;
+ // Here we just put the aim point a set distance from the viewer - same depth as the HUD.
+ float fVrHudDistance = g_ClientVirtualReality.GetHUDDistance();
+ vAimPoint = vecStart + vecAimDirection * fVrHudDistance;
+
+ Vector screen;
+ screen.Init();
+ ScreenTransform(vAimPoint, screen);
+
+ // screen[0][1] are in range (-1, 1)
+ float x = 0.5 * ( 1.0f + screen[0] ) * screenWide + 0.5;
+ float y = 0.5 * ( 1.0f - screen[1] ) * screenTall + 0.5;
+
+ *pX = (int)( x + 0.5f );
+ *pY = (int)( y + 0.5f );
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the sniper chargeup meter
+//-----------------------------------------------------------------------------
+class CHudScopeCharge : public vgui::Panel, public CHudElement
+{
+ DECLARE_CLASS_SIMPLE( CHudScopeCharge, vgui::Panel );
+
+public:
+ CHudScopeCharge( const char *pElementName );
+ virtual ~CHudScopeCharge( void );
+
+ void Init( void );
+
+protected:
+ virtual void ApplySchemeSettings(vgui::IScheme *scheme);
+ virtual void Paint( void );
+
+private:
+ int m_iChargeupTexture;
+ int m_iChargeupTextureWidth;
+ CPanelAnimationVarAliasType( float, m_iChargeup_xpos, "chargeup_xpos", "0", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_iChargeup_ypos, "chargeup_ypos", "0", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_iChargeup_wide, "chargeup_wide", "0", "proportional_float" );
+ CPanelAnimationVarAliasType( float, m_iChargeup_tall, "chargeup_tall", "0", "proportional_float" );
+
+ bool m_bJarateMode;
+};
+
+DECLARE_HUDELEMENT_DEPTH( CHudScopeCharge, 100 );
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CHudScopeCharge::CHudScopeCharge( const char *pElementName ) : CHudElement(pElementName), BaseClass(NULL, "HudScopeCharge")
+{
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetHiddenBits( HIDEHUD_PLAYERDEAD );
+
+ m_bJarateMode = false;
+
+ m_iChargeupTexture = -1;
+}
+
+CHudScopeCharge::~CHudScopeCharge( void )
+{
+ if ( vgui::surface() && m_iChargeupTexture != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iChargeupTexture );
+ m_iChargeupTexture = -1;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: standard hud element init function
+//-----------------------------------------------------------------------------
+void CHudScopeCharge::Init( void )
+{
+ if ( m_iChargeupTexture == -1 )
+ {
+ m_iChargeupTexture = vgui::surface()->CreateNewTextureID();
+ vgui::surface()->DrawSetTextureFile(m_iChargeupTexture, "HUD/sniperscope_numbers", true, false);
+ }
+
+ // Get the texture size
+ int ignored;
+ surface()->DrawGetTextureSize( m_iChargeupTexture, m_iChargeupTextureWidth, ignored );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets scheme colors
+//-----------------------------------------------------------------------------
+void CHudScopeCharge::ApplySchemeSettings( vgui::IScheme *scheme )
+{
+ BaseClass::ApplySchemeSettings(scheme);
+
+ SetPaintBackgroundEnabled(false);
+ SetPaintBorderEnabled(false);
+
+ if ( UseVR() )
+ {
+ // Force it to go direct to the framebuffer.
+ SetForceStereoRenderToFrameBuffer( true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: draws the zoom effect
+//-----------------------------------------------------------------------------
+void CHudScopeCharge::Paint( void )
+{
+ C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
+
+ if ( GetSpectatorTarget() != 0 && GetSpectatorMode() == OBS_MODE_IN_EYE )
+ {
+ pPlayer = (C_TFPlayer *)UTIL_PlayerByIndex( GetSpectatorTarget() );
+ }
+
+ if ( !pPlayer )
+ return;
+
+ if ( !pPlayer->m_Shared.InCond( TF_COND_ZOOMED ) )
+ return;
+
+ // Make sure the current weapon is a sniper rifle
+ CTFSniperRifle *pWeapon = assert_cast<CTFSniperRifle*>(pPlayer->GetActiveTFWeapon());
+ if ( !pWeapon )
+ return;
+
+ if ( pWeapon->IsJarateRifle() && !m_bJarateMode )
+ {
+ vgui::surface()->DrawSetTextureFile(m_iChargeupTexture, "HUD/sniperscope_numbers_jar", true, false);
+ m_bJarateMode = true;
+ }
+ else if ( !pWeapon->IsJarateRifle() && m_bJarateMode )
+ {
+ vgui::surface()->DrawSetTextureFile(m_iChargeupTexture, "HUD/sniperscope_numbers", true, false);
+ m_bJarateMode = false;
+ }
+
+ // Actual charge value is set through a material proxy in the sniper rifle class
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ int x = 0;
+ int y = 0;
+ bool bDisableClipping = false;
+ if ( UseVR() )
+ {
+ int vx, vy, vw, vh;
+ vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh );
+
+ int screenWide = vw;
+ int screenTall = vh;
+ bDisableClipping = true;
+ WhereToDrawSniperScope ( &x, &y, screenWide, screenTall );
+
+ // 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"
+ // So offset from there. But additional fun - the rendering coordinates are in the UI space, not the actual screen space.
+ int UiScreenWide, UiScreenTall;
+ GetHudSize(UiScreenWide, UiScreenTall);
+ x -= ( UiScreenWide / 2 );
+ y -= ( UiScreenTall / 2 );
+ }
+
+ if( bDisableClipping )
+ g_pMatSystemSurface->DisableClipping( true );
+ vgui::surface()->DrawSetColor(255,255,255,255);
+ vgui::surface()->DrawSetTexture(m_iChargeupTexture);
+ vgui::surface()->DrawTexturedRect( x, y, x+wide, y+tall );
+ if( bDisableClipping )
+ g_pMatSystemSurface->DisableClipping( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws the zoom screen
+//-----------------------------------------------------------------------------
+class CHudScope : public vgui::Panel, public CHudElement
+{
+ DECLARE_CLASS_SIMPLE( CHudScope, vgui::Panel );
+
+public:
+ CHudScope( const char *pElementName );
+ virtual ~CHudScope( void );
+
+ void Init( void );
+
+protected:
+ virtual void ApplySchemeSettings(vgui::IScheme *scheme);
+ virtual void Paint( void );
+ virtual bool ShouldDraw( void );
+
+private:
+ int m_iScopeTexture[4];
+ int m_iScopeTextureAlt[4];
+ bool m_bAltScopeMode;
+};
+
+DECLARE_HUDELEMENT_DEPTH( CHudScope, 100 );
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CHudScope::CHudScope( const char *pElementName ) : CHudElement(pElementName), BaseClass(NULL, "HudScope")
+{
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetHiddenBits( HIDEHUD_PLAYERDEAD );
+
+ for ( int i = 0; i < ARRAYSIZE( m_iScopeTexture ); i++ )
+ {
+ m_iScopeTexture[ i ] = -1;
+ }
+
+ for ( int i = 0; i < ARRAYSIZE( m_iScopeTextureAlt ); i++ )
+ {
+ m_iScopeTextureAlt[i] = -1;
+ }
+
+ m_bAltScopeMode = false;
+}
+
+CHudScope::~CHudScope( void )
+{
+ if ( vgui::surface() )
+ {
+ for ( int i = 0; i < ARRAYSIZE( m_iScopeTexture ); i++ )
+ {
+ if ( m_iScopeTexture[ i ] != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iScopeTexture[ i ] );
+ m_iScopeTexture[ i ] = -1;
+ }
+ }
+
+ for ( int i = 0; i < ARRAYSIZE( m_iScopeTextureAlt ); i++ )
+ {
+ if ( m_iScopeTextureAlt[i] != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iScopeTextureAlt[i] );
+ m_iScopeTextureAlt[i] = -1;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: standard hud element init function
+//-----------------------------------------------------------------------------
+void CHudScope::Init( void )
+{
+ for ( int i = 0; i < ARRAYSIZE( m_iScopeTexture ); i++ )
+ {
+ if ( m_iScopeTexture[ i ] == -1 )
+ {
+ m_iScopeTexture[ i ] = vgui::surface()->CreateNewTextureID();
+ }
+ }
+
+ vgui::surface()->DrawSetTextureFile( m_iScopeTexture[0], "HUD/scope_sniper_ul", true, false );
+ vgui::surface()->DrawSetTextureFile( m_iScopeTexture[1], "HUD/scope_sniper_ur", true, false );
+ vgui::surface()->DrawSetTextureFile( m_iScopeTexture[2], "HUD/scope_sniper_lr", true, false );
+ vgui::surface()->DrawSetTextureFile( m_iScopeTexture[3], "HUD/scope_sniper_ll", true, false );
+
+ for ( int i = 0; i < ARRAYSIZE( m_iScopeTextureAlt ); i++ )
+ {
+ if ( m_iScopeTextureAlt[i] == -1 )
+ {
+ m_iScopeTextureAlt[i] = vgui::surface()->CreateNewTextureID();
+ }
+ }
+
+ vgui::surface()->DrawSetTextureFile( m_iScopeTextureAlt[0], "HUD/scope_sniper_alt_ul", true, false );
+ vgui::surface()->DrawSetTextureFile( m_iScopeTextureAlt[1], "HUD/scope_sniper_alt_ur", true, false );
+ vgui::surface()->DrawSetTextureFile( m_iScopeTextureAlt[2], "HUD/scope_sniper_alt_lr", true, false );
+ vgui::surface()->DrawSetTextureFile( m_iScopeTextureAlt[3], "HUD/scope_sniper_alt_ll", true, false );
+
+ // remove ourselves from the global group so the scoreboard doesn't hide us
+ UnregisterForRenderGroup( "global" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets scheme colors
+//-----------------------------------------------------------------------------
+void CHudScope::ApplySchemeSettings( vgui::IScheme *scheme )
+{
+ BaseClass::ApplySchemeSettings(scheme);
+
+ SetPaintBackgroundEnabled(false);
+ SetPaintBorderEnabled(false);
+
+ if ( UseVR() )
+ {
+ // Make it fill the screen.
+ int iViewportWidth, iViewportHeight;
+ g_pSourceVR->GetViewportBounds( ISourceVirtualReality::VREye_Left, NULL, NULL, &iViewportWidth, &iViewportHeight );
+ SetSize ( iViewportWidth, iViewportHeight );
+ SetBounds ( 0, 0, iViewportWidth, iViewportHeight );
+ // Force it to go direct to the framebuffer.
+ SetForceStereoRenderToFrameBuffer( true );
+ }
+ else
+ {
+ int screenWide, screenTall;
+ GetHudSize(screenWide, screenTall);
+ SetBounds(0, 0, screenWide, screenTall);
+ }
+
+ // Move behind the spectator GUI, so we can be visible at the same time.
+ SetZPos( -1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CHudScope::ShouldDraw( void )
+{
+ C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
+ if ( GetSpectatorTarget() != 0 && GetSpectatorMode() == OBS_MODE_IN_EYE )
+ {
+ pPlayer = (C_TFPlayer *)UTIL_PlayerByIndex( GetSpectatorTarget() );
+ }
+
+ if ( !pPlayer || !pPlayer->m_Shared.InCond( TF_COND_ZOOMED ) )
+ return false;
+
+ if ( pPlayer->GetActiveTFWeapon() )
+ {
+ m_bAltScopeMode = ( pPlayer->GetActiveTFWeapon()->GetWeaponID() == TF_WEAPON_SNIPERRIFLE_CLASSIC );
+ }
+
+ return CHudElement::ShouldDraw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: draws the zoom effect
+//-----------------------------------------------------------------------------
+void CHudScope::Paint( void )
+{
+ // We need to update the refraction texture so the scope can refract it
+ UpdateRefractTexture();
+
+ int screenWide;
+ int screenTall;
+
+ GetHudSize(screenWide, screenTall);
+
+ // calculate the bounds in which we should draw the scope
+ int xMid = screenWide / 2;
+ int yMid = screenTall / 2;
+
+ // width of the drawn scope. in widescreen, we draw the sides with primitives
+ int wide, tall;
+ if( screenWide > screenTall )
+ {
+ wide = ( screenTall * 4 ) / 3;
+ tall = screenTall;
+ }
+ else
+ {
+ wide = screenWide;
+ tall = ( screenWide * 3 ) / 4;
+ }
+
+ bool bDisableClipping = false;
+ if ( UseVR() )
+ {
+ int vx, vy, vw, vh;
+ vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh );
+
+ screenWide = vw;
+ screenTall = vh;
+ // This is actually awful - the scope is drawn in HUD-space, which is this completely
+ // artifical 640*480 space that we invent for VR and which doesn't even have square pixels. Ugh.
+ // Hacked good enough to ship. TODO: don't hack it.
+ float fMagnification = 1.0f / g_ClientVirtualReality.GetZoomedModeMagnification();
+ wide = (int)( fMagnification * (float)screenWide );
+ tall = ( wide * 3 ) / 4;
+
+ bDisableClipping = true;
+ WhereToDrawSniperScope ( &xMid, &yMid, screenWide, screenTall );
+ }
+
+ int xLeft = xMid - wide/2;
+ int xRight = xMid + wide/2;
+ int yTop = yMid - tall/2;
+ int yBottom = yMid + tall/2;
+
+ float uv1 = 0.5f / 256.0f, uv2 = 1.0f - uv1;
+
+ vgui::Vertex_t vert[4];
+
+ Vector2D uv11( uv1, uv1 );
+ Vector2D uv12( uv1, uv2 );
+ Vector2D uv21( uv2, uv1 );
+ Vector2D uv22( uv2, uv2 );
+
+ vgui::surface()->DrawSetColor(0,0,0,255);
+
+ if( bDisableClipping )
+ g_pMatSystemSurface->DisableClipping( true );
+
+ //upper left
+ vgui::surface()->DrawSetTexture( m_bAltScopeMode ? m_iScopeTextureAlt[0] : m_iScopeTexture[0] );
+ vert[0].Init( Vector2D( xLeft, yTop ), uv11 );
+ vert[1].Init( Vector2D( xMid, yTop ), uv21 );
+ vert[2].Init( Vector2D( xMid, yMid ), uv22 );
+ vert[3].Init( Vector2D( xLeft, yMid ), uv12 );
+ vgui::surface()->DrawTexturedPolygon( 4, vert );
+
+ // top right
+ if ( m_bAltScopeMode )
+ {
+ vgui::surface()->DrawSetTexture( m_iScopeTextureAlt[1] );
+ vert[0].Init( Vector2D( xMid, yTop ), uv11 );
+ vert[1].Init( Vector2D( xRight, yTop ), uv21 );
+ vert[2].Init( Vector2D( xRight, yMid ), uv22 );
+ vert[3].Init( Vector2D( xMid, yMid ), uv12 );
+ vgui::surface()->DrawTexturedPolygon( 4, vert );
+ }
+ else
+ {
+ vgui::surface()->DrawSetTexture( m_iScopeTexture[1] );
+ vert[0].Init( Vector2D( xMid - 1, yTop ), uv11 );
+ vert[1].Init( Vector2D( xRight, yTop ), uv21 );
+ vert[2].Init( Vector2D( xRight, yMid + 1 ), uv22 );
+ vert[3].Init( Vector2D( xMid - 1, yMid + 1 ), uv12 );
+ vgui::surface()->DrawTexturedPolygon( 4, vert );
+ }
+
+ // bottom right
+ vgui::surface()->DrawSetTexture( m_bAltScopeMode ? m_iScopeTextureAlt[2] : m_iScopeTexture[2] );
+ vert[0].Init( Vector2D( xMid, yMid ), uv11 );
+ vert[1].Init( Vector2D( xRight, yMid ), uv21 );
+ vert[2].Init( Vector2D( xRight, yBottom ), uv22 );
+ vert[3].Init( Vector2D( xMid, yBottom ), uv12 );
+ vgui::surface()->DrawTexturedPolygon( 4, vert );
+
+ // bottom left
+ vgui::surface()->DrawSetTexture( m_bAltScopeMode ? m_iScopeTextureAlt[3] : m_iScopeTexture[3] );
+ vert[0].Init( Vector2D( xLeft, yMid ), uv11 );
+ vert[1].Init( Vector2D( xMid, yMid ), uv21 );
+ vert[2].Init( Vector2D( xMid, yBottom ), uv22 );
+ vert[3].Init( Vector2D( xLeft, yBottom), uv12 );
+ vgui::surface()->DrawTexturedPolygon( 4, vert );
+
+ if ( xLeft > 0 )
+ {
+ // Left block
+ vgui::surface()->DrawFilledRect( 0, 0, xLeft, screenTall );
+ }
+ if ( screenWide > xRight )
+ {
+ // Right block
+ vgui::surface()->DrawFilledRect( xRight, 0, screenWide, screenTall );
+ }
+ if ( yTop > 0 )
+ {
+ // top block
+ vgui::surface()->DrawFilledRect( 0, 0, screenWide, yTop );
+ }
+ if ( screenTall > yBottom )
+ {
+ // bottom block
+ vgui::surface()->DrawFilledRect( 0, yBottom, screenWide, screenTall );
+ }
+
+ if( bDisableClipping )
+ g_pMatSystemSurface->DisableClipping( false );
+
+} \ No newline at end of file