diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/vgui_netgraphpanel.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-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.cpp | 3026 |
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; |