Distance Field Fonts for jme3

Yeah, but I do kind of remember that the padding should be reflected in the bounds of each character… so it may be that BitmapText is broken in some other way.

Ah okay, didn’t know that. The outlines that you can make with the BMFont.exe from AngelCode himself weren’t cut off though. I don’t know the Hiero pipeline enough, so can’t tell what the problem is with distance fields cut off.

FYI - here’s the other routine. I had to resolve to use reflection to clone a BitmapFont instance properly:

/**
 * Create a clone (there is no clone mechanism in BitmapFont itself). This 
 * is variant 2: It also clones the BitmapCharacterSet, in addition to 
 * cloning the materials ("pages").
 * <br>
 * NOTE: This uses a dirty trick and may not work everywhere (Android?). It 
 * uses Java relfection to access a 'private' field of the BitmapFont class.
 * 
 * @param font the font that you want to clone
 * @return a complete clone with both materials and characerset cloned
 */
public static BitmapFont cloneFont2(BitmapFont font) {

    //protect from stupid input
    if(font == null) return null; 

    //create a clone by constructing a cloned BitmapFont manually
    BitmapFont clone = new BitmapFont();
    
    //can't clone BitmapCharacterSet
    //clone.setCharSet(font.getCharSet()); 
    
    //use dirty trick to access private field:
    BitmapCharacterSet orig = font.getCharSet();
    BitmapCharacterSet copy = new BitmapCharacterSet();
    IntMap<IntMap<BitmapCharacter>> styleMap;
    IntMap<BitmapCharacter> chars;
    Field styleMapField;
    try { 
        styleMapField = BitmapCharacterSet.class.getDeclaredField("characters"); 
        styleMapField.setAccessible(true);
        styleMap = (IntMap<IntMap<BitmapCharacter>>)styleMapField.get(orig);
    }
    catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex){
        throw new AssertionError();
    }
    chars = styleMap.get(0);
    for(Entry<BitmapCharacter> entry : chars) {
        copy.addCharacter(entry.getKey(), entry.getValue().clone());
    }
    clone.setCharSet(copy);
    
    //clone the material (textures and shader settings)
    Material[] pageClones = new Material[font.getPageSize()];
    for(int i = 0; i < pageClones.length; ++i) {
        pageClones[i] = font.getPage(i).clone();
    }
    clone.setPages(pageClones);

    //return the clone
    return clone;
}

I was working on my own GameFont-system though, which provided a wrapper to BitmapFont and other fonts I found in this forum and in my own garage - so maybe this whole thing may become resolved once this side-project nears completion… :smiley:

This is the conclusion I’ve been coming to over the last few months - for my experiments with SDF text I just swapped out the material of a BitmapText instance, but for other types of fonts (like vector fonts from a TTF) this doesn’t make a lot of sense.

I’d like to see a generic Text interface plus a common set of layout and glyph data classes. The render pipeline could look something like this:

Text interface implementation -> common layout engine -> mesh/rendering surface setup interface implementation (aligned quads, offscreen render buffer, etc) -> displayable node

Some parts of glyph data would likely need to be abstracted, however. Glyph width/height/etc. metrics should be able to stay in a common concrete class, but I’d imagine that there will be font implementations that need a data structure significantly different from bitmap font atlases.

@pspeed

Here is a simple test case that I put together:

Currently the first test case produces incorrect results.
In DFontLoader I fixed it, by subtracting padding up & padding down from lineheight & padding left and right from xadvance.

Neat. I don’t have time to look at the moment at what you’ve done but I hope to this weekend.

In the mean time, any chance of some screen shots of the tests ‘in action’?

Here is an image.

6 Likes

Ah, so you put the text in a separate window instead of rendering to a BufferedImage and sticking it on a quad.

That works, too.

1 Like

Just looked into a font that has outline around glyphs. There the padding is all zero. So, it seems that for distance fields it’s somehow needed. One might start looking in other implementations what they do with this info - I guess the libgdx ecosystem/biotope uses them? But your solution (adding to xadvance) seems to work for you? Nice.

I think I rember what “padding” is for: Mip-mapping
It may prevent the glyphs from bleeding to other glyphs. Seems a logical explanation to me.
I once looked into the code of AngelCode BMFont.exe, remember vaguely some distance between the glyphs was created for no reason, but don’t remember exactly. Everybody can look into his code though (http://www.angelcode.com/products/bmfont/ - see “Source Code”)

I still wonder, why that Hiero-tool doesn’t account for the larger glyphs - I guess it’s because those are invisible parts of a glyph and AngelCode .fnt was never intended for such thing. As I understand, distance fields are additional pixels outside the visible glyph pixels. This might be what confuses this system and what it wasn’t designed for.

I’ve tried modifying this to be a test case in the JME test suite… the issue is that I don’t have the TTF files for the fonts you are using and so can’t load them.

Are they free fonts? Can you provide the original font files from which these Bitmapfonts were generated?

Thanks.

Edit: to be clear, run “as is”, this is what I see:

In the mean time, I can use some of my own fonts, I guess.

Yes, the fonts are FreeSerif,

Droid Sans Fallback:

Droid Sans Mono:

I used Hiero to generate the .fnt file.

Thanks. I shouldn’t need to regenerate the file but I can load the TTF directly in AWT to avoid having to require it be installed already.

For the FreeSerif font which TTF did you use, do you know? There are several in there and I don’t want to assume.

When I use the basic one, the AA is totally off but that could be the swing implementation I’m running on. I just want to be sure I’m starting from the same place.

I had to rewrite the test case because it wasn’t really going to do what I needed.

I’m getting closer:

The big problem is that the angel code font tool renders fonts differently than AWT does. “Bold” in AWT is bolder, etc… I may try to run it on a newer system to see if it’s related to my older dev machine. As it is, I’ve had to resort to strange tricks just to get them as close as they are.

Font rendering is like date/time math… it’s the kind of thing that makes you wonder how any code in the world ever works at all.

For all the fonts I used the defaults installed on a linux system.

For the free serif, I think it is this one:
link: www.fontspace.com/gnu-freefont/freeserif

Btw, (the angel font tool Hiero has 3 rendering modes: Ttf, Java & Native). There is a slight difference to the result if different mode is used. If you are not looking for pixel accuracy, as you said before, this shouldn’t be a problem.

BM Font is what I use or whatever. I’m not going for pixel accuracy but it would be nice if things laid out the same horizontally… which they don’t when AWT wants to bold things 90 pixels thick and BM font only bolded them 3 pixels thick.

I’m using Hiero now to generate some Java-rendered fonts.

What character set did you use for the japanese font? What other specific settings should I try for your other tests. I know one was using distance fields, etc… I want to make sure to have the same variety.

Now we are getting closer to a good test:

…and already I see some things to look into. Where JME versus Java starts the text seems to be different in an inconsistent way. (Java rendered text is dark gray background.)

A closeup:

The FreeSerif text in JME renders with some padding but the Java version renders right at x… on the other hand, the Japanese characters are exactly opposite. (Which is what I was seeing in one of my other fonts that I can’t find at the moment.)

Sizing the Java fonts to be the right ‘pixel’ size is difficult which is why there is a little expansion in the FreeSerif-32 example… but I think it’s probably close enough to debug kerning issues and so on.

Droid Sans Fallback:

With the Hiero you can set padding and spacing. Other than this, if kerning works too, that should be all.
Effects like distance fields, outlines etc, just modify the bitmap.

I’ve just remembered about sub-pixel rendering. If that is enabled in Java, that might also add to some differences you are seeing. (After reading a bit about it, not sure if its enabled by default in Swing)