退廃的ソースコードコンテナ

ゲームシステムを組むのが好きな人の備忘録

【DirectWrite】DirectX11でフォントファイルを読み込んで文字を描画できるクラスを作った【DirectX】

今回はDirectWriteを使って、ttf形式などのフォントファイルを読み込んで文字列を描画するクラスを作りました。

 

以前作ったDirectWriteのクラスをアップデートしたものになります(1年ぶり)

この記事の中だと「フォントの埋め込み」とか言ってるやつですね。

islingtonsystem.hatenablog.jp

 

どういうメリットがあるの?

実行環境に左右されず、フォントファイルを指定できる

DirectWriteでシステムフォント(PC内にインストール済みのフォント)を使用すると相手先の実行環境に左右される欠点がありますが、フォントファイルを一緒に配布してそこから読み込めば、自分の意図したフォントを使用することができます。

 

自作したフォントファイルをゲーム内で使用できる

ttf形式など、一般的なフォントファイルに対応しているので、

自作したフォントファイルをゲーム内で呼び出して使用することもできます。

 

文字の描画が楽になるよ

これはDirectWriteを使用するメリット。

簡単なスコア表示からセリフ表示まで、DirectXでゲームを作る際は役立ちます。

learn.microsoft.com

 

今回は前回のDirectWriteの記事と同様に、

すぐ使えるDirectWriteのクラスを目指して設計しました。

よければお使いください。

目次

 

ソースコード

ソースコードGithubリポジトリに公開しています。

使い方を載せたサンプルクラスも用意しているので、よければお使いください。

また、リファレンスや使い方はReadme.mdにも載っています。

 

ヘッダーとソースファイルをプロジェクトに追加してお使いください。

github.com

 

注意点

  • 開発環境はDirectX11を使用しました。
  • DirectX12でも利用できるとは思いますが、動作未確認です。
  • 諸事情あって古い方法を使って実装しました。
  • dwrite_3.hを使用できる方はこちらの方の方法をおすすめします。
  • 利用自体は問題なくできると思います(小声)

deep-verdure.hatenablog.com

 

初期設定

バイス作成をDirect2D対応に変更する

まず、DirectX初期設定の際に行う、バイスの設定を変更します。

DirectWriteDirect2Dの技術も使っており、Direct3D共存させる必要があります。

 

D3D11CreateDeviceもしくはD3D11CreateDeviceAndSwapChain関数の第4引数を変更します。

D3D11CreateDeviceAndSwapChainの変更例

変更先の値は D3D11_CREATE_DEVICE_BGRA_SUPPORT です。

D3D11_CREATE_DEVICE_FLAG型のenumでサポートされています

learn.microsoft.com

 

IDXGISwapChainを渡せるようにする

同じくデバイス作成時に使用したIDXGISwapChainのポインタを渡せるようにしてください。

戻り値が IDXGISwapChain* 型のget関数を作成とかで対処してください。

 

フォントファイルの追加とパスの設定

プロジェクト内に.ttfなどのフォントファイルを追加後、

DirectWriteCustomFont.h内のFontList::FontPathパスを追加してください。

こんな風にフォントファイルのパスを指定してください



使用方法

ソースコード

gist5b02e44d77cd9a461304fba832ee4538

 

初期化

DirectWriteCustomFontのインスタンスを作成後、

必ずinit関数を呼び出してください。

ここで初期設定が行われます。同時に、フォントも読み込まれます。

 

フォント設定

FontData構造体の変数を編集後、SetFont関数に引数で渡してください。

詳細はヘッダーに書いてありますが、フォント名やサイズをここで指定します。

 

また、コンストラクタでFontData構造体を渡すとそちらでも設定できます。

FontData構造体で設定可能な項目


描画

DrawString関数で文字列、描画位置、テキストの整形を指定して描画します。

描画位置はD3DXVECTOR2で先頭を指定するパターンと、D2D1_RECT_Fで描画領域を指定するパターンの2つを用意しています。

 

実行例

ボタンを押すとフォントを変えるようにしてみました

こんな感じで文字列が表示が表示されたら成功です。

表示されない場合は、描画順番描画位置背景色と被っていないか見直してみてください。

 

トラブルシューティング

指定したフォントではないフォントで表示される

まずは以下の点を見直してみてください。

  • フォントファイルは破損していないか?
  • フォントのパスは正しいか?
  • フォント名は間違っていないか?(文字列で指定の場合)
  • ロケールは合っているか?(メソッドでフォント名を取得する場合*1

 

フォント名はフォントファイルの名前と違う場合はあります。*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
  • こちらを使わない場合、FontDataFontでフォント名を文字列で指定します。

パラメータ
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を使用できる方はこちらの解説の方が参考になります。

deep-verdure.hatenablog.com

 

IDWriteFontCollection

DirectWriteでのフォントコレクション。

フォントコレクションとは複数のフォントを束ね合わせたもので、

基本的に使用するフォント一覧と呼んでも差し支えはない。

learn.microsoft.com

 

IDWriteFontFamily

DirectWriteでのフォントファミリー。

フォントファミリーとは、ウェイト(太さ)の違いをまとめたフォントの総称。

例えば、Ubuntu-R.ttfUbuntu-RI.ttfは違うフォントだが、Ubuntuというフォントファミリーでまとめられている。

learn.microsoft.com

 

IDWriteLocalizedStrings

DirectWriteでのフォントファミリー名。

フォントファミリー名とはその名の通りフォントファミリーの名前だが、先に例を挙げたようにファイル名とフォントファミリー名が異なる場合がある。

Windowsの場合、ファイルをクリックすると表示される。

Windowsでttfファイルを開くと表示される

learn.microsoft.com

FindLocaleName関数

指定したロケールフォントファミリー名のインデックスを取得する。

IDWriteLocalizedStrings内には英語版、日本語版…のように複数のフォントファミリー名が入っている場合があり、ここでロケールを指定すると該当する番号をindexで渡してくれる。*4

learn.microsoft.com

 

GetString関数

indexで指定された番号のロケール名をWCHAR*型の文字列で渡してくれる。

ロケール名に特にこだわりがない場合、indexは0を指定しておけばいい。

learn.microsoft.com

 

IDWriteFontFileEnumerator

DirectWriteでカスタムフォントファイルを列挙するとかなんとか。

カスタムフォントコレクション(後述)を実装するときに使う。

インターフェースなので、使用する際は実装する必要がある。

learn.microsoft.com

 

IDWriteFontCollectionLoader

DirectWriteのカスタムフォントコレクションを作成する際に使う。

要するに、自分でフォントコレクションを作りたい場合は、これでロードする必要がある。

インターフェースなので、使用する際は自分で実装する必要がある。

learn.microsoft.com

 

CreateEnumeratorFromKey関数

実際にフォントコレクションを作る際に使用するメソッドがコレ。

フォントファイルを読み込みそれを束ね合わせてフォントコレクションを作る

その動作については自分で定義するのだが、とりあえず引数のfontFileEnumeratorに先程作ったIDWriteFontFileEnumeratorを使ってフォントファイルを列挙させていけばいい。

learn.microsoft.com

 

CreateCustomFontCollection関数

IDWriteFactoryクラス内のメソッド。カスタムフォントコレクションを作る

第4引数がIDWriteFontCollection型なので、それに作ったフォントコレクションが格納される。

これを呼び出してしまえば、カスタムフォントコレクションの作成はおしまい。

learn.microsoft.com

 

フォントコレクションの使い方

IDWriteFactoryクラスCreateTextFormatメソッドで第2引数に指定する。

引数がnullでも構わないが、その場合はシステムフォント(動作環境にインストール済みのフォント)を元にフォントが呼び出される。

第1引数のfontFamilyNameフォントファミリー名を指定する必要があり、ウェイト(太さ)は第3引数のfontWeightで指定できる。

learn.microsoft.com

 

実際の使用例については

詳しくはソースコードを見てください(投げやり)。

ソースファイル内にできるだけ丁寧な説明を加えてあるので、参考になるかと思われます。

基礎的な描画の部分もコメントを加えてあるので、ご参考ください。

github.com

 

最後に

今回はDirectX環境でDirectWriteを使い、

フォントファイルからフォントを読み込んで文字列を描画するクラスを紹介しました。

諸事情あって化石みたいな方法での実装となりましたが、

動作は可能なのでよろしければお使いください。簡単に文字列を描画できます。

最後に書いたメモ書きもお役に立てば幸いです。

 

機能の不具合、動作不良があればコメントでご質問・ご報告お待ちしています。

(必ず回答できるとは限りません…)

 

また、Githubリポジトリに修正版のプルリクエストを投げていただいても構いません。

よろしくお願いいたします。

*1:GetFontName関数で取得できます

*2:DirectWriteの用語で言うとフォントファミリー名

*3:フォントファミリー名を間違えると指定したフォントが表示されない

*4:見つからない場合は引数のexistsがFALSEを返す