DirectXTKのMakeSpriteFontの問題と解決策

#DirectXTKのMakeSpriteFontの問題と解決策

##はじめに
DirectX11からDirectX9に存在したD3DXライブラリが標準搭載されなくなった。そのせいで、便利なクラスが使えなくなった。Font表示も同様、使えなくなった。一応、D3DXライブラリのDX11版は存在するものの、ライブラリを個別にインストール・使用しなければならない（参考：[DirectX 補助ライブラリ](https://ja.wikipedia.org/wiki/Microsoft_DirectX#%E8%A3%9C%E5%8A%A9%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA) - Wikipedia）。

Font表示処理を独自に実装することは可能だが、こういう汎用的な処理はフリーウェアとして存在するのが望ましい。そこで登場するのが「DirectX Tool Kit＝DirectXTK」である。

## DirectXTKとは？
DirectXTKは、C++ で作られている。February 24, 2012に最初のリリースが行われた。DirectXTKが提供する機能は、Oct 10, 2018の時点で以下の通り（参考：[DirectXTK](https://github.com/Microsoft/DirectXTK)）。

|ヘッダ名 | 内容|
|:------------------------|:---------------------------------------|
|Audio.h  |  XAudio2を使用した低レベルのオーディオAPI（Audioパブリックヘッダ用のDirectXTK）|
|CommonStates.h  | 一般的に使用されるD3Dステートオブジェクトを提供するファクトリ|
|DDSTextureLoader.h  | 軽量なDDSファイルテクスチャローダー|
|DirectXHelpers.h  |  D3Dプログラミングのための色々な C++ヘルパー|
|Effects.h  | 一般的なレンダリングタスク用の組み込みシェーダのセット|
|GamePad.h  |  XInputを使用したゲームパッドコントローラヘルパー|
|GeometricPrimitive.h  | キューブや球などの基本図形を描画します。|
|GraphicsMemory.h  | 動的グラフィックスのメモリ割り当てを管理するヘルパー|
|Keyboard.h  | キーボードステートトラッキングヘルパー|
|Model.h  |  .CMO、.SDKMESH、または.VBOファイルから読み込まれたメッシュの描画|
|Mouse.h  | マウスヘルパー|
|PostProcess.h  | 一般的なプリプロセス処理用の組み込みシェーダのセット|
|PrimitiveBatch.h  | ユーザプリミティブを簡単かつ効率的に描画する方法|
|ScreenGrab.h  | 軽量なスクリーンショットセーバー|
|SimpleMath.h  |  DirectXMathの簡略化された C++ ラッパー|
|SpriteBatch.h  | シンプルで効率的な2Dスプライトレンダリング|
|SpriteFont.h  | ビットマップベースのテキストレンダリング|
|VertexTypes.h  | 一般的に使用される頂点データフォーマットの構造|
|WICTextureLoader.h  |  WICベースのイメージファイルテクスチャローダー|
|XboxDDSTextureLoader.h  |  Xbox OneのDDSTextureLoader専用アプリケーション|

**今回はFontを描画したいので SpriteFont.h の SpriteFontクラスを使う**。このSpriteFontクラスは、「spritefontデータ」を作成しておく必要がある。このデータには、テクスチャ・テクスチャ情報・フォント描画に必要な情報が含まれている。このデータを作成するのがDirectXTKに含まれている「MakeSpriteFont.exe」だ。以下はそのフォルダ構造である。

![Picture 2018-10-10 18_02_03.png](https://qiita-image-store.s3.amazonaws.com/0/299280/1d11590b-64cb-12e7-95bf-eb0da0d6409c.png)

MakeSpriteFontフォルダに MakeSpritFont.exe がある。
![Picture 2018-10-10 18_03_34.png](https://qiita-image-store.s3.amazonaws.com/0/299280/3594893d-22c7-11c1-04df-daf5d0ed3433.png)

##MakeSpriteFontの問題点

MakeSpriteFont.exeは「使用するフォントの文字を切り出して、テクスチャファイルと付属情報を生成し、「spritefontデータ」にするツールだ。使用する文字の数が多ければ、それだけ変換に時間を要す。加えてそのアルゴリズムが問題で、テクスチャ画像の空き領域を１ピクセル単位で探しているらしい。漢字がだいたい２万文字あるので、**変換に多大な時間が必要**になる。ちなみに、**私の環境では12時間経っても終わらなかった**（ Intel Core2Quad 2.85 GHz）。

##MakeSpriteFontの解決策
既にこの問題について解決策を提示し、記事にしてくれてる方がいた。**ZeroGram**さんの[DirectXTKでフォント表示、日本語対応](http://zerogram.info/?p=1012)（2013/4/29）である。記事の日付が2013/4/29なのでとても古い。ここで書かれている内容が現在（Oct 10, 2018）でも通用するのかを検証してみた。

**結果からいうと上手くいった。**その御蔭で「spritefontデータ」の作成が約１分で完了した。**大幅な時間改善である。**

以下にその手順を記す。

1. **ZeroGram**さんのサンプルプログラム MakeSpriteFontModify.zip をダウンロードする。
2. zipを展開すると、modifyフォルダに2つのファイルがある(GlyphPacker.cs, TrueTypeImporter.cs)。
3. DirectXTK/MakeSpriteFontフォルダに、TrueTypeImporter.cs をコピーする。
4. DirectXTK/MakeSpriteFontフォルダの、GlyphPacker.cs をテキストエディタで開く。
5. **ZeroGram**さんの GlyphPacker.csの**ArrangeGlyphs関数**を探して、関数ごとコピーする。MakeSpriteFontフォルダGlyphPacker.cs の **ArrangeGlyphs関数と差し替える**。
6. **ZeroGram**さんのGlyphPacker.csから**PositionGlyph関数**を探し、関数ごとコピーする。MakeSpriteFontフォルダGlyphPacker.cs の **ArrangeGlyphs関数の後に「貼り付け」る**。
7. DirectXTK/MakeSpriteFontフォルダの MakeSpriteFont.csproj をVisualStudio2015 で開き、ビルドする。

##MakeSpriteFontの解決策の結果
以下のコマンドを実行すると、約2万5千字もの漢字変換が行われる。所要時間は約１分。オリジナルよりも変換時間が短縮され、データも問題なく変換された。実際に表示させた所、問題なく表示された。

```c++
MakeSpriteFont.exe "ＭＳ ゴシック" myfile.spritefont /FontSize:12 /CharacterRegion:32-126 /CharacterRegion:0x3000-0x30ff /CharacterRegion:0xff00-0xffef /CharacterRegion:0x4e00-0x9fff  /CharacterRegion:0x2000-0x2fff
```

MakeSpriteFont.exeに渡すCharacterRegionオプションの意味は以下の通り。

|説明|オプション|
|:--|:--|
|アスキー文字|/CharacterRegion:32-126|
|ひらがなカタカナ|/CharacterRegion:0x3000-0x30ff|
|記号|/CharacterRegion:0xff01-0xffe5 |
|全角漢字|/CharacterRegion:0x4e00-0x9fff |
|全角特殊記号|/CharacterRegion:0x2000-0x2fff |

【コマンドプロンプトで実行した結果】は以下の通り。
![Picture 2018-10-10 18_42_09.png](https://qiita-image-store.s3.amazonaws.com/0/299280/c81a26a4-c7fe-6127-3324-1f26f4a3f052.png)

【DirectX11でSpriteFontクラスを使って表示させてみた結果】は以下の通り。
![Picture 2018-10-10 18_46_53.png](https://qiita-image-store.s3.amazonaws.com/0/299280/c83cfaad-0cbb-e776-3ec7-d2b5fc171140.png)


##まとめ
**ZeroGram**さんのサイトにある解決法で、問題は解決した。ただし、差し替え対象の2つのファイルをまるごとコピーすることはできず、ファイルの一部を直接編集しなければならなかった。GitHubに公開されている MakeSpriteFont.exe は、常に更新されているせいで、2018年現在だと今回のような対応が必要になった。

**ZeroGram**さん、ありがとうございました。