Font problems
by Rubes · in Torque Game Engine · 02/02/2006 (10:57 am) · 37 replies
I've been trying to get new fonts into my game, but I'm running into some issues (using 1.4).
I tried replacing the typical Arial font in most of my Gui's with a custom font installed on my Mac system. Works fine. Everywhere I expect to see the new font, I see it. The appropriate font/size UFT file is created in the font cache folder as well.
However, if I move my game to another system (Mac or PC) that does not have this font installed, it doesn't display at all. Or, if I disable the font in my original system, it won't work there either. So it doesn't seem to be using the cached font file.
I searched around but didn't see anything obvious on this. There is a TDN article on Torque Unicode but I didn't entirely grasp it and I'm not sure it has the solution. Anybody else seeing this?
I tried replacing the typical Arial font in most of my Gui's with a custom font installed on my Mac system. Works fine. Everywhere I expect to see the new font, I see it. The appropriate font/size UFT file is created in the font cache folder as well.
However, if I move my game to another system (Mac or PC) that does not have this font installed, it doesn't display at all. Or, if I disable the font in my original system, it won't work there either. So it doesn't seem to be using the cached font file.
I searched around but didn't see anything obvious on this. There is a TDN article on Torque Unicode but I didn't entirely grasp it and I'm not sure it has the solution. Anybody else seeing this?
#2
02/02/2006 (8:42 pm)
Awesome, thanks...1.4.1 is not out yet, right?
#3
I was looking into it, but the fix doesn't look obvious. It looks like it's failing to load the cached font every time, forcing it to recreate it (using Arial), and it seems to keep adding new characters to the internal cache as they are needed, before writing the cache during shutdown.
I tried using the PNG font export/import functions, but I couldn't get them working... I managed to export a PNG, but when I import it back, nothing happens, the font won't change: it remains Arial.
02/14/2006 (6:07 am)
Ben, could you post how to fix that bug? We are going to ship a TGE 1.4 game in 3 days, and this bug must get killed ASAP. I was looking into it, but the fix doesn't look obvious. It looks like it's failing to load the cached font every time, forcing it to recreate it (using Arial), and it seems to keep adding new characters to the internal cache as they are needed, before writing the cache during shutdown.
I tried using the PNG font export/import functions, but I couldn't get them working... I managed to export a PNG, but when I import it back, nothing happens, the font won't change: it remains Arial.
#4
02/14/2006 (11:39 am)
Go to GFont destructor, delete first if statement. The one that's writing the UFT back out.
#5
...then deleting it and recompiling didn't have any effect. The font still won't appear when it's not installed on the system, only this time no UFT file at all is created.
02/14/2006 (12:14 pm)
Not sure I get it. If you're referring to this statement:if(mGFTFile)
{
FileStream stream;
if(ResourceManager->openFileForWrite(stream, mGFTFile))
{
write(stream);
stream.close();
}
}...then deleting it and recompiling didn't have any effect. The font still won't appear when it's not installed on the system, only this time no UFT file at all is created.
#6
It's failing to load the cached fonts. Since the fonts will render properly when installed in the system, this means it can load and render then into memory properly, but somehow aren't being saved properly, generating bogus cached files.
I couldn't get PNG-exported fonts to load either, but I only did a superficial test on that.
02/15/2006 (11:23 am)
Same thing here. Are you sure that's all it's needed to do to fix that? If I call dumpFontCacheStatus() in the console, I get some nice "couldn't load font XXXXX" for the fonts that are not rendering. It's failing to load the cached fonts. Since the fonts will render properly when installed in the system, this means it can load and render then into memory properly, but somehow aren't being saved properly, generating bogus cached files.
I couldn't get PNG-exported fonts to load either, but I only did a superficial test on that.
#7
-", which is the result of a failed ATSFontFindFromName or FMGetFontFromATSFontRef call.
02/15/2006 (12:16 pm)
For me, it looks like it fails during MacCarbFont::create. The error I get in the console log is "Error: Could not load font -
#8
I don't know much about the new font system, but should't it try to load the stream as the new type GFont instead of a GOldFont? I'll check the cache writing, to see if how it's saving the cache.
02/16/2006 (8:38 am)
I am debugging through it. In windows, the font fails to load in constructFont():ResourceInstance* constructFont(Stream& stream)
{
GOldFont *ret = new GOldFont;
if(!ret->read(stream))
{
delete ret;
return NULL;
}
return ret;
}I don't know much about the new font system, but should't it try to load the stream as the new type GFont instead of a GOldFont? I'll check the cache writing, to see if how it's saving the cache.
#9
(I removed the code changes from this post, since it was a hack and broke other things, read the rest of the thread to find the proper fix).
No need to comment out that IF in the GFont destructor. Now it'll correctly load the cached font if the system font isn't present.
But I noticed that the fonts in 1.4 are not loaded all at once like 1.3. It creates the character bitmaps as needed on the fly, and then writes the cache to disk if new files were added. So now we need to make sure all characters we want to use are cached before distributing the cached font files. There is an article in the TDN about the console functions regarding that.
02/16/2006 (8:49 am)
Ha! Fixed it!(I removed the code changes from this post, since it was a hack and broke other things, read the rest of the thread to find the proper fix).
No need to comment out that IF in the GFont destructor. Now it'll correctly load the cached font if the system font isn't present.
But I noticed that the fonts in 1.4 are not loaded all at once like 1.3. It creates the character bitmaps as needed on the fly, and then writes the cache to disk if new files were added. So now we need to make sure all characters we want to use are cached before distributing the cached font files. There is an article in the TDN about the console functions regarding that.
#10
The font does load if it's not installed. But you're right, when the cache file is created, only the characters that have been used thus far are saved into the file. So when it's loaded, you don't get the full character set.
I'll check out those functions in TDN. Thanks for the sleuthing work. I still can't figure out where constructFont gets called from, though...
02/16/2006 (9:10 am)
You're right, that seems to have fixed it, to a degree.The font does load if it's not installed. But you're right, when the cache file is created, only the characters that have been used thus far are saved into the file. So when it's loaded, you don't get the full character set.
I'll check out those functions in TDN. Thanks for the sleuthing work. I still can't figure out where constructFont gets called from, though...
#11
Looks like this problem is fixed. With your correction, all you need to do is the following:
- for the fonts that you want to distribute with your game, get rid of any cached files that have already been made
- install or activate the font in your system
- In script or in the console, call the populateFontCacheRange function for that fontFace and fontSize, using 0 and 128 for the range values to capture all characters for that font.
For instance:
Then when your game application quits, it will write all of the characters in the range to the cache file, in that fontFace, at that fontSize. So in that example I'd have all characters available in TimesNewRoman at 12 point.
The command will probably give a few errors for invalid characters, but it's not a problem.
Then just repeat that with any other fonts you will need. Now your cached files can be distributed and used!
EDIT: the 0 and 128 values for the function call apply only to English, per the Torque Unicode document on TDN.
02/16/2006 (9:36 am)
Manoel, you rock.Looks like this problem is fixed. With your correction, all you need to do is the following:
- for the fonts that you want to distribute with your game, get rid of any cached files that have already been made
- install or activate the font in your system
- In script or in the console, call the populateFontCacheRange function for that fontFace and fontSize, using 0 and 128 for the range values to capture all characters for that font.
For instance:
populateFontCacheRange("TimesNewRoman", 12, 0, 128);Then when your game application quits, it will write all of the characters in the range to the cache file, in that fontFace, at that fontSize. So in that example I'd have all characters available in TimesNewRoman at 12 point.
The command will probably give a few errors for invalid characters, but it's not a problem.
Then just repeat that with any other fonts you will need. Now your cached files can be distributed and used!
EDIT: the 0 and 128 values for the function call apply only to English, per the Torque Unicode document on TDN.
#12
I looked around with more care, and noticed that fix was wrong... or sort of hacky. UFT files are "new font" files. GFT are "old font" files. I hacked the old font loading method to load new fonts. That did the trick, but that wasn't the true problem.
The problem is here, in initLibraries() inside main.cc:
That is associatng the UTF extension with the old font loading code. I looked around and found that constructNewFont does exist, but wasn't associated to any filetype. So I changed it to associate the proper extensions to the correct contruction functions:
That fixes the cache loading problem without breaking the console font/input.
BTW, you can also use populateAllFontCacheRange(start, end) to populate all fonts.
There's also populateAllFontCacheString() and populateFontCacheString(), that will populate the font with the characters you supply in a string. This is a good way to cache only the characters you need.
If you're using the localization system, you can feed all your strings into that and cache only the relevant fonts. This helps a lot if you're dealing with double-byte languages like Chinese and Japanese. Instead of caching *all* ideograms into a massive font file, for all fonts you use, cache only the ones you need for your GUI and in-game text, and use a non-cached system-font for user-input text.
Now all that is left is to learn how to properly export/import PNG files, and do fancy special effects on the fonts... it would be nice to store color instead of only alpha in the fonts. I'd love to use some outlined/drop-shadow'ed fonts.
02/16/2006 (10:52 am)
I just noticed it introduced a few bugs. I can't input some characters, and my console window is empty. D'oh!I looked around with more care, and noticed that fix was wrong... or sort of hacky. UFT files are "new font" files. GFT are "old font" files. I hacked the old font loading method to load new fonts. That did the trick, but that wasn't the true problem.
The problem is here, in initLibraries() inside main.cc:
ResourceManager->registerExtension(".uft", constructFont);That is associatng the UTF extension with the old font loading code. I looked around and found that constructNewFont does exist, but wasn't associated to any filetype. So I changed it to associate the proper extensions to the correct contruction functions:
ResourceManager->registerExtension(".uft", constructNewFont);
ResourceManager->registerExtension(".gft", constructFont);That fixes the cache loading problem without breaking the console font/input.
BTW, you can also use populateAllFontCacheRange(start, end) to populate all fonts.
There's also populateAllFontCacheString() and populateFontCacheString(), that will populate the font with the characters you supply in a string. This is a good way to cache only the characters you need.
If you're using the localization system, you can feed all your strings into that and cache only the relevant fonts. This helps a lot if you're dealing with double-byte languages like Chinese and Japanese. Instead of caching *all* ideograms into a massive font file, for all fonts you use, cache only the ones you need for your GUI and in-game text, and use a non-cached system-font for user-input text.
Now all that is left is to learn how to properly export/import PNG files, and do fancy special effects on the fonts... it would be nice to store color instead of only alpha in the fonts. I'd love to use some outlined/drop-shadow'ed fonts.
#13
I also noted some problems with not being able to enter some characters in the console after using your previous fix, but I figured it was because the font used in the console (Arial, by default) hadn't cached all the characters previously. So I trashed all of my cached font files, reloaded the app, and all the characters worked again.
But obviously, that's not important now since it sounds like you found the right fix.
I was going to suggest using populateFontCacheString(), although it didn't make sense unless you know you're only going to use a subset of characters. But like you said, it's good for double-byte languages.
Thanks for checking this out!
02/16/2006 (11:08 am)
You're right, I saw the registerExtension statement and I totally missed that it was associating UFTs with the old font loading code. Nice catch!I also noted some problems with not being able to enter some characters in the console after using your previous fix, but I figured it was because the font used in the console (Arial, by default) hadn't cached all the characters previously. So I trashed all of my cached font files, reloaded the app, and all the characters worked again.
But obviously, that's not important now since it sounds like you found the right fix.
I was going to suggest using populateFontCacheString(), although it didn't make sense unless you know you're only going to use a subset of characters. But like you said, it's good for double-byte languages.
Thanks for checking this out!
#15
03/09/2006 (10:00 am)
You need both Ben's fix and this fix. Just FYI.
#16
03/09/2006 (10:53 am)
What does Ben's fix add? Seems to be working well without it.
#17
Please correct me if I am wrong
-Ron
03/13/2006 (7:13 pm)
A bit late getting into this thread, but how does Ben's fix apply to GFont? from reading the code the only way his fix would apply is if one uses GOldFont, which if you use the corect construct for registering the extension will never occure.Please correct me if I am wrong
-Ron
#18
I pushed this change to CVS a few days ago (the constructNewFont one)
-Ron
03/15/2006 (4:48 pm)
FYI,I pushed this change to CVS a few days ago (the constructNewFont one)
-Ron
#19
03/15/2006 (4:59 pm)
The reason I mention you need Ben's fix in addition to the registerExtension fix is because I was having an issue, on the machine I'm working with here, where it would sometimes decide to destroy the cached font. Commenting out the code Ben mentions in the destructor fixed this issue.
#20
03/15/2006 (5:33 pm)
Thanks for the heads up.
Associate Ben Garney
Lemme know if this helps!