ラスタライズフォント生成ツール#

概要#

ラスタライズフォントは画像化された文字の集合体です。実装が容易で高速に扱える特徴があり、文字の使用範囲が限定されているゲームプログラミングにおいては広く用いられている手法です。一方で、リサイズや回転などの変形で劣化しやすいというデメリットがあります。

本項では、フォントデータとして広く用いられているアウトラインフォントからラスタライズフォントを生成するツールと、その出力データをMGLで扱うためのエクステンションについて解説します。

重要

本ツールの利用にあたって、変換元となるアウトラインフォントのライセンスは必ず確認してください。本ツールが出力するデータの利用は複製・改変・再配布にあたる可能性があり、ライセンスによっては禁止または制限が課せられている場合があります。

ツールの導入#

アウトラインフォントをラスタライズするためにはmgl-font2texというツールを用います。このツールはコマンドラインツールであり、コンソール(Windowsのコマンドプロンプト、macOSのターミナル等)から利用します。

ツールの導入方法は次の通りです。

Windows#

MGLのダウンロードページにアクセスし、「ツール」からmgl-font2texのWindows向けの実行可能バイナリをダウンロードしてください。ダウンロードしたアーカイブ内にある「mgl-font2tex.exe」がツール本体になります。このファイルを必要に応じてパスの通ったディレクトリにコピーしてください。

macOS#

macOSではHomebrewを用いて導入します。Homebrewについては次のリンク先を参照してください。

MGL関連のツールは公式パッケージとして登録されていないため、最初にtapコマンドを用いてパッケージの追加を行う必要があります。

$ brew tap AcerolaSoftware/tap

このコマンドにより、MGLの配布元が提供しているツール類をHomebrewから導入できるようになります。

tapコマンド実行後、installコマンドによりmgl-font2texをインストールします。

$ brew install mgl-font2tex

実行後、mgl-font2tex -vと入力してバージョン情報が表示されていれば成功です。

その他の環境#

一般的なPOSIX準拠のシステムであれば、ソースコードからビルドすることで利用可能です。

mgl-font2texはビルドに次のソフトウェアを利用します。

  • C++17に対応したコンパイラ(clang推奨)

  • SCons (バージョン4.0.0以降)

  • pkg-config

依存ライブラリは次の通りです。これらはpkg-configで参照できる必要があります。

  • libpng

  • FreeType

  • JsonCpp

ビルド方法は次の通りです。

$ scons

正常にビルドが完了した場合、そのディレクトリにmgl-font2texが生成されます。

ツールの使用方法#

設定ファイルの新規作成#

mgl-font2texはあらかじめ設定を記述したファイルを用意し、その設定ファイルを読み込むことで動作します。この設定ファイルのテンプレートはinitコマンドを用いることで生成します。

まず初めに、次のように入力して設定ファイルを新規に作成してください。

$ mgl-font2tex init

成功するとカレントディレクトリにfont2tex.configという設定ファイルが生成されます。

次のようにinitの後にファイル名を指定する事も可能です。

$ mgl-font2tex init uifont.config

この場合、uifont.configという名前で設定ファイルが作成されます。用途に応じて複数のフォントリソースを使い分ける場合に利用してください。

ラスタライズ#

initコマンドで作成した設定ファイルには、設定可能なパラメータとその説明のコメントが記述されています。まずは設定ファイルをテキストエディタで開き、コメントに従い内容を記述してください。

ここでは例として、MGLのロゴにも使用されている「自家製Rounded M+」を用いる場合を想定して編集します。自家製Rounded M+は次のサイトにて配布されており、無償で利用可能です。

まず、利用したいアウトラインフォントのファイルを設定ファイルと同じディレクトリにコピーするか、システムにインストールしてください。ここではrounded-mplus-1p-regular.ttfを利用するものと想定します。

次に、設定ファイルをテキストエディタで開いてください。設定ファイルの先頭にFontPathというパラメータがありますので、ここにアウトラインフォントのファイル名を記述します。

FontPath = rounded-mplus-1p-regular.ttf

一旦この状態で保存し、コンソール上から設定ファイルと同じディレクトリで次のように実行してください。

$ mgl-font2tex

ヒント

設定ファイルの名前を変更した場合は、次のように引数に設定ファイル名を指定してください。

$ mgl-font2tex uifont.config

引数を省略した場合はfont2tex.configが指定されます。

設定ファイルは初期状態でフォントサイズ32、画像サイズ256x256、印字可能なASCII文字のみを出力する設定になっています。設定が正しければ、font_00.pngという名前の次のような画像が生成されます。

出力画像
../_images/font_00.png

注釈

背景は本来は透過していますが、ここでは黒で塗りつぶしています。

画像ファイルの他にfont_metrics.binfont_metrics.jsonというファイルも同時に出力されています。これらはメトリクス情報と呼ばれ、文字ごとのレンダリングに必要な情報が格納されています。両者の内容は同じですが、拡張子.binはバイナリ形式で、拡張子.jsonはJSON形式です。出力結果をゲーム内で利用するには、これらのどちらかを用いることになります。

文字の追加#

設定ファイルのデフォルト設定はASCII文字のみを出力しますが、パラメータを変更することでより多くの文字を扱うことが可能です。

使用する文字を追加する一般的な方法は、追加したい文字が記述されたテキストファイルをTextFilesのパラメータに指定することです。実際のゲーム開発においては、ここにゲームが使用するメッセージデータを指定し、そのゲームが使用する文字のみをラスタライズするようにします。

ここでは仮として、設定ファイルをメッセージデータの代わりに指定します。

TextFiles = font2tex.config

ついでに、出力する画像サイズが256x256では収まりきらなくなるため、画像サイズを512x512に拡張します。全ての文字が1枚の画像に収まらなかった場合は複数枚に分割して出力されますが、描画パフォーマンスの観点から全ての文字が1枚に収まっている状態が理想的です。

PalletWidth = 512
PalletHeight = 512

この設定でのラスタライズ結果は次の通りです。

出力画像
../_images/font_00_appended.png

書体の追加#

フォントリソースには複数の書体に対応しており、このツールではボールド体とルビ用の書体を追加で収録できます。これらの書体はタグによるテキスト装飾を行う際に使用されます。

ボールド体およびルビ用の書体の設定は生成された設定ファイルの最下段にあります。これらの設定パラメータを記述することによって、出力されるフォントリソースに書体が追加されます。

# ボールド体の出力設定
#  この設定を有効にするとボールド体用のグリフを同時に出力します。
#  各パラメータの内容は先述の同名パラメータと同様です。
[bold]
Enable = No
FontPath = __PLEASE_SET_TTY_FONT_PATH__
TextFiles =
AppendAsciiCharacter = Yes
AppendHiragana = No
AppendKatakana = No
FontSize = 32
AlignmentSize = 2


# ルビの出力設定
#  この設定を有効にするとルビ用のグリフを同時に出力します。
#  各パラメータの内容は先述の同名パラメータと同様です。
[ruby]
Enable = No
FontPath = __PLEASE_SET_TTY_FONT_PATH__
TextFiles =
AppendAsciiCharacter = Yes
AppendHiragana = Yes
AppendKatakana = Yes
FontSize = 14
AlignmentSize = 2

有効にしたい書体のパラメータEnableYesを設定し、FontPathに有効な変換元フォントファイルへのパスを指定してください。その他のパラメータの意味はデフォルトの書体と同じとなるため、設定ファイル内の同名パラメータのコメントまたは設定パラメータの詳細を参考にしながら設定してください。

これらの利用例を次に示します。

設定ファイル(変更箇所のみ)
PalletWidth = 1024
PalletHeight = 1024

[bold]
Enable = Yes
FontPath = rounded-mplus-2p-heavy.ttf
TextFiles = font2tex.config

[ruby]
Enable = Yes
FontPath = rounded-mplus-1p-regular.ttf
出力画像
../_images/font_00_ruby_bold.png

出力した書体の利用方法については、フォントの利用方法タグによるテキスト装飾を参照してください。

メッセージコンバータとの連動#

メッセージコンバータにはメッセージデータを最適化する機能があり、mgl-font2texはこの最適化に対応したフォントリソースを生成する機能を備えています。この機能はメッセージの描画負荷の軽減だけでなく、文字の選定を自動化する目的も兼ねています。

メッセージコンバータが最適化されたデータを生成する場合、同時にJSON形式に使用文字リストを出力します。mgl-font2tex側はこの使用文字リストを使用してラスタライズすることで、このメッセージデータに対応したフォントリソースを生成します。メッセージコンバータ側の最適化の詳細についてはインデックス化してバイナリ出力を参照してください。

注意

使用文字リストを使用してラスタライズを行う場合、TextFilesと全てのAppend*のパラメータは無視されます。任意の文字を追加したい場合、メッセージデータ側にその文字を追加してください。

使用文字リストを使用してラスタライズを行うには、UsingCharacterListオプションにメッセージコンバータが出力したJSONファイルを指定します。

UsingCharacterList = msg_using_all.json

使用文字リストには全ての書体の情報が含まれています。もしリストが特定の書体を要求しており、その設定が有効になっていない場合はエラーとなります。その場合は各書体のパラメータを適切に設定してください。

その他の設定#

その他の設定については設定パラメータの詳細を参照してください。

MGLでの利用方法#

ライセンス#

ここで紹介するエクステンションはMGL本体と同じzlibライセンスに基づいて配布されています。もしMGLと併用する場合、このエクステンションはMGLの一部として扱って問題ありません。zlibライセンスの詳細はMGLのライセンスを参照してください。

利用方法#

MGLのダウンロードページではmgl-font2texの出力結果をMGLで扱うためのエクステンションも提供しています。このエクステンションはMGLのフォントリソースとして実装されており、MGL::Render::FontのAPIを通して利用可能になります。

エクステンションはソースコードとして配布されています。まず、ダウンロードページの「エクステンション」からmglext-rasterized-fontをダウンロードしてください。アーカイブ内のmglextディレクトリ内にソースコードが含まれていますので、これをアプリケーション側のプロジェクトへと追加してください。

ここでは、導入方法各プラットフォーム共通で示したディレクトリ構成に追加し、次のような構成になることを想定します。

src
├── app_main.cc
├── app_main.h
└── mglext
    ├── rasterized_font.cc
    └── rasterized_font.h

また、mgl-font2texの出力結果をリソースとして扱う必要があります。workdirに全てのPNGファイルとfont_metrics.binをコピーします。Xcodeの場合はプロジェクトへの追加も忘れないでください。

結果、次のような構成になることを想定します。

workdir
├── font_00.png
└── font_metrics.bin

注釈

ディレクトリ構成は一例です。作成するゲームに合わせ適宜変更してください。

最後に、このフォントリソースをプログラム側から扱うための例を示します。導入方法各プラットフォーム共通の例を元に、今回追加したフォントリソースで文字の描画する例は次の通りです。

app_main.cc
#include "app_main.h"

// ラスタライズフォント用のエクステンションをインクルード
#include "mglext/rasterized_font.h"

namespace
{
// フォントキーを定義
constexpr auto kFontKey = MGL::Render::MakeFontKey("font");
}

namespace YourApp
{
/* ------------------------------------------------------------------------- */
/*!
 *  \brief      コンストラクタ
 */
/* ------------------------------------------------------------------------- */
Application::Application() noexcept
{
}


/* ------------------------------------------------------------------------- */
/*!
 *  \brief      初期化処理
 *  \retval     true    成功
 *  \retval     false   失敗
 */
/* ------------------------------------------------------------------------- */
bool Application::OnInitialize() noexcept
{
    // ラスタライズフォントを登録
    auto font = MGL::Render::Font::Create<MGLExt::RasterizedFont>(
                kFontKey,       // 登録するフォントキー
                "$resource/",   // フォントファイル一式が格納されているディレクトリ
                "font");        // フォント名。NamePrefixに指定した文字を指定する

    if (!font)
    {
        MGL_TRACE("フォントの登録に失敗");
    }

    return true;
}


/* ------------------------------------------------------------------------- */
/*!
 *  \brief      フレーム更新処理
 */
/* ------------------------------------------------------------------------- */
void Application::OnFrameUpdate() noexcept
{
    MGL::Render::Renderer2D renderer;

    // 黒色で画面をクリア
    renderer.Clear(MGL::kColorBlue);

    // 登録したフォントを用いて描画
    MGL::Render::Font font(kFontKey);
    if (font)
    {
        font.SetPosition(MGL::Vector2(100.0f, 100.0f));
        font.Print("Rounded M+ フォント");
    }
}


/* ------------------------------------------------------------------------- */
/*!
 *  \brief      終了処理
 */
/* ------------------------------------------------------------------------- */
void Application::OnExit() noexcept
{
}

}   // namespace YourApp

フォントキーや描画方法についてはフォントの利用方法で解説している内容と共通しているため省略します。ラスタライズフォントを扱うための重要な部分は、Application::OnInitialize()内の次の部分です。

// ラスタライズフォントを登録
auto font = MGL::Render::Font::Create<MGLExt::RasterizedFont>(
            kFontKey,       // 登録するフォントキー
            "$resource/",   // フォントファイル一式が格納されているディレクトリ
            "font");        // フォント名。NamePrefixに指定した文字を指定する

MGLExt::RasterizedFontというクラスがラスタライズフォントを扱うためのフォントリソースクラスです。第2引数にフォントファイル一式が格納されているディレクトリを、第3引数にフォント名を指定しています。フォント名は設定ファイルのNamePrefixに指定した文字をそのまま指定してください。

戻り値に有効なフォントが返っている場合、フォントの登録に成功しています。

このサンプルの実行結果は次の通りです。

実行結果(640x480)
../_images/rasterized_font_sample.png

設定パラメータの詳細#

FontPath#

変換元のフォントファイルのパスを指定します。相対パスを指定した場合、フォントファイルを次の順で検索します。

  1. カレントディレクトリ

  2. 環境変数MGL_FONT_PATHに設定されたパス

  3. システムのフォントディレクトリ(Windows、macOSのみ)

WindowsとmacOSにおいては、システムのフォントディレクトリを検索する際にユーザー毎にインストールされたフォントを優先的に参照します。

このパラメータは省略できません。

FontPath = use-outline-font.ttf

OutputPath#

変換したファイルの保存先ディレクトリを指定します。

省略時は./(カレントディレクトリ)が指定されます。

OutputPath = ./

NamePrefix#

生成するファイルの先頭に付ける名前を指定します。

省略時はfontが指定されます。

NamePrefix = font

TextFiles#

使用する文字が記述されたテキストファイルのパスを指定します。複数指定する場合はtext1.txt:text2.txtのように:で区切ります。

このファイルはいずれかのUnicode形式で保存されていなければなりません。BOMがあればそれを利用して自動認識し、なければUTF-8として読み取ります。

ファイル名の先頭に!を付与した場合、そのファイルに含まれる文字がアウトラインフォントに含まれていなくても警告を表示しません。

後述するUsingCharacterListを使用せず、Append**のオプションの全てがNoの場合、このパラメータは省略できません。

TextFiles = text1.txt:!text2.txt

UsingCharacterList#

メッセージコンバータが出力するJSON形式の使用文字リストのパスを指定します。

このパラメータを指定した場合、全てのTextFilesおよびAppend*オプションは無視されます。

UsingCharacterList = msg_using_all.json

OutputJSONMetrics#

文字のメトリクス情報をJSON形式で出力するかを指定します。

出力パスはOutputPath + NamePrefix + "_metrics.json"(デフォルト設定では./font_metrics.json)です。

省略時はYesが指定されます。

OutputJSONMetrics = Yes

OutputBinaryMetrics#

文字のメトリクス情報をバイナリ形式で出力するかを指定します。

出力パスはOutputPath + NamePrefix + "_metrics.bin"(デフォルト設定では./font_metrics.bin)です。

省略時はYesが指定されます。

OutputBinaryMetrics = Yes

AppendAsciiCharacter#

ASCIIコードのうち印字可能な文字を追加します。省略時はYesが指定されます。

UsingCharacterListを指定している場合、このパラメータは無視されます。

AppendAsciiCharacter = Yes

AppendHiragana#

日本語の平仮名といくつかの記号を追加します。省略時はNoが指定されます。

UsingCharacterListを指定している場合、このパラメータは無視されます。

AppendHiragana = No

AppendKatakana#

日本語の片仮名といくつかの記号を追加します。省略時はNoが指定されます。

UsingCharacterListを指定している場合、このパラメータは無視されます。

AppendKatakana = No

FontSize#

フォントサイズを指定します。

生成される文字のピクセル数はここで指定したサイズにおおよそ収まりますが、アウトラインフォントの仕様により若干オーバーする可能性もあります。

省略時は32が指定されます。

FontSize = 32

PalletWidth#

生成されるテクスチャの幅を指定します。

省略時は256が指定されます。

PalletWidth = 256

PalletHeight#

生成されるテクスチャの高さを指定します。

省略時は256が指定されます。

PalletHeight = 256

AlignmentSize#

テクスチャ上の座標の幅と高さのアライメントを指定します。奇数サイズのテクスチャが描画品質に影響する場合などに指定してください。

指定可能な値は0, 2, 4, 8, 16, 32, 64のいずれかです。

省略時は2が指定されます。

AlignmentSize = 2

PixelMode#

生成されるテクスチャのピクセルフォーマットを指定します。

指定可能な文字とその内容は次の通りです。

  • Monochrome: 1ビットのモノクロ

  • GrayScale: 8ビットのグレースケール

省略時はGrayScaleが指定されます。

PixelMode = GrayScale

ConfigVersion#

この設定データのフォーマットバージョンです。将来の後方互換のためのものですので、変更は行わないでください。

ConfigFormatVersion = 10000

Enable#

書体を有効にするかをYesまたはNoで設定します。このオプションは追加の書体の設定でのみ有効であり、デフォルトの書体は設定に関わらず有効となります。

省略時にはNoが指定されます。

[bold]
Enable = Yes

[Ruby]
Enable = No

メトリクス情報のフォーマット#

mgl-font2texが出力するメトリクス情報の内容を次に示します。

バイナリフォーマット#

バイナリファイルは先頭にバイナリデータのヘッダが配置され、以降はチャンク単位でデータが格納されています。全てのチャンクには共通のヘッダが付与されており、アプリケーション側が未対応のチャンクは読み飛ばすことが可能となっています。

現時点でのデータフォーマットは次の通りです。型のunit32_tは符号なしの32ビット値、uint16_tは符号なしの16ビット値、int16_tは符号付きの16ビット値、char32_tはUTF-32エンコーディングされた文字を表しています。全ての値のバイトオーダーはリトルエンディアンです。

バイナリヘッダ

名前

内容

identifier

uint32_t

識別子: 0x3BA5E2D0 (MGL::Hash::FNV1a("FontMetrics")で算出)

revision

uint32_t

リビジョン番号(予約)

faceCount

uint32_t

フォントフェイス(書体)の数

textureCount

uint32_t

テクスチャの数

maxHeight

uint32_t

全ての文字の高さの最大値

flags

uint32_t

フラグ情報(予約)

チャンクヘッダ

名前

内容

identifier

uint32_t

チャンクの種類を表す識別子

chunkSize

uint32_t

チャンクのデータサイズ

フェイスチャンク(識別子:0x79337DCC MGL::Hash::FNV1a("FaceChunk")で算出)

名前

内容

faceType

uint32_t

書体の識別子(書体名をMGL::Hash::FNV1aでハッシュ化した値)

fontSize

uint32_t

フォントサイズ(設定ファイルでの指定値)

glyphCount

uint32_t

グリフの数

alignmentSize

uint32_t

アライメントサイズ

maxHeight

uint32_t

この書体が持つグリフの高さの最大値

glyphs

後述

グリフ情報のテーブル。要素数はglyphCountと同値。

フェイスチャンク内のグリフ情報

名前

内容

code

char32_t

文字を表す値(UTF-32)

useCount

uint32_t

使用回数

width

uint16_t

height

uint16_t

高さ

advance

uint16_t

送り幅

bearingX

int16_t

X方向のベアリング値

bearingY

int16_t

Y方向のベアリング値

textureX

uint16_t

テクスチャ上のX座標

textureY

uint16_t

テクスチャ上のY座標

textureWidth

uint16_t

テクスチャ上の幅

textureHeight

uint16_t

テクスチャ上の高さ

texturePage

uint16_t

文字が収録されているテクスチャの番号

flags

uint32_t

フラグ情報(予約)

これらを構造体で表すと次のようになります。なお、メモリアライメントによるパティングは発生しないものとします。

//! バイナリファイルのヘッダ
struct BinaryHeader
{
    uint32_t identifier;    //!< 識別子
    uint32_t revision;      //!< リビジョン番号
    uint32_t faceCount;     //!< フォントフェイスの数
    uint32_t textureCount;  //!< テクスチャの数
    uint32_t maxHeight;     //!< 全ての文字の高さの最大値
    uint32_t flags;         //!< フラグ情報
};

//! チャンクヘッダ
struct BinaryChunkHeader
{
    uint32_t identifier;    //!< 識別子
    uint32_t chunkSize;     //!< チャンクサイズ
};

//! フェイスチャンク
struct FaceInfo
{
    uint32_t faceType;       //!< 書体の識別子
    uint32_t fontSize;       //!< フォントサイズ
    uint32_t glyphCount;     //!< グリフの数
    uint32_t alignmentSize;  //!< アライメントサイズ
    uint32_t maxHeight;      //!< 高さの最大値
    // 以降、glyphCountの数だけGlyphInfoが続く
};

//! フェイスチャンク内のグリフ情報
struct GlyphInfo
{
    char32_t code;           //!< 文字コード(UTF-32)
    uint32_t useCount;       //!< 使用回数
    uint16_t width;          //!< 幅
    uint16_t height;         //!< 高さ
    uint16_t advance;        //!< 送り幅
    int16_t bearingX;        //!< X方向のベアリング
    int16_t bearingY;        //!< Y方向のベアリング
    uint16_t textureX;       //!< テクスチャのX座標
    uint16_t textureY;       //!< テクスチャのY座標
    uint16_t textureWidth;   //!< テクスチャ上の幅
    uint16_t textureHeight;  //!< テクスチャ上の高さ
    uint16_t texturePage;    //!< 文字が収録されているテクスチャの番号
    uint32_t flags;          //!< フラグ情報(予約)
};

JSONフォーマット#

バイナリフォーマットの出力がゲーム側で利用することを想定しているのに対し、JSONフォーマットの出力は他のツールと連携することを想定しています。このため、JSONフォーマットにはバイナリフォーマットに含まれていない情報が追加されています。

JSONフォーマットの内容は次の通りです。なお、要素の並び順は前後している可能性があります。

fontMetrics
├── <書体名>
│   ├── fontInfo                フォント情報
│   │   ├── familyName                  フォントファミリ名
│   │   ├── styleName                   スタイル名
│   │   ├── size                        設定ファイルで指定されたフォントサイズ
│   │   ├── maxHeight                   文字の高さの最大値
│   │   ├── texturePageCount            テクスチャの最大数
│   │   └── alignmentSize               幅と高さのアライメントサイズ
│   └── glyphs[]                グリフ情報(配列)
│       ├── code                        文字を表す値(Unicode符号位置)
│       ├── width                       文字の幅
│       ├── height                      文字の高さ
│       ├── advance                     文字の送り幅
│       ├── bearingX                    文字のX方向のベアリング値
│       ├── bearingY                    文字のY方向のベアリング値
│       ├── useCount                    文字の使用回数
│       ├── textureX                    テクスチャ上のX座標
│       ├── textureY                    テクスチャ上のY座標
│       ├── textureWidth                テクスチャ上の幅
│       ├── textureHeight               テクスチャ上の高さ
│       └── texturePage                 文字が収録されているテクスチャの番号
├── <書体名>
…
└─  texturePageCount        テクスチャの最大数