aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/vgui_netgraphpanel.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/vgui_netgraphpanel.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/vgui_netgraphpanel.cpp')
-rw-r--r--mp/src/game/client/vgui_netgraphpanel.cpp3026
1 files changed, 1513 insertions, 1513 deletions
diff --git a/mp/src/game/client/vgui_netgraphpanel.cpp b/mp/src/game/client/vgui_netgraphpanel.cpp
index 3fbd1113..d3837c03 100644
--- a/mp/src/game/client/vgui_netgraphpanel.cpp
+++ b/mp/src/game/client/vgui_netgraphpanel.cpp
@@ -1,1513 +1,1513 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-// $NoKeywords: $
-//=============================================================================//
-#include "cbase.h"
-#include "hud.h"
-#include "inetgraphpanel.h"
-#include "kbutton.h"
-#include <inetchannelinfo.h>
-#include "input.h"
-#include <vgui/IVGui.h>
-#include "VGuiMatSurface/IMatSystemSurface.h"
-#include <vgui_controls/Panel.h>
-#include <vgui_controls/Controls.h>
-#include <vgui/ISurface.h>
-#include <vgui/IScheme.h>
-#include <vgui/ILocalize.h>
-#include "tier0/vprof.h"
-#include "cdll_bounded_cvars.h"
-
-#include "materialsystem/imaterialsystem.h"
-#include "materialsystem/imesh.h"
-#include "materialsystem/imaterial.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-using namespace vgui;
-
-static ConVar net_scale ( "net_scale", "5", FCVAR_ARCHIVE );
-static ConVar net_graphpos ( "net_graphpos", "1", FCVAR_ARCHIVE );
-static ConVar net_graphsolid ( "net_graphsolid", "1", FCVAR_ARCHIVE );
-static ConVar net_graphtext ( "net_graphtext", "1", FCVAR_ARCHIVE, "Draw text fields" );
-static ConVar net_graphmsecs ( "net_graphmsecs", "400", FCVAR_ARCHIVE, "The latency graph represents this many milliseconds." );
-static ConVar net_graphshowlatency( "net_graphshowlatency", "1", FCVAR_ARCHIVE, "Draw the ping/packet loss graph." );
-static ConVar net_graphshowinterp ( "net_graphshowinterp", "1", FCVAR_ARCHIVE, "Draw the interpolation graph." );
-
-void NetgraphFontChangeCallback( IConVar *var, const char *pOldValue, float flOldValue );
-
-static ConVar net_graph ( "net_graph","0", FCVAR_ARCHIVE, "Draw the network usage graph, = 2 draws data on payload, = 3 draws payload legend.", NetgraphFontChangeCallback );
-static ConVar net_graphheight ( "net_graphheight", "64", FCVAR_ARCHIVE, "Height of netgraph panel", NetgraphFontChangeCallback );
-static ConVar net_graphproportionalfont( "net_graphproportionalfont", "1", FCVAR_ARCHIVE, "Determines whether netgraph font is proportional or not", NetgraphFontChangeCallback );
-
-
-#define TIMINGS 1024 // Number of values to track (must be power of 2) b/c of masking
-#define FRAMERATE_AVG_FRAC 0.9
-#define PACKETLOSS_AVG_FRAC 0.5
-#define PACKETCHOKE_AVG_FRAC 0.5
-
-#define NUM_LATENCY_SAMPLES 8
-
-#define GRAPH_RED (0.9 * 255)
-#define GRAPH_GREEN (0.9 * 255)
-#define GRAPH_BLUE (0.7 * 255)
-
-#define LERP_HEIGHT 24
-
-#define COLOR_DROPPED 0
-#define COLOR_INVALID 1
-#define COLOR_SKIPPED 2
-#define COLOR_CHOKED 3
-#define COLOR_NORMAL 4
-
-//-----------------------------------------------------------------------------
-// Purpose: Displays the NetGraph
-//-----------------------------------------------------------------------------
-class CNetGraphPanel : public Panel
-{
- typedef Panel BaseClass;
-private:
- typedef struct
- {
- int latency;
- int choked;
- } packet_latency_t;
-
- typedef struct
- {
- unsigned short msgbytes[INetChannelInfo::TOTAL+1];
- int sampleY;
- int sampleHeight;
-
- } netbandwidthgraph_t;
-
- typedef struct
- {
- float cmd_lerp;
- int size;
- bool sent;
- } cmdinfo_t;
-
- typedef struct
- {
- byte color[3];
- byte alpha;
- } netcolor_t;
-
- byte colors[ LERP_HEIGHT ][3];
-
- byte sendcolor[ 3 ];
- byte holdcolor[ 3 ];
- byte extrap_base_color[ 3 ];
-
- packet_latency_t m_PacketLatency[ TIMINGS ];
- cmdinfo_t m_Cmdinfo[ TIMINGS ];
- netbandwidthgraph_t m_Graph[ TIMINGS ];
-
- float m_Framerate;
- float m_AvgLatency;
- float m_AvgPacketLoss;
- float m_AvgPacketChoke;
- int m_IncomingSequence;
- int m_OutgoingSequence;
- int m_UpdateWindowSize;
- float m_IncomingData;
- float m_OutgoingData;
- float m_AvgPacketIn;
- float m_AvgPacketOut;
-
- int m_StreamRecv[MAX_FLOWS];
- int m_StreamTotal[MAX_FLOWS];
-
- netcolor_t netcolors[5];
-
- HFont m_hFontProportional;
- HFont m_hFont;
-
- HFont m_hFontSmall;
- const ConVar *cl_updaterate;
- const ConVar *cl_cmdrate;
-
-public:
- CNetGraphPanel( VPANEL parent );
- virtual ~CNetGraphPanel( void );
-
- virtual void ApplySchemeSettings(IScheme *pScheme);
- virtual void Paint();
- virtual void OnTick( void );
-
- virtual bool ShouldDraw( void );
-
- void InitColors( void );
- int GraphValue( void );
-
- struct CLineSegment
- {
- int x1, y1, x2, y2;
- byte color[4];
- byte color2[4];
- };
-
- CUtlVector< CLineSegment > m_Rects;
-
- inline void DrawLine( vrect_t *rect, unsigned char *color, unsigned char alpha );
- inline void DrawLine2( vrect_t *rect, unsigned char *color, unsigned char *color2, unsigned char alpha, unsigned char alpha2 );
-
- void ResetLineSegments();
- void DrawLineSegments();
-
- int DrawDataSegment( vrect_t *rcFill, int bytes, byte r, byte g, byte b, byte alpha = 255);
- void DrawUpdateRate( int xright, int y );
- void DrawCmdRate( int xright, int y );
- void DrawHatches( int x, int y, int maxmsgbytes );
- void DrawStreamProgress( int x, int y, int width );
- void DrawTimes( vrect_t vrect, cmdinfo_t *cmdinfo, int x, int w, int graphtype );
- void DrawTextFields( int graphvalue, int x, int y, int w, netbandwidthgraph_t *graph, cmdinfo_t *cmdinfo );
- void GraphGetXY( vrect_t *rect, int width, int *x, int *y );
- void GetCommandInfo( INetChannelInfo *netchannel, cmdinfo_t *cmdinfo );
- void GetFrameData( INetChannelInfo *netchannel, int *biggest_message, float *avg_message, float *f95thpercentile );
- void ColorForHeight( packet_latency_t *packet, byte *color, int *ping, byte *alpha );
- void GetColorValues( int color, byte *cv, byte *alpha );
-
- void OnFontChanged();
-
-private:
-
- void PaintLineArt( int x, int y, int w, int graphtype, int maxmsgbytes );
- void DrawLargePacketSizes( int x, int w, int graphtype, float warning_threshold );
-
- HFont GetNetgraphFont()
- {
- return net_graphproportionalfont.GetBool() ? m_hFontProportional : m_hFont;
- }
-
- void ComputeNetgraphHeight();
- void UpdateEstimatedServerFramerate( INetChannelInfo *netchannel );
-
- CMaterialReference m_WhiteMaterial;
-
- int m_EstimatedWidth;
-
- int m_nNetGraphHeight;
-
- float m_flServerFramerate;
- float m_flServerFramerateStdDeviation;
-};
-
-CNetGraphPanel *g_pNetGraphPanel = NULL;
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *parent -
-//-----------------------------------------------------------------------------
-CNetGraphPanel::CNetGraphPanel( VPANEL parent )
-: BaseClass( NULL, "CNetGraphPanel" )
-{
- int w, h;
- surface()->GetScreenSize( w, h );
-
- SetParent( parent );
- SetSize( w, h );
- SetPos( 0, 0 );
- SetVisible( false );
- SetCursor( null );
-
- m_hFont = 0;
- m_hFontProportional = 0;
- m_hFontSmall = 0;
- m_EstimatedWidth = 1;
- m_nNetGraphHeight = 100;
-
- SetFgColor( Color( 0, 0, 0, 255 ) );
- SetPaintBackgroundEnabled( false );
-
- InitColors();
-
- cl_updaterate = cvar->FindVar( "cl_updaterate" );
- cl_cmdrate = cvar->FindVar( "cl_cmdrate" );
- assert( cl_updaterate && cl_cmdrate );
-
- memset( sendcolor, 0, 3 );
- memset( holdcolor, 0, 3 );
- sendcolor[ 0 ] = sendcolor[ 1 ] = 255;
-
- memset( extrap_base_color, 255, 3 );
-
- memset( m_PacketLatency, 0, TIMINGS * sizeof( packet_latency_t ) );
- memset( m_Cmdinfo, 0, TIMINGS * sizeof( cmdinfo_t ) );
- memset( m_Graph, 0, TIMINGS * sizeof( netbandwidthgraph_t ) );
-
- m_Framerate = 0.0f;
- m_AvgLatency = 0.0f;
- m_AvgPacketLoss = 0.0f;
- m_AvgPacketChoke = 0.0f;
- m_IncomingSequence = 0;
- m_OutgoingSequence = 0;
- m_UpdateWindowSize = 0;
- m_IncomingData = 0;
- m_OutgoingData = 0;
- m_AvgPacketIn = 0.0f;
- m_AvgPacketOut = 0.0f;
- m_flServerFramerate = 0;
- m_flServerFramerateStdDeviation = 0;
-
- netcolors[COLOR_DROPPED].color[0] = 255;
- netcolors[COLOR_DROPPED].color[1] = 0;
- netcolors[COLOR_DROPPED].color[2] = 0;
- netcolors[COLOR_DROPPED].alpha = 255;
- netcolors[COLOR_INVALID].color[0] = 0;
- netcolors[COLOR_INVALID].color[1] = 0;
- netcolors[COLOR_INVALID].color[2] = 255;
- netcolors[COLOR_INVALID].alpha = 255;
- netcolors[COLOR_SKIPPED].color[0] = 240;
- netcolors[COLOR_SKIPPED].color[1] = 127;
- netcolors[COLOR_SKIPPED].color[2] = 63;
- netcolors[COLOR_SKIPPED].alpha = 255;
- netcolors[COLOR_CHOKED].color[0] = 225;
- netcolors[COLOR_CHOKED].color[1] = 225;
- netcolors[COLOR_CHOKED].color[2] = 0;
- netcolors[COLOR_CHOKED].alpha = 255;
- netcolors[COLOR_NORMAL].color[0] = 63;
- netcolors[COLOR_NORMAL].color[1] = 255;
- netcolors[COLOR_NORMAL].color[2] = 63;
- netcolors[COLOR_NORMAL].alpha = 232;
-
- ivgui()->AddTickSignal( GetVPanel(), 500 );
-
- m_WhiteMaterial.Init( "vgui/white", TEXTURE_GROUP_OTHER );
- g_pNetGraphPanel = this;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-CNetGraphPanel::~CNetGraphPanel( void )
-{
- g_pNetGraphPanel = NULL;
-}
-
-void NetgraphFontChangeCallback( IConVar *var, const char *pOldValue, float flOldValue )
-{
- if ( g_pNetGraphPanel )
- {
- g_pNetGraphPanel->OnFontChanged();
- }
-}
-
-void CNetGraphPanel::OnFontChanged()
-{
- // Estimate the width of our panel.
- char str[512];
- wchar_t ustr[512];
- Q_snprintf( str, sizeof( str ), "fps: 435 ping: 533 ms lerp 112.3 ms 0/0" );
- g_pVGuiLocalize->ConvertANSIToUnicode( str, ustr, sizeof( ustr ) );
- int textTall;
- if ( m_hFontProportional == vgui::INVALID_FONT )
- {
- m_EstimatedWidth = textTall = 0;
- }
- else
- {
- g_pMatSystemSurface->GetTextSize( m_hFontProportional, ustr, m_EstimatedWidth, textTall );
- }
-
- int w, h;
- surface()->GetScreenSize( w, h );
- SetSize( w, h );
- SetPos( 0, 0 );
-
- ComputeNetgraphHeight();
-}
-
-void CNetGraphPanel::ApplySchemeSettings(IScheme *pScheme)
-{
- BaseClass::ApplySchemeSettings(pScheme);
-
- m_hFont = pScheme->GetFont( "DefaultFixedOutline", false );
- m_hFontProportional = pScheme->GetFont( "DefaultFixedOutline", true );
- m_hFontSmall = pScheme->GetFont( "DefaultVerySmall", false );
-
- OnFontChanged();
-}
-
-void CNetGraphPanel::ComputeNetgraphHeight()
-{
- m_nNetGraphHeight = net_graphheight.GetInt();
-
- HFont fnt = GetNetgraphFont();
- int tall = surface()->GetFontTall( fnt );
-
- int lines = 3;
- if ( net_graph.GetInt() > 3 )
- {
- lines = 5;
- }
- else if ( net_graph.GetInt() > 2 )
- {
- lines = 4;
- }
- m_nNetGraphHeight = MAX( lines * tall, m_nNetGraphHeight );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Copies data from netcolor_t array into fields passed in
-// Input : color -
-// *cv -
-// *alpha -
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::GetColorValues( int color, byte *cv, byte *alpha )
-{
- int i;
- netcolor_t *pc = &netcolors[ color ];
- for ( i = 0; i < 3; i++ )
- {
- cv[ i ] = pc->color[ i ];
- }
- *alpha = pc->alpha;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Sets appropriate color values
-// Input : *packet -
-// *color -
-// *ping -
-// *alpha -
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::ColorForHeight( packet_latency_t *packet, byte *color, int *ping, byte *alpha )
-{
- int h = packet->latency;
- *ping = 0;
- switch ( h )
- {
- case 9999:
- GetColorValues( COLOR_DROPPED, color, alpha );
- break;
- case 9998:
- GetColorValues( COLOR_INVALID, color, alpha );
- break;
- case 9997:
- GetColorValues( COLOR_SKIPPED, color, alpha );
- break;
- default:
- *ping = 1;
- if (packet->choked )
- {
- GetColorValues( COLOR_CHOKED, color, alpha );
- }
- else
- {
- GetColorValues( COLOR_NORMAL, color, alpha );
- }
- break;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set up blend colors for comman/client-frame/interpolation graph
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::InitColors( void )
-{
- int i, j;
- byte mincolor[2][3];
- byte maxcolor[2][3];
- float dc[2][3];
- int hfrac;
- float f;
-
- mincolor[0][0] = 63;
- mincolor[0][1] = 0;
- mincolor[0][2] = 100;
-
- maxcolor[0][0] = 0;
- maxcolor[0][1] = 63;
- maxcolor[0][2] = 255;
-
- mincolor[1][0] = 255;
- mincolor[1][1] = 127;
- mincolor[1][2] = 0;
-
- maxcolor[1][0] = 250;
- maxcolor[1][1] = 0;
- maxcolor[1][2] = 0;
-
- for ( i = 0; i < 3; i++ )
- {
- dc[0][i] = (float)(maxcolor[0][i] - mincolor[0][i]);
- dc[1][i] = (float)(maxcolor[1][i] - mincolor[1][i]);
- }
-
- hfrac = LERP_HEIGHT / 3;
-
- for ( i = 0; i < LERP_HEIGHT; i++ )
- {
- if ( i < hfrac )
- {
- f = (float)i / (float)hfrac;
- for ( j = 0; j < 3; j++ )
- {
- colors[ i ][j] = mincolor[0][j] + f * dc[0][j];
- }
- }
- else
- {
- f = (float)(i-hfrac) / (float)(LERP_HEIGHT - hfrac );
- for ( j = 0; j < 3; j++ )
- {
- colors[ i ][j] = mincolor[1][j] + f * dc[1][j];
- }
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Draw client framerate / usercommand graph
-// Input : vrect -
-// *cmdinfo -
-// x -
-// w -
-//-----------------------------------------------------------------------------
-
-void CNetGraphPanel::DrawTimes( vrect_t vrect, cmdinfo_t *cmdinfo, int x, int w, int graphtype )
-{
- if ( !net_graphshowinterp.GetBool() || graphtype <= 1 )
- return;
-
- int i;
- int j;
- int extrap_point;
- int a, h;
- vrect_t rcFill;
-
- ResetLineSegments();
-
- extrap_point = LERP_HEIGHT / 3;
-
- for (a=0 ; a<w ; a++)
- {
- i = ( m_OutgoingSequence - a ) & ( TIMINGS - 1 );
- h = MIN( ( cmdinfo[i].cmd_lerp / 3.0 ) * LERP_HEIGHT, LERP_HEIGHT );
-
- rcFill.x = x + w -a - 1;
- rcFill.width = 1;
- rcFill.height = 1;
-
- rcFill.y = vrect.y + vrect.height - 4;
-
- if ( h >= extrap_point )
- {
- int start = 0;
-
- h -= extrap_point;
- rcFill.y -= extrap_point;
-
- if ( !net_graphsolid.GetInt() )
- {
- rcFill.y -= (h - 1);
- start = (h - 1);
- }
-
- for ( j = start; j < h; j++ )
- {
- DrawLine(&rcFill, colors[j + extrap_point], 255 );
- rcFill.y--;
- }
- }
- else
- {
- int oldh;
- oldh = h;
- rcFill.y -= h;
- h = extrap_point - h;
-
- if ( !net_graphsolid.GetInt() )
- {
- h = 1;
- }
-
- for ( j = 0; j < h; j++ )
- {
- DrawLine(&rcFill, colors[j + oldh], 255 );
- rcFill.y--;
- }
- }
-
- rcFill.y = vrect.y + vrect.height - 4 - extrap_point;
-
- DrawLine( &rcFill, extrap_base_color, 255 );
-
- rcFill.y = vrect.y + vrect.height - 3;
-
- if ( cmdinfo[ i ].sent )
- {
- DrawLine( &rcFill, sendcolor, 255 );
- }
- else
- {
- DrawLine( &rcFill, holdcolor, 200 );
- }
- }
-
- DrawLineSegments();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Compute frame database for rendering m_NetChannel computes choked, and lost packets, too.
-// Also computes latency data and sets max packet size
-// Input : *packet_latency -
-// *graph -
-// *choke_count -
-// *loss_count -
-// *biggest_message -
-// 1 -
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::GetFrameData( INetChannelInfo *netchannel, int *biggest_message, float *avg_message, float *f95thpercentile )
-{
- float frame_received_time;
- // float frame_latency;
-
- *biggest_message = 0;
- *avg_message = 0.0f;
- *f95thpercentile = 0.0f;
-
- int msg_count = 0;
-
- m_IncomingSequence = netchannel->GetSequenceNr( FLOW_INCOMING );
- m_OutgoingSequence = netchannel->GetSequenceNr( FLOW_OUTGOING );
- m_UpdateWindowSize = netchannel->GetBufferSize();
- m_AvgPacketLoss = netchannel->GetAvgLoss( FLOW_INCOMING );
- m_AvgPacketChoke = netchannel->GetAvgChoke( FLOW_INCOMING );
- m_AvgLatency = netchannel->GetAvgLatency( FLOW_OUTGOING );
- m_IncomingData = netchannel->GetAvgData( FLOW_INCOMING ) / 1024.0f;
- m_OutgoingData = netchannel->GetAvgData( FLOW_OUTGOING ) / 1024.0f;
- m_AvgPacketIn = netchannel->GetAvgPackets( FLOW_INCOMING );
- m_AvgPacketOut = netchannel->GetAvgPackets( FLOW_OUTGOING );
-
- for ( int i=0; i<MAX_FLOWS; i++ )
- netchannel->GetStreamProgress( i, &m_StreamRecv[i], &m_StreamTotal[i] );
-
- float flAdjust = 0.0f;
-
- if ( cl_updaterate->GetFloat() > 0.001f )
- {
- flAdjust = -0.5f / cl_updaterate->GetFloat();
-
- m_AvgLatency += flAdjust;
- }
-
- // Can't be below zero
- m_AvgLatency = MAX( 0.0, m_AvgLatency );
-
- flAdjust *= 1000.0f;
-
- // Fill in frame data
- for ( int seqnr =m_IncomingSequence - m_UpdateWindowSize + 1
- ; seqnr <= m_IncomingSequence
- ; seqnr++)
- {
-
-
- frame_received_time = netchannel->GetPacketTime( FLOW_INCOMING, seqnr );
-
- netbandwidthgraph_t *nbwg = &m_Graph[ seqnr & ( TIMINGS - 1 )];
- packet_latency_t *lat = &m_PacketLatency[ seqnr & ( TIMINGS - 1 ) ];
-
- netchannel->GetPacketResponseLatency( FLOW_INCOMING, seqnr, &lat->latency, &lat->choked );
-
- if ( lat->latency < 9995 )
- {
- lat->latency += flAdjust;
- lat->latency = MAX( lat->latency, 0 );
- }
-
- for ( int i=0; i<=INetChannelInfo::TOTAL; i++ )
- {
- nbwg->msgbytes[i] = netchannel->GetPacketBytes( FLOW_INCOMING, seqnr, i );
- }
-
- // Assert ( nbwg->msgbytes[INetChannelInfo::TOTAL] > 0 );
-
- if ( nbwg->msgbytes[INetChannelInfo::TOTAL] > *biggest_message )
- {
- *biggest_message = nbwg->msgbytes[INetChannelInfo::TOTAL];
- }
-
- *avg_message += (float)( nbwg->msgbytes[INetChannelInfo::TOTAL] );
- msg_count++;
-
-
- }
-
- if ( *biggest_message > 1000 )
- {
- *biggest_message = 1000;
- }
-
- if ( msg_count >= 1 )
- {
- *avg_message /= msg_count;
-
- int deviationsquared = 0;
-
- // Compute std deviation
- // Fill in frame data
- for (int seqnr=m_IncomingSequence - m_UpdateWindowSize + 1
- ; seqnr <= m_IncomingSequence
- ; seqnr++)
- {
- int bytes = m_Graph[ seqnr & ( TIMINGS - 1 )].msgbytes[INetChannelInfo::TOTAL] - ( *avg_message );
-
- deviationsquared += ( bytes * bytes );
- }
-
- float var = ( float )( deviationsquared ) / (float)( msg_count - 1 );
- float stddev = sqrt( var );
-
- *f95thpercentile = *avg_message + 2.0f * stddev;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Fills in command interpolation/holdback & message size data
-// Input : *cmdinfo -
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::GetCommandInfo( INetChannelInfo *netchannel, cmdinfo_t *cmdinfo )
-{
- for ( int seqnr = m_OutgoingSequence - m_UpdateWindowSize + 1
- ; seqnr <= m_OutgoingSequence
- ; seqnr++)
- {
- // Also set up the lerp point.
- cmdinfo_t *ci = &cmdinfo[ seqnr & ( TIMINGS - 1 ) ];
-
- ci->cmd_lerp = netchannel->GetCommandInterpolationAmount( FLOW_OUTGOING, seqnr );
- ci->sent = netchannel->IsValidPacket( FLOW_OUTGOING, seqnr );
- ci->size = netchannel->GetPacketBytes( FLOW_OUTGOING, seqnr, INetChannelInfo::TOTAL);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Draws overlay text fields showing framerate, latency, bandwidth breakdowns,
-// and, optionally, packet loss and choked packet percentages
-// Input : graphvalue -
-// x -
-// y -
-// *graph -
-// *cmdinfo -
-// count -
-// avg -
-// *framerate -
-// 0.0 -
-// avg -
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::DrawTextFields( int graphvalue, int x, int y, int w, netbandwidthgraph_t *graph, cmdinfo_t *cmdinfo )
-{
- if ( !net_graphtext.GetBool() )
- return;
-
- static int lastout;
-
- char sz[ 256 ];
- int out;
-
- HFont font = GetNetgraphFont();
-
- // Move rolling average
- m_Framerate = FRAMERATE_AVG_FRAC * m_Framerate + ( 1.0 - FRAMERATE_AVG_FRAC ) * gpGlobals->absoluteframetime;
-
- // Print it out
- y -= m_nNetGraphHeight;
-
- int saveY = y;
-
- if ( m_Framerate <= 0.0f )
- m_Framerate = 1.0f;
-
- if ( engine->IsPlayingDemo() )
- m_AvgLatency = 0.0f;
-
- int textTall = surface()->GetFontTall( font );
-
- Q_snprintf( sz, sizeof( sz ), "fps:%4i ping: %i ms", (int)(1.0f / m_Framerate), (int)(m_AvgLatency*1000.0f) );
-
- g_pMatSystemSurface->DrawColoredText( font, x, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
-
- // Draw update rate
- DrawUpdateRate( x + w, y );
-
- y += textTall;
-
- out = cmdinfo[ ( ( m_OutgoingSequence - 1 ) & ( TIMINGS - 1 ) ) ].size;
- if ( !out )
- {
- out = lastout;
- }
- else
- {
- lastout = out;
- }
-
- int totalsize = graph[ ( m_IncomingSequence & ( TIMINGS - 1 ) ) ].msgbytes[INetChannelInfo::TOTAL];
-
- Q_snprintf( sz, sizeof( sz ), "in :%4i %2.2f k/s ", totalsize, m_IncomingData );
-
- int textWidth = g_pMatSystemSurface->DrawTextLen( font, "%s", sz );
-
- g_pMatSystemSurface->DrawColoredText( font, x, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
-
- Q_snprintf( sz, sizeof( sz ), "lerp: %5.1f ms", GetClientInterpAmount() * 1000.0f );
-
- int interpcolor[ 3 ] = { GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE };
- float flInterp = GetClientInterpAmount();
- if ( flInterp > 0.001f )
- {
- // Server framerate is lower than interp can possibly deal with
- if ( m_flServerFramerate < ( 1.0f / flInterp ) )
- {
- interpcolor[ 0 ] = 255;
- interpcolor[ 1 ] = 255;
- interpcolor[ 2 ] = 31;
- }
- // flInterp is below recommended setting!!!
- else if ( flInterp < ( 2.0f / cl_updaterate->GetFloat() ) )
- {
- interpcolor[ 0 ] = 255;
- interpcolor[ 1 ] = 125;
- interpcolor[ 2 ] = 31;
- }
- }
-
- g_pMatSystemSurface->DrawColoredText( font, x + textWidth, y, interpcolor[ 0 ], interpcolor[ 1 ], interpcolor[ 2 ], 255, sz );
-
- Q_snprintf( sz, sizeof( sz ), "%3.1f/s", m_AvgPacketIn );
- textWidth = g_pMatSystemSurface->DrawTextLen( font, "%s", sz );
-
- g_pMatSystemSurface->DrawColoredText( font, x + w - textWidth - 1, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
-
- y += textTall;
-
- Q_snprintf( sz, sizeof( sz ), "out:%4i %2.2f k/s", out, m_OutgoingData );
-
- g_pMatSystemSurface->DrawColoredText( font, x, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
-
- Q_snprintf( sz, sizeof( sz ), "%3.1f/s", m_AvgPacketOut );
- textWidth = g_pMatSystemSurface->DrawTextLen( font, "%s", sz );
-
- g_pMatSystemSurface->DrawColoredText( font, x + w - textWidth - 1, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
-
- y += textTall;
-
- DrawCmdRate( x + w, y );
-
- if ( graphvalue > 2 )
- {
- Q_snprintf( sz, sizeof( sz ), "loss:%3i choke: %2i ", (int)(m_AvgPacketLoss*100.0f), (int)(m_AvgPacketChoke*100.0f) );
-
- textWidth = g_pMatSystemSurface->DrawTextLen( font, "%s", sz );
-
- g_pMatSystemSurface->DrawColoredText( font, x, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
-
- y += textTall;
-
- if ( graphvalue > 3 )
- {
- Q_snprintf( sz, sizeof( sz ), "sv : %5.1f var: %4.2f msec", m_flServerFramerate, m_flServerFramerateStdDeviation * 1000.0f );
-
- int servercolor[ 3 ] = { GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE };
-
- if ( m_flServerFramerate < 10.0f )
- {
- servercolor[ 0 ] = 255;
- servercolor[ 1 ] = 31;
- servercolor[ 2 ] = 31;
- }
- else if ( m_flServerFramerate < 20.0f )
- {
- servercolor[ 0 ] = 255;
- servercolor[ 1 ] = 255;
- servercolor[ 2 ] = 0;
- }
-
- g_pMatSystemSurface->DrawColoredText( font, x, y, servercolor[ 0 ], servercolor[ 1 ], servercolor[ 2 ], 255, sz );
-
- y += textTall;
- }
- }
-
- // Draw legend
- if ( graphvalue >= 3 )
- {
- int textTall = g_pMatSystemSurface->GetFontTall( m_hFontSmall );
-
- y = saveY - textTall - 5;
- int cw, ch;
- g_pMatSystemSurface->GetTextSize( m_hFontSmall, L"otherplayersWWW", cw, ch );
- if ( x - cw < 0 )
- {
- x += w + 5;
- }
- else
- {
- x -= cw;
- }
-
- g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 0, 255, 255, "localplayer" );
- y -= textTall;
- g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 255, 0, 255, "otherplayers" );
- y -= textTall;
- g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 255, 0, 0, 255, "entities" );
- y -= textTall;
- g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 255, 255, 0, 255, "sounds" );
- y -= textTall;
- g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 255, 255, 255, "events" );
- y -= textTall;
- g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 128, 128, 0, 255, "usermessages" );
- y -= textTall;
- g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 128, 128, 255, "entmessages" );
- y -= textTall;
- g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 128, 0, 0, 255, "stringcmds" );
- y -= textTall;
- g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 128, 0, 255, "stringtables" );
- y -= textTall;
- g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 0, 128, 255, "voice" );
- y -= textTall;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Determine type of graph to show, or if +graph key is held down, use detailed graph
-// Output : int
-//-----------------------------------------------------------------------------
-int CNetGraphPanel::GraphValue( void )
-{
- int graphtype;
-
- graphtype = net_graph.GetInt();
-
- if ( !graphtype && !( in_graph.state & 1 ) )
- return 0;
-
- // With +graph key, use max area
- if ( !graphtype )
- {
- graphtype = 2;
- }
-
- return graphtype;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Figure out x and y position for graph based on net_graphpos
-// value.
-// Input : *rect -
-// width -
-// *x -
-// *y -
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::GraphGetXY( vrect_t *rect, int width, int *x, int *y )
-{
- *x = rect->x + 5;
-
- switch ( net_graphpos.GetInt() )
- {
- case 0:
- break;
- case 1:
- *x = rect->x + rect->width - 5 - width;
- break;
- case 2:
- *x = rect->x + ( rect->width - 10 - width ) / 2;
- break;
- default:
- *x = rect->x + clamp( (int) XRES( net_graphpos.GetInt() ), 5, rect->width - width - 5 );
- }
-
- *y = rect->y+rect->height - LERP_HEIGHT - 5;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: drawing stream progess (file download etc) as green bars ( under in/out)
-// Input : x -
-// y -
-// maxmsgbytes -
-//-----------------------------------------------------------------------------
-
-void CNetGraphPanel::DrawStreamProgress( int x, int y, int width )
-{
- vrect_t rcLine;
-
- rcLine.height = 1;
- rcLine.x = x;
-
- byte color[3]; color[0] = 0; color[1] = 200; color[2] = 0;
-
- if ( m_StreamTotal[FLOW_INCOMING] > 0 )
- {
- rcLine.y = y - m_nNetGraphHeight + 15 + 14;
- rcLine.width = (m_StreamRecv[FLOW_INCOMING]*width)/m_StreamTotal[FLOW_INCOMING];
- DrawLine( &rcLine, color, 255 );
- }
-
- if ( m_StreamTotal[FLOW_OUTGOING] > 0 )
- {
- rcLine.y = y - m_nNetGraphHeight + 2*15 + 14;
- rcLine.width = (m_StreamRecv[FLOW_OUTGOING]*width)/m_StreamTotal[FLOW_OUTGOING];
- DrawLine( &rcLine, color, 255 );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: If showing bandwidth data, draw hatches big enough for largest message
-// Input : x -
-// y -
-// maxmsgbytes -
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::DrawHatches( int x, int y, int maxmsgbytes )
-{
- int starty;
- int ystep;
- vrect_t rcHatch;
-
- byte colorminor[3];
- byte color[3];
-
- ystep = (int)( 10.0 / net_scale.GetFloat() );
- ystep = MAX( ystep, 1 );
-
- rcHatch.y = y;
- rcHatch.height = 1;
- rcHatch.x = x;
- rcHatch.width = 4;
-
- color[0] = 0;
- color[1] = 200;
- color[2] = 0;
-
- colorminor[0] = 63;
- colorminor[1] = 63;
- colorminor[2] = 0;
-
- for ( starty = rcHatch.y; rcHatch.y > 0 && ((starty - rcHatch.y)*net_scale.GetFloat() < ( maxmsgbytes + 50 ) ); rcHatch.y -= ystep )
- {
- if ( !((int)((starty - rcHatch.y)*net_scale.GetFloat() ) % 50 ) )
- {
- DrawLine( &rcHatch, color, 255 );
- }
- else if ( ystep > 5 )
- {
- DrawLine( &rcHatch, colorminor, 200 );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: State how many updates a second are being requested
-// Input : x -
-// y -
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::DrawUpdateRate( int xright, int y )
-{
- char sz[ 32 ];
- Q_snprintf( sz, sizeof( sz ), "%i/s", cl_updaterate->GetInt() );
- wchar_t unicode[ 32 ];
- g_pVGuiLocalize->ConvertANSIToUnicode( sz, unicode, sizeof( unicode ) );
-
- // Last one
- int textWide, textTall;
-
- g_pMatSystemSurface->GetTextSize( GetNetgraphFont(), unicode, textWide, textTall );
-
- g_pMatSystemSurface->DrawColoredText( GetNetgraphFont(), xright - textWide - 1, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, "%s", sz );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: State how many updates a second are being requested
-// Input : x -
-// y -
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::DrawCmdRate( int xright, int y )
-{
- char sz[ 32 ];
- Q_snprintf( sz, sizeof( sz ), "%i/s", cl_cmdrate->GetInt() );
- wchar_t unicode[ 32 ];
- g_pVGuiLocalize->ConvertANSIToUnicode( sz, unicode, sizeof( unicode ) );
-
- // Last one
- int textWide, textTall;
-
- g_pMatSystemSurface->GetTextSize( GetNetgraphFont(), unicode, textWide, textTall );
-
- g_pMatSystemSurface->DrawColoredText( GetNetgraphFont(), xright - textWide - 1, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, "%s", sz );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Draws bandwidth breakdown data
-// Input : *rcFill -
-// bytes -
-// r -
-// g -
-// b -
-// alpha -
-// Output : int
-//-----------------------------------------------------------------------------
-int CNetGraphPanel::DrawDataSegment( vrect_t *rcFill, int bytes, byte r, byte g, byte b, byte alpha )
-{
- int h;
- byte color[3];
-
- h = bytes / net_scale.GetFloat();
-
- color[0] = r;
- color[1] = g;
- color[2] = b;
-
- rcFill->height = h;
- rcFill->y -= h;
-
- if ( rcFill->y < 2 )
- return 0;
-
- DrawLine( rcFill, color, alpha );
-
- return 1;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::OnTick( void )
-{
- bool bVisible = ShouldDraw();
- if ( IsVisible() != bVisible )
- {
- SetVisible( bVisible );
- }
-}
-
-bool CNetGraphPanel::ShouldDraw( void )
-{
- if ( GraphValue() != 0 )
- return true;
-
- return false;
-}
-
-void CNetGraphPanel::DrawLargePacketSizes( int x, int w, int graphtype, float warning_threshold )
-{
- vrect_t rcFill = {0,0,0,0};
- int a, i;
-
- for (a=0 ; a<w ; a++)
- {
- i = (m_IncomingSequence-a) & ( TIMINGS - 1 );
-
- rcFill.x = x + w -a -1;
- rcFill.width = 1;
- rcFill.y = m_Graph[i].sampleY;
- rcFill.height = m_Graph[i].sampleHeight;
-
- int nTotalBytes = m_Graph[ i ].msgbytes[ INetChannelInfo::TOTAL ];
-
- if ( warning_threshold != 0.0f &&
- nTotalBytes > MAX( 300, warning_threshold ) )
- {
- char sz[ 32 ];
- Q_snprintf( sz, sizeof( sz ), "%i", nTotalBytes );
-
- int len = g_pMatSystemSurface->DrawTextLen( m_hFont, sz );
-
- int textx, texty;
-
- textx = rcFill.x - len / 2;
- texty = MAX( 0, rcFill.y - 11 );
-
- g_pMatSystemSurface->DrawColoredText( m_hFont, textx, texty, 255, 255, 255, 255, sz );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: A basic version (doesn't taken into account the "holding after
-// screenshot" bit like TF does, but is good enough for hud_freezecamhide.
-//-----------------------------------------------------------------------------
-static bool IsTakingAFreezecamScreenshot()
-{
- C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
- bool bInFreezeCam = ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM );
-
- return ( bInFreezeCam && engine->IsTakingScreenshot() );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::Paint()
-{
- VPROF( "CNetGraphPanel::Paint" );
-
- // Don't display net_graph if taking freezecam screenshot and hud_freezecamhide is enabled
- extern ConVar hud_freezecamhide;
- if ( hud_freezecamhide.GetBool() && IsTakingAFreezecamScreenshot() )
- return;
-
- int graphtype;
-
- int x, y;
- int w;
- vrect_t vrect;
-
- int maxmsgbytes = 0;
-
- float avg_message = 0.0f;
- float warning_threshold = 0.0f;
-
- if ( ( graphtype = GraphValue() ) == 0 )
- return;
-
- // Since we divide by scale, make sure it's sensible
- if ( net_scale.GetFloat() <= 0 )
- {
- net_scale.SetValue( 0.1f );
- }
-
- int sw, sh;
- surface()->GetScreenSize( sw, sh );
-
- // Get screen rectangle
- vrect.x = 0;
- vrect.y = 0;
- vrect.width = sw;
- vrect.height = sh;
-
-
- w = MIN( (int)TIMINGS, m_EstimatedWidth );
- if ( vrect.width < w + 10 )
- {
- w = vrect.width - 10;
- }
-
- // get current client netchannel INetChannelInfo interface
- INetChannelInfo *nci = engine->GetNetChannelInfo();
-
- if ( nci )
- {
- // update incoming data
- GetFrameData( nci, &maxmsgbytes, &avg_message, &warning_threshold );
-
- // update outgoing data
- GetCommandInfo( nci, m_Cmdinfo );
-
- UpdateEstimatedServerFramerate( nci );
- }
-
- GraphGetXY( &vrect, w, &x, &y );
-
- if ( graphtype > 1 )
- {
- PaintLineArt( x, y, w, graphtype, maxmsgbytes );
-
- DrawLargePacketSizes( x, w, graphtype, warning_threshold );
- }
-
- // Draw client frame timing info
- DrawTimes( vrect, m_Cmdinfo, x, w, graphtype );
-
- DrawTextFields( graphtype, x, y, w, m_Graph, m_Cmdinfo );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::PaintLineArt( int x, int y, int w, int graphtype, int maxmsgbytes )
-{
- VPROF( "CNetGraphPanel::PaintLineArt" );
-
- ResetLineSegments();
-
- int lastvalidh = 0;
-
- byte color[3];
- int ping;
- byte alpha;
- vrect_t rcFill = {0,0,0,0};
-
- int pingheight = m_nNetGraphHeight - LERP_HEIGHT - 2;
-
- if (net_graphmsecs.GetInt() < 50 )
- {
- net_graphmsecs.SetValue( 50 );
- }
-
- bool bShowLatency = net_graphshowlatency.GetBool() && graphtype >= 2;
-
- for (int a=0 ; a<w ; a++)
- {
- int i = (m_IncomingSequence-a) & ( TIMINGS - 1 );
- int h = bShowLatency ? m_PacketLatency[i].latency : 0;
-
- packet_latency_t *pl = &m_PacketLatency[ i ];
- ColorForHeight( pl, color, &ping, &alpha );
-
- // Skipped
- if ( !ping )
- {
- // Re-use the last latency
- h = lastvalidh;
- }
- else
- {
- h = pingheight * (float)h/net_graphmsecs.GetFloat();
- lastvalidh = h;
- }
-
- if ( h > pingheight )
- {
- h = pingheight;
- }
-
- rcFill.x = x + w -a -1;
- rcFill.y = y - h;
- rcFill.width = 1;
- rcFill.height = h;
- if ( ping )
- {
- rcFill.height = pl->choked ? 2 : 1;
- }
-
- if ( !ping )
- {
- DrawLine2(&rcFill, color, color, alpha, 31 );
- }
- else
- {
- DrawLine(&rcFill, color, alpha );
- }
-
- rcFill.y = y;
- rcFill.height = 1;
-
- color[0] = 0;
- color[1] = 255;
- color[2] = 0;
-
- DrawLine( &rcFill, color, 160 );
-
- if ( graphtype < 2 )
- continue;
-
- // Draw a separator.
- rcFill.y = y - m_nNetGraphHeight - 1;
- rcFill.height = 1;
-
- color[0] = 255;
- color[1] = 255;
- color[2] = 255;
-
- DrawLine(&rcFill, color, 255 );
-
- // Move up for begining of data
- rcFill.y -= 1;
-
- // Packet didn't have any real data...
- if ( m_PacketLatency[i].latency > 9995 )
- continue;
-
-
- if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::LOCALPLAYER], 0, 0, 255 ) )
- continue;
-
- if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::OTHERPLAYERS], 0, 255, 0 ) )
- continue;
-
- if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::ENTITIES], 255, 0, 0 ) )
- continue;
-
- if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::SOUNDS], 255, 255, 0) )
- continue;
-
- if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::EVENTS], 0, 255, 255 ) )
- continue;
-
- if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::USERMESSAGES], 128, 128, 0 ) )
- continue;
-
- if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::ENTMESSAGES], 0, 128, 128 ) )
- continue;
-
- if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::STRINGCMD], 128, 0, 0) )
- continue;
-
- if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::STRINGTABLE], 0, 128, 0) )
- continue;
-
- if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::VOICE], 0, 0, 128 ) )
- continue;
-
- // Final data chunk is total size, don't use solid line routine for this
- h = m_Graph[i].msgbytes[INetChannelInfo::TOTAL] / net_scale.GetFloat();
-
- color[ 0 ] = color[ 1 ] = color[ 2 ] = 240;
-
- rcFill.height = 1;
- rcFill.y = y - m_nNetGraphHeight - 1 - h;
-
- if ( rcFill.y < 2 )
- continue;
-
- DrawLine(&rcFill, color, 128 );
-
- // Cache off height
- m_Graph[i].sampleY = rcFill.y;
- m_Graph[i].sampleHeight = rcFill.height;
- }
-
- if ( graphtype >= 2 )
- {
- // Draw hatches for first one:
- // on the far right side
- DrawHatches( x, y - m_nNetGraphHeight - 1, maxmsgbytes );
-
- DrawStreamProgress( x, y, w );
- }
-
- DrawLineSegments();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::ResetLineSegments()
-{
- m_Rects.RemoveAll();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::DrawLineSegments()
-{
- int c = m_Rects.Count();
- if ( c <= 0 )
- return;
-
- CMatRenderContextPtr pRenderContext( materials );
- IMesh* m_pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteMaterial );
- CMeshBuilder meshBuilder;
- meshBuilder.Begin( m_pMesh, MATERIAL_LINES, c );
-
- int i;
- for ( i = 0 ; i < c; i++ )
- {
- CLineSegment *seg = &m_Rects[ i ];
-
- meshBuilder.Color4ubv( seg->color );
- meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
- meshBuilder.Position3f( seg->x1, seg->y1, 0 );
- meshBuilder.AdvanceVertex();
-
- meshBuilder.Color4ubv( seg->color2 );
- meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
- meshBuilder.Position3f( seg->x2, seg->y2, 0 );
- meshBuilder.AdvanceVertex();
- }
-
- meshBuilder.End();
-
- m_pMesh->Draw();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Draws a colored, filled rectangle
-// Input : *rect -
-// *color -
-// alpha -
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::DrawLine( vrect_t *rect, unsigned char *color, unsigned char alpha )
-{
- DrawLine2( rect, color, color, alpha, alpha );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Draws a colored, filled rectangle
-// Input : *rect -
-// *color -
-// alpha -
-//-----------------------------------------------------------------------------
-void CNetGraphPanel::DrawLine2( vrect_t *rect, unsigned char *color, unsigned char *color2, unsigned char alpha, unsigned char alpha2 )
-{
- VPROF( "CNetGraphPanel::DrawLine2" );
-
- int idx = m_Rects.AddToTail();
- CLineSegment *seg = &m_Rects[ idx ];
-
- seg->color[0] = color[0];
- seg->color[1] = color[1];
- seg->color[2] = color[2];
- seg->color[3] = alpha;
- seg->color2[0] = color2[0];
- seg->color2[1] = color2[1];
- seg->color2[2] = color2[2];
- seg->color2[3] = alpha2;
-
- if ( rect->width == 1 )
- {
- seg->x1 = rect->x;
- seg->y1 = rect->y;
- seg->x2 = rect->x;
- seg->y2 = rect->y + rect->height;
- }
- else if ( rect->height == 1 )
- {
- seg->x1 = rect->x;
- seg->y1 = rect->y;
- seg->x2 = rect->x + rect->width;
- seg->y2 = rect->y;
- }
- else
- {
- Assert( 0 );
- m_Rects.Remove( idx );
- }
-}
-
-void CNetGraphPanel::UpdateEstimatedServerFramerate( INetChannelInfo *netchannel )
-{
- float flFrameTime;
- netchannel->GetRemoteFramerate( &flFrameTime, &m_flServerFramerateStdDeviation );
- if ( flFrameTime > FLT_EPSILON )
- {
- m_flServerFramerate = 1.0f / flFrameTime;
- }
-}
-
-class CNetGraphPanelInterface : public INetGraphPanel
-{
-private:
- CNetGraphPanel *netGraphPanel;
-public:
- CNetGraphPanelInterface( void )
- {
- netGraphPanel = NULL;
- }
- void Create( VPANEL parent )
- {
- netGraphPanel = new CNetGraphPanel( parent );
- }
- void Destroy( void )
- {
- if ( netGraphPanel )
- {
- netGraphPanel->SetParent( (Panel *)NULL );
- delete netGraphPanel;
- netGraphPanel = NULL;
- }
- }
-};
-
-static CNetGraphPanelInterface g_NetGraphPanel;
-INetGraphPanel *netgraphpanel = ( INetGraphPanel * )&g_NetGraphPanel;
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "inetgraphpanel.h"
+#include "kbutton.h"
+#include <inetchannelinfo.h>
+#include "input.h"
+#include <vgui/IVGui.h>
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+#include <vgui/IScheme.h>
+#include <vgui/ILocalize.h>
+#include "tier0/vprof.h"
+#include "cdll_bounded_cvars.h"
+
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/imesh.h"
+#include "materialsystem/imaterial.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+static ConVar net_scale ( "net_scale", "5", FCVAR_ARCHIVE );
+static ConVar net_graphpos ( "net_graphpos", "1", FCVAR_ARCHIVE );
+static ConVar net_graphsolid ( "net_graphsolid", "1", FCVAR_ARCHIVE );
+static ConVar net_graphtext ( "net_graphtext", "1", FCVAR_ARCHIVE, "Draw text fields" );
+static ConVar net_graphmsecs ( "net_graphmsecs", "400", FCVAR_ARCHIVE, "The latency graph represents this many milliseconds." );
+static ConVar net_graphshowlatency( "net_graphshowlatency", "1", FCVAR_ARCHIVE, "Draw the ping/packet loss graph." );
+static ConVar net_graphshowinterp ( "net_graphshowinterp", "1", FCVAR_ARCHIVE, "Draw the interpolation graph." );
+
+void NetgraphFontChangeCallback( IConVar *var, const char *pOldValue, float flOldValue );
+
+static ConVar net_graph ( "net_graph","0", FCVAR_ARCHIVE, "Draw the network usage graph, = 2 draws data on payload, = 3 draws payload legend.", NetgraphFontChangeCallback );
+static ConVar net_graphheight ( "net_graphheight", "64", FCVAR_ARCHIVE, "Height of netgraph panel", NetgraphFontChangeCallback );
+static ConVar net_graphproportionalfont( "net_graphproportionalfont", "1", FCVAR_ARCHIVE, "Determines whether netgraph font is proportional or not", NetgraphFontChangeCallback );
+
+
+#define TIMINGS 1024 // Number of values to track (must be power of 2) b/c of masking
+#define FRAMERATE_AVG_FRAC 0.9
+#define PACKETLOSS_AVG_FRAC 0.5
+#define PACKETCHOKE_AVG_FRAC 0.5
+
+#define NUM_LATENCY_SAMPLES 8
+
+#define GRAPH_RED (0.9 * 255)
+#define GRAPH_GREEN (0.9 * 255)
+#define GRAPH_BLUE (0.7 * 255)
+
+#define LERP_HEIGHT 24
+
+#define COLOR_DROPPED 0
+#define COLOR_INVALID 1
+#define COLOR_SKIPPED 2
+#define COLOR_CHOKED 3
+#define COLOR_NORMAL 4
+
+//-----------------------------------------------------------------------------
+// Purpose: Displays the NetGraph
+//-----------------------------------------------------------------------------
+class CNetGraphPanel : public Panel
+{
+ typedef Panel BaseClass;
+private:
+ typedef struct
+ {
+ int latency;
+ int choked;
+ } packet_latency_t;
+
+ typedef struct
+ {
+ unsigned short msgbytes[INetChannelInfo::TOTAL+1];
+ int sampleY;
+ int sampleHeight;
+
+ } netbandwidthgraph_t;
+
+ typedef struct
+ {
+ float cmd_lerp;
+ int size;
+ bool sent;
+ } cmdinfo_t;
+
+ typedef struct
+ {
+ byte color[3];
+ byte alpha;
+ } netcolor_t;
+
+ byte colors[ LERP_HEIGHT ][3];
+
+ byte sendcolor[ 3 ];
+ byte holdcolor[ 3 ];
+ byte extrap_base_color[ 3 ];
+
+ packet_latency_t m_PacketLatency[ TIMINGS ];
+ cmdinfo_t m_Cmdinfo[ TIMINGS ];
+ netbandwidthgraph_t m_Graph[ TIMINGS ];
+
+ float m_Framerate;
+ float m_AvgLatency;
+ float m_AvgPacketLoss;
+ float m_AvgPacketChoke;
+ int m_IncomingSequence;
+ int m_OutgoingSequence;
+ int m_UpdateWindowSize;
+ float m_IncomingData;
+ float m_OutgoingData;
+ float m_AvgPacketIn;
+ float m_AvgPacketOut;
+
+ int m_StreamRecv[MAX_FLOWS];
+ int m_StreamTotal[MAX_FLOWS];
+
+ netcolor_t netcolors[5];
+
+ HFont m_hFontProportional;
+ HFont m_hFont;
+
+ HFont m_hFontSmall;
+ const ConVar *cl_updaterate;
+ const ConVar *cl_cmdrate;
+
+public:
+ CNetGraphPanel( VPANEL parent );
+ virtual ~CNetGraphPanel( void );
+
+ virtual void ApplySchemeSettings(IScheme *pScheme);
+ virtual void Paint();
+ virtual void OnTick( void );
+
+ virtual bool ShouldDraw( void );
+
+ void InitColors( void );
+ int GraphValue( void );
+
+ struct CLineSegment
+ {
+ int x1, y1, x2, y2;
+ byte color[4];
+ byte color2[4];
+ };
+
+ CUtlVector< CLineSegment > m_Rects;
+
+ inline void DrawLine( vrect_t *rect, unsigned char *color, unsigned char alpha );
+ inline void DrawLine2( vrect_t *rect, unsigned char *color, unsigned char *color2, unsigned char alpha, unsigned char alpha2 );
+
+ void ResetLineSegments();
+ void DrawLineSegments();
+
+ int DrawDataSegment( vrect_t *rcFill, int bytes, byte r, byte g, byte b, byte alpha = 255);
+ void DrawUpdateRate( int xright, int y );
+ void DrawCmdRate( int xright, int y );
+ void DrawHatches( int x, int y, int maxmsgbytes );
+ void DrawStreamProgress( int x, int y, int width );
+ void DrawTimes( vrect_t vrect, cmdinfo_t *cmdinfo, int x, int w, int graphtype );
+ void DrawTextFields( int graphvalue, int x, int y, int w, netbandwidthgraph_t *graph, cmdinfo_t *cmdinfo );
+ void GraphGetXY( vrect_t *rect, int width, int *x, int *y );
+ void GetCommandInfo( INetChannelInfo *netchannel, cmdinfo_t *cmdinfo );
+ void GetFrameData( INetChannelInfo *netchannel, int *biggest_message, float *avg_message, float *f95thpercentile );
+ void ColorForHeight( packet_latency_t *packet, byte *color, int *ping, byte *alpha );
+ void GetColorValues( int color, byte *cv, byte *alpha );
+
+ void OnFontChanged();
+
+private:
+
+ void PaintLineArt( int x, int y, int w, int graphtype, int maxmsgbytes );
+ void DrawLargePacketSizes( int x, int w, int graphtype, float warning_threshold );
+
+ HFont GetNetgraphFont()
+ {
+ return net_graphproportionalfont.GetBool() ? m_hFontProportional : m_hFont;
+ }
+
+ void ComputeNetgraphHeight();
+ void UpdateEstimatedServerFramerate( INetChannelInfo *netchannel );
+
+ CMaterialReference m_WhiteMaterial;
+
+ int m_EstimatedWidth;
+
+ int m_nNetGraphHeight;
+
+ float m_flServerFramerate;
+ float m_flServerFramerateStdDeviation;
+};
+
+CNetGraphPanel *g_pNetGraphPanel = NULL;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+//-----------------------------------------------------------------------------
+CNetGraphPanel::CNetGraphPanel( VPANEL parent )
+: BaseClass( NULL, "CNetGraphPanel" )
+{
+ int w, h;
+ surface()->GetScreenSize( w, h );
+
+ SetParent( parent );
+ SetSize( w, h );
+ SetPos( 0, 0 );
+ SetVisible( false );
+ SetCursor( null );
+
+ m_hFont = 0;
+ m_hFontProportional = 0;
+ m_hFontSmall = 0;
+ m_EstimatedWidth = 1;
+ m_nNetGraphHeight = 100;
+
+ SetFgColor( Color( 0, 0, 0, 255 ) );
+ SetPaintBackgroundEnabled( false );
+
+ InitColors();
+
+ cl_updaterate = cvar->FindVar( "cl_updaterate" );
+ cl_cmdrate = cvar->FindVar( "cl_cmdrate" );
+ assert( cl_updaterate && cl_cmdrate );
+
+ memset( sendcolor, 0, 3 );
+ memset( holdcolor, 0, 3 );
+ sendcolor[ 0 ] = sendcolor[ 1 ] = 255;
+
+ memset( extrap_base_color, 255, 3 );
+
+ memset( m_PacketLatency, 0, TIMINGS * sizeof( packet_latency_t ) );
+ memset( m_Cmdinfo, 0, TIMINGS * sizeof( cmdinfo_t ) );
+ memset( m_Graph, 0, TIMINGS * sizeof( netbandwidthgraph_t ) );
+
+ m_Framerate = 0.0f;
+ m_AvgLatency = 0.0f;
+ m_AvgPacketLoss = 0.0f;
+ m_AvgPacketChoke = 0.0f;
+ m_IncomingSequence = 0;
+ m_OutgoingSequence = 0;
+ m_UpdateWindowSize = 0;
+ m_IncomingData = 0;
+ m_OutgoingData = 0;
+ m_AvgPacketIn = 0.0f;
+ m_AvgPacketOut = 0.0f;
+ m_flServerFramerate = 0;
+ m_flServerFramerateStdDeviation = 0;
+
+ netcolors[COLOR_DROPPED].color[0] = 255;
+ netcolors[COLOR_DROPPED].color[1] = 0;
+ netcolors[COLOR_DROPPED].color[2] = 0;
+ netcolors[COLOR_DROPPED].alpha = 255;
+ netcolors[COLOR_INVALID].color[0] = 0;
+ netcolors[COLOR_INVALID].color[1] = 0;
+ netcolors[COLOR_INVALID].color[2] = 255;
+ netcolors[COLOR_INVALID].alpha = 255;
+ netcolors[COLOR_SKIPPED].color[0] = 240;
+ netcolors[COLOR_SKIPPED].color[1] = 127;
+ netcolors[COLOR_SKIPPED].color[2] = 63;
+ netcolors[COLOR_SKIPPED].alpha = 255;
+ netcolors[COLOR_CHOKED].color[0] = 225;
+ netcolors[COLOR_CHOKED].color[1] = 225;
+ netcolors[COLOR_CHOKED].color[2] = 0;
+ netcolors[COLOR_CHOKED].alpha = 255;
+ netcolors[COLOR_NORMAL].color[0] = 63;
+ netcolors[COLOR_NORMAL].color[1] = 255;
+ netcolors[COLOR_NORMAL].color[2] = 63;
+ netcolors[COLOR_NORMAL].alpha = 232;
+
+ ivgui()->AddTickSignal( GetVPanel(), 500 );
+
+ m_WhiteMaterial.Init( "vgui/white", TEXTURE_GROUP_OTHER );
+ g_pNetGraphPanel = this;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CNetGraphPanel::~CNetGraphPanel( void )
+{
+ g_pNetGraphPanel = NULL;
+}
+
+void NetgraphFontChangeCallback( IConVar *var, const char *pOldValue, float flOldValue )
+{
+ if ( g_pNetGraphPanel )
+ {
+ g_pNetGraphPanel->OnFontChanged();
+ }
+}
+
+void CNetGraphPanel::OnFontChanged()
+{
+ // Estimate the width of our panel.
+ char str[512];
+ wchar_t ustr[512];
+ Q_snprintf( str, sizeof( str ), "fps: 435 ping: 533 ms lerp 112.3 ms 0/0" );
+ g_pVGuiLocalize->ConvertANSIToUnicode( str, ustr, sizeof( ustr ) );
+ int textTall;
+ if ( m_hFontProportional == vgui::INVALID_FONT )
+ {
+ m_EstimatedWidth = textTall = 0;
+ }
+ else
+ {
+ g_pMatSystemSurface->GetTextSize( m_hFontProportional, ustr, m_EstimatedWidth, textTall );
+ }
+
+ int w, h;
+ surface()->GetScreenSize( w, h );
+ SetSize( w, h );
+ SetPos( 0, 0 );
+
+ ComputeNetgraphHeight();
+}
+
+void CNetGraphPanel::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ m_hFont = pScheme->GetFont( "DefaultFixedOutline", false );
+ m_hFontProportional = pScheme->GetFont( "DefaultFixedOutline", true );
+ m_hFontSmall = pScheme->GetFont( "DefaultVerySmall", false );
+
+ OnFontChanged();
+}
+
+void CNetGraphPanel::ComputeNetgraphHeight()
+{
+ m_nNetGraphHeight = net_graphheight.GetInt();
+
+ HFont fnt = GetNetgraphFont();
+ int tall = surface()->GetFontTall( fnt );
+
+ int lines = 3;
+ if ( net_graph.GetInt() > 3 )
+ {
+ lines = 5;
+ }
+ else if ( net_graph.GetInt() > 2 )
+ {
+ lines = 4;
+ }
+ m_nNetGraphHeight = MAX( lines * tall, m_nNetGraphHeight );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Copies data from netcolor_t array into fields passed in
+// Input : color -
+// *cv -
+// *alpha -
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::GetColorValues( int color, byte *cv, byte *alpha )
+{
+ int i;
+ netcolor_t *pc = &netcolors[ color ];
+ for ( i = 0; i < 3; i++ )
+ {
+ cv[ i ] = pc->color[ i ];
+ }
+ *alpha = pc->alpha;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets appropriate color values
+// Input : *packet -
+// *color -
+// *ping -
+// *alpha -
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::ColorForHeight( packet_latency_t *packet, byte *color, int *ping, byte *alpha )
+{
+ int h = packet->latency;
+ *ping = 0;
+ switch ( h )
+ {
+ case 9999:
+ GetColorValues( COLOR_DROPPED, color, alpha );
+ break;
+ case 9998:
+ GetColorValues( COLOR_INVALID, color, alpha );
+ break;
+ case 9997:
+ GetColorValues( COLOR_SKIPPED, color, alpha );
+ break;
+ default:
+ *ping = 1;
+ if (packet->choked )
+ {
+ GetColorValues( COLOR_CHOKED, color, alpha );
+ }
+ else
+ {
+ GetColorValues( COLOR_NORMAL, color, alpha );
+ }
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set up blend colors for comman/client-frame/interpolation graph
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::InitColors( void )
+{
+ int i, j;
+ byte mincolor[2][3];
+ byte maxcolor[2][3];
+ float dc[2][3];
+ int hfrac;
+ float f;
+
+ mincolor[0][0] = 63;
+ mincolor[0][1] = 0;
+ mincolor[0][2] = 100;
+
+ maxcolor[0][0] = 0;
+ maxcolor[0][1] = 63;
+ maxcolor[0][2] = 255;
+
+ mincolor[1][0] = 255;
+ mincolor[1][1] = 127;
+ mincolor[1][2] = 0;
+
+ maxcolor[1][0] = 250;
+ maxcolor[1][1] = 0;
+ maxcolor[1][2] = 0;
+
+ for ( i = 0; i < 3; i++ )
+ {
+ dc[0][i] = (float)(maxcolor[0][i] - mincolor[0][i]);
+ dc[1][i] = (float)(maxcolor[1][i] - mincolor[1][i]);
+ }
+
+ hfrac = LERP_HEIGHT / 3;
+
+ for ( i = 0; i < LERP_HEIGHT; i++ )
+ {
+ if ( i < hfrac )
+ {
+ f = (float)i / (float)hfrac;
+ for ( j = 0; j < 3; j++ )
+ {
+ colors[ i ][j] = mincolor[0][j] + f * dc[0][j];
+ }
+ }
+ else
+ {
+ f = (float)(i-hfrac) / (float)(LERP_HEIGHT - hfrac );
+ for ( j = 0; j < 3; j++ )
+ {
+ colors[ i ][j] = mincolor[1][j] + f * dc[1][j];
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw client framerate / usercommand graph
+// Input : vrect -
+// *cmdinfo -
+// x -
+// w -
+//-----------------------------------------------------------------------------
+
+void CNetGraphPanel::DrawTimes( vrect_t vrect, cmdinfo_t *cmdinfo, int x, int w, int graphtype )
+{
+ if ( !net_graphshowinterp.GetBool() || graphtype <= 1 )
+ return;
+
+ int i;
+ int j;
+ int extrap_point;
+ int a, h;
+ vrect_t rcFill;
+
+ ResetLineSegments();
+
+ extrap_point = LERP_HEIGHT / 3;
+
+ for (a=0 ; a<w ; a++)
+ {
+ i = ( m_OutgoingSequence - a ) & ( TIMINGS - 1 );
+ h = MIN( ( cmdinfo[i].cmd_lerp / 3.0 ) * LERP_HEIGHT, LERP_HEIGHT );
+
+ rcFill.x = x + w -a - 1;
+ rcFill.width = 1;
+ rcFill.height = 1;
+
+ rcFill.y = vrect.y + vrect.height - 4;
+
+ if ( h >= extrap_point )
+ {
+ int start = 0;
+
+ h -= extrap_point;
+ rcFill.y -= extrap_point;
+
+ if ( !net_graphsolid.GetInt() )
+ {
+ rcFill.y -= (h - 1);
+ start = (h - 1);
+ }
+
+ for ( j = start; j < h; j++ )
+ {
+ DrawLine(&rcFill, colors[j + extrap_point], 255 );
+ rcFill.y--;
+ }
+ }
+ else
+ {
+ int oldh;
+ oldh = h;
+ rcFill.y -= h;
+ h = extrap_point - h;
+
+ if ( !net_graphsolid.GetInt() )
+ {
+ h = 1;
+ }
+
+ for ( j = 0; j < h; j++ )
+ {
+ DrawLine(&rcFill, colors[j + oldh], 255 );
+ rcFill.y--;
+ }
+ }
+
+ rcFill.y = vrect.y + vrect.height - 4 - extrap_point;
+
+ DrawLine( &rcFill, extrap_base_color, 255 );
+
+ rcFill.y = vrect.y + vrect.height - 3;
+
+ if ( cmdinfo[ i ].sent )
+ {
+ DrawLine( &rcFill, sendcolor, 255 );
+ }
+ else
+ {
+ DrawLine( &rcFill, holdcolor, 200 );
+ }
+ }
+
+ DrawLineSegments();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Compute frame database for rendering m_NetChannel computes choked, and lost packets, too.
+// Also computes latency data and sets max packet size
+// Input : *packet_latency -
+// *graph -
+// *choke_count -
+// *loss_count -
+// *biggest_message -
+// 1 -
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::GetFrameData( INetChannelInfo *netchannel, int *biggest_message, float *avg_message, float *f95thpercentile )
+{
+ float frame_received_time;
+ // float frame_latency;
+
+ *biggest_message = 0;
+ *avg_message = 0.0f;
+ *f95thpercentile = 0.0f;
+
+ int msg_count = 0;
+
+ m_IncomingSequence = netchannel->GetSequenceNr( FLOW_INCOMING );
+ m_OutgoingSequence = netchannel->GetSequenceNr( FLOW_OUTGOING );
+ m_UpdateWindowSize = netchannel->GetBufferSize();
+ m_AvgPacketLoss = netchannel->GetAvgLoss( FLOW_INCOMING );
+ m_AvgPacketChoke = netchannel->GetAvgChoke( FLOW_INCOMING );
+ m_AvgLatency = netchannel->GetAvgLatency( FLOW_OUTGOING );
+ m_IncomingData = netchannel->GetAvgData( FLOW_INCOMING ) / 1024.0f;
+ m_OutgoingData = netchannel->GetAvgData( FLOW_OUTGOING ) / 1024.0f;
+ m_AvgPacketIn = netchannel->GetAvgPackets( FLOW_INCOMING );
+ m_AvgPacketOut = netchannel->GetAvgPackets( FLOW_OUTGOING );
+
+ for ( int i=0; i<MAX_FLOWS; i++ )
+ netchannel->GetStreamProgress( i, &m_StreamRecv[i], &m_StreamTotal[i] );
+
+ float flAdjust = 0.0f;
+
+ if ( cl_updaterate->GetFloat() > 0.001f )
+ {
+ flAdjust = -0.5f / cl_updaterate->GetFloat();
+
+ m_AvgLatency += flAdjust;
+ }
+
+ // Can't be below zero
+ m_AvgLatency = MAX( 0.0, m_AvgLatency );
+
+ flAdjust *= 1000.0f;
+
+ // Fill in frame data
+ for ( int seqnr =m_IncomingSequence - m_UpdateWindowSize + 1
+ ; seqnr <= m_IncomingSequence
+ ; seqnr++)
+ {
+
+
+ frame_received_time = netchannel->GetPacketTime( FLOW_INCOMING, seqnr );
+
+ netbandwidthgraph_t *nbwg = &m_Graph[ seqnr & ( TIMINGS - 1 )];
+ packet_latency_t *lat = &m_PacketLatency[ seqnr & ( TIMINGS - 1 ) ];
+
+ netchannel->GetPacketResponseLatency( FLOW_INCOMING, seqnr, &lat->latency, &lat->choked );
+
+ if ( lat->latency < 9995 )
+ {
+ lat->latency += flAdjust;
+ lat->latency = MAX( lat->latency, 0 );
+ }
+
+ for ( int i=0; i<=INetChannelInfo::TOTAL; i++ )
+ {
+ nbwg->msgbytes[i] = netchannel->GetPacketBytes( FLOW_INCOMING, seqnr, i );
+ }
+
+ // Assert ( nbwg->msgbytes[INetChannelInfo::TOTAL] > 0 );
+
+ if ( nbwg->msgbytes[INetChannelInfo::TOTAL] > *biggest_message )
+ {
+ *biggest_message = nbwg->msgbytes[INetChannelInfo::TOTAL];
+ }
+
+ *avg_message += (float)( nbwg->msgbytes[INetChannelInfo::TOTAL] );
+ msg_count++;
+
+
+ }
+
+ if ( *biggest_message > 1000 )
+ {
+ *biggest_message = 1000;
+ }
+
+ if ( msg_count >= 1 )
+ {
+ *avg_message /= msg_count;
+
+ int deviationsquared = 0;
+
+ // Compute std deviation
+ // Fill in frame data
+ for (int seqnr=m_IncomingSequence - m_UpdateWindowSize + 1
+ ; seqnr <= m_IncomingSequence
+ ; seqnr++)
+ {
+ int bytes = m_Graph[ seqnr & ( TIMINGS - 1 )].msgbytes[INetChannelInfo::TOTAL] - ( *avg_message );
+
+ deviationsquared += ( bytes * bytes );
+ }
+
+ float var = ( float )( deviationsquared ) / (float)( msg_count - 1 );
+ float stddev = sqrt( var );
+
+ *f95thpercentile = *avg_message + 2.0f * stddev;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Fills in command interpolation/holdback & message size data
+// Input : *cmdinfo -
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::GetCommandInfo( INetChannelInfo *netchannel, cmdinfo_t *cmdinfo )
+{
+ for ( int seqnr = m_OutgoingSequence - m_UpdateWindowSize + 1
+ ; seqnr <= m_OutgoingSequence
+ ; seqnr++)
+ {
+ // Also set up the lerp point.
+ cmdinfo_t *ci = &cmdinfo[ seqnr & ( TIMINGS - 1 ) ];
+
+ ci->cmd_lerp = netchannel->GetCommandInterpolationAmount( FLOW_OUTGOING, seqnr );
+ ci->sent = netchannel->IsValidPacket( FLOW_OUTGOING, seqnr );
+ ci->size = netchannel->GetPacketBytes( FLOW_OUTGOING, seqnr, INetChannelInfo::TOTAL);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws overlay text fields showing framerate, latency, bandwidth breakdowns,
+// and, optionally, packet loss and choked packet percentages
+// Input : graphvalue -
+// x -
+// y -
+// *graph -
+// *cmdinfo -
+// count -
+// avg -
+// *framerate -
+// 0.0 -
+// avg -
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::DrawTextFields( int graphvalue, int x, int y, int w, netbandwidthgraph_t *graph, cmdinfo_t *cmdinfo )
+{
+ if ( !net_graphtext.GetBool() )
+ return;
+
+ static int lastout;
+
+ char sz[ 256 ];
+ int out;
+
+ HFont font = GetNetgraphFont();
+
+ // Move rolling average
+ m_Framerate = FRAMERATE_AVG_FRAC * m_Framerate + ( 1.0 - FRAMERATE_AVG_FRAC ) * gpGlobals->absoluteframetime;
+
+ // Print it out
+ y -= m_nNetGraphHeight;
+
+ int saveY = y;
+
+ if ( m_Framerate <= 0.0f )
+ m_Framerate = 1.0f;
+
+ if ( engine->IsPlayingDemo() )
+ m_AvgLatency = 0.0f;
+
+ int textTall = surface()->GetFontTall( font );
+
+ Q_snprintf( sz, sizeof( sz ), "fps:%4i ping: %i ms", (int)(1.0f / m_Framerate), (int)(m_AvgLatency*1000.0f) );
+
+ g_pMatSystemSurface->DrawColoredText( font, x, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
+
+ // Draw update rate
+ DrawUpdateRate( x + w, y );
+
+ y += textTall;
+
+ out = cmdinfo[ ( ( m_OutgoingSequence - 1 ) & ( TIMINGS - 1 ) ) ].size;
+ if ( !out )
+ {
+ out = lastout;
+ }
+ else
+ {
+ lastout = out;
+ }
+
+ int totalsize = graph[ ( m_IncomingSequence & ( TIMINGS - 1 ) ) ].msgbytes[INetChannelInfo::TOTAL];
+
+ Q_snprintf( sz, sizeof( sz ), "in :%4i %2.2f k/s ", totalsize, m_IncomingData );
+
+ int textWidth = g_pMatSystemSurface->DrawTextLen( font, "%s", sz );
+
+ g_pMatSystemSurface->DrawColoredText( font, x, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
+
+ Q_snprintf( sz, sizeof( sz ), "lerp: %5.1f ms", GetClientInterpAmount() * 1000.0f );
+
+ int interpcolor[ 3 ] = { GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE };
+ float flInterp = GetClientInterpAmount();
+ if ( flInterp > 0.001f )
+ {
+ // Server framerate is lower than interp can possibly deal with
+ if ( m_flServerFramerate < ( 1.0f / flInterp ) )
+ {
+ interpcolor[ 0 ] = 255;
+ interpcolor[ 1 ] = 255;
+ interpcolor[ 2 ] = 31;
+ }
+ // flInterp is below recommended setting!!!
+ else if ( flInterp < ( 2.0f / cl_updaterate->GetFloat() ) )
+ {
+ interpcolor[ 0 ] = 255;
+ interpcolor[ 1 ] = 125;
+ interpcolor[ 2 ] = 31;
+ }
+ }
+
+ g_pMatSystemSurface->DrawColoredText( font, x + textWidth, y, interpcolor[ 0 ], interpcolor[ 1 ], interpcolor[ 2 ], 255, sz );
+
+ Q_snprintf( sz, sizeof( sz ), "%3.1f/s", m_AvgPacketIn );
+ textWidth = g_pMatSystemSurface->DrawTextLen( font, "%s", sz );
+
+ g_pMatSystemSurface->DrawColoredText( font, x + w - textWidth - 1, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
+
+ y += textTall;
+
+ Q_snprintf( sz, sizeof( sz ), "out:%4i %2.2f k/s", out, m_OutgoingData );
+
+ g_pMatSystemSurface->DrawColoredText( font, x, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
+
+ Q_snprintf( sz, sizeof( sz ), "%3.1f/s", m_AvgPacketOut );
+ textWidth = g_pMatSystemSurface->DrawTextLen( font, "%s", sz );
+
+ g_pMatSystemSurface->DrawColoredText( font, x + w - textWidth - 1, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
+
+ y += textTall;
+
+ DrawCmdRate( x + w, y );
+
+ if ( graphvalue > 2 )
+ {
+ Q_snprintf( sz, sizeof( sz ), "loss:%3i choke: %2i ", (int)(m_AvgPacketLoss*100.0f), (int)(m_AvgPacketChoke*100.0f) );
+
+ textWidth = g_pMatSystemSurface->DrawTextLen( font, "%s", sz );
+
+ g_pMatSystemSurface->DrawColoredText( font, x, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, sz );
+
+ y += textTall;
+
+ if ( graphvalue > 3 )
+ {
+ Q_snprintf( sz, sizeof( sz ), "sv : %5.1f var: %4.2f msec", m_flServerFramerate, m_flServerFramerateStdDeviation * 1000.0f );
+
+ int servercolor[ 3 ] = { GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE };
+
+ if ( m_flServerFramerate < 10.0f )
+ {
+ servercolor[ 0 ] = 255;
+ servercolor[ 1 ] = 31;
+ servercolor[ 2 ] = 31;
+ }
+ else if ( m_flServerFramerate < 20.0f )
+ {
+ servercolor[ 0 ] = 255;
+ servercolor[ 1 ] = 255;
+ servercolor[ 2 ] = 0;
+ }
+
+ g_pMatSystemSurface->DrawColoredText( font, x, y, servercolor[ 0 ], servercolor[ 1 ], servercolor[ 2 ], 255, sz );
+
+ y += textTall;
+ }
+ }
+
+ // Draw legend
+ if ( graphvalue >= 3 )
+ {
+ int textTall = g_pMatSystemSurface->GetFontTall( m_hFontSmall );
+
+ y = saveY - textTall - 5;
+ int cw, ch;
+ g_pMatSystemSurface->GetTextSize( m_hFontSmall, L"otherplayersWWW", cw, ch );
+ if ( x - cw < 0 )
+ {
+ x += w + 5;
+ }
+ else
+ {
+ x -= cw;
+ }
+
+ g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 0, 255, 255, "localplayer" );
+ y -= textTall;
+ g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 255, 0, 255, "otherplayers" );
+ y -= textTall;
+ g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 255, 0, 0, 255, "entities" );
+ y -= textTall;
+ g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 255, 255, 0, 255, "sounds" );
+ y -= textTall;
+ g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 255, 255, 255, "events" );
+ y -= textTall;
+ g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 128, 128, 0, 255, "usermessages" );
+ y -= textTall;
+ g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 128, 128, 255, "entmessages" );
+ y -= textTall;
+ g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 128, 0, 0, 255, "stringcmds" );
+ y -= textTall;
+ g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 128, 0, 255, "stringtables" );
+ y -= textTall;
+ g_pMatSystemSurface->DrawColoredText( m_hFontSmall, x, y, 0, 0, 128, 255, "voice" );
+ y -= textTall;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Determine type of graph to show, or if +graph key is held down, use detailed graph
+// Output : int
+//-----------------------------------------------------------------------------
+int CNetGraphPanel::GraphValue( void )
+{
+ int graphtype;
+
+ graphtype = net_graph.GetInt();
+
+ if ( !graphtype && !( in_graph.state & 1 ) )
+ return 0;
+
+ // With +graph key, use max area
+ if ( !graphtype )
+ {
+ graphtype = 2;
+ }
+
+ return graphtype;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Figure out x and y position for graph based on net_graphpos
+// value.
+// Input : *rect -
+// width -
+// *x -
+// *y -
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::GraphGetXY( vrect_t *rect, int width, int *x, int *y )
+{
+ *x = rect->x + 5;
+
+ switch ( net_graphpos.GetInt() )
+ {
+ case 0:
+ break;
+ case 1:
+ *x = rect->x + rect->width - 5 - width;
+ break;
+ case 2:
+ *x = rect->x + ( rect->width - 10 - width ) / 2;
+ break;
+ default:
+ *x = rect->x + clamp( (int) XRES( net_graphpos.GetInt() ), 5, rect->width - width - 5 );
+ }
+
+ *y = rect->y+rect->height - LERP_HEIGHT - 5;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: drawing stream progess (file download etc) as green bars ( under in/out)
+// Input : x -
+// y -
+// maxmsgbytes -
+//-----------------------------------------------------------------------------
+
+void CNetGraphPanel::DrawStreamProgress( int x, int y, int width )
+{
+ vrect_t rcLine;
+
+ rcLine.height = 1;
+ rcLine.x = x;
+
+ byte color[3]; color[0] = 0; color[1] = 200; color[2] = 0;
+
+ if ( m_StreamTotal[FLOW_INCOMING] > 0 )
+ {
+ rcLine.y = y - m_nNetGraphHeight + 15 + 14;
+ rcLine.width = (m_StreamRecv[FLOW_INCOMING]*width)/m_StreamTotal[FLOW_INCOMING];
+ DrawLine( &rcLine, color, 255 );
+ }
+
+ if ( m_StreamTotal[FLOW_OUTGOING] > 0 )
+ {
+ rcLine.y = y - m_nNetGraphHeight + 2*15 + 14;
+ rcLine.width = (m_StreamRecv[FLOW_OUTGOING]*width)/m_StreamTotal[FLOW_OUTGOING];
+ DrawLine( &rcLine, color, 255 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: If showing bandwidth data, draw hatches big enough for largest message
+// Input : x -
+// y -
+// maxmsgbytes -
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::DrawHatches( int x, int y, int maxmsgbytes )
+{
+ int starty;
+ int ystep;
+ vrect_t rcHatch;
+
+ byte colorminor[3];
+ byte color[3];
+
+ ystep = (int)( 10.0 / net_scale.GetFloat() );
+ ystep = MAX( ystep, 1 );
+
+ rcHatch.y = y;
+ rcHatch.height = 1;
+ rcHatch.x = x;
+ rcHatch.width = 4;
+
+ color[0] = 0;
+ color[1] = 200;
+ color[2] = 0;
+
+ colorminor[0] = 63;
+ colorminor[1] = 63;
+ colorminor[2] = 0;
+
+ for ( starty = rcHatch.y; rcHatch.y > 0 && ((starty - rcHatch.y)*net_scale.GetFloat() < ( maxmsgbytes + 50 ) ); rcHatch.y -= ystep )
+ {
+ if ( !((int)((starty - rcHatch.y)*net_scale.GetFloat() ) % 50 ) )
+ {
+ DrawLine( &rcHatch, color, 255 );
+ }
+ else if ( ystep > 5 )
+ {
+ DrawLine( &rcHatch, colorminor, 200 );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: State how many updates a second are being requested
+// Input : x -
+// y -
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::DrawUpdateRate( int xright, int y )
+{
+ char sz[ 32 ];
+ Q_snprintf( sz, sizeof( sz ), "%i/s", cl_updaterate->GetInt() );
+ wchar_t unicode[ 32 ];
+ g_pVGuiLocalize->ConvertANSIToUnicode( sz, unicode, sizeof( unicode ) );
+
+ // Last one
+ int textWide, textTall;
+
+ g_pMatSystemSurface->GetTextSize( GetNetgraphFont(), unicode, textWide, textTall );
+
+ g_pMatSystemSurface->DrawColoredText( GetNetgraphFont(), xright - textWide - 1, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, "%s", sz );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: State how many updates a second are being requested
+// Input : x -
+// y -
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::DrawCmdRate( int xright, int y )
+{
+ char sz[ 32 ];
+ Q_snprintf( sz, sizeof( sz ), "%i/s", cl_cmdrate->GetInt() );
+ wchar_t unicode[ 32 ];
+ g_pVGuiLocalize->ConvertANSIToUnicode( sz, unicode, sizeof( unicode ) );
+
+ // Last one
+ int textWide, textTall;
+
+ g_pMatSystemSurface->GetTextSize( GetNetgraphFont(), unicode, textWide, textTall );
+
+ g_pMatSystemSurface->DrawColoredText( GetNetgraphFont(), xright - textWide - 1, y, GRAPH_RED, GRAPH_GREEN, GRAPH_BLUE, 255, "%s", sz );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws bandwidth breakdown data
+// Input : *rcFill -
+// bytes -
+// r -
+// g -
+// b -
+// alpha -
+// Output : int
+//-----------------------------------------------------------------------------
+int CNetGraphPanel::DrawDataSegment( vrect_t *rcFill, int bytes, byte r, byte g, byte b, byte alpha )
+{
+ int h;
+ byte color[3];
+
+ h = bytes / net_scale.GetFloat();
+
+ color[0] = r;
+ color[1] = g;
+ color[2] = b;
+
+ rcFill->height = h;
+ rcFill->y -= h;
+
+ if ( rcFill->y < 2 )
+ return 0;
+
+ DrawLine( rcFill, color, alpha );
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::OnTick( void )
+{
+ bool bVisible = ShouldDraw();
+ if ( IsVisible() != bVisible )
+ {
+ SetVisible( bVisible );
+ }
+}
+
+bool CNetGraphPanel::ShouldDraw( void )
+{
+ if ( GraphValue() != 0 )
+ return true;
+
+ return false;
+}
+
+void CNetGraphPanel::DrawLargePacketSizes( int x, int w, int graphtype, float warning_threshold )
+{
+ vrect_t rcFill = {0,0,0,0};
+ int a, i;
+
+ for (a=0 ; a<w ; a++)
+ {
+ i = (m_IncomingSequence-a) & ( TIMINGS - 1 );
+
+ rcFill.x = x + w -a -1;
+ rcFill.width = 1;
+ rcFill.y = m_Graph[i].sampleY;
+ rcFill.height = m_Graph[i].sampleHeight;
+
+ int nTotalBytes = m_Graph[ i ].msgbytes[ INetChannelInfo::TOTAL ];
+
+ if ( warning_threshold != 0.0f &&
+ nTotalBytes > MAX( 300, warning_threshold ) )
+ {
+ char sz[ 32 ];
+ Q_snprintf( sz, sizeof( sz ), "%i", nTotalBytes );
+
+ int len = g_pMatSystemSurface->DrawTextLen( m_hFont, sz );
+
+ int textx, texty;
+
+ textx = rcFill.x - len / 2;
+ texty = MAX( 0, rcFill.y - 11 );
+
+ g_pMatSystemSurface->DrawColoredText( m_hFont, textx, texty, 255, 255, 255, 255, sz );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: A basic version (doesn't taken into account the "holding after
+// screenshot" bit like TF does, but is good enough for hud_freezecamhide.
+//-----------------------------------------------------------------------------
+static bool IsTakingAFreezecamScreenshot()
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ bool bInFreezeCam = ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM );
+
+ return ( bInFreezeCam && engine->IsTakingScreenshot() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::Paint()
+{
+ VPROF( "CNetGraphPanel::Paint" );
+
+ // Don't display net_graph if taking freezecam screenshot and hud_freezecamhide is enabled
+ extern ConVar hud_freezecamhide;
+ if ( hud_freezecamhide.GetBool() && IsTakingAFreezecamScreenshot() )
+ return;
+
+ int graphtype;
+
+ int x, y;
+ int w;
+ vrect_t vrect;
+
+ int maxmsgbytes = 0;
+
+ float avg_message = 0.0f;
+ float warning_threshold = 0.0f;
+
+ if ( ( graphtype = GraphValue() ) == 0 )
+ return;
+
+ // Since we divide by scale, make sure it's sensible
+ if ( net_scale.GetFloat() <= 0 )
+ {
+ net_scale.SetValue( 0.1f );
+ }
+
+ int sw, sh;
+ surface()->GetScreenSize( sw, sh );
+
+ // Get screen rectangle
+ vrect.x = 0;
+ vrect.y = 0;
+ vrect.width = sw;
+ vrect.height = sh;
+
+
+ w = MIN( (int)TIMINGS, m_EstimatedWidth );
+ if ( vrect.width < w + 10 )
+ {
+ w = vrect.width - 10;
+ }
+
+ // get current client netchannel INetChannelInfo interface
+ INetChannelInfo *nci = engine->GetNetChannelInfo();
+
+ if ( nci )
+ {
+ // update incoming data
+ GetFrameData( nci, &maxmsgbytes, &avg_message, &warning_threshold );
+
+ // update outgoing data
+ GetCommandInfo( nci, m_Cmdinfo );
+
+ UpdateEstimatedServerFramerate( nci );
+ }
+
+ GraphGetXY( &vrect, w, &x, &y );
+
+ if ( graphtype > 1 )
+ {
+ PaintLineArt( x, y, w, graphtype, maxmsgbytes );
+
+ DrawLargePacketSizes( x, w, graphtype, warning_threshold );
+ }
+
+ // Draw client frame timing info
+ DrawTimes( vrect, m_Cmdinfo, x, w, graphtype );
+
+ DrawTextFields( graphtype, x, y, w, m_Graph, m_Cmdinfo );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::PaintLineArt( int x, int y, int w, int graphtype, int maxmsgbytes )
+{
+ VPROF( "CNetGraphPanel::PaintLineArt" );
+
+ ResetLineSegments();
+
+ int lastvalidh = 0;
+
+ byte color[3];
+ int ping;
+ byte alpha;
+ vrect_t rcFill = {0,0,0,0};
+
+ int pingheight = m_nNetGraphHeight - LERP_HEIGHT - 2;
+
+ if (net_graphmsecs.GetInt() < 50 )
+ {
+ net_graphmsecs.SetValue( 50 );
+ }
+
+ bool bShowLatency = net_graphshowlatency.GetBool() && graphtype >= 2;
+
+ for (int a=0 ; a<w ; a++)
+ {
+ int i = (m_IncomingSequence-a) & ( TIMINGS - 1 );
+ int h = bShowLatency ? m_PacketLatency[i].latency : 0;
+
+ packet_latency_t *pl = &m_PacketLatency[ i ];
+ ColorForHeight( pl, color, &ping, &alpha );
+
+ // Skipped
+ if ( !ping )
+ {
+ // Re-use the last latency
+ h = lastvalidh;
+ }
+ else
+ {
+ h = pingheight * (float)h/net_graphmsecs.GetFloat();
+ lastvalidh = h;
+ }
+
+ if ( h > pingheight )
+ {
+ h = pingheight;
+ }
+
+ rcFill.x = x + w -a -1;
+ rcFill.y = y - h;
+ rcFill.width = 1;
+ rcFill.height = h;
+ if ( ping )
+ {
+ rcFill.height = pl->choked ? 2 : 1;
+ }
+
+ if ( !ping )
+ {
+ DrawLine2(&rcFill, color, color, alpha, 31 );
+ }
+ else
+ {
+ DrawLine(&rcFill, color, alpha );
+ }
+
+ rcFill.y = y;
+ rcFill.height = 1;
+
+ color[0] = 0;
+ color[1] = 255;
+ color[2] = 0;
+
+ DrawLine( &rcFill, color, 160 );
+
+ if ( graphtype < 2 )
+ continue;
+
+ // Draw a separator.
+ rcFill.y = y - m_nNetGraphHeight - 1;
+ rcFill.height = 1;
+
+ color[0] = 255;
+ color[1] = 255;
+ color[2] = 255;
+
+ DrawLine(&rcFill, color, 255 );
+
+ // Move up for begining of data
+ rcFill.y -= 1;
+
+ // Packet didn't have any real data...
+ if ( m_PacketLatency[i].latency > 9995 )
+ continue;
+
+
+ if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::LOCALPLAYER], 0, 0, 255 ) )
+ continue;
+
+ if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::OTHERPLAYERS], 0, 255, 0 ) )
+ continue;
+
+ if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::ENTITIES], 255, 0, 0 ) )
+ continue;
+
+ if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::SOUNDS], 255, 255, 0) )
+ continue;
+
+ if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::EVENTS], 0, 255, 255 ) )
+ continue;
+
+ if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::USERMESSAGES], 128, 128, 0 ) )
+ continue;
+
+ if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::ENTMESSAGES], 0, 128, 128 ) )
+ continue;
+
+ if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::STRINGCMD], 128, 0, 0) )
+ continue;
+
+ if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::STRINGTABLE], 0, 128, 0) )
+ continue;
+
+ if ( !DrawDataSegment( &rcFill, m_Graph[ i ].msgbytes[INetChannelInfo::VOICE], 0, 0, 128 ) )
+ continue;
+
+ // Final data chunk is total size, don't use solid line routine for this
+ h = m_Graph[i].msgbytes[INetChannelInfo::TOTAL] / net_scale.GetFloat();
+
+ color[ 0 ] = color[ 1 ] = color[ 2 ] = 240;
+
+ rcFill.height = 1;
+ rcFill.y = y - m_nNetGraphHeight - 1 - h;
+
+ if ( rcFill.y < 2 )
+ continue;
+
+ DrawLine(&rcFill, color, 128 );
+
+ // Cache off height
+ m_Graph[i].sampleY = rcFill.y;
+ m_Graph[i].sampleHeight = rcFill.height;
+ }
+
+ if ( graphtype >= 2 )
+ {
+ // Draw hatches for first one:
+ // on the far right side
+ DrawHatches( x, y - m_nNetGraphHeight - 1, maxmsgbytes );
+
+ DrawStreamProgress( x, y, w );
+ }
+
+ DrawLineSegments();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::ResetLineSegments()
+{
+ m_Rects.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::DrawLineSegments()
+{
+ int c = m_Rects.Count();
+ if ( c <= 0 )
+ return;
+
+ CMatRenderContextPtr pRenderContext( materials );
+ IMesh* m_pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteMaterial );
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( m_pMesh, MATERIAL_LINES, c );
+
+ int i;
+ for ( i = 0 ; i < c; i++ )
+ {
+ CLineSegment *seg = &m_Rects[ i ];
+
+ meshBuilder.Color4ubv( seg->color );
+ meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
+ meshBuilder.Position3f( seg->x1, seg->y1, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ubv( seg->color2 );
+ meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
+ meshBuilder.Position3f( seg->x2, seg->y2, 0 );
+ meshBuilder.AdvanceVertex();
+ }
+
+ meshBuilder.End();
+
+ m_pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws a colored, filled rectangle
+// Input : *rect -
+// *color -
+// alpha -
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::DrawLine( vrect_t *rect, unsigned char *color, unsigned char alpha )
+{
+ DrawLine2( rect, color, color, alpha, alpha );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws a colored, filled rectangle
+// Input : *rect -
+// *color -
+// alpha -
+//-----------------------------------------------------------------------------
+void CNetGraphPanel::DrawLine2( vrect_t *rect, unsigned char *color, unsigned char *color2, unsigned char alpha, unsigned char alpha2 )
+{
+ VPROF( "CNetGraphPanel::DrawLine2" );
+
+ int idx = m_Rects.AddToTail();
+ CLineSegment *seg = &m_Rects[ idx ];
+
+ seg->color[0] = color[0];
+ seg->color[1] = color[1];
+ seg->color[2] = color[2];
+ seg->color[3] = alpha;
+ seg->color2[0] = color2[0];
+ seg->color2[1] = color2[1];
+ seg->color2[2] = color2[2];
+ seg->color2[3] = alpha2;
+
+ if ( rect->width == 1 )
+ {
+ seg->x1 = rect->x;
+ seg->y1 = rect->y;
+ seg->x2 = rect->x;
+ seg->y2 = rect->y + rect->height;
+ }
+ else if ( rect->height == 1 )
+ {
+ seg->x1 = rect->x;
+ seg->y1 = rect->y;
+ seg->x2 = rect->x + rect->width;
+ seg->y2 = rect->y;
+ }
+ else
+ {
+ Assert( 0 );
+ m_Rects.Remove( idx );
+ }
+}
+
+void CNetGraphPanel::UpdateEstimatedServerFramerate( INetChannelInfo *netchannel )
+{
+ float flFrameTime;
+ netchannel->GetRemoteFramerate( &flFrameTime, &m_flServerFramerateStdDeviation );
+ if ( flFrameTime > FLT_EPSILON )
+ {
+ m_flServerFramerate = 1.0f / flFrameTime;
+ }
+}
+
+class CNetGraphPanelInterface : public INetGraphPanel
+{
+private:
+ CNetGraphPanel *netGraphPanel;
+public:
+ CNetGraphPanelInterface( void )
+ {
+ netGraphPanel = NULL;
+ }
+ void Create( VPANEL parent )
+ {
+ netGraphPanel = new CNetGraphPanel( parent );
+ }
+ void Destroy( void )
+ {
+ if ( netGraphPanel )
+ {
+ netGraphPanel->SetParent( (Panel *)NULL );
+ delete netGraphPanel;
+ netGraphPanel = NULL;
+ }
+ }
+};
+
+static CNetGraphPanelInterface g_NetGraphPanel;
+INetGraphPanel *netgraphpanel = ( INetGraphPanel * )&g_NetGraphPanel;