summaryrefslogtreecommitdiff
path: root/game/client/tf2/hud_numeric.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf2/hud_numeric.cpp')
-rw-r--r--game/client/tf2/hud_numeric.cpp978
1 files changed, 978 insertions, 0 deletions
diff --git a/game/client/tf2/hud_numeric.cpp b/game/client/tf2/hud_numeric.cpp
new file mode 100644
index 0000000..3d2937c
--- /dev/null
+++ b/game/client/tf2/hud_numeric.cpp
@@ -0,0 +1,978 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include "hud.h"
+#include "hud_numeric.h"
+#include "iclientmode.h"
+#include <KeyValues.h>
+#include <vgui/ISurface.h>
+#include <vgui/IScheme.h>
+#include <vgui_controls/AnimationController.h>
+#include "ctype.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pElementName -
+// *panelName -
+//-----------------------------------------------------------------------------
+CHudNumeric::CHudNumeric( const char *pElementName, const char *panelName )
+ : CHudElement( pElementName ), BaseClass( NULL, panelName )
+{
+ // Make sure we have the lookups built
+ BuildPrintablesList();
+
+ vgui::Panel *pParent = g_pClientMode->GetViewport();
+ SetParent( pParent );
+
+ SetActive( true );
+ SetAutoDelete( false );
+
+ m_nTextLen = 0;
+ Q_memset( m_szPreviousValue, 0, sizeof( m_szPreviousValue ) );
+ Q_memset( m_szLatchedValue, 0, sizeof( m_szLatchedValue ) );
+
+ m_bDrawLabel = true;
+ m_bSendPulses = true;
+ m_bPulseForced = true;
+
+ m_flRotaryTime = 0.0f;
+ m_flRotaryStartTime = 0.0f;
+ m_flActualCharactersPerSecond = 7.0f;
+}
+
+bool CHudNumeric::s_bPrintablesBuilt;
+CUtlRBTree< int, int > CHudNumeric::m_Printables( 0, 0, DefLessFunc( int ) );
+
+//-----------------------------------------------------------------------------
+// Purpose: Builds a list of printable characters
+//-----------------------------------------------------------------------------
+void CHudNumeric::BuildPrintablesList( void )
+{
+ if ( s_bPrintablesBuilt )
+ return;
+
+ s_bPrintablesBuilt = true;
+ int i;
+ for ( i = 0; i < 256; i++ )
+ {
+ if ( isalnum( i ) ) // isprint or isgraph?
+ {
+ m_Printables.Insert( i );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Find the index of a printable character
+// Input : ch -
+// Output : int
+//-----------------------------------------------------------------------------
+int CHudNumeric::FindPrintableIndex( int ch )
+{
+ int idx = m_Printables.Find( ch );
+ return idx;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *scheme -
+//-----------------------------------------------------------------------------
+void CHudNumeric::ApplySchemeSettings(IScheme *scheme)
+{
+ BaseClass::ApplySchemeSettings(scheme);
+
+ m_flActualCharactersPerSecond = (float)m_flDesiredCharactersPerSecond;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CHudNumeric::IsRotating( void ) const
+{
+ if ( gpGlobals->curtime >= m_flRotaryStartTime &&
+ gpGlobals->curtime <= ( m_flRotaryStartTime + m_flRotaryTime ) )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : frac -
+// startchar -
+// endchar -
+// prevchar -
+// nextchar -
+// subfrac -
+//-----------------------------------------------------------------------------
+void CHudNumeric::GetRotatedChar( float frac, char startchar, char endchar, char& prevchar, char& nextchar, float& subfrac )
+{
+ // Recast into database of printable characters
+ int startidx = FindPrintableIndex( startchar );
+ int endidx = FindPrintableIndex( endchar );
+
+ float diff = ( float )endidx - ( float )startidx;
+
+ // No delta
+ if ( diff == 0.0f ||
+ startidx == m_Printables.InvalidIndex() ||
+ endidx == m_Printables.InvalidIndex() )
+ {
+ prevchar = startchar;
+ nextchar = startchar;
+ subfrac = 0.0f;
+
+ return;
+ }
+
+ bool reverse = false;
+ // Going backwards is same as forward except frac is reversed
+ if ( diff < 0.0f )
+ {
+ reverse = true;
+ frac = 1.0f - frac;
+ int temp = startidx;
+ startidx = endidx;
+ endidx = temp;
+ diff = -diff;
+ }
+
+ float foutindex = (float)startidx;
+ int outindex;
+ float fnextindex;
+ int nextindex;
+
+ int maxdelta = (int)diff;
+
+ if ( m_nRotaryMaxDelta != 0 )
+ {
+ maxdelta = MIN( m_nRotaryMaxDelta, maxdelta );
+ }
+
+ // Quantize steps
+ // Map frac into maxdelta discrete intervals
+ float indicesperstep = diff / (float)maxdelta;
+ float fnumstepstaken = clamp( frac * (float)maxdelta, 0.0f, (float)( maxdelta -0.001f ) );
+ int numstepstaken = (int)(fnumstepstaken);
+
+ foutindex = (float)startidx + (float)numstepstaken * indicesperstep;
+ foutindex = clamp( foutindex, (float)startidx, (float)endidx );
+
+ outindex = ( int )foutindex;
+
+ fnextindex = (float)startidx + (float)( numstepstaken + 1 ) * indicesperstep;
+ fnextindex = clamp( fnextindex, (float)startidx, (float)endidx );
+
+ nextindex = (int)fnextindex;
+
+ subfrac = fnumstepstaken - (float)numstepstaken;
+
+ if ( !m_Printables.IsValidIndex( outindex ) ||
+ !m_Printables.IsValidIndex( nextindex ) )
+ {
+ prevchar = startchar;
+ nextchar = startchar;
+ subfrac = 0.0f;
+ return;
+ }
+
+ if ( reverse )
+ {
+ subfrac = 1.0f - subfrac;
+ prevchar = m_Printables[ nextindex ];
+ nextchar = m_Printables[ outindex ];
+ }
+ else
+ {
+ prevchar = m_Printables[ outindex ];
+ nextchar = m_Printables[ nextindex ];
+ }
+}
+
+void CHudNumeric::PaintRotatedCharacterHoriz( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac )
+{
+ frac = 3 * frac * frac - 2 * frac * frac * frac;
+
+ int abcA, abcB, abcC;
+ surface()->GetCharABCwide( font, prevchar, abcA, abcB, abcC );
+ // int fontTall = surface()->GetFontTall( font );
+
+ CharRenderInfo info;
+ if ( frac < 0.5f )
+ {
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint the right half of the prevchar still
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position half way down glyph
+ info.verts[0].m_Position.x = Lerp( 0.5f, info.verts[0].m_Position.x, info.verts[1].m_Position.x );
+ info.verts[0].m_TexCoord.x = Lerp( 0.5f, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint up to frac from left of next char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[1].m_Position.x = Lerp( frac, info.verts[0].m_Position.x, info.verts[1].m_Position.x );
+ info.verts[1].m_TexCoord.x = Lerp( frac, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ // Paint divider
+
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint from frac to 0.5 of prevchar on the left
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position half way up glyph
+ vgui::Vertex_t save[2];
+
+ save[0] = info.verts[0];
+ save[1] = info.verts[1];
+
+ info.verts[0].m_Position.x = Lerp( frac, save[0].m_Position.x, save[1].m_Position.x );
+ //info.verts[0].m_TexCoord.x = Lerp( frac, save[0].m_TexCoord.x, save[1].m_TexCoord.x );
+
+ info.verts[1].m_Position.x = Lerp( 0.5f, save[0].m_Position.x, save[1].m_Position.x );
+ info.verts[1].m_TexCoord.x = Lerp( 0.5f, save[0].m_TexCoord.x, save[1].m_TexCoord.x );
+
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+ else if ( frac > 0.5f )
+ {
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint entire left half of next char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position half way down glyph
+ info.verts[1].m_Position.x = Lerp( 0.5f, info.verts[0].m_Position.x, info.verts[1].m_Position.x );
+ info.verts[1].m_TexCoord.x = Lerp( 0.5f, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ surface()->DrawSetTextPos( x, y );
+
+ // paint a bit of the previous char at far right
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[0].m_Position.x = Lerp( frac, info.verts[0].m_Position.x, info.verts[1].m_Position.x );
+ info.verts[0].m_TexCoord.x = Lerp( frac, info.verts[0].m_TexCoord.x, info.verts[1].m_TexCoord.x );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ // Paint divider
+
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint from 0.5 to frac of next char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ vgui::Vertex_t save[2];
+
+ save[0] = info.verts[0];
+ save[1] = info.verts[1];
+
+ info.verts[0].m_Position.x = Lerp( 0.5f, save[0].m_Position.x, save[1].m_Position.x );
+ info.verts[0].m_TexCoord.x = Lerp( 0.5f, save[0].m_TexCoord.x, save[1].m_TexCoord.x );
+
+ info.verts[1].m_Position.x = Lerp( frac, save[0].m_Position.x, save[1].m_Position.x );
+ //info.verts[1].m_TexCoord.x = Lerp( frac, save[0].m_TexCoord.x, save[1].m_TexCoord.x );
+
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+
+ x += ( abcA + abcB + abcC );
+ surface()->DrawSetTextPos( x, y );
+}
+
+void CHudNumeric::PaintRotatedCharacterSpeedomter( int x, int y, vgui::HFont& font, int prevchar, int nextchar, float frac )
+{
+ frac = 3 * frac * frac - 2 * frac * frac * frac;
+
+ int abcA, abcB, abcC;
+ surface()->GetCharABCwide( font, prevchar, abcA, abcB, abcC );
+ // int fontTall = surface()->GetFontTall( font );
+
+ CharRenderInfo info;
+ if ( frac <= 0.0f )
+ {
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint the whole previous char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+ else if ( frac >= 1.0f )
+ {
+ surface()->DrawSetTextPos( x, y );
+
+ // Paint the whole previous char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+ else
+ {
+ // Draw part of previous and part of next
+ surface()->DrawSetTextPos( x, y );
+
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[1].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[1].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ // Paint divider
+
+ surface()->DrawSetTextPos( x, y );
+
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[0].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[0].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+
+ x += ( abcA + abcB + abcC );
+ surface()->DrawSetTextPos( x, y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+// font -
+// prevchar -
+// nextchar -
+// frac -
+//-----------------------------------------------------------------------------
+void CHudNumeric::PaintRotatedCharacter( int x, int y, HFont& font, int prevchar, int nextchar, float frac )
+{
+ frac = SimpleSpline( frac );
+
+ int abcA[2], abcB[2], abcC[2];
+ surface()->GetCharABCwide( font, prevchar, abcA[0], abcB[0], abcC[0] );
+ surface()->GetCharABCwide( font, nextchar, abcA[1], abcB[1], abcC[1] );
+
+ int w0 = abcA[0] + abcB[0] + abcC[0];
+ int w1 = abcA[1] + abcB[1] + abcC[1];
+
+ int cellwidth = MAX( w0, w1 );
+
+ int fontTall = surface()->GetFontTall( font );
+
+ int dividery = y + clamp( Lerp( frac, 0, fontTall ), 2, fontTall - 2 );
+
+ int xprev = x;
+ int xnext = x;
+
+ int diff = abs( abcB[0] - abcB[1] ) * 0.5f;
+
+ if ( diff != 0 )
+ {
+ // Prev is wider than next, push next right a bit
+ if ( w0 > w1 )
+ {
+ xnext += diff;
+ }
+ else
+ {
+ xprev += diff;
+ }
+ }
+
+ CharRenderInfo info;
+ if ( frac < 0.5f )
+ {
+ surface()->DrawSetTextPos( xprev, y );
+
+ // Paint the bottom half of the prevchar still
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position half way down glyph
+ info.verts[0].m_Position.y = Lerp( 0.5f, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[0].m_TexCoord.y = Lerp( 0.5f, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ surface()->DrawSetTextPos( xnext, y );
+
+ // Paint up to frac from top of prev char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[1].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[1].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ // Paint divider
+ if ( frac > 0.0f )
+ {
+ surface()->DrawSetColor( m_CharBgBorder );
+ surface()->DrawLine( x - abcA[0] + 1, dividery, x + abcB[0] + abcC[0] - 1, dividery );
+ }
+
+ surface()->DrawSetTextPos( xprev, y );
+
+ // Paint from frac to 0.5 of nextchar on the top
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position half way up glyph
+ vgui::Vertex_t save[2];
+
+ save[0] = info.verts[0];
+ save[1] = info.verts[1];
+
+ info.verts[0].m_Position.y = Lerp( frac, save[0].m_Position.y, save[1].m_Position.y );
+ //info.verts[0].m_TexCoord.y = Lerp( frac, save[0].m_TexCoord.y, save[1].m_TexCoord.y );
+
+ info.verts[1].m_Position.y = Lerp( 0.5f, save[0].m_Position.y, save[1].m_Position.y );
+ info.verts[1].m_TexCoord.y = Lerp( 0.5f, save[0].m_TexCoord.y, save[1].m_TexCoord.y );
+
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+ else if ( frac >= 0.5f )
+ {
+ surface()->DrawSetTextPos( xnext, y );
+
+ // Paint entire top half of next char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position half way down glyph
+ info.verts[1].m_Position.y = Lerp( 0.5f, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[1].m_TexCoord.y = Lerp( 0.5f, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ surface()->DrawSetTextPos( xprev, y );
+
+ // paint a bit of the previous char at the bottom
+ if ( surface()->DrawGetUnicodeCharRenderInfo( prevchar, info ) )
+ {
+ // Shift tex coord and y position part way up glyph
+ info.verts[0].m_Position.y = Lerp( frac, info.verts[0].m_Position.y, info.verts[1].m_Position.y );
+ info.verts[0].m_TexCoord.y = Lerp( frac, info.verts[0].m_TexCoord.y, info.verts[1].m_TexCoord.y );
+ surface()->DrawRenderCharFromInfo( info );
+ }
+
+ // Paint divider
+ if ( frac < 1.0f )
+ {
+ surface()->DrawSetColor( m_CharBgBorder );
+ surface()->DrawLine( x - abcA[0] + 1, dividery, x + abcB[0] + abcC[0] - 1, dividery );
+ }
+
+ surface()->DrawSetTextPos( xnext, y );
+
+ // Paint from 0.5 to frac of next char
+ if ( surface()->DrawGetUnicodeCharRenderInfo( nextchar, info ) )
+ {
+ // Shift tex coord and y position half way up glyph
+ vgui::Vertex_t save[2];
+
+ save[0] = info.verts[0];
+ save[1] = info.verts[1];
+
+ info.verts[0].m_Position.y = Lerp( 0.5f, save[0].m_Position.y, save[1].m_Position.y );
+ info.verts[0].m_TexCoord.y = Lerp( 0.5f, save[0].m_TexCoord.y, save[1].m_TexCoord.y );
+
+ info.verts[1].m_Position.y = Lerp( frac, save[0].m_Position.y, save[1].m_Position.y );
+ //info.verts[1].m_TexCoord.y = Lerp( frac, save[0].m_TexCoord.y, save[1].m_TexCoord.y );
+
+ surface()->DrawRenderCharFromInfo( info );
+ }
+ }
+
+ x += cellwidth;
+ surface()->DrawSetTextPos( x, y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *prev -
+// *next -
+// Output : float
+//-----------------------------------------------------------------------------
+float CHudNumeric::MaxCharacterDiff( const char *prev, const char *next )
+{
+ float maxdiff = 0.0f;
+
+ int textlen = Q_strlen( next );
+ int prevlen = Q_strlen( prev );
+ int ch;
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ int charfromend = textlen - ch;
+ char c = next[ ch ];
+ char prevc = prev[ MAX( 0, prevlen - charfromend ) ];
+ if ( prevc == 0 )
+ {
+ int tempindex = FindPrintableIndex( c );
+ if ( tempindex != m_Printables.InvalidIndex() )
+ {
+ tempindex = MAX( 0, tempindex - 3 );
+ prevc = m_Printables[ tempindex ];
+ }
+ else
+ {
+ prevc = c;
+ }
+ }
+
+ float diff = (float)fabs( FindPrintableIndex( c ) - FindPrintableIndex( prevc ) );
+
+ if ( diff > maxdiff )
+ {
+ maxdiff = diff;
+ }
+ }
+
+ float maxdelta = maxdiff;
+
+ if ( m_nRotaryMaxDelta != 0 )
+ {
+ maxdelta = MIN( (float)m_nRotaryMaxDelta, maxdelta );
+ }
+
+ return maxdelta;
+}
+
+int CHudNumeric::ComputePixelsRequired( vgui::HFont& font, const char *text, int textlen )
+{
+ int pixels = 0;
+ for ( int ch = 0; ch < textlen; ch++ )
+ {
+ char c = text[ ch ];
+ pixels += surface()->GetCharacterWidth( font, c );
+ }
+ return pixels;
+}
+
+void CHudNumeric::DrawCharacterBackground( const char *text, int textlen, HFont& font, int x, int y )
+{
+ int abcA, abcB, abcC;
+ int fontTall = surface()->GetFontTall( font );
+
+ int ch;
+ int curx = x - ComputePixelsRequired( font, text, textlen );
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ char c = text[ ch ];
+
+ surface()->GetCharABCwide( font, c, abcA, abcB, abcC );
+
+ curx += abcA;
+
+ surface()->DrawSetColor( m_CharBg );
+ surface()->DrawFilledRect( curx - abcA, y + 2, curx + abcB + abcC, y + fontTall - 2 );
+
+ if ( m_bDrawCharacterBackgroundBorder )
+ {
+ surface()->DrawSetColor( m_CharBgBorder );
+ surface()->DrawOutlinedRect( curx - abcA, y + 2, curx + abcB + abcC, y + fontTall - 2 );
+ }
+
+ curx += ( abcB + abcC );
+ }
+}
+
+void CHudNumeric::DrawCharacterForeground( const char *text, int textlen, HFont& font, int x, int y )
+{
+ if ( m_nRotaryEffect == ROTARY_EFFECT_NONE ||
+ m_nRotaryEffect == ROTARY_EFFECT_SPEEDOMETER )
+ return;
+
+ int abcA, abcB, abcC;
+ int fontTall = surface()->GetFontTall( font );
+
+ int ch;
+ int curx = x - ComputePixelsRequired( font, text, textlen );
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ char c = text[ ch ];
+
+ surface()->GetCharABCwide( font, c, abcA, abcB, abcC );
+
+ curx += abcA;
+
+ switch ( m_nRotaryEffect )
+ {
+ default:
+ case ROTARY_EFFECT_VERTICAL_ALARM:
+ {
+ surface()->DrawSetColor( m_CharFg );
+ surface()->DrawLine( curx - abcA + 1, y + fontTall / 2, curx + abcB + abcC - 1, y + fontTall / 2 );
+ }
+ break;
+ case ROTARY_EFFECT_HORIZONTAL_ALARM:
+ {
+ surface()->DrawSetColor( m_CharFg );
+ int avex = curx + ( - abcA + abcB + abcC ) / 2;
+ surface()->DrawLine( avex, y + 2, avex, y + fontTall - 2 );
+ }
+ break;
+ }
+
+ curx += ( abcB + abcC );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *text -
+// textlen -
+// font -
+// x -
+// y -
+//-----------------------------------------------------------------------------
+void CHudNumeric::PaintStringRotary( float t, const char *text, int textlen, HFont& font, int x, int y )
+{
+ surface()->DrawSetTextFont( font );
+ int ch;
+
+ int prevlen = Q_strlen( m_szLatchedValue );
+
+ // Compute pixels actually required
+ int pixels = 0;
+
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ int charfromend = textlen - ch;
+ char c = text[ ch ];
+ char prevc = m_szLatchedValue[ MAX( 0, prevlen - charfromend ) ];
+ if ( prevc == 0 )
+ {
+ int tempindex = FindPrintableIndex( c );
+ if ( tempindex != m_Printables.InvalidIndex() )
+ {
+ tempindex = MAX( 0, tempindex - 3 );
+ prevc = m_Printables[ tempindex ];
+ }
+ else
+ {
+ prevc = c;
+ }
+ }
+
+ float diff = (float)fabs( FindPrintableIndex( c ) - FindPrintableIndex( prevc ) );
+
+ if ( m_nRotaryMaxDelta != 0 )
+ {
+ diff = MIN( (float)m_nRotaryMaxDelta, diff );
+ }
+
+ float dt = diff / m_flActualCharactersPerSecond;
+
+ float frac = 1.0f;
+ if ( dt > 0.0f )
+ {
+ frac = t / MIN( dt, m_flRotaryTime );
+ }
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ float s;
+ char chstart, chend;
+ GetRotatedChar( frac, prevc, c, chstart, chend, s );
+
+ int w0 = surface()->GetCharacterWidth( font, chstart );
+ int w1 = surface()->GetCharacterWidth( font, chend );
+
+ pixels += MAX( w0, w1 );
+ }
+
+ surface()->DrawSetTextPos( x - pixels, y );
+
+ // Now render
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ int charfromend = textlen - ch;
+ char c = text[ ch ];
+ char prevc = m_szLatchedValue[ MAX( 0, prevlen - charfromend ) ];
+ if ( prevc == 0 )
+ {
+ int tempindex = FindPrintableIndex( c );
+ if ( tempindex != m_Printables.InvalidIndex() )
+ {
+ tempindex = MAX( 0, tempindex - 3 );
+ prevc = m_Printables[ tempindex ];
+ }
+ else
+ {
+ prevc = c;
+ }
+ }
+
+ float diff = (float)fabs( FindPrintableIndex( c ) - FindPrintableIndex( prevc ) );
+
+ if ( m_nRotaryMaxDelta != 0 )
+ {
+ diff = MIN( (float)m_nRotaryMaxDelta, diff );
+ }
+
+ float dt = diff / m_flActualCharactersPerSecond;
+
+ float frac = 1.0f;
+ if ( dt > 0.0f )
+ {
+ frac = t / MIN( dt, m_flRotaryTime );
+ }
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ float s;
+ char chstart, chend;
+ GetRotatedChar( frac, prevc, c, chstart, chend, s );
+ int outx, outy;
+ surface()->DrawGetTextPos( outx, outy );
+ switch ( m_nRotaryEffect )
+ {
+ default:
+ case ROTARY_EFFECT_VERTICAL_ALARM:
+ {
+ PaintRotatedCharacter( outx, outy, font, chstart, chend, s );
+ }
+ break;
+ case ROTARY_EFFECT_HORIZONTAL_ALARM:
+ {
+ PaintRotatedCharacterHoriz( outx, outy, font, chstart, chend, s );
+ }
+ break;
+ case ROTARY_EFFECT_SPEEDOMETER:
+ {
+ PaintRotatedCharacterSpeedomter( outx, outy, font, chstart, chend, s );
+ }
+ break;
+ }
+
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *text -
+// textlen -
+// font -
+// x -
+// y -
+//-----------------------------------------------------------------------------
+void CHudNumeric::PaintString( const char *text, int textlen, HFont& font, int x, int y )
+{
+ if ( m_nRotaryEffect != ROTARY_EFFECT_NONE &&
+ IsRotating() &&
+ m_flRotaryTime > 0.0f )
+ {
+ float rotation_time = gpGlobals->curtime - m_flRotaryStartTime;
+
+ PaintStringRotary( rotation_time, text, textlen, font, x, y );
+
+ return;
+ }
+ PaintStringNormal( text, textlen, font, x, y );
+}
+
+void CHudNumeric::PaintStringNormal( const char *text, int textlen, vgui::HFont& font, int x, int y )
+{
+ surface()->DrawSetTextFont( font );
+ int ch;
+ surface()->DrawSetTextPos( x - ComputePixelsRequired( font, text, textlen ), y );
+
+ for ( ch = 0; ch < textlen; ch++ )
+ {
+ char c = text[ ch ];
+ surface()->DrawUnicodeChar( c );
+ }
+}
+
+void CHudNumeric::PaintBackground( void )
+{
+ char value[ MAX_VALUE_LENGTH ];
+
+ if ( !GetValue( value, sizeof( value ) ) )
+ return;
+
+ float alpha = m_flAlphaOverride / 255.0f;
+
+ Color boxColor = GetBoxColor();
+ boxColor[3] *= alpha;
+
+ SetBgColor( boxColor );
+
+ BaseClass::PaintBackground();
+
+ if ( !m_bUseIcon )
+ return;
+
+ CHudTexture *tex = m_hIcon;
+ if ( !tex )
+ return;
+
+ Color iconColor = m_IconColor;
+ iconColor[3] *= alpha;
+
+ tex->DrawSelf( m_flIconXPos, m_flIconYPos, m_flIconWidth, m_flIconHeight, iconColor );
+}
+
+void CHudNumeric::PaintValue( const char *value, int textlen, int wide, int tall, Color& clr )
+{
+ float alpha = m_flAlphaOverride / 255.0f;
+
+ Color boxColor = GetBoxColor();
+ boxColor[3] *= alpha;
+
+ SetBgColor( boxColor );
+
+ Color useColor = clr;
+ useColor[3] *= alpha;
+
+ surface()->DrawSetTextColor( useColor );
+
+ int x = wide - label_xpos_right;
+ int y = label_ypos;
+
+ if ( m_bDrawLabel )
+ {
+ // Label
+ PaintStringNormal( GetLabelText(), Q_strlen( GetLabelText() ), m_hLabelFont, x, y );
+ }
+
+ x = wide - value_xpos_right;
+ y = value_ypos;
+
+ if ( m_nRotaryEffect != ROTARY_EFFECT_NONE &&
+ (bool)m_bDrawCharacterBackground )
+ {
+ DrawCharacterBackground( value, textlen, m_hTextFont, x, y );
+ }
+
+ PaintString( value, textlen, m_hTextFont, x, y );
+
+ if ( m_nRotaryEffect != ROTARY_EFFECT_NONE &&
+ (bool)m_bDrawCharacterForeground )
+ {
+ DrawCharacterForeground( value, textlen, m_hTextFont, x, y );
+ }
+
+ // draw the overbright blur
+ for (float fl = m_flBlur; fl > 0.0f; fl -= 1.0f)
+ {
+ if (fl >= 1.0f)
+ {
+ PaintString( value, textlen, m_hTextFontPulsing, x, y );
+ }
+ else
+ {
+ // draw a percentage of the last one
+ Color col = useColor;
+ col[3] *= fl;
+ surface()->DrawSetTextColor(col);
+ PaintString( value, textlen, m_hTextFontPulsing, x, y );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : vgui::Color
+//-----------------------------------------------------------------------------
+Color CHudNumeric::GetColor()
+{
+ return m_TextColor;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : vgui::Color
+//-----------------------------------------------------------------------------
+Color CHudNumeric::GetBoxColor()
+{
+ return m_BoxColor;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Redraw
+//-----------------------------------------------------------------------------
+void CHudNumeric::Paint( void )
+{
+ char value[ MAX_VALUE_LENGTH ];
+
+ if ( !GetValue( value, sizeof( value ) ) )
+ return;
+
+ int w, h;
+ GetSize( w, h );
+
+ bool dopulse = ( Q_strcmp( value, m_szPreviousValue ) != 0 ) || ( m_bPulseForced );
+ bool increment = false;
+ if ( dopulse )
+ {
+ if ( atof( m_szPreviousValue ) <= atof( value ) )
+ {
+ increment = true;
+ }
+
+ Q_strncpy( m_szLatchedValue, m_szPreviousValue, sizeof( m_szLatchedValue ) );
+ m_nTextLen = Q_strlen( value );
+
+ m_flRotaryStartTime = gpGlobals->curtime;
+ float maxdiff = MaxCharacterDiff( m_szLatchedValue, value );
+ float timerequired = maxdiff / m_flDesiredCharactersPerSecond;
+ m_flActualCharactersPerSecond = (float)m_flDesiredCharactersPerSecond;
+ m_flRotaryTime = MIN( m_flRotaryTimeMax, timerequired );
+ if ( m_flRotaryTime < timerequired )
+ {
+ // Speed up rotation since we're moving so far
+ m_flActualCharactersPerSecond = ( timerequired / m_flRotaryTime ) * m_flDesiredCharactersPerSecond;
+ }
+ }
+
+ Q_strncpy( m_szPreviousValue, value, sizeof( m_szPreviousValue ) );
+
+ Color clr = GetColor();
+ PaintValue( value, m_nTextLen, w, h, clr );
+
+ if ( dopulse && m_bSendPulses )
+ {
+ // Start with a short pulse
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( GetPulseEvent( increment ) );
+
+ m_bPulseForced = false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Derived class has forced a pulse
+//-----------------------------------------------------------------------------
+void CHudNumeric::ForcePulse( void )
+{
+ m_bPulseForced = true;
+}