Page support for BitmapText

Multi-byte languages such as Korean, Chinese needs multiple number of bitmap textures for text.

I’d like to add the functionality to BitmapText, but then I have to change it from geometry to Node,

So I introduced MultiPageBitmapText.

Please change the class name if it is ugly.



[patch]

Index: src/core-plugins/com/jme3/font/plugins/BitmapFontLoader.java

===================================================================

— src/core-plugins/com/jme3/font/plugins/BitmapFontLoader.java (revision 6397)

+++ src/core-plugins/com/jme3/font/plugins/BitmapFontLoader.java (working copy)

@@ -142,6 +142,8 @@

ch.setYOffset(Integer.parseInt(tokens));

}else if (token.equals(“xadvance”)){

ch.setXAdvance(Integer.parseInt(tokens));

  •                } else if (token.equals(&quot;page&quot;)) {<br />
    
  •                    ch.setPage(Integer.parseInt(tokens<i>));<br />
    

}

}

}else if (tokens[0].equals("kerning")){

Index: src/core/com/jme3/font/MultiPageBitmapText.java

===================================================================

— src/core/com/jme3/font/MultiPageBitmapText.java (revision 0)

+++ src/core/com/jme3/font/MultiPageBitmapText.java (revision 0)

@@ -0,0 +1,96 @@

+package com.jme3.font;

+

+import java.nio.ByteBuffer;

+import java.nio.FloatBuffer;

+import java.nio.ShortBuffer;

+

+import com.jme3.math.ColorRGBA;

+import com.jme3.scene.Mesh;

+import com.jme3.scene.Node;

+import com.jme3.scene.VertexBuffer;

+import com.jme3.scene.VertexBuffer.Type;

+import com.jme3.util.BufferUtils;

+

+public class MultiPageBitmapText extends Node {

  • private final BitmapText[] bitmapTexts;

    +
  • public MultiPageBitmapText(BitmapFont font) {
  •    this(font, false, false);<br />
    
  • }

    +
  • public MultiPageBitmapText(BitmapFont font, boolean rightToLeft) {
  •    this(font, rightToLeft, false);<br />
    
  • }

    +
  • public MultiPageBitmapText(BitmapFont font, boolean rightToLeft, boolean arrayBased) {
  •    bitmapTexts = new BitmapText[font.getPageSize()];<br />
    
  •    for (int page = 0; page &lt; bitmapTexts.length; page++) {<br />
    
  •        bitmapTexts[page] = new BitmapText(font, rightToLeft, arrayBased, page);<br />
    
  •        attachChild(bitmapTexts[page]);<br />
    
  •    }<br />
    
  • }

    +
  • public void setBox(Rectangle rectangle) {
  •    for (BitmapText t : bitmapTexts) {<br />
    
  •        t.setBox(rectangle);<br />
    
  •    }<br />
    
  • }

    +
  • public void setSize(float size) {
  •    for (BitmapText t : bitmapTexts) {<br />
    
  •        t.setSize(size);<br />
    
  •    }<br />
    
  • }

    +
  • public void setText(CharSequence text) {
  •    for (BitmapText t : bitmapTexts) {<br />
    
  •        t.setText(text);<br />
    
  •    }<br />
    
  • }

    +
  • public float getLineWidth() {
  •    return bitmapTexts[0].getLineWidth();<br />
    
  • }

    +
  • public float getLineHeight() {
  •    return bitmapTexts[0].getLineHeight();<br />
    
  • }

    +
  • @Override
  • public MultiPageBitmapText clone() {
  •    MultiPageBitmapText clone = (MultiPageBitmapText) super.clone();<br />
    
  •    for (int i = 0; i &lt; bitmapTexts.length; i++) {<br />
    
  •        clone.bitmapTexts<i> = bitmapTexts<i>.clone();<br />
    
  •    }<br />
    
  •    return clone;<br />
    
  • }

    +
  • public BitmapFont getFont() {
  •    return bitmapTexts[0].getFont();<br />
    
  • }

    +
  • public String getText() {
  •    return bitmapTexts[0].getText();<br />
    
  • }

    +
  • public ColorRGBA getColor() {
  •    return bitmapTexts[0].getColor();<br />
    
  • }

    +
  • public void setColor(ColorRGBA color) {
  •    for (BitmapText t : bitmapTexts) {<br />
    
  •        t.setColor(color);<br />
    
  •    }<br />
    
  • }

    +
  • public void setAlignment(BitmapFont.Align align) {
  •    for (BitmapText t : bitmapTexts) {<br />
    
  •        t.setAlignment(align);<br />
    
  •    }<br />
    
  • }

    +
  • public BitmapFont.Align getAlignment() {
  •    return bitmapTexts[0].getAlignment();<br />
    
  • }

    +

    +}

    Index: src/core/com/jme3/font/QuadList.java

    ===================================================================

    — src/core/com/jme3/font/QuadList.java (revision 6397)

    +++ src/core/com/jme3/font/QuadList.java (working copy)

    @@ -39,10 +39,6 @@

    private ArrayList<FontQuad> quads = new ArrayList<FontQuad>();

    private int actualSize = 0;


  • public void addQuad(FontQuad quad){
  •    quads.add(quad);<br />
    
  • }

    -

    public FontQuad getQuad(int index){

    return quads.get(index);

    }

    @@ -50,17 +46,25 @@

    public int getQuantity(){

    return quads.size();

    }

    -
  • public void setActualSize(int size){
  •    if (quads.size() &lt; size){<br />
    
  •        int quadSize = quads.size();<br />
    
  •        for (int i = 0; i &lt; size - quadSize; i++){<br />
    
  •            quads.add(new FontQuad());<br />
    
  •        }<br />
    
  •    }<br />
    
  •    for (int i = 0; i &lt; quads.size(); i++){<br />
    
  •        quads.get(i).setSize(0, 0);<br />
    

+

  • public void clear() {
  •    actualSize = 0;<br />
    
  • }

    +
  • public int getActualSize() {
  •    return actualSize;<br />
    
  • }

    +
  • public FontQuad newQuad() {
  •    FontQuad q = null;<br />
    
  •    if (actualSize == quads.size()) {<br />
    
  •        q = new FontQuad();<br />
    
  •        quads.add(q);<br />
    
  •    } else {<br />
    
  •        q = quads.get(actualSize);<br />
    
  •        q.setSize(0, 0);<br />
    

}

  •    actualSize++;<br />
    
  •    return q;<br />
    

}

-

}

Index: src/core/com/jme3/font/BitmapText.java

===================================================================

— src/core/com/jme3/font/BitmapText.java (revision 6397)

+++ src/core/com/jme3/font/BitmapText.java (working copy)

@@ -55,8 +55,13 @@

private final float[] tc;

private final short[] idx;

private final byte[] color;

  • private int page;



    public BitmapText(BitmapFont font, boolean rightToLeft, boolean arrayBased) {
  •    this(font, rightToLeft, arrayBased, 0);<br />
    
  • }

    +
  • public BitmapText(BitmapFont font, boolean rightToLeft, boolean arrayBased, int page) {

    super("BitmapFont", new Mesh());



    if (font == null) {

    @@ -70,8 +75,9 @@

    this.font = font;

    this.block = new StringBlock();

    block.setSize(font.getPreferredSize());
  •    this.page = page;<br />
    

- Material mat = font.getPage(0);
+ Material mat = font.getPage(page);
if (mat == null) {
throw new IllegalStateException("The font's texture was not found!");
}
@@ -191,9 +197,9 @@
private void assemble() {
// first generate quadlist
if (block.getTextBox() == null) {
- lineWidth = font.updateText(block, quadList, rightToLeft);
+ lineWidth = font.updateText(block, quadList, rightToLeft, page);
} else {
- lineWidth = font.updateTextRect(block, quadList);
+ lineWidth = font.updateTextRect(block, quadList, page);
}

Mesh m = getMesh();
Index: src/core/com/jme3/font/BitmapFont.java
===================================================================
--- src/core/com/jme3/font/BitmapFont.java (revision 6397)
+++ src/core/com/jme3/font/BitmapFont.java (working copy)
@@ -80,6 +80,10 @@
public Material getPage(int index) {
return pages[index];
}
+
+ public int getPageSize() {
+ return pages.length;
+ }

public BitmapCharacterSet getCharSet() {
return charSet;
@@ -109,6 +113,8 @@

private int findKerningAmount(int newLineLastChar, int nextChar) {
BitmapCharacter c = charSet.getCharacter(newLineLastChar);
+ if (c == null)
+ return 0;
return c.getKerning(nextChar);
}

@@ -163,7 +169,7 @@
return Math.max(maxLineWidth, lineWidth);
}

- public float updateText(StringBlock block, QuadList target, boolean rightToLeft) {
+ public float updateText(StringBlock block, QuadList target, boolean rightToLeft, int page) {

CharSequence text = block.getCharacters();
Align alignment = block.getAlignment();
@@ -175,10 +181,9 @@
BitmapCharacter lastChar = null;
int lineNumber = 1;
int wordNumber = 1;
- int quadIndex = -1;
float wordWidth = 0f;
boolean useKerning = block.isKerning();
- target.setActualSize(text.length());
+ target.clear();

float incrScale = rightToLeft ? -1f : 1f;
textColor.set(block.getColor());
@@ -274,13 +279,23 @@
wordWidth += kernAmount;
}
}
+
+ final float x0 = x;
+ final float wordWidth0 = wordWidth;
+
+ x += xAdvance * incrScale;
+ wordWidth += xAdvance;
+ lineWidth += xAdvance;
+
+ if (c.getPage() != page) {
+ continue;
+ }

// Create the quad
- quadIndex++;
- FontQuad q = target.getQuad(quadIndex);
+ FontQuad q = target.newQuad();

// Determine quad position
- float quadPosX = x + (xOffset * incrScale);
+ float quadPosX = x0 + (xOffset * incrScale);
if (rightToLeft){
quadPosX -= width;
}
@@ -302,21 +317,17 @@
// since this is a space,
// increment wordnumber and reset wordwidth
wordNumber++;
- wordWidth = 0f;
+ wordWidth = xAdvance;
}

// set data
- q.setWordNumber(wordNumber);
+ q.setWordWidth(wordWidth0);
q.setWordWidth(wordWidth);
q.setBitmapChar(c);
q.setSizeScale(sizeScale);
q.setCharacter(text.charAt(i));
q.setTotalWidth(kernAmount + xAdvance);

- x += xAdvance * incrScale;
- wordWidth += xAdvance;
- lineWidth += xAdvance;
-
lastChar = c;
}
}
@@ -324,7 +335,7 @@
return Math.max(lineWidth, maxLineWidth);
}

- public float updateTextRect(StringBlock b, QuadList target) {
+ public float updateTextRect(StringBlock b, QuadList target, int page) {

String text = b.getText();
float x = b.getTextBox().x;
@@ -337,13 +348,12 @@
char lastChar = 0;
int lineNumber = 1;
int wordNumber = 1;
- int quadIndex = -1;
float wordWidth = 0f;
boolean firstCharOfLine = true;
boolean useKerning = b.isKerning();
Align alignment = b.getAlignment();

- target.setActualSize(text.length());
+ target.clear();

for (int i = 0; i < text.length(); i++){
BitmapCharacter c = charSet.getCharacter((int) text.charAt(i));
@@ -382,7 +392,7 @@
lineWidth = 0f;


- for (int j = 0; j <= quadIndex; j++){
+ for (int j = 0; j <= target.getActualSize(); j++){
FontQuad q = target.getQuad(j);
BitmapCharacter localChar = q.getBitmapChar();

@@ -468,12 +478,19 @@
}
}
firstCharOfLine = false;
+
+ final float x0 = x;
+
+ x += xAdvance;
+ lineWidth += xAdvance;
+ if (c.getPage() != page) {
+ continue;
+ }

// edit the quad
- quadIndex++;
- FontQuad q = target.getQuad(quadIndex);
+ FontQuad q = target.newQuad();

- float quadPosX = x + (xOffset);
+ float quadPosX = x0 + (xOffset);
float quadPosY = y - yOffset;
q.setPosition(quadPosX, quadPosY);
q.setSize(width, height);
@@ -497,8 +514,6 @@
q.setSizeScale(sizeScale);
q.setCharacter(text.charAt(i));

- x += xAdvance;
- lineWidth += xAdvance;
lastChar = text.charAt(i);

}
Index: src/core/com/jme3/font/BitmapCharacter.java
===================================================================
--- src/core/com/jme3/font/BitmapCharacter.java (revision 6397)
+++ src/core/com/jme3/font/BitmapCharacter.java (working copy)
@@ -54,6 +54,7 @@
private int yOffset;
private int xAdvance;
private IntMap<Integer> kerning = new IntMap<Integer>();
+ private int page;

@Override
public BitmapCharacter clone() {
@@ -121,6 +122,14 @@
public void setXAdvance(int advance) {
xAdvance = advance;
}
+
+ public void setPage(int page) {
+ this.page = page;
+ }
+
+ public int getPage() {
+ return page;
+ }

public void addKerning(int second, int amount){
kerning.put(second, amount);

[/patch]
1 Like

Since we are still in alpha I think its okay to break compatibility. So it should be okay to just make BitmapText into a node, and add this functionality there. That way we can support multiple pages without the user having to know about it.

Okay, then please wait for another patch.:slight_smile:

Now BitmapText is a ‘Node’ and it contains BitmapTextPages

BitmapText contains the common information and BitmapTextPage contains the page specific information.



[patch]

Index: src/core/com/jme3/font/QuadList.java

===================================================================

— src/core/com/jme3/font/QuadList.java (revision 6420)

+++ src/core/com/jme3/font/QuadList.java (working copy)

@@ -39,10 +39,6 @@

private ArrayList<FontQuad> quads = new ArrayList<FontQuad>();

private int actualSize = 0;


  • public void addQuad(FontQuad quad){
  •    quads.add(quad);<br />
    
  • }

    -

    public FontQuad getQuad(int index){

    return quads.get(index);

    }

    @@ -51,16 +47,24 @@

    return quads.size();

    }


  • public void setActualSize(int size){
  •    if (quads.size() &lt; size){<br />
    
  •        int quadSize = quads.size();<br />
    
  •        for (int i = 0; i &lt; size - quadSize; i++){<br />
    
  •            quads.add(new FontQuad());<br />
    
  •        }<br />
    
  •    }<br />
    
  •    for (int i = 0; i &lt; quads.size(); i++){<br />
    
  •        quads.get(i).setSize(0, 0);<br />
    
  •    }<br />
    
  • public void clear() {
  •    actualSize = 0;<br />
    
  • }

    +
  • public int getActualSize() {
  •    return actualSize;<br />
    

}


  • public FontQuad newQuad() {
  •    FontQuad q = null;<br />
    
  •    if (actualSize == quads.size()) {<br />
    
  •        q = new FontQuad();<br />
    
  •        quads.add(q);<br />
    
  •    } else {<br />
    
  •        q = quads.get(actualSize);<br />
    
  •        q.setSize(0, 0);<br />
    
  •    }<br />
    
  •    actualSize++;<br />
    
  •    return q;<br />
    
  • }

    }

    Index: src/core/com/jme3/font/BitmapText.java

    ===================================================================

    — src/core/com/jme3/font/BitmapText.java (revision 6420)

    +++ src/core/com/jme3/font/BitmapText.java (working copy)

    @@ -33,97 +33,53 @@



    import com.jme3.material.Material;

    import com.jme3.math.ColorRGBA;

    -import com.jme3.renderer.queue.RenderQueue.Bucket;

    -import com.jme3.scene.Geometry;

    -import com.jme3.scene.Mesh;

    -import com.jme3.scene.VertexBuffer;

    -import com.jme3.scene.VertexBuffer.Type;

    -import com.jme3.util.BufferUtils;

    -import java.nio.ByteBuffer;

    -import java.nio.FloatBuffer;

    -import java.nio.ShortBuffer;

    -

    -public class BitmapText extends Geometry {

    +import com.jme3.renderer.RenderManager;

    +import com.jme3.scene.Node;


  • private BitmapFont font;

    +public class BitmapText extends Node {

    +
  • private BitmapFont font;

    private StringBlock block;
  • private QuadList quadList = new QuadList();
  • private float lineWidth = 0f;
  • private boolean rightToLeft = false;
  • private float lineWidth = 0f;

    private boolean needRefresh = true;
  • private final float[] pos;
  • private final float[] tc;
  • private final short[] idx;
  • private final byte[] color;

    -
  • public BitmapText(BitmapFont font, boolean rightToLeft, boolean arrayBased) {
  •    super(&quot;BitmapFont&quot;, new Mesh());<br />
    

-

  •    if (font == null) {<br />
    
  •        throw new NullPointerException(&quot;'font' cannot be null.&quot;);<br />
    
  •    }<br />
    

-

  •    setQueueBucket(Bucket.Gui);<br />
    
  •    setCullHint(CullHint.Never);<br />
    

-

  •    this.rightToLeft = rightToLeft;<br />
    
  •    this.font = font;<br />
    
  •    this.block = new StringBlock();<br />
    
  •    block.setSize(font.getPreferredSize());<br />
    

-

  •    Material mat = font.getPage(0);<br />
    
  •    if (mat == null) {<br />
    
  •        throw new IllegalStateException(&quot;The font's texture was not found!&quot;);<br />
    
  •    }<br />
    

-

  •    setMaterial(mat);<br />
    

-

  •    // initialize buffers<br />
    
  •    Mesh m = getMesh();<br />
    
  •    m.setBuffer(Type.Position, 3, new float[0]);<br />
    
  •    m.setBuffer(Type.TexCoord, 2, new float[0]);<br />
    
  •    m.setBuffer(Type.Color, 4, new byte[0]);<br />
    
  •    m.setBuffer(Type.Index, 3, new short[0]);<br />
    

-

  •    // scale colors from 0 - 255 range into 0 - 1<br />
    
  •    m.getBuffer(Type.Color).setNormalized(true);<br />
    

-

  •    arrayBased = true;<br />
    
  • private boolean rightToLeft = false;
  • private final BitmapTextPage[] textPages;


  •    if (arrayBased) {<br />
    
  •        pos = new float[4 * 3];  // 4 verticies * 3 floats<br />
    
  •        tc = new float[4 * 2];  // 4 verticies * 2 floats<br />
    
  •        idx = new short[2 * 3];  // 2 triangles * 3 indices<br />
    
  •        color = new byte[4 * 4];   // 4 verticies * 4 bytes<br />
    
  •    } else {<br />
    
  •        pos = null;<br />
    
  •        tc = null;<br />
    
  •        idx = null;<br />
    
  •        color = null;<br />
    
  •    }<br />
    
  • public BitmapText(BitmapFont font) {
  •    this(font, false, false);<br />
    

}



public BitmapText(BitmapFont font, boolean rightToLeft) {

this(font, rightToLeft, false);

}


  • public BitmapText(BitmapFont font) {
  •    this(font, false, false);<br />
    
  • public BitmapText(BitmapFont font, boolean rightToLeft, boolean arrayBased) {
  •    textPages = new BitmapTextPage[font.getPageSize()];<br />
    
  •    for (int page = 0; page &lt; textPages.length; page++) {<br />
    
  •        textPages[page] = new BitmapTextPage(font, arrayBased, page);<br />
    
  •        attachChild(textPages[page]);<br />
    
  •    }<br />
    

+

  •    this.font = font;<br />
    
  •    this.block = new StringBlock();<br />
    
  •    block.setSize(font.getPreferredSize());<br />
    

}



@Override

public BitmapText clone() {

BitmapText clone = (BitmapText) super.clone();

  •    clone.mesh = mesh.deepClone();<br />
    
  •    clone.needRefresh = true;<br />
    
  •    clone.quadList = new QuadList();<br />
    
  •    for (int i = 0; i &lt; textPages.length; i++) {<br />
    
  •        clone.textPages<i> = textPages<i>.clone();<br />
    
  •    }<br />
    

clone.block = block.clone();

  •    clone.needRefresh = true;<br />
    

return clone;

}



public BitmapFont getFont() {

return font;

}

+



public void setSize(float size) {

block.setSize(size);

@@ -160,18 +116,18 @@

block.setTextBox(rect);

needRefresh = true;

}

-

+

public float getLineHeight() {

return font.getLineHeight(block);

}

-

+

public float getLineWidth() {

if (needRefresh) {

assemble();

}

return lineWidth;

}

-

+

public void setAlignment(BitmapFont.Align align) {

block.setAlignment(align);

}

@@ -179,7 +135,7 @@

public BitmapFont.Align getAlignment() {

return block.getAlignment();

}

-

+

@Override

public void updateLogicalState(float tpf) {

super.updateLogicalState(tpf);

@@ -189,69 +145,15 @@

}



private void assemble() {

  •    // first generate quadlist<br />
    
  •    if (block.getTextBox() == null) {<br />
    
  •        lineWidth = font.updateText(block, quadList, rightToLeft);<br />
    
  •    } else {<br />
    
  •        lineWidth = font.updateTextRect(block, quadList);<br />
    
  •    }<br />
    

-

  •    Mesh m = getMesh();<br />
    
  •    m.setVertexCount(quadList.getQuantity() * 4);<br />
    
  •    m.setTriangleCount(quadList.getQuantity() * 2);<br />
    

-

  •    VertexBuffer pb = m.getBuffer(Type.Position);<br />
    
  •    VertexBuffer tb = m.getBuffer(Type.TexCoord);<br />
    
  •    VertexBuffer ib = m.getBuffer(Type.Index);<br />
    
  •    VertexBuffer cb = m.getBuffer(Type.Color);<br />
    

-

  •    FloatBuffer fpb = (FloatBuffer) pb.getData();<br />
    
  •    FloatBuffer ftb = (FloatBuffer) tb.getData();<br />
    
  •    ShortBuffer sib = (ShortBuffer) ib.getData();<br />
    
  •    ByteBuffer bcb = (ByteBuffer) cb.getData();<br />
    

-

  •    // increase capacity of buffers as needed<br />
    
  •    fpb.rewind();<br />
    
  •    fpb = BufferUtils.ensureLargeEnough(fpb, m.getVertexCount() * 3);<br />
    
  •    pb.updateData(fpb);<br />
    

-

  •    ftb.rewind();<br />
    
  •    ftb = BufferUtils.ensureLargeEnough(ftb, m.getVertexCount() * 2);<br />
    
  •    tb.updateData(ftb);<br />
    

-

  •    bcb.rewind();<br />
    
  •    bcb = BufferUtils.ensureLargeEnough(bcb, m.getVertexCount() * 4);<br />
    
  •    cb.updateData(bcb);<br />
    

-

  •    sib.rewind();<br />
    
  •    sib = BufferUtils.ensureLargeEnough(sib, m.getTriangleCount() * 3);<br />
    
  •    ib.updateData(sib);<br />
    

-

  •    // go for each quad and append it to the buffers<br />
    
  •    if (pos != null) {<br />
    
  •        for (int i = 0; i &lt; quadList.getQuantity(); i++) {<br />
    
  •            FontQuad fq = quadList.getQuad(i);<br />
    
  •            fq.storeToArrays(pos, tc, idx, color, i);<br />
    
  •            fpb.put(pos);<br />
    
  •            ftb.put(tc);<br />
    
  •            sib.put(idx);<br />
    
  •            bcb.put(color);<br />
    
  •        }<br />
    
  •    } else {<br />
    
  •        for (int i = 0; i &lt; quadList.getQuantity(); i++) {<br />
    
  •            FontQuad fq = quadList.getQuad(i);<br />
    
  •            fq.appendPositions(fpb);<br />
    
  •            fq.appendTexCoords(ftb);<br />
    
  •            fq.appendIndices(sib, i);<br />
    
  •            fq.appendColors(bcb);<br />
    
  •        }<br />
    
  •    for (BitmapTextPage page : textPages) {<br />
    
  •        page.assemble(font, block, rightToLeft);<br />
    

}

-

  •    fpb.rewind();<br />
    
  •    ftb.rewind();<br />
    
  •    sib.rewind();<br />
    
  •    bcb.rewind();<br />
    

-

needRefresh = false;

}

+

  • public void render(RenderManager rm, Material mat) {
  •    for (BitmapTextPage entry : textPages) {<br />
    
  •        mat.render(entry, rm);<br />
    
  •    }<br />
    
  • }

    }

    Index: src/core/com/jme3/font/BitmapFont.java

    ===================================================================

    — src/core/com/jme3/font/BitmapFont.java (revision 6420)

    +++ src/core/com/jme3/font/BitmapFont.java (working copy)

    @@ -81,6 +81,10 @@

    return pages[index];

    }


  • public int getPageSize() {
  •    return pages.length;<br />
    
  • }

    +

    public BitmapCharacterSet getCharSet() {

    return charSet;

    }

    @@ -109,6 +113,8 @@



    private int findKerningAmount(int newLineLastChar, int nextChar) {

    BitmapCharacter c = charSet.getCharacter(newLineLastChar);
  •    if (c == null)<br />
    
  •        return 0;<br />
    

return c.getKerning(nextChar);

}



@@ -163,7 +169,7 @@

return Math.max(maxLineWidth, lineWidth);

}


  • public float updateText(StringBlock block, QuadList target, boolean rightToLeft) {
  • public float updateText(StringBlock block, QuadList target, boolean rightToLeft, int page) {



    CharSequence text = block.getCharacters();

    Align alignment = block.getAlignment();

    @@ -175,10 +181,9 @@

    BitmapCharacter lastChar = null;

    int lineNumber = 1;

    int wordNumber = 1;
  •    int quadIndex = -1;<br />
    

float wordWidth = 0f;

boolean useKerning = block.isKerning();

  •    target.setActualSize(text.length());<br />
    
  •    target.clear();<br />
    

float incrScale = rightToLeft ? -1f : 1f;
textColor.set(block.getColor());
@@ -275,12 +280,22 @@
}
}

+ final float x0 = x;
+ final float wordWidth0 = wordWidth;
+
+ x += xAdvance * incrScale;
+ wordWidth += xAdvance;
+ lineWidth += xAdvance;
+
+ if (c.getPage() != page) {
+ continue;
+ }
+
// Create the quad
- quadIndex++;
- FontQuad q = target.getQuad(quadIndex);
+ FontQuad q = target.newQuad();

// Determine quad position
- float quadPosX = x + (xOffset * incrScale);
+ float quadPosX = x0 + (xOffset * incrScale);
if (rightToLeft){
quadPosX -= width;
}
@@ -302,21 +317,17 @@
// since this is a space,
// increment wordnumber and reset wordwidth
wordNumber++;
- wordWidth = 0f;
+ wordWidth = xAdvance;
}

// set data
- q.setWordNumber(wordNumber);
+ q.setWordWidth(wordWidth0);
q.setWordWidth(wordWidth);
q.setBitmapChar(c);
q.setSizeScale(sizeScale);
q.setCharacter(text.charAt(i));
q.setTotalWidth(kernAmount + xAdvance);

- x += xAdvance * incrScale;
- wordWidth += xAdvance;
- lineWidth += xAdvance;
-
lastChar = c;
}
}
@@ -324,7 +335,7 @@
return Math.max(lineWidth, maxLineWidth);
}

- public float updateTextRect(StringBlock b, QuadList target) {
+ public float updateTextRect(StringBlock b, QuadList target, int page) {

String text = b.getText();
float x = b.getTextBox().x;
@@ -337,13 +348,12 @@
char lastChar = 0;
int lineNumber = 1;
int wordNumber = 1;
- int quadIndex = -1;
float wordWidth = 0f;
boolean firstCharOfLine = true;
boolean useKerning = b.isKerning();
Align alignment = b.getAlignment();

- target.setActualSize(text.length());
+ target.clear();

for (int i = 0; i < text.length(); i++){
BitmapCharacter c = charSet.getCharacter((int) text.charAt(i));
@@ -382,7 +392,7 @@
lineWidth = 0f;


- for (int j = 0; j <= quadIndex; j++){
+ for (int j = 0; j <= target.getActualSize(); j++){
FontQuad q = target.getQuad(j);
BitmapCharacter localChar = q.getBitmapChar();

@@ -469,11 +479,18 @@
}
firstCharOfLine = false;

+ final float x0 = x;
+
+ x += xAdvance;
+ lineWidth += xAdvance;
+ if (c.getPage() != page) {
+ continue;
+ }
+
// edit the quad
- quadIndex++;
- FontQuad q = target.getQuad(quadIndex);
+ FontQuad q = target.newQuad();

- float quadPosX = x + (xOffset);
+ float quadPosX = x0 + (xOffset);
float quadPosY = y - yOffset;
q.setPosition(quadPosX, quadPosY);
q.setSize(width, height);
@@ -497,8 +514,6 @@
q.setSizeScale(sizeScale);
q.setCharacter(text.charAt(i));

- x += xAdvance;
- lineWidth += xAdvance;
lastChar = text.charAt(i);

}
Index: src/core/com/jme3/font/BitmapCharacter.java
===================================================================
--- src/core/com/jme3/font/BitmapCharacter.java (revision 6420)
+++ src/core/com/jme3/font/BitmapCharacter.java (working copy)
@@ -54,6 +54,7 @@
private int yOffset;
private int xAdvance;
private IntMap<Integer> kerning = new IntMap<Integer>();
+ private int page;

@Override
public BitmapCharacter clone() {
@@ -122,6 +123,14 @@
xAdvance = advance;
}

+ public void setPage(int page) {
+ this.page = page;
+ }
+
+ public int getPage() {
+ return page;
+ }
+
public void addKerning(int second, int amount){
kerning.put(second, amount);
}
Index: src/core/com/jme3/font/BitmapTextPage.java
===================================================================
--- src/core/com/jme3/font/BitmapTextPage.java (revision 6420)
+++ src/core/com/jme3/font/BitmapTextPage.java (working copy)
@@ -31,32 +31,28 @@
*/
package com.jme3.font;

+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.ShortBuffer;
+
import com.jme3.material.Material;
-import com.jme3.math.ColorRGBA;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.BufferUtils;
-import java.nio.ByteBuffer;
-import java.nio.FloatBuffer;
-import java.nio.ShortBuffer;

-public class BitmapText extends Geometry {
-
- private BitmapFont font;
- private StringBlock block;
+class BitmapTextPage extends Geometry {
+
private QuadList quadList = new QuadList();
- private float lineWidth = 0f;
- private boolean rightToLeft = false;
- private boolean needRefresh = true;
private final float[] pos;
private final float[] tc;
private final short[] idx;
private final byte[] color;
+ private int page;

- public BitmapText(BitmapFont font, boolean rightToLeft, boolean arrayBased) {
+ BitmapTextPage(BitmapFont font, boolean arrayBased, int page) {
super("BitmapFont", new Mesh());

if (font == null) {
@@ -66,12 +62,9 @@
setQueueBucket(Bucket.Gui);
setCullHint(CullHint.Never);

- this.rightToLeft = rightToLeft;
- this.font = font;
- this.block = new StringBlock();
- block.setSize(font.getPreferredSize());
+ this.page = page;

- Material mat = font.getPage(0);
+ Material mat = font.getPage(page);
if (mat == null) {
throw new IllegalStateException("The font's texture was not found!");
}
@@ -102,98 +95,33 @@
color = null;
}
}
-
- public BitmapText(BitmapFont font, boolean rightToLeft) {
- this(font, rightToLeft, false);
+
+ BitmapTextPage(BitmapFont font, boolean arrayBased) {
+ this(font, arrayBased, 0);
}

- public BitmapText(BitmapFont font) {
- this(font, false, false);
+ BitmapTextPage(BitmapFont font) {
+ this(font, false, 0);
}

@Override
- public BitmapText clone() {
- BitmapText clone = (BitmapText) super.clone();
+ public BitmapTextPage clone() {
+ BitmapTextPage clone = (BitmapTextPage) super.clone();
clone.mesh = mesh.deepClone();
- clone.needRefresh = true;
clone.quadList = new QuadList();
- clone.block = block.clone();
return clone;
}

- public BitmapFont getFont() {
- return font;
- }
+

- public void setSize(float size) {
- block.setSize(size);
- needRefresh = true;
- }

- public void setText(CharSequence text) {
- if (block.getText().equals(text)) {
- return;
- }
-
- block.setText(text);
- needRefresh = true;
- }
-
- public String getText() {
- return block.getText();
- }
-
- public ColorRGBA getColor() {
- return block.getColor();
- }
-
- public void setColor(ColorRGBA color) {
- if (block.getColor().equals(color)) {
- return;
- }
-
- block.setColor(color);
- needRefresh = true;
- }
-
- public void setBox(Rectangle rect) {
- block.setTextBox(rect);
- needRefresh = true;
- }
-
- public float getLineHeight() {
- return font.getLineHeight(block);
- }
-
- public float getLineWidth() {
- if (needRefresh) {
- assemble();
- }
- return lineWidth;
- }
-
- public void setAlignment(BitmapFont.Align align) {
- block.setAlignment(align);
- }
-
- public BitmapFont.Align getAlignment() {
- return block.getAlignment();
- }
-
- @Override
- public void updateLogicalState(float tpf) {
- super.updateLogicalState(tpf);
- if (needRefresh) {
- assemble();
- }
- }
-
- private void assemble() {
+ float assemble(BitmapFont font, StringBlock block, boolean rightToLeft) {
+ float lineWidth = 0;
// first generate quadlist
if (block.getTextBox() == null) {
- lineWidth = font.updateText(block, quadList, rightToLeft);
+ lineWidth = font.updateText(block, quadList, rightToLeft, page);
} else {
- lineWidth = font.updateTextRect(block, quadList);
+ lineWidth = font.updateTextRect(block, quadList, page);
}

Mesh m = getMesh();
@@ -251,7 +179,7 @@
ftb.rewind();
sib.rewind();
bcb.rewind();
-
- needRefresh = false;
+
+ return lineWidth;
}
}
Index: src/core-plugins/com/jme3/font/plugins/BitmapFontLoader.java
===================================================================
--- src/core-plugins/com/jme3/font/plugins/BitmapFontLoader.java (revision 6420)
+++ src/core-plugins/com/jme3/font/plugins/BitmapFontLoader.java (working copy)
@@ -142,6 +142,8 @@
ch.setYOffset(Integer.parseInt(tokens));
}else if (token.equals("xadvance")){
ch.setXAdvance(Integer.parseInt(tokens));
+ } else if (token.equals("page")) {
+ ch.setPage(Integer.parseInt(tokens));
}
}
}else if (tokens[0].equals("kerning")){
Index: src/niftygui/com/jme3/niftygui/RenderDeviceJme.java
===================================================================
--- src/niftygui/com/jme3/niftygui/RenderDeviceJme.java (revision 6420)
+++ src/niftygui/com/jme3/niftygui/RenderDeviceJme.java (working copy)
@@ -197,7 +197,7 @@
tempMat.setScale(size, size, 0);

rm.setWorldMatrix(tempMat);
- niftyMat.render(text, rm);
+ text.render(rm, niftyMat);
}

public void renderImage(RenderImage image, int x, int y, int w, int h,

[/patch]

Very good! Unfortunately I am having some trouble applying the patch here. Perhaps you can provide the source files instead? Or you can just commit it yourself if thats easier

committed rev. 6424. :wink:

Thanks! Hopefully this won’t break any existing code :slight_smile:

Momoko_Fan said:
Thanks! Hopefully this won't break any existing code :)

I hope so.
Only one problem I found is multi-page BitmapText doesn't work on NiftyGUI.
Single-page BitmapText works well as before.
Now I'm looking at it.

I fixed it in SVN already.



Issue was that when you setText() many times but use less FontQuads, the unused ones will remain. You have to call setSize(0,0) on any unused quads.

Having issues with that.



When loading the game I get this (after updating to the latest version):



[java]

java.lang.IllegalArgumentException: Material parameter is not defined: m_VertexColor

at com.jme3.material.Material.checkSetParam(Material.java:283)

at com.jme3.material.Material.setParam(Material.java:298)

at com.jme3.material.Material.setBoolean(Material.java:396)

at com.jme3.font.plugins.BitmapFontLoader.load(BitmapFontLoader.java:117)

at com.jme3.asset.DesktopAssetManager.loadAsset(DesktopAssetManager.java:224)

at com.jme3.asset.DesktopAssetManager.loadFont(DesktopAssetManager.java:314)

at com.jme3.niftygui.RenderFontJme.<init>(RenderFontJme.java:55)

at com.jme3.niftygui.RenderDeviceJme.createFont(RenderDeviceJme.java:124)

at de.lessvoid.nifty.render.NiftyRenderEngineImpl.createFont(NiftyRenderEngineImpl.java:151)

at de.lessvoid.nifty.loaderv2.types.apply.Convert.font(Convert.java:35)

at de.lessvoid.nifty.loaderv2.types.apply.ApplyRenderText.apply(ApplyRenderText.java:23)

at de.lessvoid.nifty.loaderv2.types.apply.ApplyAttributes.applyRenderer(ApplyAttributes.java:81)

at de.lessvoid.nifty.loaderv2.types.apply.ApplyAttributes.perform(ApplyAttributes.java:56)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyAttributes(ElementType.java:250)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyStandard(ElementType.java:171)

at de.lessvoid.nifty.loaderv2.types.ElementType.create(ElementType.java:143)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyChildren(ElementType.java:276)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyStandard(ElementType.java:174)

at de.lessvoid.nifty.loaderv2.types.ElementType.create(ElementType.java:143)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyChildren(ElementType.java:276)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyStandard(ElementType.java:174)

at de.lessvoid.nifty.loaderv2.types.ElementType.create(ElementType.java:143)

at de.lessvoid.nifty.loaderv2.types.ScreenType.create(ScreenType.java:75)

at de.lessvoid.nifty.loaderv2.types.NiftyType.create(NiftyType.java:118)

at de.lessvoid.nifty.Nifty.loadFromFile(Nifty.java:406)

at de.lessvoid.nifty.Nifty.fromXml(Nifty.java:307)

at com.madjack.games.sc.utils.MenuUpdater.loadStartMenu(MenuUpdater.java:189)

at com.madjack.games.sc.utils.MenuUpdater.doCommand(MenuUpdater.java:103)

at com.madjack.games.sc.utils.MenuUpdater.setCommand(MenuUpdater.java:159)

at com.madjack.games.sc.Game.startGUI(Game.java:155)

at com.madjack.games.sc.Game.startUp(Game.java:149)

at com.madjack.games.sc.Game.initialize(Game.java:105)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:134)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:188)

at java.lang.Thread.run(Thread.java:662)

[/java]

Tried rebuilding jME3 but partial success.



I get:



[java]

C:UsersDanyjMonkeyProjectsjme3srcniftyguicomjme3niftyguiRenderDeviceJme.java:200: render(com.jme3.renderer.RenderManager) in com.jme3.font.BitmapText cannot be applied to (com.jme3.renderer.RenderManager,com.jme3.material.Material)

text.render(rm, niftyMat);

[/java]



After changing that method from



[java] text.render(rm, niftyMat);[/java]



to



[java] text.render(rm);[/java]



Rebuild works, but I now get this when running the game:



[java]

java.lang.NullPointerException

at com.jme3.niftygui.RenderFontJme.<init>(RenderFontJme.java:56)

at com.jme3.niftygui.RenderDeviceJme.createFont(RenderDeviceJme.java:124)

at de.lessvoid.nifty.render.NiftyRenderEngineImpl.createFont(NiftyRenderEngineImpl.java:151)

at de.lessvoid.nifty.loaderv2.types.apply.Convert.font(Convert.java:35)

at de.lessvoid.nifty.loaderv2.types.apply.ApplyRenderText.apply(ApplyRenderText.java:23)

at de.lessvoid.nifty.loaderv2.types.apply.ApplyAttributes.applyRenderer(ApplyAttributes.java:81)

at de.lessvoid.nifty.loaderv2.types.apply.ApplyAttributes.perform(ApplyAttributes.java:56)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyAttributes(ElementType.java:250)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyStandard(ElementType.java:171)

at de.lessvoid.nifty.loaderv2.types.ElementType.create(ElementType.java:143)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyChildren(ElementType.java:276)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyStandard(ElementType.java:174)

at de.lessvoid.nifty.loaderv2.types.ElementType.create(ElementType.java:143)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyChildren(ElementType.java:276)

at de.lessvoid.nifty.loaderv2.types.ElementType.applyStandard(ElementType.java:174)

at de.lessvoid.nifty.loaderv2.types.ElementType.create(ElementType.java:143)

at de.lessvoid.nifty.loaderv2.types.ScreenType.create(ScreenType.java:75)

at de.lessvoid.nifty.loaderv2.types.NiftyType.create(NiftyType.java:118)

at de.lessvoid.nifty.Nifty.loadFromFile(Nifty.java:406)

at de.lessvoid.nifty.Nifty.fromXml(Nifty.java:307)

at com.madjack.games.sc.utils.MenuUpdater.loadStartMenu(MenuUpdater.java:189)

at com.madjack.games.sc.utils.MenuUpdater.doCommand(MenuUpdater.java:103)

at com.madjack.games.sc.utils.MenuUpdater.setCommand(MenuUpdater.java:159)

at com.madjack.games.sc.Game.startGUI(Game.java:155)

at com.madjack.games.sc.Game.startUp(Game.java:149)

at com.madjack.games.sc.Game.initialize(Game.java:105)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:134)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:188)

at java.lang.Thread.run(Thread.java:662)

Jan 13, 2011 2:37:22 PM de.lessvoid.nifty.Nifty gotoScreenInternal

WARNING: screen [loadingScreen] not found

[/java]



loadingScreen does exist, it was working before I updated. Something else is not found that makes it unable to find the .xml file, thus the loadingScreen.

Kinda fixed it but there seem to be an issue with font color. At least now it’s loading properly. I’ll try to find why and post the diff.



Here’s the diff to have it work, although it’s crippled, now my game can load and I can test changes, which is something I couldn’t do before that. Hopefully that’ll help someone.



[patch]

This patch file was generated by NetBeans IDE

It uses platform neutral UTF-8 encoding and n newlines.

— Base (BASE)

+++ Locally Modified (Based On LOCAL)

@@ -53,7 +53,7 @@

public RenderFontJme(String name, NiftyJmeDisplay display) {

this.display = display;

font = display.getAssetManager().loadFont(name);

  •    texture = font.getPage(0).getTextureParam(&quot;m_Texture&quot;).getTextureValue();<br />
    

No newline at end of file

  •    texture = font.getPage(0).getTextureParam(&quot;m_ColorMap&quot;).getTextureValue();<br />
    

No newline at end of file

text = new BitmapText(font);

actualSize = font.getPreferredSize();

text.setSize(actualSize);

[/patch]



[patch]

This patch file was generated by NetBeans IDE

It uses platform neutral UTF-8 encoding and n newlines.

— Base (BASE)

+++ Locally Modified (Based On LOCAL)

@@ -197,7 +197,7 @@

tempMat.setScale(size, size, 0);



rm.setWorldMatrix(tempMat);

  •    text.render(rm, niftyMat);<br />
    
  •    text.render(rm);<br />
    

}



public void renderImage(RenderImage image, int x, int y, int w, int h,

[/patch]

Another new problem is that for some reason, text attached to rotated node is also rotated in very strange manner. Letters are ‘looking up’ but text going into different direction (top to down in my case). Instead of



MyText



I’m getting



M

y

T

e

x

t

@madjack it’s fixed in SVN

1 Like

Ok, I know what is causing my up-to-down text problem. I was trying to center the text at given point by doing,



[java]

float lineWidth = helloText.getLineWidth();

helloText.setBox(new Rectangle(-lineWidth / 2, 0, lineWidth * 1.01f, helloText.getLineHeight()));

[/java]



It used to work one week ago. Right now, getLineWidth() is always returning zero, which was causing the text to wrap on each letter.



For now, I have replaced my local copy of BitmapText.assemble with



[java]

private void assemble() {

lineWidth = 0;

for (BitmapTextPage page : textPages) {

lineWidth+=page.assemble(font, block, rightToLeft);

}

needRefresh = false;

}

[/java]



but I have no idea if it will work correctly with multiple text pages (whatever they are).

Thanks nehon. I confirm the fix works properly. :slight_smile:


[java]
private void assemble() {
lineWidth = 0;
for (BitmapTextPage page : textPages) {
lineWidth+=page.assemble(font, block, rightToLeft);
}
needRefresh = false;
}
[/java]

but I have no idea if it will work correctly with multiple text pages (whatever they are).

Actually all page returns same lineWidth.
lineWidth=page.assemble(font, block, rightToLeft);

Thank you. fixed in rev. 6434

I introduced BitmapText.getHeight() method.

getLineHeight() returns one-line height, so can’t get multi-line text height.

And removing stdout log code.



[patch]

Index: src/test/jme3test/gui/TestBitmapFont.java

===================================================================

— src/test/jme3test/gui/TestBitmapFont.java (revision 6433)

+++ src/test/jme3test/gui/TestBitmapFont.java (working copy)

@@ -54,13 +54,13 @@

txt.setBox(new Rectangle(0, 0, settings.getWidth(), settings.getHeight()));

txt.setSize(fnt.getPreferredSize() * 2f);

txt.setText(txtB);

  •    txt.setLocalTranslation(0, settings.getHeight(), 0);<br />
    
  •    txt.setLocalTranslation(0, txt.getHeight(), 0);<br />
    

guiNode.attachChild(txt);



BitmapText txt4 = new BitmapText(fnt, false);

txt4.setSize(fnt.getPreferredSize() * 1.2f);

txt4.setText("Text without restriction. nText without restriction. Text without restriction. Text without restriction");

  •    txt4.setLocalTranslation(40, txt4.getLineHeight() * 2, 0);<br />
    
  •    txt4.setLocalTranslation(40, txt4.getHeight(), 0);<br />
    

guiNode.attachChild(txt4);

}



Index: src/core/com/jme3/font/StringBlock.java

===================================================================

— src/core/com/jme3/font/StringBlock.java (revision 6433)

+++ src/core/com/jme3/font/StringBlock.java (working copy)

@@ -49,6 +49,7 @@

private float size;

private ColorRGBA color = new ColorRGBA(ColorRGBA.White);

private boolean kerning;

  • private int lineCount;



    /**

    *

    @@ -145,4 +146,13 @@

    public void setKerning(boolean kerning) {

    this.kerning = kerning;

    }

    +
  • public int getLineCount() {
  •    return lineCount;<br />
    
  • }

    +
  • void setLineCount(int lineCount) {
  •    this.lineCount = lineCount;<br />
    
  • }

    +

    }

    Index: src/core/com/jme3/font/BitmapText.java

    ===================================================================

    — src/core/com/jme3/font/BitmapText.java (revision 6434)

    +++ src/core/com/jme3/font/BitmapText.java (working copy)

    @@ -122,6 +122,18 @@

    return font.getLineHeight(block);

    }


  • public float getHeight() {
  •    if (needRefresh) {<br />
    
  •        assemble();<br />
    
  •    }<br />
    
  •    float height = getLineHeight()*block.getLineCount();<br />
    
  •    Rectangle textBox = block.getTextBox();<br />
    
  •    if (textBox != null) {<br />
    
  •        return Math.max(height, textBox.height);<br />
    
  •    }<br />
    
  •    return height;<br />
    
  • }

    +

    public float getLineWidth() {

    if (needRefresh) {

    assemble();

    Index: src/core/com/jme3/font/BitmapFont.java

    ===================================================================

    — src/core/com/jme3/font/BitmapFont.java (revision 6433)

    +++ src/core/com/jme3/font/BitmapFont.java (working copy)

    @@ -331,6 +331,7 @@

    lastChar = c;

    }

    }
  •    block.setLineCount(lineNumber);<br />
    

return Math.max(lineWidth, maxLineWidth);
}
Index: src/niftygui/com/jme3/niftygui/RenderFontJme.java
===================================================================
--- src/niftygui/com/jme3/niftygui/RenderFontJme.java (revision 6433)
+++ src/niftygui/com/jme3/niftygui/RenderFontJme.java (working copy)
@@ -53,7 +53,6 @@
public RenderFontJme(String name, NiftyJmeDisplay display) {
this.display = display;
font = display.getAssetManager().loadFont(name);
- System.out.println(name);
texture = font.getPage(0).getTextureParam("m_ColorMap").getTextureValue();
text = new BitmapText(font);
actualSize = font.getPreferredSize();

[/patch]
1 Like

committed. 6469

Thanks!