Author Topic: TrueType font rendering  (Read 46382 times)

0 Members and 1 Guest are viewing this topic.

Offline m!m

  • 211
Re: TrueType font rendering
Yeah, that's also my impression.

I may tweak the glyph positioning a bit but I think everything else is pretty much covered. Are there any issues I missed? If not then this is pretty much ready to be merged (although antipodes and CMake need to be merged before this so it might take some time).

 

Offline Yarn

  • 210
Re: TrueType font rendering
There's definitely still work to be done:
  • Improve the way that special characters are handled. For instance, you may have noticed that, when TrueType fonts are in use, the monospace 1 used by some HUD gauges looks different from the other digits. Needless to say, this can be quite jarring. If the current font is a TrueType font, special characters should be rendered with that font if at all possible. For the monospace 1 and the match-speed icon, rendering tricks can be used; the other special characters can be remapped to certain Unicode characters.
  • Ensure that accented characters are supported properly. It appears that your code only allows characters whose byte values are less than the first special character's value but no less than 0 to be rendered with the TrueType font. This means that accented characters are always rendered with a VF font, making them look as jarring as the monospace 1 (see above). The best way to handle this is to relax what characters get deferred to the VF font and remap these non-ASCII characters to the appropriate Unicode characters. (And if NanoVG definitely does not support Unicode, then you're going to need to find a different TrueType library, or else full Unicode support will be impossible to implement!)

I think I know what techniques to use for rendering the monospace 1 and the match-speed icon; the question is whether those techniques are at all possible with NanoVG. I also know which Unicode characters can be used for the other special characters and the accented characters. (The ability to check whether a TrueType font has a particular character will be useful here but not required.) I'll post more on this later.
"Your fighter is running out of oil.  Please check under the hood and add more if necessary"
--strings.tbl, entry 177

"Freespace is very tired.  It is shutting down to get some rest."
--strings.tbl, entry 178

 

Offline m!m

  • 211
Re: TrueType font rendering
NanoVG has support for UTF-8 encoded Unicode codepoints so that will be no problem.

Full UTF-8 support would be great and I already implemented that in the past but there has to be a lot of special handling to make sure retail FSO isn't affected. Accented characters cause similar issues as NanoVG expects UTF-8 encoded strings but we can't supply those so those would need to be converted when the respective table files are parsed which could cause a lot of other issues.

In my opinion the best solution would be to make modders who use TrueType fonts aware of these limitations and that the behavior may change in the future when proper UTF-8 support is implemented.

 

Offline Yarn

  • 210
Re: TrueType font rendering
OK, so most of those things can wait until Unicode support is implemented. (And you can bet that I'll start that effort shortly after this gets committed to trunk. Just don't expect it to involve simply committing your UTF-8 branch as it is currently; there's still a ton of work to do there, and there's even a possibility that the end result won't use your code at all.)

At least we can look at the monospace 1 and the match-speed icon, which shouldn't require the use of Unicode characters. Before I suggest the full rendering techniques, I want to know whether these are possible:
  • Getting the width of a single TrueType character
  • Drawing a single TrueType character to the center (at least the horizontal center) of a small portion of the screen (these two tasks would be used to render the monospace 1)
  • Drawing a "negative" of a TrueType character--that is, drawing a small box that is completely filled in except for the actual character, just like how the match-speed icon looks (you can probably guess what this would be used for)
"Your fighter is running out of oil.  Please check under the hood and add more if necessary"
--strings.tbl, entry 177

"Freespace is very tired.  It is shutting down to get some rest."
--strings.tbl, entry 178

 

Offline m!m

  • 211
Re: TrueType font rendering
  • Easily possible by using the existing string measurement functions
  • I'm not exactly sure what you mean, text can be positioned freely so horizontal centering is trivial
  • Probably isn't possible without changes to NanoVG (it's possible to do that with normal paths but text is special). It's possible to just draw a rectangle and then draw the text with another color above that. It wouldn't be a "hole" but in most cases it would probably work fine.

Just to clarify, my UTF-8 changes only affected the string rendering and nothing else. It would probably break if you threw accented characters at it...

 

Offline Yarn

  • 210
Re: TrueType font rendering
I'm not exactly sure what you mean, text can be positioned freely so horizontal centering is trivial
As long as you can draw individual characters of a string anywhere you want, that's good.

Here's how I suggest handling the monospace 1 (I hope this is clear enough):
  • As FSO starts up, for each TrueType font, get the width of each of the digits 0-9, and store the width of the widest digit. Make sure you're storing a different width for each font, not a single width for all of them! This way, you will know how much horizontal space to give each digit when drawing strings that might have a monospace 1.
  • If a string is to use the monospace 1, it should not be passed to hud_num_make_mono, at least not initially. Instead, it should be passed to gr_string as-is along with a new flag indicating that the string should be drawn with monospace digits.
  • In gr_string/gr_opengl_string, if the aforementioned flag is passed, then exactly what to do depends on what kind of font is being used to render the string. If it's a VF font, then pass the string to hud_num_make_mono, and then draw the resulting string as normal. If it's TrueType, then draw each character individually in a space as wide as the width that you got during FSO initialization (and center the character in that space).
If you attempt this, make sure you take care of every use of hud_num_make_mono! That function is used in lots of places in the HUD code and once in stats.cpp.


Probably isn't possible without changes to NanoVG (it's possible to do that with normal paths but text is special). It's possible to just draw a rectangle and then draw the text with another color above that. It wouldn't be a "hole" but in most cases it would probably work fine.
Is it possible to get the rendered text image before it's rendered to the screen? If so, then you may be able to achieve this effect by inverting the alpha of each pixel of the image (along with maybe performing other operations on it).
"Your fighter is running out of oil.  Please check under the hood and add more if necessary"
--strings.tbl, entry 177

"Freespace is very tired.  It is shutting down to get some rest."
--strings.tbl, entry 178

 

Offline m!m

  • 211
Re: TrueType font rendering
As long as you can draw individual characters of a string anywhere you want, that's good.

Here's how I suggest handling the monospace 1 (I hope this is clear enough):
  • As FSO starts up, for each TrueType font, get the width of each of the digits 0-9, and store the width of the widest digit. Make sure you're storing a different width for each font, not a single width for all of them! This way, you will know how much horizontal space to give each digit when drawing strings that might have a monospace 1.
  • If a string is to use the monospace 1, it should not be passed to hud_num_make_mono, at least not initially. Instead, it should be passed to gr_string as-is along with a new flag indicating that the string should be drawn with monospace digits.
  • In gr_string/gr_opengl_string, if the aforementioned flag is passed, then exactly what to do depends on what kind of font is being used to render the string. If it's a VF font, then pass the string to hud_num_make_mono, and then draw the resulting string as normal. If it's TrueType, then draw each character individually in a space as wide as the width that you got during FSO initialization (and center the character in that space).
If you attempt this, make sure you take care of every use of hud_num_make_mono! That function is used in lots of places in the HUD code and once in stats.cpp.
Honestly, I don't see the point in introducing yet another code path for a feature that is barely noticed. It would be better to just ignore hud_num_make_mono when a TrueType font is set. If a modder wants to have a monospaced font in the HUD then they can just use another font and change the HUD gauges which should use that font.

Is it possible to get the rendered text image before it's rendered to the screen? If so, then you may be able to achieve this effect by inverting the alpha of each pixel of the image (along with maybe performing other operations on it).
It's possible but I don't think it's worth the effort, I think it would be better to either keep using the VF character or to paint the character in black above a rectangle. In most cases that would match how it's drawn currently and it wouldn't cause any performance penalties as the other solution would be drawing it to a framebuffer and then drawing the attached texture to the screen using a special shader.

 

Offline Yarn

  • 210
Re: TrueType font rendering
Honestly, I don't see the point in introducing yet another code path for a feature that is barely noticed. It would be better to just ignore hud_num_make_mono when a TrueType font is set. If a modder wants to have a monospaced font in the HUD then they can just use another font and change the HUD gauges which should use that font.
In that case, your idea should work well enough. At least the BankGothic MT TrueType font appears to use fixed-width digits, so there shouldn't be any problem with that. If there are any good TrueType editors (preferably free ones) that can adjust character widths, modders could use one of those if desired. (And it's probably better to just make hud_num_make_mono do nothing if a TrueType font is given.)

It's possible but I don't think it's worth the effort, I think it would be better to either keep using the VF character or to paint the character in black above a rectangle. In most cases that would match how it's drawn currently and it wouldn't cause any performance penalties as the other solution would be drawing it to a framebuffer and then drawing the attached texture to the screen using a special shader.
I say go ahead with your second idea (drawing a black character). I'm a little skeptical as to whether it will look right if the speed gauge is almost completely transparent (I know, very few players would configure their HUD this way, but still), but I'd still like to see how it will look.

If you implement this by checking whether a character is the match-speed icon, be sure to use compare using unsigned integers. If you don't, then you'll most likely hit the undefined behavior of signed integer overflow.


Just so you know, I will be away from tomorrow until Wednesday of next week, and I won't be able to do any testing during that time. After I return, I'm going to check whether your code works with the German and Polish versions of the game without TrueType fonts; we want them to work first before committing your code.
"Your fighter is running out of oil.  Please check under the hood and add more if necessary"
--strings.tbl, entry 177

"Freespace is very tired.  It is shutting down to get some rest."
--strings.tbl, entry 178

 

Offline m!m

  • 211
Re: TrueType font rendering
I changed hud_num_make_mono to only do something if the font is a Volition font.

The throttle gauge now draws a black 'm' above a rectangle if a true type font is used, it looks reasonably well but a custom HUD should probably use a bold font.

 

Offline Yarn

  • 210
Re: TrueType font rendering
The latest merge from your CMake branch is preventing embedfile.cpp from compiling, at least in Visual Studio 2013. I get 13 errors, all of which are identical to the following except for the line number:
Code: [Select]
C:\Games\FreeSpace2\fs2_open\asarium_ttf-nvg\tools\embedfile\embedfile.cpp(79): error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'const std::string' (or there is no acceptable conversion)

Readding the "#include <string>" line that you removed allows me to compile, as does removing the ".h" from "#include <string.h>".
"Your fighter is running out of oil.  Please check under the hood and add more if necessary"
--strings.tbl, entry 177

"Freespace is very tired.  It is shutting down to get some rest."
--strings.tbl, entry 178

 

Offline m!m

  • 211
Re: TrueType font rendering
I readded the <string> include, that should fix compilation with VS 2013.

 

Offline Yarn

  • 210
Re: TrueType font rendering
All right, I tested the things that I wanted to test so far.

Your fix for the monospaced 1 works well, as I expected. The TrueType match-speed icon also looks good. It does look taller than the VF version (most likely due to the TrueType font having more vertical space), but it can probably be left alone for now.

I also tested your code with the German and Polish data while setting the language in the registry accordingly. German seems to work fine, although I did get a generic "this program has stopped working" error once when loading a mission (and I can't seem to reproduce it). Polish works until I quit the game, at which point I get that generic error. Oddly, if I play in Polish without the Polish data, the game quits fine. I'll do some more testing to determine what exactly is triggering this error.
"Your fighter is running out of oil.  Please check under the hood and add more if necessary"
--strings.tbl, entry 177

"Freespace is very tired.  It is shutting down to get some rest."
--strings.tbl, entry 178

 

Offline m!m

  • 211
Re: TrueType font rendering
If you build a debug build with Visual Studio and run that you should be able to attach the debugger when the executable crashes. A stacktrace would be very useful to resolve this issue

 

Offline Yarn

  • 210
Re: TrueType font rendering
I've determined that the crash is being triggered by the Polish tstrings.tbl. I don't know yet whether any specific lines are causing it, though.

When I run the debugger, this is the error that I get:
Code: [Select]
Unhandled exception at 0x00B6153E in fs2_open_3_7_3-AVX-DEBUG.exe: 0xC0000005: Access violation reading location 0x04B71532.

And this is the stack trace:
Code: [Select]
fs2_open_3_7_3-AVX-DEBUG.exe!CheckBytes(unsigned char * pb, unsigned char bCheck, unsigned int nSize) Line 1696
fs2_open_3_7_3-AVX-DEBUG.exe!_free_dbg_nolock(void * pUserData, int nBlockUse) Line 1357
fs2_open_3_7_3-AVX-DEBUG.exe!_free_dbg(void * pUserData, int nBlockUse) Line 1265
fs2_open_3_7_3-AVX-DEBUG.exe!_vm_free(void * ptr, char * filename, int line) Line 1221
fs2_open_3_7_3-AVX-DEBUG.exe!lcl_xstr_close() Line 463
[External Code]
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]

EDIT: If you want to try reproducing this yourself, you can get the Polish data files at the bottom of this post: http://www.hard-light.net/forums/index.php?topic=85492.msg1709621#msg1709621. Make sure you change the game's language to Polish, or else the crash will not occur.
« Last Edit: August 11, 2015, 03:16:55 pm by Yarn »
"Your fighter is running out of oil.  Please check under the hood and add more if necessary"
--strings.tbl, entry 177

"Freespace is very tired.  It is shutting down to get some rest."
--strings.tbl, entry 178

 

Offline m!m

  • 211
Re: TrueType font rendering
:mad: I tried reproducing the crash but apparently it is Windows/Visual Studio specific (which is not surprising given the stacktrace).
I also tried running FSO through valgrind (a memory debugging tool) but that also didn't produce any results.

Can you try building and running a build from my 'cmake' branch? I want to know if this issue is specific to the TrueType stuff or if it was introduced with the cmake changes.

 

Offline Yarn

  • 210
Re: TrueType font rendering
The crash indeed happened in the CMake branch. Fortunately, your recent changes seem to have fixed the problem in both the CMake and TrueType branches. I'll do some more testing and see whether I find any more localization-related issues.

I've noticed that the TrueType font in your example mod is rendered a bit too low compared to the default VF font, in both the HUD and the menus, despite the fact that both fonts are the same size. I'm sure this is due to the TrueType font having more space above the letters for accents and such. While the HUD can be modified to better fit the font, the menus cannot. Thus, I think you should add a parameter that adjusts a font's Y offset. This parameter should affect all text rendered with that font as well as all boxes drawn behind it. (If it would make this simpler to implement, you could also allow VF fonts to take this parameter.)
"Your fighter is running out of oil.  Please check under the hood and add more if necessary"
--strings.tbl, entry 177

"Freespace is very tired.  It is shutting down to get some rest."
--strings.tbl, entry 178

 

Offline m!m

  • 211
Re: TrueType font rendering
There is an option to specify a top and bottom offset for fonts to artificially increase the line height. I'll have tot test of this properly handles negative numbers but in theory that should be enough to decrease the line height.

EDIT: It works well but "special" characters (e.g. the copyright symbol) are misplaced. I'll have to figure out a solution for that.
« Last Edit: August 13, 2015, 05:32:03 am by m!m »

 

Offline Yarn

  • 210
Re: TrueType font rendering
There is an option to specify a top and bottom offset for fonts to artificially increase the line height. I'll have tot test of this properly handles negative numbers but in theory that should be enough to decrease the line height.
Unfortunately, that probably won't be enough. Increasing the line height also increases the height of any boxes drawn behind the text, so simply decreasing the height can result in accents and such being drawn outside the boxes. Also, if the line height is decreased from only the top or bottom, then boxes could extend too far in one direction. (And no, reducing the line height from both the top and bottom isn't good enough either because doing so can cause accents to run into the line above.)
"Your fighter is running out of oil.  Please check under the hood and add more if necessary"
--strings.tbl, entry 177

"Freespace is very tired.  It is shutting down to get some rest."
--strings.tbl, entry 178

 

Offline m!m

  • 211
Re: TrueType font rendering
Well, accents are the whole reason why the box is too big. If a modder wants a version where the box isn't too big they will have to find a font where accented characters aren't bigger than the normal characters.

 

Offline Yarn

  • 210
Re: TrueType font rendering
I understand that, but I'm trying to say that changing +Top offset and +Bottom offset also affects the height of the box. Thus, setting +Top offset to a negative value and +Bottom offset to a positive value to fix the Y position of the text would also make the boxes off-centered, which wouldn't look good. This is why I think a new parameter should be added that adjusts the Y position of a font as well as any boxes drawn behind that font.
"Your fighter is running out of oil.  Please check under the hood and add more if necessary"
--strings.tbl, entry 177

"Freespace is very tired.  It is shutting down to get some rest."
--strings.tbl, entry 178