Merge pull request #485 from kyzentun/font_errors
Non-fatal font errors.
This commit is contained in:
+15
-7
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user