2012年10月6日土曜日

大まかな概念:DirectWriteを使った文字列描画

Direct2Dで文字を表示するにはDirectWriteというAPIの力を借ります。
DirectWriteはフォントデータの管理が主な仕事であって、それを描画するにはDirect2Dの様な別のAPIが必要みたいです。つまり2つのAPIが協力して文字を描画します。

下の図はDirect2DとDirectWriteを使って文字を表示する時に使う、関数、及びインタフェースをまとめてあります。

図の左半分がDirect2Dのインタフェースと関数です。
図の右半分がDirectWriteのインタフェースと関数です。

全体的な構造

Direct2D側にはID2D1RenderTarget(レンダーターゲット)というDirect2Dにおける基礎的なインタフェースとそれが持つ基本的な文字列描画関数であるDrawText( 図中左上 )DrawTextLayout(図中左下)を図示しました。この2つの関数のどちらを使っても文字列が描画出来ます。使い分けについては後で説明します。

DirectWrite側にはIDWriteFactoryというDirectWriteにおけるお母さんみたいな?インタフェースと、それが持つ関数CreateTextFromat(図中右上)CreateTextLayout(図中右下)を示しました。
この二つの関数はそれぞれIDWriteTextFormat(以下テキストフォーマット)と、IDWriteTextLayout(以下、 テキストレイアウト)というインターフェースを生成する役割があります。

このページでこれらの用語の色分けは図と一致させています。

DirectWriteを使って文字を描画するには今挙げた2つのインターフェースが重要な働きをします。簡単に説明すると

テキストフォーマット(IDWriteTextFormat)はフォントやフォントのスタイル等の書体情報を表します。

このインタフェースはCreateTextFormat()の引数としてポインタのポインタを渡す事で得られます。そして図中でそこから伸びる線を追うとDrawText()の引数、及びCreateTextLayout()の引数として使用されている様が確認できると思います。

・・・そしてもう一方の

テキストレイアウト(IDWriteTextLayout)テキストフォーマットを継承するインターフェースです。 テキストフォーマット が持つ書体情報に加え、描画する文字列自身の内容と、レイアウト(どんぐらいで改行するかとか)や、その他多くの情報も含みます。このインターフェースを作るには CreateTextLayout()を呼ぶ必要があるのですが、その際の引数として結局テキストフォーマットも必要になります。

さて、既にここまでで沢山のインターフェースや関数が登場した様に見えますが、ここで示した中で実際に文字を描画するメソッドはDrawText()DrawTextLayout()の2つしかありません。しかもDrawText()で文字を描画したい場合は図中の上半分を、DrawTextLayout()で文字を描画したい場合は図中の下半分に注目すれば概ねOKです。

細かいことはこれから説明しますがここでは
描画メソッドはDirect2DのDrawText()、もしくは DrawTextLayout() を使うという事と、そのメソッドが取る引数はDirectWriteのインタフェースであるテキストフォーマット、または テキストレイアウトを取るという事は覚えておいて下さい。


ここまでのまとめ
DrawText()  引数にテキストフォーマット (IDWriteTextFormat) が必要(だから事前に CreateTextFormat() も呼ぶ必要あり)
DrawTextLayout()  引数に テキストレイアウト(
IDWriteTextLayout) が必要(だから事前に CreateTextLayout()も呼ぶ必要があり、その前に結局CreateTextFormat()も呼ぶ必要あり。(´・ω・`))。

描画用メソッド

描画用のメソッドにはDrawText()DrawTextLayout()の2つがあると述べましたが役割の違いは何なのでしょうか?

構造上の大きな違い
DirectWriteのインターフェースである テキストレイアウト  IDWriteTextLayoutを必要とするかどうかです。 テキストレイアウトが必要な関数が DrawTextLayout()、必要ないのが DrawText()です。(関数名にLayoutが含まれているかどうかで判別できます。)

テキストレイアウトが必要な DrawTextLayout()は、言い換えれば  テキストレイアウトの機能を利用できる分けです。例えば テキストレイアウト のメソッドを使って描画する文字列に下線を付けるなどの操作が可能です。

ところで テキストレイアウト作成時にテキストフォーマットも作成する必要があると言いましたが、これは  テキストレイアウトテキストフォーマット の派生クラスであり、 テキストフォーマット が持つ情報は全て テキストレイアウトに含まれるという設計上の構造を反映しています。


テキストフォーマット を作る時は CreateTextFormat() の引数で、描画する文字列をどの様なフォントや書体にするか指定出来ますが、そこで指定した情報はそのままでは変更できません。しかし  CreateTextLayout() よって テキストレイアウト を生成すると、 テキストレイアウト のメソッドを通じてテキストフォーマット内部にあった書体情報も変更が可能になります。

DrawText() が必要とするDirectWriteのインターフェースは テキストフォーマット (IDWriteTextFormat) だけなので、使えるメソッド も少ないです。本来 テキストフォーマット の管轄である書体情報ですら書き換え不能なのは先程述べた通りです。

ところで、 IDWriteTextLayoutIDWriteTextFormat の派生クラスなので、 DrawText()IDWriteTextLayout を入れて使う事も出来ます。(ただしその場合、  テキストレイアウト で設定した項目は無視されます。)



2つの関数は実行速度にも大きな違いがあります。
DrawText()は一回きりの描画ならば DrawTextLayout()よりも若干速い様です。しかし2回以上の描画から、 DrawTextLayout()の方がずっと速くなります。
尚、どちらの関数を使うにしろ、細切れな短文を何度も出力するよりも沢山の文章を一度に出力した方が、高速です。

DrawTextLayout()のデメリット
描画する文字列そのものを変更する時は、別の文字列で初期化したテキストレイアウトを用意する必要があります。



参考:テキストの書式設定とレイアウト(MSDN)

0 件のコメント: