TrueType font loader

Hi,



I had problems finding appropriate fnt fonts so I’ve implemented a loader for much more popular ttf :smiley:

Hope it will be useful :wink:



Here’s the loader:

package com.jme3.font.plugins;



import java.awt.Color;

import java.awt.Font;

import java.awt.FontFormatException;

import java.awt.FontMetrics;

import java.awt.Graphics2D;

import java.awt.GraphicsConfiguration;

import java.awt.GraphicsEnvironment;

import java.awt.RenderingHints;

import java.awt.Transparency;

import java.awt.font.GlyphMetrics;

import java.awt.font.GlyphVector;

import java.awt.geom.AffineTransform;

import java.awt.image.BufferedImage;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;



import com.jme3.asset.AssetInfo;

import com.jme3.asset.AssetKey;

import com.jme3.asset.AssetLoader;

import com.jme3.asset.FontKey;

import com.jme3.font.BitmapCharacter;

import com.jme3.font.BitmapCharacterSet;

import com.jme3.font.BitmapFont;

import com.jme3.material.Material;

import com.jme3.material.MaterialDef;

import com.jme3.material.RenderState.BlendMode;

import com.jme3.math.ColorRGBA;

import com.jme3.texture.Image;

import com.jme3.texture.Texture;

import com.jme3.texture.Texture2D;

import com.jme3.texture.plugins.AWTLoader;



/**

  • This class loads the font stored in TrueType file format.
  • @author Marcin Roguski

    */

    public class TTFFontLoader implements AssetLoader {

    /**
  • @see AssetLoader
  • @throws IllegalArgumentException
  •     an exception is thrown if the asset key is not of FontKey type<br />
    

*/

@Override

public Object load(AssetInfo assetInfo) throws IOException {

if(assetInfo.getKey() instanceof FontKey) {

Graphics2D graphics = this.getGraphics();

FontKey fontKey = (FontKey)assetInfo.getKey();

Font font = this.getFont(assetInfo);

graphics.setFont(font);

FontData fontData = this.calculateFontData(graphics, fontKey);

Texture t = this.prepareTexture(fontData, graphics, fontKey.getColor());

this.setPagesForFont(assetInfo, fontData.bitmapFont, t);

return fontData.bitmapFont;

} else {

throw new IllegalArgumentException("The given asset key should be of type: " + FontKey.class.getName());

}

}



/**

  • Creates the AWT graphics object to render the fonts.
  • @return AWT graphics object

    */

    protected Graphics2D getGraphics() {

    GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();

    return gc.createCompatibleImage(1, 1, Transparency.TRANSLUCENT).createGraphics();

    }



    /**
  • This method loads AWT type font from the stream indicated by assetInfo.
  • @param assetInfo
  •    the information about font asset<br />
    
  • @return AWT type font
  • @throws IOException
  •     an exception is thrown if there are problems with the stream<br />
    
  •     itself or with the font type (it should be TrueType)<br />
    

*/

protected Font getFont(AssetInfo assetInfo) throws IOException {

try {

FontKey fontKey = (FontKey)assetInfo.getKey();

return Font.createFont(fontKey.getType(), assetInfo.openStream()).deriveFont(fontKey.getStyle(), fontKey.getSize());

} catch(FontFormatException e) {

throw new IOException(e.getMessage(), e);

}

}



/**

  • This method reads all available fonts and prepares the basic data about
  • its characters.
  • @param graphics
  •    the graphics object that will later prepare the image of the fonts<br />
    
  • @param fontKey
  •    the key containing essential font information<br />
    
  • @return the basic data about the font

    */

    protected FontData calculateFontData(Graphics2D graphics, FontKey fontKey) {

    Font font = graphics.getFont();

    FontMetrics fontMetrics = graphics.getFontMetrics();

    int glyphsAmount = font.getNumGlyphs(), i = 0;

    int missingGlyphCode = font.getMissingGlyphCode();

    char[] chars = new char[] {0};



    FontData result = new FontData();

    result.bitmapFont = new BitmapFont();

    result.bitmapFont.setCharSet(new BitmapCharacterSet());

    result.bitmapFont.getCharSet().setRenderedSize(font.getSize());

    result.charList = new ArrayList<TTFFontLoader.CharacterData>();



    while(i < glyphsAmount) {

    GlyphVector gv = font.createGlyphVector(graphics.getFontRenderContext(), chars);

    int glyphCode = gv.getGlyphCode(0);

    GlyphMetrics gm = gv.getGlyphMetrics(0);

    if(glyphCode != missingGlyphCode && glyphCode < glyphsAmount && result.bitmapFont.getCharSet().getCharacter((int)chars[0]) == null) {

    BitmapCharacter bitmapCharacter = new BitmapCharacter();

    bitmapCharacter.setWidth(Character.isWhitespace(chars[0]) ? (int)Math.ceil(gm.getAdvanceX()) : (int)Math.ceil(gm.getBounds2D().getWidth()));

    bitmapCharacter.setXAdvance((int)Math.ceil(gm.getAdvanceX()));

    result.bitmapFont.getCharSet().addCharacter((int)chars[0], bitmapCharacter);



    result.imageWidth += bitmapCharacter.getWidth() + (int)Math.ceil(Math.abs(gm.getLSB()));//LSB only affects the render image width

    result.imageHeight = (int)Math.ceil(Math.max(result.imageHeight, gv.getGlyphVisualBounds(0).getBounds2D().getHeight()));

    result.charList.add(new CharacterData(chars[0], gm.getLSB(), bitmapCharacter));

    ++i;

    } else if(Character.isWhitespace(chars[0])) {

    ++i;

    }

    chars[0] = (char)(chars[0] + 1);

    }

    int ascentBuffer = this.parseBuffer(fontKey.getAboveAscentBuffer(), result.imageHeight);

    int descentBuffer = this.parseBuffer(fontKey.getAboveAscentBuffer(), result.imageHeight);

    result.imageHeight += ascentBuffer + descentBuffer;

    result.bitmapFont.getCharSet().setBase(fontMetrics.getMaxAscent()+ascentBuffer);//we move the base down by the value of ascentBuffer

    result.bitmapFont.getCharSet().setLineHeight(fontMetrics.getMaxAscent() + fontMetrics.getMaxDescent()+ascentBuffer+descentBuffer);

    result.bitmapFont.getCharSet().setRenderedSize(font.getSize());

    return result;

    }



    /**
  • This mehtod parsers the buffer value.
  • The value should be a numeric value that ends in ‘%’, ‘px’ or nothing.
  • ‘px’ is a default measure unit.
  • @param buffer the buffer value to be parsed
  • @param imageHeight the height of the image; required if the buffer value
  • is given in percents
  • @return an integer value of buffer height in pixels

    */

    protected int parseBuffer(String buffer, int imageHeight) {

    if(buffer==null || buffer.isEmpty()) {

    return 0;

    }

    if(buffer.endsWith("%")) {

    String value = buffer.split("%")[0];

    float percent = Float.parseFloat(value);

    if(percent!=0.0f) {

    percent = 1.0f/percent;

    }

    return (int)Math.round(imageHeight * percent);

    }

    else if(buffer.endsWith(“px”)) {

    String value = buffer.split(“px”)[0];

    return (int)Float.parseFloat(value);

    }

    return 0;

    }



    /**
  • This method prepares the jme texture for the font. It also sets the rest
  • of data required by font data.
  • @param fontData
  •    the data of the font<br />
    
  • @param graphics
  •    the object that renders the font<br />
    
  • @return font’s texture

    */

    protected Texture prepareTexture(FontData fontData, Graphics2D graphics, Color fontColor) {

    BufferedImage bufferedImage = graphics.getDeviceConfiguration().createCompatibleImage(fontData.imageWidth, fontData.imageHeight, Transparency.TRANSLUCENT);



    //prepare the graphics object to render the font

    Graphics2D imageGraphics = (Graphics2D)bufferedImage.getGraphics();

    imageGraphics.setFont(graphics.getFont());

    imageGraphics.setColor(fontColor);

    imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);



    //we need to mirror the image vertically (do not know why, but the engine redners it up-side down :slight_smile: )

    AffineTransform at = new AffineTransform();

    at.scale(1.0, -1.0);

    at.translate(0.0, -bufferedImage.getHeight());

    imageGraphics.transform(at);



    //render each font and fill the x and y positions data and its height

    int xPos = 0;

    int base = fontData.bitmapFont.getCharSet().getBase();

    char[] chars = new char[1];

    for(CharacterData characterData : fontData.charList) {

    chars[0] = characterData.character;

    characterData.bitmapCharacter.setXOffset(characterData.lsb);

    characterData.bitmapCharacter.setX(xPos);

    characterData.bitmapCharacter.setY(0);

    characterData.bitmapCharacter.setHeight(bufferedImage.getHeight());

    //move the char so that when it is rendered it won’t hit other characters

    xPos -= characterData.lsb;

    imageGraphics.drawChars(chars, 0, 1, xPos, base);

    xPos += characterData.lsb + characterData.bitmapCharacter.getWidth() + characterData.widthDelta;

    }

    //set the size of the bitmap

    fontData.bitmapFont.getCharSet().setHeight(bufferedImage.getHeight());

    fontData.bitmapFont.getCharSet().setWidth(bufferedImage.getWidth());



    //create the texture

    Image image = new AWTLoader().load(bufferedImage, false);

    Texture texture = new Texture2D(image);

    texture.setMagFilter(Texture.MagFilter.Bilinear);

    texture.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);

    return texture;

    }



    /**
  • This method sets the pages for font. For now only one page is supported.
  • @param assetInfo
  •    the information about the font asset<br />
    
  • @param bitmapFont
  •    the result bitmap font where the data will be stored<br />
    
  • @param textures
  •    a list of textures to apply to the bitmap font pages (one texture<br />
    
  •    per page)<br />
    

*/

@SuppressWarnings({“unchecked”, “rawtypes”})

protected void setPagesForFont(AssetInfo assetInfo, BitmapFont bitmapFont, Texture… textures) {

Material[] pages = new Material[textures.length];

MaterialDef spriteMat = (MaterialDef)assetInfo.getManager().loadAsset(new AssetKey(“Common/MatDefs/Gui/Gui.j3md”));

for(int i = 0; i < textures.length; ++i) {

Material mat = new Material(spriteMat);

mat.setTexture(“m_Texture”, textures);

mat.setColor(“m_Color”, ColorRGBA.White);

mat.setBoolean(“m_VertexColor”, true);

mat.getAdditionalRenderState().setBlendMode(BlendMode.AlphaAdditive);

pages = mat;

}

bitmapFont.setPages(pages);

}



/**

  • Internal data aggregator class. It stores the result BitmapFont class. It
  • also contains a list of characters data (calculated first and then passed
  • to the method that renders the font texture). It also contains the size
  • of the result image.
  • @author Marcin Roguski

    */

    protected static class FontData {

    public BitmapFont bitmapFont;

    public List charList;

    public int imageWidth;

    public int imageHeight;

    }



    /**
  • A class containing the data of a single character. The data contained:
  • the character itself, the left (top) side bearing of the glyph (see
  • java.awt.font.GlyphMetrics.getLSB()), the bitmap character that will be
  • stored in the output data
  • @author Marcin Roguski

    */

    protected static class CharacterData {

    public char character;

    public int lsb;

    public int widthDelta;

    public BitmapCharacter bitmapCharacter;



    public CharacterData(char character, float lsb, BitmapCharacter bitmapCharacter) {

    this.character = character;

    this.lsb = (int)Math.floor(lsb);//that is the distace the character will be moved before rendering

    this.widthDelta = (int)Math.ceil(Math.abs(lsb));//that is width modification caused by lsb

    this.bitmapCharacter = bitmapCharacter;

    }

    }

    }





    And here is the font key class:

    package com.jme3.asset;



    import java.awt.Color;

    import java.awt.Font;

    import java.io.IOException;



    import com.jme3.export.InputCapsule;

    import com.jme3.export.JmeExporter;

    import com.jme3.export.JmeImporter;

    import com.jme3.export.OutputCapsule;

    import com.jme3.font.BitmapFont;



    /**
  • A key to find fonts in asset manager.
  • @author Marcin Roguski

    */

    public class FontKey extends AssetKey {

    /**
  • The type of the font. available values: Font.TRUETYPE_FONT,
  • Font.TYPE1_FONT

    /

    protected int type;

    /
    * The size of the font (should be greater than zero of course). /

    protected int size;

    /
    * The color of the font. */

    protected Color color;

    /**
  • The style of the font; available values: Font.ITALIC, Font.PLAIN,
  • Font.BOLD.

    */

    protected int style;

    /**
  • The amount of pixels to be added above the ascent line. Available units:
  • %, px.

    */

    protected String aboveAscentBuffer;



    /**
  • The amount of pixels to be added below the descent line. Available units:
  • %, px.

    */

    protected String belowDescentBuffer;



    /**
  • Constructor with the aseet name. The constructor does not validate the
  • given data. If the data is wrong it will arise exceptions during font
  • creation. The aboveAscent and belowDescent buffers are both set to 0.
  • @param fontName
  •    the name of the font asset<br />
    
  • @param type
  •    the type of the font; available values: Font.TRUETYPE_FONT,<br />
    
  •    Font.TYPE1_FONT<br />
    
  • @param color
  •    the color of the font<br />
    
  • @param size
  •    the size of the font (should be greater than zero of course)<br />
    
  • @param style
  •    the style of the font; available values: Font.ITALIC, Font.PLAIN,<br />
    
  •    Font.BOLD<br />
    

*/

public FontKey(String fontName, int type, Color color, int size, int style) {

super(fontName);

this.type = type;

this.color = color;

this.size = size;

this.style = style;

}



/**

  • Constructor with the aseet name. The constructor does not validate the
  • given data. If the data is wrong it will arise exceptions during font
  • creation.
  • @param fontName
  •    the name of the font asset<br />
    
  • @param type
  •    the type of the font; available values: Font.TRUETYPE_FONT,<br />
    
  •    Font.TYPE1_FONT<br />
    
  • @param color
  •    the color of the font<br />
    
  • @param size
  •    the size of the font (should be greater than zero of course)<br />
    
  • @param style
  •    the style of the font; available values: Font.ITALIC, Font.PLAIN,<br />
    
  •    Font.BOLD<br />
    
  • @param aboveAscentBuffer
  •    the amount of pixels to be added above the ascent line<br />
    
  • @param belowDescentBuffer
  •    the amount of pixels to be added below the descent line<br />
    

*/

public FontKey(String fontName, int type, Color color, int size, int style, String aboveAscentBuffer, String belowDescentBuffer) {

this(fontName, type, color, size, style);

this.aboveAscentBuffer = aboveAscentBuffer;

this.belowDescentBuffer = belowDescentBuffer;

}



/**

  • This method returns the type of the font.
  • @return the type of the font

    */

    public int getType() {

    return type;

    }



    /**
  • This method returns the color of the font.
  • @return the color of the font

    */

    public Color getColor() {

    return color;

    }



    /**
  • This method returns the size of the font.
  • @return the size of the font

    */

    public int getSize() {

    return size;

    }



    /**
  • This method returns the style of the font.
  • @return the style of the font

    */

    public int getStyle() {

    return style;

    }



    /**
  • This method returns the amount of pixels to be added above the ascent
  • line.
  • @return the amount of pixels to be added above the ascent line

    */

    public String getAboveAscentBuffer() {

    return aboveAscentBuffer;

    }



    /**
  • This method returns the amount of pixels to be added below the descent
  • line.
  • @return the amount of pixels to be added below the descent line

    */

    public String getBelowDescentBuffer() {

    return belowDescentBuffer;

    }



    @Override

    public void write(JmeExporter ex) throws IOException {

    super.write(ex);

    OutputCapsule oc = ex.getCapsule(this);

    oc.write(type, “type”, Font.TRUETYPE_FONT);

    oc.write(size, “size”, 18);

    oc.write(style, “style”, Font.PLAIN);

    oc.write(new float[] {color.getRed(), color.getGreen(), color.getBlue()}, “color”, null);

    }



    @Override

    public void read(JmeImporter im) throws IOException {

    super.read(im);

    InputCapsule ic = im.getCapsule(this);

    type = ic.readInt(“type”, Font.TRUETYPE_FONT);

    size = ic.readInt(“size”, 18);

    style = ic.readInt(“style”, Font.PLAIN);

    float[] colorTable = ic.readFloatArray(“color”, new float[] {0.0f, 0.0f, 0.0f});

    color = new Color(colorTable[0], colorTable[1], colorTable[2]);

    }



    @Override

    public int hashCode() {

    final int prime = 31;

    int result = super.hashCode();

    result = prime * result + ((color == null) ? 0 : color.hashCode());

    result = prime * result + size;

    result = prime * result + style;

    result = prime * result + type;

    return result;

    }



    @Override

    public boolean equals(Object obj) {

    if(this == obj) {

    return true;

    }

    if(!super.equals(obj)) {

    return false;

    }

    if(getClass() != obj.getClass()) {

    return false;

    }

    FontKey other = (FontKey)obj;

    if(color == null) {

    if(other.color != null) {

    return false;

    }

    } else if(!color.equals(other.color)) {

    return false;

    }

    if(size != other.size) {

    return false;

    }

    if(style != other.style) {

    return false;

    }

    if(type != other.type) {

    return false;

    }

    return true;

    }

    }

5 Likes

Wow, cool! Thanks for the contribution!

Cheers,

Normen

Very cool, I like the idea and everything :smiley:

A few things, by the way:

  1. You don’t need to consider the color of the text (just make it white). You can change the color dynamically using BitmapText.setColor()
  2. You can have much more efficient font glyph packing by using JOGL’s RectanglePacker class.

I tried adding this to jME3, I think there might be a bug:

Can you give me the name of the font you use or post a link to it?

I’ll check this when I return home.

I’m 99% certain the problem is with calculating uv mappings for the texture.



As for the color, you can always use the value from the key as a default color for the font and change it later if there is a need :wink: .

OK, I’ve made some bugfixing.

The font should look ok now. I had some problems calculating the width of the font and that caused the bad look :wink:



I also fixed a bug that caused not loading all the characters in some fonts.

And the generic type of FontKey is changed. Now it extends the AssetKey[BitmapFont] instead of AssetKey[Font].



I’ve posted the fixed code inside the first topic. Just to make less mess here.



Cheers,

Kaelthas



P.S.

The code of FontKey of course derives from AssetKey[BitmapFont] not from the raw type AssetKey.

It seems like the forum is interpreting tags inside the ‘code’ closure.

The same goes for emoticons used in the commented lines (changed into picture link).

Could you guys please check this out? :slight_smile:

Hi,



once again I changed the code a little :wink:


  1. All methods in the loader are protected or public in case someone needed to change its beaviuor.
  2. I’ve added ascent and descent buffer to the FontKey. I came across a font whose characters are drawn above the ascent and below the descent line.

    I couln’t find any parameter that could give me the proper measures of those characters so I’ve added a buffer so that they can be safely drawn.



    If someone knows how to find out the heights above ascent line and below descent line please let me know.





    Cheers,

    Kaelthas

This font loader is very useful!



The downside of the font loader is that it requires a FontKey. I wanted to use truetype fonts in nifty, so that was a problem. As a solution, I wrote my own AssetLocator which is able to convert asset names into FontKeys. To do so, it uses a syntax which enables the size, color and style of the font to be specified.



For example, assetManager.loadFont(“font(15,0xFF0000,italic):Fonts/MyFont.ttf”) would load the font called Fonts/MyFont.ttf with a size of 15, red, italic. Font style and color are optional.



Enjoy!



[java]package com.jme3.asset;



import com.jme3.asset.plugins.ClasspathLocator;

import java.awt.Color;

import java.awt.Font;



/**

  • Enables truetype fonts to be loaded using a location string.

    *
  • String format:
  • font(size):font_resource_name
  • font(size,color):font_resource_name
  • font(size,color,style):font_resource_name

    *
  • Color is expressed in hex (0xRRGGBB). Style can be BOLD or ITALIC. Default
  • color is black.

    *
  • Example: font(15,0xFF0000,BOLD):Fonts/MyFont.ttf

    *
  • Registering the locator: assetManager.registerLocator("", FontLocator.class);
  • Don’t forget to register the TTF FontLoader:
  • assetManager.registerLoader(TTFFontLoader.class.getName(), “ttf”);

    *
  • @author Stan Hebben

    /

    public class FontLocator implements AssetLocator {

    private AssetLocator base;



    public FontLocator() {

    base = new ClasspathLocator();

    }



    public void setRootPath(String rootPath) {

    base.setRootPath(rootPath);

    }



    public AssetInfo locate(AssetManager manager, AssetKey key) {

    if (!key.getName().startsWith(“font(”)) {

    return null;

    } else {

    /
    Separate the query string from the asset name /

    int ix = key.getName().indexOf(’:’);

    String query = key.getName().substring(5, ix - 1);

    String name = key.getName().substring(ix + 1);



    /
    Split and process the query parameters /

    String[] params = query.split(",");

    int size = Integer.parseInt(params[0].trim());

    Color color;

    int style = Font.PLAIN;

    if (params.length > 1) {

    color = new Color(Integer.decode(params[1].trim()));



    if (params.length > 2) {

    String styleString = params[2].trim();

    if (styleString.toLowerCase().equals(“bold”)) {

    style = Font.BOLD;

    } else if (styleString.toLowerCase().equals(“italic”)) {

    style = Font.ITALIC;

    }

    }

    } else {

    color = Color.BLACK;

    }



    /
    Delegates the font location to the actualy loader */

    FontKey newkey = new FontKey(name, Font.TRUETYPE_FONT, color, size, style);

    return base.locate(manager, newkey);

    }

    }

    }

    [/java]
1 Like

Hi,



I’ve just recently added the TTFFontLoader class (I haven’t found it in the latest nightly build) and it’s just beautiful to be able to load ttf-fonts. Thanks for all the work. There is one minor thing though, which I’m not getting rid of, and I’m wondering if it’s because of the font I use, or maybe because of a bug in the loader. When I use text that uses a lower g, q or j, the hook of those is getting cut off, as if the box used for the font is too small for letters extending downwards. Any suggestions?



P.S.: I hope I’m allowed to use those classes? I’ve not found any disclaimer about “this and that person did all the stuff” and I thought I would at least want to add this information to the code as you duely deserve it (maybe a BSD License?)

I also found some minor errors in the loaded fonts (but not in all of them).

I’ll look into the loader when I have a little time to spare (I am working on blender loader for the time being :wink: ).



As for the licence it should be licenced as all other jme3 classes are. (GPL I belive).

But I have no objections to give it BSD license (if the core developers approve this of course). :slight_smile:

Pretty sure JME is BSD.

As I am new to JME platform, I’m finding difficulty to understand how to used this is TTFFontLoader and FontLocator ie putting the pieces together to get TTF fontloader to work. Can somebody kind enough to post some code/hints on how to used this. I tried to search on svn but mustang is down.

Just convert your truetype fonts using the FontCreator in jMP.

True Type font loader is not a part of jme as I am aware.

If you want to load ttf fonts use the code above in your app or create a library of it.

Then you’ll need to register the loader and locator to your AssetManager (there are topics on forum and in tutorials how to do that).



Or use the plugin in JMP and do the conversion as Normen suggested :wink:



Normen maybe we could add this loader to jme just like blender loader was added.

TTF is the most common font file I belive.

It would make things easier :wink:

Hi, i’m currently looking for custom font’s (by now only for custom size) for jme and i think this loader would be nice. Fonts are really important for good looking GUI’s and Games.

I only found the two jme fnt files in the data folder and wondered if i have to make my own in the same style(which would be no fun for me)!



If this will not become part of jme, perhaps it could be shared as lib via google code or something else!

I would test it in my own project and could provide bug reports and such things.



JMP is really nice but is a big overhead only for generating fonts .

You do not need jmp to generate fonts as there is another tool out there that can do it also. JMP provides a bunch of other cool things and so for people that are already using it (like me) it is convenient.



…but I generated my fonts with the AngelCode font utility: BMFont - AngelCode.com Because at the time JMP didn’t have it yet.

Help !

I used this insert to JME3 .but it have error.Debug in JMonkeyPlatform.



and this is error information.



/****************************************************

Deleting: E:MyDocumentsjMonkeyProjectsBasicGamebuildbuilt-jar.properties

deps-jar:

Updating property file: E:MyDocumentsjMonkeyProjectsBasicGamebuildbuilt-jar.properties

Compiling 2 source files to E:MyDocumentsjMonkeyProjectsBasicGamebuildclasses

警告: [options] 未与 -source 1.5 一起设置引导类路径

E:MyDocumentsjMonkeyProjectsBasicGamesrccomjme3fontpluginsTTFFontLoader.java:214: 不兼容的类型

for(CharacterData characterData : fontData.charList) {

需要: TTFFontLoader.CharacterData

找到: Object

注: E:MyDocumentsjMonkeyProjectsBasicGamesrccomjme3fontpluginsTTFFontLoader.java使用了未经检查或不安全的操作。

/**************************************************



It said “CharacterData” and “fontData.charList” isn’t the same type;

I currently don’t have a suite to actually test it, but replacing the line:



[java]imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);[/java]



with:



[java]

imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);

imageGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

[/java]



might improve the quality of text rendering.