SFML community forums
General => General discussions => Topic started by: Laurent on December 13, 2009, 04:51:12 pm
-
Hi
I've written a new implementation for sf::Font in SFML 2, in order to make it more flexible :
- no more need for a fixed character set (glyphs are loaded dynamically on demand)
- no more need for a fixed size (all the requested sizes are handled in a single font)
- proper handling of kerning
- proper handling of line spacing
This should normally have almost no effect on text rendering (once glyphs are in the cache, it works basically the same as before), the only major impact that I can see is an increase in the number of glyph textures produced.
I need the usual feedback : does it crash, is it slow, do you like it, etc. :)
Thanks
-
I did few basic tests to see if new font implementation is more convenient and faster. I used this code for old sf::Font class: http://paste-it.net/public/qe854f8/ and this for new one: http://paste-it.net/public/r0a9e21/
The results are:
Old sf::Font without styles:
(http://img69.imageshack.us/img69/1761/oldnostyles.th.png) (http://img69.imageshack.us/i/oldnostyles.png/)
FPS: 390-400
Old sf::Font with styles:
(http://img51.imageshack.us/img51/1706/oldwithstyles.th.png) (http://img51.imageshack.us/i/oldwithstyles.png/)
FPS: 100-110
New sf::Font without styles:
(http://img51.imageshack.us/img51/5174/newnostyles.th.png) (http://img51.imageshack.us/i/newnostyles.png/)
FPS: 330-340
New sf::Font with styles:
(http://img51.imageshack.us/img51/281/newwithstyles.th.png) (http://img51.imageshack.us/i/newwithstyles.png/)
FPS: 90-100
In overall:
+ Higher quality of font
+ Kerning
+ Don't need bother about charsets (easier translations)
- Some issues while displaying text with small rotation
- Slower rendering
Questions:
- Why underline is more transparent then font itself.
- Why text with styles is brighter (have invalid colour)
I didn't check how will be displayed small fonts. Which is also very important.
Good job Laurent!
-
Hi
Thanks a lot for doing these tests, I apreciate :)
- Slower rendering
This is not supposed to happen, I'll do some tests to figure out what's wrong.
- Why underline is more transparent then font itself.
- Why text with styles is brighter (have invalid colour)
This is because of the Bold style. It is currently implemented by rendering 4 times the text with a slight offset in all directions. It results in an incorrect color when alpha is used. Underline is not impacted because it is drawn once even in bold style.
I'm currently not very happy with the way styles are implemented, I'll see if I can find a better solution.
- Some issues while displaying text with small rotation
2D rendering (especially pixels with integer coordinates) and 1 degree rotations are usually not friends ;)
-
I did some tests, and on my machine the kerning calculation is the piece of code that slows the thing down compared to the old version.
Can you deactivate it and try again? To do so, comment the line 246 in src/SFML/Graphics/Text.cpp.
-
Yep, I uncommented that line and font rendering is even faster then in old version! FPS: 400-410, 90-100. But there is small glitch when rendering with styles, without kerning:
(http://img704.imageshack.us/img704/4880/glitch.th.png) (http://img704.imageshack.us/i/glitch.png/)
After look at 2 letters: VA, I really don't know if kerning is disabled or not, but line is of course uncommented.
-
But there is small glitch when rendering with styles, without kerning:
This is because I didn't make you comment all the lines involving kerning.
So again, the bold style is messing things up :)
After look at 2 letters: VA, I really don't know if kerning is disabled or not
You can see that the difference between bold and regular becomes noticeable after the "AV" pair, so yes it is properly disabled on your screenshot.
I'll try to optimize kerning calculations, thanks for your help :)
I may require your help to test the results, because my machine is too fast to make relevant benchmarks.
-
Actually I need you to test one more thing before trying to optimize.
The code to modify is in Font::GetKerning (src/SFML/Graphics/Font.cpp - line 173).
1. First test: replace these lines
FT_UInt index1 = FT_Get_Char_Index(face, first);
FT_UInt index2 = FT_Get_Char_Index(face, second);
with these ones
FT_UInt index1 = 54;
FT_UInt index2 = 62;
2. Second test: restore the code you modified in test 1, and replace these lines
FT_Vector kerning;
FT_Get_Kerning(face, index1, index2, FT_KERNING_DEFAULT, &kerning);
// Return the X advance
return kerning.x >> 6;
with these ones
return 0;
And then tell me if it is FT_Get_Char_Index, FT_Get_Kerning or both that impact performances :)
I found that both impact equally the performances, but like I said it's not very convenient to test at 1000+ FPS.
-
But do these tests with disabled line 246 in src/SFML/Graphics/Text.cpp?
-
No, uncomment it. Now we're diving deeper into the kerning code ;)
-
Test 1:
FPS: 380-390 , no changes at all...
Test 2:
FPS: ~410... so there are small changes.
-
Ok I see. So the expensive call is FT_Get_Kerning actually.
Unfortunately, it will be hard to optimize (if not impossible). Kerning informations involve a pair of two characters, which makes way too many combinations to even think about caching it.
-
I think it's not worth to optimize that thing. If I were you I'd focus on better implementation of styles. Because now they are slow and little buggy. And justify feature would be nice :D
-
I completely agree with that ;)
Except the justify feature. I understand that it is impossible to implement externally, but for now this kind of feature is not planned. But maybe one day. The next thing I'll implement will be different text directions (right-to-left, top-to-bottom, etc.).
-
17. Is it possible to perform styling (like oblique, italic, bold,
underline, etc.) with FreeType?
Actually, these refer to very different things:
- Italic and Bold styles usually mean many variations from the
'Regular' font. This is why you normally need a proper font
file for each of these. For example, the MS core font Times
comes in the following TrueType files:
TIMES.TTF Times New Roman Regular
TIMESI.TTF Times New Roman Italic
TIMESB.TTF Times New Roman Bold
TIMESBI.TTF Times New Roman Bold Italic
(sometimes named TIMESZ.TTF)
With FreeType, you simply need the required font file to use it.
- Oblique style refers to a transformation that is applied to a
regular font in order to make it 'slanted', likes italics do.
However, an italic font very frequently contains small but
important variations that cannot be produced by this method and
make the font more appealing.
Slanting can easily be done with a transformation under
FreeType, with the exact same process as rendering rotated text.
Please read the "glyphs" documentation file where it is
explained in details.
Usually, Windows or the Macintosh produce oblique versions of a
regular font when the corresponding italic TrueType file isn't
available. They also stretch horizontally regular fonts when
the bold one isn't available. All of this can be done with
trivial transformations.
- Underlining and stroking, are not really part of the glyphs.
They're simply lines that are printed on the glyph after it has
been rendered. Each TrueType file provides, in its OS/2 table,
which is accessible through the face object properties in
FreeType, several values that define the position and width of
those lines, in notional font units.
If you want to use them, you'll have to scale these values to
your current instance/point size, then draw the lines yourself.
I really didn't know that there is no support for making bold, italic and underline font faces in freetype 2 library. Now, after some look at your code I finally understand why you use such tricks to render proper text. It would be difficult to do further optimizations in the source code. But I suggest you mentioning in documentation to use specific font files if possible (Arial Bold, Arial Italic) instead of using sf::Text::Style.
-
Even if it was directly provided by FreeType, I probably wouldn't use it anyway. Storing 8 versions (every possible combination of styles) of each glyph would consume too much video memory.
About my plans for improvement:
- italic is ok, the rendering is perfect and involves no extra performance cost
- underline is ok too, it could just be more accurate by requesting the proper offset/thickness values from the font
- bold is clearly too heavy to render and too ugly, I think I can find a better "algorithm"
But I suggest you mentioning in documentation to use specific font files if possible (Arial Bold, Arial Italic) instead of using sf::Text::Style.
Absolutely, I'll do it when I rewrite the sf::Text documentation.
-
I fixed Bold and Underlined styles. It's much much better now ;)
And actually FreeType provides functions for bold (FT_Outline_Embold and FT_Bitmap_Embold -- for fonts not supporting vector outlines) that can be used to generate the bold version of a glyph. So the bold style is no longer faked, it is generated and added to the glyphs texture.
-
That's a great news. I did few tests with different sizes of displayed fonts and styles, and results are really good. Only few FPS lower with styled text. That's how font class should look like form the beginning (I know it wasn't possible ;)). One question although..
What about memory management? I really didn't look at the code. I would spend a lot of time to understand all the concepts, so question is much more convenient.
For example if I use one font, display text size 10 and then use size 50 I bet glyphs are rendered only if I exceed last maximum size? Last one: rendered bold and regular glyphs are held separately?
What are your next plans for sf::String, sf::Text, sf::Font classes ;D?
-
For example if I use one font, display text size 10 and then use size 50 I bet glyphs are rendered only if I exceed last maximum size?
No, actually the glyphs are rendered at every requested size. Scaling down a glyph is nearly as ugly as scaling it up ;)
So in this case you will end up with two textures: one containing the glyphs at size 10, and the other for size 50.
If this texture management causes problems, I can add functions to have more control over it (Clear(size), Preload(string, size), etc.). I'll just wait for "real situations" feedback ;)
Last one: rendered bold and regular glyphs are held separately?
Absolutely. A bold character produces a new glyph, even if the non-bold character is already loaded.
What are your next plans for sf::String, sf::Text, sf::Font classes ;D?
- sf::String: waiting for more feedback or better ideas; I'm not really satisfied with the current implementation but it will probably stay like that for now
- sf::Text: I'm going to implement text directions (right-to-left, top-to-bottom, etc.)
- sf::Font: I read two excellent articles about text rendering, and tried to improve the text quality in my implementation but I failed so far. I'm also waiting for feedback, but I'm pretty satisfied with the current implementation. It can be optimized regarding texture usage, but I need to tweak sf::Image to do so.
-
No, actually the glyphs are rendered at every requested size.
So it's nicely done trap ;) For example user want to do effect which looks like:
text.SetCharacterSize((frames%100)/100);
And then... oops. My linux suspended in few seconds. No one knows what's going on :) The problem is that this function looks like a "scaling" one. In SFML 1 i used it a lot (but had a different name I think) so others also can misunderstand its meaning.
According to sf::String I will test it for a longer time and say something about it.
-
Absolutely, and that's why:
- SetCharacterSize now takes an unsigned int instead of a float (it no longer looks like a scale)
- The documentation and tutorials will strongly encourage to use SetScale to scale text :)
-
Is there still a default font?
-
Of course, and there will still be a default font regardless of the way sf::Font is implemented, because I embed the Arial.ttf file directly in the source code and use LoadFromMemory.
-
Of course, and there will still be a default font regardless of the way sf::Font is implemented, because I embed the Arial.ttf file directly in the source code and use LoadFromMemory.
Ok, I just had a problem but it was related to the fact that I had a shader program loaded while trying to render stuff ;)