diff --git a/stepmania/src/Font.cpp b/stepmania/src/Font.cpp index 0c61f35d39..03f2004653 100644 --- a/stepmania/src/Font.cpp +++ b/stepmania/src/Font.cpp @@ -20,6 +20,8 @@ #include "RageException.h" #include "FontManager.h" #include "GameState.h" +#include "ThemeManager.h" +#include "GameManager.h" const longchar Font::DEFAULT_GLYPH = 0xFFFFFF; @@ -242,20 +244,20 @@ void Font::Unload() delete pages[i]; pages.clear(); - /* Free any fonts that we merged into us. These aren't managed by - * FontManager (we own them), so just delete them. */ - for(i = 0; i < merged_fonts.size(); ++i) - delete merged_fonts[i]; - merged_fonts.clear(); - m_iCharToGlyph.clear(); def = NULL; - path.clear(); /* Don't clear the refcount. We've unloaded, but that doesn't mean things * aren't still pointing to us. */ } +void Font::Reload() +{ + Unload(); + ASSERT(!path.empty()); + Load(path, Chars); +} + void Font::AddPage(FontPage *fp) { @@ -268,16 +270,17 @@ void Font::AddPage(FontPage *fp) } } -void Font::MergeFont(Font *f) +void Font::MergeFont(Font &f) { - for(map::iterator it = f->m_iCharToGlyph.begin(); - it != f->m_iCharToGlyph.end(); ++it) + for(map::iterator it = f.m_iCharToGlyph.begin(); + it != f.m_iCharToGlyph.end(); ++it) { m_iCharToGlyph[it->first] = it->second; } - /* We now have ownership of f. Mark it to be freed. */ - merged_fonts.push_back(f); + pages.insert(pages.end(), f.pages.begin(), f.pages.end()); + + f.pages.clear(); } const glyph &Font::GetGlyph( longchar c ) const @@ -329,3 +332,347 @@ void Font::SetDefaultGlyph(FontPage *fp) } +/* "Normal.png", "Normal [foo].png", "Normal 16x16.png", and "Normal [foo] 16x16.png" + * are all part of the FontName "Normal". "Normal2 16x16.png" is not. + * + * So, FileName must start with FontName, followed by either " [", " DIGIT" or + * a period. + * + * This is to make sure we don't pull in textures from similarly-named fonts. + */ +bool Font::MatchesFont(CString FontName, CString FileName) +{ + FontName.MakeLower(); + FileName.MakeLower(); + + if(FileName.substr(0, FontName.size()) != FontName) + return false; + FileName = FileName.substr(FontName.size()); + + return regex("^( \\[|\\.| [0-9]+x[0-9]+)", FileName); +} + +void Font::GetFontPaths(const CString &sFontOrTextureFilePath, + CStringArray &TexturePaths, CString &IniPath) +{ + CString sDrive, sDir, sFName, sExt; + splitpath( false, sFontOrTextureFilePath, sDrive, sDir, sFName, sExt ); + + ASSERT(sExt.CompareNoCase("ini")); /* don't give us an INI! */ + ASSERT(sExt.CompareNoCase("redir")); /* don't give us a redir! */ + + if(!sExt.empty()) + { + TexturePaths.push_back(sFontOrTextureFilePath); + return; + } + + /* If we have no extension, we need to search. */ + GetDirListing( sFontOrTextureFilePath + "*.png", TexturePaths, false, true ); + + CStringArray IniPaths; + GetDirListing( sFontOrTextureFilePath + "*.ini", IniPaths, false, true ); + + /* Filter out texture files that aren't actually for this font. */ + unsigned i = 0; + while(i < TexturePaths.size()) + { + if(!MatchesFont(sFontOrTextureFilePath, TexturePaths[i])) + TexturePaths.erase(TexturePaths.begin()+i); + else + i++; + } + + for(i = 0; i < IniPaths.size(); ++i) + if(MatchesFont(sFontOrTextureFilePath, IniPaths[i])) break; + if(i < IniPaths.size()) IniPath = IniPaths[i]; + + ASSERT(!TexturePaths.empty()); /* ThemeManager should have checked this */ +} + +CString Font::GetPageNameFromFileName(const CString &fn) +{ + unsigned begin = fn.find_first_of('['); + if(begin == fn.npos) return "main"; + unsigned end = fn.find_first_of(']', begin); + if(end == fn.npos) return "main"; + begin++; end--; + if(end == begin) return "main"; + return fn.substr(begin, end-begin+1); +} + +void Font::LoadFontPageSettings(FontPageSettings &cfg, IniFile &ini, const CString &TexturePath, const CString &PageName, CString sChars) +{ + cfg.TexturePath = TexturePath; + + /* If we have any characters to map, add them. */ + for( unsigned n=0; nTrace("Loading font page '%s' settings from page name '%s'", + TexturePath.GetString(), PageName.GetString()); + + ini.GetValueI( PageName, "DrawExtraPixelsLeft", cfg.DrawExtraPixelsLeft ); + ini.GetValueI( PageName, "DrawExtraPixelsRight", cfg.DrawExtraPixelsRight ); + ini.GetValueI( PageName, "AddToAllWidths", cfg.AddToAllWidths ); + ini.GetValueF( PageName, "ScaleAllWidthsBy", cfg.ScaleAllWidthsBy ); + ini.GetValueI( PageName, "LineSpacing", cfg.LineSpacing ); + ini.GetValueI( PageName, "Top", cfg.Top ); + ini.GetValueI( PageName, "Baseline", cfg.Baseline ); + ini.GetValueB( PageName, "Kanji", cfg.Kanji ); + + /* Iterate over all keys. */ + const IniFile::key *k = ini.GetKey(PageName); + if(k == NULL) + return; + + 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)) + { + cfg.GlyphWidths[atoi(val)] = atoi(data); + continue; + } + + /* "map XXXX=frame" maps a char to a frame. */ + if(val.substr(0, 4) == "MAP ") + { + /* map CODEPOINT=frame. CODEPOINT can be + * 1. U+hexval + * 2. an alias ("kakumei1") + * 3. a game type followed by a game alias, eg "pump menuleft" + * + * map 1=2 is the same as + * range unicode #1-1=2 + */ + CString codepoint = val.substr(4); /* "XXXX" */ + + longchar c; + Game game = GAME_INVALID; + + if(codepoint.find_first_of(' ') != codepoint.npos) + { + /* There's a space; the first word should be a game type. Split it. */ + unsigned pos = codepoint.find_first_of(' '); + CString gamename = codepoint.substr(0, pos); + codepoint = codepoint.substr(pos+1); + + game = GameManager::StringToGameType(gamename); + + if(game == GAME_INVALID) + RageException::Throw( "Font definition '%s' uses unknown game type '%s'", + ini.GetPath().GetString(), gamename.GetString() ); + } + + if(codepoint.substr(0, 2) == "U+" && IsHexVal(codepoint.substr(2))) + sscanf(codepoint.substr(2).c_str(), "%x", &c); + else if(FontManager::CharAliases.find(codepoint) != FontManager::CharAliases.end()) + c = FontManager::CharAliases[codepoint]; + else + RageException::Throw( "Font definition '%s' has an invalid value '%s'.", + ini.GetPath().GetString(), val.GetString() ); + + if(game != GAME_INVALID) c = FontManager::MakeGameGlyph(c, game); + + cfg.CharToGlyphNo[c] = atoi(data); + continue; + } +#if 0 + /* not implemented yet */ + if(val.substr(0, 6) == "RANGE ") + { + /* range RANGE=first_frame + * + * RANGE is: + * CODESET or + * CODESET #start-end + * eg + * range ISO-8859-1=0 (default for 256-frame fonts) + * range ASCII=0 (default for 128-frame fonts) + * + * (Start and end are in hex.) + * + * Map two high-bit portions of ISO-8859- to one font: + * range ISO-8859-2 #80-FF=0 + * range ISO-8859-3 #80-FF=128 + * + * Map hiragana to 0-84: + * range Unicode #3041-3094=0 + */ + CString range = val.substr(6); + unsigned first = 0, last = 0xFFFF; /* all */ + unsigned space = range.find_first_of(' '); + if(space != val.npos) + { + + } + + + + continue; + } +#endif + } +} + +static CStringArray LoadStack; + +/* A font set is a set of files, eg: + * + * Normal 16x16.png + * Normal [other] 16x16.png + * Normal [more] 8x8.png + * Normal 16x16.ini (the 16x16 here is optional) + * + * Only one texture is required; the INI is optional. [1] This is + * designed to be backwards-compatible. + * + * sFontOrTextureFilePath can be a partial path, eg. + * "Themes/default/Fonts/Normal" + * or a complete path to a texture file (in which case no other + * files will be searched for). + * + * The entire font can be redirected; that's handled in ThemeManager. + * Individual font files can not be redirected. + * + * TODO: + * [main] + * import=FontName,FontName2 (load other fonts) + * + * [1] If a file has no INI and sChars is not set, it will receive a default + * mapping of ASCII or ISO-8859-1 if the font has exactly 128 or 256 frames. + * However, if it doesn't, we don't know what it is and the font will receive + * no default mapping. A font isn't useful with no characters mapped. + */ +void Font::Load(const CString &sFontOrTextureFilePath, CString sChars) +{ + /* Check for recursion (recursive imports). */ + { + for(unsigned i = 0; i < LoadStack.size(); ++i) + { + if(LoadStack[i] == sFontOrTextureFilePath) + { + CString str = join("\n", LoadStack); + str += "\n" + sFontOrTextureFilePath; + RageException::Throw("Font import recursion detected\n%s", str.GetString()); + } + } + LoadStack.push_back(sFontOrTextureFilePath); + } + + /* The font is not already loaded. Figure out what we have. */ +// LOG->Trace( "FontManager::LoadFont(%s).", sFontFilePath.GetString() ); + + path = sFontOrTextureFilePath; + Chars = sChars; + + /* Get the filenames associated with this font. */ + CStringArray TexturePaths; + CString IniPath; + GetFontPaths(sFontOrTextureFilePath, TexturePaths, IniPath); + + bool CapitalsOnly = false; + + /* If we have an INI, load it. */ + IniFile ini; + if( !IniPath.empty() ) + { + ini.SetPath( IniPath ); + ini.ReadFile(); + ini.RenameKey("Char Widths", "main"); + ini.GetValueB( "main", "CapitalsOnly", CapitalsOnly ); + } + + { + /* If this is a top-level font (not a subfont), load the default font first. */ + CStringArray ImportList; + if(LoadStack.size() == 1) + ImportList.push_back("default font"); + + /* Check to see if we need to import any other fonts. Do this + * before loading this font, so any characters in this font + * override imported characters. */ + CString imports; + ini.GetValue( "main", "import", imports ); + split(imports, ",", ImportList, true); + for(unsigned i = 0; i < ImportList.size(); ++i) + { + CString path = THEME->GetPathTo("Fonts", ImportList[i]); + Font subfont; + subfont.Load(path, ""); + MergeFont(subfont); + } + } + + /* Load each font page. */ + for(unsigned i = 0; i < TexturePaths.size(); ++i) + { + FontPage *fp = new FontPage; + + /* Grab the page name, eg "foo" from "Normal [foo].png". */ + CString pagename = GetPageNameFromFileName(TexturePaths[i]); + + /* Load settings for this page from the INI. */ + FontPageSettings cfg; + LoadFontPageSettings(cfg, ini, TexturePaths[i], pagename, sChars); + + /* Go. */ + fp->Load(cfg); + + /* 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::const_iterator it = fp->m_iCharToGlyphNo.begin(); + it != fp->m_iCharToGlyphNo.end(); ++it) + { + if(it->second < fp->m_pTexture->GetNumFrames()) continue; /* OK */ + RageException::Throw( "The font '%s' maps %s to frame %i, but the font only has %i frames.", + TexturePaths[i].GetString(), WcharDisplayText(wchar_t(it->first)).GetString(), it->second, fp->m_pTexture->GetNumFrames() ); + } + + LOG->Trace("Adding page %s (%s) to %s; %i glyphs", + TexturePaths[i].GetString(), pagename.GetString(), + sFontOrTextureFilePath.GetString(), fp->m_iCharToGlyphNo.size()); + AddPage(fp); + + /* If this is the first font loaded, or it's called "main", this page's + * properties become the font's properties. */ + if(i == 0 || pagename == "main") + SetDefaultGlyph(fp); + } + + if(CapitalsOnly) + CapsOnly(); + + if(m_iCharToGlyph.empty()) + LOG->Warn("Font %s has no characters", sFontOrTextureFilePath.GetString()); + + LoadStack.pop_back(); +} diff --git a/stepmania/src/Font.h b/stepmania/src/Font.h index 79fcf065ba..0475e19e2c 100644 --- a/stepmania/src/Font.h +++ b/stepmania/src/Font.h @@ -95,7 +95,6 @@ class Font public: int m_iRefCount; CString path; - map m_iCharToGlyph; Font(); ~Font(); @@ -111,32 +110,44 @@ public: void AddPage(FontPage *fp); /* Steal all of a font's pages. */ - void MergeFont(Font *f); + void MergeFont(Font &f); + void Load(const CString &sFontOrTextureFilePath, CString sChars); void Unload(); + void Reload(); /* Load font-wide settings. */ void CapsOnly(); -// int GetBaseline() const { return def->baseline; } int GetHeight() const { return def->height; } bool IsKanjiFont() const { return def->kanji; } int GetCenter() const { return def->GetCenter(); } - int GetVshift() const { return def->vshift; } int GetLineSpacing() const { return def->LineSpacing; } void SetDefaultGlyph(FontPage *fp); static const longchar DEFAULT_GLYPH; -private: - /* List of pages and fonts that we're responsible for freeing. */ - vector pages; - vector merged_fonts; + static bool MatchesFont(CString FontName, CString FileName); - /* This is the primary fontpage of this font; font-wide baseline, ascender, - * etc. is pulled from it. */ +private: + /* List of pages and fonts that we use (and are responsible for freeing). */ + vector pages; + + /* This is the primary fontpage of this font; font-wide height, center, + * etc. is pulled from it. (This is one of pages[].) */ FontPage *def; + + /* Map from characters to glyphs. (Each glyph* is part of one of pages[].) */ + map m_iCharToGlyph; + + /* We keep this around only for reloading. */ + CString Chars; + + void LoadFontPageSettings(FontPageSettings &cfg, IniFile &ini, const CString &TexturePath, const CString &PageName, CString sChars); + static void GetFontPaths(const CString &sFontOrTextureFilePath, + CStringArray &TexturePaths, CString &IniPath); + CString GetPageNameFromFileName(const CString &fn); }; #endif diff --git a/stepmania/src/FontManager.cpp b/stepmania/src/FontManager.cpp index 62a75ea013..cadc8091c6 100644 --- a/stepmania/src/FontManager.cpp +++ b/stepmania/src/FontManager.cpp @@ -18,8 +18,6 @@ #include "RageLog.h" #include "RageException.h" #include "RageTimer.h" -#include "ThemeManager.h" -#include "GameManager.h" FontManager::aliasmap FontManager::CharAliases; map FontManager::CharAliasRepl; @@ -58,371 +56,16 @@ bool FontManager::ExtractGameGlyph(longchar ch, int &c, Game &g) return true; } -#if 0 + void FontManager::ReloadFonts() { - map m_mapPathToFont; - for(map::iterator i = m_mapPathToFont.begin(); i != m_mapPathToFont.end(); ++i) { - CString path = i->first; - Font *f = i->second; - f->Unload(); - f->Load(f); - -// i-> - - } - - - -} -#endif - -void FontManager::LoadFontPageSettings(FontPageSettings &cfg, IniFile &ini, const CString &TexturePath, const CString &PageName, CString sChars) -{ - cfg.TexturePath = TexturePath; - - /* If we have any characters to map, add them. */ - for( unsigned n=0; nTrace("Loading font page '%s' settings from page name '%s'", - TexturePath.GetString(), PageName.GetString()); - - ini.GetValueI( PageName, "DrawExtraPixelsLeft", cfg.DrawExtraPixelsLeft ); - ini.GetValueI( PageName, "DrawExtraPixelsRight", cfg.DrawExtraPixelsRight ); - ini.GetValueI( PageName, "AddToAllWidths", cfg.AddToAllWidths ); - ini.GetValueF( PageName, "ScaleAllWidthsBy", cfg.ScaleAllWidthsBy ); - ini.GetValueI( PageName, "LineSpacing", cfg.LineSpacing ); - ini.GetValueI( PageName, "Top", cfg.Top ); - ini.GetValueI( PageName, "Baseline", cfg.Baseline ); - ini.GetValueB( PageName, "Kanji", cfg.Kanji ); - - /* Iterate over all keys. */ - const IniFile::key *k = ini.GetKey(PageName); - if(k == NULL) - return; - - 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)) - { - cfg.GlyphWidths[atoi(val)] = atoi(data); - continue; - } - - /* "map XXXX=frame" maps a char to a frame. */ - if(val.substr(0, 4) == "MAP ") - { - /* map CODEPOINT=frame. CODEPOINT can be - * 1. U+hexval - * 2. an alias ("kakumei1") - * 3. a game type followed by a game alias, eg "pump menuleft" - * - * map 1=2 is the same as - * range unicode #1-1=2 - */ - CString codepoint = val.substr(4); /* "XXXX" */ - - longchar c; - Game game = GAME_INVALID; - - if(codepoint.find_first_of(' ') != codepoint.npos) - { - /* There's a space; the first word should be a game type. Split it. */ - unsigned pos = codepoint.find_first_of(' '); - CString gamename = codepoint.substr(0, pos); - codepoint = codepoint.substr(pos+1); - - game = GameManager::StringToGameType(gamename); - - if(game == GAME_INVALID) - RageException::Throw( "Font definition '%s' uses unknown game type '%s'", - ini.GetPath().GetString(), gamename.GetString() ); - } - - if(codepoint.substr(0, 2) == "U+" && IsHexVal(codepoint.substr(2))) - sscanf(codepoint.substr(2).c_str(), "%x", &c); - else if(CharAliases.find(codepoint) != CharAliases.end()) - c = CharAliases[codepoint]; - else - RageException::Throw( "Font definition '%s' has an invalid value '%s'.", - ini.GetPath().GetString(), val.GetString() ); - - if(game != GAME_INVALID) c = MakeGameGlyph(c, game); - - cfg.CharToGlyphNo[c] = atoi(data); - continue; - } -#if 0 - /* not implemented yet */ - if(val.substr(0, 6) == "RANGE ") - { - /* range RANGE=first_frame - * - * RANGE is: - * CODESET or - * CODESET #start-end - * eg - * range ISO-8859-1=0 (default for 256-frame fonts) - * range ASCII=0 (default for 128-frame fonts) - * - * (Start and end are in hex.) - * - * Map two high-bit portions of ISO-8859- to one font: - * range ISO-8859-2 #80-FF=0 - * range ISO-8859-3 #80-FF=128 - * - * Map hiragana to 0-84: - * range Unicode #3041-3094=0 - */ - CString range = val.substr(6); - unsigned first = 0, last = 0xFFFF; /* all */ - unsigned space = range.find_first_of(' '); - if(space != val.npos) - { - - } - - - - continue; - } -#endif + i->second->Reload(); } } -/* "Normal.png", "Normal [foo].png", "Normal 16x16.png", and "Normal [foo] 16x16.png" - * are all part of the FontName "Normal". "Normal2 16x16.png" is not. - * - * So, FileName must start with FontName, followed by either " [", " DIGIT" or - * a period. - * - * This is to make sure we don't pull in textures from similarly-named fonts. - */ -bool FontManager::MatchesFont(CString FontName, CString FileName) -{ - FontName.MakeLower(); - FileName.MakeLower(); - - if(FileName.substr(0, FontName.size()) != FontName) - return false; - FileName = FileName.substr(FontName.size()); - - return regex("^( \\[|\\.| [0-9]+x[0-9]+)", FileName); -} - -void FontManager::GetFontPaths(const CString &sFontOrTextureFilePath, - CStringArray &TexturePaths, CString &IniPath) -{ - CString sDrive, sDir, sFName, sExt; - splitpath( false, sFontOrTextureFilePath, sDrive, sDir, sFName, sExt ); - - ASSERT(sExt.CompareNoCase("ini")); /* don't give us an INI! */ - ASSERT(sExt.CompareNoCase("redir")); /* don't give us a redir! */ - - if(!sExt.empty()) - { - TexturePaths.push_back(sFontOrTextureFilePath); - return; - } - - /* If we have no extension, we need to search. */ - GetDirListing( sFontOrTextureFilePath + "*.png", TexturePaths, false, true ); - - CStringArray IniPaths; - GetDirListing( sFontOrTextureFilePath + "*.ini", IniPaths, false, true ); - - /* Filter out texture files that aren't actually for this font. */ - unsigned i = 0; - while(i < TexturePaths.size()) - { - if(!MatchesFont(sFontOrTextureFilePath, TexturePaths[i])) - TexturePaths.erase(TexturePaths.begin()+i); - else - i++; - } - - for(i = 0; i < IniPaths.size(); ++i) - if(MatchesFont(sFontOrTextureFilePath, IniPaths[i])) break; - if(i < IniPaths.size()) IniPath = IniPaths[i]; - - ASSERT(!TexturePaths.empty()); /* ThemeManager should have checked this */ -} - -static CStringArray LoadStack; - -/* Load the named font and return it. */ -Font *FontManager::LoadFontInt(const CString &sFontOrTextureFilePath, CString sChars) -{ - /* Check for recursion (recursive imports). */ - { - for(unsigned i = 0; i < LoadStack.size(); ++i) - { - if(LoadStack[i] == sFontOrTextureFilePath) - { - CString str = join("\n", LoadStack); - str += "\n" + sFontOrTextureFilePath; - RageException::Throw("Font import recursion detected\n%s", str.GetString()); - } - } - LoadStack.push_back(sFontOrTextureFilePath); - } - - /* The font is not already loaded. Figure out what we have. */ -// LOG->Trace( "FontManager::LoadFont(%s).", sFontFilePath.GetString() ); - - /* Get the filenames associated with this font. */ - CStringArray TexturePaths; - CString IniPath; - GetFontPaths(sFontOrTextureFilePath, TexturePaths, IniPath); - - Font* pFont = new Font; - pFont->path = sFontOrTextureFilePath; - - bool CapitalsOnly = false; - - /* If we have an INI, load it. */ - IniFile ini; - if( !IniPath.empty() ) - { - ini.SetPath( IniPath ); - ini.ReadFile(); - ini.RenameKey("Char Widths", "main"); - ini.GetValueB( "main", "CapitalsOnly", CapitalsOnly ); - } - - { - /* Check to see if we need to import any other fonts. Do this - * before loading this font, so any characters in this font - * override imported characters. */ - CString imports; - ini.GetValue( "main", "import", imports ); - CStringArray ImportList; - split(imports, ",", ImportList, true); - - /* Load the default font first, unless we're currently loading it. */ - static bool LoadingDefaultFont = false; - if(!LoadingDefaultFont) - { - LoadingDefaultFont = true; - CString path = THEME->GetPathTo("Fonts", "default font"); - pFont->MergeFont(LoadFontInt(path, "")); - LoadingDefaultFont = false; - } - - /* Load imports. */ - for(unsigned i = 0; i < ImportList.size(); ++i) - { - CString path = THEME->GetPathTo("Fonts", ImportList[i]); - pFont->MergeFont(LoadFontInt(path, "")); - } - } - - /* Load each font page. */ - for(unsigned i = 0; i < TexturePaths.size(); ++i) - { - FontPage *fp = new FontPage; - - /* Grab the page name, eg "foo" from "Normal [foo].png". */ - CString pagename = GetPageNameFromFileName(TexturePaths[i]); - - /* Load settings for this page from the INI. */ - FontPageSettings cfg; - LoadFontPageSettings(cfg, ini, TexturePaths[i], pagename, sChars); - - /* Go. */ - fp->Load(cfg); - - /* 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::const_iterator it = fp->m_iCharToGlyphNo.begin(); - it != fp->m_iCharToGlyphNo.end(); ++it) - { - if(it->second < fp->m_pTexture->GetNumFrames()) continue; /* OK */ - RageException::Throw( "The font '%s' maps %s to frame %i, but the font only has %i frames.", - TexturePaths[i].GetString(), WcharDisplayText(wchar_t(it->first)).GetString(), it->second, fp->m_pTexture->GetNumFrames() ); - } - - LOG->Trace("Adding page %s (%s) to %s; %i glyphs", - TexturePaths[i].GetString(), pagename.GetString(), - sFontOrTextureFilePath.GetString(), fp->m_iCharToGlyphNo.size()); - pFont->AddPage(fp); - - /* If this is the first font loaded, or it's called "main", this page's - * properties become the font's properties. */ - if(i == 0 || pagename == "main") - pFont->SetDefaultGlyph(fp); - } - - if(CapitalsOnly) - pFont->CapsOnly(); - - if(pFont->m_iCharToGlyph.empty()) - LOG->Warn("Font %s has no characters", sFontOrTextureFilePath.GetString()); - - LoadStack.pop_back(); - - return pFont; -} - -/* A font set is a set of files, eg: - * - * Normal 16x16.png - * Normal [other] 16x16.png - * Normal [more] 8x8.png - * Normal 16x16.ini (the 16x16 here is optional) - * - * Only one texture is required; the INI is optional. [1] This is - * designed to be backwards-compatible. - * - * sFontOrTextureFilePath can be a partial path, eg. - * "Themes/default/Fonts/Normal" - * or a complete path to a texture file (in which case no other - * files will be searched for). - * - * The entire font can be redirected; that's handled in ThemeManager. - * Individual font files can not be redirected. - * - * TODO: - * [main] - * import=FontName,FontName2 (load other fonts) - * - * [1] If a file has no INI and sChars is not set, it will receive a default - * mapping of ASCII or ISO-8859-1 if the font has exactly 128 or 256 frames. - * However, if it doesn't, we don't know what it is and the font will receive - * no default mapping. A font isn't useful with no characters mapped. - */ Font* FontManager::LoadFont( const CString &sFontOrTextureFilePath, CString sChars ) { InitCharAliases(); @@ -440,7 +83,10 @@ Font* FontManager::LoadFont( const CString &sFontOrTextureFilePath, CString sCha return pFont; } - Font *f = LoadFontInt(sFontOrTextureFilePath, sChars); + /* XXX: This will mismatch cached fonts if we load the same font with two + * different sChars. */ + Font *f = new Font; + f->Load(sFontOrTextureFilePath, sChars); m_mapPathToFont[sFontOrTextureFilePath] = f; return f; } @@ -471,17 +117,6 @@ void FontManager::UnloadFont( Font *fp ) RageException::Throw( "Unloaded an unknown font (%p)", fp ); } -CString FontManager::GetPageNameFromFileName(const CString &fn) -{ - unsigned begin = fn.find_first_of('['); - if(begin == fn.npos) return "main"; - unsigned end = fn.find_first_of(']', begin); - if(end == fn.npos) return "main"; - begin++; end--; - if(end == begin) return "main"; - return fn.substr(begin, end-begin+1); -} - void FontManager::InitCharAliases() { diff --git a/stepmania/src/FontManager.h b/stepmania/src/FontManager.h index c284ed97b2..dd5bc112be 100644 --- a/stepmania/src/FontManager.h +++ b/stepmania/src/FontManager.h @@ -16,8 +16,6 @@ #include class Font; -class IniFile; -struct FontPageSettings; //----------------------------------------------------------------------------- // FontManager Class Declarations @@ -30,7 +28,9 @@ public: Font* LoadFont( const CString &sFontOrTextureFilePath, CString sChars = "" ); void UnloadFont( Font *fp ); + void ReloadFonts(); + /* Return true if FileName is a part of the font "FontName". */ static bool MatchesFont(CString FontName, CString FileName); static longchar MakeGameGlyph(longchar c, Game g); @@ -45,11 +45,6 @@ public: protected: // map from file name to a texture holder map m_mapPathToFont; - static Font *LoadFontInt(const CString &sFontOrTextureFilePath, CString sChars); - static CString GetPageNameFromFileName(const CString &fn); - static void LoadFontPageSettings(FontPageSettings &cfg, IniFile &ini, const CString &TexturePath, const CString &PageName, CString sChars); - static void GetFontPaths(const CString &sFontOrTextureFilePath, - CStringArray &TexturePaths, CString &IniPath); static void InitCharAliases(); }; diff --git a/stepmania/src/ThemeManager.cpp b/stepmania/src/ThemeManager.cpp index c7f8e6e2c8..ac456f60c2 100644 --- a/stepmania/src/ThemeManager.cpp +++ b/stepmania/src/ThemeManager.cpp @@ -19,7 +19,7 @@ #include "GameDef.h" #include "IniFile.h" #include "RageTimer.h" -#include "FontManager.h" +#include "Font.h" using namespace std; @@ -151,7 +151,7 @@ try_element_again: /* Weed out false matches. (For example, this gets rid of "normal2" when * we're really looking for "normal".) */ for(i = 0; i < int(asPossibleElementFilePaths.size()); ) { - if(!FontManager::MatchesFont(path + "Fonts\\"+ sFileName, asPossibleElementFilePaths[i])) + if(!Font::MatchesFont(path + "Fonts\\"+ sFileName, asPossibleElementFilePaths[i])) asPossibleElementFilePaths.erase(asPossibleElementFilePaths.begin()+i); else i++; } @@ -166,7 +166,7 @@ try_element_again: } for(i = 0; i < int(asPossibleElementFilePaths.size()); ) { - if(!FontManager::MatchesFont(path + "Fonts\\"+ sFileName, asPossibleElementFilePaths[i])) + if(!Font::MatchesFont(path + "Fonts\\"+ sFileName, asPossibleElementFilePaths[i])) asPossibleElementFilePaths.erase(asPossibleElementFilePaths.begin()+i); else i++; } @@ -250,7 +250,7 @@ try_element_again: }; static const char *sound_masks[] = { ".set", ".mp3", ".ogg", ".wav", ".redir", NULL }; static const char *font_masks[] = { "*.png", ".redir", NULL }; - static const char *numbers_masks[] = { " 5x3.png", ".redir", NULL }; + static const char *numbers_masks[] = { "*.png", ".redir", NULL }; static const char *bganimations_masks[] = { ".", ".redir", NULL }; static const char *blank_mask[] = { "", NULL }; const char **asset_masks = NULL;