initial
This commit is contained in:
340
vgui2/vgui_surfacelib/BitmapFont.cpp
Normal file
340
vgui2/vgui_surfacelib/BitmapFont.cpp
Normal file
@@ -0,0 +1,340 @@
|
||||
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: XBox Compiled Bitmap Fonts
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
// conversion from 'double' to 'float', possible loss of data
|
||||
#pragma warning( disable : 4244 )
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#if !defined( _PS3 )
|
||||
#include <malloc.h>
|
||||
#endif // ! _PS3
|
||||
#include "vgui_surfacelib/BitmapFont.h"
|
||||
#include "vgui_surfacelib/fontmanager.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "vgui_surfacelib/ifontsurface.h"
|
||||
#include "tier0/mem.h"
|
||||
#include "utlbuffer.h"
|
||||
#include "filesystem.h"
|
||||
#include "materialsystem/itexture.h"
|
||||
#include "rendersystem/irenderdevice.h"
|
||||
#include "resourcesystem/stronghandle.h"
|
||||
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
struct BitmapFontTable_t
|
||||
{
|
||||
BitmapFontTable_t()
|
||||
{
|
||||
m_szName = UTL_INVAL_SYMBOL;
|
||||
m_pBitmapFont = NULL;
|
||||
m_pBitmapGlyphs = NULL;
|
||||
m_pTexture = NULL;
|
||||
}
|
||||
|
||||
CUtlSymbol m_szName;
|
||||
BitmapFont_t *m_pBitmapFont;
|
||||
BitmapGlyph_t *m_pBitmapGlyphs;
|
||||
ITexture *m_pTexture;
|
||||
HRenderTextureStrong m_pTexture2;
|
||||
};
|
||||
|
||||
static CUtlVector< BitmapFontTable_t > g_BitmapFontTable( 1, 4 );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CBitmapFont::CBitmapFont()
|
||||
{
|
||||
m_scalex = 1.0f;
|
||||
m_scaley = 1.0f;
|
||||
|
||||
m_bitmapFontHandle = g_BitmapFontTable.InvalidIndex();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CBitmapFont::~CBitmapFont()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: creates the font. returns false if the font cannot be mounted.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBitmapFont::Create( const char *pFontFilename, float scalex, float scaley, int flags )
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
|
||||
if ( !pFontFilename || !pFontFilename[0] )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CUtlSymbol symbol;
|
||||
char fontName[MAX_PATH];
|
||||
Q_FileBase( pFontFilename, fontName, MAX_PATH );
|
||||
Q_strlower( fontName );
|
||||
symbol = fontName;
|
||||
|
||||
// find a match that can use same entries
|
||||
BitmapFontTable_t *pFontTable = NULL;
|
||||
for ( int i=0; i<g_BitmapFontTable.Count(); i++ )
|
||||
{
|
||||
if ( symbol == g_BitmapFontTable[i].m_szName )
|
||||
{
|
||||
m_bitmapFontHandle = i;
|
||||
pFontTable = &g_BitmapFontTable[m_bitmapFontHandle];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !pFontTable )
|
||||
{
|
||||
void *pBuf = NULL;
|
||||
int nLength;
|
||||
|
||||
nLength = FontManager().FileSystem()->ReadFileEx( pFontFilename, "GAME", &pBuf );
|
||||
if ( nLength <= 0 || !pBuf )
|
||||
{
|
||||
// not found
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ((BitmapFont_t*)pBuf)->m_id != LittleLong( BITMAPFONT_ID ) || ((BitmapFont_t*)pBuf)->m_Version != LittleLong( BITMAPFONT_VERSION ) )
|
||||
{
|
||||
// bad version
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( IsGameConsole() )
|
||||
{
|
||||
CByteswap swap;
|
||||
swap.ActivateByteSwapping( true );
|
||||
swap.SwapFieldsToTargetEndian( (BitmapFont_t*)pBuf );
|
||||
swap.SwapFieldsToTargetEndian( (BitmapGlyph_t*)((char*)pBuf + sizeof( BitmapFont_t )), ((BitmapFont_t*)pBuf)->m_NumGlyphs );
|
||||
}
|
||||
|
||||
// create it
|
||||
m_bitmapFontHandle = g_BitmapFontTable.AddToTail();
|
||||
pFontTable = &g_BitmapFontTable[m_bitmapFontHandle];
|
||||
|
||||
pFontTable->m_szName = fontName;
|
||||
|
||||
pFontTable->m_pBitmapFont = new BitmapFont_t;
|
||||
memcpy( pFontTable->m_pBitmapFont, pBuf, sizeof( BitmapFont_t ) );
|
||||
|
||||
pFontTable->m_pBitmapGlyphs = new BitmapGlyph_t[pFontTable->m_pBitmapFont->m_NumGlyphs];
|
||||
memcpy( pFontTable->m_pBitmapGlyphs, (unsigned char*)pBuf + sizeof(BitmapFont_t), pFontTable->m_pBitmapFont->m_NumGlyphs*sizeof(BitmapGlyph_t) );
|
||||
|
||||
FontManager().FileSystem()->FreeOptimalReadBuffer( pBuf );
|
||||
|
||||
// load the art resources
|
||||
char textureName[MAX_PATH];
|
||||
Q_snprintf( textureName, MAX_PATH, "vgui/fonts/%s", fontName );
|
||||
if ( g_pMaterialSystem )
|
||||
{
|
||||
pFontTable->m_pTexture = FontManager().MaterialSystem()->FindTexture( textureName, TEXTURE_GROUP_VGUI );
|
||||
|
||||
#if defined( DEVELOPMENT_ONLY ) || defined( ALLOW_TEXT_MODE )
|
||||
static bool s_bTextMode = CommandLine()->HasParm( "-textmode" );
|
||||
#else
|
||||
const bool s_bTextMode = false;
|
||||
#endif
|
||||
|
||||
#if defined( _DEBUG ) && !defined( POSIX )
|
||||
if ( ( pFontTable->m_pBitmapFont->m_PageWidth != pFontTable->m_pTexture->GetActualWidth() ||
|
||||
pFontTable->m_pBitmapFont->m_PageHeight != pFontTable->m_pTexture->GetActualHeight() ) && !s_bTextMode )
|
||||
{
|
||||
// font is out of sync with its art
|
||||
Assert( 0 );
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// the font texture lives forever, ensure it doesn't get purged
|
||||
pFontTable->m_pTexture->IncrementReferenceCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert(0); // TODO add support for materialsystem2
|
||||
}
|
||||
}
|
||||
|
||||
// setup font properties
|
||||
m_scalex = scalex;
|
||||
m_scaley = scaley;
|
||||
|
||||
// flags are derived from the baked font
|
||||
m_iFlags = FONTFLAG_BITMAP;
|
||||
int bitmapFlags = pFontTable->m_pBitmapFont->m_Flags;
|
||||
|
||||
if ( bitmapFlags & BF_ANTIALIASED )
|
||||
{
|
||||
m_iFlags |= FONTFLAG_ANTIALIAS;
|
||||
}
|
||||
|
||||
if ( bitmapFlags & BF_ITALIC )
|
||||
{
|
||||
m_iFlags |= FONTFLAG_ITALIC;
|
||||
}
|
||||
|
||||
if ( bitmapFlags & BF_BLURRED )
|
||||
{
|
||||
m_iFlags |= FONTFLAG_GAUSSIANBLUR;
|
||||
m_iBlur = 1;
|
||||
}
|
||||
|
||||
if ( bitmapFlags & BF_SCANLINES )
|
||||
{
|
||||
m_iScanLines = 1;
|
||||
}
|
||||
|
||||
if ( bitmapFlags & BF_OUTLINED )
|
||||
{
|
||||
m_iFlags |= FONTFLAG_OUTLINE;
|
||||
m_iOutlineSize = 1;
|
||||
}
|
||||
|
||||
if ( bitmapFlags & BF_DROPSHADOW )
|
||||
{
|
||||
m_iFlags |= FONTFLAG_DROPSHADOW;
|
||||
m_iDropShadowOffset = 1;
|
||||
}
|
||||
|
||||
if ( flags & FONTFLAG_ADDITIVE )
|
||||
{
|
||||
m_bAdditive = true;
|
||||
m_iFlags |= FONTFLAG_ADDITIVE;
|
||||
}
|
||||
|
||||
m_iMaxCharWidth = (float)pFontTable->m_pBitmapFont->m_MaxCharWidth * m_scalex;
|
||||
m_iHeight = (float)pFontTable->m_pBitmapFont->m_MaxCharHeight * m_scaley;
|
||||
m_iAscent = (float)pFontTable->m_pBitmapFont->m_Ascent * m_scaley;
|
||||
|
||||
// mark as valid
|
||||
m_szName = fontName;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true if the font is equivalent to that specified
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBitmapFont::IsEqualTo( const char *windowsFontName, float scalex, float scaley, int flags )
|
||||
{
|
||||
char fontname[MAX_PATH];
|
||||
Q_FileBase( windowsFontName, fontname, MAX_PATH );
|
||||
|
||||
if ( !Q_stricmp( fontname, m_szName.String() ) &&
|
||||
m_scalex == scalex &&
|
||||
m_scaley == scaley )
|
||||
{
|
||||
int commonFlags = m_iFlags & flags;
|
||||
if ( commonFlags & FONTFLAG_ADDITIVE )
|
||||
{
|
||||
// an exact match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets the scale for a font
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBitmapFont::SetScale( float sx, float sy )
|
||||
{
|
||||
m_scalex = sx;
|
||||
m_scaley = sy;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the abc widths for a character
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBitmapFont::GetCharABCWidths( int ch, int &a, int &b, int &c )
|
||||
{
|
||||
Assert( IsValid() && ch >= 0 && ch <= 255 );
|
||||
|
||||
BitmapFontTable_t *pFont = &g_BitmapFontTable[m_bitmapFontHandle];
|
||||
|
||||
ch = pFont->m_pBitmapFont->m_TranslateTable[ch];
|
||||
a = (float)pFont->m_pBitmapGlyphs[ch].a * m_scalex;
|
||||
b = (float)pFont->m_pBitmapGlyphs[ch].b * m_scalex;
|
||||
c = (float)pFont->m_pBitmapGlyphs[ch].c * m_scalex;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the abc widths for a character
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBitmapFont::GetKernedCharWidth( wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA, float &abcC )
|
||||
{
|
||||
int a, b, c;
|
||||
GetCharABCWidths( ch, a, b, c );
|
||||
wide = a+b+c;
|
||||
abcA = a;
|
||||
abcC = c;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the texcoords for a character
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBitmapFont::GetCharCoords( int ch, float *left, float *top, float *right, float *bottom )
|
||||
{
|
||||
Assert( IsValid() && ch >= 0 && ch <= 255 );
|
||||
|
||||
BitmapFontTable_t *pFont = &g_BitmapFontTable[m_bitmapFontHandle];
|
||||
|
||||
ch = pFont->m_pBitmapFont->m_TranslateTable[ch];
|
||||
*left = (float)pFont->m_pBitmapGlyphs[ch].x/(float)pFont->m_pBitmapFont->m_PageWidth;
|
||||
*top = (float)pFont->m_pBitmapGlyphs[ch].y/(float)pFont->m_pBitmapFont->m_PageHeight;
|
||||
*right = (float)(pFont->m_pBitmapGlyphs[ch].x+pFont->m_pBitmapGlyphs[ch].w)/(float)pFont->m_pBitmapFont->m_PageWidth;
|
||||
*bottom = (float)(pFont->m_pBitmapGlyphs[ch].y+pFont->m_pBitmapGlyphs[ch].h)/(float)pFont->m_pBitmapFont->m_PageHeight;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the texture page
|
||||
//-----------------------------------------------------------------------------
|
||||
ITexture *CBitmapFont::GetTexturePage()
|
||||
{
|
||||
if ( g_pMaterialSystem )
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return g_BitmapFontTable[m_bitmapFontHandle].m_pTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_BYTESWAP_DATADESC( BitmapGlyph_t )
|
||||
DEFINE_FIELD( x, FIELD_SHORT ),
|
||||
DEFINE_FIELD( y, FIELD_SHORT ),
|
||||
DEFINE_FIELD( w, FIELD_SHORT ),
|
||||
DEFINE_FIELD( h, FIELD_SHORT ),
|
||||
DEFINE_FIELD( a, FIELD_SHORT ),
|
||||
DEFINE_FIELD( b, FIELD_SHORT ),
|
||||
DEFINE_FIELD( c, FIELD_SHORT ),
|
||||
END_BYTESWAP_DATADESC()
|
||||
|
||||
BEGIN_BYTESWAP_DATADESC( BitmapFont_t )
|
||||
DEFINE_FIELD( m_id, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_Version, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_PageWidth, FIELD_SHORT ),
|
||||
DEFINE_FIELD( m_PageHeight, FIELD_SHORT ),
|
||||
DEFINE_FIELD( m_MaxCharWidth, FIELD_SHORT ),
|
||||
DEFINE_FIELD( m_MaxCharHeight, FIELD_SHORT ),
|
||||
DEFINE_FIELD( m_Flags, FIELD_SHORT ),
|
||||
DEFINE_FIELD( m_Ascent, FIELD_SHORT ),
|
||||
DEFINE_FIELD( m_NumGlyphs, FIELD_SHORT ),
|
||||
DEFINE_ARRAY( m_TranslateTable, FIELD_CHARACTER, 256 ),
|
||||
END_BYTESWAP_DATADESC()
|
||||
183
vgui2/vgui_surfacelib/FontAmalgam.cpp
Normal file
183
vgui2/vgui_surfacelib/FontAmalgam.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "vgui_surfacelib/FontAmalgam.h"
|
||||
#include "vgui_surfacelib/ifontsurface.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFontAmalgam::CFontAmalgam()
|
||||
{
|
||||
m_Fonts.EnsureCapacity( 4 );
|
||||
m_iMaxHeight = 0;
|
||||
m_iMaxWidth = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFontAmalgam::~CFontAmalgam()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: adds a font to the amalgam
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontAmalgam::AddFont(font_t *pFont, int lowRange, int highRange)
|
||||
{
|
||||
int i = m_Fonts.AddToTail();
|
||||
|
||||
m_Fonts[i].pWin32Font = pFont;
|
||||
m_Fonts[i].lowRange = lowRange;
|
||||
m_Fonts[i].highRange = highRange;
|
||||
|
||||
m_iMaxHeight = MAX(pFont->GetHeight(), m_iMaxHeight);
|
||||
m_iMaxWidth = MAX(pFont->GetMaxCharWidth(), m_iMaxWidth);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: clears the fonts
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontAmalgam::RemoveAll()
|
||||
{
|
||||
// clear out
|
||||
m_Fonts.RemoveAll();
|
||||
m_iMaxHeight = 0;
|
||||
m_iMaxWidth = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the font for the given character
|
||||
//-----------------------------------------------------------------------------
|
||||
font_t *CFontAmalgam::GetFontForChar(int ch)
|
||||
{
|
||||
for (int i = 0; i < m_Fonts.Count(); i++)
|
||||
{
|
||||
if ( ch >= m_Fonts[i].lowRange && ch <= m_Fonts[i].highRange )
|
||||
{
|
||||
Assert( m_Fonts[i].pWin32Font->IsValid() );
|
||||
return m_Fonts[i].pWin32Font;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets the scale of the font
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontAmalgam::SetFontScale(float sx, float sy)
|
||||
{
|
||||
if (!m_Fonts.Count())
|
||||
return;
|
||||
|
||||
// Make sure this is a bitmap font!
|
||||
if ( GetFlags( 0 ) & FONTFLAG_BITMAP )
|
||||
{
|
||||
reinterpret_cast< CBitmapFont* >( m_Fonts[0].pWin32Font )->SetScale( sx, sy );
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning( "%s: Can't set font scale on a non-bitmap font!\n", m_Fonts[0].pWin32Font->GetName() );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the max height of the font set
|
||||
//-----------------------------------------------------------------------------
|
||||
int CFontAmalgam::GetFontHeight()
|
||||
{
|
||||
if (!m_Fonts.Count())
|
||||
{
|
||||
return m_iMaxHeight;
|
||||
}
|
||||
return m_Fonts[0].pWin32Font->GetHeight();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the maximum width of a character in a font
|
||||
//-----------------------------------------------------------------------------
|
||||
int CFontAmalgam::GetFontMaxWidth()
|
||||
{
|
||||
return m_iMaxWidth;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the name of the font that is loaded
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CFontAmalgam::GetFontName( int i )
|
||||
{
|
||||
if ( m_Fonts.Count() && m_Fonts[i].pWin32Font && m_Fonts[i].pWin32Font->IsValid() )
|
||||
{
|
||||
return m_Fonts[i].pWin32Font->GetName();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the name of the font that is loaded
|
||||
//-----------------------------------------------------------------------------
|
||||
int CFontAmalgam::GetFlags(int i)
|
||||
{
|
||||
if ( m_Fonts.Count() && m_Fonts[i].pWin32Font )
|
||||
{
|
||||
return m_Fonts[i].pWin32Font->GetFlags();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the number of fonts this amalgam contains
|
||||
//-----------------------------------------------------------------------------
|
||||
int CFontAmalgam::GetCount()
|
||||
{
|
||||
return m_Fonts.Count();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the max height of the font set
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontAmalgam::GetUnderlined()
|
||||
{
|
||||
if (!m_Fonts.Count())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return m_Fonts[0].pWin32Font->GetUnderlined();
|
||||
}
|
||||
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Ensure that all of our internal structures are consistent, and
|
||||
// account for all memory that we've allocated.
|
||||
// Input: validator - Our global validator object
|
||||
// pchName - Our name (typically a member var in our container)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontAmalgam::Validate( CValidator &validator, char *pchName )
|
||||
{
|
||||
validator.Push( "CFontAmalgam", this, pchName );
|
||||
|
||||
ValidateObj( m_Fonts );
|
||||
|
||||
validator.Pop();
|
||||
}
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
213
vgui2/vgui_surfacelib/FontEffects.cpp
Normal file
213
vgui2/vgui_surfacelib/FontEffects.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Font effects that operate on linear rgba data
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#include "tier0/platform.h"
|
||||
#include <tier0/dbg.h>
|
||||
#include <math.h>
|
||||
#include "FontEffects.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Adds center line to font
|
||||
//-----------------------------------------------------------------------------
|
||||
void ApplyRotaryEffectToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, bool bRotary )
|
||||
{
|
||||
if ( !bRotary )
|
||||
return;
|
||||
|
||||
int y = rgbaTall * 0.5;
|
||||
|
||||
unsigned char *line = &rgba[(y * rgbaWide) * 4];
|
||||
|
||||
// Draw a line down middle
|
||||
for (int x = 0; x < rgbaWide; x++, line+=4)
|
||||
{
|
||||
line[0] = 127;
|
||||
line[1] = 127;
|
||||
line[2] = 127;
|
||||
line[3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: adds scanlines to the texture
|
||||
//-----------------------------------------------------------------------------
|
||||
void ApplyScanlineEffectToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, int iScanLines )
|
||||
{
|
||||
if ( iScanLines < 2 )
|
||||
return;
|
||||
|
||||
float scale;
|
||||
scale = 0.7f;
|
||||
|
||||
// darken all the areas except the scanlines
|
||||
for (int y = 0; y < rgbaTall; y++)
|
||||
{
|
||||
// skip the scan lines
|
||||
if (y % iScanLines == 0)
|
||||
continue;
|
||||
|
||||
unsigned char *pBits = &rgba[(y * rgbaWide) * 4];
|
||||
|
||||
// darken the other lines
|
||||
for (int x = 0; x < rgbaWide; x++, pBits += 4)
|
||||
{
|
||||
pBits[0] *= scale;
|
||||
pBits[1] *= scale;
|
||||
pBits[2] *= scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: adds a dropshadow the the font texture
|
||||
//-----------------------------------------------------------------------------
|
||||
void ApplyDropShadowToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, int iDropShadowOffset )
|
||||
{
|
||||
if ( !iDropShadowOffset )
|
||||
return;
|
||||
|
||||
// walk the original image from the bottom up
|
||||
// shifting it down and right, and turning it black (the dropshadow)
|
||||
for (int y = rgbaTall - 1; y >= iDropShadowOffset; y--)
|
||||
{
|
||||
for (int x = rgbaWide - 1; x >= iDropShadowOffset; x--)
|
||||
{
|
||||
unsigned char *dest = &rgba[(x + (y * rgbaWide)) * 4];
|
||||
if (dest[3] == 0)
|
||||
{
|
||||
// there is nothing in this spot, copy in the dropshadow
|
||||
unsigned char *src = &rgba[(x - iDropShadowOffset + ((y - iDropShadowOffset) * rgbaWide)) * 4];
|
||||
dest[0] = 0;
|
||||
dest[1] = 0;
|
||||
dest[2] = 0;
|
||||
dest[3] = src[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: adds an outline to the font texture
|
||||
//-----------------------------------------------------------------------------
|
||||
void ApplyOutlineToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, int iOutlineSize )
|
||||
{
|
||||
if ( !iOutlineSize )
|
||||
return;
|
||||
|
||||
int x, y;
|
||||
for( y = 0; y < rgbaTall; y++ )
|
||||
{
|
||||
for( x = 0; x < rgbaWide; x++ )
|
||||
{
|
||||
unsigned char *src = &rgba[(x + (y * rgbaWide)) * 4];
|
||||
if( src[3] == 0 )
|
||||
{
|
||||
// We have a valid font texel. Make all the alpha == 0 neighbors black.
|
||||
int shadowX, shadowY;
|
||||
for( shadowX = -(int)iOutlineSize; shadowX <= (int)iOutlineSize; shadowX++ )
|
||||
{
|
||||
for( shadowY = -(int)iOutlineSize; shadowY <= (int)iOutlineSize; shadowY++ )
|
||||
{
|
||||
if( shadowX == 0 && shadowY == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int testX, testY;
|
||||
testX = shadowX + x;
|
||||
testY = shadowY + y;
|
||||
if( testX < 0 || testX >= rgbaWide ||
|
||||
testY < 0 || testY >= rgbaTall )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
unsigned char *test = &rgba[(testX + (testY * rgbaWide)) * 4];
|
||||
if( test[0] != 0 && test[1] != 0 && test[2] != 0 && test[3] != 0 )
|
||||
{
|
||||
src[0] = 0;
|
||||
src[1] = 0;
|
||||
src[2] = 0;
|
||||
src[3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets the blur value for a single pixel
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE void GetBlurValueForPixel(unsigned char *src, int blur, float *gaussianDistribution, int srcX, int srcY, int rgbaWide, int rgbaTall, unsigned char *dest)
|
||||
{
|
||||
float accum = 0.0f;
|
||||
|
||||
// scan the positive x direction
|
||||
int maxX = MIN(srcX + blur, rgbaWide - 1);
|
||||
int minX = MAX(srcX - blur, 0);
|
||||
for (int x = minX; x <= maxX; x++)
|
||||
{
|
||||
int maxY = MIN(srcY + blur, rgbaTall - 1);
|
||||
int minY = MAX(srcY - blur, 0);
|
||||
for (int y = minY; y <= maxY; y++)
|
||||
{
|
||||
unsigned char *srcPos = src + ((x + (y * rgbaWide)) * 4);
|
||||
|
||||
// muliply by the value matrix
|
||||
float weight = gaussianDistribution[x - srcX + blur];
|
||||
float weight2 = gaussianDistribution[y - srcY + blur];
|
||||
accum += (srcPos[0] * (weight * weight2));
|
||||
}
|
||||
}
|
||||
|
||||
dest[0] = dest[1] = dest[2] = 255; //leave ALL pixels white or we get black backgrounds mixed in
|
||||
dest[3] = MIN( (int)accum, 255); //blur occurs entirely in the alpha
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: blurs the texture
|
||||
//-----------------------------------------------------------------------------
|
||||
void ApplyGaussianBlurToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, int iBlur )
|
||||
{
|
||||
float *pGaussianDistribution;
|
||||
|
||||
if ( !iBlur )
|
||||
return;
|
||||
|
||||
// generate the gaussian field
|
||||
pGaussianDistribution = (float*) stackalloc( (iBlur*2+1) * sizeof(float) );
|
||||
double sigma = 0.683 * iBlur;
|
||||
for (int x = 0; x <= (iBlur * 2); x++)
|
||||
{
|
||||
int val = x - iBlur;
|
||||
pGaussianDistribution[x] = (float)( 1.0f / sqrt(2 * 3.14 * sigma * sigma)) * pow(2.7, -1 * (val * val) / (2 * sigma * sigma));
|
||||
}
|
||||
|
||||
// alloc a new buffer
|
||||
unsigned char *src = (unsigned char *) stackalloc( rgbaWide * rgbaTall * 4);
|
||||
|
||||
// copy in
|
||||
memcpy(src, rgba, rgbaWide * rgbaTall * 4);
|
||||
|
||||
// incrementing destination pointer
|
||||
unsigned char *dest = rgba;
|
||||
for (int y = 0; y < rgbaTall; y++)
|
||||
{
|
||||
for (int x = 0; x < rgbaWide; x++)
|
||||
{
|
||||
// scan the source pixel
|
||||
GetBlurValueForPixel(src, iBlur, pGaussianDistribution, x, y, rgbaWide, rgbaTall, dest);
|
||||
|
||||
// move to the next
|
||||
dest += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
vgui2/vgui_surfacelib/FontEffects.h
Normal file
20
vgui2/vgui_surfacelib/FontEffects.h
Normal file
@@ -0,0 +1,20 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Font effects that operate on linear rgba data
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#ifndef _FONTEFFECTS_H
|
||||
#define _FONTEFFECTS_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
void ApplyScanlineEffectToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, int iScanLines );
|
||||
void ApplyGaussianBlurToTexture(int rgbaWide, int rgbaTall, unsigned char *rgba, int iBlur );
|
||||
void ApplyDropShadowToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, int iDropShadowOffset );
|
||||
void ApplyOutlineToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, int iOutlineSize );
|
||||
void ApplyRotaryEffectToTexture( int rgbaWide, int rgbaTall, unsigned char *rgba, bool bRotary );
|
||||
|
||||
#endif
|
||||
583
vgui2/vgui_surfacelib/Win32Font.cpp
Normal file
583
vgui2/vgui_surfacelib/Win32Font.cpp
Normal file
@@ -0,0 +1,583 @@
|
||||
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#pragma warning( disable : 4244 ) // conversion from 'double' to 'float', possible loss of data
|
||||
|
||||
#define SUPPORT_CUSTOM_FONT_FORMAT
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#if !defined( _PS3 )
|
||||
#include <malloc.h>
|
||||
#endif // ! _PS3
|
||||
#include "vgui_surfacelib/Win32Font.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "vgui_surfacelib/IFontSurface.h"
|
||||
#include "tier0/mem.h"
|
||||
#include "utlbuffer.h"
|
||||
#include "FontEffects.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
static OSVERSIONINFO s_OsVersionInfo;
|
||||
static bool s_bOsVersionInitialized = false;
|
||||
bool s_bSupportsUnicode = false;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CWin32Font::CWin32Font() : m_ExtendedABCWidthsCache(256, 0, &ExtendedABCWidthsCacheLessFunc)
|
||||
{
|
||||
m_szName = UTL_INVAL_SYMBOL;
|
||||
m_iTall = 0;
|
||||
m_iWeight = 0;
|
||||
m_iHeight = 0;
|
||||
m_iAscent = 0;
|
||||
m_iFlags = 0;
|
||||
m_iMaxCharWidth = 0;
|
||||
m_hFont = NULL;
|
||||
m_hDC = NULL;
|
||||
m_hDIB = NULL;
|
||||
m_bAntiAliased = false;
|
||||
m_bUnderlined = false;
|
||||
m_iBlur = 0;
|
||||
m_iScanLines = 0;
|
||||
m_bRotary = false;
|
||||
m_bAdditive = false;
|
||||
m_rgiBitmapSize[ 0 ] = m_rgiBitmapSize[ 1 ] = 0;
|
||||
|
||||
m_ExtendedABCWidthsCache.EnsureCapacity( 128 );
|
||||
|
||||
if ( !s_bOsVersionInitialized )
|
||||
{
|
||||
// get the operating system version
|
||||
s_bOsVersionInitialized = true;
|
||||
memset(&s_OsVersionInfo, 0, sizeof(s_OsVersionInfo));
|
||||
s_OsVersionInfo.dwOSVersionInfoSize = sizeof(s_OsVersionInfo);
|
||||
GetVersionEx(&s_OsVersionInfo);
|
||||
|
||||
if (s_OsVersionInfo.dwMajorVersion >= 5)
|
||||
{
|
||||
s_bSupportsUnicode = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_bSupportsUnicode = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CWin32Font::~CWin32Font()
|
||||
{
|
||||
if ( m_hFont )
|
||||
::DeleteObject( m_hFont );
|
||||
if ( m_hDC )
|
||||
::DeleteDC( m_hDC );
|
||||
if ( m_hDIB )
|
||||
::DeleteObject( m_hDIB );
|
||||
}
|
||||
|
||||
#ifndef SUPPORT_CUSTOM_FONT_FORMAT
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Font iteration callback function
|
||||
// used to determine whether or not a font exists on the system
|
||||
//-----------------------------------------------------------------------------
|
||||
extern bool g_bFontFound = false;
|
||||
int CALLBACK FontEnumProc(
|
||||
const LOGFONT *lpelfe, // logical-font data
|
||||
const TEXTMETRIC *lpntme, // physical-font data
|
||||
DWORD FontType, // type of font
|
||||
LPARAM lParam ) // application-defined data
|
||||
{
|
||||
g_bFontFound = true;
|
||||
return 0;
|
||||
}
|
||||
#endif // SUPPORT_CUSTOM_FONT_FORMAT
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: creates the font from windows. returns false if font does not exist in the OS.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWin32Font::Create(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
// setup font properties
|
||||
m_szName = windowsFontName;
|
||||
m_iTall = tall;
|
||||
m_iWeight = weight;
|
||||
m_iFlags = flags;
|
||||
m_bAntiAliased = (flags & FONTFLAG_ANTIALIAS) ? 1 : 0;
|
||||
m_bUnderlined = (flags & FONTFLAG_UNDERLINE) ? 1 : 0;
|
||||
m_iDropShadowOffset = (flags & FONTFLAG_DROPSHADOW) ? 1 : 0;
|
||||
m_iOutlineSize = (flags & FONTFLAG_OUTLINE) ? 1 : 0;
|
||||
m_iBlur = blur;
|
||||
m_iScanLines = scanlines;
|
||||
m_bRotary = (flags & FONTFLAG_ROTARY) ? 1 : 0;
|
||||
m_bAdditive = (flags & FONTFLAG_ADDITIVE) ? 1 : 0;
|
||||
|
||||
int charset = (flags & FONTFLAG_SYMBOL) ? SYMBOL_CHARSET : ANSI_CHARSET;
|
||||
|
||||
// hack for japanese win98 support
|
||||
if ( !stricmp( windowsFontName, "win98japanese" ) )
|
||||
{
|
||||
// use any font that contains the japanese charset
|
||||
charset = SHIFTJIS_CHARSET;
|
||||
m_szName = "Tahoma";
|
||||
}
|
||||
|
||||
// create our windows device context
|
||||
m_hDC = ::CreateCompatibleDC(NULL);
|
||||
Assert( m_hDC );
|
||||
|
||||
#ifndef SUPPORT_CUSTOM_FONT_FORMAT
|
||||
// Vitaliy: fonts registered using custom font format are
|
||||
// not enumerated. Font creation will fail below for a font that
|
||||
// cannot be instantiated.
|
||||
{
|
||||
// see if the font exists on the system
|
||||
LOGFONT logfont;
|
||||
logfont.lfCharSet = DEFAULT_CHARSET;
|
||||
logfont.lfPitchAndFamily = 0;
|
||||
strcpy(logfont.lfFaceName, m_szName.String());
|
||||
g_bFontFound = false;
|
||||
::EnumFontFamiliesEx(m_hDC, &logfont, &FontEnumProc, 0, 0);
|
||||
if (!g_bFontFound)
|
||||
{
|
||||
// needs to go to a fallback
|
||||
m_szName = UTL_INVAL_SYMBOL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_hFont = ::CreateFontA(tall, 0, 0, 0,
|
||||
m_iWeight,
|
||||
flags & FONTFLAG_ITALIC,
|
||||
flags & FONTFLAG_UNDERLINE,
|
||||
flags & FONTFLAG_STRIKEOUT,
|
||||
charset,
|
||||
OUT_DEFAULT_PRECIS,
|
||||
CLIP_DEFAULT_PRECIS,
|
||||
m_bAntiAliased ? ANTIALIASED_QUALITY : NONANTIALIASED_QUALITY,
|
||||
DEFAULT_PITCH | FF_DONTCARE,
|
||||
windowsFontName);
|
||||
if (!m_hFont)
|
||||
{
|
||||
Error("Couldn't create windows font '%s'\n", windowsFontName);
|
||||
m_szName = UTL_INVAL_SYMBOL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// set as the active font
|
||||
::SetMapMode(m_hDC, MM_TEXT);
|
||||
::SelectObject(m_hDC, m_hFont);
|
||||
::SetTextAlign(m_hDC, TA_LEFT | TA_TOP | TA_UPDATECP);
|
||||
|
||||
// get info about the font
|
||||
::TEXTMETRIC tm;
|
||||
memset( &tm, 0, sizeof( tm ) );
|
||||
if ( !GetTextMetrics(m_hDC, &tm) )
|
||||
{
|
||||
m_szName = UTL_INVAL_SYMBOL;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_iHeight = tm.tmHeight + m_iDropShadowOffset + 2 * m_iOutlineSize;
|
||||
m_iMaxCharWidth = tm.tmMaxCharWidth;
|
||||
m_iAscent = tm.tmAscent;
|
||||
|
||||
// code for rendering to a bitmap
|
||||
m_rgiBitmapSize[0] = tm.tmMaxCharWidth + m_iOutlineSize * 2;
|
||||
m_rgiBitmapSize[1] = tm.tmHeight + m_iDropShadowOffset + m_iOutlineSize * 2;
|
||||
|
||||
::BITMAPINFOHEADER header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.biSize = sizeof(header);
|
||||
header.biWidth = m_rgiBitmapSize[0];
|
||||
header.biHeight = -m_rgiBitmapSize[1];
|
||||
header.biPlanes = 1;
|
||||
header.biBitCount = 32;
|
||||
header.biCompression = BI_RGB;
|
||||
|
||||
m_hDIB = ::CreateDIBSection(m_hDC, (BITMAPINFO*)&header, DIB_RGB_COLORS, (void**)(&m_pBuf), NULL, 0);
|
||||
::SelectObject(m_hDC, m_hDIB);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: writes the char into the specified 32bpp texture
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWin32Font::GetCharRGBA(wchar_t ch, int rgbaWide, int rgbaTall, unsigned char *rgba)
|
||||
{
|
||||
int a, b, c;
|
||||
GetCharABCWidths(ch, a, b, c);
|
||||
|
||||
// set us up to render into our dib
|
||||
::SelectObject(m_hDC, m_hFont);
|
||||
|
||||
int wide = b;
|
||||
if ( m_bUnderlined )
|
||||
{
|
||||
wide += ( a + c );
|
||||
}
|
||||
|
||||
int tall = m_iHeight;
|
||||
GLYPHMETRICS glyphMetrics;
|
||||
MAT2 mat2 = { { 0, 1}, { 0, 0}, { 0, 0}, { 0, 1}};
|
||||
int bytesNeeded = 0;
|
||||
|
||||
bool bShouldAntialias = m_bAntiAliased;
|
||||
// filter out
|
||||
if ( ch > 0x00FF && !(m_iFlags & FONTFLAG_CUSTOM) )
|
||||
{
|
||||
bShouldAntialias = false;
|
||||
}
|
||||
if ( !s_bSupportsUnicode )
|
||||
{
|
||||
// win98 hack, don't antialias some characters that ::GetGlyphOutline() produces bad results for
|
||||
if (ch == 'I' || ch == '1')
|
||||
{
|
||||
bShouldAntialias = false;
|
||||
}
|
||||
|
||||
// don't antialias big fonts at all (since win98 often produces bad results)
|
||||
if (m_iHeight >= 13)
|
||||
{
|
||||
bShouldAntialias = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// only antialias latin characters, since it essentially always fails for asian characters
|
||||
if (bShouldAntialias)
|
||||
{
|
||||
// try and get the glyph directly
|
||||
::SelectObject(m_hDC, m_hFont);
|
||||
bytesNeeded = ::GetGlyphOutline(m_hDC, ch, GGO_GRAY8_BITMAP, &glyphMetrics, 0, NULL, &mat2);
|
||||
}
|
||||
|
||||
if (bytesNeeded > 0)
|
||||
{
|
||||
// take it
|
||||
unsigned char *lpbuf = (unsigned char *)_alloca(bytesNeeded);
|
||||
::GetGlyphOutline(m_hDC, ch, GGO_GRAY8_BITMAP, &glyphMetrics, bytesNeeded, lpbuf, &mat2);
|
||||
|
||||
// rows are on DWORD boundaries
|
||||
wide = glyphMetrics.gmBlackBoxX;
|
||||
while (wide % 4 != 0)
|
||||
{
|
||||
wide++;
|
||||
}
|
||||
|
||||
// see where we should start rendering
|
||||
int pushDown = m_iAscent - glyphMetrics.gmptGlyphOrigin.y;
|
||||
|
||||
// set where we start copying from
|
||||
int xstart = 0;
|
||||
|
||||
// don't copy the first set of pixels if the antialiased bmp is bigger than the char width
|
||||
if ((int)glyphMetrics.gmBlackBoxX >= b + 2)
|
||||
{
|
||||
xstart = (glyphMetrics.gmBlackBoxX - b) / 2;
|
||||
}
|
||||
|
||||
// iterate through copying the generated dib into the texture
|
||||
for (unsigned int j = 0; j < glyphMetrics.gmBlackBoxY; j++)
|
||||
{
|
||||
for (unsigned int i = xstart; i < glyphMetrics.gmBlackBoxX; i++)
|
||||
{
|
||||
int x = i - xstart + m_iBlur + m_iOutlineSize;
|
||||
int y = j + pushDown;
|
||||
if ((x < rgbaWide) && (y < rgbaTall))
|
||||
{
|
||||
unsigned char grayscale = lpbuf[(j*wide+i)];
|
||||
|
||||
float r, g, b, a;
|
||||
if (grayscale)
|
||||
{
|
||||
r = g = b = 1.0f;
|
||||
a = (grayscale + 0) / 64.0f;
|
||||
if (a > 1.0f) a = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = g = b = a = 0.0f;
|
||||
}
|
||||
|
||||
// Don't want anything drawn for tab characters.
|
||||
if (ch == '\t')
|
||||
{
|
||||
r = g = b = 0;
|
||||
}
|
||||
|
||||
unsigned char *dst = &rgba[(y*rgbaWide+x)*4];
|
||||
dst[0] = (unsigned char)(r * 255.0f);
|
||||
dst[1] = (unsigned char)(g * 255.0f);
|
||||
dst[2] = (unsigned char)(b * 255.0f);
|
||||
dst[3] = (unsigned char)(a * 255.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// use render-to-bitmap to get our font texture
|
||||
::SetBkColor(m_hDC, RGB(0, 0, 0));
|
||||
::SetTextColor(m_hDC, RGB(255, 255, 255));
|
||||
::SetBkMode(m_hDC, OPAQUE);
|
||||
if ( m_bUnderlined )
|
||||
{
|
||||
::MoveToEx(m_hDC, 0, 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
::MoveToEx(m_hDC, -a, 0, NULL);
|
||||
}
|
||||
|
||||
// render the character
|
||||
wchar_t wch = (wchar_t)ch;
|
||||
|
||||
if (s_bSupportsUnicode)
|
||||
{
|
||||
// clear the background first
|
||||
RECT rect = { 0, 0, wide, tall};
|
||||
::ExtTextOutW( m_hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL );
|
||||
|
||||
// just use the unicode renderer
|
||||
::ExtTextOutW( m_hDC, 0, 0, 0, NULL, &wch, 1, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
// clear the background first (it may not get done automatically in win98/ME
|
||||
RECT rect = { 0, 0, wide, tall};
|
||||
::ExtTextOut(m_hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
|
||||
|
||||
// convert the character using the current codepage
|
||||
char mbcs[6] = { 0 };
|
||||
::WideCharToMultiByte(CP_ACP, 0, &wch, 1, mbcs, sizeof(mbcs), NULL, NULL);
|
||||
::ExtTextOutA(m_hDC, 0, 0, 0, NULL, mbcs, strlen(mbcs), NULL);
|
||||
}
|
||||
|
||||
::SetBkMode(m_hDC, TRANSPARENT);
|
||||
|
||||
if (wide > m_rgiBitmapSize[0])
|
||||
{
|
||||
wide = m_rgiBitmapSize[0];
|
||||
}
|
||||
if (tall > m_rgiBitmapSize[1])
|
||||
{
|
||||
tall = m_rgiBitmapSize[1];
|
||||
}
|
||||
|
||||
// iterate through copying the generated dib into the texture
|
||||
for (int j = (int)m_iOutlineSize; j < tall - (int)m_iOutlineSize; j++ )
|
||||
{
|
||||
// only copy from within the dib, ignore the outline border we are artificially adding
|
||||
for (int i = (int)m_iOutlineSize; i < wide - (int)m_iDropShadowOffset - (int)m_iOutlineSize; i++)
|
||||
{
|
||||
if ((i < rgbaWide) && (j < rgbaTall))
|
||||
{
|
||||
unsigned char *src = &m_pBuf[(i + j*m_rgiBitmapSize[0])*4];
|
||||
unsigned char *dst = &rgba[(i + j*rgbaWide)*4];
|
||||
|
||||
// Don't want anything drawn for tab characters.
|
||||
unsigned char r, g, b;
|
||||
if ( ch == '\t' )
|
||||
{
|
||||
r = g = b = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = src[0];
|
||||
g = src[1];
|
||||
b = src[2];
|
||||
}
|
||||
|
||||
// generate alpha based on luminance conversion
|
||||
dst[0] = r;
|
||||
dst[1] = g;
|
||||
dst[2] = b;
|
||||
dst[3] = (unsigned char)((float)r * 0.34f + (float)g * 0.55f + (float)b * 0.11f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we have a dropshadow, we need to clean off the bottom row of pixels
|
||||
// this is because of a bug in winME that writes noise to them, only on the first time the game is run after a reboot
|
||||
// the bottom row should guaranteed to be empty to fit the dropshadow
|
||||
if ( m_iDropShadowOffset )
|
||||
{
|
||||
unsigned char *dst = &rgba[((m_iHeight - 1) * rgbaWide) * 4];
|
||||
for (int i = 0; i < wide; i++)
|
||||
{
|
||||
dst[0] = 0;
|
||||
dst[1] = 0;
|
||||
dst[2] = 0;
|
||||
dst[3] = 0;
|
||||
dst += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apply requested effects in specified order
|
||||
ApplyDropShadowToTexture( rgbaWide, rgbaTall, rgba, m_iDropShadowOffset );
|
||||
ApplyOutlineToTexture( rgbaWide, rgbaTall, rgba, m_iOutlineSize );
|
||||
ApplyGaussianBlurToTexture( rgbaWide, rgbaTall, rgba, m_iBlur );
|
||||
ApplyScanlineEffectToTexture( rgbaWide, rgbaTall, rgba, m_iScanLines );
|
||||
ApplyRotaryEffectToTexture( rgbaWide, rgbaTall, rgba, m_bRotary );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true if the font is equivalent to that specified
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWin32Font::IsEqualTo(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
if ( !stricmp(windowsFontName, m_szName.String() )
|
||||
&& m_iTall == tall
|
||||
&& m_iWeight == weight
|
||||
&& m_iBlur == blur
|
||||
&& m_iFlags == flags)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true only if this font is valid for use
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWin32Font::IsValid()
|
||||
{
|
||||
if ( m_szName.IsValid() && m_szName.String()[0] )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: set the font to be the one to currently draw with in the gdi
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWin32Font::SetAsActiveFont(HDC hdc)
|
||||
{
|
||||
Assert( IsValid() );
|
||||
::SelectObject( hdc, m_hFont );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the abc widths for a character
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWin32Font::GetCharABCWidths(int ch, int &a, int &b, int &c)
|
||||
{
|
||||
Assert( IsValid() );
|
||||
|
||||
// look for it in the cache
|
||||
abc_cache_t finder = { (wchar_t)ch };
|
||||
|
||||
unsigned short i = m_ExtendedABCWidthsCache.Find(finder);
|
||||
if (m_ExtendedABCWidthsCache.IsValidIndex(i))
|
||||
{
|
||||
a = m_ExtendedABCWidthsCache[i].abc.a;
|
||||
b = m_ExtendedABCWidthsCache[i].abc.b;
|
||||
c = m_ExtendedABCWidthsCache[i].abc.c;
|
||||
return;
|
||||
}
|
||||
|
||||
// not in the cache, get from windows (this call is a little slow)
|
||||
ABC abc;
|
||||
if (::GetCharABCWidthsW(m_hDC, ch, ch, &abc) || ::GetCharABCWidthsA(m_hDC, ch, ch, &abc))
|
||||
{
|
||||
a = abc.abcA;
|
||||
b = abc.abcB;
|
||||
c = abc.abcC;
|
||||
}
|
||||
else
|
||||
{
|
||||
// wide character version failed, try the old api function
|
||||
SIZE size;
|
||||
char mbcs[6] = { 0 };
|
||||
wchar_t wch = ch;
|
||||
::WideCharToMultiByte(CP_ACP, 0, &wch, 1, mbcs, sizeof(mbcs), NULL, NULL);
|
||||
if (::GetTextExtentPoint32(m_hDC, mbcs, strlen(mbcs), &size))
|
||||
{
|
||||
a = c = 0;
|
||||
b = size.cx;
|
||||
}
|
||||
else
|
||||
{
|
||||
// failed to get width, just use the max width
|
||||
a = c = 0;
|
||||
b = m_iMaxCharWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// add to the cache
|
||||
finder.abc.a = a - m_iBlur - m_iOutlineSize;
|
||||
finder.abc.b = b + ((m_iBlur + m_iOutlineSize) * 2) + m_iDropShadowOffset;
|
||||
finder.abc.c = c - m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
|
||||
m_ExtendedABCWidthsCache.Insert(finder);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the height of the font, in pixels
|
||||
//-----------------------------------------------------------------------------
|
||||
int CWin32Font::GetHeight()
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return m_iHeight;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the ascent of the font, in pixels (ascent=units above the base line)
|
||||
//-----------------------------------------------------------------------------
|
||||
int CWin32Font::GetAscent()
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return m_iAscent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the maximum width of a character, in pixels
|
||||
//-----------------------------------------------------------------------------
|
||||
int CWin32Font::GetMaxCharWidth()
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return m_iMaxCharWidth;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the flags used to make this font, used by the dynamic resizing code
|
||||
//-----------------------------------------------------------------------------
|
||||
int CWin32Font::GetFlags()
|
||||
{
|
||||
return m_iFlags;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Comparison function for abc widths storage
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWin32Font::ExtendedABCWidthsCacheLessFunc(const abc_cache_t &lhs, const abc_cache_t &rhs)
|
||||
{
|
||||
return lhs.wch < rhs.wch;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get the kerned size of a char, for win32 just pass thru for now
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWin32Font::GetKernedCharWidth( wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA, float &abcC )
|
||||
{
|
||||
int a,b,c;
|
||||
GetCharABCWidths(ch, a, b, c );
|
||||
wide = ( a + b + c);
|
||||
abcA = a;
|
||||
abcC = c;
|
||||
}
|
||||
|
||||
|
||||
404
vgui2/vgui_surfacelib/Win32Font_x360.cpp
Normal file
404
vgui2/vgui_surfacelib/Win32Font_x360.cpp
Normal file
@@ -0,0 +1,404 @@
|
||||
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Xbox 360 support for TrueType Fonts. The only cuurent solution is to use XUI
|
||||
// to mount the TTF, and rasterize glyph into a render target. XUI does not support
|
||||
// rasterization directly to a system memory region.
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <malloc.h>
|
||||
#include <tier0/dbg.h>
|
||||
#include <vgui/ISurface.h>
|
||||
#include <tier0/mem.h>
|
||||
#include <utlbuffer.h>
|
||||
#include "filesystem.h"
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "FontEffects.h"
|
||||
#include "vgui_surfacelib/vguifont.h"
|
||||
#include "vgui_surfacelib/FontManager.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
bool s_bSupportsUnicode = true;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Determine possible style from parameters.
|
||||
//-----------------------------------------------------------------------------
|
||||
int GetStyleFromParameters( int iFlags, int iWeight )
|
||||
{
|
||||
// Available xbox TTF styles are very restricted.
|
||||
int style = XUI_FONT_STYLE_NORMAL;
|
||||
if ( iFlags & FONTFLAG_ITALIC )
|
||||
style |= XUI_FONT_STYLE_ITALIC;
|
||||
if ( iFlags & FONTFLAG_UNDERLINE )
|
||||
style |= XUI_FONT_STYLE_UNDERLINE;
|
||||
if ( iWeight > 400 )
|
||||
style |= XUI_FONT_STYLE_BOLD;
|
||||
return style;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CWin32Font::CWin32Font() : m_ExtendedABCWidthsCache( 256, 0, &ExtendedABCWidthsCacheLessFunc )
|
||||
{
|
||||
m_szName = UTL_INVAL_SYMBOL;
|
||||
m_iTall = 0;
|
||||
m_iWeight = 0;
|
||||
m_iHeight = 0;
|
||||
m_iAscent = 0;
|
||||
m_iFlags = 0;
|
||||
m_iMaxCharWidth = 0;
|
||||
m_hFont = NULL;
|
||||
m_hDC = NULL;
|
||||
m_bAntiAliased = false;
|
||||
m_bUnderlined = false;
|
||||
m_iBlur = 0;
|
||||
m_iScanLines = 0;
|
||||
m_bRotary = false;
|
||||
m_bAdditive = false;
|
||||
m_rgiBitmapSize[0] = 0;
|
||||
m_rgiBitmapSize[1] = 0;
|
||||
|
||||
s_bSupportsUnicode = true;
|
||||
|
||||
Q_memset( m_ABCWidthsCache, 0, sizeof( m_ABCWidthsCache ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CWin32Font::~CWin32Font()
|
||||
{
|
||||
CloseResource();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates the font.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWin32Font::Create( const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags )
|
||||
{
|
||||
// setup font properties
|
||||
m_iTall = tall;
|
||||
m_iWeight = weight;
|
||||
m_iFlags = flags;
|
||||
m_bAntiAliased = (flags & FONTFLAG_ANTIALIAS) ? 1 : 0;
|
||||
m_bUnderlined = (flags & FONTFLAG_UNDERLINE) ? 1 : 0;
|
||||
m_iDropShadowOffset = (flags & FONTFLAG_DROPSHADOW) ? 1 : 0;
|
||||
m_iOutlineSize = (flags & FONTFLAG_OUTLINE) ? 1 : 0;
|
||||
m_iBlur = blur;
|
||||
m_iScanLines = scanlines;
|
||||
m_bRotary = (flags & FONTFLAG_ROTARY) ? 1 : 0;
|
||||
m_bAdditive = (flags & FONTFLAG_ADDITIVE) ? 1 : 0;
|
||||
|
||||
int style = GetStyleFromParameters( flags, weight );
|
||||
|
||||
// must support > 128, there are characters in this range in the custom fonts
|
||||
COMPILE_TIME_ASSERT( ABCWIDTHS_CACHE_SIZE == 256 );
|
||||
|
||||
XUIFontMetrics fontMetrics;
|
||||
XUICharMetrics charMetrics[256];
|
||||
|
||||
// many redundant requests are made that are actually the same font metrics
|
||||
// find it in the metric cache first based on the true specific keys
|
||||
if ( !FontManager().GetCachedXUIMetrics( windowsFontName, tall, style, &fontMetrics, charMetrics ) )
|
||||
{
|
||||
m_hFont = FontManager().MaterialSystem()->OpenTrueTypeFont( windowsFontName, tall, style );
|
||||
if ( !m_hFont )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the predominant font metrics now [1-255], the extended set [256-65535] is on-demand
|
||||
FontManager().MaterialSystem()->GetTrueTypeFontMetrics( m_hFont, 1, 255, &fontMetrics, &charMetrics[1] );
|
||||
|
||||
// getting the metrics is an expensive i/o operation, cache results
|
||||
FontManager().SetCachedXUIMetrics( windowsFontName, tall, style, &fontMetrics, charMetrics );
|
||||
}
|
||||
|
||||
m_szName = windowsFontName;
|
||||
|
||||
m_iHeight = fontMetrics.fMaxHeight + m_iDropShadowOffset + 2 * m_iOutlineSize;
|
||||
m_iMaxCharWidth = fontMetrics.fMaxWidth;
|
||||
m_iAscent = fontMetrics.fMaxAscent;
|
||||
|
||||
// determine cell bounds
|
||||
m_rgiBitmapSize[0] = m_iMaxCharWidth + m_iOutlineSize * 2;
|
||||
m_rgiBitmapSize[1] = m_iHeight;
|
||||
|
||||
// get char spacing
|
||||
// a is space before character (can be negative)
|
||||
// b is the width of the character
|
||||
// c is the space after the character
|
||||
Assert( ABCWIDTHS_CACHE_SIZE <= 256 );
|
||||
Q_memset( m_ABCWidthsCache, 0, sizeof( m_ABCWidthsCache ) );
|
||||
|
||||
for ( int i = 1; i < ABCWIDTHS_CACHE_SIZE; i++ )
|
||||
{
|
||||
int a,b,c;
|
||||
|
||||
// Determine real a,b,c mapping from XUI Character Metrics
|
||||
a = charMetrics[i].fMinX - 1; // Add one column of padding to make up for font rendering blurring into left column (and adjust in b)
|
||||
b = charMetrics[i].fMaxX - charMetrics[i].fMinX + 1;
|
||||
c = charMetrics[i].fAdvance - charMetrics[i].fMaxX; // NOTE: We probably should add a column here, but it's rarely needed in our current fonts so we're opting to save memory instead
|
||||
|
||||
// Widen for blur, outline, and shadow. Need to widen b and reduce a and c.
|
||||
m_ABCWidthsCache[i].a = a - m_iBlur - m_iOutlineSize;
|
||||
m_ABCWidthsCache[i].b = b + ( ( m_iBlur + m_iOutlineSize ) * 2 ) + m_iDropShadowOffset;
|
||||
m_ABCWidthsCache[i].c = c - m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: generates texture data (written into appropriate font page subrects) for multiple chars
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWin32Font::GetCharsRGBA( newChar_t *newChars, int numNewChars, unsigned char *pRGBA )
|
||||
{
|
||||
if ( !m_hFont )
|
||||
{
|
||||
// demand request for font glyph, re-create font
|
||||
int style = GetStyleFromParameters( m_iFlags, m_iWeight );
|
||||
m_hFont = FontManager().MaterialSystem()->OpenTrueTypeFont( GetName(), m_iTall, style );
|
||||
}
|
||||
|
||||
wchar_t *pWch = (wchar_t *)_alloca( numNewChars*sizeof(wchar_t) );
|
||||
int *pOffsetX = (int *)_alloca( numNewChars*sizeof(int) );
|
||||
int *pOffsetY = (int *)_alloca( numNewChars*sizeof(int) );
|
||||
int *pWidth = (int *)_alloca( numNewChars*sizeof(int) );
|
||||
int *pHeight = (int *)_alloca( numNewChars*sizeof(int) );
|
||||
int *pRGBAOffset = (int *)_alloca( numNewChars*sizeof(int) );
|
||||
for ( int i = 0; i < numNewChars; i++ )
|
||||
{
|
||||
int a, c, wide;
|
||||
GetCharABCWidths( newChars[i].wch, a, wide, c );
|
||||
pWch[i] = newChars[i].wch;
|
||||
pOffsetX[i] = -a;
|
||||
pOffsetY[i] = 0;
|
||||
pWidth[i] = newChars[i].fontWide;
|
||||
pHeight[i] = newChars[i].fontTall;
|
||||
pRGBAOffset[i] = newChars[i].offset;
|
||||
}
|
||||
if ( !FontManager().MaterialSystem()->GetTrueTypeGlyphs( m_hFont, numNewChars, pWch, pOffsetX, pOffsetY, pWidth, pHeight, pRGBA, pRGBAOffset ) )
|
||||
{
|
||||
// failure
|
||||
return;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < numNewChars; i++ )
|
||||
{
|
||||
// apply requested effects in specified order
|
||||
unsigned char *pCharRGBA = pRGBA + newChars[i].offset;
|
||||
ApplyDropShadowToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iDropShadowOffset );
|
||||
ApplyOutlineToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iOutlineSize );
|
||||
ApplyGaussianBlurToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iBlur );
|
||||
ApplyScanlineEffectToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iScanLines );
|
||||
ApplyRotaryEffectToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_bRotary );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: writes the char into the specified 32bpp texture at specified rect
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWin32Font::GetCharRGBA( wchar_t ch, int rgbaWide, int rgbaTall, unsigned char *pRGBA )
|
||||
{
|
||||
newChar_t newChar;
|
||||
newChar.wch = ch;
|
||||
newChar.fontWide = rgbaWide;
|
||||
newChar.fontTall = rgbaTall;
|
||||
newChar.offset = 0;
|
||||
GetCharsRGBA( &newChar, 1, pRGBA );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true if the font is equivalent to that specified
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWin32Font::IsEqualTo(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
// do an true comparison that accounts for non-supported behaviors that gets remapped
|
||||
// avoids creating fonts that are graphically equivalent, though specified differently
|
||||
if ( !stricmp( windowsFontName, m_szName.String() ) &&
|
||||
m_iTall == tall &&
|
||||
m_iBlur == blur &&
|
||||
m_iScanLines == scanlines )
|
||||
{
|
||||
// only these flags affect the font glyphs
|
||||
int validFlags = FONTFLAG_DROPSHADOW |
|
||||
FONTFLAG_OUTLINE |
|
||||
FONTFLAG_ROTARY |
|
||||
FONTFLAG_ITALIC |
|
||||
FONTFLAG_UNDERLINE;
|
||||
if ( ( m_iFlags & validFlags ) == ( flags & validFlags ) )
|
||||
{
|
||||
if ( GetStyleFromParameters( m_iFlags, m_iWeight ) == GetStyleFromParameters( flags, weight ) )
|
||||
{
|
||||
// the font is equivalent
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true only if this font is valid for use
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWin32Font::IsValid()
|
||||
{
|
||||
if ( m_szName != UTL_INVAL_SYMBOL )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: set the font to be the one to currently draw with in the gdi
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWin32Font::SetAsActiveFont( HDC hdc )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the abc widths for a character
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWin32Font::GetCharABCWidths( int ch, int &a, int &b, int &c )
|
||||
{
|
||||
Assert( IsValid() );
|
||||
|
||||
if ( ch < ABCWIDTHS_CACHE_SIZE )
|
||||
{
|
||||
// use the cache entry
|
||||
a = m_ABCWidthsCache[ch].a;
|
||||
b = m_ABCWidthsCache[ch].b;
|
||||
c = m_ABCWidthsCache[ch].c;
|
||||
}
|
||||
else
|
||||
{
|
||||
// look for it in the extended cache
|
||||
abc_cache_t finder = { (wchar_t)ch };
|
||||
unsigned short i = m_ExtendedABCWidthsCache.Find( finder );
|
||||
if ( m_ExtendedABCWidthsCache.IsValidIndex( i ) )
|
||||
{
|
||||
a = m_ExtendedABCWidthsCache[i].abc.a;
|
||||
b = m_ExtendedABCWidthsCache[i].abc.b;
|
||||
c = m_ExtendedABCWidthsCache[i].abc.c;
|
||||
return;
|
||||
}
|
||||
|
||||
// not in the cache, get from system
|
||||
// getting the metrics is an expensive i/o operation
|
||||
if ( !m_hFont )
|
||||
{
|
||||
// demand request for font metrics, re-open font
|
||||
int style = GetStyleFromParameters( m_iFlags, m_iWeight );
|
||||
m_hFont = FontManager().MaterialSystem()->OpenTrueTypeFont( GetName(), m_iTall, style );
|
||||
}
|
||||
|
||||
if ( m_hFont )
|
||||
{
|
||||
XUIFontMetrics fontMetrics;
|
||||
XUICharMetrics charMetrics;
|
||||
FontManager().MaterialSystem()->GetTrueTypeFontMetrics( m_hFont, ch, ch, &fontMetrics, &charMetrics );
|
||||
|
||||
// Determine real a,b,c mapping from XUI Character Metrics
|
||||
a = charMetrics.fMinX - 1; // Add one column of padding to make up for font rendering blurring into left column (and adjust in b)
|
||||
b = charMetrics.fMaxX - charMetrics.fMinX + 1;
|
||||
c = charMetrics.fAdvance - charMetrics.fMaxX; // NOTE: We probably should add a column here, but it's rarely needed in our current fonts so we're opting to save memory instead
|
||||
|
||||
// Widen for blur, outline, and shadow. Need to widen b and reduce a and c.
|
||||
a = a - m_iBlur - m_iOutlineSize;
|
||||
b = b + ( ( m_iBlur + m_iOutlineSize ) * 2 ) + m_iDropShadowOffset;
|
||||
c = c - m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = 0;
|
||||
b = 0;
|
||||
c = 0;
|
||||
}
|
||||
|
||||
// add to the cache
|
||||
finder.abc.a = a;
|
||||
finder.abc.b = b;
|
||||
finder.abc.c = c;
|
||||
m_ExtendedABCWidthsCache.Insert( finder );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the height of the font, in pixels
|
||||
//-----------------------------------------------------------------------------
|
||||
int CWin32Font::GetHeight()
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return m_iHeight;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the ascent of the font, in pixels (ascent=units above the base line)
|
||||
//-----------------------------------------------------------------------------
|
||||
int CWin32Font::GetAscent()
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return m_iAscent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the maximum width of a character, in pixels
|
||||
//-----------------------------------------------------------------------------
|
||||
int CWin32Font::GetMaxCharWidth()
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return m_iMaxCharWidth;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the flags used to make this font, used by the dynamic resizing code
|
||||
//-----------------------------------------------------------------------------
|
||||
int CWin32Font::GetFlags()
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return m_iFlags;
|
||||
}
|
||||
|
||||
void CWin32Font::CloseResource()
|
||||
{
|
||||
if ( !m_hFont )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// many fonts are blindly precached by vgui and never used
|
||||
// save memory and don't hold font open, re-open if glyph actually requested used during draw
|
||||
FontManager().MaterialSystem()->CloseTrueTypeFont( m_hFont );
|
||||
m_hFont = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Comparison function for abc widths storage
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CWin32Font::ExtendedABCWidthsCacheLessFunc( const abc_cache_t &lhs, const abc_cache_t &rhs )
|
||||
{
|
||||
return lhs.wch < rhs.wch;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get the kerned size of a char, for win32 just pass thru for now
|
||||
//-----------------------------------------------------------------------------
|
||||
void CWin32Font::GetKernedCharWidth( wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA, float &abcC )
|
||||
{
|
||||
int a,b,c;
|
||||
GetCharABCWidths(ch, a, b, c );
|
||||
wide = ( a + b + c);
|
||||
abcA = a;
|
||||
abcC = c;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// ----------------------------------------- //
|
||||
// File generated by VPC //
|
||||
// ----------------------------------------- //
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\BitmapFont.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\BitmapFont.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\BitmapFont.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\common\debug_lib_check.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\common\debug_lib_check.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\common\debug_lib_check.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\FontAmalgam.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\FontAmalgam.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\FontAmalgam.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\FontEffects.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\FontEffects.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\FontEffects.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\fontmanager.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\fontmanager.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\fontmanager.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\fonttexturecache.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\fonttexturecache.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\fonttexturecache.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\texturedictionary.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\texturedictionary.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\texturedictionary.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\Win32Font.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\Win32Font.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\vgui2\vgui_surfacelib\Win32Font.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
847
vgui2/vgui_surfacelib/fontmanager.cpp
Normal file
847
vgui2/vgui_surfacelib/fontmanager.cpp
Normal file
@@ -0,0 +1,847 @@
|
||||
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#include <locale.h>
|
||||
#include "vgui_surfacelib/BitmapFont.h"
|
||||
#include "vgui_surfacelib/fontmanager.h"
|
||||
#include "convar.h"
|
||||
#include <vgui/ISurface.h>
|
||||
#include <tier0/dbg.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
static CFontManager s_FontManager;
|
||||
|
||||
#ifdef WIN32
|
||||
extern bool s_bSupportsUnicode;
|
||||
#endif
|
||||
|
||||
#if !defined( _X360 )
|
||||
#define MAX_INITIAL_FONTS 100
|
||||
#else
|
||||
#define MAX_INITIAL_FONTS 1
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: singleton accessor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFontManager &FontManager()
|
||||
{
|
||||
return s_FontManager;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFontManager::CFontManager()
|
||||
{
|
||||
// add a single empty font, to act as an invalid font handle 0
|
||||
m_FontAmalgams.EnsureCapacity( MAX_INITIAL_FONTS );
|
||||
m_FontAmalgams.AddToTail();
|
||||
m_Win32Fonts.EnsureCapacity( MAX_INITIAL_FONTS );
|
||||
|
||||
#ifdef LINUX
|
||||
FT_Error error = FT_Init_FreeType( &library );
|
||||
if ( error )
|
||||
Error( "Unable to initalize freetype library, is it installed?" );
|
||||
pFontDataHelper = NULL;
|
||||
#endif
|
||||
|
||||
// setup our text locale
|
||||
setlocale( LC_CTYPE, "" );
|
||||
setlocale( LC_TIME, "" );
|
||||
setlocale( LC_COLLATE, "" );
|
||||
setlocale( LC_MONETARY, "" );
|
||||
|
||||
m_pFileSystem = NULL;
|
||||
m_pMaterialSystem = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: language setting for font fallbacks
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontManager::SetLanguage(const char *language)
|
||||
{
|
||||
Q_strncpy(m_szLanguage, language, sizeof(m_szLanguage));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CFontManager::GetLanguage()
|
||||
{
|
||||
return m_szLanguage;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFontManager::~CFontManager()
|
||||
{
|
||||
ClearAllFonts();
|
||||
#ifdef LINUX
|
||||
FT_Done_FreeType( library );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: frees the fonts
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontManager::ClearAllFonts()
|
||||
{
|
||||
// free the fonts
|
||||
for (int i = 0; i < m_Win32Fonts.Count(); i++)
|
||||
{
|
||||
delete m_Win32Fonts[i];
|
||||
}
|
||||
m_Win32Fonts.RemoveAll();
|
||||
|
||||
m_FontAmalgams.RemoveAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
vgui::HFont CFontManager::CreateFont()
|
||||
{
|
||||
int i = m_FontAmalgams.AddToTail();
|
||||
return i;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the valid glyph ranges for a font created by CreateFont()
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontManager::SetFontGlyphSet(HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
return SetFontGlyphSet( font, windowsFontName, tall, weight, blur, scanlines, flags, 0, 0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets the valid glyph ranges for a font created by CreateFont()
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontManager::SetFontGlyphSet(HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int nRangeMin, int nRangeMax)
|
||||
{
|
||||
// ignore all but the first font added
|
||||
// need to rev vgui versions and change the name of this function
|
||||
if ( m_FontAmalgams[font].GetCount() > 0 )
|
||||
{
|
||||
// clear any existing fonts
|
||||
m_FontAmalgams[font].RemoveAll();
|
||||
}
|
||||
|
||||
bool bForceSingleFont = false;
|
||||
if ( IsX360() )
|
||||
{
|
||||
//-----//
|
||||
// 360 //
|
||||
//-----//
|
||||
|
||||
// AV - The 360 must use the same size font for 0-255 and 256-0xFFFF regardless of the font since the
|
||||
// fontAmalgam can only deal with a consistent font height for all fonts in a single amalgam. We
|
||||
// could change this if we forced all fonts within a single amalgam to have the same height with
|
||||
// the font baselines aligned, but even then the fonts wouldn't look great, because different
|
||||
// fonts set to the same size don't necessarily have the same height visually. We need to revisit
|
||||
// this before shipping l4d2 on the PC!
|
||||
bForceSingleFont = true;
|
||||
|
||||
// discovered xbox only allows glyphs from these languages from the foreign fallback font
|
||||
// prefer to have the entire range of chars from the font so UI doesn't suffer from glyph disparity
|
||||
if ( !V_stricmp( windowsFontName, "toolbox" ) || !V_stricmp( windowsFontName, "courier new" ) )
|
||||
{
|
||||
// toolbox stays as-is
|
||||
// courier new is an internal debug font, not part of customer UI, need it stay as is
|
||||
}
|
||||
else
|
||||
{
|
||||
bool bUseFallback = false;
|
||||
if ( !V_stricmp( m_szLanguage, "portuguese" ) ||
|
||||
!V_stricmp( m_szLanguage, "polish" ) )
|
||||
{
|
||||
static ConVarRef mat_xbox_iswidescreen( "mat_xbox_iswidescreen" );
|
||||
static ConVarRef mat_xbox_ishidef( "mat_xbox_ishidef" );
|
||||
|
||||
// we can support these languages with our desired fonts in hidef/widescreen modes only
|
||||
// we must fallback to the more legible font in the lowdef or non-widescreen
|
||||
bUseFallback = !( mat_xbox_iswidescreen.GetBool() && mat_xbox_ishidef.GetBool() );
|
||||
}
|
||||
|
||||
if ( bUseFallback ||
|
||||
!V_stricmp( m_szLanguage, "japanese" ) ||
|
||||
!V_stricmp( m_szLanguage, "korean" ) ||
|
||||
!V_stricmp( m_szLanguage, "schinese" ) ||
|
||||
!V_stricmp( m_szLanguage, "tchinese" ) ||
|
||||
!V_stricmp( m_szLanguage, "russian" ) )
|
||||
{
|
||||
// these languages must use the font that has their glyphs
|
||||
// these language require a high degree of legibility
|
||||
windowsFontName = GetForeignFallbackFontName();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//----//
|
||||
// PC //
|
||||
//----//
|
||||
|
||||
// AV - The PC has the same issues caused by multiple fonts in a single amalgam with different font
|
||||
// heights...see comment above. Given the available languages in Steam, the languages below
|
||||
// were illegible at 1024x768. Resolutions of 800x600 and 640x480 are a complete mess for all
|
||||
// languages, including English. We probably need to fallback to Tahoma for all languages when
|
||||
// the vertical resolution < 720. This will probably be the next check-in, but we need to evaluate
|
||||
// this further tomorrow.
|
||||
|
||||
if ( !V_stricmp( windowsFontName, "toolbox" ) || !V_stricmp( windowsFontName, "courier new" ) )
|
||||
{
|
||||
// toolbox stays as-is
|
||||
// courier new is an internal debug font, not part of customer UI, need it stay as is
|
||||
}
|
||||
else
|
||||
{
|
||||
// These languages are illegible @ vertical resolutions <= 768
|
||||
if ( !V_stricmp( m_szLanguage, "korean" ) ||
|
||||
!V_stricmp( m_szLanguage, "schinese" ) ||
|
||||
!V_stricmp( m_szLanguage, "tchinese" ) ||
|
||||
!V_stricmp( m_szLanguage, "russian" ) ||
|
||||
!V_stricmp( m_szLanguage, "thai" ) ||
|
||||
!V_stricmp( m_szLanguage, "japanese" ) ||
|
||||
!V_stricmp( m_szLanguage, "czech" ) )
|
||||
{
|
||||
windowsFontName = GetForeignFallbackFontName();
|
||||
bForceSingleFont = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AV - If we actually want to support multiple fonts within an amalgam, we need a change here. Currently,
|
||||
// the code will use winFont for 0-255 and pExtendedFont for 256-0xFFFF! But since the functions for
|
||||
// getting the font height from the amalgam can only return one height, the heights of the two fonts
|
||||
// need to be identical. This isn't trivial because even if we query both fonts for their height
|
||||
// first, that won't force their baselines within the font pages to be aligned. So we would have to
|
||||
// do something much more complicated where we loop over all characters in each font to find the
|
||||
// absolute ascent and descent above/below the baseline and then when we create the font, align both
|
||||
// fonts to the shared baseline with a shared height. But even with the font baselines aligned with a
|
||||
// shared height, the fonts still wouldn't look great, because different fonts set to the same size
|
||||
// don't necessarily have the same height visually. We need to revisit this before shipping l4d2 on the PC!
|
||||
// And there are still issues with what I'm suggesting here because when we ask the font API what
|
||||
// the maxHeight, maxAscent, maxDescent is, we get inconsistent results, so I'm not even sure we could
|
||||
// successfully align the baseline of two fonts in the font pages.
|
||||
|
||||
font_t *winFont = CreateOrFindWin32Font( windowsFontName, tall, weight, blur, scanlines, flags );
|
||||
|
||||
// cycle until valid english/extended font support has been created
|
||||
do
|
||||
{
|
||||
// add to the amalgam
|
||||
if ( bForceSingleFont || IsFontForeignLanguageCapable( windowsFontName ) )
|
||||
{
|
||||
if ( winFont )
|
||||
{
|
||||
// font supports the full range of characters
|
||||
m_FontAmalgams[font].AddFont( winFont, 0x0000, 0xFFFF );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// font cannot provide glyphs and just supports the normal range
|
||||
// redirect to a font that can supply glyps
|
||||
const char *localizedFontName = GetForeignFallbackFontName();
|
||||
if ( winFont && !stricmp( localizedFontName, windowsFontName ) )
|
||||
{
|
||||
// it's the same font and can support the full range
|
||||
m_FontAmalgams[font].AddFont( winFont, 0x0000, 0xFFFF );
|
||||
return true;
|
||||
}
|
||||
|
||||
// create the extended support font
|
||||
font_t *pExtendedFont = CreateOrFindWin32Font( localizedFontName, tall, weight, blur, scanlines, flags );
|
||||
if ( winFont && pExtendedFont )
|
||||
{
|
||||
// use the normal font for english characters, and the extended font for the rest
|
||||
int nMin = 0x0000, nMax = 0x00FF;
|
||||
|
||||
// did we specify a range?
|
||||
if ( nRangeMin > 0 || nRangeMax > 0 )
|
||||
{
|
||||
nMin = nRangeMin;
|
||||
nMax = nRangeMax;
|
||||
|
||||
// make sure they're in the correct order
|
||||
if ( nMin > nMax )
|
||||
{
|
||||
int nTemp = nMin;
|
||||
nMin = nMax;
|
||||
nMax = nTemp;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nMin > 0 )
|
||||
{
|
||||
m_FontAmalgams[font].AddFont( pExtendedFont, 0x0000, nMin - 1 );
|
||||
}
|
||||
|
||||
m_FontAmalgams[font].AddFont( winFont, nMin, nMax );
|
||||
|
||||
if ( nMax < 0xFFFF )
|
||||
{
|
||||
m_FontAmalgams[font].AddFont( pExtendedFont, nMax + 1, 0xFFFF );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if ( pExtendedFont )
|
||||
{
|
||||
// the normal font failed to create
|
||||
// just use the extended font for the full range
|
||||
m_FontAmalgams[font].AddFont( pExtendedFont, 0x0000, 0xFFFF );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// no valid font has been created, so fallback to a different font and try again
|
||||
}
|
||||
while ( NULL != ( windowsFontName = GetFallbackFontName( windowsFontName ) ) );
|
||||
|
||||
// nothing successfully created
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: adds glyphs to a font created by CreateFont()
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontManager::SetBitmapFontGlyphSet(HFont font, const char *windowsFontName, float scalex, float scaley, int flags)
|
||||
{
|
||||
if ( m_FontAmalgams[font].GetCount() > 0 )
|
||||
{
|
||||
// clear any existing fonts
|
||||
m_FontAmalgams[font].RemoveAll();
|
||||
}
|
||||
|
||||
CBitmapFont *winFont = CreateOrFindBitmapFont( windowsFontName, scalex, scaley, flags );
|
||||
if ( winFont )
|
||||
{
|
||||
// bitmap fonts are only 0-255
|
||||
m_FontAmalgams[font].AddFont( winFont, 0x0000, 0x00FF );
|
||||
return true;
|
||||
}
|
||||
|
||||
// nothing successfully created
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates a new win32 font, or reuses one if possible
|
||||
//-----------------------------------------------------------------------------
|
||||
font_t *CFontManager::CreateOrFindWin32Font(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
// see if we already have the win32 font
|
||||
font_t *winFont = NULL;
|
||||
int i;
|
||||
for (i = 0; i < m_Win32Fonts.Count(); i++)
|
||||
{
|
||||
if (m_Win32Fonts[i]->IsEqualTo(windowsFontName, tall, weight, blur, scanlines, flags))
|
||||
{
|
||||
winFont = m_Win32Fonts[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// create the new win32font if we didn't find it
|
||||
if (!winFont)
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
|
||||
i = m_Win32Fonts.AddToTail();
|
||||
#ifdef LINUX
|
||||
int memSize = 0;
|
||||
void *pchFontData = pFontDataHelper( windowsFontName, memSize );
|
||||
if ( pchFontData )
|
||||
{
|
||||
m_Win32Fonts[i] = new font_t();
|
||||
if (m_Win32Fonts[i]->CreateFromMemory( windowsFontName, pchFontData, memSize, tall, weight, blur, scanlines, flags))
|
||||
{
|
||||
// add to the list
|
||||
winFont = m_Win32Fonts[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
// failed to create, remove
|
||||
delete m_Win32Fonts[i];
|
||||
m_Win32Fonts.Remove(i);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
m_Win32Fonts[i] = new font_t();
|
||||
if (m_Win32Fonts[i]->Create(windowsFontName, tall, weight, blur, scanlines, flags))
|
||||
{
|
||||
// add to the list
|
||||
winFont = m_Win32Fonts[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
// failed to create, remove
|
||||
delete m_Win32Fonts[i];
|
||||
m_Win32Fonts.Remove(i);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef LINUX
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return winFont;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates a new win32 font, or reuses one if possible
|
||||
//-----------------------------------------------------------------------------
|
||||
CBitmapFont *CFontManager::CreateOrFindBitmapFont(const char *windowsFontName, float scalex, float scaley, int flags)
|
||||
{
|
||||
// see if we already have the font
|
||||
CBitmapFont *winFont = NULL;
|
||||
int i;
|
||||
for ( i = 0; i < m_Win32Fonts.Count(); i++ )
|
||||
{
|
||||
font_t *font = m_Win32Fonts[i];
|
||||
|
||||
// Only looking for bitmap fonts
|
||||
int testflags = font->GetFlags();
|
||||
if ( !( testflags & FONTFLAG_BITMAP ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CBitmapFont *bitmapFont = reinterpret_cast< CBitmapFont* >( font );
|
||||
if ( bitmapFont->IsEqualTo( windowsFontName, scalex, scaley, flags ) )
|
||||
{
|
||||
winFont = bitmapFont;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// create the font if we didn't find it
|
||||
if ( !winFont )
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
|
||||
i = m_Win32Fonts.AddToTail();
|
||||
|
||||
CBitmapFont *bitmapFont = new CBitmapFont();
|
||||
if ( bitmapFont->Create( windowsFontName, scalex, scaley, flags ) )
|
||||
{
|
||||
// add to the list
|
||||
m_Win32Fonts[i] = bitmapFont;
|
||||
winFont = bitmapFont;
|
||||
}
|
||||
else
|
||||
{
|
||||
// failed to create, remove
|
||||
delete bitmapFont;
|
||||
m_Win32Fonts.Remove(i);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return winFont;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets the scale of a bitmap font
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontManager::SetFontScale(vgui::HFont font, float sx, float sy)
|
||||
{
|
||||
m_FontAmalgams[font].SetFontScale( sx, sy );
|
||||
}
|
||||
|
||||
const char *CFontManager::GetFontName( HFont font )
|
||||
{
|
||||
// ignore the amalgam of disparate char ranges, assume the first font
|
||||
return m_FontAmalgams[font].GetFontName( 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the windows font for the particular font in the amalgam
|
||||
//-----------------------------------------------------------------------------
|
||||
font_t *CFontManager::GetFontForChar( vgui::HFont font, wchar_t wch )
|
||||
{
|
||||
return m_FontAmalgams[font].GetFontForChar(wch);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the abc widths of a single character
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontManager::GetCharABCwide(HFont font, int ch, int &a, int &b, int &c)
|
||||
{
|
||||
font_t *winFont = m_FontAmalgams[font].GetFontForChar(ch);
|
||||
if (winFont)
|
||||
{
|
||||
winFont->GetCharABCWidths(ch, a, b, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no font for this range, just use the default width
|
||||
a = c = 0;
|
||||
b = m_FontAmalgams[font].GetFontMaxWidth();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the max height of a font
|
||||
//-----------------------------------------------------------------------------
|
||||
int CFontManager::GetFontTall(HFont font)
|
||||
{
|
||||
return m_FontAmalgams[font].GetFontHeight();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the ascent of a font
|
||||
//-----------------------------------------------------------------------------
|
||||
int CFontManager::GetFontAscent(HFont font, wchar_t wch)
|
||||
{
|
||||
font_t *winFont = m_FontAmalgams[font].GetFontForChar(wch);
|
||||
if ( winFont )
|
||||
{
|
||||
return winFont->GetAscent();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontManager::IsFontAdditive(HFont font)
|
||||
{
|
||||
return ( m_FontAmalgams[font].GetFlags( 0 ) & FONTFLAG_ADDITIVE ) ? true : false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontManager::IsBitmapFont(HFont font)
|
||||
{
|
||||
// A FontAmalgam is either some number of non-bitmap fonts, or a single bitmap font - so this check is valid
|
||||
return ( m_FontAmalgams[font].GetFlags( 0 ) & FONTFLAG_BITMAP ) ? true : false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the pixel width of a single character
|
||||
//-----------------------------------------------------------------------------
|
||||
int CFontManager::GetCharacterWidth(HFont font, int ch)
|
||||
{
|
||||
if ( !iswcntrl( ch ) )
|
||||
{
|
||||
int a, b, c;
|
||||
GetCharABCwide(font, ch, a, b, c);
|
||||
return (a + b + c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the area of a text string, including newlines
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontManager::GetTextSize(HFont font, const wchar_t *text, int &wide, int &tall)
|
||||
{
|
||||
wide = 0;
|
||||
tall = 0;
|
||||
|
||||
if (!text)
|
||||
return;
|
||||
|
||||
// AV - Calling GetFontTall() for an amalgam with multiple fonts will return
|
||||
// the font height of the first font only! We should be doing something like:
|
||||
//
|
||||
// tall = FontManager().GetFontForChar( font, text[0] )->GetHeight();
|
||||
//
|
||||
// but that's a little hacky since we're only looking at the first character!
|
||||
// Same goes for the calls to GetFontTall() in the for loop below
|
||||
tall = GetFontTall(font);
|
||||
|
||||
float xx = 0;
|
||||
char chBefore = 0;
|
||||
char chAfter = 0;
|
||||
for (int i = 0; ; i++)
|
||||
{
|
||||
wchar_t ch = text[i];
|
||||
if (ch == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
chAfter = text[i+1];
|
||||
|
||||
if (ch == '\n')
|
||||
{
|
||||
// AV - See note above about calling this instead: tall += FontManager().GetFontForChar( font, text[0] )->GetHeight();
|
||||
tall += GetFontTall(font);
|
||||
|
||||
xx=0;
|
||||
}
|
||||
else if (ch == '&')
|
||||
{
|
||||
// underscore character, so skip
|
||||
}
|
||||
else
|
||||
{
|
||||
float flWide, flabcA, flabcC;
|
||||
GetKernedCharWidth( font, ch, chBefore, chAfter, flWide, flabcA, flabcC );
|
||||
xx += flWide;
|
||||
if (xx > wide)
|
||||
{
|
||||
wide = ceil(xx);
|
||||
}
|
||||
}
|
||||
chBefore = ch;
|
||||
}
|
||||
}
|
||||
|
||||
// font validation functions
|
||||
struct FallbackFont_t
|
||||
{
|
||||
const char *font;
|
||||
const char *fallbackFont;
|
||||
};
|
||||
|
||||
const char *g_szValidAsianFonts[] = {
|
||||
#ifdef WIN32
|
||||
"Marlett",
|
||||
#else
|
||||
"Helvetica",
|
||||
#endif
|
||||
NULL };
|
||||
|
||||
// list of how fonts fallback
|
||||
FallbackFont_t g_FallbackFonts[] =
|
||||
{
|
||||
{ "Times New Roman", "Courier New" },
|
||||
{ "Courier New", "Courier" },
|
||||
{ "Verdana", "Arial" },
|
||||
{ "Trebuchet MS", "Arial" },
|
||||
#ifdef WIN32
|
||||
{ "Tahoma", NULL },
|
||||
{ NULL, "Tahoma" }, // every other font falls back to this
|
||||
#else
|
||||
{ "Tahoma", "Helvetica" },
|
||||
{ "Helvetica", NULL },
|
||||
{ NULL, "Helvetica" } // every other font falls back to this
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true if the font is in the list of OK asian fonts
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontManager::IsFontForeignLanguageCapable(const char *windowsFontName)
|
||||
{
|
||||
if ( IsX360() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; g_szValidAsianFonts[i] != NULL; i++)
|
||||
{
|
||||
if (!stricmp(g_szValidAsianFonts[i], windowsFontName))
|
||||
return true;
|
||||
}
|
||||
|
||||
// typeface isn't supported by asian languages
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: fallback fonts
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CFontManager::GetFallbackFontName(const char *windowsFontName)
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; g_FallbackFonts[i].font != NULL; i++ )
|
||||
{
|
||||
if (!stricmp(g_FallbackFonts[i].font, windowsFontName))
|
||||
return g_FallbackFonts[i].fallbackFont;
|
||||
}
|
||||
|
||||
// the ultimate fallback
|
||||
return g_FallbackFonts[i].fallbackFont;
|
||||
}
|
||||
|
||||
struct Win98ForeignFallbackFont_t
|
||||
{
|
||||
const char *language;
|
||||
const char *fallbackFont;
|
||||
};
|
||||
|
||||
// list of how fonts fallback
|
||||
Win98ForeignFallbackFont_t g_Win98ForeignFallbackFonts[] =
|
||||
{
|
||||
{ "russian", "system" },
|
||||
{ "japanese", "win98japanese" },
|
||||
{ "thai", "system" },
|
||||
#ifdef WIN32
|
||||
{ NULL, "Tahoma" }, // every other font falls back to this
|
||||
#else
|
||||
{ NULL, "Helvetica" }, // every other font falls back to this
|
||||
#endif
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: specialized fonts
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CFontManager::GetForeignFallbackFontName()
|
||||
{
|
||||
#ifdef WIN32
|
||||
if ( s_bSupportsUnicode )
|
||||
{
|
||||
if ( IsX360() )
|
||||
{
|
||||
return "arial unicode ms";
|
||||
}
|
||||
|
||||
// tahoma has all the necessary characters for asian/russian languages for winXP/2K+
|
||||
return "Tahoma";
|
||||
}
|
||||
#endif
|
||||
|
||||
int i;
|
||||
for (i = 0; g_Win98ForeignFallbackFonts[i].language != NULL; i++)
|
||||
{
|
||||
if (!stricmp(g_Win98ForeignFallbackFonts[i].language, m_szLanguage))
|
||||
return g_Win98ForeignFallbackFonts[i].fallbackFont;
|
||||
}
|
||||
|
||||
// the ultimate fallback
|
||||
return g_Win98ForeignFallbackFonts[i].fallbackFont;
|
||||
}
|
||||
|
||||
#if defined( _X360 )
|
||||
bool CFontManager::GetCachedXUIMetrics( const char *pFontName, int tall, int style, XUIFontMetrics *pFontMetrics, XUICharMetrics charMetrics[256] )
|
||||
{
|
||||
// linear lookup is good enough
|
||||
CUtlSymbol fontSymbol = pFontName;
|
||||
bool bFound = false;
|
||||
int i;
|
||||
for ( i = 0; i < m_XUIMetricCache.Count(); i++ )
|
||||
{
|
||||
if ( m_XUIMetricCache[i].fontSymbol == fontSymbol && m_XUIMetricCache[i].tall == tall && m_XUIMetricCache[i].style == style )
|
||||
{
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !bFound )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// get from the cache
|
||||
*pFontMetrics = m_XUIMetricCache[i].fontMetrics;
|
||||
V_memcpy( charMetrics, m_XUIMetricCache[i].charMetrics, 256 * sizeof( XUICharMetrics ) );
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined( _X360 )
|
||||
void CFontManager::SetCachedXUIMetrics( const char *pFontName, int tall, int style, XUIFontMetrics *pFontMetrics, XUICharMetrics charMetrics[256] )
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
|
||||
int i = m_XUIMetricCache.AddToTail();
|
||||
|
||||
m_XUIMetricCache[i].fontSymbol = pFontName;
|
||||
m_XUIMetricCache[i].tall = tall;
|
||||
m_XUIMetricCache[i].style = style;
|
||||
m_XUIMetricCache[i].fontMetrics = *pFontMetrics;
|
||||
V_memcpy( m_XUIMetricCache[i].charMetrics, charMetrics, 256 * sizeof( XUICharMetrics ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
void CFontManager::ClearTemporaryFontCache()
|
||||
{
|
||||
#if defined( _X360 )
|
||||
COM_TimestampedLog( "ClearTemporaryFontCache(): Start" );
|
||||
|
||||
m_XUIMetricCache.Purge();
|
||||
|
||||
// many fonts are blindly precached by vgui and never used
|
||||
// font will re-open if glyph is actually requested
|
||||
for ( int i = 0; i < m_Win32Fonts.Count(); i++ )
|
||||
{
|
||||
m_Win32Fonts[i]->CloseResource();
|
||||
}
|
||||
|
||||
COM_TimestampedLog( "ClearTemporaryFontCache(): Finish" );
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the max height of a font
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontManager::GetFontUnderlined( HFont font )
|
||||
{
|
||||
return m_FontAmalgams[font].GetUnderlined();
|
||||
}
|
||||
|
||||
void CFontManager::GetKernedCharWidth( vgui::HFont font, wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &flabcA, float &flabcC )
|
||||
{
|
||||
wide = 0.0f;
|
||||
flabcA = 0.0f;
|
||||
|
||||
Assert( font != vgui::INVALID_FONT );
|
||||
if ( font == vgui::INVALID_FONT )
|
||||
return;
|
||||
|
||||
font_t *pFont = m_FontAmalgams[font].GetFontForChar(ch);
|
||||
if ( !pFont )
|
||||
{
|
||||
// no font for this range, just use the default width
|
||||
flabcA = 0.0f;
|
||||
wide = m_FontAmalgams[font].GetFontMaxWidth();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_FontAmalgams[font].GetFontForChar( chBefore ) != pFont )
|
||||
chBefore = 0;
|
||||
|
||||
if ( m_FontAmalgams[font].GetFontForChar( chAfter ) != pFont )
|
||||
chAfter = 0;
|
||||
|
||||
pFont->GetKernedCharWidth( ch, chBefore, chAfter, wide, flabcA, flabcC );
|
||||
}
|
||||
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Ensure that all of our internal structures are consistent, and
|
||||
// account for all memory that we've allocated.
|
||||
// Input: validator - Our global validator object
|
||||
// pchName - Our name (typically a member var in our container)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontManager::Validate( CValidator &validator, char *pchName )
|
||||
{
|
||||
validator.Push( "CFontManager", this, pchName );
|
||||
|
||||
ValidateObj( m_FontAmalgams );
|
||||
for ( int iFont = 0; iFont < m_FontAmalgams.Count(); iFont++ )
|
||||
{
|
||||
ValidateObj( m_FontAmalgams[iFont] );
|
||||
}
|
||||
|
||||
ValidateObj( m_Win32Fonts );
|
||||
for ( int iWin32Font = 0; iWin32Font < m_Win32Fonts.Count(); iWin32Font++ )
|
||||
{
|
||||
ValidatePtr( m_Win32Fonts[ iWin32Font ] );
|
||||
}
|
||||
|
||||
validator.Pop();
|
||||
}
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
|
||||
585
vgui2/vgui_surfacelib/fonttexturecache.cpp
Normal file
585
vgui2/vgui_surfacelib/fonttexturecache.cpp
Normal file
@@ -0,0 +1,585 @@
|
||||
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#if !defined( _GAMECONSOLE ) && defined( _WIN32 )
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "vgui_surfacelib/fonttexturecache.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "materialsystem/itexture.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "fmtstr.h"
|
||||
#include "vgui_surfacelib/texturedictionary.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
#define TEXTURE_PAGE_WIDTH 256
|
||||
#define TEXTURE_PAGE_HEIGHT 256
|
||||
|
||||
|
||||
ConVar vgui_show_glyph_miss( "vgui_show_glyph_miss", "0", FCVAR_DEVELOPMENTONLY );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFontTextureCache::CFontTextureCache() : m_CharCache( 0, 256, CacheEntryLessFunc )
|
||||
{
|
||||
V_memset( m_CommonCharCache, 0, sizeof( m_CommonCharCache ) );
|
||||
Clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CFontTextureCache::~CFontTextureCache()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontTextureCache::SetPrefix( const char *pTexturePagePrefix )
|
||||
{
|
||||
m_TexturePagePrefix = pTexturePagePrefix;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Resets the cache
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontTextureCache::Clear()
|
||||
{
|
||||
// remove all existing data
|
||||
m_CharCache.RemoveAll();
|
||||
|
||||
for ( int i = 0; i < m_PageList.Count(); ++i )
|
||||
{
|
||||
if ( m_PageList[i].pPackedFontTextureCache )
|
||||
{
|
||||
delete m_PageList[i].pPackedFontTextureCache;
|
||||
}
|
||||
}
|
||||
m_PageList.RemoveAll();
|
||||
|
||||
m_CurrPage = -1;
|
||||
|
||||
m_FontPages.RemoveAll();
|
||||
m_FontPages.SetLessFunc( DefLessFunc( FontHandle_t ) );
|
||||
|
||||
for ( int i = 0; i < ARRAYSIZE( m_CommonCharCache ); i++ )
|
||||
{
|
||||
delete m_CommonCharCache[i];
|
||||
m_CommonCharCache[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: comparison function for cache entries
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontTextureCache::CacheEntryLessFunc( CacheEntry_t const &lhs, CacheEntry_t const &rhs )
|
||||
{
|
||||
uint64 lhsLookupID = ( ((uint64)lhs.font) << 32 ) | ((uint64)lhs.wch);
|
||||
uint64 rhsLookupID = ( ((uint64)rhs.font) << 32 ) | ((uint64)rhs.wch);
|
||||
|
||||
return lhsLookupID < rhsLookupID;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the texture info for the given char & font
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontTextureCache::GetTextureForChar( FontHandle_t font, FontDrawType_t type, wchar_t wch, int *textureID, float **texCoords )
|
||||
{
|
||||
// Ask for just one character
|
||||
return GetTextureForChars( font, type, &wch, textureID, texCoords, 1 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the texture info for the given char & font
|
||||
// This function copies in the texcoords out from the static into a preallocated passed in arg.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontTextureCache::GetTextureAndCoordsForChar( FontHandle_t font, FontDrawType_t type, wchar_t wch, int *textureID, float *texCoords )
|
||||
{
|
||||
// Ask for just one character
|
||||
float *textureCoords = NULL;
|
||||
bool bSuccess = GetTextureForChars( font, type, &wch, textureID, &textureCoords, 1 );
|
||||
if ( textureCoords )
|
||||
{
|
||||
texCoords[0] = textureCoords[0];
|
||||
texCoords[1] = textureCoords[1];
|
||||
texCoords[2] = textureCoords[2];
|
||||
texCoords[3] = textureCoords[3];
|
||||
}
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the texture info for the given chars & font
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontTextureCache::GetTextureForChars( FontHandle_t hFont, FontDrawType_t type, wchar_t *wch, int *textureID, float **texCoords, int numChars )
|
||||
{
|
||||
Assert( wch && textureID && texCoords );
|
||||
Assert( numChars >= 1 );
|
||||
|
||||
if ( type == FONT_DRAW_DEFAULT )
|
||||
{
|
||||
type = FontManager().IsFontAdditive( hFont ) ? FONT_DRAW_ADDITIVE : FONT_DRAW_NONADDITIVE;
|
||||
}
|
||||
|
||||
int typePage = (int)type - 1;
|
||||
typePage = clamp( typePage, 0, (int)FONT_DRAW_TYPE_COUNT - 1 );
|
||||
|
||||
if ( FontManager().IsBitmapFont( hFont ) )
|
||||
{
|
||||
const int MAX_BITMAP_CHARS = 256;
|
||||
if ( numChars > MAX_BITMAP_CHARS )
|
||||
{
|
||||
// Increase MAX_BITMAP_CHARS
|
||||
Assert( 0 );
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < numChars; i++ )
|
||||
{
|
||||
static float sTexCoords[ 4*MAX_BITMAP_CHARS ];
|
||||
CBitmapFont *pWinFont;
|
||||
float left, top, right, bottom;
|
||||
int index;
|
||||
Page_t *pPage;
|
||||
|
||||
pWinFont = reinterpret_cast< CBitmapFont* >( FontManager().GetFontForChar( hFont, wch[i] ) );
|
||||
if ( !pWinFont )
|
||||
{
|
||||
// bad font handle
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the texture coords
|
||||
pWinFont->GetCharCoords( wch[i], &left, &top, &right, &bottom );
|
||||
sTexCoords[i*4 + 0] = left;
|
||||
sTexCoords[i*4 + 1] = top;
|
||||
sTexCoords[i*4 + 2] = right;
|
||||
sTexCoords[i*4 + 3] = bottom;
|
||||
|
||||
// find font handle in our list of ready pages
|
||||
index = m_FontPages.Find( hFont );
|
||||
if ( index == m_FontPages.InvalidIndex() )
|
||||
{
|
||||
// not found, create the texture id and its materials
|
||||
index = m_FontPages.Insert( hFont );
|
||||
pPage = &m_FontPages.Element( index );
|
||||
|
||||
for (int type = 0; type < FONT_DRAW_TYPE_COUNT; ++type )
|
||||
{
|
||||
pPage->textureID[type] = TextureDictionary()->CreateTexture( false );
|
||||
}
|
||||
CreateFontMaterials( *pPage, pWinFont->GetTexturePage(), true );
|
||||
}
|
||||
|
||||
texCoords[i] = &(sTexCoords[ i*4 ]);
|
||||
textureID[i] = m_FontPages.Element( index ).textureID[typePage];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
font_t *pWinFont = FontManager().GetFontForChar( hFont, wch[0] );
|
||||
if ( !pWinFont )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
struct newPageEntry_t
|
||||
{
|
||||
int page; // The font page a new character will go in
|
||||
int drawX; // X location within the font page
|
||||
int drawY; // Y location within the font page
|
||||
};
|
||||
|
||||
// Determine how many characters need to have their texture generated
|
||||
newChar_t *newChars = (newChar_t *)stackalloc( numChars*sizeof( newChar_t ) );
|
||||
newPageEntry_t *newEntries = (newPageEntry_t *)stackalloc( numChars*sizeof( newPageEntry_t ) );
|
||||
int numNewChars = 0;
|
||||
int maxNewCharTexels = 0;
|
||||
int totalNewCharTexels = 0;
|
||||
|
||||
for ( int i = 0; i < numChars; i++ )
|
||||
{
|
||||
wchar_t wideChar = wch[i];
|
||||
|
||||
int *pCachePage;
|
||||
float *pCacheCoords;
|
||||
|
||||
// profiling dicatated that avoiding the naive font/char RB lookup was beneficial
|
||||
// instead waste a little memory to get all the western language chars to be direct
|
||||
if ( IsGameConsole() && wideChar < MAX_COMMON_CHARS && hFont < ARRAYSIZE( m_CommonCharCache ) )
|
||||
{
|
||||
// dominant amount of simple chars are instant direct lookup
|
||||
CommonChar_t *pCommonChars = m_CommonCharCache[hFont];
|
||||
if ( !pCommonChars )
|
||||
{
|
||||
// missing
|
||||
if ( pWinFont != FontManager().GetFontForChar( hFont, wideChar ) )
|
||||
{
|
||||
// all characters in string must come out of the same font
|
||||
return false;
|
||||
}
|
||||
|
||||
// init and insert
|
||||
pCommonChars = new CommonChar_t;
|
||||
memset( pCommonChars, 0, sizeof( CommonChar_t ) );
|
||||
m_CommonCharCache[hFont] = pCommonChars;
|
||||
}
|
||||
pCachePage = &pCommonChars->details[wideChar].page;
|
||||
pCacheCoords = pCommonChars->details[wideChar].texCoords;
|
||||
}
|
||||
else
|
||||
{
|
||||
// for console only, either more fonts than expected (> 256 fonts!) or not a simple integer
|
||||
// want to keep this a direct lookup and not a search (which defeats the perf gain)
|
||||
AssertMsgOnce( !IsGameConsole() || hFont < ARRAYSIZE( m_CommonCharCache ), "CFontTextureCache: Unexpected hFont out-of-range\n" );
|
||||
|
||||
// extended chars are a costlier lookup
|
||||
// page and char form a unique key to find in cache
|
||||
CacheEntry_t cacheItem;
|
||||
cacheItem.font = hFont;
|
||||
cacheItem.wch = wideChar;
|
||||
HCacheEntry cacheHandle = m_CharCache.Find( cacheItem );
|
||||
if ( !m_CharCache.IsValidIndex( cacheHandle ) )
|
||||
{
|
||||
// missing
|
||||
if ( pWinFont != FontManager().GetFontForChar( hFont, wideChar ) )
|
||||
{
|
||||
// all characters in string must come out of the same font
|
||||
return false;
|
||||
}
|
||||
|
||||
// init and insert
|
||||
cacheItem.texCoords[0] = 0;
|
||||
cacheItem.texCoords[1] = 0;
|
||||
cacheItem.texCoords[2] = 0;
|
||||
cacheItem.texCoords[3] = 0;
|
||||
cacheHandle = m_CharCache.Insert( cacheItem );
|
||||
Assert( m_CharCache.IsValidIndex( cacheHandle ) );
|
||||
}
|
||||
pCachePage = &m_CharCache[cacheHandle].page;
|
||||
pCacheCoords = m_CharCache[cacheHandle].texCoords;
|
||||
}
|
||||
|
||||
if ( pCacheCoords[2] == 0 && pCacheCoords[3] == 0 )
|
||||
{
|
||||
// invalid page, setup for page allocation
|
||||
// get the char details
|
||||
int a, b, c;
|
||||
pWinFont->GetCharABCWidths( wideChar, a, b, c );
|
||||
int fontWide = MAX( b, 1 );
|
||||
int fontTall = MAX( pWinFont->GetHeight(), 1 );
|
||||
if ( pWinFont->GetUnderlined() )
|
||||
{
|
||||
fontWide += ( a + c );
|
||||
}
|
||||
|
||||
// Get a texture to render into
|
||||
int page, drawX, drawY, twide, ttall;
|
||||
if ( !AllocatePageForChar( fontWide, fontTall, page, drawX, drawY, twide, ttall ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// accumulate data to pass to GetCharsRGBA below
|
||||
newEntries[numNewChars].page = page;
|
||||
newEntries[numNewChars].drawX = drawX;
|
||||
newEntries[numNewChars].drawY = drawY;
|
||||
newChars[numNewChars].wch = wideChar;
|
||||
newChars[numNewChars].fontWide = fontWide;
|
||||
newChars[numNewChars].fontTall = fontTall;
|
||||
newChars[numNewChars].offset = 4*totalNewCharTexels;
|
||||
totalNewCharTexels += fontWide*fontTall;
|
||||
maxNewCharTexels = MAX( maxNewCharTexels, fontWide*fontTall );
|
||||
numNewChars++;
|
||||
|
||||
// the 0.5 texel offset is done in CMatSystemTexture::SetMaterial()
|
||||
pCacheCoords[0] = (float)( (double)drawX / ((double)twide) );
|
||||
pCacheCoords[1] = (float)( (double)drawY / ((double)ttall) );
|
||||
pCacheCoords[2] = (float)( (double)(drawX + fontWide) / (double)twide );
|
||||
pCacheCoords[3] = (float)( (double)(drawY + fontTall) / (double)ttall );
|
||||
|
||||
*pCachePage = page;
|
||||
}
|
||||
|
||||
// give data to caller
|
||||
textureID[i] = m_PageList[*pCachePage].textureID[typePage];
|
||||
texCoords[i] = pCacheCoords;
|
||||
}
|
||||
|
||||
// Generate texture data for all newly-encountered characters
|
||||
if ( numNewChars > 0 )
|
||||
{
|
||||
if ( vgui_show_glyph_miss.GetBool() )
|
||||
{
|
||||
char *pMissString = (char *)stackalloc( numNewChars * sizeof( char ) );
|
||||
char *pString = pMissString;
|
||||
for ( int i = 0; i < numNewChars; i++ )
|
||||
{
|
||||
// build a string representative enough for debugging puproses
|
||||
wchar_t wch = newChars[i].wch;
|
||||
if ( V_isprint( wch ) )
|
||||
{
|
||||
*pString++ = (char)wch;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pString++ = '?';
|
||||
}
|
||||
}
|
||||
*pString = '\0';
|
||||
|
||||
const char *pMsg = CFmtStr( "Glyph Miss: FontHandle_t:0x%8.8x (%s), %s (0x%x)\n", (int)hFont, pWinFont->GetName(), pMissString, pMissString[0] );
|
||||
if ( IsGameConsole() )
|
||||
{
|
||||
// valid on xbox, and really want this spew treated like console spew
|
||||
Warning( "%s", pMsg );
|
||||
}
|
||||
else
|
||||
{
|
||||
// debugger output only, to prevent any reentrant glyph miss as a result of spewing
|
||||
Plat_DebugString( pMsg );
|
||||
}
|
||||
}
|
||||
|
||||
if ( IsGameConsole() && numNewChars > 1 )
|
||||
{
|
||||
MEM_ALLOC_CREDIT();
|
||||
|
||||
// Use the 360 fast path that generates multiple characters at once
|
||||
int newCharDataSize = totalNewCharTexels*4;
|
||||
CUtlBuffer newCharData( 0, newCharDataSize, CUtlBuffer::READ_ONLY );
|
||||
unsigned char *pRGBA = (unsigned char *)newCharData.Base();
|
||||
#if defined( _X360 ) || defined( _PS3 )
|
||||
pWinFont->GetCharsRGBA( newChars, numNewChars, pRGBA );
|
||||
#endif
|
||||
// Copy the data into our font pages
|
||||
for ( int i = 0; i < numNewChars; i++ )
|
||||
{
|
||||
newChar_t &newChar = newChars[i];
|
||||
newPageEntry_t &newEntry = newEntries[i];
|
||||
|
||||
// upload the new sub texture
|
||||
// NOTE: both textureIDs reference the same ITexture, so we're ok
|
||||
unsigned char *characterRGBA = pRGBA + newChar.offset;
|
||||
TextureDictionary()->SetSubTextureRGBA( m_PageList[newEntry.page].textureID[typePage], newEntry.drawX, newEntry.drawY, characterRGBA, newChar.fontWide, newChar.fontTall );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a buffer for new characters to be rendered into
|
||||
int nByteCount = maxNewCharTexels * 4;
|
||||
unsigned char *pRGBA = (unsigned char *)stackalloc( nByteCount * sizeof( unsigned char ) );
|
||||
|
||||
// Generate characters individually
|
||||
for ( int i = 0; i < numNewChars; i++ )
|
||||
{
|
||||
newChar_t &newChar = newChars[i];
|
||||
newPageEntry_t &newEntry = newEntries[i];
|
||||
|
||||
// render the character into the buffer
|
||||
Q_memset( pRGBA, 0, nByteCount );
|
||||
pWinFont->GetCharRGBA( newChar.wch, newChar.fontWide, newChar.fontTall, pRGBA );
|
||||
|
||||
// Make the char white if we are in source 2
|
||||
if ( !g_pMaterialSystem )
|
||||
{
|
||||
for ( int i = 0; i < nByteCount; i += 4 )
|
||||
{
|
||||
pRGBA[i+0] = pRGBA[i+1] = pRGBA[i+2] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// upload the new sub texture
|
||||
// NOTE: both textureIDs reference the same ITexture, so we're ok
|
||||
TextureDictionary()->SetSubTextureRGBA( m_PageList[newEntry.page].textureID[typePage], newEntry.drawX, newEntry.drawY, pRGBA, newChar.fontWide, newChar.fontTall );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates font materials
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontTextureCache::CreateFontMaterials( Page_t &page, ITexture *pFontTexture, bool bitmapFont )
|
||||
{
|
||||
// The normal material
|
||||
KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
|
||||
pVMTKeyValues->SetInt( "$vertexcolor", 1 );
|
||||
pVMTKeyValues->SetInt( "$vertexalpha", 1 );
|
||||
pVMTKeyValues->SetInt( "$ignorez", 1 );
|
||||
pVMTKeyValues->SetInt( "$no_fullbright", 1 );
|
||||
pVMTKeyValues->SetInt( "$translucent", 1 );
|
||||
pVMTKeyValues->SetString( "$basetexture", pFontTexture->GetName() );
|
||||
CUtlString materialName = m_TexturePagePrefix + "__fontpage";
|
||||
Assert( g_pMaterialSystem );
|
||||
IMaterial *pMaterial = g_pMaterialSystem->CreateMaterial( materialName, pVMTKeyValues );
|
||||
pMaterial->Refresh();
|
||||
|
||||
int typePageNonAdditive = (int)FONT_DRAW_NONADDITIVE-1;
|
||||
TextureDictionary()->BindTextureToMaterial( page.textureID[typePageNonAdditive], pMaterial );
|
||||
pMaterial->DecrementReferenceCount();
|
||||
|
||||
// The additive material
|
||||
pVMTKeyValues = new KeyValues( "UnlitGeneric" );
|
||||
pVMTKeyValues->SetInt( "$vertexcolor", 1 );
|
||||
pVMTKeyValues->SetInt( "$vertexalpha", 1 );
|
||||
pVMTKeyValues->SetInt( "$ignorez", 1 );
|
||||
pVMTKeyValues->SetInt( "$no_fullbright", 1 );
|
||||
pVMTKeyValues->SetInt( "$translucent", 1 );
|
||||
pVMTKeyValues->SetInt( "$additive", 1 );
|
||||
pVMTKeyValues->SetString( "$basetexture", pFontTexture->GetName() );
|
||||
|
||||
CUtlString addmaterialName = m_TexturePagePrefix + "__fontpage_additive";
|
||||
pMaterial = g_pMaterialSystem->CreateMaterial( addmaterialName.String(), pVMTKeyValues );
|
||||
pMaterial->Refresh();
|
||||
|
||||
int typePageAdditive = (int)FONT_DRAW_ADDITIVE-1;
|
||||
if ( bitmapFont )
|
||||
{
|
||||
TextureDictionary()->BindTextureToMaterial( page.textureID[typePageAdditive], pMaterial );
|
||||
}
|
||||
else
|
||||
{
|
||||
TextureDictionary()->BindTextureToMaterialReference( page.textureID[typePageAdditive], page.textureID[typePageNonAdditive], pMaterial);
|
||||
}
|
||||
pMaterial->DecrementReferenceCount();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: allocates a new page for a given character
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontTextureCache::AllocatePageForChar( int charWide, int charTall, int &pageIndex, int &drawX, int &drawY, int &twide, int &ttall )
|
||||
{
|
||||
// Catch the case where the glyph is too tall for the page
|
||||
if ( charTall > TEXTURE_PAGE_HEIGHT )
|
||||
return false;
|
||||
|
||||
// See if there is room in the last page for this character
|
||||
pageIndex = m_CurrPage;
|
||||
|
||||
bool bNeedsNewPage = true;
|
||||
int nodeIndex = -1;
|
||||
Rect_t glpyhRect;
|
||||
glpyhRect.x = 0;
|
||||
glpyhRect.y = 0;
|
||||
glpyhRect.width = charWide;
|
||||
glpyhRect.height = charTall;
|
||||
|
||||
if ( pageIndex > -1 )
|
||||
{
|
||||
// Let's use r/b tree to find a good spot.
|
||||
nodeIndex = m_PageList[pageIndex].pPackedFontTextureCache->InsertRect( glpyhRect );
|
||||
bNeedsNewPage = ( nodeIndex == -1 );
|
||||
}
|
||||
|
||||
if ( bNeedsNewPage )
|
||||
{
|
||||
// allocate a new page
|
||||
pageIndex = m_PageList.AddToTail();
|
||||
Page_t &newPage = m_PageList[pageIndex];
|
||||
m_CurrPage = pageIndex;
|
||||
|
||||
for (int i = 0; i < FONT_DRAW_TYPE_COUNT; ++i )
|
||||
{
|
||||
newPage.textureID[i] = TextureDictionary()->CreateTexture( true );
|
||||
}
|
||||
newPage.pPackedFontTextureCache = new CTexturePacker( TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT, ( IsGameConsole() ? 0 : 1 ) );
|
||||
|
||||
nodeIndex = newPage.pPackedFontTextureCache->InsertRect( glpyhRect );
|
||||
Assert( nodeIndex != -1 );
|
||||
|
||||
|
||||
static int nFontPageId = 0;
|
||||
char pTextureName[64];
|
||||
Q_snprintf( pTextureName, 64, "%s__font_page_%d", m_TexturePagePrefix.String(), nFontPageId );
|
||||
++nFontPageId;
|
||||
|
||||
MEM_ALLOC_CREDIT();
|
||||
if ( g_pMaterialSystem )
|
||||
{
|
||||
ITexture *pTexture = AllocateNewPage( pTextureName );
|
||||
CreateFontMaterials( newPage, pTexture );
|
||||
pTexture->DecrementReferenceCount();
|
||||
}
|
||||
|
||||
if ( IsPC() || !IsDebug() )
|
||||
{
|
||||
// clear the texture from the inital checkerboard to black
|
||||
// allocate for 32bpp format
|
||||
int nByteCount = TEXTURE_PAGE_WIDTH * TEXTURE_PAGE_HEIGHT * 4;
|
||||
CUtlMemory<unsigned char> mRGBA;
|
||||
mRGBA.EnsureCapacity( nByteCount );
|
||||
|
||||
//Q_memset( mRGBA.Base(), 0, nByteCount );
|
||||
|
||||
// Clear to white, full alpha.
|
||||
for ( int i = 0; i < nByteCount; i += 4 )
|
||||
{
|
||||
mRGBA[i+0] = mRGBA[i+1] = mRGBA[i+2] = 255;
|
||||
mRGBA[i+3] = 0;
|
||||
}
|
||||
|
||||
int typePageNonAdditive = (int)(FONT_DRAW_NONADDITIVE)-1;
|
||||
TextureDictionary()->SetTextureRGBAEx( newPage.textureID[typePageNonAdditive], ( const char* )mRGBA.Base(),
|
||||
TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT, IMAGE_FORMAT_RGBA8888, k_ETextureScalingPointSample );
|
||||
|
||||
|
||||
// Note, in rendersystem2 we do not have materials, as we actually have 2 diff textures.
|
||||
if ( !g_pMaterialSystem )
|
||||
{
|
||||
int typePageAdditive = (int)(FONT_DRAW_ADDITIVE)-1;
|
||||
newPage.textureID[typePageAdditive] = newPage.textureID[typePageNonAdditive];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// output the position
|
||||
Page_t &page = m_PageList[ pageIndex ];
|
||||
Assert( nodeIndex != -1 );
|
||||
const CTexturePacker::TreeEntry_t &newEntry = page.pPackedFontTextureCache->GetEntry( nodeIndex );
|
||||
drawX = newEntry.rc.x;
|
||||
drawY = newEntry.rc.y;
|
||||
twide = TEXTURE_PAGE_WIDTH;
|
||||
ttall = TEXTURE_PAGE_HEIGHT;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: allocates a new page
|
||||
//-----------------------------------------------------------------------------
|
||||
ITexture *CFontTextureCache::AllocateNewPage( char *pTextureName )
|
||||
{
|
||||
Assert( g_pMaterialSystem );
|
||||
ITexture *pTexture = g_pMaterialSystem->CreateProceduralTexture(
|
||||
pTextureName,
|
||||
TEXTURE_GROUP_VGUI,
|
||||
TEXTURE_PAGE_WIDTH,
|
||||
TEXTURE_PAGE_HEIGHT,
|
||||
IMAGE_FORMAT_RGBA8888,
|
||||
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT |
|
||||
TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY );
|
||||
|
||||
return pTexture;
|
||||
}
|
||||
|
||||
624
vgui2/vgui_surfacelib/linuxfont.cpp
Normal file
624
vgui2/vgui_surfacelib/linuxfont.cpp
Normal file
@@ -0,0 +1,624 @@
|
||||
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
|
||||
#include "vgui_surfacelib/linuxfont.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <malloc.h>
|
||||
#include <tier0/dbg.h>
|
||||
#include <vgui/ISurface.h>
|
||||
#include <utlbuffer.h>
|
||||
#include <fontconfig/fontconfig.h>
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
|
||||
#include "vgui_surfacelib/fontmanager.h"
|
||||
#include "FontEffects.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
namespace {
|
||||
|
||||
//Due to different font rendering approaches on different platforms, we have
|
||||
//to apply custom tweaks to fonts on Linux to make them render as desired.
|
||||
struct MetricsTweaks_t
|
||||
{
|
||||
const char *m_windowsFontName;
|
||||
int m_tallAdjust;
|
||||
};
|
||||
|
||||
MetricsTweaks_t GetFontMetricsTweaks(const char* windowsFontName)
|
||||
{
|
||||
static const MetricsTweaks_t FontMetricTweaks[] =
|
||||
{
|
||||
{ "Stubble bold", -5 },
|
||||
};
|
||||
|
||||
for( int i = 0; i != Q_ARRAYSIZE( FontMetricTweaks ); ++i )
|
||||
{
|
||||
if ( !Q_stricmp( windowsFontName, FontMetricTweaks[i].m_windowsFontName ) )
|
||||
{
|
||||
return FontMetricTweaks[i];
|
||||
}
|
||||
}
|
||||
|
||||
static const MetricsTweaks_t DefaultMetricTweaks = { NULL, 0 };
|
||||
return DefaultMetricTweaks;
|
||||
}
|
||||
|
||||
// Freetype uses a lot of fixed float values that are 26.6 splits of a 32 bit word.
|
||||
// to make it an int, shift down the 6 bits and round up if the high bit of the 6
|
||||
// bits was set.
|
||||
inline int32_t FIXED6_2INT(int32_t x) { return ( (x>>6) + ( (x&0x20) ? (x<0 ? -1 : 1) : 0) ); }
|
||||
inline float FIXED6_2FLOAT(int32_t x) { return (float)x / 64.0f; }
|
||||
inline int32_t INT_2FIXED6(int32_t x) { return x << 6; }
|
||||
|
||||
}
|
||||
|
||||
bool CLinuxFont::ms_bSetFriendlyNameCacheLessFunc = false;
|
||||
CUtlRBTree< CLinuxFont::font_name_entry > CLinuxFont::m_FriendlyNameCache;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CLinuxFont::CLinuxFont() : m_ExtendedABCWidthsCache(256, 0, &ExtendedABCWidthsCacheLessFunc),
|
||||
m_ExtendedKernedABCWidthsCache( 256, 0, &ExtendedKernedABCWidthsCacheLessFunc )
|
||||
{
|
||||
m_iTall = 0;
|
||||
m_iWeight = 0;
|
||||
m_iFlags = 0;
|
||||
m_iMaxCharWidth = 0;
|
||||
m_bAntiAliased = false;
|
||||
m_bUnderlined = false;
|
||||
m_iBlur = 0;
|
||||
m_pGaussianDistribution = NULL;
|
||||
m_iScanLines = 0;
|
||||
m_bRotary = false;
|
||||
m_bAdditive = false;
|
||||
if ( !ms_bSetFriendlyNameCacheLessFunc )
|
||||
{
|
||||
ms_bSetFriendlyNameCacheLessFunc = true;
|
||||
SetDefLessFunc( m_FriendlyNameCache );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CLinuxFont::~CLinuxFont()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: build a map of friendly (char *) name to crazy ATSU bytestream, so we can ask for "Tahoma" and actually load it
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinuxFont::CreateFontList()
|
||||
{
|
||||
if ( m_FriendlyNameCache.Count() > 0 )
|
||||
return;
|
||||
|
||||
if(!FcInit())
|
||||
return;
|
||||
FcConfig *config;
|
||||
FcPattern *pat;
|
||||
FcObjectSet *os;
|
||||
FcFontSet *fontset;
|
||||
int i;
|
||||
char *file;
|
||||
const char *name;
|
||||
|
||||
config = FcConfigGetCurrent();
|
||||
FcConfigAppFontAddDir(config, "platform/vgui/fonts");
|
||||
pat = FcPatternCreate();
|
||||
os = FcObjectSetCreate();
|
||||
FcObjectSetAdd(os, FC_FILE);
|
||||
FcObjectSetAdd(os, FC_FULLNAME);
|
||||
FcObjectSetAdd(os, FC_FAMILY);
|
||||
FcObjectSetAdd(os, FC_SCALABLE);
|
||||
fontset = FcFontList(config, pat, os);
|
||||
if(!fontset)
|
||||
return;
|
||||
for(i = 0; i < fontset->nfont; i++)
|
||||
{
|
||||
FcBool scalable;
|
||||
|
||||
if ( FcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable )
|
||||
continue;
|
||||
|
||||
|
||||
if ( FcPatternGetString(fontset->fonts[i], FC_FAMILY, 0, (FcChar8**)&name) != FcResultMatch )
|
||||
continue;
|
||||
if ( FcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch )
|
||||
continue;
|
||||
|
||||
font_name_entry entry;
|
||||
entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 );
|
||||
entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1);
|
||||
Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 );
|
||||
Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1);
|
||||
m_FriendlyNameCache.Insert( entry );
|
||||
|
||||
// substitute Vera Sans for Tahoma on X
|
||||
if ( !V_stricmp( name, "Bitstream Vera Sans" ) )
|
||||
{
|
||||
name = "Tahoma";
|
||||
entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 );
|
||||
entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1);
|
||||
Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 );
|
||||
Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1);
|
||||
m_FriendlyNameCache.Insert( entry );
|
||||
|
||||
name = "Verdana";
|
||||
entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 );
|
||||
entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1);
|
||||
Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 );
|
||||
Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1);
|
||||
m_FriendlyNameCache.Insert( entry );
|
||||
|
||||
name = "Lucidia Console";
|
||||
entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 );
|
||||
entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1);
|
||||
Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 );
|
||||
Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1);
|
||||
m_FriendlyNameCache.Insert( entry );
|
||||
}
|
||||
}
|
||||
|
||||
FcFontSetDestroy(fontset);
|
||||
FcObjectSetDestroy(os);
|
||||
FcPatternDestroy(pat);
|
||||
}
|
||||
|
||||
static FcPattern* FontMatch(const char* type, FcType vtype, const void* value,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, value);
|
||||
|
||||
FcPattern* pattern = FcPatternCreate();
|
||||
|
||||
for (;;) {
|
||||
FcValue fcvalue;
|
||||
fcvalue.type = vtype;
|
||||
switch (vtype) {
|
||||
case FcTypeString:
|
||||
fcvalue.u.s = (FcChar8*) value;
|
||||
break;
|
||||
case FcTypeInteger:
|
||||
fcvalue.u.i = (int) value;
|
||||
break;
|
||||
default:
|
||||
Assert(!"FontMatch unhandled type");
|
||||
}
|
||||
FcPatternAdd(pattern, type, fcvalue, 0);
|
||||
|
||||
type = va_arg(ap, const char *);
|
||||
if (!type)
|
||||
break;
|
||||
// FcType is promoted to int when passed through ...
|
||||
vtype = static_cast<FcType>(va_arg(ap, int));
|
||||
value = va_arg(ap, const void *);
|
||||
};
|
||||
va_end(ap);
|
||||
|
||||
FcConfigSubstitute(0, pattern, FcMatchPattern);
|
||||
FcDefaultSubstitute(pattern);
|
||||
|
||||
FcResult result;
|
||||
FcPattern* match = FcFontMatch(0, pattern, &result);
|
||||
FcPatternDestroy(pattern);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
bool CLinuxFont::CreateFromMemory(const char *windowsFontName, void *data, int size, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
// setup font properties
|
||||
m_szName = windowsFontName;
|
||||
m_iTall = tall;
|
||||
m_iWeight = weight;
|
||||
m_iFlags = flags;
|
||||
m_bAntiAliased = flags & FONTFLAG_ANTIALIAS;
|
||||
m_bUnderlined = flags & FONTFLAG_UNDERLINE;
|
||||
m_iDropShadowOffset = (flags & FONTFLAG_DROPSHADOW) ? 1 : 0;
|
||||
m_iOutlineSize = (flags & FONTFLAG_OUTLINE) ? 1 : 0;
|
||||
m_iBlur = blur;
|
||||
m_iScanLines = scanlines;
|
||||
m_bRotary = flags & FONTFLAG_ROTARY;
|
||||
m_bAdditive = flags & FONTFLAG_ADDITIVE;
|
||||
|
||||
FT_Error error = FT_New_Memory_Face( FontManager().GetFontLibraryHandle(), (FT_Byte *)data, size, 0, &face );
|
||||
if ( error == FT_Err_Unknown_File_Format )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if ( error )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
InitMetrics();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: creates the font from windows. returns false if font does not exist in the OS.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CLinuxFont::Create(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
// setup font properties
|
||||
m_szName = windowsFontName;
|
||||
m_iTall = tall;
|
||||
m_iWeight = weight;
|
||||
m_iFlags = flags;
|
||||
m_bAntiAliased = flags & FONTFLAG_ANTIALIAS;
|
||||
m_bUnderlined = flags & FONTFLAG_UNDERLINE;
|
||||
m_iDropShadowOffset = (flags & FONTFLAG_DROPSHADOW) ? 1 : 0;
|
||||
m_iOutlineSize = (flags & FONTFLAG_OUTLINE) ? 1 : 0;
|
||||
m_iBlur = blur;
|
||||
m_iScanLines = scanlines;
|
||||
m_bRotary = flags & FONTFLAG_ROTARY;
|
||||
m_bAdditive = flags & FONTFLAG_ADDITIVE;
|
||||
|
||||
CreateFontList();
|
||||
|
||||
const char *pchFontName = windowsFontName;
|
||||
if ( !Q_stricmp( pchFontName, "Tahoma" ) )
|
||||
pchFontName = "Bitstream Vera Sans";
|
||||
const int italic = flags & FONTFLAG_ITALIC ? FC_SLANT_ITALIC : FC_SLANT_ROMAN;
|
||||
FcPattern* match = FontMatch(FC_FAMILY, FcTypeString, pchFontName,
|
||||
FC_WEIGHT, FcTypeInteger, FC_WEIGHT_NORMAL,
|
||||
FC_SLANT, FcTypeInteger, italic,
|
||||
NULL);
|
||||
|
||||
if (!match)
|
||||
{
|
||||
AssertMsg1( false, "Unable to find font named %s\n", windowsFontName );
|
||||
m_szName = "";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
FcChar8* filename;
|
||||
if ( FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch )
|
||||
{
|
||||
AssertMsg1( false, "Unable to find font named %s\n", windowsFontName );
|
||||
m_szName = "";
|
||||
FcPatternDestroy(match);
|
||||
return false;
|
||||
}
|
||||
|
||||
FT_Error error = FT_New_Face( FontManager().GetFontLibraryHandle(), (const char *)filename, 0, &face );
|
||||
|
||||
// Only destroy the pattern at this point so that "filename" is pointing
|
||||
// to valid memory
|
||||
FcPatternDestroy(match);
|
||||
|
||||
if ( error == FT_Err_Unknown_File_Format )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if ( error )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( face->charmap == nullptr )
|
||||
{
|
||||
FT_Error error = FT_Select_Charmap( face, FT_ENCODING_APPLE_ROMAN );
|
||||
if ( error )
|
||||
{
|
||||
FT_Done_Face( face );
|
||||
face = NULL;
|
||||
|
||||
Msg( "Font %s has no valid charmap\n", windowsFontName );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InitMetrics();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLinuxFont::InitMetrics()
|
||||
{
|
||||
const MetricsTweaks_t metricTweaks = GetFontMetricsTweaks( m_szName );
|
||||
|
||||
FT_Set_Pixel_Sizes( face, 0, m_iTall + metricTweaks.m_tallAdjust );
|
||||
|
||||
m_iAscent = FIXED6_2INT( face->size->metrics.ascender );
|
||||
m_iMaxCharWidth = FIXED6_2INT( face->size->metrics.max_advance );
|
||||
|
||||
const int fxpHeight = face->size->metrics.height + INT_2FIXED6( m_iDropShadowOffset + 2 * m_iOutlineSize );
|
||||
m_iHeight = FIXED6_2INT( fxpHeight );
|
||||
|
||||
// calculate our gaussian distribution for if we're blurred
|
||||
if (m_iBlur > 1)
|
||||
{
|
||||
m_pGaussianDistribution = new float[m_iBlur * 2 + 1];
|
||||
double sigma = 0.683 * m_iBlur;
|
||||
for (int x = 0; x <= (m_iBlur * 2); x++)
|
||||
{
|
||||
int val = x - m_iBlur;
|
||||
m_pGaussianDistribution[x] = (float)(1.0f / sqrt(2 * 3.14 * sigma * sigma)) * pow(2.7, -1 * (val * val) / (2 * sigma * sigma));
|
||||
|
||||
// brightening factor
|
||||
m_pGaussianDistribution[x] *= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: writes the char into the specified 32bpp texture
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinuxFont::GetCharRGBA(wchar_t ch, int rgbaWide, int rgbaTall, unsigned char *prgba )
|
||||
{
|
||||
bool bShouldAntialias = m_bAntiAliased;
|
||||
// filter out
|
||||
if ( ch > 0x00FF && !(m_iFlags & FONTFLAG_CUSTOM) )
|
||||
{
|
||||
bShouldAntialias = false;
|
||||
}
|
||||
|
||||
FT_Error error = FT_Load_Char( face,ch, FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL);
|
||||
if ( error )
|
||||
return;
|
||||
|
||||
int glyph_index = FT_Get_Char_Index( face, ch );
|
||||
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER );
|
||||
if ( error )
|
||||
{
|
||||
fprintf( stderr, "Error in FL_Load_Glyph: %x\n", error );
|
||||
return;
|
||||
}
|
||||
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
uint32 nSkipRows = ( m_iAscent - slot->bitmap_top );
|
||||
if ( nSkipRows )
|
||||
nSkipRows--;
|
||||
if ( nSkipRows > rgbaTall )
|
||||
return;
|
||||
|
||||
unsigned char *rgba = prgba + ( nSkipRows * rgbaWide * 4 );
|
||||
FT_Bitmap bitmap = face->glyph->bitmap;
|
||||
|
||||
Assert( bitmap.rows <= rgbaTall );
|
||||
Assert( rgbaWide >= bitmap.width + m_iBlur );
|
||||
if ( bitmap.width == 0 )
|
||||
return;
|
||||
|
||||
/* now draw to our target surface */
|
||||
for ( int y = 0; y < MIN( bitmap.rows, rgbaTall ); y++ )
|
||||
{
|
||||
for ( int x = 0; x < bitmap.width; x++ )
|
||||
{
|
||||
int rgbaOffset = 4*(x + m_iBlur); // +(rgbaTall-y-1)*rgbaWide*4
|
||||
rgba[ rgbaOffset] = 255;
|
||||
rgba[ rgbaOffset+1] = 255;
|
||||
rgba[ rgbaOffset+2] = 255;
|
||||
rgba[ rgbaOffset+3] = bitmap.buffer[ x + y*bitmap.width ];
|
||||
}
|
||||
rgba += ( rgbaWide*4 );
|
||||
}
|
||||
|
||||
// apply requested effects in specified order
|
||||
ApplyDropShadowToTexture( rgbaWide, rgbaTall, prgba, m_iDropShadowOffset );
|
||||
ApplyOutlineToTexture( rgbaWide, rgbaTall, prgba, m_iOutlineSize );
|
||||
ApplyGaussianBlurToTexture( rgbaWide, rgbaTall, prgba, m_iBlur );
|
||||
ApplyScanlineEffectToTexture( rgbaWide, rgbaTall, prgba, m_iScanLines );
|
||||
ApplyRotaryEffectToTexture( rgbaWide, rgbaTall, prgba, m_bRotary );
|
||||
}
|
||||
|
||||
void CLinuxFont::GetKernedCharWidth( wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA, float &abcC )
|
||||
{
|
||||
abcA = abcC = wide = 0.0f;
|
||||
|
||||
// look for it in the cache
|
||||
kerned_abc_cache_t finder = { ch, chBefore, chAfter };
|
||||
|
||||
unsigned short iKerned = m_ExtendedKernedABCWidthsCache.Find(finder);
|
||||
if (m_ExtendedKernedABCWidthsCache.IsValidIndex(iKerned))
|
||||
{
|
||||
abcA = 0; //$ NYI. m_ExtendedKernedABCWidthsCache[iKerned].abc.abcA;
|
||||
abcC = 0; //$ NYI. m_ExtendedKernedABCWidthsCache[iKerned].abc.abcC;
|
||||
wide = m_ExtendedKernedABCWidthsCache[iKerned].abc.wide;
|
||||
return;
|
||||
}
|
||||
|
||||
FT_UInt glyph_index;
|
||||
FT_Bool use_kerning;
|
||||
FT_UInt previous;
|
||||
int32_t iFxpPenX;
|
||||
|
||||
iFxpPenX = 0;
|
||||
wide = 0;
|
||||
|
||||
use_kerning = FT_HAS_KERNING( face );
|
||||
previous = chBefore;
|
||||
|
||||
/* convert character code to glyph index */
|
||||
glyph_index = FT_Get_Char_Index( face, ch );
|
||||
|
||||
/* retrieve kerning distance and move pen position */
|
||||
if ( use_kerning && previous && glyph_index )
|
||||
{
|
||||
FT_Vector delta;
|
||||
|
||||
FT_Get_Kerning( face, previous, glyph_index,
|
||||
FT_KERNING_DEFAULT, &delta );
|
||||
|
||||
iFxpPenX += delta.x;
|
||||
}
|
||||
|
||||
/* load glyph image into the slot (erase previous one) */
|
||||
int error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
|
||||
if ( error )
|
||||
{
|
||||
fprintf( stderr, "Error in FL_Load_Glyph: %x\n", error );
|
||||
}
|
||||
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
iFxpPenX += slot->advance.x;
|
||||
|
||||
if ( FIXED6_2INT(iFxpPenX) > wide )
|
||||
wide = FIXED6_2INT(iFxpPenX);
|
||||
|
||||
//$ NYI: finder.abc.abcA = abcA;
|
||||
//$ NYI: finder.abc.abcC = abcC;
|
||||
finder.abc.wide = wide;
|
||||
m_ExtendedKernedABCWidthsCache.Insert(finder);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the abc widths for a character
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinuxFont::GetCharABCWidths(int ch, int &a, int &b, int &c)
|
||||
{
|
||||
Assert(IsValid());
|
||||
|
||||
// look for it in the cache
|
||||
abc_cache_t finder = { (wchar_t)ch };
|
||||
|
||||
unsigned short i = m_ExtendedABCWidthsCache.Find(finder);
|
||||
if (m_ExtendedABCWidthsCache.IsValidIndex(i))
|
||||
{
|
||||
a = m_ExtendedABCWidthsCache[i].abc.a;
|
||||
b = m_ExtendedABCWidthsCache[i].abc.b;
|
||||
c = m_ExtendedABCWidthsCache[i].abc.c;
|
||||
return;
|
||||
}
|
||||
|
||||
a = b = c = 0;
|
||||
|
||||
FT_Error error = FT_Load_Char( face,ch, 0 );
|
||||
if ( error )
|
||||
return;
|
||||
|
||||
FT_Glyph_Metrics metrics = face->glyph->metrics;
|
||||
|
||||
finder.abc.a = metrics.horiBearingX/64 - m_iBlur - m_iOutlineSize;
|
||||
finder.abc.b = metrics.width/64 + ((m_iBlur + m_iOutlineSize) * 2) + m_iDropShadowOffset;
|
||||
finder.abc.c = (metrics.horiAdvance-metrics.horiBearingX-metrics.width)/64 - m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
|
||||
|
||||
m_ExtendedABCWidthsCache.Insert(finder);
|
||||
|
||||
a = finder.abc.a;
|
||||
b = finder.abc.b;
|
||||
c = finder.abc.c;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true if the font is equivalent to that specified
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CLinuxFont::IsEqualTo(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
if (!Q_stricmp(windowsFontName, m_szName.String() )
|
||||
&& m_iTall == tall
|
||||
&& m_iWeight == weight
|
||||
&& m_iBlur == blur
|
||||
&& m_iFlags == flags)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true only if this font is valid for use
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CLinuxFont::IsValid()
|
||||
{
|
||||
if ( !m_szName.IsEmpty() )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the height of the font, in pixels
|
||||
//-----------------------------------------------------------------------------
|
||||
int CLinuxFont::GetHeight()
|
||||
{
|
||||
assert(IsValid());
|
||||
return m_iHeight;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the ascent of the font, in pixels (ascent=units above the base line)
|
||||
//-----------------------------------------------------------------------------
|
||||
int CLinuxFont::GetAscent()
|
||||
{
|
||||
assert(IsValid());
|
||||
return m_iAscent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the maximum width of a character, in pixels
|
||||
//-----------------------------------------------------------------------------
|
||||
int CLinuxFont::GetMaxCharWidth()
|
||||
{
|
||||
assert(IsValid());
|
||||
return m_iMaxCharWidth;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the flags used to make this font, used by the dynamic resizing code
|
||||
//-----------------------------------------------------------------------------
|
||||
int CLinuxFont::GetFlags()
|
||||
{
|
||||
return m_iFlags;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Comparison function for abc widths storage
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CLinuxFont::ExtendedABCWidthsCacheLessFunc(const abc_cache_t &lhs, const abc_cache_t &rhs)
|
||||
{
|
||||
return lhs.wch < rhs.wch;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Comparison function for abc widths storage
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CLinuxFont::ExtendedKernedABCWidthsCacheLessFunc(const kerned_abc_cache_t &lhs, const kerned_abc_cache_t &rhs)
|
||||
{
|
||||
return lhs.wch < rhs.wch || ( lhs.wch == rhs.wch && lhs.wchBefore < rhs.wchBefore )
|
||||
|| ( lhs.wch == rhs.wch && lhs.wchBefore == rhs.wchBefore && lhs.wchAfter < rhs.wchAfter );
|
||||
}
|
||||
|
||||
void *CLinuxFont::SetAsActiveFont( void *cglContext )
|
||||
{
|
||||
Assert( false );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Ensure that all of our internal structures are consistent, and
|
||||
// account for all memory that we've allocated.
|
||||
// Input: validator - Our global validator object
|
||||
// pchName - Our name (typically a member var in our container)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CLinuxFont::Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
validator.Push( "CLinuxFont", this, pchName );
|
||||
|
||||
m_ExtendedABCWidthsCache.Validate( validator, "m_ExtendedABCWidthsCache" );
|
||||
m_ExtendedKernedABCWidthsCache.Validate( validator, "m_ExtendedKernedABCWidthsCache" );
|
||||
validator.ClaimMemory( m_pGaussianDistribution );
|
||||
|
||||
validator.Pop();
|
||||
}
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
533
vgui2/vgui_surfacelib/osxfont.cpp
Normal file
533
vgui2/vgui_surfacelib/osxfont.cpp
Normal file
@@ -0,0 +1,533 @@
|
||||
//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <malloc.h>
|
||||
#include <tier0/dbg.h>
|
||||
#include <vgui/ISurface.h>
|
||||
#include <tier0/mem.h>
|
||||
#include <utlbuffer.h>
|
||||
#include <vstdlib/vstrtools.h>
|
||||
|
||||
#include "filesystem.h"
|
||||
#include "vgui_surfacelib/osxfont.h"
|
||||
#include "FontEffects.h"
|
||||
|
||||
#define DEBUG_FONT_CREATE 0
|
||||
|
||||
struct MetricsTweaks_t
|
||||
{
|
||||
const char *m_windowsFontName;
|
||||
int m_sizeAdjust;
|
||||
float m_ascentMultiplier;
|
||||
float m_descentMultiplier;
|
||||
float m_leadingMultiplier;
|
||||
};
|
||||
|
||||
static const MetricsTweaks_t g_defaultMetricTweaks = { NULL, 0, 1.0, 1.0, 1.0 };// -2, 1.0, 1.0, 1.0 };
|
||||
|
||||
static MetricsTweaks_t g_FontMetricTweaks[] =
|
||||
{
|
||||
{ "Helvetica", 0, 1.0, 1.0, 1.05 },
|
||||
{ "Helvetica Bold", 0, 1.0, 1.0, 1.0 },
|
||||
{ "HL2cross", 0, 0.8, 1.0, 1.1},
|
||||
{ "Counter-Strike Logo", 0, 1.0, 1.0, 1.1},
|
||||
{ "TF2", -2, 1.0, 1.0, 1.0 },
|
||||
{ "TF2 Professor", -2, 1.0, 1.1, 1.1 },
|
||||
{ "TF2 Build", -2, 1.0, 1.0, 1.0 },
|
||||
{ "UniversLTStd-BoldCn", 0, 1.4, 1.0, 0.8 },
|
||||
{ "UniversLTStd-Cn", 0, 1.2, 1.0, 1.0 },
|
||||
//{ "TF2 Secondary", -2, 1.0, 1.0, 1.0 },
|
||||
// { "Verdana", 0, 1.25, 1.0, 1.0 },
|
||||
};
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
COSXFont::COSXFont() : m_ExtendedABCWidthsCache(256, 0, &ExtendedABCWidthsCacheLessFunc),
|
||||
m_ExtendedKernedABCWidthsCache( 256, 0, &ExtendedKernedABCWidthsCacheLessFunc )
|
||||
{
|
||||
m_iTall = 0;
|
||||
m_iAscent = 0;
|
||||
m_iDescent = 0;
|
||||
m_iWeight = 0;
|
||||
m_iFlags = 0;
|
||||
m_iMaxCharWidth = 0;
|
||||
m_bAntiAliased = false;
|
||||
m_bUnderlined = false;
|
||||
m_iBlur = 0;
|
||||
m_pGaussianDistribution = NULL;
|
||||
m_iScanLines = 0;
|
||||
m_bRotary = false;
|
||||
m_bAdditive = false;
|
||||
m_ContextRef = 0;
|
||||
m_pContextMemory = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
COSXFont::~COSXFont()
|
||||
{
|
||||
if ( m_ContextRef )
|
||||
{
|
||||
CGContextRelease( m_ContextRef );
|
||||
}
|
||||
|
||||
if ( m_pContextMemory )
|
||||
delete [] m_pContextMemory;
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: creates the font from windows. returns false if font does not exist in the OS.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool COSXFont::Create(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
// setup font properties
|
||||
m_szName = windowsFontName;
|
||||
m_iTall = tall;
|
||||
m_iWeight = weight;
|
||||
m_iFlags = flags;
|
||||
m_bAntiAliased = flags & FONTFLAG_ANTIALIAS;
|
||||
#if 0
|
||||
// the font used in portal2 looks ok (better, in fact) anti-aliased when small,
|
||||
if ( tall < 20 )
|
||||
{
|
||||
m_bAntiAliased = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_bUnderlined = flags & FONTFLAG_UNDERLINE;
|
||||
m_iDropShadowOffset = (flags & FONTFLAG_DROPSHADOW) ? 1 : 0;
|
||||
m_iOutlineSize = (flags & FONTFLAG_OUTLINE) ? 1 : 0;
|
||||
m_iBlur = blur;
|
||||
m_iScanLines = scanlines;
|
||||
m_bRotary = flags & FONTFLAG_ROTARY;
|
||||
m_bAdditive = flags & FONTFLAG_ADDITIVE;
|
||||
|
||||
char sCustomPath[1024];
|
||||
Q_snprintf( sCustomPath, sizeof( sCustomPath ), "./platform/vgui/fonts/%s.ttf", windowsFontName );
|
||||
|
||||
if ( g_pFullFileSystem->FileExists( sCustomPath ) )
|
||||
{
|
||||
CFStringRef path = CFStringCreateWithCString( NULL, windowsFontName, kCFStringEncodingUTF8 );
|
||||
CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, false);
|
||||
CGDataProviderRef dataProvider = CGDataProviderCreateWithURL( url );
|
||||
CGFontRef cgFont = CGFontCreateWithDataProvider( dataProvider );
|
||||
m_hFont = CTFontCreateWithGraphicsFont( cgFont, tall, nullptr, nullptr );
|
||||
CFRelease( cgFont );
|
||||
CFRelease( dataProvider );
|
||||
CFRelease( url );
|
||||
CFRelease( path );
|
||||
|
||||
CTFontCopyCharacterSet(m_hFont);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
const void *pKeys[2];
|
||||
const void *pValues[2];
|
||||
|
||||
float fCTWeight = ( (float)( weight - 400 ) / 500.0f );
|
||||
pKeys[0] = kCTFontWeightTrait;
|
||||
pValues[0] = CFNumberCreate( NULL, kCFNumberFloatType, &fCTWeight );
|
||||
float fCTSlant = ( flags & FONTFLAG_ITALIC ) != 0 ? 1.0f : 0.0f;
|
||||
pKeys[1] = kCTFontSlantTrait;
|
||||
pValues[1] = CFNumberCreate( NULL, kCFNumberFloatType, &fCTSlant );
|
||||
|
||||
CFDictionaryRef pTraitsDict = CFDictionaryCreate( NULL, pKeys, pValues, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
|
||||
if ( !pTraitsDict )
|
||||
{
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
CFRelease( (CFNumberRef)pValues[0] );
|
||||
CFRelease( (CFNumberRef)pValues[1] );
|
||||
|
||||
pKeys[0] = kCTFontNameAttribute;
|
||||
pValues[0] = CFStringCreateWithCString( NULL, windowsFontName, kCFStringEncodingUTF8 );
|
||||
pKeys[1] = kCTFontTraitsAttribute;
|
||||
pValues[1] = pTraitsDict;
|
||||
|
||||
CFDictionaryRef pDescDict;
|
||||
|
||||
pDescDict = CFDictionaryCreate( NULL, pKeys, pValues, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
|
||||
|
||||
CFRelease( (CFStringRef)pValues[0] );
|
||||
CFRelease( pTraitsDict );
|
||||
|
||||
if ( !pDescDict )
|
||||
{
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
CTFontDescriptorRef pFontDesc;
|
||||
|
||||
pFontDesc = CTFontDescriptorCreateWithAttributes( pDescDict );
|
||||
|
||||
CFRelease( pDescDict );
|
||||
|
||||
if ( !pFontDesc )
|
||||
{
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
// Fudge the size of the font to something reasonable.
|
||||
m_hFont = CTFontCreateWithFontDescriptor( pFontDesc, int(tall*0.85), NULL );
|
||||
|
||||
CFRelease( pFontDesc );
|
||||
}
|
||||
|
||||
if ( !m_hFont )
|
||||
{
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
CGRect bbox;
|
||||
|
||||
bbox = CTFontGetBoundingBox( m_hFont );
|
||||
|
||||
m_iAscent = ceil( CTFontGetAscent( m_hFont ) );
|
||||
// The bounding box height seems to be overly large so use
|
||||
// ascent plus descent.
|
||||
m_iHeight = m_iAscent + ceil( CTFontGetDescent( m_hFont ) ) + m_iDropShadowOffset + 2 * m_iOutlineSize;
|
||||
m_iMaxCharWidth = ceil( bbox.size.width ) + 2 * m_iOutlineSize;
|
||||
|
||||
uint bytesPerRow;
|
||||
|
||||
bytesPerRow = m_iMaxCharWidth * 4;
|
||||
m_pContextMemory = new char[ (int)bytesPerRow * m_iHeight ];
|
||||
memset( m_pContextMemory, 0x0, (int)( bytesPerRow * m_iHeight) );
|
||||
|
||||
CGColorSpaceRef colorSpace;
|
||||
|
||||
colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
m_ContextRef = CGBitmapContextCreate( m_pContextMemory, m_iMaxCharWidth, m_iHeight,
|
||||
8,
|
||||
bytesPerRow,
|
||||
colorSpace,
|
||||
kCGImageAlphaPremultipliedLast );
|
||||
CGColorSpaceRelease( colorSpace );
|
||||
if ( !m_ContextRef )
|
||||
{
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
CGContextSetAllowsAntialiasing( m_ContextRef, m_bAntiAliased );
|
||||
CGContextSetShouldAntialias( m_ContextRef, m_bAntiAliased );
|
||||
CGContextSetTextDrawingMode( m_ContextRef, kCGTextFill );
|
||||
CGContextSetRGBStrokeColor( m_ContextRef, 1.0, 1.0, 1.0, 1.0 );
|
||||
CGContextSetLineWidth( m_ContextRef, 1 );
|
||||
|
||||
return true;
|
||||
|
||||
Fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void COSXFont::GetKernedCharWidth( wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA, float &abcC )
|
||||
{
|
||||
int a,b,c;
|
||||
GetCharABCWidths(ch, a, b, c );
|
||||
wide = ( a + b + c );
|
||||
abcA = a;
|
||||
abcC = c;
|
||||
}
|
||||
|
||||
static bool GetGlyphsForCharacter( CTFontRef hFont, wchar_t ch, CGGlyph* pGlyphs )
|
||||
{
|
||||
UniChar pUniChars[2];
|
||||
pUniChars[0] = ch;
|
||||
pUniChars[1] = 0;
|
||||
|
||||
if ( !CTFontGetGlyphsForCharacters( hFont, pUniChars, pGlyphs, 1 ) )
|
||||
{
|
||||
char str[2];
|
||||
str[0] = (char)ch;
|
||||
str[1] = 0;
|
||||
|
||||
CFStringRef s = CFStringCreateWithCString(nullptr, str, kTextEncodingUnicodeDefault);
|
||||
pGlyphs[0] = CTFontGetGlyphWithName(hFont, s);
|
||||
CFRelease( s );
|
||||
if ( !pGlyphs[0] )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: writes the char into the specified 32bpp texture
|
||||
//-----------------------------------------------------------------------------
|
||||
void COSXFont::GetCharRGBA( wchar_t ch, int rgbaWide, int rgbaTall, unsigned char *rgba )
|
||||
{
|
||||
wchar_t pWchars[1];
|
||||
pWchars[0] = (wchar_t)ch;
|
||||
|
||||
CGGlyph pGlyphs[1];
|
||||
|
||||
if ( !GetGlyphsForCharacter( m_hFont, ch, pGlyphs ) )
|
||||
{
|
||||
AssertMsg( false, "CTFontGetGlyphsForCharacters failed" );
|
||||
return;
|
||||
}
|
||||
|
||||
CGRect rect = { { 0, 0 }, { m_iMaxCharWidth, m_iHeight } };
|
||||
CGContextClearRect( m_ContextRef, rect );
|
||||
|
||||
CGRect pBounds[1];
|
||||
|
||||
CTFontGetBoundingRectsForGlyphs( m_hFont, kCTFontDefaultOrientation, pGlyphs, pBounds, 1 );
|
||||
|
||||
CGPoint pPositions[1];
|
||||
|
||||
// The character will be drawn offset by the 'A' distance so adjust
|
||||
// it back as this routine only wants the core bits.
|
||||
pPositions[0].x = m_iOutlineSize;
|
||||
// The DrawGlyphs coordinate system puts zero Y at the bottom of
|
||||
// the bitmap and puts the text baseline at zero Y so push
|
||||
// it up to place characters where we expect them.
|
||||
pPositions[0].y = ( m_iHeight - m_iAscent ) - m_iOutlineSize;
|
||||
|
||||
CTFontDrawGlyphs( m_hFont, pGlyphs, pPositions, 1, m_ContextRef );
|
||||
|
||||
CGContextFlush( m_ContextRef );
|
||||
|
||||
char *pContextData = (char *)CGBitmapContextGetData( m_ContextRef );
|
||||
|
||||
uint8 *pchPixelData = rgba;
|
||||
for ( int y = 0; y < rgbaTall; y++ )
|
||||
{
|
||||
char *row = pContextData + y * m_iMaxCharWidth * 4;
|
||||
for ( int x = 0; x < rgbaWide; x++ )
|
||||
{
|
||||
if ( row[0] || row[1] || row[2] || row[3] )
|
||||
{
|
||||
pchPixelData[0] = 0xff;
|
||||
pchPixelData[1] = 0xff;
|
||||
pchPixelData[2] = 0xff;
|
||||
pchPixelData[3] = row[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
pchPixelData[0] = 0;
|
||||
pchPixelData[1] = 0;
|
||||
pchPixelData[2] = 0;
|
||||
pchPixelData[3] = 0;
|
||||
}
|
||||
row += 4;
|
||||
pchPixelData += 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw top and bottom bars for character placement debugging.
|
||||
#if FORCE_CHAR_BOX_BOUNDS
|
||||
pchPixelData = rgba;
|
||||
for ( int x = 0; x < rgbaWide; x++ )
|
||||
{
|
||||
pchPixelData[0] = 0;
|
||||
pchPixelData[1] = 0;
|
||||
pchPixelData[2] = 0;
|
||||
pchPixelData[3] = 0xff;
|
||||
pchPixelData += 4;
|
||||
}
|
||||
pchPixelData = rgba + ( rgbaTall - 1 ) * rgbaWide * 4;
|
||||
for ( int x = 0; x < rgbaWide; x++ )
|
||||
{
|
||||
pchPixelData[0] = 0;
|
||||
pchPixelData[1] = 0;
|
||||
pchPixelData[2] = 0;
|
||||
pchPixelData[3] = 0xff;
|
||||
pchPixelData += 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
// apply requested effects in specified order
|
||||
ApplyDropShadowToTexture( rgbaWide, rgbaTall, rgba, m_iDropShadowOffset );
|
||||
ApplyOutlineToTexture( rgbaWide, rgbaTall, rgba, m_iOutlineSize );
|
||||
ApplyGaussianBlurToTexture( rgbaWide, rgbaTall, rgba, m_iBlur );
|
||||
ApplyScanlineEffectToTexture( rgbaWide, rgbaTall, rgba, m_iScanLines );
|
||||
ApplyRotaryEffectToTexture( rgbaWide, rgbaTall, rgba, m_bRotary );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the abc widths for a character
|
||||
//-----------------------------------------------------------------------------
|
||||
void COSXFont::GetCharABCWidths(int ch, int &a, int &b, int &c)
|
||||
{
|
||||
Assert(IsValid());
|
||||
|
||||
// look for it in the cache
|
||||
abc_cache_t finder = { (wchar_t)ch };
|
||||
|
||||
uint16 i = m_ExtendedABCWidthsCache.Find(finder);
|
||||
if (m_ExtendedABCWidthsCache.IsValidIndex(i))
|
||||
{
|
||||
a = m_ExtendedABCWidthsCache[i].abc.a;
|
||||
b = m_ExtendedABCWidthsCache[i].abc.b;
|
||||
c = m_ExtendedABCWidthsCache[i].abc.c;
|
||||
return;
|
||||
}
|
||||
|
||||
a = 0;
|
||||
b = 0;
|
||||
c = 0;
|
||||
|
||||
wchar_t pWchars[1];
|
||||
|
||||
pWchars[0] = (wchar_t)ch;
|
||||
|
||||
CGGlyph pGlyphs[1];
|
||||
|
||||
if ( !GetGlyphsForCharacter( m_hFont, ch, pGlyphs ) )
|
||||
{
|
||||
AssertMsg( false, "CTFontGetGlyphsForCharacters failed" );
|
||||
return;
|
||||
}
|
||||
|
||||
CGSize pAdvances[1];
|
||||
|
||||
CTFontGetAdvancesForGlyphs( m_hFont, kCTFontDefaultOrientation, pGlyphs, pAdvances, 1 );
|
||||
|
||||
CGRect pBounds[1];
|
||||
|
||||
CTFontGetBoundingRectsForGlyphs( m_hFont, kCTFontDefaultOrientation, pGlyphs, pBounds, 1 );
|
||||
|
||||
a = 0;
|
||||
b = ceil(pAdvances->width);
|
||||
c = 0;
|
||||
finder.abc.a = a;
|
||||
finder.abc.b = b;
|
||||
finder.abc.c = c;
|
||||
m_ExtendedABCWidthsCache.Insert( finder );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true if the font is equivalent to that specified
|
||||
//-----------------------------------------------------------------------------
|
||||
bool COSXFont::IsEqualTo(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
if (!Q_stricmp(windowsFontName, m_szName.String() )
|
||||
&& m_iTall == tall
|
||||
&& m_iWeight == weight
|
||||
&& m_iBlur == blur
|
||||
&& m_iFlags == flags)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true only if this font is valid for use
|
||||
//-----------------------------------------------------------------------------
|
||||
bool COSXFont::IsValid()
|
||||
{
|
||||
if ( !m_szName.IsEmpty() && m_szName.String()[0] )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the height of the font, in pixels
|
||||
//-----------------------------------------------------------------------------
|
||||
int COSXFont::GetHeight()
|
||||
{
|
||||
assert(IsValid());
|
||||
return m_iHeight;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the ascent of the font, in pixels (ascent=units above the base line)
|
||||
//-----------------------------------------------------------------------------
|
||||
int COSXFont::GetAscent()
|
||||
{
|
||||
assert(IsValid());
|
||||
return m_iAscent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the ascent of the font, in pixels (ascent=units above the base line)
|
||||
//-----------------------------------------------------------------------------
|
||||
int COSXFont::GetDescent()
|
||||
{
|
||||
assert(IsValid());
|
||||
return m_iDescent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the maximum width of a character, in pixels
|
||||
//-----------------------------------------------------------------------------
|
||||
int COSXFont::GetMaxCharWidth()
|
||||
{
|
||||
assert(IsValid());
|
||||
return m_iMaxCharWidth;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the flags used to make this font, used by the dynamic resizing code
|
||||
//-----------------------------------------------------------------------------
|
||||
int COSXFont::GetFlags()
|
||||
{
|
||||
return m_iFlags;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Comparison function for abc widths storage
|
||||
//-----------------------------------------------------------------------------
|
||||
bool COSXFont::ExtendedABCWidthsCacheLessFunc(const abc_cache_t &lhs, const abc_cache_t &rhs)
|
||||
{
|
||||
return lhs.wch < rhs.wch;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Comparison function for abc widths storage
|
||||
//-----------------------------------------------------------------------------
|
||||
bool COSXFont::ExtendedKernedABCWidthsCacheLessFunc(const kerned_abc_cache_t &lhs, const kerned_abc_cache_t &rhs)
|
||||
{
|
||||
return lhs.wch < rhs.wch || ( lhs.wch == rhs.wch && lhs.wchBefore < rhs.wchBefore )
|
||||
|| ( lhs.wch == rhs.wch && lhs.wchBefore == rhs.wchBefore && lhs.wchAfter < rhs.wchAfter );
|
||||
}
|
||||
|
||||
|
||||
void *COSXFont::SetAsActiveFont( CGContextRef cgContext )
|
||||
{
|
||||
CGContextSelectFont ( cgContext, m_szName.String(), m_iHeight, kCGEncodingMacRoman);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Ensure that all of our internal structures are consistent, and
|
||||
// account for all memory that we've allocated.
|
||||
// Input: validator - Our global validator object
|
||||
// pchName - Our name (typically a member var in our container)
|
||||
//-----------------------------------------------------------------------------
|
||||
void COSXFont::Validate( CValidator &validator, char *pchName )
|
||||
{
|
||||
validator.Push( "COSXFont", this, pchName );
|
||||
|
||||
m_ExtendedABCWidthsCache.Validate( validator, "m_ExtendedABCWidthsCache" );
|
||||
m_ExtendedKernedABCWidthsCache.Validate( validator, "m_ExtendedKernedABCWidthsCache" );
|
||||
validator.ClaimMemory( m_pGaussianDistribution );
|
||||
|
||||
validator.Pop();
|
||||
}
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
422
vgui2/vgui_surfacelib/ps3font.cpp
Normal file
422
vgui2/vgui_surfacelib/ps3font.cpp
Normal file
@@ -0,0 +1,422 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: PS3 support for TrueType Fonts as hastily bastardized from Xbox 360 code.
|
||||
// On 360, the only solution is to use XUI
|
||||
// to mount the TTF, and rasterize glyph into a render target. XUI does not support
|
||||
// rasterization directly to a system memory region.
|
||||
// On PS3 that is not a problem, but rather than reimplement this whole class,
|
||||
// the minimal-code-change approach is just to patch some functions in shaderapi,
|
||||
// even though we don't need to do the work in shaderapi. I hang my head in shame
|
||||
// for this unworthy laziness/haste.
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <tier0/dbg.h>
|
||||
#include <vgui/ISurface.h>
|
||||
#include <tier0/mem.h>
|
||||
#include <utlbuffer.h>
|
||||
#include "filesystem.h"
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "FontEffects.h"
|
||||
#include "vgui_surfacelib/vguifont.h"
|
||||
#include "vgui_surfacelib/FontManager.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
bool s_bSupportsUnicode = true;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Determine possible style from parameters.
|
||||
//-----------------------------------------------------------------------------
|
||||
int GetStyleFromParameters( int iFlags, int iWeight )
|
||||
{
|
||||
// Available xbox TTF styles are very restricted.
|
||||
int style = CPS3Font::kFONT_STYLE_NORMAL;
|
||||
if ( iFlags & FONTFLAG_ITALIC )
|
||||
style |= CPS3Font::kFONT_STYLE_ITALIC;
|
||||
if ( iFlags & FONTFLAG_UNDERLINE )
|
||||
style |= CPS3Font::kFONT_STYLE_UNDERLINE;
|
||||
if ( iWeight > 400 )
|
||||
style |= CPS3Font::kFONT_STYLE_BOLD;
|
||||
return style;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CPS3Font::CPS3Font() : m_ExtendedABCWidthsCache( 256, 0, &ExtendedABCWidthsCacheLessFunc )
|
||||
{
|
||||
m_szName = UTL_INVAL_SYMBOL;
|
||||
m_iTall = 0;
|
||||
m_iWeight = 0;
|
||||
m_iHeight = 0;
|
||||
m_iAscent = 0;
|
||||
m_iFlags = 0;
|
||||
m_iMaxCharWidth = 0;
|
||||
m_hFont = NULL;
|
||||
m_bAntiAliased = false;
|
||||
m_bUnderlined = false;
|
||||
m_iBlur = 0;
|
||||
m_iScanLines = 0;
|
||||
m_bRotary = false;
|
||||
m_bAdditive = false;
|
||||
m_rgiBitmapSize[0] = 0;
|
||||
m_rgiBitmapSize[1] = 0;
|
||||
|
||||
s_bSupportsUnicode = true;
|
||||
|
||||
Q_memset( m_ABCWidthsCache, 0, sizeof( m_ABCWidthsCache ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CPS3Font::~CPS3Font()
|
||||
{
|
||||
if ( m_hFont != NULL )
|
||||
{
|
||||
// many fonts are blindly precached by vgui and never used
|
||||
// save memory and don't hold font open, re-open if glyph actually requested used during draw
|
||||
if ( IMaterialSystem *pMS = FontManager().MaterialSystem() )
|
||||
pMS->CloseTrueTypeFont( m_hFont );
|
||||
}
|
||||
m_hFont = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates the font.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPS3Font::Create( const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags )
|
||||
{
|
||||
// setup font properties
|
||||
m_iTall = tall;
|
||||
m_iWeight = weight;
|
||||
m_iFlags = flags;
|
||||
m_bAntiAliased = (flags & FONTFLAG_ANTIALIAS) ? 1 : 0;
|
||||
m_bUnderlined = (flags & FONTFLAG_UNDERLINE) ? 1 : 0;
|
||||
m_iDropShadowOffset = (flags & FONTFLAG_DROPSHADOW) ? 1 : 0;
|
||||
m_iOutlineSize = (flags & FONTFLAG_OUTLINE) ? 1 : 0;
|
||||
m_iBlur = blur;
|
||||
m_iScanLines = scanlines;
|
||||
m_bRotary = (flags & FONTFLAG_ROTARY) ? 1 : 0;
|
||||
m_bAdditive = (flags & FONTFLAG_ADDITIVE) ? 1 : 0;
|
||||
|
||||
int style = GetStyleFromParameters( flags, weight );
|
||||
|
||||
// must support > 128, there are characters in this range in the custom fonts
|
||||
COMPILE_TIME_ASSERT( ABCWIDTHS_CACHE_SIZE == 256 );
|
||||
|
||||
CPS3FontMetrics fontMetrics;
|
||||
CPS3CharMetrics charMetrics[ABCWIDTHS_CACHE_SIZE];
|
||||
|
||||
// many redundant requests are made that are actually the same font metrics
|
||||
// find it in the metric cache first based on the true specific keys
|
||||
if ( !FontManager().GetCachedPS3Metrics( windowsFontName, tall, style, &fontMetrics, charMetrics ) )
|
||||
{
|
||||
if ( !m_hFont )
|
||||
{
|
||||
m_hFont = FontManager().MaterialSystem()->OpenTrueTypeFont( windowsFontName, tall, style );
|
||||
// no you're not seeing double
|
||||
if ( !m_hFont )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// get the predominant font metrics now [1-255], the extended set [256-65535] is on-demand
|
||||
FontManager().MaterialSystem()->GetTrueTypeFontMetrics( m_hFont, m_iTall, 1, 255, &fontMetrics, &charMetrics[1] );
|
||||
|
||||
// getting the metrics is an expensive i/o operation, cache results
|
||||
FontManager().SetCachedPS3Metrics( windowsFontName, tall, style, &fontMetrics, charMetrics );
|
||||
}
|
||||
|
||||
m_szName = windowsFontName;
|
||||
|
||||
m_iHeight = fontMetrics.lineHeight + fontMetrics.effectHeight + m_iDropShadowOffset + 2 * m_iOutlineSize;
|
||||
m_iMaxCharWidth = ceilf(fontMetrics.fMaxWidth);
|
||||
m_iAscent = fontMetrics.baseLineY;
|
||||
|
||||
// determine cell bounds
|
||||
m_rgiBitmapSize[0] = m_iMaxCharWidth + m_iOutlineSize * 2;
|
||||
m_rgiBitmapSize[1] = m_iHeight;
|
||||
|
||||
// get char spacing
|
||||
// a is space before character (can be negative)
|
||||
// b is the width of the character
|
||||
// c is the space after the character
|
||||
Assert( ABCWIDTHS_CACHE_SIZE <= 256 );
|
||||
Q_memset( m_ABCWidthsCache, 0, sizeof( m_ABCWidthsCache ) );
|
||||
|
||||
for ( int i = 1; i < ABCWIDTHS_CACHE_SIZE; i++ )
|
||||
{
|
||||
int a,b,c;
|
||||
|
||||
/*
|
||||
// Determine real a,b,c mapping from XUI Character Metrics
|
||||
a = charMetrics[i].fMinX - 1; // Add one column of padding to make up for font rendering blurring into left column (and adjust in b)
|
||||
b = charMetrics[i].fMaxX - charMetrics[i].fMinX + 1;
|
||||
c = charMetrics[i].fAdvance - charMetrics[i].fMaxX; // NOTE: We probably should add a column here, but it's rarely needed in our current fonts so we're opting to save memory instead
|
||||
*/
|
||||
a = charMetrics[i].A();
|
||||
b = charMetrics[i].B();
|
||||
c = charMetrics[i].C();
|
||||
|
||||
// Widen for blur, outline, and shadow. Need to widen b and reduce a and c.
|
||||
m_ABCWidthsCache[i].a = a - m_iOutlineSize;
|
||||
m_ABCWidthsCache[i].b = b + ( ( m_iBlur + m_iOutlineSize ) * 2 ) + m_iDropShadowOffset;
|
||||
m_ABCWidthsCache[i].c = c - 2*m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: generates texture data (written into appropriate font page subrects) for multiple chars
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPS3Font::GetCharsRGBA( newChar_t *newChars, int numNewChars, unsigned char *pRGBA )
|
||||
{
|
||||
if ( !m_hFont )
|
||||
{
|
||||
// demand request for font glyph, re-create font
|
||||
int style = GetStyleFromParameters( m_iFlags, m_iWeight );
|
||||
m_hFont = FontManager().MaterialSystem()->OpenTrueTypeFont( GetName(), m_iTall, style );
|
||||
}
|
||||
|
||||
wchar_t *pWch = (wchar_t *)_alloca( numNewChars*sizeof(wchar_t) );
|
||||
int *pOffsetX = (int *)_alloca( numNewChars*sizeof(int) );
|
||||
int *pOffsetY = (int *)_alloca( numNewChars*sizeof(int) );
|
||||
int *pWidth = (int *)_alloca( numNewChars*sizeof(int) );
|
||||
int *pHeight = (int *)_alloca( numNewChars*sizeof(int) );
|
||||
int *pRGBAOffset = (int *)_alloca( numNewChars*sizeof(int) );
|
||||
for ( int i = 0; i < numNewChars; i++ )
|
||||
{
|
||||
int a, c, wide;
|
||||
GetCharABCWidths( newChars[i].wch, a, wide, c );
|
||||
pWch[i] = newChars[i].wch;
|
||||
pOffsetX[i] = -a;
|
||||
pOffsetY[i] = 0;
|
||||
pWidth[i] = newChars[i].fontWide;
|
||||
pHeight[i] = newChars[i].fontTall;
|
||||
pRGBAOffset[i] = newChars[i].offset;
|
||||
}
|
||||
if ( !FontManager().MaterialSystem()->GetTrueTypeGlyphs( m_hFont, m_iTall, numNewChars, pWch, pOffsetX, pOffsetY, pWidth, pHeight, pRGBA, pRGBAOffset ) )
|
||||
{
|
||||
// failure
|
||||
return;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < numNewChars; i++ )
|
||||
{
|
||||
// apply requested effects in specified order
|
||||
unsigned char *pCharRGBA = pRGBA + newChars[i].offset;
|
||||
ApplyDropShadowToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iDropShadowOffset );
|
||||
ApplyOutlineToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iOutlineSize );
|
||||
ApplyGaussianBlurToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iBlur );
|
||||
ApplyScanlineEffectToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_iScanLines );
|
||||
ApplyRotaryEffectToTexture( newChars[i].fontWide, newChars[i].fontTall, pCharRGBA, m_bRotary );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: writes the char into the specified 32bpp texture at specified rect
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPS3Font::GetCharRGBA( wchar_t ch, int rgbaWide, int rgbaTall, unsigned char *pRGBA )
|
||||
{
|
||||
newChar_t newChar;
|
||||
newChar.wch = ch;
|
||||
newChar.fontWide = rgbaWide;
|
||||
newChar.fontTall = rgbaTall;
|
||||
newChar.offset = 0;
|
||||
GetCharsRGBA( &newChar, 1, pRGBA );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true if the font is equivalent to that specified
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPS3Font::IsEqualTo(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
// do an true comparison that accounts for non-supported behaviors that gets remapped
|
||||
// avoids creating fonts that are graphically equivalent, though specified differently
|
||||
if ( !stricmp( windowsFontName, m_szName.String() ) &&
|
||||
m_iTall == tall &&
|
||||
m_iBlur == blur &&
|
||||
m_iScanLines == scanlines )
|
||||
{
|
||||
// only these flags affect the font glyphs
|
||||
int validFlags = FONTFLAG_DROPSHADOW |
|
||||
FONTFLAG_OUTLINE |
|
||||
FONTFLAG_ROTARY |
|
||||
FONTFLAG_ITALIC |
|
||||
FONTFLAG_UNDERLINE;
|
||||
if ( ( m_iFlags & validFlags ) == ( flags & validFlags ) )
|
||||
{
|
||||
if ( GetStyleFromParameters( m_iFlags, m_iWeight ) == GetStyleFromParameters( flags, weight ) )
|
||||
{
|
||||
// the font is equivalent
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns true only if this font is valid for use
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPS3Font::IsValid()
|
||||
{
|
||||
if ( m_szName != UTL_INVAL_SYMBOL )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the abc widths for a character
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPS3Font::GetCharABCWidths( int ch, int &a, int &b, int &c )
|
||||
{
|
||||
Assert( IsValid() );
|
||||
|
||||
if ( ch < ABCWIDTHS_CACHE_SIZE )
|
||||
{
|
||||
// use the cache entry
|
||||
a = m_ABCWidthsCache[ch].a;
|
||||
b = m_ABCWidthsCache[ch].b;
|
||||
c = m_ABCWidthsCache[ch].c;
|
||||
}
|
||||
else
|
||||
{
|
||||
// look for it in the extended cache
|
||||
abc_cache_t finder = { (wchar_t)ch };
|
||||
unsigned short i = m_ExtendedABCWidthsCache.Find( finder );
|
||||
if ( m_ExtendedABCWidthsCache.IsValidIndex( i ) )
|
||||
{
|
||||
a = m_ExtendedABCWidthsCache[i].abc.a;
|
||||
b = m_ExtendedABCWidthsCache[i].abc.b;
|
||||
c = m_ExtendedABCWidthsCache[i].abc.c;
|
||||
return;
|
||||
}
|
||||
|
||||
// not in the cache, get from system
|
||||
// getting the metrics is an expensive i/o operation
|
||||
if ( !m_hFont )
|
||||
{
|
||||
// demand request for font metrics, re-open font
|
||||
int style = GetStyleFromParameters( m_iFlags, m_iWeight );
|
||||
m_hFont = FontManager().MaterialSystem()->OpenTrueTypeFont( GetName(), m_iTall, style );
|
||||
}
|
||||
|
||||
if ( m_hFont )
|
||||
{
|
||||
CPS3FontMetrics fontMetrics;
|
||||
CPS3CharMetrics charMetrics;
|
||||
FontManager().MaterialSystem()->GetTrueTypeFontMetrics( m_hFont, m_iTall, ch, ch, &fontMetrics, &charMetrics );
|
||||
|
||||
/*
|
||||
// Determine real a,b,c mapping from XUI Character Metrics
|
||||
a = charMetrics.fMinX - 1; // Add one column of padding to make up for font rendering blurring into left column (and adjust in b)
|
||||
b = charMetrics.fMaxX - charMetrics.fMinX + 1;
|
||||
c = charMetrics.fAdvance - charMetrics.fMaxX; // NOTE: We probably should add a column here, but it's rarely needed in our current fonts so we're opting to save memory instead
|
||||
*/
|
||||
|
||||
a = charMetrics.A();
|
||||
b = charMetrics.B();
|
||||
c = charMetrics.C();
|
||||
|
||||
// Widen for blur, outline, and shadow. Need to widen b and reduce a and c.
|
||||
a = a - m_iOutlineSize;
|
||||
b = b + ( ( m_iBlur + m_iOutlineSize ) * 2 ) + m_iDropShadowOffset;
|
||||
c = c - 2*m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = 0;
|
||||
b = 0;
|
||||
c = 0;
|
||||
}
|
||||
|
||||
// add to the cache
|
||||
finder.abc.a = a;
|
||||
finder.abc.b = b;
|
||||
finder.abc.c = c;
|
||||
m_ExtendedABCWidthsCache.Insert( finder );
|
||||
}
|
||||
}
|
||||
|
||||
void CPS3Font::GetKernedCharWidth( wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA, float &abcC )
|
||||
{
|
||||
int a, b, c;
|
||||
GetCharABCWidths( ch, a, b, c );
|
||||
wide = a+b+c;
|
||||
abcA = a;
|
||||
abcC = c;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the height of the font, in pixels
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPS3Font::GetHeight()
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return m_iHeight;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the ascent of the font, in pixels (ascent=units above the base line)
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPS3Font::GetAscent()
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return m_iAscent;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the maximum width of a character, in pixels
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPS3Font::GetMaxCharWidth()
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return m_iMaxCharWidth;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: returns the flags used to make this font, used by the dynamic resizing code
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPS3Font::GetFlags()
|
||||
{
|
||||
Assert( IsValid() );
|
||||
return m_iFlags;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Comparison function for abc widths storage
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPS3Font::ExtendedABCWidthsCacheLessFunc( const abc_cache_t &lhs, const abc_cache_t &rhs )
|
||||
{
|
||||
return lhs.wch < rhs.wch;
|
||||
}
|
||||
|
||||
void CPS3Font::CloseResource()
|
||||
{
|
||||
if ( !m_hFont )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// many fonts are blindly precached by vgui and never used
|
||||
// save memory and don't hold font open, re-open if glyph actually requested used during draw
|
||||
FontManager().MaterialSystem()->CloseTrueTypeFont( m_hFont );
|
||||
m_hFont = NULL;
|
||||
}
|
||||
1471
vgui2/vgui_surfacelib/texturedictionary.cpp
Normal file
1471
vgui2/vgui_surfacelib/texturedictionary.cpp
Normal file
File diff suppressed because it is too large
Load Diff
61
vgui2/vgui_surfacelib/texturedictionary.h
Normal file
61
vgui2/vgui_surfacelib/texturedictionary.h
Normal file
@@ -0,0 +1,61 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Contains all texture state for the material system surface to use
|
||||
//
|
||||
// $Revision: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TEXTUREDICTIONARY_H
|
||||
#define TEXTUREDICTIONARY_H
|
||||
|
||||
class IMaterial;
|
||||
|
||||
enum
|
||||
{
|
||||
INVALID_TEXTURE_ID = -1
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// A class that manages textures used by the material system surface
|
||||
//-----------------------------------------------------------------------------
|
||||
class ITextureDictionary
|
||||
{
|
||||
public:
|
||||
// Create, destroy textures
|
||||
virtual int CreateTexture( bool procedural = false ) = 0;
|
||||
virtual void DestroyTexture( int id ) = 0;
|
||||
virtual void DestroyAllTextures() = 0;
|
||||
|
||||
// Is this a valid id?
|
||||
virtual bool IsValidId( int id ) const = 0;
|
||||
|
||||
// Binds a material to a texture
|
||||
virtual void BindTextureToFile( int id, const char *pFileName ) = 0;
|
||||
|
||||
// Binds a material to a texture
|
||||
virtual void BindTextureToMaterial( int id, IMaterial *pMaterial ) = 0;
|
||||
|
||||
// Binds a material to a texture
|
||||
virtual void BindTextureToMaterialReference( int id, int referenceId, IMaterial *pMaterial ) = 0;
|
||||
|
||||
// Texture info
|
||||
virtual IMaterial *GetTextureMaterial( int id ) = 0;
|
||||
virtual void GetTextureSize(int id, int& iWide, int& iTall ) = 0;
|
||||
virtual void GetTextureTexCoords( int id, float &s0, float &t0, float &s1, float &t1 ) = 0;
|
||||
|
||||
virtual void SetTextureRGBA( int id, const char* rgba, int wide, int tall ) = 0;
|
||||
|
||||
virtual int FindTextureIdForTextureFile( char const *pFileName ) = 0;
|
||||
virtual void SetSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall ) = 0;
|
||||
virtual void SetSubTextureRGBAEx( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat format ) = 0;
|
||||
|
||||
virtual void SetTextureRGBAEx( int id, const char* rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoordsForDimensions ) = 0;
|
||||
|
||||
virtual void UpdateSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat ) = 0;
|
||||
};
|
||||
|
||||
ITextureDictionary *TextureDictionary();
|
||||
|
||||
#endif // TEXTUREDICTIONARY_H
|
||||
60
vgui2/vgui_surfacelib/vgui_surfacelib.vpc
Normal file
60
vgui2/vgui_surfacelib/vgui_surfacelib.vpc
Normal file
@@ -0,0 +1,60 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// VGUI_SURFACELIB.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$macro SRCDIR "..\.."
|
||||
|
||||
$include "$SRCDIR\vpc_scripts\source_lib_base.vpc"
|
||||
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$PreprocessorDefinitions "$BASE;ALLOW_TEXT_MODE=1" [$CSTRIKE_TRUNK_BUILD||$CSTRIKE_STAGING_BUILD]
|
||||
}
|
||||
}
|
||||
|
||||
$Project "vgui_surfacelib"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "BitmapFont.cpp"
|
||||
$File "FontAmalgam.cpp"
|
||||
$File "fontmanager.cpp"
|
||||
$File "FontEffects.cpp"
|
||||
$File "FontEffects.h"
|
||||
$File "fonttexturecache.cpp"
|
||||
$File "texturedictionary.cpp"
|
||||
$File "Win32Font.cpp" [$WINDOWS]
|
||||
$File "Win32Font_x360.cpp" [$X360]
|
||||
$File "ps3font.cpp" [$PS3]
|
||||
$File "osxfont.cpp" [$OSXALL]
|
||||
$File "linuxfont.cpp" [$LINUXALL]
|
||||
}
|
||||
|
||||
$Folder "Public Header Files"
|
||||
{
|
||||
$File "$SRCDIR\public\tier0\basetypes.h"
|
||||
$File "$SRCDIR\common\vgui_surfacelib\BitmapFont.h"
|
||||
$File "$SRCDIR\common\vgui_surfacelib\FontAmalgam.h"
|
||||
$File "$SRCDIR\common\vgui_surfacelib\fontmanager.h"
|
||||
$File "$SRCDIR\common\vgui_surfacelib\fonttexturecache.h"
|
||||
$File "$SRCDIR\common\vgui_surfacelib\ifontsurface.h"
|
||||
$File "$SRCDIR\common\vgui_surfacelib\texturedictionary.h"
|
||||
$File "$SRCDIR\public\appframework\iappsystem.h"
|
||||
$File "$SRCDIR\public\tier1\interface.h"
|
||||
$File "$SRCDIR\public\tier1\strtools.h"
|
||||
$File "$SRCDIR\public\tier1\utlbuffer.h"
|
||||
$File "$SRCDIR\public\tier1\utlmemory.h"
|
||||
$File "$SRCDIR\public\tier1\utlvector.h"
|
||||
$File "$SRCDIR\public\mathlib\vector2d.h"
|
||||
$File "$SRCDIR\public\vstdlib\vstdlib.h"
|
||||
$File "$SRCDIR\common\vgui_surfacelib\vguifont.h"
|
||||
$File "$SRCDIR\common\vgui_surfacelib\Win32Font.h" [$WINDOWS]
|
||||
$File "$SRCDIR\common\vgui_surfacelib\ps3font.h" [$PS3]
|
||||
$File "$SRCDIR\common\vgui_surfacelib\osxfont.h" [$OSXALL]
|
||||
}
|
||||
}
|
||||
13
vgui2/vgui_surfacelib/vgui_surfacelib.vpc.vpc_cache
Normal file
13
vgui2/vgui_surfacelib/vgui_surfacelib.vpc.vpc_cache
Normal file
@@ -0,0 +1,13 @@
|
||||
"vpc_cache"
|
||||
{
|
||||
"CacheVersion" "1"
|
||||
"win32"
|
||||
{
|
||||
"CRCFile" "vgui_surfacelib.vcxproj.vpc_crc"
|
||||
"OutputFiles"
|
||||
{
|
||||
"0" "vgui_surfacelib.vcxproj"
|
||||
"1" "vgui_surfacelib.vcxproj.filters"
|
||||
}
|
||||
}
|
||||
}
|
||||
2
vgui2/vgui_surfacelib/vsi.nul
Normal file
2
vgui2/vgui_surfacelib/vsi.nul
Normal file
@@ -0,0 +1,2 @@
|
||||
SN Visual Studio Integration
|
||||
IMPORTANT: Do not remove the custom build step for this file
|
||||
213
vgui2/vgui_surfacelib/win32font_ps3.cpp
Normal file
213
vgui2/vgui_surfacelib/win32font_ps3.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: PS3 support for true type fonts.
|
||||
//
|
||||
//=====================================================================================//
|
||||
|
||||
#if 0 // clipped for now
|
||||
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "vgui_surfacelib/Win32Font.h"
|
||||
#include "vgui_surfacelib/FontManager.h"
|
||||
#include "../materialsystem/ifont.h"
|
||||
#include "FontEffects.h"
|
||||
#include <vgui/ISurface.h>
|
||||
|
||||
CWin32Font::CWin32Font() : m_ExtendedABCWidthsCache(256, 0, &ExtendedABCWidthsCacheLessFunc)
|
||||
{
|
||||
m_pFont = NULL;
|
||||
}
|
||||
|
||||
CWin32Font::~CWin32Font()
|
||||
{
|
||||
//FontManager().MaterialSystem()->CloseTrueTypeFont(m_pFont);
|
||||
|
||||
m_pFont = NULL;
|
||||
}
|
||||
|
||||
// Create the font
|
||||
bool CWin32Font::Create(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
// setup font properties
|
||||
m_iTall = tall;
|
||||
m_iWeight = weight;
|
||||
m_iFlags = flags;
|
||||
m_bAntiAliased = (flags & FONTFLAG_ANTIALIAS) ? 1 : 0;
|
||||
m_iDropShadowOffset = (flags & FONTFLAG_DROPSHADOW) ? 1 : 0;
|
||||
m_iOutlineSize = (flags & FONTFLAG_OUTLINE) ? 1 : 0;
|
||||
m_iBlur = blur;
|
||||
m_iScanLines = scanlines;
|
||||
m_bRotary = (flags & FONTFLAG_ROTARY) ? 1 : 0;
|
||||
m_bAdditive = (flags & FONTFLAG_ADDITIVE) ? 1 : 0;
|
||||
m_szName = windowsFontName;
|
||||
|
||||
// if the weight is greater that 400, set the style to bold (cf win32font_x360)
|
||||
// By default use the regular style
|
||||
m_iWeight = 0x10000 ; // ONE16Dot16 1.0f (F16Dot16 format used by font fusion)
|
||||
if ( weight > 400 )
|
||||
{
|
||||
m_iWeight = 5L << 14; // 1.25 (F16Dot16 format used by font fusion)
|
||||
}
|
||||
|
||||
// Open the font
|
||||
ExecuteNTimes( 5, Warning( "Fonts dont work on PS3\n" ) );
|
||||
//m_pFont = FontManager().MaterialSystem()->OpenTrueTypeFont(windowsFontName, tall, m_iWeight);
|
||||
if(m_pFont == NULL)
|
||||
{
|
||||
Warning("Failed to open font %s\n", windowsFontName);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the font parameters
|
||||
m_iHeight = m_pFont->GetMaxHeight();
|
||||
m_iAscent = m_pFont->GetAscent();
|
||||
m_iMaxCharWidth = m_pFont->GetMaxWidth();
|
||||
|
||||
// Setup ABC cache
|
||||
// get char spacing
|
||||
// a is space before character (can be negative)
|
||||
// b is the width of the character
|
||||
// c is the space after the character
|
||||
memset(m_ABCWidthsCache, 0, sizeof(m_ABCWidthsCache));
|
||||
for(int i = 0; i < ABCWIDTHS_CACHE_SIZE; i++)
|
||||
{
|
||||
int a,b,c;
|
||||
a = 0;
|
||||
b = 0;
|
||||
c = 0;
|
||||
m_pFont->GetCharABCWidth(i, a, b, c);
|
||||
|
||||
m_ABCWidthsCache[i].a = a - m_iBlur;
|
||||
m_ABCWidthsCache[i].b = b + m_iBlur*2;
|
||||
m_ABCWidthsCache[i].c = c - m_iBlur;
|
||||
}
|
||||
|
||||
// many fonts are blindly precached by vgui and never used
|
||||
// save memory and don't hold font open, re-open if glyph actually requested used during draw
|
||||
Assert( 0 );
|
||||
//FontManager().MaterialSystem()->CloseTrueTypeFont( m_pFont );
|
||||
m_pFont = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Render the font to a buffer
|
||||
void CWin32Font::GetCharRGBA(wchar_t ch, int rgbaWide, int rgbaTall, unsigned char *rgba)
|
||||
{
|
||||
if ( ch == '\t' )
|
||||
{
|
||||
// tabs don't draw
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !m_pFont )
|
||||
{
|
||||
// demand request for font glyph, re-create font
|
||||
Assert( 0 );
|
||||
//m_pFont = FontManager().MaterialSystem()->OpenTrueTypeFont(GetName(), m_iTall, m_iWeight);
|
||||
}
|
||||
|
||||
int a, c, wide, tall;
|
||||
GetCharABCWidths( ch, a, wide, c );
|
||||
tall = m_iHeight;
|
||||
|
||||
m_pFont->RenderToBuffer(ch, m_iBlur, rgbaWide, rgbaTall, rgba);
|
||||
|
||||
// apply requested effects in specified order
|
||||
//ApplyDropShadowToTexture( rgbaX, rgbaY, rgbaWide, rgbaTall, wide, tall, rgba, m_iDropShadowOffset );
|
||||
//ApplyOutlineToTexture( rgbaX, rgbaY, rgbaWide, rgbaTall, wide, tall, rgba, m_iOutlineSize );
|
||||
ApplyGaussianBlurToTexture( rgbaWide, rgbaTall, rgba, m_iBlur );
|
||||
ApplyScanlineEffectToTexture( rgbaWide, rgbaTall, rgba, m_iScanLines );
|
||||
//ApplyRotaryEffectToTexture( rgbaX, rgbaY, rgbaWide, rgbaTall, rgba, m_bRotary );
|
||||
}
|
||||
|
||||
bool CWin32Font::IsEqualTo(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
|
||||
{
|
||||
if ( !stricmp(windowsFontName, m_szName.String() )
|
||||
&& m_iTall == tall
|
||||
&& m_iWeight == weight
|
||||
&& m_iBlur == blur
|
||||
&& m_iScanLines == scanlines)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CWin32Font::IsValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Font metrics
|
||||
void CWin32Font::GetCharABCWidths(int ch, int &a, int &b, int &c)
|
||||
{
|
||||
Assert( IsValid() );
|
||||
if (ch < ABCWIDTHS_CACHE_SIZE)
|
||||
{
|
||||
// use the cache entry
|
||||
a = m_ABCWidthsCache[ch].a;
|
||||
b = m_ABCWidthsCache[ch].b;
|
||||
c = m_ABCWidthsCache[ch].c;
|
||||
}
|
||||
else
|
||||
{
|
||||
// look for it in the cache
|
||||
abc_cache_t finder = { (wchar_t)ch };
|
||||
|
||||
unsigned short i = m_ExtendedABCWidthsCache.Find(finder);
|
||||
if (m_ExtendedABCWidthsCache.IsValidIndex(i))
|
||||
{
|
||||
a = m_ExtendedABCWidthsCache[i].abc.a;
|
||||
b = m_ExtendedABCWidthsCache[i].abc.b;
|
||||
c = m_ExtendedABCWidthsCache[i].abc.c;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!m_pFont)
|
||||
{
|
||||
//BRAD: In some instances (e.g. when you try and create an EAOnline account) it tries
|
||||
// to call GetCharABCWidths before GetCharRGBA so m_pFont is not opened.
|
||||
// demand request for font glyph, re-create font
|
||||
Assert( 0 );
|
||||
//m_pFont = FontManager().MaterialSystem()->OpenTrueTypeFont(GetName(), m_iTall, m_iWeight);
|
||||
|
||||
}
|
||||
m_pFont->GetCharABCWidth(ch, a, b, c);
|
||||
|
||||
// add to the cache
|
||||
finder.abc.a = a;
|
||||
finder.abc.b = b;
|
||||
finder.abc.c = c;
|
||||
m_ExtendedABCWidthsCache.Insert(finder);
|
||||
}
|
||||
}
|
||||
|
||||
int CWin32Font::GetHeight()
|
||||
{
|
||||
return m_iHeight;
|
||||
}
|
||||
|
||||
int CWin32Font::GetAscent()
|
||||
{
|
||||
return m_iAscent;
|
||||
}
|
||||
|
||||
int CWin32Font::GetMaxCharWidth()
|
||||
{
|
||||
return m_iMaxCharWidth;
|
||||
}
|
||||
|
||||
int CWin32Font::GetFlags()
|
||||
{
|
||||
return m_iFlags;
|
||||
}
|
||||
|
||||
bool CWin32Font::ExtendedABCWidthsCacheLessFunc(const abc_cache_t &lhs, const abc_cache_t &rhs)
|
||||
{
|
||||
return lhs.wch < rhs.wch;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user