diff options
Diffstat (limited to 'game/client/hl2/hud_radar.cpp')
| -rw-r--r-- | game/client/hl2/hud_radar.cpp | 587 |
1 files changed, 587 insertions, 0 deletions
diff --git a/game/client/hl2/hud_radar.cpp b/game/client/hl2/hud_radar.cpp new file mode 100644 index 0000000..2f0fd7e --- /dev/null +++ b/game/client/hl2/hud_radar.cpp @@ -0,0 +1,587 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include <vgui/ISurface.h> +#include "hud_numericdisplay.h" +#include "iclientmode.h" +#include <coordsize.h> +#include "hud_macros.h" +#include "vgui/IVGui.h" +#include "vgui/ILocalize.h" +#include "mapoverview.h" +#include "hud_radar.h" +#include "iclientvehicle.h" + +#define RADAR_DOT_NORMAL 0 +#define RADAR_IGNORE_Z (1<<6) //always draw this item as if it was at the same Z as the player +#define RADAR_MAX_GHOST_ALPHA 25 + +DECLARE_VGUI_SCREEN_FACTORY( CHudRadar, "jalopy_radar_panel" ); + +#define RADAR_PANEL_MATERIAL "vgui/screens/radar" +#define RADAR_CONTACT_LAMBDA_MATERIAL "vgui/icons/icon_lambda" // Lambda cache +#define RADAR_CONTACT_BUSTER_MATERIAL "vgui/icons/icon_buster" // Striderbuster +#define RADAR_CONTACT_STRIDER_MATERIAL "vgui/icons/icon_strider" // Strider +#define RADAR_CONTACT_DOG_MATERIAL "vgui/icons/icon_dog" // Dog +#define RADAR_CONTACT_BASE_MATERIAL "vgui/icons/icon_base" // Ally base + +static CHudRadar *s_Radar = NULL; + +CHudRadar *GetHudRadar() +{ + return s_Radar; +} + +DECLARE_HUDELEMENT( CMapOverview ); + +//--------------------------------------------------------- +//--------------------------------------------------------- +CHudRadar::CHudRadar( vgui::Panel *parent, const char *panelName ) : BaseClass( parent, panelName ) +{ + m_pVehicle = NULL; + m_iImageID = -1; + m_textureID_IconLambda = -1; + m_textureID_IconBuster = -1; + m_textureID_IconStrider = -1; + m_textureID_IconDog = -1; + m_textureID_IconBase = -1; +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +CHudRadar::~CHudRadar() +{ + s_Radar = NULL; + +#if defined(_X360) + if( m_iImageID != -1 ) + { + vgui::surface()->DestroyTextureID( m_iImageID ); + m_iImageID = -1; + } + + if( m_textureID_IconLambda != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconLambda ); + m_textureID_IconLambda = -1; + } + + if( m_textureID_IconBuster != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconBuster ); + m_textureID_IconBuster = -1; + } + + if( m_textureID_IconStrider != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconStrider ); + m_textureID_IconStrider = -1; + } + + if( m_textureID_IconDog != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconDog ); + m_textureID_IconDog = -1; + } + + if( m_textureID_IconBase != -1 ) + { + vgui::surface()->DestroyTextureID( m_textureID_IconBase ); + m_textureID_IconBase = -1; + } +#endif//_X360 +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +bool CHudRadar::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) +{ + bool result = BaseClass::Init( pKeyValues, pInitData ); + ClearAllRadarContacts(); + s_Radar = this; + + m_ghostAlpha = 0; + m_flTimeStartGhosting = gpGlobals->curtime + 1.0f; + + return result; +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CHudRadar::VidInit(void) +{ +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CHudRadar::MsgFunc_UpdateRadar(bf_read &msg ) +{ +} + +//--------------------------------------------------------- +// Purpose: Register a radar contact in the list of contacts +//--------------------------------------------------------- +void CHudRadar::AddRadarContact( const Vector &vecOrigin, int iType, float flTimeToLive ) +{ + if( m_iNumRadarContacts == RADAR_MAX_CONTACTS ) + return; + + Vector v = vecOrigin; + int iExistingContact = FindRadarContact( vecOrigin ); + + if( iExistingContact > -1 ) + { + // Just update this contact. + m_radarContacts[iExistingContact].m_flTimeToRemove = gpGlobals->curtime + flTimeToLive; + return; + } + + m_radarContacts[m_iNumRadarContacts].m_vecOrigin = vecOrigin; + m_radarContacts[m_iNumRadarContacts].m_iType = iType; + m_radarContacts[m_iNumRadarContacts].m_flTimeToRemove = gpGlobals->curtime + flTimeToLive; + m_iNumRadarContacts++; +} + +//--------------------------------------------------------- +// Purpose: Search the contact list for a specific contact +//--------------------------------------------------------- +int CHudRadar::FindRadarContact( const Vector &vecOrigin ) +{ + for( int i = 0 ; i < m_iNumRadarContacts ; i++ ) + { + if( m_radarContacts[ i ].m_vecOrigin == vecOrigin ) + return i; + } + + return -1; +} + +//--------------------------------------------------------- +// Purpose: Go through all radar targets and see if any +// have expired. If yes, remove them from the +// list. +//--------------------------------------------------------- +void CHudRadar::MaintainRadarContacts() +{ + bool bKeepWorking = true; + while( bKeepWorking ) + { + bKeepWorking = false; + for( int i = 0 ; i < m_iNumRadarContacts ; i++ ) + { + CRadarContact *pContact = &m_radarContacts[ i ]; + if( gpGlobals->curtime >= pContact->m_flTimeToRemove ) + { + // Time for this guy to go. Easiest thing is just to copy the last element + // into this element's spot and then decrement the count of entities. + bKeepWorking = true; + + m_radarContacts[ i ] = m_radarContacts[ m_iNumRadarContacts - 1 ]; + m_iNumRadarContacts--; + break; + } + } + } +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CHudRadar::SetVisible(bool state) +{ + BaseClass::SetVisible(state); + + if( g_pMapOverview && g_pMapOverview->GetMode() == CMapOverview::MAP_MODE_RADAR ) + { + // We are the hud element still, but he is in charge of the new style now. + g_pMapOverview->SetVisible( state ); + } +} + +#define RADAR_BLIP_FADE_TIME 1.0f +#define RADAR_USE_ICONS 1 +//--------------------------------------------------------- +// Purpose: Draw the radar panel. +// We're probably doing too much other work in here +//--------------------------------------------------------- +void CHudRadar::Paint() +{ + if (m_iImageID == -1 ) + { + // Set up the image ID's if they've somehow gone bad. + m_textureID_IconLambda = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconLambda, RADAR_CONTACT_LAMBDA_MATERIAL, true, false ); + + m_textureID_IconBuster = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconBuster, RADAR_CONTACT_BUSTER_MATERIAL, true, false ); + + m_textureID_IconStrider = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconStrider, RADAR_CONTACT_STRIDER_MATERIAL, true, false ); + + m_textureID_IconDog = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconDog, RADAR_CONTACT_DOG_MATERIAL, true, false ); + + m_textureID_IconBase = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_textureID_IconBase, RADAR_CONTACT_BASE_MATERIAL, true, false ); + + m_iImageID = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_iImageID, RADAR_PANEL_MATERIAL, true, false ); + } + + // Draw the radar background. + int wide, tall; + GetSize(wide, tall); + int alpha = 255; + vgui::surface()->DrawSetColor(255, 255, 255, alpha); + vgui::surface()->DrawSetTexture(m_iImageID); + vgui::surface()->DrawTexturedRect(0, 0, wide, tall); + + // Manage the CRT 'ghosting' effect + if( gpGlobals->curtime > m_flTimeStartGhosting ) + { + if( m_ghostAlpha < RADAR_MAX_GHOST_ALPHA ) + { + m_ghostAlpha++; + } + else + { + m_flTimeStartGhosting = FLT_MAX; + m_flTimeStopGhosting = gpGlobals->curtime + RandomFloat( 1.0f, 2.0f );// How long to ghost for + } + } + else if( gpGlobals->curtime > m_flTimeStopGhosting ) + { + // We're supposed to stop ghosting now. + if( m_ghostAlpha > 0 ) + { + // Still fading the effects. + m_ghostAlpha--; + } + else + { + // DONE fading the effects. Now stop ghosting for a short while + m_flTimeStartGhosting = gpGlobals->curtime + RandomFloat( 2.0f, 3.0f );// how long between ghosts + m_flTimeStopGhosting = FLT_MAX; + } + } + + // Now go through the list of radar targets and represent them on the radar screen + // by drawing their icons on top of the background. + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + + for( int i = 0 ; i < m_iNumRadarContacts ; i++ ) + { + int alpha = 90; + CRadarContact *pContact = &m_radarContacts[ i ]; + float deltaT = pContact->m_flTimeToRemove - gpGlobals->curtime; + if ( deltaT < RADAR_BLIP_FADE_TIME ) + { + float factor = deltaT / RADAR_BLIP_FADE_TIME; + + alpha = (int) ( ((float)alpha) * factor ); + + if( alpha < 10 ) + alpha = 10; + } + + if( RADAR_USE_ICONS ) + { + int flicker = RandomInt( 0, 30 ); + DrawIconOnRadar( pContact->m_vecOrigin, pLocalPlayer, pContact->m_iType, RADAR_IGNORE_Z, 255, 255, 255, alpha + flicker ); + } + else + { + DrawPositionOnRadar( pContact->m_vecOrigin, pLocalPlayer, pContact->m_iType, RADAR_IGNORE_Z, 255, 255, 255, alpha ); + } + } + + MaintainRadarContacts(); +} + +ConVar radar_range("radar_range", "3000" ); // 180 feet +//--------------------------------------------------------- +// Scale maps the distance of the target from the radar +// source. +// +// 1.0 = target at or beyond radar range. +// 0.5 = target at (radar_range * 0.5) units distance +// 0.25 = target at (radar_range * 0.25) units distance +// -etc- +//--------------------------------------------------------- +bool CHudRadar::WorldToRadar( const Vector location, const Vector origin, const QAngle angles, float &x, float &y, float &z_delta, float &scale ) +{ + bool bInRange = true; + + float x_diff = location.x - origin.x; + float y_diff = location.y - origin.y; + + // Supply epsilon values to avoid divide-by-zero + if(x_diff == 0) + x_diff = 0.00001f; + + if(y_diff == 0) + y_diff = 0.00001f; + + int iRadarRadius = GetWide(); //width of the panel + float fRange = radar_range.GetFloat(); + + // This magic /2.15 makes the radar scale seem smaller than the VGUI panel so the icons clamp + // to the outer ring in the radar graphic, not the very edge of the panel itself. + float fScale = (iRadarRadius/2.15f) / fRange; + + float flOffset = atan(y_diff/x_diff); + flOffset *= 180; + flOffset /= M_PI; + + if ((x_diff < 0) && (y_diff >= 0)) + flOffset = 180 + flOffset; + else if ((x_diff < 0) && (y_diff < 0)) + flOffset = 180 + flOffset; + else if ((x_diff >= 0) && (y_diff < 0)) + flOffset = 360 + flOffset; + + y_diff = -1*(sqrt((x_diff)*(x_diff) + (y_diff)*(y_diff))); + x_diff = 0; + + flOffset = angles.y - flOffset; + + flOffset *= M_PI; + flOffset /= 180; // now theta is in radians + + // Transform relative to radar source + float xnew_diff = x_diff * cos(flOffset) - y_diff * sin(flOffset); + float ynew_diff = x_diff * sin(flOffset) + y_diff * cos(flOffset); + + if ( (-1 * y_diff) > fRange ) + { + float flScale; + + flScale = ( -1 * y_diff) / fRange; + + xnew_diff /= (flScale); + ynew_diff /= (flScale); + + bInRange = false; + + scale = 1.0f; + } + else + { + // scale + float flDist = sqrt( ((xnew_diff)*(xnew_diff) + (ynew_diff)*(ynew_diff)) ); + scale = flDist / fRange; + } + + + // Scale the dot's position to match radar scale + xnew_diff *= fScale; + ynew_diff *= fScale; + + // Translate to screen coordinates + x = (iRadarRadius/2) + (int)xnew_diff; + y = (iRadarRadius/2) + (int)ynew_diff; + z_delta = 0.0f; + + return bInRange; +} + +void CHudRadar::DrawPositionOnRadar( Vector vecPos, C_BasePlayer *pLocalPlayer, int type, int flags, int r, int g, int b, int a ) +{ + float x, y, z_delta; + int iBaseDotSize = 3; + + QAngle viewAngle = pLocalPlayer->EyeAngles(); + + if( m_pVehicle != NULL ) + { + viewAngle = m_pVehicle->GetAbsAngles(); + viewAngle.y += 90.0f; + } + + float flScale; + + WorldToRadar( vecPos, pLocalPlayer->GetAbsOrigin(), viewAngle, x, y, z_delta, flScale ); + + if( flags & RADAR_IGNORE_Z ) + z_delta = 0; + + switch( type ) + { + case RADAR_CONTACT_GENERIC: + r = 255; g = 170; b = 0; + iBaseDotSize *= 2; + break; + case RADAR_CONTACT_MAGNUSSEN_RDU: + r = 0; g = 200; b = 255; + iBaseDotSize *= 2; + break; + case RADAR_CONTACT_ENEMY: + r = 255; g = 0; b = 0; + iBaseDotSize *= 2; + break; + case RADAR_CONTACT_LARGE_ENEMY: + r = 255; g = 0; b = 0; + iBaseDotSize *= 3; + break; + } + + DrawRadarDot( x, y, z_delta, iBaseDotSize, flags, r, g, b, a ); +} + +//--------------------------------------------------------- +// Purpose: Compute the proper position on the radar screen +// for this object's position relative to the player. +// Then draw the icon in the proper location on the +// radar screen. +//--------------------------------------------------------- +#define RADAR_ICON_MIN_SCALE 0.75f +#define RADAR_ICON_MAX_SCALE 1.0f +void CHudRadar::DrawIconOnRadar( Vector vecPos, C_BasePlayer *pLocalPlayer, int type, int flags, int r, int g, int b, int a ) +{ + float x, y, z_delta; + int wide, tall; + + // for 'ghosting' CRT effects: + int xmod; + int ymod; + int xoffset; + int yoffset; + + // Assume we're going to use the player's location and orientation + QAngle viewAngle = pLocalPlayer->EyeAngles(); + Vector viewOrigin = pLocalPlayer->GetAbsOrigin(); + + // However, happily use those of the vehicle if available! + if( m_pVehicle != NULL ) + { + viewAngle = m_pVehicle->GetAbsAngles(); + viewAngle.y += 90.0f; + viewOrigin = m_pVehicle->WorldSpaceCenter(); + } + + float flScale; + + WorldToRadar( vecPos, viewOrigin, viewAngle, x, y, z_delta, flScale ); + + flScale = RemapVal( flScale, 1.0f, 0.0f, RADAR_ICON_MIN_SCALE, RADAR_ICON_MAX_SCALE ); + + // Get the correct icon for this type of contact + int iTextureID_Icon = -1; + + switch( type ) + { + case RADAR_CONTACT_GENERIC: + iTextureID_Icon = m_textureID_IconLambda; + break; + case RADAR_CONTACT_MAGNUSSEN_RDU: + iTextureID_Icon = m_textureID_IconBuster; + break; + case RADAR_CONTACT_LARGE_ENEMY: + case RADAR_CONTACT_ENEMY: + iTextureID_Icon = m_textureID_IconStrider; + break; + case RADAR_CONTACT_DOG: + iTextureID_Icon = m_textureID_IconDog; + break; + case RADAR_CONTACT_ALLY_INSTALLATION: + iTextureID_Icon = m_textureID_IconBase; + break; + default: + return; + break; + } + + vgui::surface()->DrawSetColor( r, g, b, a ); + vgui::surface()->DrawSetTexture( iTextureID_Icon ); + vgui::surface()->DrawGetTextureSize( iTextureID_Icon, wide, tall ); + + wide = ( int((float)wide * flScale) ); + tall = ( int((float)tall * flScale) ); + + if( type == RADAR_CONTACT_LARGE_ENEMY ) + { + wide *= 2; + tall *= 2; + } + + // Center the icon around its position. + x -= (wide >> 1); + y -= (tall >> 1); + + vgui::surface()->DrawTexturedRect(x, y, x+wide, y+tall); + + // Draw the crt 'ghost' if the icon is not pegged to the outer rim + if( flScale > RADAR_ICON_MIN_SCALE && m_ghostAlpha > 0 ) + { + vgui::surface()->DrawSetColor( r, g, b, m_ghostAlpha ); + xmod = RandomInt( 1, 4 ); + ymod = RandomInt( 1, 4 ); + xoffset = RandomInt( -1, 1 ); + yoffset = RandomInt( -1, 1 ); + x -= (xmod - xoffset); + y -= (ymod - yoffset); + wide += (xmod + xoffset); + tall += (ymod + yoffset); + vgui::surface()->DrawTexturedRect(x, y, x+wide, y+tall); + } +} + +void CHudRadar::FillRect( int x, int y, int w, int h ) +{ + int panel_x, panel_y, panel_w, panel_h; + GetBounds( panel_x, panel_y, panel_w, panel_h ); + vgui::surface()->DrawFilledRect( x, y, x+w, y+h ); +} + +void CHudRadar::DrawRadarDot( int x, int y, float z_diff, int iBaseDotSize, int flags, int r, int g, int b, int a ) +{ + vgui::surface()->DrawSetColor( r, g, b, a ); + + if ( z_diff < -128 ) // below the player + { + z_diff *= -1; + + if ( z_diff > 3096 ) + { + z_diff = 3096; + } + + int iBar = (int)( z_diff / 400 ) + 2; + + // Draw an upside-down T shape to symbolize the dot is below the player. + + iBaseDotSize /= 2; + + //horiz + FillRect( x-(2*iBaseDotSize), y, 5*iBaseDotSize, iBaseDotSize ); + + //vert + FillRect( x, y - iBar*iBaseDotSize, iBaseDotSize, iBar*iBaseDotSize ); + } + else if ( z_diff > 128 ) // above the player + { + if ( z_diff > 3096 ) + { + z_diff = 3096; + } + + int iBar = (int)( z_diff / 400 ) + 2; + + iBaseDotSize /= 2; + + // Draw a T shape to symbolize the dot is above the player. + + //horiz + FillRect( x-(2*iBaseDotSize), y, 5*iBaseDotSize, iBaseDotSize ); + + //vert + FillRect( x, y, iBaseDotSize, iBar*iBaseDotSize ); + } + else + { + FillRect( x, y, iBaseDotSize, iBaseDotSize ); + } +} |