2012年10月7日日曜日

DrawText()を使ったテキストの描画

Direct2Dの基本的な文字描画関数にはDrawText()DrawTextLayout()がある事と、その際にDirectWriteのインターフェースもいくつか作成する必要がある事を前回の大まかな概念で説明しました。
文字列の描画に関わる基本要素

今回はとりあえず DrawText() で実際に文字を出す例を示そうと思います。 DrawTextLayout() で描画する時もここで解説する事の多くが役立つと思います。

なお、 DrawText()DrawTextLayout() もDirect2Dのレンダーターゲットインターフェースのメソッドですから、レンダーターゲットが作られている事が前提となります。レンダーターゲットの作り方は既に説明済みなのでここでは触れません。

おおまかな流れ

 下の図の番号は DrawText() を行うまでの基本的な手順です。

DrawText()までの手順

1)IDWriteFactoryの作成
2)CreateTextFormat()を利用してテキストフォーマットIDWriteTextFormat)を作成
3) DrawText() を呼ぶ
という3ステップに分けました。

我々は DrawText() を呼びたいだけなんですが、その引数で

どの様な書式の文字列を作成するか?

という情報をテキストフォーマットで指定する必要があります。
テキストフォーマットIDWriteTextFormat というDirectWriteのインターフェースなので先に示したの手順が必要になります。

…その前にDirectWriteを使えるようにVC++にライブラリ(DWrite.lib)を登録しましょう。
プロパティ→リンカ→入力→追加の依存ファイルにDWrite.libを加えればOKです。
また、ソースコード中にヘッダファイルのインクルードが必要です。
#include <D2d1.h>
#include <Dwrite.h>

1)IDWriteFactoryの作成

以下はpWriteFactory_という変数名でIDWriteFactoryを作成する例です。

IDWriteFactory* pWriteFactory_;
HRESULT hr;

hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&pWriteFactory_)
);
//失敗時はメッセージBOXを表示
if (!SUCCEEDED(hr))
{
MessageBox(NULL,L"DWriteCreateFactory()に失敗",NULL,NULL);
return false;
 }

DWriteCreateFactory()という関数にIDWriteFactoryのポインタを入れて上げればOKです。ただしIUnknown型の引数を渡す必要があるのでキャストしています。

2)CreateTextFormat()テキストフォーマットを作成

下の例は pFom という変数名のテキストフォーマット(IDWriteTextFormat)を作成しています。
なお、成否の調査    if (SUCCEEDED(hr))は省略しました。
_________
IDWriteTextFormat* pFom = NULL;

pWriteFactory_->CreateTextFormat(
 L"メイリオ", // フォント(MS P明朝/MS Pゴシックとか)
 NULL, // フォントコレクション(NULL=システムフォント)
 DWRITE_FONT_WEIGHT_NORMAL, //太さ
 DWRITE_FONT_STYLE_NORMAL, //スタイル(傾き)
 DWRITE_FONT_STRETCH_NORMAL,//幅
 100.0f,//文字の大きさ
L"ja-jp",//ロケール(地域)/ja-jp/en-us
& pFom
);
________

CreateTextFormat()の引数でどのような書体=テキストフォーマットを作成するかを指定できます。DrawText()を呼ぶ時に、ここで作ったテキストフォーマットが利用される分けです。ただし、全てのフォントがこれらのパラメーターの全てをサポートしている分けではなかった様な気がします。

第1引数
フォントの種類です。 例えばメイリオだとかMS P明朝だとかMS Pゴシックなどです。(私の環境では)ここで間違った名前を入れちゃうとメイリオになるっぽいです。(メイリオっていうフォントは現状、一番綺麗にCleary Typeで描画される様な気がします。)
参考:フォントを列挙する方法

第2引数
フォントコレクションを指定します。フォントというのは誰がどれだけ作っているか分からないのでこの様な概念が必要になります。一つのフォントコレクションの中に、第一引数で選べた様な複数のフォントが格納されていたりします。NULLを指定すれば、システムフォントコレクションが利用されます。システムフォントコレクションというのはOSに最初から備わっているフォントコレクションの事です(多分)。

第3引数
 DWRITE_FONT_WEIGHT 列挙型で文字の太さを指定できます。

第4引数
DWRITE_FONT_STYLE 列挙型でイタリックの様な傾斜のあるスタイルを指定できます。

第5引数
DWRITE_FONT_STRETCH 列挙型で文字の幅を指定でき・・・るはずなのですが私はうまく行きませんでした。

第6引数
FLOATでフォントの大きさを指定します。

第7引数
ロケール名です。言語圏を指定します。

第8引数
ここに IDWriteTextFormatのポインタ変数のアドレスを入れます。関数呼び出し後にこの引数で指定した変数がテキストフォーマットとして完成する分けです。


3) DrawText() を呼ぶ

さて、ようやく最後のステップ、本命のDrawText()を呼び出して文字列の描画を行うことが出来ます。
たかが文字を描画するだけでどんだけ大変なんだアホ、バカ、ボケ!
ヽ(`Д´)ノ・・・と思っていた人も溜飲が下がる瞬間だと言えます。
(*´ー`*)ーЭ ふぅ・・・

大きさ100でテキストフォーマットを作った例

下の例では一旦std::wstringに描画したい文字列を格納しているので
#include <string>
だか何かのヘッダファイルも必要です。

//描画する文字列
std::wstring wst(L"abcd文字列");

//レイアウト
float width = 1300.0f;
float height = 100.0f;

//描画位置
D2D1_RECT_F rect;
rect.left = 50.0f;
rect.top = 50.0f;
rect.right = rect.left + width;
rect.bottom = rect.top + height;

//DrawText
 pHwndRenderTarget->DrawText(wst.c_str(), wst.size(), pFom, rect, pBrush_);


レンダーターゲットは pHwndRenderTargetという名前の変数を事前に用意してあります。レンダーターゲットの作り方はここで説明しました。
DrawText()の引数を解説します。

第1引数: WCHAR *
描画する文字列を表します。

第2数:UINT
描画する文字の数です。

第3引数:IDWriteTextFormat
テキストフォーマットです。

第4引数: D2D1_RECT_F
テキストの配置を表す矩形です。D2D1_RECT_Fという構造体メンバleftがテキスト表示範囲の左端の座標を、topが上端の座標を表します。
矩形の幅は文字列の行の長さを表します。
例としてこれを100に変えてみましょう。(これは上の例におけるレイアウトというコメントの部分を次の様に変えれば出来ます。)

//レイアウト
float width = 220.0f;
float height = 100.0f;

すると実行結果は次の様に改行されます。

長方形はレイアウト幅を示します

ちなみに文字列に改行コードを入れても改行出来ます。
改行コード

第5引数: ID2D1Brush
テキストを描画するブラシです。これはDirect2Dの基本的なインターフェースであり、描画色等を指定できます。
-----------------------
これ以降の引数はオプションです。上の例では指定していません。
------------------------
第6引数:D2D1_DRAW_TEXT_OPTIONS
描画オプションです。指定しないとデフォルト引数がD2D1_DRAW_TEXT_OPTIONS_NONEとなります。
ここで
D2D1_DRAW_TEXT_OPTIONS_CLIP
を指定するとどうなるでしょうか?
結果は下の様になります。

 第4引数で指定した矩形の中に収まらない部分はトリミングされます。

このレイアウトを表す矩形の概念は次回 IDWriteTextLayout(テキストレイアウト)を作る時にも登場します。

そう言えば、使い終わった後はお約束のインターフェースの解放処理もやった方が良いのだと思います。

例)
if(pWriteFactory_!= NULL) pWriteFactory_->Release();

pFomやDirect2D系のリソースも言わずもがな。

0 件のコメント: