jME-TrueTypeFont Rendering Library

Ah, ok thanks. I have never updated jme3 because I didn’t realise that you had to do it manually. I will do that now.

EDIT: Yep, it worked I am now able to load ttf to my guiNode. Thanks @Tryder :grinning:

No problem JDC, I didn’t realize that method was unavailable in 3.0 myself. Can’t say I’ve really found any issues with jME 3.1 so I wouldn’t worry too much about it being listed as Beta as it’s at least as stable as 3.0.

Yeah, I’ve been messing around with it for the last 30 mins and it seems stable.

Is there currently any implemented way to use this library with lemur?. I’ve seen the whole post and the lemur-dynamo project but it seems to not work with the latest version (2.0.0, from jcenter).

1 Like

I prefer to use bitfont generators to generate fonts to use with native GUI of jME.

I have not yet updated Lemur Dynamo to work with the latest version of jme-ttf. If I recall an older version of this library is available on my website http://1337atr.weebly.com/jttf.html and that version is compatible with Lemur Dynamo.

I would recommend, though, loading up the Lemur Dynamo source in your IDE of choice with jme-ttf 2.0.0 and fixing whatever errors pop up. Shouldn’t be too hard as there weren’t a hole lot of changes, everything still essentially works the same, but some methods and classes were renamed and moved around.

Looks like electricity is going to be a bit scarce for the foreseeable future. My power will be provided through a portable 21 watt solar charger and 20,000mAh power bank. Hoping to double up on that with a second set, but we’ll see. Anyway I’ll be limited to a Windows tablet as far as computing goes because my laptop is not at all power efficient and can’t be USB charged anyway. So it may be a while until I can get Lemur Dynamo updated myself.

1 Like

if the tablet supports usb OTG+hub you are good to go with a normal keyboard and mouse! compiling times, memory and IDE usage speed , may be a problem tho I guess.

here I stuck my cellphone on a “wired arm” (I like playing with wires) affixed it on my desk, just in front of my face it got positioned so to have big enough to read letters, and I used it as a monitor for some time thru NoMachine :> (the arm is still here in case I need it, with also a small cpu fan on it to cool my head xD)

1 Like

It’s a MicroCenter Winbook TW801, MicroCenter is an electronics store we have here in the US midwest. For the most part it’s a small windows computer, quad core 1.4Ghz Intel Atom, 2gb memory, 32gb emmc internal storage (Windows takes up like 20gb of that), 8" touchscreen, Windows 8.1 (not upgrading to 10), microSD card reader, one micro USB port (for charging) and one full size USB 3.0 port.

The full size USB 3.0 port comes in handy. I have a 4 port USB 3.0 hub plugged into it which hosts a mouse, a wireless logitech keyboard and occasionally an external hard drive. Up until now my girlfriend sometimes used it, but really it’s just been sitting round not doing much. I put Eclipse, Blender and GIMP on it and probably get jME up and running here when I have a moment.

Unfortunately once my girlfriend was listening to music on it via headphones and dropped it right on the headphone port which jammed her headphone connector into the tablet ripping the headphone port off the motherboard so now neither the headphone port or built in speakers work, other than that it’s pretty good as far as Windows tablets go.

I’d greatly rather use Linux, but it is what it is I guess. This uses a 32bit efi boot loader so GNU/Linux can be tricky to get running. I was able to get Ubuntu working on this, but not well enough to be viable. The WIFI didn’t work and neither did the microSD card reader. If the tablet went to sleep, either via idle or lock/power button press, it couldn’t wake back up.

One interesting thing was the screen. The touch screen worked and when I installed Lubuntu I could get the screen to rotate from portrait to landscape and back again via an xrandr command. xrandr -q indicated the output device as “DSI-1” and I could just rotate that via the xrandr --rotate command. To cement the installation process in my head I decided to re-install Ubuntu this time using Xubuntu. When I got it all up and running I could no longer rotate the screen, xrandr -q just said the output device was “default” and attempting to rotate it just said that rotation was not supported by the device. After fiddling with config files and whatnot I decided to re-install Lubuntu and had the same results, meaning it still didn’t work. I have no idea what, if anything, I did different the first time.

I tested my solar panel for the second time today, it’s an Anker 21 watt. The first time I tested it the weather was completely overcast, I didn’t even have a shadow, and it produced 5 watts on average. Today was beautiful and lightly cloudy so for the first two hours it produced 15 watts and the second hour and a half it produced 20 watts. On a day like today it should take 6-7 hours to charge my power bank from 0-100%, on an overcast day I could probably charge it from 0-25% in that same time period. Of course on a rainy day I’ll just be twiddling my thumbs.

I also have a BioLite CampStove which is a nifty little invention. It’s a portable wood burning stove that has a built in 2400mAh, if memory serves, battery that it charges using the heat produced from the fire. The battery is mainly for powering a small fan that feeds oxygen to the fire, but can also be used to charge a single USB device. It would take a good while to charge a cell phone with it as it will occasionally stop charging a connected device to charge itself up so it can continue powering the fan, but I imagine it would be quite useful in a pinch. As far as cooking food on it, wonderfully useful.

1 Like

have u considered a small wind turbine? 24h of power (I guess you could even manually spin it in a calm night, just attach a bike on it in some way hehe)

1 Like

Indeed there are instructions on making homemade bicycle generators on the internet. I might look into that later at some point, but something like that might be too heavy. My girlfriend and I will be traveling the country on bicycles so we’re limited on space and weight. The rear racks on our bikes are rated for a maximum of 55lbs and the front low rider racks max out at 25lbs. As you can imagine most of that space is going to camping equipment, food and clothing. Luckily our electronics don’t take up much space or weigh a whole lot.

We have two phones, an Android BLU Life One(2015) and an iPhone 5. Also the Winbook and a freebie Android tablet. We also picked up a four port eight amp USB wall charger so we can supplement with the occasional charge up at coffee shops and just ordered a second Anker solar charger and power bank.

Also ordered a Lifestraw water filter and a tub of activated carbon. The Lifestraw is bad ass, filters out 99.99% of bacteria, protozoa and viruses and lasts for over 4,700 gallons, 18,000 liters, of water. The activated carbon is the same stuff they use in commercial filters, like Brita or Zero Water, to remove chemical toxins.

Full on off the grid :wink:

P.S. I don’t really like the assholes you have to work for in order to make a living so I choose not to work for them.

2 Likes

Okay so my girlfriend and I have cycled a good 350-400 miles around the country over the last month and a half and I finally got around to updating Lemur Dynamo to beta 17 which adds support for the latest version of jme-ttf! I’m not going to go into a whole lot of detail right now, but check out the loadFont and loadMeshFont methods in the GuiGlobals class to see how to load true type fonts. The loadFont methods will load a true type font that will be displayed using textures, like traditional bitmap fonts, while the loadMeshFont methods will load a true type font that will display each character by creating a mesh shaped like the character to display. If you’re using Groovy styles then you’ll want to use the font and mfont methods respectively.

Unless you’re using large point sizes I wouldn’t recommend using mesh fonts for 2D UIs, but they should be great for 3D UIs due to their scalability, especially with anti-aliasing enabled.

The link the Lemur Dynamo download is buried somewhere in this thread so I’ll post it again: https://drive.google.com/file/d/0B6BscJ4Cq-K7ZUlJakxKZFRiTGs/view?usp=sharing

P.S. We’ve had plenty of sunlight so our two 20 watt solar chargers have had no trouble keeping our stuff charged up. My Android phone has only dropped below 50% once that I can remember. Just haven’t had a whole lot of time to code since I’ve been spending a lot of time cycling, filtering water, chopping wood, etc…

5 Likes

I just updated jME-TTF to fix a bug that would cause a crash when using clipped word or char wrapping in conjunction with an ellipsis and a StringContainer that is too narrow to display any text including the ellipsis. Unfortunately I am not able to update the jCenter package at this time so you’ll need to pick up the updated version from my web site 1337atr.weebly.com/jttf.html.

3 Likes

jME-TTF has been updated to v2b. I noticed with smaller fonts UV rounding errors can cause a little sliver from an adjacent character in the atlas to be displayed. I increased the amount of padding around characters in the atlas from 4 pixels to 10 and that seemed to correct the issue. Also added some preprocessor directives to some of the shaders to better handle GLES devices. Again I have not yet updated the jCenter version of this so you’ll need to visit http://1337atr.weebly.com/jttf.html to get these updates.

Additionally I started working on Lemur Dynamo to add the ability to use custom materials with your text:

It’s not ready yet, the battery on this thing only holds a two hour charge. Plus it drains while it’s off, I often start up with only 60% charge remaining even after fully charging during the previous use. Hopefully I’ll be able to get a new device at some point.

4 Likes

jME-TTF is now up to version 2.1 which improves performance a bit by adding the ability to specify a string of characters to initialize a font with on the Constructor or via a TrueTypeKey. Previously the texture atlas for non-mesh fonts was initialized with the default glyph, this initial texture was imediately thrown away when more characters were added to the atlas. Now characters supplied to the constructor will be added to that initial texture atlas eliminating the need to destroy the initial atlas.

For instance you can now load all your characters into the font during construction and then lock the font to prevent any new characters from being added which, in the case of TrueTypeBMP, will prevent the texture from being regenerated:

String preload = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            + "abcdefghijklmnopqrstuvwxyz"
            + "0123456789!@#$%^&*()-_+=*/"
            + "\\:;\"<>,.?{}[]|`~'";
TrueTypeBMP ttf = (TrueTypeBMP)assets.loadAsset(
        new TrueTypeKeyBMP("fonts/myfont.ttf", Style.Plain, 24, 0, 72, false,
        preload));
ttf.lock(true);

The latest version of jME-TTF is available on jCenter:
groupId: com.atr
artifactId: jme-ttf
version: 2.1.0

3 Likes

Quick update to v2.11 which adds the ability to specify a maximum texture resolution for the texture atlas in the constructor and removes DirectByteBuffer destruction from instances of TrueTypeSfntly running on Android. This is available on my site and jCenter:

groupId: com.atr
artifactId: jme-ttf
version: 2.1.1

2 Likes

I added that wonderful library of yours in my pom.xml and the repository jcenter but I get the following error :
Missing artifact com.jaredrummler:sfntly:jar:1.+

<repositories>
    <repository>
        <id>jcenter</id>
        <url>http://jcenter.bintray.com</url>
    </repository>
</repositories>
 ...
 <dependency>
     <groupId>com.atr</groupId>
     <artifactId>jme-ttf</artifactId>
     <version>2.1.1</version>
     <type>pom</type>
</dependency>

Everything else is fine. I took the dependency from jcenter. Am I doing something wrong and is this the right place to post this?

There’s probably no “wrong” place to post this.

Anyway, when I first uploaded the library to jcenter I used the package in question as a dependency, perhaps the package is no longer available or I made a typo somewhere. At any rate the library I use for the sfntly dependency is available in the download on my website or search for the source code for Google’s Sfntly library and build your own.

2 Likes

Hi, @Tryder
Thanks for your hard work. I got some problems using jme-ttf-2.1.2.

Shader compatibility

I’m now using MacOS 10.14.5. OpenGL 4.1 Core profile. GLSL100 works not good on this machine.

I have to make some custom material to make your awesome lib work on Higher version of OpenGL.

.j3md modify:

    Technique {
        // - VertexShader GLSL100: Common/MatDefs/TTF/TTF_Bitmap.vert
        VertexShader GLSL100 GLSL150: MatDefs/TTF_Bitmap.vert
        // - FragmentShader GLSL100: Common/MatDefs/TTF/TTF_Bitmap.frag
        FragmentShader GLSL100 GLSL150: MatDefs/TTF_Bitmap.frag
        // ..
    }

.frag shader modify:

#import "Common/ShaderLib/GLSLCompat.glsllib"
//#ifdef GL_ES
//    precision mediump float;
//#endif

.vert modify:

#import "Common/ShaderLib/GLSLCompat.glsllib"

Can’t createAltas

I made a test case like below.

build.gradle

plugins {
    id 'java-library'
}

repositories {
    jcenter()
    maven {
        url  "https://dl.bintray.com/tryder/maven" 
    }
}

dependencies {
    implementation 'com.atr:jme-ttf:2.1.2'
    implementation 'org.jmonkeyengine:jme3-core:3.2.0-stable'
    implementation 'org.jmonkeyengine:jme3-desktop:3.2.0-stable'
    implementation 'org.jmonkeyengine:jme3-lwjgl:3.2.0-stable'
}

Main.java

package net.jmecn.font;

import com.atr.jme.font.TrueTypeFont;
import com.atr.jme.font.asset.TrueTypeKey;
import com.atr.jme.font.asset.TrueTypeKeyBMP;
import com.atr.jme.font.asset.TrueTypeLoader;
import com.atr.jme.font.shape.TrueTypeContainer;
import com.atr.jme.font.shape.TrueTypeNode;
import com.atr.jme.font.util.StringContainer;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.plugins.FileLocator;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;

/**
 * @title Main
 * @author yanmaoyuan
 * @date 2019-08-21
 * @version 1.0
 */
public class Main extends SimpleApplication {

    static String FONT = "fonts/Arial Unicode.ttf";

    static String CONTENT = "Hello world!";

    /**
     * @param args
     */
    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        flyCam.setMoveSpeed(100f);

        assetManager.registerLocator(".", FileLocator.class);
        assetManager.registerLoader(TrueTypeLoader.class, "ttf");
        
        // use customer shader.
        Material mat = new Material(assetManager, "MatDefs/TTF.j3md");
        mat.setColor("Color", ColorRGBA.White);

        TrueTypeKey key = new TrueTypeKeyBMP(FONT, 24);

        TrueTypeFont font = (TrueTypeFont)assetManager.loadAsset(key);

        StringContainer sc = new StringContainer(font, CONTENT);

        // test getFormattedText
        //TrueTypeContainer ttc = font.getFormattedText(sc, ColorRGBA.White);
        TrueTypeContainer ttc = font.getFormattedText(sc, mat);
        guiNode.attachChild(ttc);

        // test getText
        //TrueTypeNode text = font.getText(CONTENT, 1, ColorRGBA.White);
        TrueTypeNode text = font.getText(CONTENT, 1, mat);
        rootNode.attachChild(text);
    }

}

I found nothing on the screen, so I digged into the code.

Line 208 in com.atr.jme.font.TrueTypeBMP#getGlyphs(StringBuilder), the input param “text” is never used.

207    @Override
208    public T[] getGlyphs(StringBuilder text) {  // input param "text" is never used
209        T[] glyphs = (T[])new GlyphBMP[sb.length()];    // why use "sb" instead of "text"? 
210        LinkedList<CharToCreate> unCached = new LinkedList<CharToCreate>();    

Also, com.atr.jme.font.TrueTypeMesh#getGlyphs(StringBuilder), the input param “text” is never used.

So the atlas is not properly created.

Last question: is there any git repo we can contribute to?

1 Like

Oops, guess I missed where getGlyphs(StringBuilder) was referencing a member variable rather than the local variable. I uploaded the source to a new GitHub repository and fixed the getGlyphs bug. I have not yet updated the binary package available on my site.

4 Likes

Cool.

I also made a PR to fix shader compatibility.