more bitmap font work

This commit is contained in:
Glenn Maynard
2003-01-04 01:47:01 +00:00
parent 1c6dba0ccc
commit 4bb452404c
4 changed files with 99 additions and 55 deletions
+26 -23
View File
@@ -104,6 +104,7 @@ void BitmapText::SetText( CString sText )
/* Break the string into lines. */
m_szTextLines.clear();
m_iLineWidths.clear();
m_iLineHeights.clear();
split(m_szText, "\n", m_szTextLines, false);
@@ -113,6 +114,7 @@ void BitmapText::SetText( CString sText )
for( unsigned l=0; l<m_szTextLines.size(); l++ ) // for each line
{
m_iLineWidths.push_back(m_pFont->GetLineWidthInSourcePixels( m_szTextLines[l] ));
m_iLineHeights.push_back(m_pFont->GetLineHeightInSourcePixels( m_szTextLines[l] ));
m_iWidestLineWidth = max(m_iWidestLineWidth, m_iLineWidths.back());
}
}
@@ -157,30 +159,31 @@ void BitmapText::DrawPrimitives()
int iNumV = 0; // the current vertex number
// make the object in logical units centered at the origin
const int iHeight = pTexture->GetSourceFrameHeight(); // height of a character
const int iLineSpacing = m_pFont->m_iLineSpacing; // spacing between lines
float TotalHeight = 0;
unsigned i;
for(i = 0; i < m_szTextLines.size(); ++i)
TotalHeight += m_iLineHeights[i];
int iY; // the center position of the first row of characters
float iY; // the top position of the first row of characters
switch( m_VertAlign )
{
case align_bottom: iY = -(int(m_szTextLines.size())) * iLineSpacing + iLineSpacing/2; break;
case align_middle: iY = -(int(m_szTextLines.size())-1) * iLineSpacing/2; break;
case align_top: iY = + iLineSpacing/2; break;
default: ASSERT( false ); return;
case align_top: iY = 0; break;
case align_middle: iY = -TotalHeight/2.0f; break;
case align_bottom: iY = -TotalHeight; break;
default: ASSERT( false ); return;
}
for( unsigned i=0; i<m_szTextLines.size(); i++ ) // foreach line
for( i=0; i<m_szTextLines.size(); i++ ) // foreach line
{
const CString &szLine = m_szTextLines[i];
const int iLineWidth = m_iLineWidths[i];
const float fLineWidth = float(m_iLineWidths[i]);
int iX;
float iX;
switch( m_HorizAlign )
{
case align_left: iX = 0; break;
case align_center: iX = -(iLineWidth/2); break;
case align_right: iX = -iLineWidth; break;
case align_center: iX = -fLineWidth/2.0f; break;
case align_right: iX = -fLineWidth; break;
default: ASSERT( false ); return;
}
@@ -195,24 +198,24 @@ void BitmapText::DrawPrimitives()
const glyph &g = m_pFont->GetGlyph(iFrameNo);
/* set vertex positions */
v[iNumV++].p = RageVector3( (float)iX-g.left, iY-iHeight/2.0f, 0 ); // top left
v[iNumV++].p = RageVector3( (float)iX-g.left, iY+iHeight/2.0f, 0 ); // bottom left
v[iNumV++].p = RageVector3( (float)iX+g.right, iY+iHeight/2.0f, 0 ); // bottom right
v[iNumV++].p = RageVector3( (float)iX+g.right, iY-iHeight/2.0f, 0 ); // top right
v[iNumV++].p = RageVector3( (float)iX+g.hshift, iY+g.vshift, 0 ); // top left
v[iNumV++].p = RageVector3( (float)iX+g.hshift, iY+g.vshift+g.height, 0 ); // bottom left
v[iNumV++].p = RageVector3( (float)iX+g.hshift+g.width, iY+g.vshift+g.height, 0 ); // bottom right
v[iNumV++].p = RageVector3( (float)iX+g.hshift+g.width, iY+g.vshift, 0 ); // top right
/* Advance the cursor. */
iX += g.width;
iX += g.advance;
/* set texture coordinates */
iNumV -= 4;
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( g.rect.right, g.rect.bottom ); // bottom right
v[iNumV++].t = RageVector2( g.rect.right, g.rect.top ); // top right
v[iNumV++].t = RageVector2( g.rect.left, g.rect.top );
v[iNumV++].t = RageVector2( g.rect.left, g.rect.bottom );
v[iNumV++].t = RageVector2( g.rect.right, g.rect.bottom );
v[iNumV++].t = RageVector2( g.rect.right, g.rect.top );
}
iY += iLineSpacing;
iY += m_iLineHeights[i];
}
+1
View File
@@ -46,6 +46,7 @@ protected:
CString m_szText;
vector<CString> m_szTextLines;
vector<int> m_iLineWidths; // in source pixels
vector<int> m_iLineHeights; // in source pixels
int m_iWidestLineWidth; // in source pixels
bool m_bRainbow;
+63 -29
View File
@@ -63,6 +63,25 @@ void Font::Load( const CString &TexturePath, IniFile &ini )
FrameWidths[atoi(val)] = atoi(data);
continue;
}
/* "map XXXX=frame" maps a char to a frame. */
if(val.substr(0, 4) == "map ")
{
val = val.substr(4); /* "XXXX" */
/* XXXX can be "U+HEX". */
int c = -1;
if(val.substr(0, 2) == "U+" && IsHexVal(val.substr(2)))
sscanf(val.substr(2).c_str(), "%x", &c);
if(c == -1)
RageException::Throw( "The font '%s' has an invalid INI value '%s'.",
m_sTexturePath.GetString(), val.GetString() );
m_iCharToFrameNo[i] = atoi(data);
}
}
}
}
@@ -144,35 +163,45 @@ Font::Font( const CString &sTexturePath, const CString& sCharacters )
void Font::SetTextureCoords(const vector<int> &widths)
{
// force widths to even number
// Why do this? It seems to just artificially widen some characters a little and
// make it look a little worse in 640x480 ...
/* for( i=0; i<256; i++ )
if( m_iFrameNoToWidth[i]%2 == 1 )
m_iFrameNoToWidth[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
* of the character (most characters don't take a full block). */
g.rect = *m_pTexture->GetTextureCoordRect(i);;
float fPixelsToChopOff = m_pTexture->GetSourceFrameWidth() - (float)widths[i];
float fTexCoordsToChopOff = fPixelsToChopOff / m_pTexture->GetSourceWidth();
g.rect.left += fTexCoordsToChopOff/2;
g.rect.right -= fTexCoordsToChopOff/2;
/* Set the width and height to the width and line spacing, respectively. */
g.width = float(widths[i]);
g.height = float(m_pTexture->GetSourceFrameHeight());
/* Add normal widths. */
g.left = 0;
g.right = g.width = widths[i];
/* Shift the character up so the top of the rendered quad is at the top
* of the character. */
g.vshift = -(m_pTexture->GetSourceFrameHeight() - m_iLineSpacing)/2.0f;
/* Do the same thing with X. Do this by changing the actual rendered
* rect, instead of shifting it, so we don't render more than we need to. */
g.hshift = 0;
{
int iPixelsToChopOff = m_pTexture->GetSourceFrameWidth() - widths[i];
float fTexCoordsToChopOff = float(iPixelsToChopOff) / m_pTexture->GetSourceWidth();
g.rect.left += fTexCoordsToChopOff/2;
g.rect.right -= fTexCoordsToChopOff/2;
}
/* By default, advance one pixel more than the width. (This could be
* an option.) */
g.advance = g.width + 1;
glyphs.push_back(g);
}
// force widths to even number
// Why do this? It seems to just artificially widen some characters a little and
// make it look a little worse in 640x480 ...
// for( i=0; i<int(glyphs.size()); i++ )
// if( glyphs[i].width %2 == 1 )
// glyphs[i].width++;
}
void Font::SetExtraPixels(int DrawExtraPixelsLeft, int DrawExtraPixelsRight)
@@ -181,17 +210,18 @@ void Font::SetExtraPixels(int DrawExtraPixelsLeft, int DrawExtraPixelsRight)
for(unsigned i = 0; i < glyphs.size(); ++i)
{
int iFrameWidth = m_pTexture->GetSourceFrameWidth();
int iCharWidth = glyphs[i].width;
float iCharWidth = glyphs[i].advance;
/* Extra pixels to draw to the left and right. */
int ExtraLeft = min( DrawExtraPixelsLeft, (iFrameWidth-iCharWidth)/2 );
int ExtraRight = min( DrawExtraPixelsRight, (iFrameWidth-iCharWidth)/2 ) + ExtraLeft;
float ExtraLeft = min( float(DrawExtraPixelsLeft), (iFrameWidth-iCharWidth)/2.0f );
float ExtraRight = min( float(DrawExtraPixelsRight), (iFrameWidth-iCharWidth)/2.0f );
/* Move left and expand right. */
glyphs[i].rect.left -= float(ExtraLeft) / m_pTexture->GetSourceWidth();
glyphs[i].rect.right += float(ExtraRight) / m_pTexture->GetSourceWidth();
glyphs[i].left += ExtraLeft;
glyphs[i].right += ExtraRight;
glyphs[i].rect.left -= ExtraLeft / m_pTexture->GetSourceWidth();
glyphs[i].rect.right += ExtraRight / m_pTexture->GetSourceWidth();
glyphs[i].hshift -= ExtraLeft;
glyphs[i].width += ExtraLeft + ExtraRight;
// glyphs[i].advance += ExtraLeft + ExtraRight;
}
}
@@ -204,19 +234,23 @@ Font::~Font()
int Font::GetLineWidthInSourcePixels( const CString &szLine )
{
int iLineWidth = 0;
float LineWidth = 0;
for( unsigned i=0; i<szLine.size(); i++ )
{
const char c = szLine[i];
const int iFrameNo = m_iCharToFrameNo[ (unsigned char)c ];
if( iFrameNo == -1 ) // this font doesn't impelemnt this character
if(m_iCharToFrameNo.find(c) == m_iCharToFrameNo.end())
RageException::Throw( "The font '%s' does not implement the character '%c'", m_sTexturePath.GetString(), c );
iLineWidth += glyphs[iFrameNo].width;
const int iFrameNo = m_iCharToFrameNo[ (unsigned char)c ];
LineWidth += glyphs[iFrameNo].advance;
}
return iLineWidth;
return int(LineWidth);
}
int Font::GetLineHeightInSourcePixels( const CString &szLine )
{
return m_iLineSpacing;
}
+9 -3
View File
@@ -15,9 +15,14 @@
#include "IniFile.h"
struct glyph {
int width;
/* X coordinates to be rendered for this character are X-left and X+right. */
int left, right;
/* Number of pixels to advance horizontally after drawing this character. */
float advance;
/* Size of the actual rendered character. */
float width, height;
/* Number of pixels to offset this character when rendering. */
float hshift, vshift;
/* Texture coordinate rect. */
RectF rect;
@@ -32,6 +37,7 @@ public:
void Init();
int GetLineWidthInSourcePixels( const CString &szLine );
int GetLineHeightInSourcePixels( const CString &szLine );
int m_iRefCount;