diff options
Diffstat (limited to 'game/client/tf2/hud_numeric.cpp')
| -rw-r--r-- | game/client/tf2/hud_numeric.cpp | 978 |
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; +} |