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.
314 lines
8.8 KiB
314 lines
8.8 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "hud.h" |
|
#include "hud_crosshair.h" |
|
#include "iclientmode.h" |
|
#include "view.h" |
|
#include "vgui_controls/Controls.h" |
|
#include "vgui/ISurface.h" |
|
#include "ivrenderview.h" |
|
#include "materialsystem/imaterialsystem.h" |
|
#include "VGuiMatSurface/IMatSystemSurface.h" |
|
#include "client_virtualreality.h" |
|
#include "sourcevr/isourcevirtualreality.h" |
|
|
|
#ifdef SIXENSE |
|
#include "sixense/in_sixense.h" |
|
#endif |
|
|
|
#ifdef PORTAL |
|
#include "c_portal_player.h" |
|
#endif // PORTAL |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
ConVar crosshair( "crosshair", "1", FCVAR_ARCHIVE ); |
|
ConVar cl_observercrosshair( "cl_observercrosshair", "1", FCVAR_ARCHIVE ); |
|
|
|
using namespace vgui; |
|
|
|
int ScreenTransform( const Vector& point, Vector& screen ); |
|
|
|
#ifdef TF_CLIENT_DLL |
|
// If running TF, we use CHudTFCrosshair instead (which is derived from CHudCrosshair) |
|
#else |
|
DECLARE_HUDELEMENT( CHudCrosshair ); |
|
#endif |
|
|
|
CHudCrosshair::CHudCrosshair( const char *pElementName ) : |
|
CHudElement( pElementName ), BaseClass( NULL, "HudCrosshair" ) |
|
{ |
|
vgui::Panel *pParent = g_pClientMode->GetViewport(); |
|
SetParent( pParent ); |
|
|
|
m_pCrosshair = 0; |
|
|
|
m_clrCrosshair = Color( 0, 0, 0, 0 ); |
|
|
|
m_vecCrossHairOffsetAngle.Init(); |
|
|
|
SetHiddenBits( HIDEHUD_PLAYERDEAD | HIDEHUD_CROSSHAIR ); |
|
} |
|
|
|
CHudCrosshair::~CHudCrosshair() |
|
{ |
|
} |
|
|
|
void CHudCrosshair::ApplySchemeSettings( IScheme *scheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( scheme ); |
|
|
|
m_pDefaultCrosshair = gHUD.GetIcon("crosshair_default"); |
|
SetPaintBackgroundEnabled( false ); |
|
|
|
SetSize( ScreenWidth(), ScreenHeight() ); |
|
|
|
SetForceStereoRenderToFrameBuffer( true ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Save CPU cycles by letting the HUD system early cull |
|
// costly traversal. Called per frame, return true if thinking and |
|
// painting need to occur. |
|
//----------------------------------------------------------------------------- |
|
bool CHudCrosshair::ShouldDraw( void ) |
|
{ |
|
bool bNeedsDraw; |
|
|
|
if ( m_bHideCrosshair ) |
|
return false; |
|
|
|
C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( !pPlayer ) |
|
return false; |
|
|
|
C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); |
|
if ( pWeapon && !pWeapon->ShouldDrawCrosshair() ) |
|
return false; |
|
|
|
#ifdef PORTAL |
|
C_Portal_Player *portalPlayer = ToPortalPlayer(pPlayer); |
|
if ( portalPlayer && portalPlayer->IsSuppressingCrosshair() ) |
|
return false; |
|
#endif // PORTAL |
|
|
|
/* disabled to avoid assuming it's an HL2 player. |
|
// suppress crosshair in zoom. |
|
if ( pPlayer->m_HL2Local.m_bZooming ) |
|
return false; |
|
*/ |
|
|
|
// draw a crosshair only if alive or spectating in eye |
|
if ( IsX360() ) |
|
{ |
|
bNeedsDraw = m_pCrosshair && |
|
!engine->IsDrawingLoadingImage() && |
|
!engine->IsPaused() && |
|
( !pPlayer->IsSuitEquipped() || g_pGameRules->IsMultiplayer() ) && |
|
g_pClientMode->ShouldDrawCrosshair() && |
|
!( pPlayer->GetFlags() & FL_FROZEN ) && |
|
( pPlayer->entindex() == render->GetViewEntity() ) && |
|
( pPlayer->IsAlive() || ( pPlayer->GetObserverMode() == OBS_MODE_IN_EYE ) || ( cl_observercrosshair.GetBool() && pPlayer->GetObserverMode() == OBS_MODE_ROAMING ) ); |
|
} |
|
else |
|
{ |
|
bNeedsDraw = m_pCrosshair && |
|
crosshair.GetInt() && |
|
!engine->IsDrawingLoadingImage() && |
|
!engine->IsPaused() && |
|
g_pClientMode->ShouldDrawCrosshair() && |
|
!( pPlayer->GetFlags() & FL_FROZEN ) && |
|
( pPlayer->entindex() == render->GetViewEntity() ) && |
|
!pPlayer->IsInVGuiInputMode() && |
|
( pPlayer->IsAlive() || ( pPlayer->GetObserverMode() == OBS_MODE_IN_EYE ) || ( cl_observercrosshair.GetBool() && pPlayer->GetObserverMode() == OBS_MODE_ROAMING ) ); |
|
} |
|
|
|
return ( bNeedsDraw && CHudElement::ShouldDraw() ); |
|
} |
|
|
|
#ifdef TF_CLIENT_DLL |
|
extern ConVar cl_crosshair_red; |
|
extern ConVar cl_crosshair_green; |
|
extern ConVar cl_crosshair_blue; |
|
extern ConVar cl_crosshair_scale; |
|
#endif |
|
|
|
|
|
void CHudCrosshair::GetDrawPosition ( float *pX, float *pY, bool *pbBehindCamera, QAngle angleCrosshairOffset ) |
|
{ |
|
QAngle curViewAngles = CurrentViewAngles(); |
|
Vector curViewOrigin = CurrentViewOrigin(); |
|
|
|
int vx, vy, vw, vh; |
|
vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh ); |
|
|
|
float screenWidth = vw; |
|
float screenHeight = vh; |
|
|
|
float x = screenWidth / 2; |
|
float y = screenHeight / 2; |
|
|
|
bool bBehindCamera = false; |
|
|
|
C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( ( pPlayer != NULL ) && ( pPlayer->GetObserverMode()==OBS_MODE_NONE ) ) |
|
{ |
|
bool bUseOffset = false; |
|
|
|
Vector vecStart; |
|
Vector vecEnd; |
|
|
|
if ( UseVR() ) |
|
{ |
|
// These are the correct values to use, but they lag the high-speed view data... |
|
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 ); |
|
vecEnd = vecStart + vecAimDirection * MAX_TRACE_LENGTH; |
|
|
|
bUseOffset = true; |
|
} |
|
|
|
#ifdef SIXENSE |
|
// TODO: actually test this Sixsense code interaction with things like HMDs & stereo. |
|
if ( g_pSixenseInput->IsEnabled() && !UseVR() ) |
|
{ |
|
// Never autoaim a predicted weapon (for now) |
|
vecStart = pPlayer->Weapon_ShootPosition(); |
|
Vector aimVector; |
|
AngleVectors( CurrentViewAngles() - g_pSixenseInput->GetViewAngleOffset(), &aimVector ); |
|
// calculate where the bullet would go so we can draw the cross appropriately |
|
vecEnd = vecStart + aimVector * MAX_TRACE_LENGTH; |
|
bUseOffset = true; |
|
} |
|
#endif |
|
|
|
if ( bUseOffset ) |
|
{ |
|
trace_t tr; |
|
UTIL_TraceLine( vecStart, vecEnd, MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr ); |
|
|
|
Vector screen; |
|
screen.Init(); |
|
bBehindCamera = ScreenTransform(tr.endpos, screen) != 0; |
|
|
|
x = 0.5f * ( 1.0f + screen[0] ) * screenWidth + 0.5f; |
|
y = 0.5f * ( 1.0f - screen[1] ) * screenHeight + 0.5f; |
|
} |
|
} |
|
|
|
// MattB - angleCrosshairOffset is the autoaim angle. |
|
// if we're not using autoaim, just draw in the middle of the |
|
// screen |
|
if ( angleCrosshairOffset != vec3_angle ) |
|
{ |
|
QAngle angles; |
|
Vector forward; |
|
Vector point, screen; |
|
|
|
// this code is wrong |
|
angles = curViewAngles + angleCrosshairOffset; |
|
AngleVectors( angles, &forward ); |
|
VectorAdd( curViewOrigin, forward, point ); |
|
ScreenTransform( point, screen ); |
|
|
|
x += 0.5f * screen[0] * screenWidth + 0.5f; |
|
y += 0.5f * screen[1] * screenHeight + 0.5f; |
|
} |
|
|
|
*pX = x; |
|
*pY = y; |
|
*pbBehindCamera = bBehindCamera; |
|
} |
|
|
|
|
|
void CHudCrosshair::Paint( void ) |
|
{ |
|
if ( !m_pCrosshair ) |
|
return; |
|
|
|
if ( !IsCurrentViewAccessAllowed() ) |
|
return; |
|
|
|
C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( !pPlayer ) |
|
return; |
|
|
|
float x, y; |
|
bool bBehindCamera; |
|
GetDrawPosition ( &x, &y, &bBehindCamera, m_vecCrossHairOffsetAngle ); |
|
|
|
if( bBehindCamera ) |
|
return; |
|
|
|
float flWeaponScale = 1.f; |
|
int iTextureW = m_pCrosshair->Width(); |
|
int iTextureH = m_pCrosshair->Height(); |
|
C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); |
|
if ( pWeapon ) |
|
{ |
|
pWeapon->GetWeaponCrosshairScale( flWeaponScale ); |
|
} |
|
|
|
int iScreenDiv = 1600; |
|
if ( IsSteamDeck() ) |
|
iScreenDiv = 1440; |
|
|
|
float flPlayerScale; |
|
if ( !m_pCrosshair->bRenderUsingFont ) |
|
flPlayerScale = (ScreenHeight() / iScreenDiv) + 1; |
|
else |
|
flPlayerScale = 1.0f; |
|
#ifdef TF_CLIENT_DLL |
|
Color clr( cl_crosshair_red.GetInt(), cl_crosshair_green.GetInt(), cl_crosshair_blue.GetInt(), 255 ); |
|
flPlayerScale = cl_crosshair_scale.GetFloat() / 32.0f; // the player can change the scale in the options/multiplayer tab |
|
#else |
|
Color clr = m_clrCrosshair; |
|
#endif |
|
float flWidth = flWeaponScale * flPlayerScale * (float)iTextureW; |
|
float flHeight = flWeaponScale * flPlayerScale * (float)iTextureH; |
|
int iWidth = (int)( flWidth + 0.5f ); |
|
int iHeight = (int)( flHeight + 0.5f ); |
|
int iX = (int)( x + 0.5f ); |
|
int iY = (int)( y + 0.5f ); |
|
|
|
m_pCrosshair->DrawSelfCropped ( |
|
iX-(iWidth/2), iY-(iHeight/2), |
|
0, 0, |
|
iTextureW, iTextureH, |
|
iWidth, iHeight, |
|
clr ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CHudCrosshair::SetCrosshairAngle( const QAngle& angle ) |
|
{ |
|
VectorCopy( angle, m_vecCrossHairOffsetAngle ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CHudCrosshair::SetCrosshair( CHudTexture *texture, const Color& clr ) |
|
{ |
|
m_pCrosshair = texture; |
|
m_clrCrosshair = clr; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Resets the crosshair back to the default |
|
//----------------------------------------------------------------------------- |
|
void CHudCrosshair::ResetCrosshair() |
|
{ |
|
SetCrosshair( m_pDefaultCrosshair, Color(255, 255, 255, 255) ); |
|
}
|
|
|