summaryrefslogtreecommitdiff
path: root/game/client/tf/tf_hud_passtime_ball_offscreen_arrow.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/tf/tf_hud_passtime_ball_offscreen_arrow.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/client/tf/tf_hud_passtime_ball_offscreen_arrow.cpp')
-rw-r--r--game/client/tf/tf_hud_passtime_ball_offscreen_arrow.cpp370
1 files changed, 370 insertions, 0 deletions
diff --git a/game/client/tf/tf_hud_passtime_ball_offscreen_arrow.cpp b/game/client/tf/tf_hud_passtime_ball_offscreen_arrow.cpp
new file mode 100644
index 0000000..e1b4a9c
--- /dev/null
+++ b/game/client/tf/tf_hud_passtime_ball_offscreen_arrow.cpp
@@ -0,0 +1,370 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "c_tf_passtime_logic.h"
+#include "tf_hud_passtime_ball_offscreen_arrow.h"
+#include "iclientmode.h"
+#include <vgui/ILocalize.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include "tf_controls.h"
+#include "view.h"
+#include "ivieweffects.h"
+#include "viewrender.h"
+#include "prediction.h"
+#include "tf_gamerules.h"
+#include "c_tf_player.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define PANEL_WIDE (XRES(48))
+#define PANEL_TALL (XRES(48))
+#define PANEL_ARROW_WIDE (XRES(24))
+#define PANEL_ARROW_TALL (XRES(24))
+
+//-----------------------------------------------------------------------------
+static const char *GetBallImageForTeam( int iTeam )
+{
+ switch( iTeam )
+ {
+ case TF_TEAM_RED: return "../passtime/hud/passtime_ball_offscreen_red";
+ case TF_TEAM_BLUE: return "../passtime/hud/passtime_ball_offscreen_blue";
+ default: return "../passtime/hud/passtime_ball";
+ };
+}
+
+
+//=============================================================================
+// CTFHudPasstimeOffscreenArrow
+//=============================================================================
+
+
+//-----------------------------------------------------------------------------
+CTFHudPasstimeOffscreenArrow::CTFHudPasstimeOffscreenArrow( Panel *parent, const char *name )
+ : EditablePanel( parent, name )
+ , m_pArrowMaterial( 0 )
+ , m_pImage( 0 )
+{
+}
+
+//-----------------------------------------------------------------------------
+CTFHudPasstimeOffscreenArrow::~CTFHudPasstimeOffscreenArrow()
+{
+ if ( m_pArrowMaterial )
+ {
+ m_pArrowMaterial->DecrementReferenceCount();
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CTFHudPasstimeOffscreenArrow::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ LoadControlSettings( "resource/UI/HudPasstimeOffscreenArrow.res" );
+ SetBounds( 0,0, PANEL_WIDE, PANEL_TALL );
+ SetVisible( true );
+
+ if ( m_pArrowMaterial )
+ {
+ m_pArrowMaterial->DecrementReferenceCount();
+ }
+ m_pArrowMaterial = materials->FindMaterial( "HUD/medic_arrow", TEXTURE_GROUP_VGUI );
+ m_pArrowMaterial->IncrementReferenceCount();
+
+ m_pImage = FindControl<vgui::ImagePanel>( "Image" );
+ if ( m_pImage )
+ {
+ m_pImage->SetVisible( true );
+ m_pImage->SetSize( PANEL_WIDE, PANEL_TALL );
+ m_pImage->SetPos( (GetWide() - m_pImage->GetWide()) * 0.5, (GetTall() - m_pImage->GetTall()) * 0.5 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// TODO what's the difference between Paint and PaintBackground?
+extern int HudTransform( const Vector& point, Vector& screen );
+void CTFHudPasstimeOffscreenArrow::PaintBackground()
+{
+ // BaseClass::PaintBackground();
+ if ( !g_pPasstimeLogic )
+ {
+ return;
+ }
+
+ //
+ // Let subclasses determine where to point and how to look
+ //
+ C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
+ C_BaseEntity *pEnt = PreparePaint( m_pImage, pLocalPlayer );
+
+ //
+ // Check if everything is valid, friendly, and visible.
+ //
+ {
+ if ( !pEnt || !pLocalPlayer )
+ {
+ SetAlpha( 0 );
+ return;
+ }
+
+ const bool bTargetVisible = (pEnt->GetEffects() & EF_NODRAW) != 0;
+ const bool bLocalPlayerTarget = (pEnt == pLocalPlayer);
+ if ( bTargetVisible || bLocalPlayerTarget )
+ {
+ SetAlpha( 0 );
+ return;
+ }
+ }
+
+ //
+ // Determine if the arrow should even be visible
+ // HudTransform works ok as long as the point is on-screen, otherwise it's useless.
+ // Calling HudTransform here does a lot of redundant work, but I don't care right now.
+ //
+ Vector vecEntPos = pEnt->WorldSpaceCenter();
+ {
+ Vector vecActualProjection;
+ const bool bBehind = HudTransform( vecEntPos, vecActualProjection );
+ const bool bCenterOfScreen =
+ (vecActualProjection.x < 1.0f) && (vecActualProjection.x > -1.0f)
+ && (vecActualProjection.y < 1.0f) && (vecActualProjection.y > -1.0f);
+ if ( !bBehind && bCenterOfScreen )
+ {
+ SetAlpha( 0 );
+ return;
+ }
+ }
+
+ // Definitely visible
+
+ //
+ // Move the target into view space.
+ // The screen is in the y/z plane.
+ //
+ Vector vecLocalTarget;
+ {
+ VMatrix mWorldToView( SetupMatrixIdentity() );
+ const VMatrix mTemp( SetupMatrixOrgAngles( CurrentViewOrigin(), CurrentViewAngles() ) );
+ MatrixInverseTR( mTemp, mWorldToView );
+ Vector3DMultiplyPosition( mWorldToView, vecEntPos, vecLocalTarget );
+ }
+
+ //
+ // Calc the direction in viewspace from the view origin to the target.
+ // Since all we want is a direction on-screen that goes toward the object, we
+ // don't need to actually project it. it's transformed to view space to get a direction.
+ // vecHudDir is always a point on the exact edge of the screen.
+ //
+ float flArrowAngle;
+ {
+ const Vector vecHudDir = Vector( -vecLocalTarget.y / engine->GetScreenAspectRatio(), -vecLocalTarget.z, 0 ).Normalized();
+ flArrowAngle = atan2( vecHudDir.y, vecHudDir.x );
+ // put it in the range 0 to 2PI
+ if ( flArrowAngle > (M_PI_F * 2.0f) )
+ flArrowAngle -= (M_PI_F * 2.0f);
+ else if ( flArrowAngle < 0 )
+ flArrowAngle += (M_PI_F * 2.0f);
+ }
+
+ //
+ // Build the mesh for the arrow, because vgui can't rotate
+ // TODO probably don't need to build this mesh every frame
+ // The code that draws the arrow mesh has to use the current vgui
+ // position or there will be a one-frame position lag between the two.
+ //
+ {
+ int iX = PANEL_ARROW_WIDE / 2;
+ int iY = PANEL_ARROW_TALL / 2;
+
+ CMatRenderContextPtr pRenderContext( materials );
+ pRenderContext->Bind( m_pArrowMaterial );
+
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ meshBuilder.Position3f( -iX, -iY, 0 );
+ meshBuilder.TexCoord2f( 0, 0, 0 );
+ meshBuilder.Color4ub( 255, 255, 255, GetAlpha() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( iX, -iY, 0 );
+ meshBuilder.TexCoord2f( 0, 1, 0 );
+ meshBuilder.Color4ub( 255, 255, 255, GetAlpha() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( iX, iY, 0 );
+ meshBuilder.TexCoord2f( 0, 1, 1 );
+ meshBuilder.Color4ub( 255, 255, 255, GetAlpha() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( -iX, iY, 0 );
+ meshBuilder.TexCoord2f( 0, 0, 1 );
+ meshBuilder.Color4ub( 255, 255, 255, GetAlpha() );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.End();
+
+ // Determine a scale factor based on how close the player is to the ball. Scale is between 1-2.
+ Vector vecPlayerPos = pLocalPlayer->GetNetworkOrigin();
+ float flDistanceToTargetSq = (float)(vecEntPos.DistToSqr( vecPlayerPos ));
+ float flMaxDistanceSq = 1000000.0f;
+ flDistanceToTargetSq = Min( flDistanceToTargetSq, flMaxDistanceSq );
+ float flDistanceScale = (flDistanceToTargetSq / flMaxDistanceSq) + 1.0f;
+
+ GetPos( iX, iY );
+ iX += GetWide() / 2;
+ iY += GetTall() / 2;
+ pRenderContext->PushMatrix();
+ pRenderContext->Translate( iX, iY, 0 );
+ pRenderContext->Rotate( RAD2DEG( flArrowAngle ), 0, 0, 1 );
+ pRenderContext->Scale( flDistanceScale, 1.0f, 1.0f );
+ pRenderContext->Translate( GetWide() / 2, 0, 0 );
+ pMesh->Draw();
+ pRenderContext->PopMatrix();
+ }
+
+ //
+ // Given the angle, calc a position on the screen for the indicator.
+ // This finds the point at which vecHudDir intersects with the edges of the screen.
+ // Roughly.
+ //
+ Vector vecHudPoint;
+ {
+ Assert( flArrowAngle >= 0 && flArrowAngle < (M_PI_F * 2.0f) );
+ vecHudPoint.y = tanf( flArrowAngle );
+ if ( fabsf( vecHudPoint.y ) <= 1 )
+ {
+ // point will be either along the left or right edge.
+ // y coord is between top and bottom edges, decide whether it lies on
+ // the left or right side of the screen.
+ const float fHalfPi = M_PI_F / 2.0f;
+ if ( (flArrowAngle < fHalfPi) || (flArrowAngle > (M_PI_F + fHalfPi)) )
+ vecHudPoint.Init( 1, vecHudPoint.y );
+ else
+ vecHudPoint.Init( -1, -vecHudPoint.y );
+ }
+ else
+ {
+ // point will be either along the top or bottom edge.
+ // y coord is out of bounds, clamp it and compute x coord
+ if ( flArrowAngle < M_PI_F )
+ vecHudPoint.Init( (1 / vecHudPoint.y), 1 );
+ else
+ vecHudPoint.Init( (-1 / vecHudPoint.y), -1 );
+ }
+ vecHudPoint.x *= 0.8f; // bring toward center.
+ vecHudPoint.y *= 0.5f;
+ }
+
+ //
+ // Convert to hud coordinates and reposition the vgui control
+ //
+ {
+ const int iX = (0.5f * ( 1.0f + vecHudPoint.x ) * ScreenWidth()) - (GetWide() / 2);
+ const int iY = (0.5f * ( 1.0f + vecHudPoint.y ) * ScreenHeight()) - (GetTall() / 2);
+
+#ifdef DEBUG
+ // This block avoids calling SetPos with invalid values while debugging,
+ // because otherwise Paint will never be called again.
+ const int min = 8;
+ const int maxx = ScreenWidth() - 8;
+ const int maxy = ScreenHeight() - 8;
+ if ( iX > min && iX < maxx && iY > min && iY < maxy )
+#endif
+ SetPos( iX, iY );
+ }
+}
+
+
+//=============================================================================
+// CTFHudPasstimeBallOffscreenArrow
+//=============================================================================
+
+
+//-----------------------------------------------------------------------------
+CTFHudPasstimeBallOffscreenArrow::CTFHudPasstimeBallOffscreenArrow( vgui::Panel *pParent )
+ : BaseClass( pParent, "PasstimeBallOffscreenArrow" )
+{
+}
+
+//-----------------------------------------------------------------------------
+C_BaseEntity *CTFHudPasstimeBallOffscreenArrow::PreparePaint(
+ vgui::ImagePanel *pImage, C_TFPlayer *pLocalPlayer )
+{
+ if ( !g_pPasstimeLogic )
+ {
+ return NULL;
+ }
+
+ C_PasstimeBall *pBall = g_pPasstimeLogic->GetBall();
+ C_BaseEntity *pTarget = 0;
+ bool bHomingActive = false;
+ bool bHaveTarget = g_pPasstimeLogic->GetBallReticleTarget( &pTarget, &bHomingActive );
+ if ( !pImage || !pBall || !pLocalPlayer || !bHaveTarget )
+ {
+ return NULL;
+ }
+
+ if ( pLocalPlayer->m_Shared.IsTargetedForPasstimePass() || bHomingActive )
+ {
+ SetAlpha( (int)( (fmodf( gpGlobals->curtime * 3.0f, 1.0f )) * 255 ) );
+ }
+ else
+ {
+ SetAlpha( 128 );
+ }
+
+ if ( pImage )
+ {
+ // setimage will ignore redundant calls
+ if ( pTarget )
+ {
+ pImage->SetImage( GetBallImageForTeam( pTarget->GetTeamNumber() ) );
+ }
+ else
+ {
+ pImage->SetImage( "../passtime/hud/passtime_ball" );
+ }
+ }
+
+ return pTarget;
+}
+
+
+//=============================================================================
+// CTFHudPasstimePlayerOffscreenArrow
+//=============================================================================
+
+
+//-----------------------------------------------------------------------------
+CTFHudPasstimePlayerOffscreenArrow::CTFHudPasstimePlayerOffscreenArrow( vgui::Panel *pParent, int iPlayerIndex )
+ : BaseClass( pParent, "PasstimePlayerOffscreenArrow" )
+ , m_iPlayerIndex( iPlayerIndex )
+{
+}
+
+//-----------------------------------------------------------------------------
+C_BaseEntity *CTFHudPasstimePlayerOffscreenArrow::PreparePaint(
+ vgui::ImagePanel *pImage, C_TFPlayer *pLocalPlayer )
+{
+ if ( !pImage || (!pLocalPlayer->m_Shared.HasPasstimeBall() && !pLocalPlayer->IsObserver()) )
+ {
+ return NULL;
+ }
+
+ C_TFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( m_iPlayerIndex ) );
+ if ( !pPlayer || (pPlayer == pLocalPlayer) || (pPlayer->m_Shared.AskForBallTime() < gpGlobals->curtime) )
+ {
+ return NULL;
+ }
+
+ SetAlpha( 128 );
+ pImage->SetImage( "../passtime/hud/passtime_pass_to_me_prompt" );
+ return pPlayer;
+}