Distorted text in Nifty 1.2/1.3

I’ve been working on a simple gui with some buttons and a text window to display game info. It’s working, but the text appears distorted or corrupted most of the time.



The text is multi-line, and I set the textRenderer to use line wrapping.



Here’s a screen shot. The text is supposed to read “Hey, this is \nsome text \nto demonstrate \nthe problem.”

(edit: those are actually slash-n characters for line returns, i.e. slash-n some not nsome)







I’m using the font I found in the helloworld example, aurulent-sans-17.fnt. aurulent-sans-16-bold.fnt seems to work a little better (that’s it in the screen shot), but still not right.



Any one know what am I doing wrong?

Have you tested this on Nifty 1.3? Try the newest version and report back please.

Ok, I ported over to nifty 1.3 and the JME 3 alpha 4 code. The only major change was that I had to switch to aurulent-sans-16.fnt. Same result, except the font is a little different:



Can you provide a test case? I have never seen this issue happen before …

Sure. Here’s a JMP version of roughly the same thing I’m trying to do.



Main class:

[java]package mygame;



import com.jme3.app.SimpleApplication;

import com.jme3.input.MouseInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.MouseButtonTrigger;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector3f;

import com.jme3.niftygui.NiftyJmeDisplay;

import com.jme3.renderer.RenderManager;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;

import de.lessvoid.nifty.Nifty;



/**

  • test
  • @author normenhansen

    */

    public class Main extends SimpleApplication

    implements ActionListener {



    public static void main(String[] args) {

    Main app = new Main();

    app.start();

    }

    private static Main theApp;

    private HUDController hudController;

    private Nifty nifty;



    public Main() {

    theApp = this;

    }



    public static Main getInstance() {

    return theApp;

    }



    @Override

    public void simpleInitApp() {

    //generate Nifty GUI

    NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(

    assetManager, inputManager, audioRenderer, guiViewPort);

    nifty = niftyDisplay.getNifty();



    // init Nifty start screen

    nifty.fromXml("Interface/interface.xml", "start");



    // attach the Nifty display to the gui view port as a processor

    guiViewPort.addProcessor(niftyDisplay);



    // disable the fly cam

    flyCam.setDragToRotate(true);



    Box b = new Box(Vector3f.ZERO, 1, 1, 1);

    Geometry geom = new Geometry("Box", b);

    geom.updateModelBound();



    Material mat = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");

    mat.setColor("m_Color", ColorRGBA.Blue);

    geom.setMaterial(mat);



    rootNode.attachChild(geom);



    inputManager.addMapping("Toggle Panel", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));



    // Add the names to the action listener.

    inputManager.addListener(this, new String[]{"Toggle Panel"});

    }



    @Override

    public void simpleUpdate(float tpf) {

    //TODO: add update code

    }



    @Override

    public void simpleRender(RenderManager rm) {

    //TODO: add render code

    }



    public void onAction(String name, boolean keyPressed, float tpf) {



    if (name.equals("Toggle Panel")) {

    changeText ("Hey, this is nsome text nto demonstrate nthe problem.");

    }

    }



    public void registerHUDController(HUDController hudController) {

    this.hudController = hudController;

    }



    public void changeText(String string) {

    hudController.updateInfoPanel(string);

    }

    }

    [/java]



    Screen controller:

    [java]package mygame;



    import de.lessvoid.nifty.Nifty;

    import de.lessvoid.nifty.elements.Element;

    import de.lessvoid.nifty.elements.render.TextRenderer;

    import de.lessvoid.nifty.screen.Screen;

    import de.lessvoid.nifty.screen.ScreenController;



    /**

    *
  • @author mking

    */

    public class HUDController implements ScreenController {



    Nifty nifty;



    public void bind(Nifty nifty, Screen screen) {

    this.nifty = nifty;

    }



    public void onStartScreen() {

    Main.getInstance().registerHUDController(this);

    getElement ("info_panel").setVisible(false);

    }



    public void onEndScreen() {



    }



    public void onMouseOver() {



    }



    private Element getElement(final String id) {

    return nifty.getCurrentScreen().findElementByName(id);

    }



    public void updateInfoPanel(String string) {

    if (string != null) {

    System.out.println (string);

    getElement ("info_panel").setVisible(true);

    TextRenderer textRenderer = getElement ("info_panel_text").getRenderer(TextRenderer.class);

    textRenderer.setLineWrapping(true);

    textRenderer.setText(string);

    }

    else {

    getElement ("info_panel").setVisible(false);

    }

    }

    }

    [/java]



    and the nifty layout file interface.xml:

    [xml]<?xml version="1.0" encoding="UTF-8"?>

    <nifty xmlns="http://nifty-gui.sourceforge.net/nifty.xsd"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://nifty-gui.sourceforge.net/nifty.xsd

    http://nifty-gui.sourceforge.net/nifty.xsd">

    <screen id="start" controller="mygame.HUDController">

    <layer id="layer" backgroundColor="#00000000" childLayout="vertical">

    <panel id="info_panel" height="30%" width="20%" align="left" valign="bottom" backgroundColor="#ffffff80" childLayout="vertical" visibleToMouse="false">

    <text font="aurulent-sans-16.fnt" color="#000f" text="Hello World!" id="info_panel_text" height="100%" width="100%" backgroundColor="#ffffffff" />

    </panel>

    </layer>

    </screen>

    </nifty>

    [/xml]

This basically duplicates what I’m trying to do in my code. I want to allow the player to click an object, and then a panel opens up with text data about that object. Which works great, except that the text is mangled.



I think it must have something to do with the n (slash n) characters (which this forum doesn’t like much either). If I take out the slash n, then the text appears correctly every time I tried it. However, whether setLineWrapping is true or not, the text is never wrapped to fit the space available, so it appears on one long line that disappears off both sides:



Wow, this is really a weird one. I switched fonts (to verdana-small-regular, from the nifty-examples-1.3) and that appeared to work a lot better. But then I found some strings that don’t work on it.



It is very consistent. If two objects have the same descriptive text, then they have the same results. Either they both work, or they are both garbled in the exact same way. You can see that in the samples above. Even though the fonts are different, they are both displaying the same graphical artifacts, just in a different size.



I traced through the code, and didn’t see anything obviously bad with the layout and sizing. It must be something happening when it creates the text textures.

@milieu said:
Wow, this is really a weird one. I switched fonts (to verdana-small-regular, from the nifty-examples-1.3) and that appeared to work a lot better. But then I found some strings that don't work on it.

It is very consistent. If two objects have the same descriptive text, then they have the same results. Either they both work, or they are both garbled in the exact same way. You can see that in the samples above. Even though the fonts are different, they are both displaying the same graphical artifacts, just in a different size.

I traced through the code, and didn't see anything obviously bad with the layout and sizing. It must be something happening when it creates the text textures.



Just for the record and in case someone does the same as @milieu and got the same result (just like milieu as well) with the following similar code, such as:
[java]
Element myText = screen.findElementByName("myTextID");
TextRenderer textRenderer = myText.getRenderer(TextRenderer.class);
textRenderer.setLineWrapping(true);
textRender.setText("The big brown fox jumped over the grand fences.");
[/java]

Please, remember to add this line after the above code as well!
[java]
...
myText.getParent().layoutElements();
[/java]

Remember to re-layout the elements on the current screen to refresh the properties of the text and you will get your wrapping result inside panel/placeholder it is sitting within. (Provided that you set a width and height beforehand, if your message is long enough, it will be wrapped within its parent-panel).

In general, every time you change something on a nifty element from Java, you need to call the layoutElements() on at least that element.

It is not always needed to call it on the entire screen. Calling it on the container of the current element should be enough. This could just as easily be a panel or a layer for instance.