Managing Bitmap Font assets in LibGdx - libgdx

I can load a Bitmap Font just fine with the following code:
BitmapFont font= new BitmapFont(
Gdx.files.internal( "Fonts/MyFont.fnt" ),
Gdx.files.internal( "Fonts/MyFont.png" ),
false );
but I'm trying to implement the AssetManager instead. So I recoded that snippet with the following code:
AssetManager assetManager = new AssetManager();
assetManager.load( "Fonts/MyFont.fnt", BitmapFont.class );
assetManager.load( "Fonts/MyFont.png", Texture.class );
assetManager.finishLoading();
BitmapFont font = assetManager.get( "Fonts/MyFont.fnt" );
If failed of course. The the call to the finishLoading() method returned a message indicating:
Couldn't load dependencies of asset: "Fonts/MyFont.fnt"
Ok. that makes sense, because I didn't do anything with the texture. So how do I pass the texture file as dependency? github.com/libgdx/libgdx/wiki/Managing-your-assets says:
BitmapFontLoader is a good example of an asynchronous loader that also
has dependencies that need to be loaded before the actual asset can be
loaded (in that case it's the texture storing the glyphs). Again, you
can do pretty much anything with this.
Well Duh! I guess they assume, "... if you only knew how!" But, their example doesn't show how - as a matter of fact their example shows pretty much what I've written. So, I'm stumped. All Google seems to be able to find are examples of what to do with TTF fonts, but nothing for regular old Bitmap Fonts.
Does anyone have an example of the solution to this error. Thanks a million!

When you use the AssetManager to load a BitmapFont is uses the BitmapFontLoader class. In the Libgdx api docs is says (api)
AssetLoader for BitmapFont instances. Loads the font description file (.fnt) asynchronously, loads the Texture containing the glyphs as a dependency.
The glyphs texture is automatically loaded as a dependency of the font. However, to know which file to load as the texture it checks in the .fnt file for the location of the texture.
I suspect that the reason that the font loaded successfully without using the AssetManager was because you manually added the Texture of the font as a parameter.
BitmapFont font= new BitmapFont(
Gdx.files.internal( "Fonts/MyFont.fnt" ),
Gdx.files.internal( "Fonts/MyFont.png" ), // This lets it know what texture to use
false );
When you used the AssetManager on the other hand it could not find/load the texture dependency. To fix this, open the .fnt file and make sure that the file="something.png" points to your fonts texture glyphs. (It must be the same as the name of the png. In your case file="MyFont.png")
That hopefully will solve your problem.
My tried and tested code:
AssetManager manager = new AssetManager();
manager.load("fonts/MyFont.fnt", BitmapFont.class);
manager.finishLoading();
font = manager.get("fonts/MyFont.fnt", BitmapFont.class);
An extract of the MyFont.fnt file:
info face=font size=54 bold=0 italic=0 charset= unicode= stretchH=100 smooth=1
aa=1 padding=2,2,2,2 spacing=0,0 outline=0 common lineHeight=50 base=43 scaleW=243
scaleH=511 pages=1 packed=0
page id=0 file="MyFont.png" <-- The important part
Hopefully that will solve your problem!
Also please note, as I was testing out the AssetManager I noticed that it only loaded when the .fnt was in basic text. When I tried use a .fnt file which used tags (like html) the texture failed to load. I used littera to generate the bitmap font I used for my test.

Related

How to make two or more different font files use a common Atlas in libgdx?

I use different fonts for different screens. some of the fonts are only few letters, so it would be inefficient to generate an atlas for each font.So is there a way to make all of my fonts use a single Atlas?
You can use a constructor that takes a TextureRegion. For example, if your font and image were named myFont.fnt and myFont.png, you can put myFont.png in with the rest of your sprite source images and pack it into the texture atlas. Put the .fnt files in with the rest of your assets. Then after loading the texture atlas:
myFont = new BitmapFont(Gdx.files.internal("myFont.fnt"), myTextureAtlas.findRegion("myFont"));
To use it in a Skin, you'll want to add it to a Skin before loading the Json file:
skin = new Skin(); // instantiate blank skin
skin.add(myFont, "myFont");
skin.load(Gdx.files.internal("mySkin.json"));
The Json file can reference the font by the name you use when adding it to the skin.
Although, I'd highly advise using AssetManager for everything. In this case, your skin Json could define the font normally. The only extra step you need beyond loading everything to the asset manager the usual way would be to add a BitmapFontLoader.BitmapFontParameter that specifies the TextureAtlas that contains the region. The AssetManager will use this to determine that the BitmapFont is dependent on the atlas, so it will load them in the correct order.
BitmapFontLoader.BitmapFontParameter fontParam = new BitmapFontLoader.BitmapFontParameter(){{
atlasName = "mySkin.pack";
}};
assetManager.load("myFont.fnt", BitmapFont.class, fontParam);
The atlas should be the same one the skin uses.

How to set a texture filter

How important is it to set a texture filter?
In the book Java Game Development with LibGDX in chapter 3 they set a texture filter.
When I load video assets with the assetmanager I can't convert a textureregion to a texture to set the texture filter.
But I can however set a texture filter on the entire spritesheet like so:
textureAtlas = assetManager.get("images/packed/game.pack.atlas") // all images are found in this global static variable
textureAtlas!!.findRegion("button").texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
How important is it to set a texture filter? Is this an ok solution? How can I get the textures from the atlas?
Textures always have a filter. If you don't set one, it will have the default filter of (Nearest, Nearest). This filter is appropriate for retro graphics (pixellated look). Otherwise, you'll most likely want to use (MipMapLinearLinear, Linear). If your game is mostly done and you've identified sprite drawing as a performance bottle-neck, then you can downgrade to (MipMapLinearNearest, Linear).
When creating an atlas using the TexturePacker, there is an option for texture filter, and if you set that you don't have to set it after you load the TextureAtlas in your game. You could also add a line at the top of your pack file like this:
filter: MipMapLinearLinear,Linear
Otherwise, if you want to set it on the atlas, it is fine with a single-page atlas to do what you did, and apply the filter using a texture reference from any of the texture regions, since they are all referencing the same Texture instance. But TextureAtlases can have multiple pages, so it would be more appropriate to do this:
for (Texture texture : textureAtlas.getTextures())
texture.setFilter(...);
Edit: To add settings to a TexturePacker build, put a text file named pack.json in the directory with the source images. You only have to add the settings that you want to change from the defaults. LibGDX can read simplified json that omits quotation marks for elements with no whitespace. So to just set the texture filter, this is all you need in the file:
{
filterMin: MipMapLinearLinear,
filterMag: Linear
}

TmxMapLoader to use packed tileset

In the old libgdx map api, they used to have
map = TiledLoader.createMap(Gdx.files.internal("maps/testmap.tmx"));
atlas = new TileAtlas(map, Gdx.files.internal("maps"));
tileMapRenderer = new TileMapRenderer(map, atlas, 8, 8);
However in the new libgdx the rule changes, to load a tilemap there is no longer needed to use map packer first. You can directly use the .tmx file with the tileset png. Something like following will work, and then call render.
TiledMap map = new TmxMapLoader().load("maps/testmap.tmx");
My question is the original tileselt.png that used to generate the .tmx file, it's size is not power of two. So I still have to either use Texture packer or a map packer to pack it for using.
I could not successfully associate the packed file with the .tmx;
Is there anyway to approach this issue?
Thanks
If you target GLES 1.0, you will need power-of-two tilesets. Some devices might allow non-power-of-two with GLES 1.0, but that isn't guaranteed. With GLES 2.0 this restriction is lifted, but you still might get better performance out of power-of-two.
You can still use the TiledMapPacker-produced maps, you will just need to load the map with AtlasTmxMapLoader instead of TmxMapLoader.
They do not need to be power of two. If you have Problems with it like you get the power of two error set Texture.setEnforcePotImages(false); inside of your MainClass.
You do not need the packer anymore so i think you cant associate the packer to the tmx file.
If you use the TmxMapLoader the tilesets need to be inside of the same folder of the .tmxfile.
If they are inside of an different directory you need to configure the source path inside of the .tmx file. here is an Example:
<tileset firstgid="257" name="mountain" tilewidth="32" tileheight="32">
<image source="mountain.png" width="512" height="512"/>
</tileset>
is the regular output of Tiled. If the Tileset is inside of for example config it you need to change it like this:
<tileset firstgid="257" name="mountain" tilewidth="32" tileheight="32">
<image source="config/mountain.png" width="512" height="512"/>
</tileset>
But it still need to be a subfolder of the path where the tmx file is.
Regards hope that may helps.

libgdx TextureAtlas, and NinePatch's

I am making a simple game using libgdx. I have a TextureAtlas that has I ninepatch I am trying to use:
The image is saved as menu.9.png
I am using the following code:
Image bg = new Image(Room.iAtlas.findRegion("GUI/menu"));
bg.setBounds(guix-border,guiy-border,(border+radius)*2,(border+radius)*2);
batch.begin();
bg.draw(s,1);
batch.end();
The output is like this:
I really just have no idea what I am doing wrong, but it should be more like this(Except it would have the shapes on top of it, but I didn't add those):
(I created that by hand, i've never actually had 9patch working, and it doesn't have the ships because I didn't bother to edit those in)
It looks like your "nine patch" isn't being treated as a real nine path, and is being treated as a "degenerate" nine patch (I had a very similar problem earlier: Loading nine-patch image as a Libgdx Scene2d Button background looks awful, though I wasn't using a TextureAtlas which is supposed to be the solution.)
Basically, when Libgdx reads the nine-patch out of your atlas, its supposed to read all the meta-data that describes how to chop the image up into 9 tiles (see https://code.google.com/p/libgdx/wiki/TexturePacker#NinePatches). I see a couple places this could go wrong:
Your texture isn't a valid nine-patch, and the meta-data is being ignored. (Check with the Android draw9patch tool.)
Your texture packer isn't processing the .9.png file correctly. Check the contents of the .txt file for your atlas, and see if it has "split" entries associated with the "menu.9.png" entry.
The texture lookup is just returning a regular TextureRegion wrapper for the nine-patch region, and isn't wrapping it in a NinePatch object. Try using TextureRegion.createNinePatch to make that more explicit. (I'm under the impression that this isn't necessary, but maybe it is ...)

actionscript-3 papervision3d mxmlc embedded collada model not showing

I am writing some code based on the following tutorial:
http://active.tutsplus.com/tutorials/3d/quick-tip-displaying-a-3d-model-with-papervision3d/
I copied the code from the example and added paths to my own assets.
[Embed(source="/Models/daeModel/cow.dae", mimeType="application/octet-stream")]
private var CowModelClass:Class;
[Embed(source="/Models/daeModel/Cow.png")]
private var CowTextureClass:Class;
[Embed(source="/Models/SkyDome/images.jpg")]
private var SkyTextureClass:Class;
[Embed(source="/Textures/grass-texture.jpg")]
private var GrassTextureClass:Class;
The assets shown above are used to display a Collada cow model standing on grass (plane) under a skydome (sphere), so my code differs slightly from the tutorial and I am loading Collada not DAE.
import org.papervision3d.objects.parsers.Collada;
I publish it in Flash CS3 and the .swf works perfectly. Cow model displays, grass plane and skydome all show up.
Unfortunately the assets are loaded at runtime because Flash CS3 does not embed.
To embed the assets I then compile the .as using mxmlc.exe using:
-static-link-runtime-shared-libraries=true
and I get no compilation errors.
However, when I run the .swf, the grass plane and the skydome appear normally with their embedded textures, but the collada model does not show.
My own debug text displays the width of the model as 0, so it looks like the model hasn't loaded. The Collada class still works fine because I am able to move the 3D co-ordinates of the model and thereby move some 3D text which is centred on the co-ordinates of the model. The text displays but the model is not visible.
By making a simple change I am able to check the model's texture 'Cow.png' by applying it to the grass plane, and it shows up fine. Because the texture is in the same folder as the model, I know that navigating the path to the model's location isn't the problem.
Does anyone know of any reason Collada models might not show after compile with mxmlc?
Am I missing any command line parameters or something obvious like that?
Failing that is there any other way of embedding this model?
Problem Solved!
Compiler mxmlc required me to define cowByteArray as XML:
//load cow model MXMLC
var cowByteArray:ByteArray = new CowModelClass ( );
cow = new Collada ( ) ;
cow.load ( new XML(cowByteArray), cowMaterialsList ) ;
Using the second code, after compiling with mxmlc, the model shows up fine!
Hope this helps somebody!