- wglUseFontBitmaps関数でマルチバイト文字表示 -
Windows環境でOpenGLで文字を表示するにはwglUseFontBitmapを使います。
wglUseFontBitmapは指定したフォントを使って文字のビットマップをディスプレイリストとして作成してくれます。
(TextOut等のWindowsのGDIも使えますが、OpenGLではダブルバッファで描画する為ちらつき等が発生してしまいます)
そんなwglUseFontBitmapを使って日本語(マルチバイト文字)を表示してみます。


wglUseFontBitmapでの文字表示の流れとしては、

1.ディスプレイリスト領域を確保。
2.wglUseFontBitmapsで文字のディスプレイリストを作成。
3.glCallListでディスプレイリストを呼んで描画。

基本的にはこんな感じです。ただ、色々準備があります。
では、とりあえずソースを見て見ましょう。

[ソース]
int drawTextOnGL(char *text, HDC hdc, HFONT font, GLfloat red, GLfloat green, GLfloat blue,
		 GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat xmove)
{
	unsigned int textLength;	//引数で受け取ったテキストの長さ
	WCHAR * unicodeText;		//textをUNICODEに変換した文字列を格納する
	GLuint listbaseIdx;		//ディスプレイリストの最初のインデックス


	//日本語の文字列として扱うよう設定
	setlocale(LC_CTYPE, "jpn");

	//textの文字数を取得
	textLength = (unsigned int)_mbstrlen(text);
	if(textLength == -1)
		return -1;

	//textの文字数分のワイド文字列の領域を作成
	unicodeText = (WCHAR *)calloc(textLength + 1, sizeof(WCHAR));
	if(unicodeText == NULL)
	{
		return -2;
	}

	//取得したジョイントIDをUNICODEに変換する
	if(MultiByteToWideChar(CP_ACP,	0, text, -1, unicodeText, (sizeof(WCHAR) * textLength) + 1) == 0)
		return -3;

	SelectObject(hdc, font);

	//文字数分のディスプレイリストを確保し、ディスプレイリストの最初のインデックスを取得
	listbaseIdx = glGenLists(textLength);

	for(unsigned int textCnt = 0; textCnt < textLength; ++textCnt)
	{
		if(wglUseFontBitmapsW(hdc, unicodeText[textCnt], 1, listbaseIdx + textCnt) == FALSE)
		{
			//MessageBox(hwnd, "wglUseFontBitmaps() Error!!", "wgl Error", MB_OK);
		}
	}

	//文字色の指定
	glColor3f(red, green, blue);

	//1文字描画したら文字を何bitずらすか
	glBitmap( 0, 0, 0, 0, xmove/*x move*/, 0/*y move*/, NULL );

	//文字を描画する位置を決める
	glRasterPos3f(posX, posY, posZ);

	//ディスプレイリストを実行する
	for(unsigned int textCnt = 0; textCnt < textLength; textCnt++)
	{
		glCallList(listbaseIdx + (GLuint)textCnt);
	}

	return 1;
}


[詳細]

setlocale(LC_CTYPE, "jpn");

textLength = (unsigned int)_mbstrlen(text);
if(textLength == -1)
	return -1;

unicodeText = (WCHAR *)calloc(textLength + 1, sizeof(WCHAR));
if(unicodeText == NULL)
{
	return -2;
}
最初にsetlocale()で日本語文字列を扱うことを明示し、_mbstrlenでtextのマルチバイト文字数を計算します。 もちろん1バイト文字のみでも正しく文字数が返ってきます。 その文字数を使ってcalloc()でワイド文字配列の領域を確保します。 この配列にはUNICODEを入れるので1バイト文字もすべて2バイトになることからこのようにしています。 そのUNICODEを取得する為に次のようにします。
if(MultiByteToWideChar(CP_ACP,	0, text, -1, unicodeText, 
				(sizeof(WCHAR) * textLength) + 1) == 0)
	return -3;
MultiByteToWideChar()はその名の通り、マルチバイト文字をワイド文字に変換する関数です。 第1引数・第2引数は上記のように、第3引数にマルチバイト文字、第4引数には-1を指定して第3引数の文字数を計算させます。 第4引数にはcallocで作成したワイド文字配列の先頭アドレスを。第5引数は第4引数のバイト数を指定します。 成功するとunicodeTextにtextがUNICODEに変換されたものが格納されます。 そしていよいよディスプレイリストの作成です。
SelectObject(hdc, font);
listbaseIdx = glGenLists(textLength);

for(unsigned int textCnt = 0; textCnt < textLength; ++textCnt)
{
	if(wglUseFontBitmapsW(hdc, unicodeText[textCnt], 1, 
				listbaseIdx + textCnt) == FALSE)
	{
		//エラー処理
	}
}
まずSelectObject()でフォントを選択します。 第1引数にはOpenGLに関連付けられたデバイスコンテキストを指定します。 第2引数はHFONT構造体です。これは各自で構造体を宣言し、メンバ変数を設定してください。 glGenLists()は引数の数分の連続したディスプレイリストを作成し、ディスプレイリストの先頭のインデックスが返ってきます。 そして次のfor分で1文字ずつ文字をビットマップに変換し、ディスプレイリストに格納していきます。 wglUseFontBitmapsW()はUNICODEを専門に扱う関数です。ちなみにwglUseFontBitmapsA()はASCIIコードを扱うバージョンです。 第1引数にデバイスコンテキスト、第2引数にはUNICODEに変換された1文字、 第3引数には文字数、第4引数にはディスプレイリストのインデックスを指定します。 成功するとディスプレイリストの中には、ビットマップに変換された文字が格納されています。 あとはglCallList()で1文字分ずつディスプレイリストを呼び出すことで画面に文字が描画されます。 上の例では呼び出す前にglColor*()で文字色を、 glBitmap()で1文字描画した後にx軸方向にどのくらいずらして次の文字を描画するか、 という指定を、glRasterPos*()で最初の文字が描画される位置をそれぞれ指定しています。 マルチバイト文字が描画に関しては以上で終わりです。 注意点としてはデバイスコンテキストの取得はWM_PAINT内のBeginPaint()で取得するということです。 筆者の知識不足だと思いますが、GetDC()で取得した場合、上手く描画されませんでした。 あと、setlocale()と_mbstrlen()を使うために、locale.hとmbstring.hをインクルードしてください。


inserted by FC2 system