Merge pull request #485 from kyzentun/font_errors

Non-fatal font errors.
This commit is contained in:
Kyzentun
2015-03-06 17:35:22 -07:00
4 changed files with 165 additions and 59 deletions
+15 -7
View File
@@ -622,19 +622,27 @@ bool BitmapText::StringWillUseAlternate( const RString& sText, const RString& sA
return true;
}
void BitmapText::CropToWidth( int iMaxWidthInSourcePixels )
void BitmapText::CropLineToWidth(size_t l, int width)
{
iMaxWidthInSourcePixels = max( 0, iMaxWidthInSourcePixels );
for( unsigned l=0; l<m_wTextLines.size(); l++ ) // for each line
if(l < m_wTextLines.size())
{
while( m_iLineWidths[l] > iMaxWidthInSourcePixels )
int used_width= width;
wstring& line= m_wTextLines[l];
int fit= m_pFont->GetGlyphsThatFit(line, &used_width);
if(fit < line.size())
{
m_wTextLines[l].erase( m_wTextLines[l].end()-1, m_wTextLines[l].end() );
m_iLineWidths[l] = m_pFont->GetLineWidthInSourcePixels( m_wTextLines[l] );
line.erase(line.begin()+fit, line.end());
}
m_iLineWidths[l]= used_width;
}
}
void BitmapText::CropToWidth(int width)
{
for(size_t l= 0; l < m_wTextLines.size(); ++l)
{
CropLineToWidth(l, width);
}
BuildChars();
}
+2 -1
View File
@@ -62,7 +62,8 @@ public:
void SetMaxHeight( float fMaxHeight );
void SetMaxDimUseZoom(bool use);
void SetWrapWidthPixels( int iWrapWidthPixels );
void CropToWidth( int iWidthInSourcePixels );
void CropLineToWidth(size_t l, int width);
void CropToWidth(int width);
virtual bool EarlyAbortDraw() const;
virtual void DrawPrimitives();
+147 -51
View File
@@ -26,7 +26,14 @@ void FontPage::Load( const FontPageSettings &cfg )
ID1.AdditionalTextureHints = cfg.m_sTextureHints;
m_FontPageTextures.m_pTextureMain = TEXTUREMAN->LoadTexture( ID1 );
ASSERT( m_FontPageTextures.m_pTextureMain != NULL );
if(m_FontPageTextures.m_pTextureMain == NULL)
{
LuaHelpers::ReportScriptErrorFmt(
"Failed to load main texture %s for font page.",
m_sTexturePath.c_str());
m_FontPageTextures.m_pTextureMain= TEXTUREMAN->LoadTexture(
TEXTUREMAN->GetDefaultTextureID());
}
RageTextureID ID2 = ID1;
// "arial 20 16x16 [main].png" => "arial 20 16x16 [main-stroke].png"
@@ -36,9 +43,35 @@ void FontPage::Load( const FontPageSettings &cfg )
if( IsAFile(ID2.filename) )
{
m_FontPageTextures.m_pTextureStroke = TEXTUREMAN->LoadTexture( ID2 );
ASSERT( m_FontPageTextures.m_pTextureStroke != NULL );
ASSERT_M( m_FontPageTextures.m_pTextureMain->GetSourceFrameWidth() == m_FontPageTextures.m_pTextureStroke->GetSourceFrameWidth(), ssprintf("'%s' and '%s' must have the same frame widths", ID1.filename.c_str(), ID2.filename.c_str()) );
ASSERT_M( m_FontPageTextures.m_pTextureMain->GetNumFrames() == m_FontPageTextures.m_pTextureStroke->GetNumFrames(), ssprintf("'%s' and '%s' must have the same frame dimensions", ID1.filename.c_str(), ID2.filename.c_str()) );
if(m_FontPageTextures.m_pTextureStroke == NULL)
{
LuaHelpers::ReportScriptErrorFmt(
"Failed to load stroke texture %s for font page.",
ID2.filename.c_str());
m_FontPageTextures.m_pTextureStroke=
m_FontPageTextures.m_pTextureMain;
}
// If the source frame dimensions or number of frames don't match, set
// the stroke layer to be the same as the main layer so that the
// assumptions based on the frames are still safe. -Kyz
if(m_FontPageTextures.m_pTextureMain->GetSourceFrameWidth() !=
m_FontPageTextures.m_pTextureStroke->GetSourceFrameWidth())
{
LuaHelpers::ReportScriptErrorFmt(
"'%s' and '%s' must have the same frame widths",
ID1.filename.c_str(), ID2.filename.c_str());
m_FontPageTextures.m_pTextureStroke=
m_FontPageTextures.m_pTextureMain;
}
if(m_FontPageTextures.m_pTextureMain->GetNumFrames() !=
m_FontPageTextures.m_pTextureStroke->GetNumFrames())
{
LuaHelpers::ReportScriptErrorFmt(
"'%s' and '%s' must have the same frame dimensions",
ID1.filename.c_str(), ID2.filename.c_str());
m_FontPageTextures.m_pTextureStroke=
m_FontPageTextures.m_pTextureMain;
}
}
}
@@ -220,6 +253,23 @@ int Font::GetLineHeightInSourcePixels( const wstring &szLine ) const
return iLineHeight;
}
// width is a pointer so that we can return the used width through it.
int Font::GetGlyphsThatFit(const wstring& line, int* width) const
{
if(*width == 0)
{
*width= GetLineWidthInSourcePixels(line);
return line.size();
}
int curr_width= 0;
unsigned int i= 0;
for(i= 0; i < line.size() && curr_width < *width; ++i)
{
curr_width+= GetGlyph(line[i]).m_iHadvance;
}
*width= curr_width;
return i;
}
Font::Font(): m_iRefCount(1), path(""), m_apPages(), m_pDefault(NULL),
m_iCharToGlyph(), m_bRightToLeft(false),
@@ -246,8 +296,12 @@ void Font::Unload()
void Font::Reload()
{
if(path.empty())
{
LuaHelpers::ReportScriptError("Cannot reload a font that has an empty path.");
return;
}
Unload();
ASSERT( !path.empty() );
Load( path, m_sChars );
}
@@ -347,7 +401,13 @@ void Font::CapsOnly()
void Font::SetDefaultGlyph( FontPage *pPage )
{
ASSERT( pPage != NULL );
ASSERT( !pPage->m_aGlyphs.empty() );
if(pPage->m_aGlyphs.empty())
{
LuaHelpers::ReportScriptErrorFmt(
"Attempted to set default glyphs for %s to a blank page.",
path.c_str());
return;
}
m_pDefault = pPage;
}
@@ -393,9 +453,9 @@ void Font::LoadFontPageSettings( FontPageSettings &cfg, IniFile &ini, const RStr
char c = sChars[n];
cfg.CharToGlyphNo[c] = n;
}
int iNumFramesWide, iNumFramesHigh;
RageTexture::GetFrameDimensionsFromFileName( sTexturePath, &iNumFramesWide, &iNumFramesHigh );
int iNumFrames = iNumFramesWide * iNumFramesHigh;
int num_frames_wide, num_frames_high;
RageTexture::GetFrameDimensionsFromFileName( sTexturePath, &num_frames_wide, &num_frames_high );
int iNumFrames = num_frames_wide * num_frames_high;
// Deal with fonts generated by Bitmap Font Builder.
ini.RenameKey("Char Widths", "main");
@@ -487,33 +547,41 @@ void Font::LoadFontPageSettings( FontPageSettings &cfg, IniFile &ini, const RStr
*/
vector<RString> asMatches;
static Regex parse("^RANGE ([A-Z0-9\\-]+)( ?#([0-9A-F]+)-([0-9A-F]+))?$");
bool bMatch = parse.Compare( sName, asMatches );
bool match = parse.Compare( sName, asMatches );
ASSERT( asMatches.size() == 4 ); // 4 parens
if( !bMatch || asMatches[0].empty() )
RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": parse error.",
ini.GetPath().c_str(), sName.c_str() );
if(!match || asMatches[0].empty())
{
LuaHelpers::ReportScriptErrorFmt(
"Font definition \"%s\" has an invalid range \"%s\": parse error.",
ini.GetPath().c_str(), sName.c_str());
continue;
}
// We must have either 1 match (just the codeset) or 4 (the whole thing).
int iCount = -1;
int iFirst = 0;
int count = -1;
int first = 0;
if( !asMatches[2].empty() )
{
sscanf( asMatches[2].c_str(), "%x", &iFirst );
int iLast;
sscanf( asMatches[3].c_str(), "%x", &iLast );
if( iLast < iFirst )
RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": %i < %i.",
ini.GetPath().c_str(), sName.c_str(), iLast, iFirst );
iCount = iLast - iFirst + 1;
sscanf( asMatches[2].c_str(), "%x", &first );
int last;
sscanf( asMatches[3].c_str(), "%x", &last );
if(last < first)
{
LuaHelpers::ReportScriptErrorFmt(
"Font definition \"%s\" has an invalid range \"%s\": %i < %i.",
ini.GetPath().c_str(), sName.c_str(), last, first);
continue;
}
count = last - first + 1;
}
RString sRet = cfg.MapRange( asMatches[0], iFirst, pValue->GetValue<int>(), iCount );
if( !sRet.empty() )
RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": %s.",
ini.GetPath().c_str(), sName.c_str(), sRet.c_str() );
RString error_string = cfg.MapRange( asMatches[0], first, pValue->GetValue<int>(), count );
if(!error_string.empty())
{
LuaHelpers::ReportScriptErrorFmt(
"Font definition \"%s\" has an invalid range \"%s\": %s.",
ini.GetPath().c_str(), sName.c_str(), error_string.c_str());
continue;
}
continue;
}
@@ -526,26 +594,42 @@ void Font::LoadFontPageSettings( FontPageSettings &cfg, IniFile &ini, const RStr
*
* This lets us assign characters very compactly and readably. */
RString sRowStr = sName.substr(5);
TrimLeft( sRowStr );
RString row_str = sName.substr(5);
TrimLeft(row_str);
ASSERT( IsAnInt(sRowStr) );
const int iRow = StringToInt( sRowStr );
const int iFirstFrame = iRow * iNumFramesWide;
if(!IsAnInt(row_str))
{
LuaHelpers::ReportScriptErrorFmt("Line name %s is not a number.",
row_str.c_str());
continue;
}
const int row = StringToInt(row_str);
const int first_frame = row * num_frames_wide;
if( iRow > iNumFramesHigh )
RageException::Throw( "The font definition \"%s\" tries to assign line %i, but the font is only %i characters high.",
ini.GetPath().c_str(), iFirstFrame, iNumFramesHigh );
if(row > num_frames_high)
{
LuaHelpers::ReportScriptErrorFmt(
"The font definition \"%s\" tries to assign line %i, "
"but the font is only %i characters high.",
ini.GetPath().c_str(), first_frame, num_frames_high);
continue;
}
// Decode the string.
const wstring wdata( RStringToWstring(pValue->GetValue<RString>()) );
if( int(wdata.size()) > iNumFramesWide )
RageException::Throw( "The font definition \"%s\" assigns %i characters to row %i (\"%ls\"), but the font is only %i characters wide.",
ini.GetPath().c_str(), (int)wdata.size(), iRow, wdata.c_str(), iNumFramesWide );
if(int(wdata.size()) > num_frames_wide)
{
LuaHelpers::ReportScriptErrorFmt(
"The font definition \"%s\" assigns %i characters to row %i"
"(\"%ls\"), but the font is only %i characters wide.",
ini.GetPath().c_str(), (int)wdata.size(), row, wdata.c_str(),
num_frames_wide);
continue;
}
for( unsigned i = 0; i < wdata.size(); ++i )
cfg.CharToGlyphNo[wdata[i]] = iFirstFrame+i;
cfg.CharToGlyphNo[wdata[i]] = first_frame+i;
}
}
}
@@ -657,8 +741,13 @@ static vector<RString> LoadStack;
*/
void Font::Load( const RString &sIniPath, RString sChars )
{
ASSERT_M( !GetExtension(sIniPath).CompareNoCase("ini"), sIniPath );
if(GetExtension(sIniPath).CompareNoCase("ini"))
{
LuaHelpers::ReportScriptErrorFmt(
"%s is not an ini file. Fonts can only be loaded from ini files.",
sIniPath.c_str());
return;
}
//LOG->Trace( "Font: Loading new font '%s'",sIniPath.c_str());
// Check for recursion (recursive imports).
@@ -667,8 +756,10 @@ void Font::Load( const RString &sIniPath, RString sChars )
if( LoadStack[i] == sIniPath )
{
RString str = join("\n", LoadStack);
str += "\n" + sIniPath;
RageException::Throw( "Font import recursion detected\n%s", str.c_str() );
str += "\nCurrent font: " + sIniPath;
LuaHelpers::ReportScriptErrorFmt(
"Font import recursion detected\n%s", str.c_str());
return;
}
}
LoadStack.push_back( sIniPath );
@@ -762,13 +853,18 @@ void Font::Load( const RString &sIniPath, RString sChars )
/* Expect at least as many frames as we have premapped characters. */
/* Make sure that we don't map characters to frames we don't actually
* have. This can happen if the font is too small for an sChars. */
for( map<wchar_t,int>::const_iterator it = pPage->m_iCharToGlyphNo.begin();
it != pPage->m_iCharToGlyphNo.end(); ++it )
for(map<wchar_t,int>::iterator it = pPage->m_iCharToGlyphNo.begin();
it != pPage->m_iCharToGlyphNo.end(); ++it)
{
if( it->second < pPage->m_FontPageTextures.m_pTextureMain->GetNumFrames() )
continue; /* OK */
RageException::Throw( "The font \"%s\" maps \"%s\" to frame %i, but the font only has %i frames.",
sTexturePath.c_str(), WcharDisplayText(wchar_t(it->first)).c_str(), it->second, pPage->m_FontPageTextures.m_pTextureMain->GetNumFrames() );
LuaHelpers::ReportScriptErrorFmt(
"The font \"%s\" maps \"%s\" to frame %i, "
"but the font only has %i frames.",
sTexturePath.c_str(), WcharDisplayText(wchar_t(it->first)).c_str(),
it->second,
pPage->m_FontPageTextures.m_pTextureMain->GetNumFrames());
it->second= 0;
}
// LOG->Trace( "Adding page %s (%s) to %s; %i glyphs",
@@ -786,7 +882,7 @@ void Font::Load( const RString &sIniPath, RString sChars )
CapsOnly();
if( m_iCharToGlyph.empty() )
LOG->Warn( "Font %s has no characters", sIniPath.c_str() );
LuaHelpers::ReportScriptErrorFmt("Font %s has no characters", sIniPath.c_str());
LoadStack.pop_back();
+1
View File
@@ -145,6 +145,7 @@ public:
int GetLineWidthInSourcePixels( const wstring &szLine ) const;
int GetLineHeightInSourcePixels( const wstring &szLine ) const;
int GetGlyphsThatFit(const wstring& line, int* width) const;
bool FontCompleteForString( const wstring &str ) const;