You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1485 lines
38 KiB
1485 lines
38 KiB
5 years ago
|
//-----------------------------------------------------------------------------
|
||
|
// Name: Glyphs.cpp
|
||
|
//
|
||
|
// Desc: Functions and global variables for keeping track of font glyphs
|
||
|
//
|
||
|
// Hist: 09.06.02 - Revised Fontmaker sample
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
#include "stdafx.h"
|
||
|
#include "Glyphs.h"
|
||
|
#include "FontMaker.h"
|
||
|
|
||
|
const COLORREF COLOR_WHITE = RGB(255,255,255);
|
||
|
const COLORREF COLOR_BLACK = RGB( 0, 0, 0);
|
||
|
const COLORREF COLOR_BLUE = RGB( 0, 0,255);
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: CTextureFont()
|
||
|
// Desc: Constructor
|
||
|
//-----------------------------------------------------------------------------
|
||
|
CTextureFont::CTextureFont()
|
||
|
{
|
||
|
ZeroMemory( this, sizeof( *this ) );
|
||
|
|
||
|
m_bIncludeNullCharacter = TRUE;
|
||
|
m_bAntialiasEffect = TRUE;
|
||
|
|
||
|
// Texture info
|
||
|
m_dwTextureWidth = 256;
|
||
|
m_dwTextureHeight = 256;
|
||
|
|
||
|
// Default glyph range
|
||
|
WORD wStartGlyph = 32;
|
||
|
WORD wEndGlyph = 255;
|
||
|
ExtractValidGlyphsFromRange( wStartGlyph, wEndGlyph );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: ~CTextureFont()
|
||
|
// Desc: Destructor
|
||
|
//-----------------------------------------------------------------------------
|
||
|
CTextureFont::~CTextureFont()
|
||
|
{
|
||
|
DestroyObjects();
|
||
|
|
||
|
if ( m_hFont )
|
||
|
DeleteObject( m_hFont );
|
||
|
|
||
|
if ( m_pBits )
|
||
|
delete[] m_pBits;
|
||
|
|
||
|
m_pBits = NULL;
|
||
|
m_hFont = NULL;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// ClearFont
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CTextureFont::ClearFont()
|
||
|
{
|
||
|
DestroyObjects();
|
||
|
|
||
|
ZeroMemory( &m_LogFont, sizeof(LOGFONT) );
|
||
|
|
||
|
m_strFontName[0] = '\0';
|
||
|
|
||
|
m_hFont = NULL;
|
||
|
|
||
|
m_dwTextureWidth = 256;
|
||
|
m_dwTextureHeight = 256;
|
||
|
|
||
|
m_bAntialiasEffect = FALSE;
|
||
|
m_bShadowEffect = FALSE;
|
||
|
m_bOutlineEffect = FALSE;
|
||
|
m_nBlur = 0;
|
||
|
m_nScanlines = 0;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: DestroyObjects()
|
||
|
// Desc: Cleans up all allocated resources for the class
|
||
|
//-----------------------------------------------------------------------------
|
||
|
VOID CTextureFont::DestroyObjects()
|
||
|
{
|
||
|
if ( m_pGlyphs )
|
||
|
delete[] m_pGlyphs;
|
||
|
if ( m_ValidGlyphs )
|
||
|
delete[] m_ValidGlyphs;
|
||
|
if ( m_TranslatorTable )
|
||
|
delete[] m_TranslatorTable;
|
||
|
|
||
|
if ( m_pCustomFilename )
|
||
|
{
|
||
|
TL_Free( (void*)m_pCustomFilename );
|
||
|
m_pCustomFilename = NULL;
|
||
|
|
||
|
for (DWORD i=0; i<m_dwNumGlyphs; i++)
|
||
|
{
|
||
|
if ( m_pCustomGlyphFiles[i] )
|
||
|
{
|
||
|
TL_Free( m_pCustomGlyphFiles[i] );
|
||
|
m_pCustomGlyphFiles[i] = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_cMaxGlyph = 0;
|
||
|
m_dwNumGlyphs = 0;
|
||
|
m_pGlyphs = NULL;
|
||
|
m_ValidGlyphs = NULL;
|
||
|
m_TranslatorTable = NULL;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT CTextureFont::InsertGlyph( WORD wGlyph )
|
||
|
{
|
||
|
m_cMaxGlyph = 0;
|
||
|
m_dwNumGlyphs = 0;
|
||
|
|
||
|
m_ValidGlyphs[wGlyph] = 1;
|
||
|
|
||
|
for ( DWORD c=0; c<=65535; c++ )
|
||
|
{
|
||
|
if ( m_ValidGlyphs[c] )
|
||
|
{
|
||
|
m_dwNumGlyphs++;
|
||
|
m_cMaxGlyph = (WCHAR)c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BuildTranslatorTable();
|
||
|
theApp.CalculateAndRenderGlyphs();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT CTextureFont::DeleteGlyph( WORD wGlyph )
|
||
|
{
|
||
|
m_cMaxGlyph = 0;
|
||
|
m_dwNumGlyphs = 0;
|
||
|
|
||
|
m_ValidGlyphs[wGlyph] = 0;
|
||
|
|
||
|
for ( DWORD c=0; c<=65535; c++ )
|
||
|
{
|
||
|
if ( m_ValidGlyphs[c] )
|
||
|
{
|
||
|
m_dwNumGlyphs++;
|
||
|
m_cMaxGlyph = (WCHAR)c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BuildTranslatorTable();
|
||
|
theApp.CalculateAndRenderGlyphs();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: ExtractValidGlyphsFromRange()
|
||
|
// Desc: Set global variables to indicate we will be drawing all glyphs in the
|
||
|
// range specified.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT CTextureFont::ExtractValidGlyphsFromRange( WORD wStartGlyph, WORD wEndGlyph )
|
||
|
{
|
||
|
// Cleanup any previous entries
|
||
|
if( m_ValidGlyphs )
|
||
|
delete[] m_ValidGlyphs;
|
||
|
|
||
|
m_cMaxGlyph = 0;
|
||
|
m_dwNumGlyphs = 0;
|
||
|
m_ValidGlyphs = NULL;
|
||
|
|
||
|
// Allocate memory for the array of vaild glyphs
|
||
|
m_ValidGlyphs = new BYTE[65536];
|
||
|
ZeroMemory( m_ValidGlyphs, 65536 );
|
||
|
|
||
|
for( DWORD c=(DWORD)wStartGlyph; c<=(DWORD)wEndGlyph; c++ )
|
||
|
{
|
||
|
m_ValidGlyphs[c] = 1;
|
||
|
m_dwNumGlyphs++;
|
||
|
}
|
||
|
|
||
|
m_cMaxGlyph = wEndGlyph;
|
||
|
|
||
|
BuildTranslatorTable();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: ExtractValidGlyphsFromRange()
|
||
|
// Desc: Set global variables to indicate we will be drawing all glyphs that
|
||
|
// are present in the specified text file.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT CTextureFont::ExtractValidGlyphsFromFile( const CHAR* strFileName )
|
||
|
{
|
||
|
// Open the file
|
||
|
FILE* file = fopen( strFileName, "rb" );
|
||
|
if( NULL == file )
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Cleanup any previous entries
|
||
|
if( m_ValidGlyphs )
|
||
|
delete[] m_ValidGlyphs;
|
||
|
|
||
|
m_cMaxGlyph = 0;
|
||
|
m_dwNumGlyphs = 0;
|
||
|
m_ValidGlyphs = NULL;
|
||
|
|
||
|
// Allocate memory for the array of vaild glyphs
|
||
|
m_ValidGlyphs = new BYTE[65536];
|
||
|
ZeroMemory( m_ValidGlyphs, 65536 );
|
||
|
|
||
|
// Skip the unicode marker
|
||
|
BOOL bIsUnicode = (fgetwc(file) == 0xfeff) ? TRUE : FALSE;
|
||
|
|
||
|
if( bIsUnicode == FALSE )
|
||
|
rewind( file );
|
||
|
|
||
|
// Record which glyphs are valid
|
||
|
WCHAR c;
|
||
|
while( (WCHAR)EOF != ( c = bIsUnicode ? fgetwc(file) : fgetc(file) ) )
|
||
|
{
|
||
|
while( c == L'\\' )
|
||
|
{
|
||
|
c = bIsUnicode ? fgetwc(file) : fgetc(file);
|
||
|
|
||
|
// Handle octal-coded characters
|
||
|
if( isdigit(c) )
|
||
|
{
|
||
|
int code = (c - L'0');
|
||
|
c = bIsUnicode ? fgetwc(file) : fgetc(file);
|
||
|
|
||
|
if( isdigit(c) )
|
||
|
{
|
||
|
code = code*8 + (c - L'0');
|
||
|
c = bIsUnicode ? fgetwc(file) : fgetc(file);
|
||
|
|
||
|
if( isdigit(c) )
|
||
|
{
|
||
|
code = code*8 + (c - L'0');
|
||
|
c = bIsUnicode ? fgetwc(file) : fgetc(file);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( m_ValidGlyphs[code] == 0 )
|
||
|
{
|
||
|
if( code > m_cMaxGlyph )
|
||
|
m_cMaxGlyph = (WCHAR)code;
|
||
|
|
||
|
m_dwNumGlyphs++;
|
||
|
m_ValidGlyphs[code] = 2;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Add the backslash character
|
||
|
if( L'\\' > m_cMaxGlyph )
|
||
|
m_cMaxGlyph = L'\\';
|
||
|
|
||
|
if( m_ValidGlyphs[L'\\'] == 0 )
|
||
|
{
|
||
|
m_dwNumGlyphs++;
|
||
|
m_ValidGlyphs[L'\\'] = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( m_ValidGlyphs[c] == 0 )
|
||
|
{
|
||
|
// If the character is a printable one, add it
|
||
|
if( c != L'\n' && c != L'\r' && c != 0xffff )
|
||
|
{
|
||
|
m_dwNumGlyphs++;
|
||
|
m_ValidGlyphs[c] = 1;
|
||
|
|
||
|
if( c > m_cMaxGlyph )
|
||
|
m_cMaxGlyph = c;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Done with the file
|
||
|
fclose( file );
|
||
|
|
||
|
BuildTranslatorTable();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: BuildTranslatorTable()
|
||
|
// Desc: Builds a table to translate from a WCHAR to a glyph index.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT CTextureFont::BuildTranslatorTable()
|
||
|
{
|
||
|
if ( m_TranslatorTable )
|
||
|
delete[] m_TranslatorTable;
|
||
|
|
||
|
// Insure the \0 is there
|
||
|
if ( m_bIncludeNullCharacter && 0 == m_ValidGlyphs[0] )
|
||
|
{
|
||
|
m_dwNumGlyphs++;
|
||
|
m_ValidGlyphs[0] = 1;
|
||
|
}
|
||
|
|
||
|
// Fill the string of all valid glyphs and build the translator table
|
||
|
m_TranslatorTable = new WORD[m_cMaxGlyph+1];
|
||
|
ZeroMemory( m_TranslatorTable, sizeof(WORD)*(m_cMaxGlyph+1) );
|
||
|
|
||
|
if ( !m_pCustomFilename )
|
||
|
{
|
||
|
// ttf has glyphs that are sequential
|
||
|
DWORD dwGlyph = 0;
|
||
|
for ( DWORD i=0; i<65536; i++ )
|
||
|
{
|
||
|
if ( m_ValidGlyphs[i] )
|
||
|
{
|
||
|
m_TranslatorTable[i] = (WORD)dwGlyph;
|
||
|
dwGlyph++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// custom font has glyphs that are scattered
|
||
|
DWORD dwGlyph = 0;
|
||
|
for ( DWORD i=0; i<m_dwNumGlyphs; i++ )
|
||
|
{
|
||
|
if ( !i && m_bIncludeNullCharacter )
|
||
|
{
|
||
|
m_TranslatorTable[0] = 0;
|
||
|
dwGlyph++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
m_TranslatorTable[m_customGlyphs[i-1]] = (WORD)dwGlyph;
|
||
|
dwGlyph++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
void StripQuotedToken( char *pToken )
|
||
|
{
|
||
|
int len = strlen( pToken );
|
||
|
if ( !len )
|
||
|
return;
|
||
|
|
||
|
if ( pToken[0] == '\"' && pToken[len-1] == '\"' )
|
||
|
{
|
||
|
memcpy( pToken, pToken+1, len-1 );
|
||
|
pToken[len-2] = '\0';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// ReadCustomFontFile
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT CTextureFont::ReadCustomFontFile( CHAR* strFileName )
|
||
|
{
|
||
|
char *pToken;
|
||
|
char fontName[128];
|
||
|
bool bSuccess;
|
||
|
unsigned char glyphs[256];
|
||
|
char *glyphFiles[512];
|
||
|
char basePath[MAX_PATH];
|
||
|
int numGlyphs;
|
||
|
char filename[MAX_PATH];
|
||
|
|
||
|
bSuccess = false;
|
||
|
numGlyphs = 0;
|
||
|
|
||
|
ClearFont();
|
||
|
|
||
|
TL_LoadScriptFile( strFileName );
|
||
|
|
||
|
strcpy( basePath, strFileName );
|
||
|
TL_StripFilename( basePath );
|
||
|
TL_AddSeperatorToPath( basePath, basePath );
|
||
|
|
||
|
fontName[0] = '\0';
|
||
|
while ( 1 )
|
||
|
{
|
||
|
pToken = TL_GetToken( true );
|
||
|
if ( !pToken || !pToken[0] )
|
||
|
break;
|
||
|
StripQuotedToken( pToken );
|
||
|
|
||
|
// get font name
|
||
|
if ( !stricmp( pToken, "fontName" ) )
|
||
|
{
|
||
|
pToken = TL_GetToken( true );
|
||
|
if ( !pToken || !pToken[0] )
|
||
|
goto cleanUp;
|
||
|
StripQuotedToken( pToken );
|
||
|
strcpy( fontName, pToken );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// get glyph
|
||
|
if ( strlen( pToken ) != 1 )
|
||
|
goto cleanUp;
|
||
|
glyphs[numGlyphs] = pToken[0];
|
||
|
|
||
|
// get glyph file
|
||
|
pToken = TL_GetToken( true );
|
||
|
if ( !pToken || !pToken[0] )
|
||
|
goto cleanUp;
|
||
|
StripQuotedToken( pToken );
|
||
|
sprintf( filename, "%s%s", basePath, pToken );
|
||
|
glyphFiles[numGlyphs] = TL_CopyString( filename );
|
||
|
|
||
|
numGlyphs++;
|
||
|
if ( numGlyphs >= 256 )
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( numGlyphs == 0 )
|
||
|
goto cleanUp;
|
||
|
|
||
|
m_pCustomFilename = TL_CopyString( strFileName );
|
||
|
strcpy ( m_strFontName, fontName );
|
||
|
|
||
|
m_dwTextureWidth = 256;
|
||
|
m_dwTextureHeight = 256;
|
||
|
|
||
|
m_ValidGlyphs = new BYTE[65536];
|
||
|
ZeroMemory( m_ValidGlyphs, 65536 );
|
||
|
|
||
|
m_dwNumGlyphs = numGlyphs;
|
||
|
m_cMaxGlyph = 0;
|
||
|
for (int i=0; i<numGlyphs; i++)
|
||
|
{
|
||
|
m_ValidGlyphs[glyphs[i]] = 1;
|
||
|
|
||
|
if ( m_cMaxGlyph < glyphs[i] )
|
||
|
m_cMaxGlyph = glyphs[i];
|
||
|
|
||
|
m_customGlyphs[i] = glyphs[i];
|
||
|
m_pCustomGlyphFiles[i] = glyphFiles[i];
|
||
|
}
|
||
|
|
||
|
BuildTranslatorTable();
|
||
|
|
||
|
bSuccess = true;
|
||
|
|
||
|
cleanUp:
|
||
|
TL_FreeScriptFile();
|
||
|
return bSuccess ? S_OK : E_FAIL;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: ReadFontInfoFile()
|
||
|
// Desc: Loads the font's glyph info from a file
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT CTextureFont::ReadFontInfoFile( CHAR* strFileName )
|
||
|
{
|
||
|
BitmapFont_t bitmapFont;
|
||
|
|
||
|
// open the info file
|
||
|
FILE* file = fopen( strFileName, "rb" );
|
||
|
if ( NULL == file )
|
||
|
return E_FAIL;
|
||
|
|
||
|
memset( &bitmapFont, 0, sizeof( BitmapFont_t ) );
|
||
|
fread( &bitmapFont, 1, sizeof( BitmapFont_t ), file );
|
||
|
|
||
|
if ( bitmapFont.m_id != BITMAPFONT_ID || bitmapFont.m_Version != BITMAPFONT_VERSION )
|
||
|
{
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
theApp.SetTextureSize( bitmapFont.m_PageWidth, bitmapFont.m_PageHeight );
|
||
|
|
||
|
ZeroMemory( m_ValidGlyphs, 65536 );
|
||
|
|
||
|
m_dwNumGlyphs = 0;
|
||
|
m_cMaxGlyph = 0;
|
||
|
for (int i=0; i<256; i++)
|
||
|
{
|
||
|
if ( bitmapFont.m_TranslateTable[i] )
|
||
|
{
|
||
|
m_ValidGlyphs[i] = 1;
|
||
|
m_cMaxGlyph = i;
|
||
|
m_dwNumGlyphs++;
|
||
|
}
|
||
|
}
|
||
|
BuildTranslatorTable();
|
||
|
|
||
|
// success
|
||
|
fclose( file );
|
||
|
|
||
|
theApp.OnGlyphsCustom();
|
||
|
theApp.CalculateAndRenderGlyphs();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: WriteFontInfoFile()
|
||
|
// Desc: Writes the font's glyph info to a file
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT CTextureFont::WriteFontInfoFile( CHAR* strFileName )
|
||
|
{
|
||
|
BitmapFont_t bitmapFont;
|
||
|
BitmapGlyph_t bitmapGlyph;
|
||
|
|
||
|
// Create the info file
|
||
|
FILE* file = fopen( strFileName, "wb" );
|
||
|
if ( NULL == file )
|
||
|
return E_FAIL;
|
||
|
|
||
|
bitmapFont.m_id = BITMAPFONT_ID;
|
||
|
bitmapFont.m_Version = BITMAPFONT_VERSION;
|
||
|
bitmapFont.m_PageWidth = (short)m_dwTextureWidth;
|
||
|
bitmapFont.m_PageHeight = (short)m_dwTextureHeight;
|
||
|
bitmapFont.m_Ascent = 0;
|
||
|
bitmapFont.m_NumGlyphs = (short)m_dwNumGlyphs;
|
||
|
|
||
|
// generate flags
|
||
|
bitmapFont.m_Flags = 0;
|
||
|
if ( m_bAntialiasEffect )
|
||
|
{
|
||
|
bitmapFont.m_Flags |= BF_ANTIALIASED;
|
||
|
}
|
||
|
if ( m_bShadowEffect )
|
||
|
{
|
||
|
bitmapFont.m_Flags |= BF_DROPSHADOW;
|
||
|
}
|
||
|
if ( m_bOutlineEffect )
|
||
|
{
|
||
|
bitmapFont.m_Flags |= BF_OUTLINED;
|
||
|
}
|
||
|
if ( m_nBlur )
|
||
|
{
|
||
|
bitmapFont.m_Flags |= BF_BLURRED;
|
||
|
}
|
||
|
if ( m_nScanlines )
|
||
|
{
|
||
|
bitmapFont.m_Flags |= BF_SCANLINES;
|
||
|
}
|
||
|
if ( m_LogFont.lfItalic )
|
||
|
{
|
||
|
bitmapFont.m_Flags |= BF_ITALIC;
|
||
|
}
|
||
|
if ( m_LogFont.lfWeight > 400 )
|
||
|
{
|
||
|
bitmapFont.m_Flags |= BF_BOLD;
|
||
|
}
|
||
|
if ( m_pCustomFilename )
|
||
|
{
|
||
|
bitmapFont.m_Flags |= BF_CUSTOM;
|
||
|
}
|
||
|
|
||
|
// determine max char width from all glyphs
|
||
|
bitmapFont.m_MaxCharWidth = 0;
|
||
|
for (unsigned int i=0; i<m_dwNumGlyphs; i++ )
|
||
|
{
|
||
|
if ( bitmapFont.m_MaxCharWidth < m_pGlyphs[i].w )
|
||
|
{
|
||
|
bitmapFont.m_MaxCharWidth = m_pGlyphs[i].w;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bitmapFont.m_MaxCharHeight = 0;
|
||
|
for (unsigned int i=0; i<m_dwNumGlyphs; i++ )
|
||
|
{
|
||
|
if ( bitmapFont.m_MaxCharHeight < m_pGlyphs[i].h )
|
||
|
{
|
||
|
bitmapFont.m_MaxCharHeight = m_pGlyphs[i].h;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// maps a char index to its actual glyph
|
||
|
for (int i=0; i<256; i++)
|
||
|
{
|
||
|
if ( i <= m_cMaxGlyph )
|
||
|
{
|
||
|
bitmapFont.m_TranslateTable[i] = (unsigned char)m_TranslatorTable[i];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bitmapFont.m_TranslateTable[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// write out the header
|
||
|
fwrite( &bitmapFont, sizeof( BitmapFont_t ), 1, file );
|
||
|
|
||
|
// Write out the vertical padding caused by effects
|
||
|
// FLOAT fTopPadding = ( m_bOutlineEffect ? 1.0f : 0.0f );
|
||
|
// FLOAT fBottomPadding = ( m_bOutlineEffect ? ( m_bShadowEffect ? 2.0f : 1.0f ) : ( m_bShadowEffect ? 2.0f : 0.0f ) );
|
||
|
// FLOAT fFontYAdvance = fFontHeight - fTopPadding - fBottomPadding;
|
||
|
|
||
|
// Write the glyph attributes to the file
|
||
|
for (unsigned int i=0; i<m_dwNumGlyphs; i++ )
|
||
|
{
|
||
|
bitmapGlyph.x = m_pGlyphs[i].x;
|
||
|
bitmapGlyph.y = m_pGlyphs[i].y;
|
||
|
bitmapGlyph.w = m_pGlyphs[i].w;
|
||
|
bitmapGlyph.h = m_pGlyphs[i].h;
|
||
|
bitmapGlyph.a = m_pGlyphs[i].a;
|
||
|
bitmapGlyph.b = m_pGlyphs[i].b;
|
||
|
bitmapGlyph.c = m_pGlyphs[i].c;
|
||
|
|
||
|
fwrite( &bitmapGlyph, sizeof( BitmapGlyph_t ), 1, file );
|
||
|
}
|
||
|
|
||
|
// success
|
||
|
fclose( file );
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: WriteTargaFile()
|
||
|
// Desc: Writes 32-bit RGBA data to a .tga file
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT WriteTargaFile( CHAR* strFileName, DWORD dwWidth, DWORD dwHeight,
|
||
|
DWORD* pRGBAData )
|
||
|
{
|
||
|
struct TargaHeader
|
||
|
{
|
||
|
BYTE IDLength;
|
||
|
BYTE ColormapType;
|
||
|
BYTE ImageType;
|
||
|
BYTE ColormapSpecification[5];
|
||
|
WORD XOrigin;
|
||
|
WORD YOrigin;
|
||
|
WORD ImageWidth;
|
||
|
WORD ImageHeight;
|
||
|
BYTE PixelDepth;
|
||
|
BYTE ImageDescriptor;
|
||
|
} tga;
|
||
|
|
||
|
// Create the file
|
||
|
FILE* file = fopen( strFileName, "wb" );
|
||
|
if( NULL == file )
|
||
|
return E_FAIL;
|
||
|
|
||
|
// Write the TGA header
|
||
|
ZeroMemory( &tga, sizeof(tga) );
|
||
|
tga.IDLength = 0;
|
||
|
tga.ImageType = 2;
|
||
|
tga.ImageWidth = (WORD)dwWidth;
|
||
|
tga.ImageHeight = (WORD)dwHeight;
|
||
|
tga.PixelDepth = 32;
|
||
|
tga.ImageDescriptor = 0x28;
|
||
|
fwrite( &tga, sizeof(TargaHeader), 1, file );
|
||
|
|
||
|
// Write the pixels
|
||
|
fwrite( pRGBAData, sizeof(DWORD), dwHeight*dwWidth, file );
|
||
|
|
||
|
// Close the file and return okay
|
||
|
fclose( file );
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: WriteFontImageFile()
|
||
|
// Desc: Writes 32-bit RGBA data to a .tga file
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT CTextureFont::WriteFontImageFile( CHAR* strFileName, bool bAdditiveMode, bool bCustomFont )
|
||
|
{
|
||
|
// Convert the bits to have an alpha channel
|
||
|
DWORD* pRGBAData = new DWORD[m_dwTextureWidth*m_dwTextureHeight];
|
||
|
|
||
|
FLOAT l;
|
||
|
for ( DWORD i=0; i<m_dwTextureWidth*m_dwTextureHeight; i++ )
|
||
|
{
|
||
|
FLOAT a = ( ( 0xff000000 & m_pBits[i] ) >> 24L ) / 255.0f;
|
||
|
FLOAT r = ( ( 0x00ff0000 & m_pBits[i] ) >> 16L ) / 255.0f;
|
||
|
FLOAT g = ( ( 0x0000ff00 & m_pBits[i] ) >> 8L ) / 255.0f;
|
||
|
FLOAT b = ( ( 0x000000ff & m_pBits[i] ) >> 0L ) / 255.0f;
|
||
|
|
||
|
if ( bCustomFont )
|
||
|
{
|
||
|
if ( a == 0.0f && b == 1.0f )
|
||
|
{
|
||
|
// pure transluscent
|
||
|
a = 0;
|
||
|
r = g = b = 0.0f;
|
||
|
}
|
||
|
|
||
|
int red = (int)(r * 255.0f);
|
||
|
int green = (int)(g * 255.0f);
|
||
|
int blue = (int)(b * 255.0f);
|
||
|
int alpha = (int)(a * 255.0f);
|
||
|
|
||
|
pRGBAData[i] = (alpha<<24L) | (red<<16L) | (green<<8L) | (blue<<0L);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( bAdditiveMode )
|
||
|
{
|
||
|
// all channels should be same
|
||
|
if (( r != g ) || ( r != b ))
|
||
|
{
|
||
|
}
|
||
|
|
||
|
l = r;
|
||
|
a = 1.0f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
a = r + (1-b);
|
||
|
if ( a )
|
||
|
l = r / a;
|
||
|
else
|
||
|
l = 1;
|
||
|
}
|
||
|
|
||
|
DWORD alpha = (DWORD)( a * 255.0f );
|
||
|
DWORD lum = (DWORD)( l * 255.0f );
|
||
|
|
||
|
pRGBAData[i] = (alpha<<24L) | (lum<<16L) | (lum<<8L) | (lum<<0L);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Write the file
|
||
|
HRESULT hr = WriteTargaFile( strFileName, m_dwTextureWidth,
|
||
|
m_dwTextureHeight, pRGBAData );
|
||
|
|
||
|
// Cleanup and return
|
||
|
delete[] pRGBAData;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
void GetBitmapBits2( HBITMAP hBitmap, int width, int height, void *pBits )
|
||
|
{
|
||
|
memset( pBits, 0, width*height*4 );
|
||
|
|
||
|
HDC hDC = CreateCompatibleDC( NULL );
|
||
|
BITMAPINFO bitmapInfo = {0};
|
||
|
bitmapInfo.bmiHeader.biSize = sizeof( bitmapInfo.bmiHeader );
|
||
|
bitmapInfo.bmiHeader.biWidth = width;
|
||
|
bitmapInfo.bmiHeader.biHeight = -height;
|
||
|
bitmapInfo.bmiHeader.biPlanes = 1;
|
||
|
bitmapInfo.bmiHeader.biBitCount = 32;
|
||
|
bitmapInfo.bmiHeader.biCompression = BI_RGB;
|
||
|
GetDIBits( hDC, hBitmap, 0, height, pBits, &bitmapInfo ,DIB_RGB_COLORS );
|
||
|
DeleteDC( hDC );
|
||
|
}
|
||
|
|
||
|
void SetBitmapBits2( HBITMAP hBitmap, int width, int height, void *pBits )
|
||
|
{
|
||
|
HDC hDC = CreateCompatibleDC( NULL );
|
||
|
BITMAPINFO bitmapInfo = {0};
|
||
|
bitmapInfo.bmiHeader.biSize = sizeof( bitmapInfo.bmiHeader );
|
||
|
bitmapInfo.bmiHeader.biWidth = width;
|
||
|
bitmapInfo.bmiHeader.biHeight = -height;
|
||
|
bitmapInfo.bmiHeader.biPlanes = 1;
|
||
|
bitmapInfo.bmiHeader.biBitCount = 32;
|
||
|
bitmapInfo.bmiHeader.biCompression = BI_RGB;
|
||
|
SetDIBits( hDC, hBitmap, 0, height, pBits, &bitmapInfo ,DIB_RGB_COLORS );
|
||
|
DeleteDC( hDC );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// SetTextureBits
|
||
|
//
|
||
|
// Blit the rect back into the bitmap
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void SetTextureBits( HBITMAP hBitmap, int bitmapWidth, int bitmapHeight, int x, int y, int w, int h, unsigned char *pRGBA )
|
||
|
{
|
||
|
// get the enitre bitmap
|
||
|
unsigned char *pBitmapBits = (unsigned char *)malloc( bitmapWidth * bitmapHeight * 4);
|
||
|
GetBitmapBits2( hBitmap, bitmapWidth, bitmapHeight, pBitmapBits );
|
||
|
|
||
|
// copy into bitmap bits
|
||
|
unsigned char *pSrc = pRGBA;
|
||
|
for (int yy=y; yy<y+h; yy++)
|
||
|
{
|
||
|
if ( yy >= bitmapHeight )
|
||
|
{
|
||
|
// past end of bitmap
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
unsigned char *pDst = pBitmapBits + (yy*bitmapWidth + x)*4;
|
||
|
for (int xx=0; xx<w; xx++)
|
||
|
{
|
||
|
if ( xx+x < bitmapWidth )
|
||
|
{
|
||
|
pDst[0] = pSrc[0];
|
||
|
pDst[1] = pSrc[1];
|
||
|
pDst[2] = pSrc[2];
|
||
|
pDst[3] = pSrc[3];
|
||
|
}
|
||
|
pSrc += 4;
|
||
|
pDst += 4;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SetBitmapBits2( hBitmap, bitmapWidth, bitmapHeight, pBitmapBits );
|
||
|
|
||
|
free( pBitmapBits );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// GetTextureBits
|
||
|
//
|
||
|
// Blit the rect out of the bitmap
|
||
|
//-----------------------------------------------------------------------------
|
||
|
unsigned char *GetTextureBits( HBITMAP hBitmap, int bitmapWidth, int bitmapHeight, int x, int y, int w, int h )
|
||
|
{
|
||
|
// get the enitre bitmap
|
||
|
unsigned char *pBitmapBits = new unsigned char[bitmapWidth * bitmapHeight * 4];
|
||
|
GetBitmapBits2( hBitmap, bitmapWidth, bitmapHeight, pBitmapBits );
|
||
|
|
||
|
unsigned char *pRGBA = new unsigned char[w * h * 4];
|
||
|
memset( pRGBA, 0, w*h*4 );
|
||
|
|
||
|
// copy out bits
|
||
|
unsigned char *pDst = pRGBA;
|
||
|
for (int yy=y; yy<y+h; yy++)
|
||
|
{
|
||
|
if ( yy >= bitmapHeight )
|
||
|
{
|
||
|
// past last row of bitmap
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
unsigned char *pSrc = pBitmapBits + (yy*bitmapWidth + x)*4;
|
||
|
for (int xx=0; xx<w; xx++)
|
||
|
{
|
||
|
if ( xx + x < bitmapWidth )
|
||
|
{
|
||
|
pDst[0] = pSrc[0];
|
||
|
pDst[1] = pSrc[1];
|
||
|
pDst[2] = pSrc[2];
|
||
|
pDst[3] = pSrc[3];
|
||
|
}
|
||
|
pSrc += 4;
|
||
|
pDst += 4;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete [] pBitmapBits;
|
||
|
return pRGBA;
|
||
|
}
|
||
|
|
||
|
|
||
|
int g_blur;
|
||
|
float *g_pGaussianDistribution;
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Gets the blur value for a single pixel
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void GetBlurValueForPixel(unsigned char *src, int blur, float *gaussianDistribution, int srcX, int srcY, int srcWide, int srcTall, unsigned char *dest)
|
||
|
{
|
||
|
int r = 0, g = 0, b = 0, a = 0;
|
||
|
|
||
|
float accum = 0.0f;
|
||
|
|
||
|
// scan the positive x direction
|
||
|
int maxX = min(srcX + blur, srcWide);
|
||
|
int minX = max(srcX - blur, 0);
|
||
|
for (int x = minX; x <= maxX; x++)
|
||
|
{
|
||
|
int maxY = min(srcY + blur, srcTall - 1);
|
||
|
int minY = max(srcY - blur, 0);
|
||
|
for (int y = minY; y <= maxY; y++)
|
||
|
{
|
||
|
unsigned char *srcPos = src + ((x + (y * srcWide)) * 4);
|
||
|
|
||
|
unsigned char red = srcPos[2];
|
||
|
unsigned char green = srcPos[1];
|
||
|
unsigned char blue = srcPos[0];
|
||
|
|
||
|
// muliply by the value matrix
|
||
|
float weight = gaussianDistribution[x - srcX + blur];
|
||
|
float weight2 = gaussianDistribution[y - srcY + blur];
|
||
|
accum += (red * (weight * weight2));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// blurring decreased the range, for xbox kick some back
|
||
|
accum *= 1.30f;
|
||
|
|
||
|
// all the values are the same for fonts, just use the calculated alpha
|
||
|
r = g = b = (int)accum;
|
||
|
|
||
|
dest[0] = min(b, 255);
|
||
|
dest[1] = min(g, 255);
|
||
|
dest[2] = min(r, 255);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// ApplyGaussianBlurToTexture
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void ApplyGaussianBlurToTexture( int blur, int rgbaX, int rgbaY, int rgbaWide, int rgbaTall, unsigned char *rgba)
|
||
|
{
|
||
|
// calculate our gaussian distribution for if we're blurred
|
||
|
if ( blur > 1 && blur != g_blur )
|
||
|
{
|
||
|
g_blur = blur;
|
||
|
g_pGaussianDistribution = new float[blur * 2 + 1];
|
||
|
double sigma = 0.683f * blur;
|
||
|
for (int x = 0; x <= (blur * 2); x++)
|
||
|
{
|
||
|
int val = x - blur;
|
||
|
g_pGaussianDistribution[x] = (float)((1.0 / sqrt(2.0 * 3.14 * sigma * sigma)) * pow(2.7, -1.0 * (val * val) / (2.0 * sigma * sigma)));
|
||
|
|
||
|
// brightening factor
|
||
|
g_pGaussianDistribution[x] *= 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// alloc a new buffer
|
||
|
unsigned char *src = (unsigned char *)_alloca(rgbaWide * rgbaTall * 4);
|
||
|
memcpy(src, rgba, rgbaWide * rgbaTall * 4);
|
||
|
|
||
|
unsigned char *dest = rgba;
|
||
|
for (int y = 0; y < rgbaTall; y++)
|
||
|
{
|
||
|
for (int x = 0; x < rgbaWide; x++)
|
||
|
{
|
||
|
// scan the source pixel
|
||
|
GetBlurValueForPixel(src, blur, g_pGaussianDistribution, x, y, rgbaWide, rgbaTall, dest);
|
||
|
|
||
|
// move to the next
|
||
|
dest += 4;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// ApplyScanlineEffectToTexture
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void ApplyScanlineEffectToTexture( int scanLines, int rgbaX, int rgbaY, int rgbaWide, int rgbaTall, unsigned char *rgba)
|
||
|
{
|
||
|
if (scanLines < 2)
|
||
|
return;
|
||
|
|
||
|
float scale;
|
||
|
scale = 0;
|
||
|
|
||
|
// darken all the areas except the scanlines
|
||
|
for (int y = 0; y < rgbaTall; y++)
|
||
|
{
|
||
|
// skip the scan lines
|
||
|
if (y % scanLines == 0)
|
||
|
continue;
|
||
|
|
||
|
DWORD *pBits = (DWORD*)&rgba[(rgbaX + ((y + rgbaY) * rgbaWide)) * 4];
|
||
|
|
||
|
// darken the other lines
|
||
|
for (int x = 0; x < rgbaWide; x++, pBits++)
|
||
|
{
|
||
|
FLOAT r = ( ( 0x00ff0000 & pBits[0] ) >> 16L ) / 255.0f;
|
||
|
FLOAT g = ( ( 0x0000ff00 & pBits[0] ) >> 8L ) / 255.0f;
|
||
|
FLOAT b = ( ( 0x000000ff & pBits[0] ) >> 0L ) / 255.0f;
|
||
|
|
||
|
r *= scale;
|
||
|
g *= scale;
|
||
|
b *= scale;
|
||
|
|
||
|
pBits[0] = (((int)(r * 255.0f))<<16) | (((int)(g * 255.0f))<<8) | ((int)(b * 255.0f));
|
||
|
pBits[0] |= 0xFF000000;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: RenderTTFGlyphs()
|
||
|
// Desc: Draws the list of font glyphs in the scroll view
|
||
|
//-----------------------------------------------------------------------------
|
||
|
GLYPH_ATTR* CTextureFont::RenderTTFGlyphs( HFONT hFont, HBITMAP hBitmap,
|
||
|
DWORD dwTextureWidth, DWORD dwTextureHeight,
|
||
|
BOOL bOutlineEffect, BOOL bShadowEffect,
|
||
|
int nScanlineEffect, int nBlurEffect,
|
||
|
BOOL bAntialias,
|
||
|
BYTE* ValidGlyphs, DWORD dwNumGlyphs )
|
||
|
{
|
||
|
// Create a DC
|
||
|
HDC hDC = CreateCompatibleDC( NULL );
|
||
|
|
||
|
// Associate the drawing surface
|
||
|
SelectObject( hDC, hBitmap );
|
||
|
|
||
|
// Create a clip region
|
||
|
HRGN rgn = CreateRectRgn( 0, 0, dwTextureWidth, dwTextureHeight );
|
||
|
SelectClipRgn( hDC, rgn );
|
||
|
|
||
|
// Setup the DC for the font
|
||
|
SetTextColor( hDC, COLOR_WHITE );
|
||
|
SelectObject( hDC, hFont );
|
||
|
SetTextAlign( hDC, TA_LEFT|TA_TOP|TA_UPDATECP );
|
||
|
SetMapMode( hDC, MM_TEXT );
|
||
|
SetBkMode( hDC, TRANSPARENT );
|
||
|
|
||
|
if ( nScanlineEffect || nBlurEffect )
|
||
|
{
|
||
|
SetBkColor( hDC, COLOR_BLACK );
|
||
|
|
||
|
if ( nBlurEffect < 2 )
|
||
|
nBlurEffect = 2;
|
||
|
if ( nScanlineEffect < 2 )
|
||
|
nScanlineEffect = 2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetBkColor( hDC, COLOR_BLUE );
|
||
|
}
|
||
|
|
||
|
// Fill the background in blue
|
||
|
RECT rect;
|
||
|
SetRect( &rect, 0, 0, dwTextureWidth, dwTextureHeight );
|
||
|
ExtTextOut( hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL );
|
||
|
|
||
|
// Get the effective font height
|
||
|
WCHAR str[2] = L"A";
|
||
|
SIZE size;
|
||
|
GetTextExtentPoint32W( hDC, str, 1, &size );
|
||
|
|
||
|
DWORD dwLeftOrigin = 1;
|
||
|
DWORD dwTopOrigin = 1;
|
||
|
|
||
|
GLYPH_ATTR* pGlyphs = new GLYPH_ATTR[dwNumGlyphs];
|
||
|
memset( pGlyphs, 0, dwNumGlyphs*sizeof( GLYPH_ATTR ) );
|
||
|
|
||
|
// Loop through all printable character and output them to the bitmap..
|
||
|
// Meanwhile, keep track of the corresponding tex coords for each character.
|
||
|
DWORD x = dwLeftOrigin;
|
||
|
DWORD y = dwTopOrigin;
|
||
|
int sx;
|
||
|
int sy;
|
||
|
|
||
|
int numGlyphs = 0;
|
||
|
|
||
|
for( DWORD i=0; i<65536; i++ )
|
||
|
{
|
||
|
if ( 0 == ValidGlyphs[i])
|
||
|
continue;
|
||
|
|
||
|
str[0] = (WCHAR)i;
|
||
|
|
||
|
if ( i==0 && ValidGlyphs[i] == 1 )
|
||
|
{
|
||
|
// account for unprintable, but don't render it
|
||
|
numGlyphs++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
GetTextExtentPoint32W( hDC, str, 1, &size );
|
||
|
|
||
|
// Get char width a different way
|
||
|
int charwidth;
|
||
|
GetCharWidth32( hDC, str[0], str[0], &charwidth );
|
||
|
|
||
|
// Get the ABC widths for the letter
|
||
|
ABC abc;
|
||
|
if ( FALSE == GetCharABCWidthsW( hDC, str[0], str[0], &abc ) )
|
||
|
{
|
||
|
abc.abcA = 0;
|
||
|
abc.abcB = size.cx;
|
||
|
abc.abcC = 0;
|
||
|
}
|
||
|
|
||
|
int w = abc.abcB;
|
||
|
int h = size.cy;
|
||
|
|
||
|
// Determine padding for effects
|
||
|
int left_padding = 0;
|
||
|
int right_padding = 0;
|
||
|
int top_padding = 0;
|
||
|
int bottom_padding = 0;
|
||
|
if ( bOutlineEffect || bShadowEffect )
|
||
|
{
|
||
|
if ( bOutlineEffect )
|
||
|
left_padding = 1;
|
||
|
|
||
|
if ( bOutlineEffect )
|
||
|
{
|
||
|
if ( bShadowEffect )
|
||
|
right_padding = 2;
|
||
|
else
|
||
|
right_padding = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( bShadowEffect )
|
||
|
right_padding = 2;
|
||
|
else
|
||
|
right_padding = 0;
|
||
|
}
|
||
|
|
||
|
if ( bOutlineEffect )
|
||
|
top_padding = 1;
|
||
|
|
||
|
if ( bOutlineEffect )
|
||
|
{
|
||
|
if ( bShadowEffect )
|
||
|
bottom_padding = 2;
|
||
|
else
|
||
|
bottom_padding = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( bShadowEffect )
|
||
|
bottom_padding = 2;
|
||
|
else
|
||
|
bottom_padding = 0;
|
||
|
}
|
||
|
}
|
||
|
else if ( nBlurEffect )
|
||
|
{
|
||
|
left_padding = nBlurEffect;
|
||
|
right_padding = nBlurEffect;
|
||
|
}
|
||
|
|
||
|
if ( ValidGlyphs[i] == 2 )
|
||
|
{
|
||
|
// Handle special characters
|
||
|
// Advance to the next line, if necessary
|
||
|
if ( x + h + left_padding + right_padding >= (int)dwTextureWidth )
|
||
|
{
|
||
|
x = dwLeftOrigin;
|
||
|
y += h + top_padding + bottom_padding + 1;
|
||
|
}
|
||
|
|
||
|
sx = x;
|
||
|
sy = y;
|
||
|
|
||
|
// Draw a square box for a placeholder for custom glyph graphics
|
||
|
w = h + left_padding + right_padding;
|
||
|
h = h + top_padding + bottom_padding;
|
||
|
|
||
|
abc.abcA = 0;
|
||
|
abc.abcB = w;
|
||
|
abc.abcC = 0;
|
||
|
|
||
|
RECT rect;
|
||
|
SetRect( &rect, x, y, x+w, y+h );
|
||
|
SetBkColor( hDC, COLOR_BLACK );
|
||
|
ExtTextOut( hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Hack to adjust for Kanji
|
||
|
if ( str[0] > 0x1000 )
|
||
|
{
|
||
|
w = h;
|
||
|
}
|
||
|
|
||
|
// Advance to the next line, if necessary
|
||
|
if ( x + w + left_padding + right_padding + 1 >= (int)dwTextureWidth )
|
||
|
{
|
||
|
x = dwLeftOrigin;
|
||
|
y += h + top_padding + bottom_padding + 1;
|
||
|
}
|
||
|
|
||
|
sx = x;
|
||
|
sy = y;
|
||
|
|
||
|
// Adjust ccordinates to account for the leading edge
|
||
|
if ( abc.abcA >= 0 )
|
||
|
x += abc.abcA;
|
||
|
else
|
||
|
sx -= abc.abcA;
|
||
|
|
||
|
// Hack to adjust for Kanji
|
||
|
if ( str[0] > 0x1000 )
|
||
|
{
|
||
|
sx += abc.abcA;
|
||
|
}
|
||
|
|
||
|
// Add padding to the width and height
|
||
|
w += left_padding + right_padding;
|
||
|
h += top_padding + bottom_padding;
|
||
|
abc.abcA -= left_padding;
|
||
|
abc.abcB += left_padding + right_padding;
|
||
|
abc.abcC -= right_padding;
|
||
|
|
||
|
if ( bOutlineEffect || bShadowEffect )
|
||
|
{
|
||
|
if ( bOutlineEffect )
|
||
|
{
|
||
|
SetTextColor( hDC, COLOR_BLACK );
|
||
|
MoveToEx( hDC, sx+0, sy+0, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
MoveToEx( hDC, sx+1, sy+0, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
MoveToEx( hDC, sx+2, sy+0, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
MoveToEx( hDC, sx+0, sy+1, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
MoveToEx( hDC, sx+2, sy+1, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
MoveToEx( hDC, sx+0, sy+2, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
MoveToEx( hDC, sx+1, sy+2, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
MoveToEx( hDC, sx+2, sy+2, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
|
||
|
if ( bShadowEffect )
|
||
|
{
|
||
|
MoveToEx( hDC, sx+3, sy+3, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
}
|
||
|
|
||
|
// Output the letter
|
||
|
SetTextColor( hDC, COLOR_WHITE );
|
||
|
MoveToEx( hDC, sx+1, sy+1, NULL ); ExtTextOutW( hDC, sx, sy, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( bShadowEffect )
|
||
|
{
|
||
|
SetTextColor( hDC, COLOR_BLACK );
|
||
|
MoveToEx( hDC, sx+2, sy+2, NULL ); ExtTextOutW( hDC, 0, 0, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
}
|
||
|
|
||
|
// Output the letter
|
||
|
SetTextColor( hDC, COLOR_WHITE );
|
||
|
MoveToEx( hDC, sx, sy, NULL ); ExtTextOutW( hDC, sx, sy, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
}
|
||
|
}
|
||
|
else if ( nBlurEffect )
|
||
|
{
|
||
|
// blur effect
|
||
|
SetTextColor( hDC, COLOR_WHITE );
|
||
|
MoveToEx( hDC, sx + nBlurEffect, sy, NULL );
|
||
|
ExtTextOutW( hDC, sx, sy, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
|
||
|
// apply blur effect
|
||
|
unsigned char *pBGRA = GetTextureBits( hBitmap, dwTextureWidth, dwTextureHeight, x, y, w, h );
|
||
|
if ( pBGRA )
|
||
|
{
|
||
|
ApplyGaussianBlurToTexture( nBlurEffect, 0, 0, w, h, pBGRA );
|
||
|
SetTextureBits( hBitmap, dwTextureWidth, dwTextureHeight, x, y, w, h, pBGRA );
|
||
|
delete [] pBGRA;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// normal, no effect
|
||
|
// Output the letter
|
||
|
SetTextColor( hDC, COLOR_WHITE );
|
||
|
MoveToEx( hDC, sx, sy, NULL );
|
||
|
ExtTextOutW( hDC, sx, sy, ETO_OPAQUE, NULL, str, 1, NULL );
|
||
|
}
|
||
|
|
||
|
// apply scanline effect
|
||
|
if ( nScanlineEffect )
|
||
|
{
|
||
|
unsigned char *pBGRA = GetTextureBits( hBitmap, dwTextureWidth, dwTextureHeight, x, y, w, h );
|
||
|
if ( pBGRA )
|
||
|
{
|
||
|
ApplyScanlineEffectToTexture( nScanlineEffect, 0, 0, w, h, pBGRA );
|
||
|
SetTextureBits( hBitmap, dwTextureWidth, dwTextureHeight, x, y, w, h, pBGRA );
|
||
|
delete [] pBGRA;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Hack for extended characters (like Kanji) that don't seem to report
|
||
|
// correct ABC widths. In this case, use the width calculated from
|
||
|
// drawing the glyph.
|
||
|
if( str[0] > 0x1000 )
|
||
|
{
|
||
|
POINT pos;
|
||
|
GetCurrentPositionEx( hDC, &pos );
|
||
|
abc.abcB = pos.x - sx;
|
||
|
|
||
|
if( abc.abcC < 0 )
|
||
|
abc.abcB -= abc.abcC;
|
||
|
|
||
|
w = abc.abcB;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Store the glyph attributes
|
||
|
pGlyphs[numGlyphs].x = x;
|
||
|
pGlyphs[numGlyphs].y = y;
|
||
|
pGlyphs[numGlyphs].w = w;
|
||
|
pGlyphs[numGlyphs].h = h;
|
||
|
pGlyphs[numGlyphs].a = abc.abcA;
|
||
|
pGlyphs[numGlyphs].b = abc.abcB;
|
||
|
pGlyphs[numGlyphs].c = abc.abcC;
|
||
|
pGlyphs[numGlyphs].fLeft = ((FLOAT)(x+0)) / dwTextureWidth;
|
||
|
pGlyphs[numGlyphs].fTop = ((FLOAT)(y+0)) / dwTextureHeight;
|
||
|
pGlyphs[numGlyphs].fRight = ((FLOAT)(x+w)) / dwTextureWidth;
|
||
|
pGlyphs[numGlyphs].fBottom = ((FLOAT)(y+h)) / dwTextureHeight;
|
||
|
numGlyphs++;
|
||
|
|
||
|
// Advance the cursor to the next position
|
||
|
x += w + 1;
|
||
|
}
|
||
|
|
||
|
SelectClipRgn( hDC, NULL );
|
||
|
DeleteObject( rgn );
|
||
|
DeleteDC( hDC );
|
||
|
|
||
|
return pGlyphs;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: RenderCustomGlyphs()
|
||
|
// Desc: Draws the list of font glyphs in the scroll view
|
||
|
//-----------------------------------------------------------------------------
|
||
|
GLYPH_ATTR* CTextureFont::RenderCustomGlyphs( HBITMAP hBitmap )
|
||
|
{
|
||
|
int i;
|
||
|
int w;
|
||
|
int h;
|
||
|
byte_t *pTGAPixels;
|
||
|
|
||
|
m_maxCustomCharHeight = 0;
|
||
|
|
||
|
// Create a DC
|
||
|
HDC hDC = CreateCompatibleDC( NULL );
|
||
|
|
||
|
// Associate the drawing surface
|
||
|
SelectObject( hDC, hBitmap );
|
||
|
|
||
|
// Create a clip region
|
||
|
HRGN rgn = CreateRectRgn( 0, 0, m_dwTextureWidth, m_dwTextureHeight );
|
||
|
SelectClipRgn( hDC, rgn );
|
||
|
|
||
|
// clear the background
|
||
|
unsigned char *pBGRA = GetTextureBits( hBitmap, m_dwTextureWidth, m_dwTextureHeight, 0, 0, m_dwTextureWidth, m_dwTextureHeight );
|
||
|
for (i=0; i<(int)(m_dwTextureHeight*m_dwTextureWidth); i++)
|
||
|
{
|
||
|
pBGRA[i*4+0] = 0xFF;
|
||
|
pBGRA[i*4+1] = 0x00;
|
||
|
pBGRA[i*4+2] = 0x00;
|
||
|
pBGRA[i*4+3] = 0x00;
|
||
|
}
|
||
|
SetTextureBits( hBitmap, m_dwTextureWidth, m_dwTextureHeight, 0, 0, m_dwTextureWidth, m_dwTextureHeight, pBGRA );
|
||
|
|
||
|
// build the glyph table
|
||
|
GLYPH_ATTR* pGlyphs = new GLYPH_ATTR[m_dwNumGlyphs];
|
||
|
memset( pGlyphs, 0, m_dwNumGlyphs*sizeof( GLYPH_ATTR ) );
|
||
|
|
||
|
int x = 0;
|
||
|
int y = 0;
|
||
|
int maxHeight = 0;
|
||
|
|
||
|
for( DWORD i=0; i<m_dwNumGlyphs; i++ )
|
||
|
{
|
||
|
if ( !i )
|
||
|
{
|
||
|
// account for null
|
||
|
continue;
|
||
|
}
|
||
|
else if ( TL_Exists( m_pCustomGlyphFiles[i-1] ) )
|
||
|
{
|
||
|
TL_LoadTGA( m_pCustomGlyphFiles[i-1], &pTGAPixels, &w, &h );
|
||
|
|
||
|
// convert to expected order
|
||
|
for (int j=0; j<h*w; j++)
|
||
|
{
|
||
|
int r = pTGAPixels[j*4+0];
|
||
|
int g = pTGAPixels[j*4+1];
|
||
|
int b = pTGAPixels[j*4+2];
|
||
|
|
||
|
pTGAPixels[j*4+0] = b;
|
||
|
pTGAPixels[j*4+1] = g;
|
||
|
pTGAPixels[j*4+2] = r;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// build a "bad" symbol
|
||
|
pTGAPixels = (byte_t*)TL_Malloc( 32*32*4 );
|
||
|
w = 32;
|
||
|
h = 32;
|
||
|
for (int j=0; j<32*32; j++)
|
||
|
{
|
||
|
pTGAPixels[j*4+0] = 0x00;
|
||
|
pTGAPixels[j*4+1] = 0x00;
|
||
|
pTGAPixels[j*4+2] = 0xFF;
|
||
|
pTGAPixels[j*4+3] = 0xFF;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( m_maxCustomCharHeight < h )
|
||
|
{
|
||
|
m_maxCustomCharHeight = h;
|
||
|
}
|
||
|
|
||
|
if ( maxHeight < h )
|
||
|
{
|
||
|
maxHeight = h;
|
||
|
}
|
||
|
|
||
|
if ( x + w > (int)m_dwTextureWidth )
|
||
|
{
|
||
|
// skip to new row
|
||
|
y += maxHeight;
|
||
|
x = 0;
|
||
|
maxHeight = h;
|
||
|
}
|
||
|
|
||
|
SetTextureBits( hBitmap, m_dwTextureWidth, m_dwTextureHeight, x, y, w, h, pTGAPixels );
|
||
|
TL_Free( pTGAPixels );
|
||
|
|
||
|
// Store the glyph attributes
|
||
|
pGlyphs[i].x = x;
|
||
|
pGlyphs[i].y = y;
|
||
|
pGlyphs[i].w = w;
|
||
|
pGlyphs[i].h = h;
|
||
|
pGlyphs[i].a = 0;
|
||
|
pGlyphs[i].b = w;
|
||
|
pGlyphs[i].c = 0;
|
||
|
pGlyphs[i].fLeft = ((FLOAT)(x+0)) / m_dwTextureWidth;
|
||
|
pGlyphs[i].fTop = ((FLOAT)(y+0)) / m_dwTextureHeight;
|
||
|
pGlyphs[i].fRight = ((FLOAT)(x+w)) / m_dwTextureWidth;
|
||
|
pGlyphs[i].fBottom = ((FLOAT)(y+h)) / m_dwTextureHeight;
|
||
|
|
||
|
x += w;
|
||
|
}
|
||
|
|
||
|
SelectClipRgn( hDC, NULL );
|
||
|
DeleteObject( rgn );
|
||
|
DeleteDC( hDC );
|
||
|
delete [] pBGRA;
|
||
|
|
||
|
return pGlyphs;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Name: CalculateAndRenderGlyphs()
|
||
|
// Desc: Draws the list of font glyphs
|
||
|
//-----------------------------------------------------------------------------
|
||
|
HRESULT CTextureFont::CalculateAndRenderGlyphs()
|
||
|
{
|
||
|
// Create a bitmap
|
||
|
HBITMAP hBitmap = CreateBitmap( m_dwTextureWidth, m_dwTextureHeight, 1, 32, NULL );
|
||
|
|
||
|
if ( m_pGlyphs )
|
||
|
delete[] m_pGlyphs;
|
||
|
|
||
|
if ( m_pCustomFilename )
|
||
|
{
|
||
|
m_pGlyphs = RenderCustomGlyphs( hBitmap );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Create a font
|
||
|
if ( m_hFont )
|
||
|
{
|
||
|
DeleteObject( m_hFont );
|
||
|
}
|
||
|
|
||
|
if ( m_bAntialiasEffect )
|
||
|
{
|
||
|
m_LogFont.lfQuality = ANTIALIASED_QUALITY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_LogFont.lfQuality = NONANTIALIASED_QUALITY;
|
||
|
}
|
||
|
|
||
|
m_hFont = CreateFontIndirect( &m_LogFont );
|
||
|
|
||
|
m_pGlyphs = RenderTTFGlyphs(
|
||
|
m_hFont,
|
||
|
hBitmap,
|
||
|
m_dwTextureWidth,
|
||
|
m_dwTextureHeight,
|
||
|
m_bOutlineEffect,
|
||
|
m_bShadowEffect,
|
||
|
m_nScanlines,
|
||
|
m_nBlur,
|
||
|
m_bAntialiasEffect,
|
||
|
m_ValidGlyphs,
|
||
|
m_dwNumGlyphs );
|
||
|
}
|
||
|
|
||
|
// Store the resulting bits
|
||
|
if ( m_pBits )
|
||
|
delete[] m_pBits;
|
||
|
m_pBits = new DWORD[ m_dwTextureWidth * m_dwTextureHeight ];
|
||
|
|
||
|
GetBitmapBits2( hBitmap, m_dwTextureWidth, m_dwTextureHeight, m_pBits );
|
||
|
|
||
|
DeleteObject( hBitmap );
|
||
|
|
||
|
return S_OK;
|
||
|
}
|