libGDX 1.5.6-1.6.0 で起きたフォント周りの変更とGlyphLayoutについて

５月６日に、[libGDX 1.6.0がリリース](http://www.badlogicgames.com/wordpress/?p=3682)されたようです。

ついこの間少し触っていたときに、アップデートするとBitmapFont.getBounds()が消えてて、コードを修正しなければならなくなりました。これ自体は1.5.6がリリースされた４月には起きていたことなので、既にもうみなさん解決してるかもしれないですね。。

タイミングが遅くはありますが、これについてどんな変更が起きたのか簡単にまとめました。


変更されたAPI
---------------------------------------

[libGDX 1.5.6](http://www.badlogicgames.com/wordpress/?p=3666) で、フォント周りのAPIと内部の動作に大きな変更がありました。このフォント周りの大きな変更は、[BitmapFont refactoring](http://www.badlogicgames.com/wordpress/?p=3658)でまとめて解説されています。これによると、一部の言語できちんと動作しない場合があったのを、リファクタリングすることで解決したようです。（リファクタリング…？）

その解説記事にかかれていますが、基本は先程の記事にあったこのコードを見れば一目瞭然でした。

```java
// Old:
font.draw(batch, "meow", x, y);
font.drawMultiline(batch, "meow\nmeow", x, y);
font.drawWrapped(batch, "meow meow meow meow meow meow", x, y, width, HAlignment.RIGHT);

TextBounds bounds = font.getBounds("meow");
font.draw(batch, "meow", x + bounds.width / 3, y + bounds.height / 3);

// New:
font.draw(batch, "meow", x, y);
font.draw(batch, "meow\nmeow", x, y);
font.draw(batch, "meow meow meow meow meow meow", x, y, width, Align.right, true);

GlyphLayout layout = new GlyphLayout(); // 毎回newしないようにすること
layout.setText("meow");
font.draw(batch, layout, x + layout.width / 3, y + layout.height / 3);
```

具体的に変更点まとめるとこんな感じ（たぶんもう少しあります…）

* [GlyphLayout](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/GlyphLayout.html) っていうクラスが追加された
* BitmapFont.drawMultiline(), BitmapFont.drawWrapped(), BitmapFont.getBounds(), BitmapFont.getWrappedBounds(), BitmapFont.getMultiLineBounds(), BitmapFontCache.setWrappedText(), BitmapFontCache.setMultiLineText() メソッド削除
  * GlyphLayout を代わりに使う
  * [1.6.0] Label#getBounds() も削除
* Align クラスのパッケージ名が変更になった
  * com.badlogic.gdx.scenes.scene2d.utils -> com.badlogic.gdx.utils
* BitmapFont.setScale() メソッド削除
  * BitmapFont.getData().setScale() を利用する
* BitmapFont.getData().setMarkupEnabled() メソッド削除
  * BitmapFont.getData().markupEnabled を利用する


GlyphLayout利用例
---------------------------------------

verdana39.fnt, verdana39.pngは[libGDXのgdx-tests-android/assets/data](https://github.com/libgdx/libgdx/tree/1.6.0/tests/gdx-tests-android/assets/data)にあります。

```java:MyGdxGame.java
package myapp;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Align;

public class MyGdxGame extends ApplicationAdapter {
    SpriteBatch batch;
    private GlyphLayout glyphLayout;
    private BitmapFont font;

    @Override
    public void create() {
        batch = new SpriteBatch();

        // 初期化
        font = new BitmapFont(Gdx.files.internal("verdana39.fnt"));
        glyphLayout = new GlyphLayout();
    }

    @Override
    public void render() {
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        // 更新

        // テキスト
        String text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " +
                "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
        // テキストの色
        Color color = Color.TEAL;
        // テキストの描画幅
        float targetWidth = Gdx.graphics.getWidth() * 0.5f;
        // targetWidthの幅で自動的に改行を行うかどうか
        boolean wrap = true;
        // targetWidth の幅で、テキストを中央寄せにするかどうか
        int halign = Align.center;
        glyphLayout.setText(font, text, color, targetWidth, halign, wrap);

        // 描画

        batch.begin();

        float x = 0;
        float y = Gdx.graphics.getHeight();
        font.draw(batch, glyphLayout, x, y);

        batch.end();
    }

    @Override
    public void resize(int width, int height) {
        super.resize(width, height);
        batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
    }
}
```

![実行結果](https://qiita-image-store.s3.amazonaws.com/0/20530/329bca0a-3373-495f-cb6e-dffa13803b8d.png "libgdx-glyphlayout.png")

あと、上記サンプルでは普通にGlyphLayoutをnewしてますが、このクラス[Pool.Poolable](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/utils/Pool.Poolable.html)インターフェースを実装しているので、[LibgdxのPoolを使ってみた。（オブジェクトの使い回し） - Qiita](http://qiita.com/kamedon39/items/06592c18551bec55fde3)の方法使うと、ゲームループで毎回newしたりすること避けやすいかもしれないです。


いきなりビルドが通らなくなるようなAPIの変更があったことについて
---------------------------------------

先ほどの[BitmapFont refactoring](http://www.badlogicgames.com/wordpress/?p=3658)にありました。

* グリフの新しいレンダリング方法を導入するにあたり、APIの変更は避けられませんでした。ごめんなさい！
* どうせ変えるんだったら一気に変える方がいいよね！

Oh...


1.6.0 にかけての変更
---------------------------------------

あと、一応変更点(CHANGELOG)からフォント関連だけをピックアップしてみました。BitmapFont、いままではpadding無視してたけれど、 1.6.0 で、修正したっぽいです。(→[| Font metrics changes](http://www.badlogicgames.com/wordpress/?p=3678))

```
[1.6.0]
- API Change: GlyphLayout xAdvances now have an additional entry at the beginning. This was required to implement tighter text bounds. #3034
- API Change: BitmapFont metrics now respect padding. #3074
- API Change: Label#getTextBounds changed to getGlyphLayout. This exposes all the runs, not just the width and height.

[1.5.6]
- API Change: BitmapFontData, BitmapFont, and BitmapFontCache have been refactored. http://www.badlogicgames.com/wordpress/?p=3658
- FreeTypeFontGenerator can now render glyphs on the fly.
```