3.イメージビューワーを作ろう!!



 さてさて、前回のプログラムは説明が少なすぎて何が何だか分りにくかった上、「DirectXとしてちゃんと動いてんのか?コレ」状態でした。反省。
 そこで、今回は前回の反省を含めて、プログラムと説明を繰り返し書いて行く形式にしました。まともに動くソースファイルをが欲しい場合は、このページの最後の方にリンクがはってあるソースファイル(lzh形式)を解凍して、前回の方法で実行して下さい。もしくは、このページの説明を読んで自分で書いてみて下さい。ということは、他人に解る説明を書かなくては・・・うっ、責任重大(汗


 前置きはこの程度にして、本題に入りましょう。今回作るのはイメージビューワーです。読んで字のごとく、イメージを見ることが出来るアプリケーションです。で、今回作るアプリの特徴は、
 ・DirectDrawが使われている
 ・見れる画像はアプリと同一フォルダにある[sample.bmp]のみ
 ・メニューバーから[ファイル→終了]てな感じで終了できる
の3つです。特徴その一は・・・まあ、このページがDirectXの説明だからDirectDrawが使われていて当然。特徴の2つめは、3つめと少し重なるんですが、ファイルが複数選択できるとプログラムが多少難しくなるのが主な理由です。なぜ難しくなるかと言うと、特徴の3つめ、リソースを書き加えなければならないからなんですね。


 というわけで、先ずはリソースの説明から入ります。普通VCでプログラムを作った場合、メニューバーの内容は、全てリソースファイルに書かれています。リソースファイルに書き加えることで、メニューの内容は増えて行くわけです。
 左の画像を見て下さい。これは、今回作った[dx03.dsw]なるワークスペースの構造なんですが、この中にある[dx03.rc][resource.h]がリソースに関わるファイルです。この辺の詳しい説明は、私より詳しく説明してくれる人がいると思うので、割愛(笑
 では、早速ですが[dx03.rc]の内容です。

#include "resource.h"
IDR_MENU MENU DISCARDABLE
BEGIN
 POPUP "ファイル(&F)"
 BEGIN
  MENUITEM "終了(&X)" , IDM_EXIT
 END
END


 ・・・以上です。少ないですね。続いて、[resource.h]の内容です。

#define IDR_MENU 102
#define IDM_EXIT 40001


 ・・・以上です。いや、マジで。今回の目的はDirectDrawでビットマップを読み出す事が出来たら大成功ですから、余計なプロセスは省きます。ビットマップを呼び出して、プログラムを正常に終わらせることが出来れば充分なのです!!


 え〜、少々熱くなってしまったようで(汗 気を取り直して、次に行きましょう。今回はプログラムが300行近くて、全てをブラウザに表示させると大変なので、一部重要なプログラムのみを解説します。


 先ずは一番重要(?)な、ビットマップをDirectDrawサーフェスにロードする関数です。関数名は[bitmap_surface]とでもしておきましょう。下にプログラムの詳細を表示します。

//-----------------ビットマップをロードする関数-----------------//
LPDIRECTDRAWSURFACE7 bitmap_surface (LPCTSTR file_name)
{
	HDC hdc;
	HBITMAP bit;
	LPDIRECTDRAWSURFACE7 surf;

	//インターフェイスビットマップをロード
	bit = (HBITMAP) LoadImage
		(NULL,file_name,IMAGE_BITMAP,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);
	if (!bit)	//ロード失敗
		return NULL;

	//ビットマップのディメンジョンを取得
	BITMAP bitmap;
	GetObject (bit , sizeof (BITMAP) , &bitmap);
	int surf_width = bitmap.bmWidth;
	int surf_height = bitmap.bmHeight;

	//サーフェスを作成
	HRESULT ddrval;
	DDSURFACEDESC2 ddsd;
	ZeroMemory (&ddsd , sizeof (ddsd) );
	ddsd.dwSize = sizeof (DDSURFACEDESC2);
	ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
	ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
	ddsd.dwWidth = surf_width;
	ddsd.dwHeight = surf_height;

	//サーフェスを実際に作成
	ddrval = lpDD->CreateSurface (&ddsd , &surf , NULL);

	//サーフェスが作成できたか確認
	if (ddrval != DD_OK) {
		//出来なかったのでビットマップを解放、呼び出し側に失敗を返す
		DeleteObject (bit);
		return NULL;
	}
	else {
		//出来たのでサーフェスのDCを取得
		surf->GetDC (&hdc);

		//互換DCを作成
		HDC bit_dc = CreateCompatibleDC (hdc);

		//インターフェイスをサーフェスにブロック転送
		SelectObject (bit_dc , bit);
		BitBlt (hdc , 0 , 0 , surf_width , surf_height , bit_dc , 0 , 0 , SRCCOPY);

		//DCを解放
		surf->ReleaseDC (hdc);
		DeleteDC (bit_dc);
	}

	//ビットマップをクリア
	DeleteObject (bit);

	//呼び出し側にポインタを返す
	return surf;
}

 と、ここまで書いといて、「サーフェスって何?」という重要なことを説明することを忘れていました。サーフェスとは、イメージ操作をするために確保されるメモリ領域のことです。イメージの格納、画面への描画、アニメーション用のバックバッファとプライマリサーフェスとのデータ交換、等等・・・DirectDrawを扱うにはサーフェスは必須です。
 上の関数では、呼び出したビットマップイメージのサイズを元にサーフェスを作成しています。基本はこの程度です。意外と簡単ですね。
 この他にも、プログラム内の初期化関数でプライマリサーフェスを作成しています。プライマリサーフェスは、DirectDrawで画面に書き込みを行うときにアクセスに利用する、橋渡し適存在です。作成自体はCreateSurface ( )を呼び出して行うのですが、それに前後して、設定を行わなければなりません。この辺りは、ソースファイルの方を参考にして下さい。


 もう1つ、重要な関数としてインターフェイスの割り当てを解除する関数があります。

//------------インターフェイスの割り当て解除--------------//
void Cleanup (void)
{
	//インターフェイスを解放
	if (lpBmp){
		lpBmp->Release ( ); lpBmp = NULL;
	}
	if (lpDDSPrimary){
		lpDDSPrimary->Release ( ); lpDDSPrimary = NULL;
	}
	if (lpClip){
		lpClip->Release ( ); lpClip = NULL;
	}
	if (lpDD){
		lpDD->Release ( ); lpDD = NULL;
	}

	//エラーの場合は表示
	if (ErrStr)
		MessageBox (NULL , ErrStr , szCaption , MB_OK);
}

 プログラム終了時に、実行中に作成したDirectXインターフェースを解放する必要があります。解放しなかったら、大変なことになるのは想像に難しくありません。しかし、上の関数を作成、実行するに当たり、注意点が2つほどあります。
 ・インターフェイスは作成順の逆の順序で解放する
 ・作成されていないインターフェイスは解放しない
まだ使用しているインターフェイスがある可能性を考慮して、インターフェイスは作成順の逆で解放しましょう。また、作成されていないインターフェイスを解放しようとすると、プログラムエラーが起こります(当然です)。そのために、インターフェイスのポインタが有効かどうかをif文で確認しています。同じような文が続くので、面倒ならばdefineを使ってマクロ定義した方が簡単です。


 さて、説明はこの程度です。下にある[dx03_cpp.lzh]を解凍後コンパイルして実行、または[dx03_exe.lzh]内の[dx03.exe]を実行した結果、御使用のパソコンの解像度に合わせて、下の画像が表示されるはずです。



・・・良く解らん心の叫び(笑


まとめ
・「サーフェス」を頭の隅っこに記憶しておく
・プログラム終了時にインターフェイスは解放する
・筆者の更新が遅くても気にしない

ファイル
dx03.lzh
 ├ readme.txt
 ├ dx03.cpp
 ├ dx03.rc
 ├ resource.h
 └ sample.bmp
dx03_exe.lzh
 ├ readme.txt
 ├ dx03.exe
 └ sample.bmp


電脳館
written by みや
First Write : 2000.12.18
Last Update : 2001.03.06



戻る


テレワークならECナビ Yahoo 楽天 LINEがデータ消費ゼロで月額500円〜!
無料ホームページ 無料のクレジットカード 海外格安航空券 海外旅行保険が無料! 海外ホテル