📄 hud_numeric.cpp
字号:
#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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -