2002-03-30 20:00:13 +00:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
Class: Font
|
|
|
|
|
|
|
|
|
|
Desc: See header.
|
|
|
|
|
|
2003-01-04 05:20:40 +00:00
|
|
|
Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved.
|
2002-03-30 20:00:13 +00:00
|
|
|
Chris Danford
|
2003-01-04 05:17:51 +00:00
|
|
|
Glenn Maynard
|
2002-03-30 20:00:13 +00:00
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "Font.h"
|
|
|
|
|
#include "IniFile.h"
|
2002-08-23 01:06:36 +00:00
|
|
|
|
2002-03-30 20:00:13 +00:00
|
|
|
#include "RageTextureManager.h"
|
|
|
|
|
#include "RageUtil.h"
|
2002-05-01 19:14:55 +00:00
|
|
|
#include "RageLog.h"
|
2002-07-27 19:29:51 +00:00
|
|
|
#include "RageException.h"
|
2002-06-14 22:25:22 +00:00
|
|
|
|
2003-01-04 05:17:51 +00:00
|
|
|
FontPage::FontPage()
|
2002-03-30 20:00:13 +00:00
|
|
|
{
|
2003-01-04 05:17:51 +00:00
|
|
|
m_pTexture = NULL;
|
2003-01-03 20:59:50 +00:00
|
|
|
}
|
|
|
|
|
|
2003-01-05 03:32:41 +00:00
|
|
|
void FontPage::Load( const CString &TexturePath, const FontPageSettings &cfg )
|
2003-01-03 20:59:50 +00:00
|
|
|
{
|
2003-01-03 22:53:22 +00:00
|
|
|
m_sTexturePath = TexturePath;
|
2002-03-30 20:00:13 +00:00
|
|
|
|
2002-09-03 22:31:06 +00:00
|
|
|
// load texture
|
|
|
|
|
m_sTexturePath.MakeLower();
|
2002-12-30 02:43:52 +00:00
|
|
|
m_pTexture = TEXTUREMAN->LoadTexture( m_sTexturePath );
|
2002-09-03 22:31:06 +00:00
|
|
|
ASSERT( m_pTexture != NULL );
|
2002-03-30 20:00:13 +00:00
|
|
|
|
2002-09-03 22:31:06 +00:00
|
|
|
// load character widths
|
2003-01-05 05:13:45 +00:00
|
|
|
vector<int> FrameWidths;
|
2003-01-03 22:53:22 +00:00
|
|
|
int i;
|
|
|
|
|
// Assume each character is the width of the frame by default.
|
2003-01-04 05:17:51 +00:00
|
|
|
for( i=0; i<m_pTexture->GetNumFrames(); i++ )
|
2003-01-03 22:53:22 +00:00
|
|
|
{
|
2003-01-05 03:32:41 +00:00
|
|
|
map<int,int>::const_iterator it = cfg.GlyphWidths.find(i);
|
|
|
|
|
if(it != cfg.GlyphWidths.end())
|
2003-01-03 22:53:22 +00:00
|
|
|
{
|
2003-01-05 03:32:41 +00:00
|
|
|
FrameWidths.push_back(it->second);
|
|
|
|
|
} else {
|
|
|
|
|
FrameWidths.push_back(m_pTexture->GetSourceFrameWidth());
|
2003-01-03 22:53:22 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-05 03:32:41 +00:00
|
|
|
if( cfg.AddToAllWidths )
|
2002-03-30 20:00:13 +00:00
|
|
|
{
|
2002-09-03 22:31:06 +00:00
|
|
|
for( int i=0; i<256; i++ )
|
2003-01-05 03:32:41 +00:00
|
|
|
FrameWidths[i] += cfg.AddToAllWidths;
|
2002-03-30 20:00:13 +00:00
|
|
|
}
|
2002-03-31 07:55:25 +00:00
|
|
|
|
2003-01-05 03:32:41 +00:00
|
|
|
if( cfg.ScaleAllWidthsBy != 1 )
|
2002-09-04 03:49:08 +00:00
|
|
|
{
|
|
|
|
|
for( int i=0; i<256; i++ )
|
2003-01-05 03:32:41 +00:00
|
|
|
FrameWidths[i] = int(roundf( FrameWidths[i] * cfg.ScaleAllWidthsBy ));
|
2002-09-04 03:49:08 +00:00
|
|
|
}
|
|
|
|
|
|
2003-01-05 03:32:41 +00:00
|
|
|
m_iCharToGlyphNo = cfg.CharToGlyphNo;
|
|
|
|
|
|
2003-01-04 05:17:51 +00:00
|
|
|
/* All characters on a page have the same vertical spacing. */
|
2003-01-05 03:32:41 +00:00
|
|
|
int LineSpacing = cfg.LineSpacing;
|
|
|
|
|
if(LineSpacing == -1)
|
|
|
|
|
LineSpacing = m_pTexture->GetSourceFrameHeight();
|
2002-03-30 20:00:13 +00:00
|
|
|
|
2003-01-04 05:17:51 +00:00
|
|
|
SetTextureCoords(FrameWidths, LineSpacing);
|
2003-01-05 03:32:41 +00:00
|
|
|
SetExtraPixels(cfg.DrawExtraPixelsLeft, cfg.DrawExtraPixelsRight);
|
2002-03-30 20:00:13 +00:00
|
|
|
}
|
|
|
|
|
|
2003-01-04 05:17:51 +00:00
|
|
|
void FontPage::SetTextureCoords(const vector<int> &widths, int LineSpacing)
|
2003-01-03 20:59:50 +00:00
|
|
|
{
|
|
|
|
|
for(int i = 0; i < m_pTexture->GetNumFrames(); ++i)
|
|
|
|
|
{
|
2003-01-03 22:53:22 +00:00
|
|
|
glyph g;
|
|
|
|
|
|
2003-01-03 20:59:50 +00:00
|
|
|
/* Make a copy of each texture rect, reducing each to the actual dimensions
|
|
|
|
|
* of the character (most characters don't take a full block). */
|
2003-01-03 22:53:22 +00:00
|
|
|
g.rect = *m_pTexture->GetTextureCoordRect(i);;
|
2003-01-03 20:59:50 +00:00
|
|
|
|
2003-01-04 01:47:01 +00:00
|
|
|
/* Set the width and height to the width and line spacing, respectively. */
|
|
|
|
|
g.width = float(widths[i]);
|
|
|
|
|
g.height = float(m_pTexture->GetSourceFrameHeight());
|
2003-01-03 20:59:50 +00:00
|
|
|
|
2003-01-04 07:55:42 +00:00
|
|
|
/* By default, advance one pixel more than the width. (This could be
|
|
|
|
|
* an option.) */
|
|
|
|
|
g.hadvance = int(g.width + 1);
|
|
|
|
|
|
2003-01-04 01:47:01 +00:00
|
|
|
/* Shift the character up so the top of the rendered quad is at the top
|
|
|
|
|
* of the character. */
|
2003-01-04 05:17:51 +00:00
|
|
|
g.vshift = -(m_pTexture->GetSourceFrameHeight() - LineSpacing)/2.0f;
|
2003-01-03 22:53:22 +00:00
|
|
|
|
2003-01-04 01:47:01 +00:00
|
|
|
/* 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];
|
2003-01-04 07:55:42 +00:00
|
|
|
if((iPixelsToChopOff % 2) == 1)
|
|
|
|
|
{
|
|
|
|
|
/* We don't want to chop off an odd number of pixels, since that'll
|
|
|
|
|
* put our texture coordinates between texels and make things blurrier. */
|
|
|
|
|
iPixelsToChopOff--;
|
|
|
|
|
g.width++;
|
|
|
|
|
}
|
2003-01-04 01:47:01 +00:00
|
|
|
float fTexCoordsToChopOff = float(iPixelsToChopOff) / m_pTexture->GetSourceWidth();
|
2003-01-04 07:55:42 +00:00
|
|
|
|
2003-01-04 01:47:01 +00:00
|
|
|
g.rect.left += fTexCoordsToChopOff/2;
|
|
|
|
|
g.rect.right -= fTexCoordsToChopOff/2;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-04 07:55:42 +00:00
|
|
|
g.vadvance = LineSpacing;
|
|
|
|
|
g.Texture = m_pTexture;
|
|
|
|
|
|
2003-01-03 22:53:22 +00:00
|
|
|
glyphs.push_back(g);
|
2003-01-03 20:59:50 +00:00
|
|
|
}
|
2002-08-13 23:26:46 +00:00
|
|
|
}
|
|
|
|
|
|
2003-01-04 05:17:51 +00:00
|
|
|
void FontPage::SetExtraPixels(int DrawExtraPixelsLeft, int DrawExtraPixelsRight)
|
2003-01-03 20:59:50 +00:00
|
|
|
{
|
2003-01-04 05:17:51 +00:00
|
|
|
/* Hack: do one more than we were asked to; I think a lot of fonts are one
|
|
|
|
|
* too low. */
|
|
|
|
|
DrawExtraPixelsRight++;
|
|
|
|
|
DrawExtraPixelsLeft++;
|
|
|
|
|
|
2003-01-04 07:55:42 +00:00
|
|
|
if((DrawExtraPixelsLeft % 2) == 1)
|
|
|
|
|
DrawExtraPixelsLeft++;
|
|
|
|
|
|
2003-01-03 20:59:50 +00:00
|
|
|
/* Adjust for DrawExtraPixelsLeft and DrawExtraPixelsRight. */
|
2003-01-03 22:53:22 +00:00
|
|
|
for(unsigned i = 0; i < glyphs.size(); ++i)
|
2003-01-03 20:59:50 +00:00
|
|
|
{
|
|
|
|
|
int iFrameWidth = m_pTexture->GetSourceFrameWidth();
|
2003-01-04 07:55:42 +00:00
|
|
|
float iCharWidth = glyphs[i].width;
|
2003-01-03 20:59:50 +00:00
|
|
|
|
2003-01-04 07:55:42 +00:00
|
|
|
/* Extra pixels to draw to the left and right. We don't have to
|
|
|
|
|
* worry about alignment here; CharWidth is always even (by
|
|
|
|
|
* SetTextureCoords) and iFrameWidth are almost always even. */
|
2003-01-04 01:47:01 +00:00
|
|
|
float ExtraLeft = min( float(DrawExtraPixelsLeft), (iFrameWidth-iCharWidth)/2.0f );
|
|
|
|
|
float ExtraRight = min( float(DrawExtraPixelsRight), (iFrameWidth-iCharWidth)/2.0f );
|
2003-01-03 20:59:50 +00:00
|
|
|
|
|
|
|
|
/* Move left and expand right. */
|
2003-01-04 01:47:01 +00:00
|
|
|
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;
|
2003-01-03 20:59:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
2002-08-13 23:26:46 +00:00
|
|
|
|
2003-01-04 05:17:51 +00:00
|
|
|
FontPage::~FontPage()
|
2002-03-30 20:00:13 +00:00
|
|
|
{
|
|
|
|
|
if( m_pTexture != NULL )
|
2003-01-03 22:53:22 +00:00
|
|
|
TEXTUREMAN->UnloadTexture( m_pTexture );
|
2002-03-30 20:00:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-01-05 05:13:45 +00:00
|
|
|
int Font::GetLineWidthInSourcePixels( const wstring &szLine ) const
|
2002-03-30 20:00:13 +00:00
|
|
|
{
|
2003-01-04 07:55:42 +00:00
|
|
|
int LineWidth = 0;
|
2002-03-30 20:00:13 +00:00
|
|
|
|
2002-12-29 22:55:26 +00:00
|
|
|
for( unsigned i=0; i<szLine.size(); i++ )
|
2003-01-04 07:55:42 +00:00
|
|
|
LineWidth += GetGlyph(szLine[i]).hadvance;
|
2002-03-30 20:00:13 +00:00
|
|
|
|
2003-01-04 07:55:42 +00:00
|
|
|
return LineWidth;
|
2002-03-30 20:00:13 +00:00
|
|
|
}
|
|
|
|
|
|
2003-01-05 05:13:45 +00:00
|
|
|
int Font::GetLineHeightInSourcePixels( const wstring &szLine ) const
|
2003-01-04 01:47:01 +00:00
|
|
|
{
|
2003-01-04 07:55:42 +00:00
|
|
|
int iLineSpacing = 0;
|
2003-01-04 05:17:51 +00:00
|
|
|
|
2003-01-04 07:55:42 +00:00
|
|
|
/* The spacing of a line is the spacing of its tallest used font page. */
|
|
|
|
|
for( unsigned i=0; i<szLine.size(); i++ )
|
|
|
|
|
iLineSpacing = max(iLineSpacing, GetGlyph(szLine[i]).vadvance);
|
2003-01-04 05:17:51 +00:00
|
|
|
|
2003-01-04 07:55:42 +00:00
|
|
|
return iLineSpacing;
|
2003-01-04 05:17:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Font::Font()
|
|
|
|
|
{
|
|
|
|
|
//LOG->Trace( "Font::LoadFromFontName(%s)", sASCIITexturePath.GetString() );
|
|
|
|
|
|
|
|
|
|
m_iRefCount = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Font::~Font()
|
|
|
|
|
{
|
|
|
|
|
for(unsigned i = 0; i < pages.size(); ++i)
|
|
|
|
|
delete pages[i];
|
2003-01-04 01:47:01 +00:00
|
|
|
}
|
2002-03-30 20:00:13 +00:00
|
|
|
|
2003-01-04 05:17:51 +00:00
|
|
|
void Font::AddPage(FontPage *fp)
|
|
|
|
|
{
|
|
|
|
|
pages.push_back(fp);
|
|
|
|
|
|
2003-01-05 05:13:45 +00:00
|
|
|
for(map<wchar_t,int>::const_iterator it = fp->m_iCharToGlyphNo.begin();
|
2003-01-04 05:17:51 +00:00
|
|
|
it != fp->m_iCharToGlyphNo.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
m_iCharToGlyph[it->first] = &fp->glyphs[it->second];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-05 05:13:45 +00:00
|
|
|
const glyph &Font::GetGlyph( wchar_t c ) const
|
2003-01-04 05:17:51 +00:00
|
|
|
{
|
2003-01-05 05:13:45 +00:00
|
|
|
map<wchar_t,glyph*>::const_iterator it = m_iCharToGlyph.find(c);
|
2003-01-04 05:17:51 +00:00
|
|
|
|
|
|
|
|
if(it == m_iCharToGlyph.end())
|
|
|
|
|
RageException::Throw( "The font '%s' does not implement the character '%c'", path.GetString(), c );
|
|
|
|
|
|
|
|
|
|
return *it->second;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-05 05:13:45 +00:00
|
|
|
RageTexture *Font::GetGlyphTexture( wchar_t c )
|
2003-01-04 07:55:42 +00:00
|
|
|
{
|
2003-01-05 05:13:45 +00:00
|
|
|
map<wchar_t,glyph*>::iterator it = m_iCharToGlyph.find(c);
|
2003-01-04 07:55:42 +00:00
|
|
|
|
|
|
|
|
if(it == m_iCharToGlyph.end())
|
|
|
|
|
RageException::Throw( "The font '%s' does not implement the character '%c'", path.GetString(), c );
|
|
|
|
|
|
|
|
|
|
return it->second->Texture;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-05 03:32:41 +00:00
|
|
|
void Font::CapsOnly()
|
2003-01-04 05:17:51 +00:00
|
|
|
{
|
2003-01-05 03:32:41 +00:00
|
|
|
/* For each uppercase character that we have a mapping for, add
|
|
|
|
|
* a lowercase one. */
|
|
|
|
|
for(char c = 'A'; c <= 'Z'; ++c)
|
2003-01-04 05:17:51 +00:00
|
|
|
{
|
2003-01-05 05:13:45 +00:00
|
|
|
map<wchar_t,glyph*>::const_iterator it = m_iCharToGlyph.find(c);
|
2003-01-04 05:17:51 +00:00
|
|
|
|
2003-01-05 03:32:41 +00:00
|
|
|
if(it == m_iCharToGlyph.end())
|
|
|
|
|
continue;
|
2003-01-04 05:17:51 +00:00
|
|
|
|
2003-01-05 05:13:45 +00:00
|
|
|
m_iCharToGlyph[(char) tolower(c)] = it->second;
|
2003-01-04 05:17:51 +00:00
|
|
|
}
|
|
|
|
|
}
|