【DirectWrite】DirectX11でフォントファイルを読み込んで文字を描画できるクラスを作った【DirectX】
今回はDirectWriteを使って、ttf形式などのフォントファイルを読み込んで文字列を描画するクラスを作りました。
以前作ったDirectWriteのクラスをアップデートしたものになります(1年ぶり)
この記事の中だと「フォントの埋め込み」とか言ってるやつですね。
どういうメリットがあるの?
実行環境に左右されず、フォントファイルを指定できる
DirectWriteでシステムフォント(PC内にインストール済みのフォント)を使用すると相手先の実行環境に左右される欠点がありますが、フォントファイルを一緒に配布してそこから読み込めば、自分の意図したフォントを使用することができます。
自作したフォントファイルをゲーム内で使用できる
ttf形式など、一般的なフォントファイルに対応しているので、
自作したフォントファイルをゲーム内で呼び出して使用することもできます。
文字の描画が楽になるよ
これはDirectWriteを使用するメリット。
簡単なスコア表示からセリフ表示まで、DirectXでゲームを作る際は役立ちます。
今回は前回のDirectWriteの記事と同様に、
すぐ使えるDirectWriteのクラスを目指して設計しました。
よければお使いください。
目次
ソースコード
使い方を載せたサンプルクラスも用意しているので、よければお使いください。
また、リファレンスや使い方はReadme.mdにも載っています。
ヘッダーとソースファイルをプロジェクトに追加してお使いください。
注意点
- 開発環境はDirectX11を使用しました。
- DirectX12でも利用できるとは思いますが、動作未確認です。
- 諸事情あって古い方法を使って実装しました。
- dwrite_3.hを使用できる方はこちらの方の方法をおすすめします。
- 利用自体は問題なくできると思います(小声)
初期設定
デバイス作成をDirect2D対応に変更する
まず、DirectXの初期設定の際に行う、デバイスの設定を変更します。
DirectWriteはDirect2Dの技術も使っており、Direct3Dと共存させる必要があります。
D3D11CreateDeviceもしくはD3D11CreateDeviceAndSwapChain関数の第4引数を変更します。
変更先の値は D3D11_CREATE_DEVICE_BGRA_SUPPORT です。
D3D11_CREATE_DEVICE_FLAG型のenumでサポートされています
IDXGISwapChainを渡せるようにする
同じくデバイス作成時に使用したIDXGISwapChainのポインタを渡せるようにしてください。
戻り値が IDXGISwapChain* 型のget関数を作成とかで対処してください。
フォントファイルの追加とパスの設定
プロジェクト内に.ttfなどのフォントファイルを追加後、
DirectWriteCustomFont.h内のFontList::FontPathにパスを追加してください。
使用方法
ソースコード
gist5b02e44d77cd9a461304fba832ee4538
初期化
DirectWriteCustomFontのインスタンスを作成後、
必ずinit関数を呼び出してください。
ここで初期設定が行われます。同時に、フォントも読み込まれます。
フォント設定
FontData構造体の変数を編集後、SetFont関数に引数で渡してください。
詳細はヘッダーに書いてありますが、フォント名やサイズをここで指定します。
また、コンストラクタでFontData構造体を渡すとそちらでも設定できます。
描画
DrawString関数で文字列、描画位置、テキストの整形を指定して描画します。
描画位置はD3DXVECTOR2で先頭を指定するパターンと、D2D1_RECT_Fで描画領域を指定するパターンの2つを用意しています。
実行例
こんな感じで文字列が表示が表示されたら成功です。
表示されない場合は、描画順番や描画位置、背景色と被っていないか見直してみてください。
トラブルシューティング
指定したフォントではないフォントで表示される
まずは以下の点を見直してみてください。
フォント名はフォントファイルの名前と違う場合はあります。*2
ttfファイルをクリックして、「フォント名」に表示されたものを確認してください。
ロケール名はデフォルトでen-usですが、日本語フォントは非対応の場合があります。
その場合、GetFontFamilyName関数でja-JP対応のフォント名を再取得してください。
フォント設定が反映されない
FontData構造体の変数を編集後、その都度SetFont関数に引数で渡してください。
それでも反映されない場合、引数の設定が間違っているかを確認してください。
文章が画面からはみ出てしまう
DrawString関数のうち、D2D1_RECT_F型で描画領域を指定する物をお使いください。
この形式だと、領域をはみ出る場合は自動で改行してくれる機能があります。
D2D1_RECT_F型で指定した四角形の中に表示されます。
リファレンス
Init
- 全体の初期設定に使用します。
- 呼び出しと同時にFontList::FontPassで指定されたフォントも読み込まれます。
- できるだけ早い段階で呼ぶことをおすすめします(念のために)。
パラメータ
IDXGISwapChain* swapChain: Direct2Dの初期設定時、バックバッファの取得で使用します。
SetFont
- 指定したフォントデータを使用してフォント設定を適用します。
- フォントデータを編集した場合、その都度反映させてください。
パラメータ
FontData data: フォントの名前、サイズ、スタイルなどを指定したものです。
DrawString
- 指定した文字列を、指定された位置に描画します。
- 1件のオーバーロードが存在します。
パラメータ
string str: 描画するテキスト。
D3DXVECTOR2 pos: 描画ポジション。先頭文字の開始位置を指定します。D2D1_DRAW_TEXT_OPTIONS options: テキストの整形を指定します。
bool shadow: 影の描画を指定します。(しれっと追加)
D2D1_RECT_F rect: 描画領域。四角で指定した中に文字列を描画します。
GetFontName
- 読み込んだフォントファイルから、フォント名を返します。
- フォント設定時のフォント名の記載ミスが起きないため、おすすめです。*3
- こちらを使わない場合、FontDataのFontでフォント名を文字列で指定します。
パラメータ
int num: FontList::Fontpathで指定したフォントファイルの順番を指定。
戻り値
wstring: 指定されたフォントファイルのフォント名。
GetFontNameNum
- 読み込んだフォントファイルの数を返します。
戻り値
int: 読み込んだフォントファイルの数。
GetFontFamilyName
- フォントファイルの名前を読み込み直します。
- ロケール名を指定できるので、日本語版フォントを読み込みたい場合などに使用してください。
パラメータ
IDWriteFontCollection* customFontCollection: フォントファミリー名を読み込み直すフォントコレクション。
const WCHAR* locale: ロケール名。デフォルトでは"en-us"が選択されています。
GetAllFontFamilyName
- 全てのフォント名を読み込み直します。
注意
英語や日本語のフォント名が全て読み込まれるので、
順番がフォントファイルの順番と異なることになります。
(GetFontNameの使用が難しくなります)
正直、あまりおすすめはしません。
パラメータ
IDWriteFontCollection* customFontCollection: フォントファミリー名を読み込み直すフォントコレクションを指定します。
FontLoader
- フォントファイルを読み込み直します。
- FontList::FontPassにパスを追加した際などにお使いください。
DirectWriteの解説(メモ書き)
ここからはクラスを使用するだけなら関係ないのですが、
せっかく作ったのでDirectWriteの使い方をざっくりと解説しようと思います。
興味がある方はご覧ください。
注意
冒頭にも述べた通り、こちらでは古い方法で実装しています。
dwrite_3.hを使用できる方はこちらの解説の方が参考になります。
IDWriteFontCollection
DirectWriteでのフォントコレクション。
フォントコレクションとは複数のフォントを束ね合わせたもので、
基本的に使用するフォント一覧と呼んでも差し支えはない。
IDWriteFontFamily
DirectWriteでのフォントファミリー。
フォントファミリーとは、ウェイト(太さ)の違いをまとめたフォントの総称。
例えば、Ubuntu-R.ttfとUbuntu-RI.ttfは違うフォントだが、Ubuntuというフォントファミリーでまとめられている。
IDWriteLocalizedStrings
DirectWriteでのフォントファミリー名。
フォントファミリー名とはその名の通りフォントファミリーの名前だが、先に例を挙げたようにファイル名とフォントファミリー名が異なる場合がある。
Windowsの場合、ファイルをクリックすると表示される。
FindLocaleName関数
指定したロケールフォントファミリー名のインデックスを取得する。
IDWriteLocalizedStrings内には英語版、日本語版…のように複数のフォントファミリー名が入っている場合があり、ここでロケールを指定すると該当する番号をindexで渡してくれる。*4
GetString関数
indexで指定された番号のロケール名をWCHAR*型の文字列で渡してくれる。
ロケール名に特にこだわりがない場合、indexは0を指定しておけばいい。
IDWriteFontFileEnumerator
DirectWriteでカスタムフォントファイルを列挙するとかなんとか。
カスタムフォントコレクション(後述)を実装するときに使う。
インターフェースなので、使用する際は実装する必要がある。
IDWriteFontCollectionLoader
DirectWriteのカスタムフォントコレクションを作成する際に使う。
要するに、自分でフォントコレクションを作りたい場合は、これでロードする必要がある。
インターフェースなので、使用する際は自分で実装する必要がある。
CreateEnumeratorFromKey関数
実際にフォントコレクションを作る際に使用するメソッドがコレ。
フォントファイルを読み込み、それを束ね合わせてフォントコレクションを作る。
その動作については自分で定義するのだが、とりあえず引数のfontFileEnumeratorに先程作ったIDWriteFontFileEnumeratorを使ってフォントファイルを列挙させていけばいい。
CreateCustomFontCollection関数
IDWriteFactoryクラス内のメソッド。カスタムフォントコレクションを作る。
第4引数がIDWriteFontCollection型なので、それに作ったフォントコレクションが格納される。
これを呼び出してしまえば、カスタムフォントコレクションの作成はおしまい。
フォントコレクションの使い方
IDWriteFactoryクラスのCreateTextFormatメソッドで第2引数に指定する。
引数がnullでも構わないが、その場合はシステムフォント(動作環境にインストール済みのフォント)を元にフォントが呼び出される。
第1引数のfontFamilyNameでフォントファミリー名を指定する必要があり、ウェイト(太さ)は第3引数のfontWeightで指定できる。
実際の使用例については
詳しくはソースコードを見てください(投げやり)。
ソースファイル内にできるだけ丁寧な説明を加えてあるので、参考になるかと思われます。
基礎的な描画の部分もコメントを加えてあるので、ご参考ください。
最後に
今回はDirectX環境でDirectWriteを使い、
フォントファイルからフォントを読み込んで文字列を描画するクラスを紹介しました。
諸事情あって化石みたいな方法での実装となりましたが、
動作は可能なのでよろしければお使いください。簡単に文字列を描画できます。
最後に書いたメモ書きもお役に立てば幸いです。
機能の不具合、動作不良があればコメントでご質問・ご報告お待ちしています。
(必ず回答できるとは限りません…)
また、Githubのリポジトリに修正版のプルリクエストを投げていただいても構いません。
よろしくお願いいたします。