bitmap font work
This commit is contained in:
@@ -187,28 +187,29 @@ void BitmapText::DrawPrimitives()
|
|||||||
for( unsigned j=0; j<szLine.size(); j++ ) // for each character in the line
|
for( unsigned j=0; j<szLine.size(); j++ ) // for each character in the line
|
||||||
{
|
{
|
||||||
const char c = szLine[j];
|
const char c = szLine[j];
|
||||||
const int iFrameNo = m_pFont->m_iCharToFrameNo[ (unsigned char)c ];
|
if(m_pFont->m_iCharToFrameNo.find(c) == m_pFont->m_iCharToFrameNo.end())
|
||||||
if( iFrameNo == -1 ) // this font doesn't impelemnt this character
|
|
||||||
RageException::Throw( "The font '%s' does not implement the character '%c'", m_sFontFilePath.GetString(), c );
|
RageException::Throw( "The font '%s' does not implement the character '%c'", m_sFontFilePath.GetString(), c );
|
||||||
|
|
||||||
|
const int iFrameNo = m_pFont->m_iCharToFrameNo[ (unsigned char)c ];
|
||||||
|
|
||||||
|
const glyph &g = m_pFont->GetGlyph(iFrameNo);
|
||||||
|
|
||||||
/* set vertex positions */
|
/* set vertex positions */
|
||||||
v[iNumV++].p = RageVector3( (float)iX-m_pFont->m_Left[iFrameNo], iY-iHeight/2.0f, 0 ); // top left
|
v[iNumV++].p = RageVector3( (float)iX-g.left, iY-iHeight/2.0f, 0 ); // top left
|
||||||
v[iNumV++].p = RageVector3( (float)iX-m_pFont->m_Left[iFrameNo], iY+iHeight/2.0f, 0 ); // bottom left
|
v[iNumV++].p = RageVector3( (float)iX-g.left, iY+iHeight/2.0f, 0 ); // bottom left
|
||||||
v[iNumV++].p = RageVector3( (float)iX+m_pFont->m_Right[iFrameNo], iY+iHeight/2.0f, 0 ); // bottom right
|
v[iNumV++].p = RageVector3( (float)iX+g.right, iY+iHeight/2.0f, 0 ); // bottom right
|
||||||
v[iNumV++].p = RageVector3( (float)iX+m_pFont->m_Right[iFrameNo], iY-iHeight/2.0f, 0 ); // top right
|
v[iNumV++].p = RageVector3( (float)iX+g.right, iY-iHeight/2.0f, 0 ); // top right
|
||||||
|
|
||||||
/* Advance the cursor. */
|
/* Advance the cursor. */
|
||||||
iX += m_pFont->m_iFrameNoToWidth[iFrameNo];
|
iX += g.width;
|
||||||
|
|
||||||
/* set texture coordinates */
|
/* set texture coordinates */
|
||||||
iNumV -= 4;
|
iNumV -= 4;
|
||||||
|
|
||||||
RectF frectTexCoords = m_pFont->GetTextureCoordRect( iFrameNo );
|
v[iNumV++].t = RageVector2( g.rect.left, g.rect.top ); // top left
|
||||||
|
v[iNumV++].t = RageVector2( g.rect.left, g.rect.bottom ); // bottom left
|
||||||
v[iNumV++].t = RageVector2( frectTexCoords.left, frectTexCoords.top ); // top left
|
v[iNumV++].t = RageVector2( g.rect.right, g.rect.bottom ); // bottom right
|
||||||
v[iNumV++].t = RageVector2( frectTexCoords.left, frectTexCoords.bottom ); // bottom left
|
v[iNumV++].t = RageVector2( g.rect.right, g.rect.top ); // top right
|
||||||
v[iNumV++].t = RageVector2( frectTexCoords.right, frectTexCoords.bottom ); // bottom right
|
|
||||||
v[iNumV++].t = RageVector2( frectTexCoords.right, frectTexCoords.top ); // top right
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iY += iLineSpacing;
|
iY += iLineSpacing;
|
||||||
|
|||||||
+101
-91
@@ -23,17 +23,74 @@
|
|||||||
|
|
||||||
void Font::Init()
|
void Font::Init()
|
||||||
{
|
{
|
||||||
int i;
|
m_bCapitalsOnly = false;
|
||||||
|
m_iRefCount = 1;
|
||||||
for( i=0; i<MAX_FONT_CHARS; i++ )
|
|
||||||
{
|
|
||||||
m_iCharToFrameNo[i] = -1;
|
|
||||||
m_iFrameNoToWidth[i] = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_bCapitalsOnly = false;
|
void Font::Load( const CString &TexturePath, IniFile &ini )
|
||||||
|
{
|
||||||
|
m_sTexturePath = TexturePath;
|
||||||
|
|
||||||
m_iRefCount = 1;
|
// load texture
|
||||||
|
m_sTexturePath.MakeLower();
|
||||||
|
m_pTexture = TEXTUREMAN->LoadTexture( m_sTexturePath );
|
||||||
|
ASSERT( m_pTexture != NULL );
|
||||||
|
|
||||||
|
m_iLineSpacing = m_pTexture->GetSourceFrameHeight();
|
||||||
|
|
||||||
|
// load character widths
|
||||||
|
vector<int> FrameWidths;
|
||||||
|
int i;
|
||||||
|
// Assume each character is the width of the frame by default.
|
||||||
|
for( i=0; i<256; i++ )
|
||||||
|
FrameWidths.push_back(m_pTexture->GetSourceFrameWidth());
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Iterate over all keys. */
|
||||||
|
const IniFile::key *k = ini.GetKey("main");
|
||||||
|
if(k)
|
||||||
|
{
|
||||||
|
for(IniFile::key::const_iterator key = k->begin(); key != k->end(); ++key)
|
||||||
|
{
|
||||||
|
CString val = key->first;
|
||||||
|
CString data = key->second;
|
||||||
|
|
||||||
|
val.MakeUpper();
|
||||||
|
|
||||||
|
/* If val is an integer, it's a width, eg. "10=27". */
|
||||||
|
if(IsAnInt(val))
|
||||||
|
{
|
||||||
|
FrameWidths[atoi(val)] = atoi(data);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ini.GetValueB( "main", "CapitalsOnly", m_bCapitalsOnly );
|
||||||
|
int DrawExtraPixelsLeft = 0, DrawExtraPixelsRight = 0;
|
||||||
|
|
||||||
|
ini.GetValueI( "main", "DrawExtraPixelsLeft", DrawExtraPixelsLeft );
|
||||||
|
ini.GetValueI( "main", "DrawExtraPixelsRight", DrawExtraPixelsRight );
|
||||||
|
|
||||||
|
int iAddToAllWidths = 0;
|
||||||
|
if( ini.GetValueI( "main", "AddToAllWidths", iAddToAllWidths ) )
|
||||||
|
{
|
||||||
|
for( int i=0; i<256; i++ )
|
||||||
|
FrameWidths[i] += iAddToAllWidths;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fScaleAllWidthsBy = 0;
|
||||||
|
if( ini.GetValueF( "main", "ScaleAllWidthsBy", fScaleAllWidthsBy ) )
|
||||||
|
{
|
||||||
|
for( int i=0; i<256; i++ )
|
||||||
|
FrameWidths[i] = int(roundf( FrameWidths[i] * fScaleAllWidthsBy ));
|
||||||
|
}
|
||||||
|
|
||||||
|
ini.GetValueI( "main", "LineSpacing", m_iLineSpacing );
|
||||||
|
|
||||||
|
SetTextureCoords(FrameWidths);
|
||||||
|
SetExtraPixels(DrawExtraPixelsLeft, DrawExtraPixelsRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::Font( const CString &sASCIITexturePath )
|
Font::Font( const CString &sASCIITexturePath )
|
||||||
@@ -42,56 +99,23 @@ Font::Font( const CString &sASCIITexturePath )
|
|||||||
|
|
||||||
Init();
|
Init();
|
||||||
|
|
||||||
// load texture
|
/* Default to 0..255. */
|
||||||
m_sTexturePath = sASCIITexturePath;
|
for( int i=0; i<256; i++ )
|
||||||
m_sTexturePath.MakeLower();
|
|
||||||
m_pTexture = TEXTUREMAN->LoadTexture( m_sTexturePath );
|
|
||||||
ASSERT( m_pTexture != NULL );
|
|
||||||
if( m_pTexture->GetNumFrames() != 16*16 )
|
|
||||||
RageException::Throw( "The font '%s' has only %d frames. All fonts must have 16*16 frames.", m_sTexturePath.GetString() );
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for( i=0; i<256; i++ )
|
|
||||||
m_iCharToFrameNo[i] = i;
|
m_iCharToFrameNo[i] = i;
|
||||||
|
|
||||||
// Find .ini widths path from texture path
|
// Find .ini widths path from texture path
|
||||||
CString sDir, sFileName, sExtension;
|
CString sDir, sFileName, sExtension;
|
||||||
splitrelpath( sASCIITexturePath, sDir, sFileName, sExtension );
|
splitrelpath( sASCIITexturePath, sDir, sFileName, sExtension );
|
||||||
const CString sIniPath = sDir + sFileName + ".ini";
|
const CString sIniPath = sDir + sFileName + ".ini";
|
||||||
|
|
||||||
IniFile ini;
|
IniFile ini;
|
||||||
ini.SetPath( sIniPath );
|
ini.SetPath( sIniPath );
|
||||||
ini.ReadFile();
|
ini.ReadFile();
|
||||||
|
ini.RenameKey("Char Widths", "main");
|
||||||
|
Load(sASCIITexturePath, ini);
|
||||||
|
|
||||||
// load character widths
|
if( m_pTexture->GetNumFrames() != 16*16 )
|
||||||
for( i=0; i<256; i++ )
|
RageException::Throw( "The font '%s' has only %d frames. All fonts must have 16*16 frames.", m_sTexturePath.GetString() );
|
||||||
if( !ini.GetValueI( "Char Widths", ssprintf("%d",i), m_iFrameNoToWidth[i] ) )
|
|
||||||
RageException::Throw( "Error reading width value '%d' from '%s'.", i, sIniPath.GetString() );
|
|
||||||
|
|
||||||
ini.GetValueB( "Char Widths", "CapitalsOnly", m_bCapitalsOnly );
|
|
||||||
int DrawExtraPixelsLeft = 0, DrawExtraPixelsRight = 0;
|
|
||||||
|
|
||||||
ini.GetValueI( "Char Widths", "DrawExtraPixelsLeft", DrawExtraPixelsLeft );
|
|
||||||
ini.GetValueI( "Char Widths", "DrawExtraPixelsRight", DrawExtraPixelsRight );
|
|
||||||
|
|
||||||
int iAddToAllWidths = 0;
|
|
||||||
if( ini.GetValueI( "Char Widths", "AddToAllWidths", iAddToAllWidths ) )
|
|
||||||
{
|
|
||||||
for( int i=0; i<256; i++ )
|
|
||||||
m_iFrameNoToWidth[i] += iAddToAllWidths;
|
|
||||||
}
|
|
||||||
|
|
||||||
float fScaleAllWidthsBy = 0;
|
|
||||||
if( ini.GetValueF( "Char Widths", "ScaleAllWidthsBy", fScaleAllWidthsBy ) )
|
|
||||||
{
|
|
||||||
for( int i=0; i<256; i++ )
|
|
||||||
m_iFrameNoToWidth[i] = int(roundf( m_iFrameNoToWidth[i] * fScaleAllWidthsBy ));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_iLineSpacing = m_pTexture->GetSourceFrameHeight();
|
|
||||||
ini.GetValueI( "Char Widths", "LineSpacing", m_iLineSpacing );
|
|
||||||
|
|
||||||
SetTextureCoords();
|
|
||||||
SetExtraPixels(DrawExtraPixelsLeft, DrawExtraPixelsRight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -101,42 +125,24 @@ Font::Font( const CString &sTexturePath, const CString& sCharacters )
|
|||||||
|
|
||||||
Init();
|
Init();
|
||||||
|
|
||||||
//
|
/* Map characters to frames; we don't actually have an INI. */
|
||||||
// load texture
|
for( int i=0; i<sCharacters.GetLength(); i++ )
|
||||||
//
|
{
|
||||||
m_sTexturePath = sTexturePath; // save
|
char c = sCharacters[i];
|
||||||
m_sTexturePath.MakeLower();
|
m_iCharToFrameNo[c] = i;
|
||||||
|
}
|
||||||
|
|
||||||
m_pTexture = TEXTUREMAN->LoadTexture( m_sTexturePath );
|
/* load texture */
|
||||||
ASSERT( m_pTexture != NULL );
|
IniFile ini;
|
||||||
m_iLineSpacing = m_pTexture->GetSourceFrameHeight();
|
Load(sTexturePath, ini);
|
||||||
|
|
||||||
//
|
|
||||||
// find out what characters are in this font
|
|
||||||
//
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if( sCharacters.GetLength() != m_pTexture->GetNumFrames() )
|
if( sCharacters.GetLength() != m_pTexture->GetNumFrames() )
|
||||||
RageException::Throw( "The image '%s' doesn't have the correct number of frames. It has %d frames but should have %d frames.",
|
RageException::Throw( "The image '%s' doesn't have the correct number of frames. It has %d frames but should have %d frames.",
|
||||||
m_sTexturePath.GetString(), m_pTexture->GetNumFrames(), sCharacters.GetLength() );
|
m_sTexturePath.GetString(), m_pTexture->GetNumFrames(), sCharacters.GetLength() );
|
||||||
|
|
||||||
// set the char to frame number map
|
|
||||||
int i;
|
|
||||||
for( i=0; i<sCharacters.GetLength(); i++ )
|
|
||||||
{
|
|
||||||
char c = sCharacters[i];
|
|
||||||
int iFrameNo = i;
|
|
||||||
|
|
||||||
m_iCharToFrameNo[c] = iFrameNo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assume each character is the width of the frame.
|
void Font::SetTextureCoords(const vector<int> &widths)
|
||||||
for( i=0; i<(int)m_pTexture->GetNumFrames(); i++ )
|
|
||||||
m_iFrameNoToWidth[i] = m_pTexture->GetSourceFrameWidth();
|
|
||||||
|
|
||||||
SetTextureCoords();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Font::SetTextureCoords()
|
|
||||||
{
|
{
|
||||||
// force widths to even number
|
// force widths to even number
|
||||||
// Why do this? It seems to just artificially widen some characters a little and
|
// Why do this? It seems to just artificially widen some characters a little and
|
||||||
@@ -148,47 +154,51 @@ void Font::SetTextureCoords()
|
|||||||
|
|
||||||
for(int i = 0; i < m_pTexture->GetNumFrames(); ++i)
|
for(int i = 0; i < m_pTexture->GetNumFrames(); ++i)
|
||||||
{
|
{
|
||||||
|
glyph g;
|
||||||
|
g.left = g.right = 0;
|
||||||
|
|
||||||
/* Make a copy of each texture rect, reducing each to the actual dimensions
|
/* Make a copy of each texture rect, reducing each to the actual dimensions
|
||||||
* of the character (most characters don't take a full block). */
|
* of the character (most characters don't take a full block). */
|
||||||
RectF r = *m_pTexture->GetTextureCoordRect(i);;
|
g.rect = *m_pTexture->GetTextureCoordRect(i);;
|
||||||
|
|
||||||
float fPixelsToChopOff = m_pTexture->GetSourceFrameWidth() - (float)m_iFrameNoToWidth[i];
|
float fPixelsToChopOff = m_pTexture->GetSourceFrameWidth() - (float)widths[i];
|
||||||
float fTexCoordsToChopOff = fPixelsToChopOff / m_pTexture->GetSourceWidth();
|
float fTexCoordsToChopOff = fPixelsToChopOff / m_pTexture->GetSourceWidth();
|
||||||
|
|
||||||
r.left += fTexCoordsToChopOff/2;
|
g.rect.left += fTexCoordsToChopOff/2;
|
||||||
r.right -= fTexCoordsToChopOff/2;
|
g.rect.right -= fTexCoordsToChopOff/2;
|
||||||
m_TextureCoordRects.push_back(r);
|
|
||||||
|
|
||||||
/* Add normal widths. */
|
/* Add normal widths. */
|
||||||
m_Left.push_back(0);
|
g.left = 0;
|
||||||
m_Right.push_back(m_iFrameNoToWidth[i]);
|
g.right = g.width = widths[i];
|
||||||
|
|
||||||
|
glyphs.push_back(g);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::SetExtraPixels(int DrawExtraPixelsLeft, int DrawExtraPixelsRight)
|
void Font::SetExtraPixels(int DrawExtraPixelsLeft, int DrawExtraPixelsRight)
|
||||||
{
|
{
|
||||||
/* Adjust for DrawExtraPixelsLeft and DrawExtraPixelsRight. */
|
/* Adjust for DrawExtraPixelsLeft and DrawExtraPixelsRight. */
|
||||||
for(unsigned i = 0; i < m_TextureCoordRects.size(); ++i)
|
for(unsigned i = 0; i < glyphs.size(); ++i)
|
||||||
{
|
{
|
||||||
int iFrameWidth = m_pTexture->GetSourceFrameWidth();
|
int iFrameWidth = m_pTexture->GetSourceFrameWidth();
|
||||||
int iCharWidth = m_iFrameNoToWidth[i];
|
int iCharWidth = glyphs[i].width;
|
||||||
|
|
||||||
/* Extra pixels to draw to the left and right. */
|
/* Extra pixels to draw to the left and right. */
|
||||||
int ExtraLeft = min( DrawExtraPixelsLeft, (iFrameWidth-iCharWidth)/2 );
|
int ExtraLeft = min( DrawExtraPixelsLeft, (iFrameWidth-iCharWidth)/2 );
|
||||||
int ExtraRight = min( DrawExtraPixelsRight, (iFrameWidth-iCharWidth)/2 ) + ExtraLeft;
|
int ExtraRight = min( DrawExtraPixelsRight, (iFrameWidth-iCharWidth)/2 ) + ExtraLeft;
|
||||||
|
|
||||||
/* Move left and expand right. */
|
/* Move left and expand right. */
|
||||||
m_TextureCoordRects[i].left -= float(ExtraLeft) / m_pTexture->GetSourceWidth();
|
glyphs[i].rect.left -= float(ExtraLeft) / m_pTexture->GetSourceWidth();
|
||||||
m_TextureCoordRects[i].right += float(ExtraRight) / m_pTexture->GetSourceWidth();
|
glyphs[i].rect.right += float(ExtraRight) / m_pTexture->GetSourceWidth();
|
||||||
m_Left[i] += ExtraLeft;
|
glyphs[i].left += ExtraLeft;
|
||||||
m_Right[i] += ExtraRight;
|
glyphs[i].right += ExtraRight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::~Font()
|
Font::~Font()
|
||||||
{
|
{
|
||||||
if( m_pTexture != NULL )
|
if( m_pTexture != NULL )
|
||||||
TEXTUREMAN->UnloadTexture( m_sTexturePath );
|
TEXTUREMAN->UnloadTexture( m_pTexture );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -203,7 +213,7 @@ int Font::GetLineWidthInSourcePixels( const CString &szLine )
|
|||||||
if( iFrameNo == -1 ) // this font doesn't impelemnt this character
|
if( iFrameNo == -1 ) // this font doesn't impelemnt this character
|
||||||
RageException::Throw( "The font '%s' does not implement the character '%c'", m_sTexturePath.GetString(), c );
|
RageException::Throw( "The font '%s' does not implement the character '%c'", m_sTexturePath.GetString(), c );
|
||||||
|
|
||||||
iLineWidth += m_iFrameNoToWidth[iFrameNo];
|
iLineWidth += glyphs[iFrameNo].width;
|
||||||
}
|
}
|
||||||
|
|
||||||
return iLineWidth;
|
return iLineWidth;
|
||||||
|
|||||||
+14
-11
@@ -12,9 +12,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "RageTexture.h"
|
#include "RageTexture.h"
|
||||||
|
#include "IniFile.h"
|
||||||
|
|
||||||
const int MAX_FONT_CHARS = 256; // only low ASCII chars are supported
|
struct glyph {
|
||||||
|
int width;
|
||||||
|
/* X coordinates to be rendered for this character are X-left and X+right. */
|
||||||
|
int left, right;
|
||||||
|
|
||||||
|
/* Texture coordinate rect. */
|
||||||
|
RectF rect;
|
||||||
|
};
|
||||||
|
|
||||||
class Font
|
class Font
|
||||||
{
|
{
|
||||||
@@ -30,24 +37,20 @@ public:
|
|||||||
|
|
||||||
CString m_sTexturePath;
|
CString m_sTexturePath;
|
||||||
|
|
||||||
|
vector<glyph> glyphs;
|
||||||
|
|
||||||
RageTexture* m_pTexture;
|
RageTexture* m_pTexture;
|
||||||
bool m_bCapitalsOnly;
|
bool m_bCapitalsOnly;
|
||||||
int m_iLineSpacing;
|
int m_iLineSpacing;
|
||||||
|
|
||||||
int m_iCharToFrameNo[MAX_FONT_CHARS];
|
map<int,int> m_iCharToFrameNo;
|
||||||
int m_iFrameNoToWidth[MAX_FONT_CHARS]; // in soure coordinate space
|
|
||||||
|
|
||||||
const RectF &GetTextureCoordRect( int frameNo ) const { return m_TextureCoordRects[frameNo]; }
|
const glyph &GetGlyph( int frameNo ) const { return glyphs[frameNo]; }
|
||||||
|
|
||||||
/* Source pixels to print to the left and right of each character.
|
|
||||||
* m_Left[] is usually 0. */
|
|
||||||
vector<int> m_Left, m_Right;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector<RectF> m_TextureCoordRects;
|
|
||||||
void SetExtraPixels(int DrawExtraPixelsLeft, int DrawExtraPixelsRight);
|
void SetExtraPixels(int DrawExtraPixelsLeft, int DrawExtraPixelsRight);
|
||||||
void SetTextureCoords();
|
void SetTextureCoords(const vector<int> &widths);
|
||||||
|
void Load( const CString &sASCIITexturePath, IniFile &ini );
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user