gFont.cpp
Classes:
class
Used for repacking in GFont::importStrip.
Public Functions
DefineEngineFunction(dumpFontCacheStatus , void , () , "Dumps <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the console a full description of all cached fonts, along with " "info on the codepoints each <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">contains.\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(duplicateCachedFont , void , (const char *oldFontName, S32 oldFontSize, const char *newFontName) , "Copy the specified old font <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> a <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> name. The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> copy will not have a " "platform font backing it, and so will never have characters added <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> it. " "But this is useful <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> making copies of fonts <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> add postprocessing effects " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> via <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">exportCachedFont.\n</a>" " @param oldFontName The name of the font face <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">copy.\n</a>" " @param oldFontSize The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the font <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">copy.\n</a>" " @param newFontName The name of the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> font <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">face.\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(exportCachedFont , void , (const char *faceName, S32 fontSize, const char *fileName, S32 padding, S32 kerning) , "Export specified font <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the specified filename as a PNG. The " "image can then be processed in Photoshop or another tool and " "reimported using importCachedFont. Characters in the font are " "exported as one long <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">strip.\n</a>" "@param faceName The name of the font <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">face.\n</a>" "@param fontSize The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the font in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pixels.\n</a>" "@param fileName The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> name and path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the output <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PNG.\n</a>" "@param padding The padding between <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">characters.\n</a>" "@param kerning The kerning between <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">characters.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(importCachedFont , void , (const char *faceName, S32 fontSize, const char *fileName, S32 padding, S32 kerning) , "Import an image strip from exportCachedFont. Call with the " "same parameters you called <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">exportCachedFont.\n</a>" "@param faceName The name of the font <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">face.\n</a>" "@param fontSize The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the font in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pixels.\n</a>" "@param fileName The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> name and path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the input <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PNG.\n</a>" "@param padding The padding between <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">characters.\n</a>" "@param kerning The kerning between <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">characters.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(populateAllFontCacheRange , void , (U32 rangeStart, U32 rangeEnd) , "Populate the font cache <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> all fonts with Unicode code points in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">range.\n</a>" "@param rangeStart The start Unicode <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n</a>" "@param rangeEnd The end Unicode <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n</a>" "@note We only support BMP- 0, so code points range from 0 <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> 65535.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(populateAllFontCacheString , void , (const char *string) , "Populate the font cache <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> all fonts with characters from the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">string.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(populateFontCacheRange , void , (const char *faceName, S32 fontSize, U32 rangeStart, U32 rangeEnd) , "Populate the font cache <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the specified font with Unicode code points in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">range.\n</a>" "@param faceName The name of the font <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">face.\n</a>" "@param fontSize The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the font in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pixels.\n</a>" "@param rangeStart The start Unicode <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n</a>" "@param rangeEnd The end Unicode <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n</a>" "@note We only support BMP- 0, so code points range from 0 <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> 65535.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(populateFontCacheString , void , (const char *faceName, S32 fontSize, const char *string) , "Populate the font cache <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the specified font with characters from the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">string.\n</a>" "@param faceName The name of the font <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">face.\n</a>" "@param fontSize The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the font in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pixels.\n</a>" "@param string The string <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">populate.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(writeFontCache , void , () , "Force all cached fonts <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> serialize themselves <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">cache.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
GFX_ImplementTextureProfile(GFXFontTextureProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da23d780ef2bcc57521a4945415ce5207f">GFXTextureProfile::Static</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daa6bb823fc92adbec55ba4c34cd586062">GFXTextureProfile::KeepBitmap</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf55b13e32bd1a1746406b68ead73ba05">GFXTextureProfile::NoMipmap , GFXTextureProfile::NONE )
GlyphMapCompare(const void * a, const void * b)
Detailed Description
Public Functions
DefineEngineFunction(dumpFontCacheStatus , void , () , "Dumps <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the console a full description of all cached fonts, along with " "info on the codepoints each <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">contains.\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(duplicateCachedFont , void , (const char *oldFontName, S32 oldFontSize, const char *newFontName) , "Copy the specified old font <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> a <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> name. The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> copy will not have a " "platform font backing it, and so will never have characters added <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> it. " "But this is useful <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> making copies of fonts <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> add postprocessing effects " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> via <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">exportCachedFont.\n</a>" " @param oldFontName The name of the font face <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">copy.\n</a>" " @param oldFontSize The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the font <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">copy.\n</a>" " @param newFontName The name of the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> font <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">face.\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(exportCachedFont , void , (const char *faceName, S32 fontSize, const char *fileName, S32 padding, S32 kerning) , "Export specified font <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the specified filename as a PNG. The " "image can then be processed in Photoshop or another tool and " "reimported using importCachedFont. Characters in the font are " "exported as one long <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">strip.\n</a>" "@param faceName The name of the font <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">face.\n</a>" "@param fontSize The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the font in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pixels.\n</a>" "@param fileName The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> name and path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the output <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PNG.\n</a>" "@param padding The padding between <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">characters.\n</a>" "@param kerning The kerning between <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">characters.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(importCachedFont , void , (const char *faceName, S32 fontSize, const char *fileName, S32 padding, S32 kerning) , "Import an image strip from exportCachedFont. Call with the " "same parameters you called <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">exportCachedFont.\n</a>" "@param faceName The name of the font <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">face.\n</a>" "@param fontSize The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the font in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pixels.\n</a>" "@param fileName The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a702945180aa732857b380a007a7e2a21">file</a> name and path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the input <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">PNG.\n</a>" "@param padding The padding between <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">characters.\n</a>" "@param kerning The kerning between <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">characters.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(populateAllFontCacheRange , void , (U32 rangeStart, U32 rangeEnd) , "Populate the font cache <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> all fonts with Unicode code points in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">range.\n</a>" "@param rangeStart The start Unicode <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n</a>" "@param rangeEnd The end Unicode <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n</a>" "@note We only support BMP- 0, so code points range from 0 <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> 65535.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(populateAllFontCacheString , void , (const char *string) , "Populate the font cache <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> all fonts with characters from the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">string.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(populateFontCacheRange , void , (const char *faceName, S32 fontSize, U32 rangeStart, U32 rangeEnd) , "Populate the font cache <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the specified font with Unicode code points in the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">range.\n</a>" "@param faceName The name of the font <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">face.\n</a>" "@param fontSize The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the font in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pixels.\n</a>" "@param rangeStart The start Unicode <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n</a>" "@param rangeEnd The end Unicode <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">point.\n</a>" "@note We only support BMP- 0, so code points range from 0 <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> 65535.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(populateFontCacheString , void , (const char *faceName, S32 fontSize, const char *string) , "Populate the font cache <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the specified font with characters from the specified <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">string.\n</a>" "@param faceName The name of the font <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">face.\n</a>" "@param fontSize The <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1ab7d671599a7b25ca99a487fa341bc33a">size</a> of the font in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">pixels.\n</a>" "@param string The string <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">populate.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
DefineEngineFunction(writeFontCache , void , () , "Force all cached fonts <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> serialize themselves <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">cache.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Font\n</a>" )
GFX_ImplementTextureProfile(GFXFontTextureProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da23d780ef2bcc57521a4945415ce5207f">GFXTextureProfile::Static</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daa6bb823fc92adbec55ba4c34cd586062">GFXTextureProfile::KeepBitmap</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf55b13e32bd1a1746406b68ead73ba05">GFXTextureProfile::NoMipmap , GFXTextureProfile::NONE )
GlyphMapCompare(const void * a, const void * b)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "platform/platform.h" 25#include "gfx/gFont.h" 26 27#include "core/resourceManager.h" 28#include "core/stream/fileStream.h" 29#include "core/strings/unicode.h" 30#include "core/strings/findMatch.h" 31#include "core/strings/stringFunctions.h" 32#include "core/util/endian.h" 33#include "core/util/safeDelete.h" 34#include "console/console.h" 35#include "console/engineAPI.h" 36#include "platform/threads/mutex.h" 37#include "zlib/zlib.h" 38 39 40GFX_ImplementTextureProfile(GFXFontTextureProfile, 41 GFXTextureProfile::DiffuseMap, 42 GFXTextureProfile::PreserveSize | 43 GFXTextureProfile::Static | 44 GFXTextureProfile::KeepBitmap | 45 GFXTextureProfile::NoMipmap, 46 GFXTextureProfile::NONE); 47 48template<> void *Resource<GFont>::create(const Torque::Path &path) 49{ 50#ifdef TORQUE_DEBUG_RES_MANAGER 51 Con::printf( "Resource<GFont>::create - [%s]", path.getFullPath().c_str() ); 52#endif 53 54 return GFont::load( path ); 55} 56 57template<> ResourceBase::Signature Resource<GFont>::signature() 58{ 59 return MakeFourCC('f','o','n','t'); 60} 61 62/// Used for repacking in GFont::importStrip. 63struct GlyphMap 64{ 65 U32 charId; 66 GBitmap *bitmap; 67}; 68 69static S32 QSORT_CALLBACK GlyphMapCompare(const void *a, const void *b) 70{ 71 S32 ha = ((GlyphMap *) a)->bitmap->getHeight(); 72 S32 hb = ((GlyphMap *) b)->bitmap->getHeight(); 73 74 return hb - ha; 75} 76 77 78const U32 GFont::csm_fileVersion = 3; 79 80String GFont::getFontCacheFilename(const String &faceName, U32 size) 81{ 82 return String::ToString("%s/%s %d (%s).uft", 83 Con::getVariable("$GUI::fontCacheDirectory"), faceName.c_str(), size, getCharSetName(0)); 84} 85 86GFont* GFont::load( const Torque::Path& path ) 87{ 88 FileStream stream; 89 90 stream.open( path.getFullPath(), Torque::FS::File::Read ); 91 if ( stream.getStatus() != Stream::Ok ) 92 return NULL; 93 94 GFont *ret = new GFont; 95 ret->mGFTFile = path; 96 97 if(!ret->read(stream)) 98 { 99 Con::errorf( "GFont::load - error reading '%s'", path.getFullPath().c_str() ); 100 SAFE_DELETE(ret); 101 } 102 else 103 { 104#ifndef TORQUE_OS_XENON 105 PlatformFont *platFont = createPlatformFont(ret->getFontFaceName(), ret->getFontSize(), ret->getFontCharSet()); 106 107 if ( platFont == NULL ) 108 { 109 Con::errorf( "GFont::load - error creating platform font for '%s'", path.getFullPath().c_str() ); 110 SAFE_DELETE(ret); 111 } 112 else 113 ret->setPlatformFont(platFont); 114#endif 115 } 116 117 return ret; 118} 119 120Resource<GFont> GFont::create(const String &faceName, U32 size, const char *cacheDirectory, U32 charset /* = TGE_ANSI_CHARSET */) 121{ 122 if( !cacheDirectory ) 123 cacheDirectory = Con::getVariable( "$GUI::fontCacheDirectory" ); 124 125 const Torque::Path path( String::ToString("%s/%s %d (%s).uft", 126 cacheDirectory, faceName.c_str(), size, getCharSetName(charset)) ); 127 128 Resource<GFont> ret; 129 130 // If the file already exists attempt to load it 131 if (Platform::isFile(path.getFullPath().c_str())) 132 { 133 ret = ResourceManager::get().load(path); 134 135 if (ret != NULL) 136 { 137 ret->mGFTFile = path; 138 return ret; 139 } 140 } 141 142 // Otherwise attempt to have the platform generate a new font 143 PlatformFont *platFont = createPlatformFont(faceName, size, charset); 144 145 if (platFont == NULL) 146 { 147 String fontName; 148 149#ifdef _XBOX 150 //AssertFatal( false, "Font creation is not supported on the Xbox platform. Create the font files (*.uft) using the Windows/MacOS build of the project." ); 151 if(!faceName.equal("arial", String::NoCase) || size != 14) 152 { 153 return create("Arial", 14, cacheDirectory, charset); 154 } 155 return ret; 156#endif 157 158 // Couldn't load the requested font. This probably will be common 159 // since many unix boxes don't have arial or lucida console installed. 160 // Attempt to map the font name into a font we're pretty sure exist 161 // Lucida Console is a common code & console font on windows, and 162 // Monaco is the recommended code & console font on mac. 163 if (faceName.equal("arial", String::NoCase)) 164 fontName = "Helvetica"; 165 else if (faceName.equal("lucida console", String::NoCase)) 166 fontName = "Monaco"; 167 else if (faceName.equal("monaco", String::NoCase)) 168 fontName = "Courier"; 169 else 170 return ret; 171 172 return create(fontName, size, cacheDirectory, charset); 173 } 174 175 // Create the actual GFont and set some initial properties 176 GFont *font = new GFont; 177 font->mPlatformFont = platFont; 178 font->mGFTFile = path; 179 font->mFaceName = faceName; 180 font->mSize = size; 181 font->mCharSet = charset; 182 183 font->mHeight = platFont->getFontHeight(); 184 font->mBaseline = platFont->getFontBaseLine(); 185 font->mAscent = platFont->getFontBaseLine(); 186 font->mDescent = platFont->getFontHeight() - platFont->getFontBaseLine(); 187 188 // Flag it to save when we exit 189 font->mNeedSave = true; 190 191 // Load the newly created font into the ResourceManager 192 ret.setResource(ResourceManager::get().load(path), font); 193 194 return ret; 195} 196 197//------------------------------------------------------------------------- 198 199GFont::GFont() 200{ 201 VECTOR_SET_ASSOCIATION(mCharInfoList); 202 VECTOR_SET_ASSOCIATION(mTextureSheets); 203 204 for (U32 i = 0; i < (sizeof(mRemapTable) / sizeof(S32)); i++) 205 mRemapTable[i] = -1; 206 207 mCurX = mCurY = mCurSheet = -1; 208 209 mPlatformFont = NULL; 210 mSize = 0; 211 mCharSet = 0; 212 mNeedSave = false; 213 214 mMutex = Mutex::createMutex(); 215} 216 217GFont::~GFont() 218{ 219 if(mNeedSave) 220 { 221 AssertFatal( mGFTFile.getFullPath().isNotEmpty(), "GFont::~GFont - path not set" ); 222 223 FileStream stream; 224 stream.open(mGFTFile, Torque::FS::File::Write); 225 226 if(stream.getStatus() == Stream::Ok) 227 write(stream); 228 229 stream.close(); 230 } 231 232 S32 i; 233 234 for(i = 0;i < mCharInfoList.size();i++) 235 { 236 SAFE_DELETE_ARRAY(mCharInfoList[i].bitmapData); 237 } 238 239 for(i=0; i<mTextureSheets.size(); i++) 240 mTextureSheets[i] = NULL; 241 242 SAFE_DELETE(mPlatformFont); 243 244 Mutex::destroyMutex(mMutex); 245} 246 247void GFont::dumpInfo() const 248{ 249 // Number and extent of mapped characters? 250 U32 mapCount = 0, mapBegin=0xFFFF, mapEnd=0; 251 for(U32 i=0; i<0x10000; i++) 252 { 253 if(mRemapTable[i] != -1) 254 { 255 mapCount++; 256 if(i<mapBegin) mapBegin = i; 257 if(i>mapEnd) mapEnd = i; 258 } 259 } 260 261 262 // Let's write out all the info we can on this font. 263 Con::printf(" '%s' %dpt", mFaceName.c_str(), mSize); 264 Con::printf(" - %d texture sheets, %d mapped characters.", mTextureSheets.size(), mapCount); 265 266 if(mapCount) 267 Con::printf(" - Codepoints range from 0x%x to 0x%x.", mapBegin, mapEnd); 268 else 269 Con::printf(" - No mapped codepoints."); 270 Con::printf(" - Platform font is %s.", (mPlatformFont ? "present" : "not present") ); 271} 272 273//----------------------------------------------------------------------------- 274 275bool GFont::loadCharInfo(const UTF16 ch) 276{ 277 PROFILE_SCOPE(GFont_loadCharInfo); 278 279 if(mRemapTable[ch] != -1) 280 return true; // Not really an error 281 282 if(mPlatformFont && mPlatformFont->isValidChar(ch)) 283 { 284 Mutex::lockMutex(mMutex); // the CharInfo returned by mPlatformFont is static data, must protect from changes. 285 PlatformFont::CharInfo &ci = mPlatformFont->getCharInfo(ch); 286 if(ci.bitmapData) 287 addBitmap(ci); 288 289 mCharInfoList.push_back(ci); 290 mRemapTable[ch] = mCharInfoList.size() - 1; 291 292 mNeedSave = true; 293 294 Mutex::unlockMutex(mMutex); 295 return true; 296 } 297 298 return false; 299} 300 301void GFont::addBitmap(PlatformFont::CharInfo &charInfo) 302{ 303 U32 nextCurX = U32(mCurX + charInfo.width ); /*7) & ~0x3;*/ 304 U32 nextCurY = U32(mCurY + mPlatformFont->getFontHeight()); // + 7) & ~0x3; 305 306 // These are here for postmortem debugging. 307 bool routeA = false, routeB = false; 308 309 if(mCurSheet == -1 || nextCurY >= TextureSheetSize) 310 { 311 routeA = true; 312 addSheet(); 313 314 // Recalc our nexts. 315 nextCurX = U32(mCurX + charInfo.width); // + 7) & ~0x3; 316 nextCurY = U32(mCurY + mPlatformFont->getFontHeight()); // + 7) & ~0x3; 317 } 318 319 if( nextCurX >= TextureSheetSize) 320 { 321 routeB = true; 322 mCurX = 0; 323 mCurY = nextCurY; 324 325 // Recalc our nexts. 326 nextCurX = U32(mCurX + charInfo.width); // + 7) & ~0x3; 327 nextCurY = U32(mCurY + mPlatformFont->getFontHeight()); // + 7) & ~0x3; 328 } 329 330 // Check the Y once more - sometimes we advance to a new row and run off 331 // the end. 332 if(nextCurY >= TextureSheetSize) 333 { 334 routeA = true; 335 addSheet(); 336 337 // Recalc our nexts. 338 nextCurX = U32(mCurX + charInfo.width); // + 7) & ~0x3; 339 nextCurY = U32(mCurY + mPlatformFont->getFontHeight()); // + 7) & ~0x3; 340 } 341 342 charInfo.bitmapIndex = mCurSheet; 343 charInfo.xOffset = mCurX; 344 charInfo.yOffset = mCurY; 345 346 mCurX = nextCurX; 347 348 S32 x, y; 349 GBitmap *bmp = mTextureSheets[mCurSheet].getBitmap(); 350 351 AssertFatal(bmp->getFormat() == GFXFormatA8, "GFont::addBitmap - cannot added characters to non-greyscale textures!"); 352 353 for(y = 0;y < charInfo.height;y++) 354 for(x = 0;x < charInfo.width;x++) 355 *bmp->getAddress(x + charInfo.xOffset, y + charInfo.yOffset) = charInfo.bitmapData[y * charInfo.width + x]; 356 357 mTextureSheets[mCurSheet].refresh(); 358} 359 360void GFont::addSheet() 361{ 362 GBitmap *bitmap = new GBitmap(TextureSheetSize, TextureSheetSize, false, GFXFormatA8 ); 363 364 // Set everything to transparent. 365 U8 *bits = bitmap->getWritableBits(); 366 dMemset(bits, 0, sizeof(U8) *TextureSheetSize*TextureSheetSize); 367 368 GFXTexHandle handle = GFXTexHandle( bitmap, &GFXFontTextureProfile, true, avar("%s() - (line %d)", __FUNCTION__, __LINE__) ); 369 mTextureSheets.increment(); 370 mTextureSheets.last() = handle; 371 372 mCurX = 0; 373 mCurY = 0; 374 mCurSheet = mTextureSheets.size() - 1; 375} 376 377//----------------------------------------------------------------------------- 378 379const PlatformFont::CharInfo &GFont::getCharInfo(const UTF16 in_charIndex) 380{ 381 PROFILE_SCOPE(GFont_getCharInfo); 382 383 AssertFatal(in_charIndex, "GFont::getCharInfo - can't get info for char 0!"); 384 385 if(mRemapTable[in_charIndex] == -1) 386 loadCharInfo(in_charIndex); 387 388 AssertFatal(mRemapTable[in_charIndex] != -1, "No remap info for this character"); 389 390 return mCharInfoList[mRemapTable[in_charIndex]]; 391} 392 393const PlatformFont::CharInfo &GFont::getDefaultCharInfo() 394{ 395 static PlatformFont::CharInfo c; 396 // c is initialized by the CharInfo default constructor. 397 return c; 398} 399 400//----------------------------------------------------------------------------- 401 402U32 GFont::getStrWidth(const UTF8* in_pString) 403{ 404 AssertFatal(in_pString != NULL, "GFont::getStrWidth: String is NULL, height is undefined"); 405 // If we ain't running debug... 406 if (in_pString == NULL || *in_pString == '\0') 407 return 0; 408 409 return getStrNWidth(in_pString, dStrlen(in_pString)); 410} 411 412U32 GFont::getStrWidthPrecise(const UTF8* in_pString) 413{ 414 AssertFatal(in_pString != NULL, "GFont::getStrWidth: String is NULL, height is undefined"); 415 // If we ain't running debug... 416 if (in_pString == NULL) 417 return 0; 418 419 return getStrNWidthPrecise(in_pString, dStrlen(in_pString)); 420} 421 422//----------------------------------------------------------------------------- 423U32 GFont::getStrNWidth(const UTF8 *str, U32 n) 424{ 425 // UTF8 conversion is expensive. Avoid converting in a tight loop. 426 FrameTemp<UTF16> str16(n + 1); 427 convertUTF8toUTF16N(str, str16, n + 1); 428 return getStrNWidth(str16, dStrlen(str16)); 429} 430 431U32 GFont::getStrNWidth(const UTF16 *str, U32 n) 432{ 433 AssertFatal(str != NULL, "GFont::getStrNWidth: String is NULL"); 434 435 if (str == NULL || str[0] == '\0' || n == 0) 436 return 0; 437 438 U32 totWidth = 0; 439 UTF16 curChar; 440 U32 charCount; 441 442 for(charCount = 0; charCount < n; charCount++) 443 { 444 curChar = str[charCount]; 445 if(curChar == '\0') 446 break; 447 448 if(isValidChar(curChar)) 449 { 450 const PlatformFont::CharInfo& rChar = getCharInfo(curChar); 451 totWidth += rChar.xIncrement; 452 } 453 else if (curChar == dT('\t')) 454 { 455 const PlatformFont::CharInfo& rChar = getCharInfo(dT(' ')); 456 totWidth += rChar.xIncrement * TabWidthInSpaces; 457 } 458 } 459 460 return(totWidth); 461} 462 463U32 GFont::getStrNWidthPrecise(const UTF8 *str, U32 n) 464{ 465 FrameTemp<UTF16> str16(n + 1); 466 convertUTF8toUTF16N(str, str16, n + 1); 467 return getStrNWidthPrecise(str16, dStrlen(str16)); 468} 469 470U32 GFont::getStrNWidthPrecise(const UTF16 *str, U32 n) 471{ 472 AssertFatal(str != NULL, "GFont::getStrNWidth: String is NULL"); 473 474 if (str == NULL || str[0] == '\0' || n == 0) 475 return(0); 476 477 U32 totWidth = 0; 478 UTF16 curChar; 479 U32 charCount = 0; 480 481 for(charCount = 0; charCount < n; charCount++) 482 { 483 curChar = str[charCount]; 484 if(curChar == '\0') 485 break; 486 487 if(isValidChar(curChar)) 488 { 489 const PlatformFont::CharInfo& rChar = getCharInfo(curChar); 490 totWidth += rChar.xIncrement; 491 } 492 else if (curChar == dT('\t')) 493 { 494 const PlatformFont::CharInfo& rChar = getCharInfo(dT(' ')); 495 totWidth += rChar.xIncrement * TabWidthInSpaces; 496 } 497 } 498 499 UTF16 endChar = str[getMin(charCount,n-1)]; 500 501 if (isValidChar(endChar)) 502 { 503 const PlatformFont::CharInfo& rChar = getCharInfo(endChar); 504 if (rChar.width != rChar.xIncrement) 505 totWidth += (rChar.width - rChar.xIncrement); 506 } 507 508 return(totWidth); 509} 510 511U32 GFont::getBreakPos(const UTF16 *str16, U32 slen, U32 width, bool breakOnWhitespace) 512{ 513 // Some early out cases. 514 if(slen==0) 515 return 0; 516 517 U32 ret = 0; 518 U32 lastws = 0; 519 UTF16 c; 520 U32 charCount = 0; 521 522 for( charCount=0; charCount < slen; charCount++) 523 { 524 c = str16[charCount]; 525 if(c == '\0') 526 break; 527 528 if(c == dT('\t')) 529 c = dT(' '); 530 531 if(!isValidChar(c)) 532 { 533 ret++; 534 continue; 535 } 536 537 if(c == dT(' ')) 538 lastws = ret+1; 539 540 const PlatformFont::CharInfo& rChar = getCharInfo(c); 541 if(rChar.width > width || rChar.xIncrement > width) 542 { 543 if(lastws && breakOnWhitespace) 544 return lastws; 545 return ret; 546 } 547 548 width -= rChar.xIncrement; 549 550 ret++; 551 } 552 return ret; 553} 554 555void GFont::wrapString(const UTF8 *txt, U32 lineWidth, Vector<U32> &startLineOffset, Vector<U32> &lineLen) 556{ 557 // TODO: Is this error still true? 558 //Con::errorf("GFont::wrapString(): Not yet converted to be UTF-8 safe"); 559 560 startLineOffset.clear(); 561 lineLen.clear(); 562 563 if (!txt || !txt[0] || lineWidth < getCharWidth('W')) //make sure the line width is greater then a single character 564 return; 565 566 U32 len = dStrlen(txt); 567 568 U32 startLine; 569 570 for (U32 i = 0; i < len;) 571 { 572 U32 wide = 0; 573 startLine = i; 574 startLineOffset.push_back(startLine); 575 576 // loop until the string is too large 577 bool needsNewLine = false; 578 U32 lineStrWidth = 0; 579 for (; i < len; i++) 580 { 581 if( txt[ i ] == '\n' ) 582 { 583 needsNewLine = true; 584 break; 585 } 586 else if(isValidChar(txt[i])) 587 { 588 lineStrWidth += getCharInfo(txt[i]).xIncrement; 589 if(txt[i] < 0) // symbols which code > 127 590 { 591 wide++; i++; 592 } 593 if( lineStrWidth > lineWidth ) 594 { 595 needsNewLine = true; 596 break; 597 } 598 } 599 } 600 601 if (!needsNewLine) 602 { 603 // we are done! 604 lineLen.push_back(i - startLine - wide); 605 return; 606 } 607 608 S32 j; 609 610 // Did we hit a hardwrap (newline character) in the string. 611 bool hardwrap = ( txt[i] == '\n' ); 612 613 if ( hardwrap ) 614 { 615 j = i; 616 } 617 // determine where to put the newline 618 // we need to backtrack until we find a space character 619 // we don't do this for hardwrap(s) 620 else 621 { 622 for (j = i - 1; j >= startLine; j--) 623 { 624 if ( dIsspace(txt[j]) || txt[i] == '\n' ) 625 break; 626 } 627 628 if (j < startLine) 629 { 630 // the line consists of a single word! 631 // So, just break up the word 632 633 j = i - 1; 634 } 635 } 636 637 lineLen.push_back(j - startLine - wide); 638 i = j; 639 640 // Now we need to increment through any space characters at the 641 // beginning of the next line. 642 // We don't skip spaces after a hardwrap because they were obviously intended. 643 for (i++; i < len; i++) 644 { 645 if ( txt[i] == '\n' ) 646 continue; 647 648 if ( dIsspace( txt[i] ) && !hardwrap ) 649 continue; 650 651 break; 652 } 653 } 654} 655 656//----------------------------------------------------------------------------- 657 658bool GFont::read(Stream& io_rStream) 659{ 660 // Handle versioning 661 U32 version; 662 io_rStream.read(&version); 663 if(version != csm_fileVersion) 664 return false; 665 666 char buf[256]; 667 io_rStream.readString(buf); 668 mFaceName = buf; 669 670 io_rStream.read(&mSize); 671 io_rStream.read(&mCharSet); 672 673 io_rStream.read(&mHeight); 674 io_rStream.read(&mBaseline); 675 io_rStream.read(&mAscent); 676 io_rStream.read(&mDescent); 677 678 U32 size = 0; 679 io_rStream.read(&size); 680 mCharInfoList.setSize(size); 681 U32 i; 682 for(i = 0; i < size; i++) 683 { 684 PlatformFont::CharInfo *ci = &mCharInfoList[i]; 685 io_rStream.read(&ci->bitmapIndex); 686 io_rStream.read(&ci->xOffset); 687 io_rStream.read(&ci->yOffset); 688 io_rStream.read(&ci->width); 689 io_rStream.read(&ci->height); 690 io_rStream.read(&ci->xOrigin); 691 io_rStream.read(&ci->yOrigin); 692 io_rStream.read(&ci->xIncrement); 693 ci->bitmapData = NULL; 694 } 695 696 U32 numSheets = 0; 697 io_rStream.read(&numSheets); 698 699 for(i = 0; i < numSheets; i++) 700 { 701 GBitmap *bmp = new GBitmap; 702 if(!bmp->readBitmap("png", io_rStream)) 703 { 704 delete bmp; 705 return false; 706 } 707 GFXTexHandle handle = GFXTexHandle(bmp, &GFXFontTextureProfile, true, avar("%s() - Read Font Sheet for %s %d (line %d)", __FUNCTION__, mFaceName.c_str(), mSize, __LINE__)); 708 //handle.setFilterNearest(); 709 mTextureSheets.push_back(handle); 710 } 711 712 // Read last position info 713 io_rStream.read(&mCurX); 714 io_rStream.read(&mCurY); 715 io_rStream.read(&mCurSheet); 716 717 // Read the remap table. 718 U32 minGlyph, maxGlyph; 719 io_rStream.read(&minGlyph); 720 io_rStream.read(&maxGlyph); 721 722 if(maxGlyph >= minGlyph) 723 { 724 // Length of buffer.. 725 U32 buffLen; 726 io_rStream.read(&buffLen); 727 728 // Read the buffer. 729 FrameTemp<S32> inBuff(buffLen); 730 io_rStream.read(buffLen, inBuff); 731 732 // Decompress. 733 uLongf destLen = (maxGlyph-minGlyph+1)*sizeof(S32); 734 uncompress((Bytef*)&mRemapTable[minGlyph], &destLen, (Bytef*)(S32*)inBuff, buffLen); 735 736 AssertISV(destLen == (maxGlyph-minGlyph+1)*sizeof(S32), "GFont::read - invalid remap table data!"); 737 738 // Make sure we've got the right endianness. 739 for(i = minGlyph; i <= maxGlyph; i++) 740 mRemapTable[i] = convertBEndianToHost(mRemapTable[i]); 741 } 742 743 return (io_rStream.getStatus() == Stream::Ok); 744} 745 746bool GFont::write(Stream& stream) 747{ 748 // Handle versioning 749 stream.write(csm_fileVersion); 750 751 // Write font info 752 stream.write(mFaceName); 753 stream.write(mSize); 754 stream.write(mCharSet); 755 756 stream.write(mHeight); 757 stream.write(mBaseline); 758 stream.write(mAscent); 759 stream.write(mDescent); 760 761 // Write char info list 762 stream.write(U32(mCharInfoList.size())); 763 U32 i; 764 for(i = 0; i < mCharInfoList.size(); i++) 765 { 766 const PlatformFont::CharInfo *ci = &mCharInfoList[i]; 767 stream.write(ci->bitmapIndex); 768 stream.write(ci->xOffset); 769 stream.write(ci->yOffset); 770 stream.write(ci->width); 771 stream.write(ci->height); 772 stream.write(ci->xOrigin); 773 stream.write(ci->yOrigin); 774 stream.write(ci->xIncrement); 775 } 776 777 stream.write(mTextureSheets.size()); 778 for(i = 0; i < mTextureSheets.size(); i++) 779 mTextureSheets[i].getBitmap()->writeBitmap("png", stream); 780 781 stream.write(mCurX); 782 stream.write(mCurY); 783 stream.write(mCurSheet); 784 785 // Get the min/max we have values for, and only write that range out. 786 S32 minGlyph = S32_MAX, maxGlyph = 0; 787 788 for(i = 0; i < 65536; i++) 789 { 790 if(mRemapTable[i] != -1) 791 { 792 if(i>maxGlyph) maxGlyph = i; 793 if(i<minGlyph) minGlyph = i; 794 } 795 } 796 797 stream.write(minGlyph); 798 stream.write(maxGlyph); 799 800 // Skip it if we don't have any glyphs to do... 801 if(maxGlyph >= minGlyph) 802 { 803 // Put everything big endian, to be consistent. Do this inplace. 804 for(i = minGlyph; i <= maxGlyph; i++) 805 mRemapTable[i] = convertHostToBEndian(mRemapTable[i]); 806 807 { 808 // Compress. 809 const U32 buffSize = 128 * 1024; 810 FrameTemp<S32> outBuff(buffSize); 811 uLongf destLen = buffSize * sizeof(S32); 812 compress2((Bytef*)(S32*)outBuff, &destLen, (Bytef*)(S32*)&mRemapTable[minGlyph], (maxGlyph-minGlyph+1)*sizeof(S32), 9); 813 814 // Write out. 815 stream.write((U32)destLen); 816 stream.write(destLen, outBuff); 817 } 818 819 // Put us back to normal. 820 for(i = minGlyph; i <= maxGlyph; i++) 821 mRemapTable[i] = convertBEndianToHost(mRemapTable[i]); 822 } 823 824 return (stream.getStatus() == Stream::Ok); 825} 826 827void GFont::exportStrip(const char *fileName, U32 padding, U32 kerning) 828{ 829 // Figure dimensions of our strip by iterating over all the char infos. 830 U32 totalHeight = 0; 831 U32 totalWidth = 0; 832 833 S32 heightMin=0, heightMax=0; 834 835 for(S32 i=0; i<mCharInfoList.size(); i++) 836 { 837 totalWidth += mCharInfoList[i].width + kerning + 2*padding; 838 heightMin = getMin((S32)heightMin, (S32)getBaseline() - (S32)mCharInfoList[i].yOrigin); 839 heightMax = getMax((S32)heightMax, (S32)getBaseline() - (S32)mCharInfoList[i].yOrigin + (S32)mCharInfoList[i].height); 840 } 841 842 totalHeight = heightMax - heightMin + 2*padding; 843 844 // Make the bitmap. 845 GBitmap gb(totalWidth, totalHeight, false, mTextureSheets[0].getBitmap()->getFormat()); 846 847 dMemset(gb.getWritableBits(), 0, sizeof(U8) * totalHeight * totalWidth ); 848 849 // Ok, copy some rects, taking into account padding, kerning, offset. 850 U32 curWidth = kerning + padding; 851 852 for(S32 i=0; i<mCharInfoList.size(); i++) 853 { 854 // Skip invalid stuff. 855 if(mCharInfoList[i].bitmapIndex == -1 || mCharInfoList[i].height == 0 || mCharInfoList[i].width == 0) 856 continue; 857 858 // Copy the rect. 859 U32 bitmap = mCharInfoList[i].bitmapIndex; 860 861 RectI ri(mCharInfoList[i].xOffset, mCharInfoList[i].yOffset, mCharInfoList[i].width, mCharInfoList[i].height ); 862 Point2I outRi(curWidth, padding + getBaseline() - mCharInfoList[i].yOrigin); 863 gb.copyRect(mTextureSheets[bitmap].getBitmap(), ri, outRi); 864 865 // Advance. 866 curWidth += mCharInfoList[i].width + kerning + 2*padding; 867 } 868 869 // Write the image! 870 FileStream fs; 871 872 fs.open( fileName, Torque::FS::File::Write ); 873 874 if(fs.getStatus() != Stream::Ok) 875 { 876 Con::errorf("GFont::exportStrip - failed to open '%s' for writing.", fileName); 877 return; 878 } 879 880 // Done! 881 gb.writeBitmap("png", fs); 882} 883 884void GFont::setPlatformFont(PlatformFont *inPlatformFont) 885{ 886 AssertFatal( mPlatformFont == NULL, "Trying to set platform font which already exists"); 887 888 mPlatformFont = inPlatformFont; 889} 890 891void GFont::importStrip(const char *fileName, U32 padding, U32 kerning) 892{ 893 // Wipe our texture sheets, and reload bitmap data from the specified file. 894 // Also deal with kerning. 895 // Also, we may have to load RGBA instead of RGB. 896 897 // Wipe our texture sheets. 898 mCurSheet = mCurX = mCurY = 0; 899 mTextureSheets.clear(); 900 901 // Now, load the font strip. 902 Resource<GBitmap> strip = GBitmap::load(fileName); 903 904 if(!strip) 905 { 906 Con::errorf("GFont::importStrip - could not load file '%s'!", fileName); 907 return; 908 } 909 910 // And get parsing and copying - load up all the characters as separate 911 // GBitmaps, sort, then pack. Not terribly efficient but this is basically 912 // on offline task anyway. 913 914 // Ok, snag some glyphs. 915 Vector<GlyphMap> glyphList; 916 glyphList.reserve(mCharInfoList.size()); 917 918 U32 curWidth = 0; 919 for(S32 i=0; i<mCharInfoList.size(); i++) 920 { 921 // Skip invalid stuff. 922 if(mCharInfoList[i].bitmapIndex == -1 || mCharInfoList[i].height == 0 || mCharInfoList[i].width == 0) 923 continue; 924 925 // Allocate a new bitmap for this glyph, taking into account kerning and padding. 926 glyphList.increment(); 927 GlyphMap& lastGlyphMap = glyphList.last(); 928 lastGlyphMap.bitmap = new GBitmap(mCharInfoList[i].width + kerning + 2 * padding, mCharInfoList[i].height + 2 * padding, false, strip->getFormat()); 929 lastGlyphMap.charId = i; 930 931 // Copy the rect. 932 RectI ri(curWidth, getBaseline() - mCharInfoList[i].yOrigin, lastGlyphMap.bitmap->getWidth(), lastGlyphMap.bitmap->getHeight()); 933 Point2I outRi(0,0); 934 lastGlyphMap.bitmap->copyRect(strip, ri, outRi); 935 936 // Update glyph attributes. 937 mCharInfoList[i].width = lastGlyphMap.bitmap->getWidth(); 938 mCharInfoList[i].height = lastGlyphMap.bitmap->getHeight(); 939 mCharInfoList[i].xOffset -= kerning + padding; 940 mCharInfoList[i].xIncrement += kerning; 941 mCharInfoList[i].yOffset -= padding; 942 943 // Advance. 944 curWidth += ri.extent.x; 945 } 946 947 // Ok, we have a big list of glyphmaps now. So let's sort them, then pack them. 948 dQsort(glyphList.address(), glyphList.size(), sizeof(GlyphMap), GlyphMapCompare); 949 950 // They're sorted by height, so now we can do some sort of awesome packing. 951 Point2I curSheetSize(256, 256); 952 Vector<U32> sheetSizes; 953 954 S32 curY = 0; 955 S32 curX = 0; 956 S32 curLnHeight = 0; 957 S32 maxHeight = 0; 958 for(U32 i = 0; i < glyphList.size(); i++) 959 { 960 PlatformFont::CharInfo *ci = &mCharInfoList[glyphList[i].charId]; 961 962 if(ci->height > maxHeight) 963 maxHeight = ci->height; 964 965 if(curX + ci->width > curSheetSize.x) 966 { 967 curY += curLnHeight; 968 curX = 0; 969 curLnHeight = 0; 970 } 971 972 if(curY + ci->height > curSheetSize.y) 973 { 974 sheetSizes.push_back(curSheetSize.y); 975 curX = 0; 976 curY = 0; 977 curLnHeight = 0; 978 } 979 980 if(ci->height > curLnHeight) 981 curLnHeight = ci->height; 982 983 ci->bitmapIndex = sheetSizes.size(); 984 ci->xOffset = curX; 985 ci->yOffset = curY; 986 curX += ci->width; 987 } 988 989 // Terminate the packing loop calculations. 990 curY += curLnHeight; 991 992 if(curY < 64) 993 curSheetSize.y = 64; 994 else if(curY < 128) 995 curSheetSize.y = 128; 996 997 sheetSizes.push_back(curSheetSize.y); 998 999 if(getHeight() + padding * 2 > maxHeight) 1000 maxHeight = getHeight() + padding * 2; 1001 1002 // Allocate texture pages. 1003 for(S32 i=0; i<sheetSizes.size(); i++) 1004 { 1005 GBitmap *bitmap = new GBitmap(TextureSheetSize, TextureSheetSize, false, strip->getFormat()); 1006 1007 // Set everything to transparent. 1008 U8 *bits = bitmap->getWritableBits(); 1009 dMemset(bits, 0, sizeof(U8) *TextureSheetSize*TextureSheetSize * strip->getBytesPerPixel()); 1010 1011 GFXTexHandle handle = GFXTexHandle( bitmap, &GFXFontTextureProfile, true, avar("%s() - Font Sheet for %s (line %d)", __FUNCTION__, fileName, __LINE__) ); 1012 mTextureSheets.increment(); 1013 mTextureSheets.last() = handle; 1014 } 1015 1016 // Alright, we're ready to copy bits! 1017 for(S32 i=0; i<glyphList.size(); i++) 1018 { 1019 // Copy each glyph into the appropriate place. 1020 PlatformFont::CharInfo *ci = &mCharInfoList[glyphList[i].charId]; 1021 U32 bi = ci->bitmapIndex; 1022 mTextureSheets[bi]->getBitmap()->copyRect(glyphList[i].bitmap, RectI(0,0, glyphList[i].bitmap->getWidth(),glyphList[i].bitmap->getHeight()), Point2I(ci->xOffset, ci->yOffset)); 1023 } 1024 1025 // Ok, all done! Just refresh some textures and we're set. 1026 for(S32 i=0; i<sheetSizes.size(); i++) 1027 mTextureSheets[i].refresh(); 1028} 1029 1030DefineEngineFunction( populateFontCacheString, void, ( const char *faceName, S32 fontSize, const char *string ),, 1031 "Populate the font cache for the specified font with characters from the specified string.\n" 1032 "@param faceName The name of the font face.\n" 1033 "@param fontSize The size of the font in pixels.\n" 1034 "@param string The string to populate.\n" 1035 "@ingroup Font\n" ) 1036{ 1037 Resource<GFont> f = GFont::create(faceName, fontSize, Con::getVariable("$GUI::fontCacheDirectory")); 1038 1039 if(f == NULL) 1040 { 1041 Con::errorf("populateFontCacheString - could not load font '%s %d'", faceName, fontSize); 1042 return; 1043 } 1044 1045 if(!f->hasPlatformFont()) 1046 { 1047 Con::errorf("populateFontCacheString - font '%s %d' has no platform font. Cannot generate more characters.", faceName, fontSize); 1048 return; 1049 } 1050 1051 // This has the side effect of generating character info, including the bitmaps. 1052 f->getStrWidthPrecise( string ); 1053} 1054 1055DefineEngineFunction( populateFontCacheRange, void, ( const char *faceName, S32 fontSize, U32 rangeStart, U32 rangeEnd ),, 1056 "Populate the font cache for the specified font with Unicode code points in the specified range.\n" 1057 "@param faceName The name of the font face.\n" 1058 "@param fontSize The size of the font in pixels.\n" 1059 "@param rangeStart The start Unicode point.\n" 1060 "@param rangeEnd The end Unicode point.\n" 1061 "@note We only support BMP-0, so code points range from 0 to 65535.\n" 1062 "@ingroup Font\n" ) 1063{ 1064 Resource<GFont> f = GFont::create(faceName, fontSize, Con::getVariable("$GUI::fontCacheDirectory")); 1065 1066 if(f == NULL) 1067 { 1068 Con::errorf("populateFontCacheRange - could not load font '%s %d'", faceName, fontSize); 1069 return; 1070 } 1071 1072 if(rangeStart > rangeEnd) 1073 { 1074 Con::errorf("populateFontCacheRange - range start is after end"); 1075 return; 1076 } 1077 1078 if(!f->hasPlatformFont()) 1079 { 1080 Con::errorf("populateFontCacheRange - font '%s %d' has no platform font Cannot generate more characters.", faceName, fontSize); 1081 return; 1082 } 1083 1084 // This has the side effect of generating character info, including the bitmaps. 1085 for(U32 i=rangeStart; i<rangeEnd; i++) 1086 { 1087 if(f->isValidChar(i)) 1088 f->getCharWidth(i); 1089 else 1090 Con::warnf("populateFontCacheRange - skipping invalid char 0x%x", i); 1091 } 1092 1093 // All done! 1094} 1095 1096DefineEngineFunction( dumpFontCacheStatus, void, (),, 1097 "Dumps to the console a full description of all cached fonts, along with " 1098 "info on the codepoints each contains.\n" 1099 "@ingroup Font\n" ) 1100{ 1101 Resource<GFont> theFont = ResourceManager::get().startResourceList( Resource<GFont>::signature() ); 1102 1103 Con::printf("--------------------------------------------------------------------------"); 1104 Con::printf(" Font Cache Usage Report"); 1105 1106 while( theFont != NULL ) 1107 { 1108 theFont->dumpInfo(); 1109 1110 theFont = ResourceManager::get().nextResource(); 1111 } 1112} 1113 1114DefineEngineFunction( writeFontCache, void, (),, 1115 "Force all cached fonts to serialize themselves to the cache.\n" 1116 "@ingroup Font\n" ) 1117{ 1118 Resource<GFont> theFont = ResourceManager::get().startResourceList( Resource<GFont>::signature() ); 1119 1120 Con::printf("--------------------------------------------------------------------------"); 1121 Con::printf(" Writing font cache to disk"); 1122 1123 while( theFont != NULL ) 1124 { 1125 const String fileName( theFont.getPath() ); 1126 1127 FileStream stream; 1128 stream.open(fileName, Torque::FS::File::Write); 1129 1130 if(stream.getStatus() == Stream::Ok) 1131 { 1132 Con::printf(" o Writing '%s' to disk...", fileName.c_str()); 1133 theFont->write(stream); 1134 } 1135 else 1136 { 1137 Con::errorf(" o Could not open '%s' for write", fileName.c_str()); 1138 } 1139 1140 theFont = ResourceManager::get().nextResource(); 1141 } 1142} 1143 1144DefineEngineFunction( populateAllFontCacheString, void, ( const char *string ),, 1145 "Populate the font cache for all fonts with characters from the specified string.\n" 1146 "@ingroup Font\n" ) 1147{ 1148 Resource<GFont> theFont = ResourceManager::get().startResourceList( Resource<GFont>::signature() ); 1149 1150 Con::printf("Populating font cache with string '%s'", string); 1151 1152 while( theFont != NULL ) 1153 { 1154 if(theFont->hasPlatformFont()) 1155 { 1156 // This has the side effect of generating character info, including the bitmaps. 1157 theFont->getStrWidthPrecise( string ); 1158 } 1159 else 1160 { 1161 const String fileName( theFont.getPath() ); 1162 Con::errorf("populateAllFontCacheString - font '%s' has no platform font. Cannot generate more characters.", fileName.c_str()); 1163 } 1164 1165 theFont = ResourceManager::get().nextResource(); 1166 } 1167} 1168 1169DefineEngineFunction( populateAllFontCacheRange, void, ( U32 rangeStart, U32 rangeEnd ),, 1170 "Populate the font cache for all fonts with Unicode code points in the specified range.\n" 1171 "@param rangeStart The start Unicode point.\n" 1172 "@param rangeEnd The end Unicode point.\n" 1173 "@note We only support BMP-0, so code points range from 0 to 65535.\n" 1174 "@ingroup Font\n" ) 1175{ 1176 if(rangeStart > rangeEnd) 1177 { 1178 Con::errorf("populateAllFontCacheRange - range start is after end!"); 1179 return; 1180 } 1181 1182 Resource<GFont> theFont = ResourceManager::get().startResourceList( Resource<GFont>::signature() ); 1183 1184 Con::printf("Populating font cache with range 0x%x to 0x%x", rangeStart, rangeEnd); 1185 1186 while( theFont != NULL ) 1187 { 1188 const String fileName( theFont.getPath() ); 1189 1190 if(theFont->hasPlatformFont()) 1191 { 1192 // This has the side effect of generating character info, including the bitmaps. 1193 Con::printf(" o Populating font '%s'", fileName.c_str()); 1194 for(U32 i=rangeStart; i<rangeEnd; i++) 1195 { 1196 if(theFont->isValidChar(i)) 1197 theFont->getCharWidth(i); 1198 else 1199 Con::warnf("populateAllFontCacheRange - skipping invalid char 0x%x", i); 1200 } 1201 } 1202 else 1203 { 1204 Con::errorf("populateAllFontCacheRange - font '%s' has no platform font. Cannot generate more characters.", fileName.c_str()); 1205 } 1206 1207 theFont = ResourceManager::get().nextResource(); 1208 } 1209} 1210 1211DefineEngineFunction( exportCachedFont, void, 1212 ( const char *faceName, S32 fontSize, const char *fileName, S32 padding, S32 kerning ),, 1213 "Export specified font to the specified filename as a PNG. The " 1214 "image can then be processed in Photoshop or another tool and " 1215 "reimported using importCachedFont. Characters in the font are " 1216 "exported as one long strip.\n" 1217 "@param faceName The name of the font face.\n" 1218 "@param fontSize The size of the font in pixels.\n" 1219 "@param fileName The file name and path for the output PNG.\n" 1220 "@param padding The padding between characters.\n" 1221 "@param kerning The kerning between characters.\n" 1222 "@ingroup Font\n" ) 1223{ 1224 // Tell the font to export itself. 1225 Resource<GFont> f = GFont::create(faceName, fontSize, Con::getVariable("$GUI::fontCacheDirectory")); 1226 1227 if(f == NULL) 1228 { 1229 Con::errorf("exportCachedFont - could not load font '%s %d'", faceName, fontSize); 1230 return; 1231 } 1232 1233 f->exportStrip(fileName, padding, kerning); 1234} 1235 1236DefineEngineFunction( importCachedFont, void, 1237 ( const char *faceName, S32 fontSize, const char *fileName, S32 padding, S32 kerning ),, 1238 "Import an image strip from exportCachedFont. Call with the " 1239 "same parameters you called exportCachedFont.\n" 1240 "@param faceName The name of the font face.\n" 1241 "@param fontSize The size of the font in pixels.\n" 1242 "@param fileName The file name and path for the input PNG.\n" 1243 "@param padding The padding between characters.\n" 1244 "@param kerning The kerning between characters.\n" 1245 "@ingroup Font\n" ) 1246{ 1247 // Tell the font to import itself. 1248 Resource<GFont> f = GFont::create(faceName, fontSize, Con::getVariable("$GUI::fontCacheDirectory")); 1249 1250 if(f == NULL) 1251 { 1252 Con::errorf("importCachedFont - could not load font '%s %d'", faceName, fontSize); 1253 return; 1254 } 1255 1256 f->importStrip(fileName, padding, kerning); 1257} 1258 1259DefineEngineFunction( duplicateCachedFont, void, 1260 ( const char *oldFontName, S32 oldFontSize, const char *newFontName ),, 1261 "Copy the specified old font to a new name. The new copy will not have a " 1262 "platform font backing it, and so will never have characters added to it. " 1263 "But this is useful for making copies of fonts to add postprocessing effects " 1264 "to via exportCachedFont.\n" 1265 "@param oldFontName The name of the font face to copy.\n" 1266 "@param oldFontSize The size of the font to copy.\n" 1267 "@param newFontName The name of the new font face.\n" 1268 "@ingroup Font\n" ) 1269{ 1270 String newFontFile = GFont::getFontCacheFilename(newFontName, oldFontSize); 1271 1272 // Load the original font. 1273 Resource<GFont> font = GFont::create(oldFontName, oldFontSize, Con::getVariable("$GUI::fontCacheDirectory")); 1274 1275 // Deal with inexplicably missing or failed to load fonts. 1276 if (font == NULL) 1277 { 1278 Con::errorf(" o Couldn't find font : %s", oldFontName); 1279 return; 1280 } 1281 1282 // Ok, dump info! 1283 FileStream stream; 1284 stream.open( newFontFile, Torque::FS::File::Write ); 1285 if(stream.getStatus() == Stream::Ok) 1286 { 1287 Con::printf( " o Writing duplicate font '%s' to disk...", newFontFile.c_str() ); 1288 font->write(stream); 1289 stream.close(); 1290 } 1291 else 1292 { 1293 Con::errorf( " o Could not open '%s' for write", newFontFile.c_str() ); 1294 } 1295} 1296 1297
