Hi there,
I am running into troubles with stb_truetype again when it comes to calculating string sizes. I have a very simple question and I am afraid of the answer since I guess it wont be the one I want:
Can I calculate the width of a String rendered with stb_truetype without actually rendering it?
I tried the following:
1) My first approach was to call stbtt_GetCodepointBox and stbtt_GetCodepointHMetrics for each code point and calculating the width and height of the glyph like this:
float glyphW = Math.max(Math.abs(x0 - x1), Math.abs(adv + lsb));
float glyphH = Math.max(Math.abs(y0 - y1), fontHeight);
with x0, x1, y0 and y1 taken from stbtt_GetCodepointBox and adv and lsb being the advance and the left side bearing from stbtt_GetCodepointHMetrics.
Then I calculated the size of a string by adding up the glyphW values for each code point in the String. This value was too large! It usually missed the mark by 5% ~ 20% depending on the contents of the String.
2) My second approach was to calculate the width of all glyphs the same way the rendering does and store the widths statically. I called stbtt_GetBakedQuad and calculated:
float glyphW = Math.abs(q.x0() - q.x1());
float glyphH = Math.max(Math.abs(q.y0() - q.y1()), fontHeight);
Again I calculated the width of a String by iterating over all code points and adding the glyphW values I previously calculated. This value was often (not always) too small!
So, is there a reliable and correct way to statically calculate the string size without keeping the stb data around after an initialization phase? Or do I need to call stbtt_GetBakedQuad (and keep the quad info) every time I want to know the size of a String?
Thank you all.
The correct approach has already been explained here (http://forum.lwjgl.org/index.php?topic=6565.msg34783#msg34783). What you're trying to do is unnecessarily complex, the only thing you need is stbtt_GetCodepointHMetrics and the advance value.
I have updated the Truetype demo in the LWJGL repository with some example code, here (https://github.com/LWJGL/lwjgl3/blob/776e8fef90564c2e80a368546551538cd74a7b31/modules/core/src/test/java/org/lwjgl/demo/stb/Truetype.java#L204). It does the following:
- Iterates the string's codepoints correctly (i.e. combines surrogate pairs), so works across the entire UTF-16 range.
- Uses stbtt_GetCodepointHMetrics to sum the codepoint advance values. (super simple)
- Uses stbtt_GetCodepointKernAdvance to adjust the advance value, for fonts with kerning information. (improves quality significantly)
All of the above can be precomputed/cached for performance.
If you can run the demo, press K to toggle kerning on/off and B to render a bounding box around each line (it should be tight around the text). Note that the included demo/FiraSans.ttf does not have kerning information. Change it to e.g. C:\Windows\Fonts\Arial.ttf to see how kerning works.
Also note how the line bounding box is adjusted with the descent value returned from stbtt_GetFontVMetrics.
This seems to be doing it, thank you very much!