playn

For PlayN, can someone provide a simple code example showing how to load a font file?


I'm looking for a simple example that loads a ttf file (in my case, Inconsolata.ttf) and creates a text layer.

Is it possible to do this in a platform-agnostic way? From this response here, I get the impression it is not.

I am working on a simple proof-of-concept using the TextDemo sample from the playn-samples showcase as a reference.

I'm presently a little confused on how to register the ttf file. Here's my code:

private void testCustomFont() {
    // text
    String text = "Hello, Cleveland!";

    // load font
    String fontName = "Inconsolata";
    Font.Style fontStyle = Font.Style.BOLD;
    Float fontSize = 24f;
    Font myFont = graphics().createFont(fontName, fontStyle, fontSize);

    // format text
    Integer fontColor = Color.rgb(0, 0, 255);
    TextFormat textFormat = new TextFormat().withFont(myFont).withTextColor(fontColor);

    // create font image layer
    ImageLayer textLayer = graphics().createImageLayer();
    TextLayout textLayout = graphics().layoutText(text, textFormat);
    CanvasImage textImage = graphics().createImage((int)Math.ceil(textLayout.width()), 
            (int)Math.ceil(textLayout.height()));
    textImage.canvas().drawText(textLayout, 0, 0);
    textLayer.setImage(textImage);


    // position text layer and add to root layer
    textLayer.setTranslation(20, 20);
    graphics().rootLayer().add(textLayer);
}

The projects is laid out like so:

/project
├── core
│   └── MyProject.java
└──  resources
    └──  fonts
         └──  Inconsolata.ttf

This displays the text but, as expected, not in the desired typeface.


Solution

  • Ideally, I would have like font-loading to have worked like image-loading with the asset manager:

    String fontPath = "fonts/Inconsolata.ttf";
    Font.Style fontStyle = Font.Style.BOLD;
    Float fontSize = 24f;
    Font myFont = assetManager().getFont(fontPath, fontStyle, fontSize);
    

    That wasn't possible, so I looked into doing something like this:

    private void registerFont() {
        if (platformType().equals(Platform.Type.JAVA)) {
            Platform platform = Platform.getJavaPlatformApi();
            platform.assets().setPathPrefix("com/klenwell/myproject/resources");
            platform.graphics().registerFont("Inconsolata", "fonts/Inconsolata.ttf");
        }
        else if (platformType().equals(Platform.Type.ANDROID)) {
            Platform platform = Platform.getAndroidPlatformApi();
            platform.assets().setPathPrefix("com/klenwell/myproject/resources");
            platform.graphics().registerFont("Inconsolata", "fonts/Inconsolata.ttf");
        }
        else if (platformType().equals(Platform.Type.HTML)) {
            // rely on CSS setting in HTML host file
        }
    }
    

    But there is no method like getJavaPlatformApi in the core Platform class. So as noted here, "you have to register the font manually on each backend that you intend to use."


    Following the example of the TextDemo sample, this is how I would load the font in my example above for the Java and HTML platforms:

    Java Platform

    Update game class in Java dir:

    public class MyProjectJava {
    
      public static void main(String[] args) {
        JavaPlatform platform = JavaPlatform.register();
        platform.assets().setPathPrefix("com/klenwell/myproject/resources");
        platform.graphics().registerFont("Inconsolata", "fonts/Inconsolata.ttf");
        PlayN.run(new MyProject());
      }
    }
    

    HTML Platform

    Edit the HTML host file under HTML snapshot directory:

    <!DOCTYPE html>
    <html>
      <head>
        <title>MyProject Font Loading Example</title>
        <style>
          @font-face {
            font-family: "Inconsolata";
            src: url(myproject/resources/fonts/Inconsolata.ttf);
          }
        </style>
      </head>
      <body bgcolor="black">
        <script src="myproject/myproject.nocache.js"></script>
      </body>
    </html>
    

    Android Platform

    To Be Announced

    iOS Platform

    To Be Announced

    I haven't yet ventured into Android or iOS compilation yet, so I can't offer an example of those at present.