サンプルコードのダウンロード

では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、
お持ちの方はVisual C++でプロジェクトファイルを開いてください(「ddraw_07.dsw」をダブルクリックすれば開けます)。
圧縮ファイルに含まれる「ddraw_07.exe」をダブルクリックし、実行してみてください。
どうでしょう?画面が切り替わり、フルスクリーン化し、
test0がフロントバッファに読み込まれると思います。

というわけで、今回は256色のビットマップ形式(*.bmp)をサーフェイスを読み込みたいと思います。

パレット設定

さて、256色のビットマップを正確に表示するためには、まずビットマップファイルが持つパレットを読み込む必要があります。
これをサボると、ビットマップの色がバケてしまいますからね。

ちなみに、256色の場合は、パレットが256個あり、サーフェイスの1ドット1ドットは表示しているパレット番号(色)を記憶しているだけです。これはビットマップ画像(*.bmp)も同じ構造です。

であ、よく解らない解説いってみよう!

//----------[ ビットマップファイルからパレットを読み込む ]--------------------------------------
void LoadPalette(char *filename){
	int i;
	FILE *fp;
	if((fp=fopen(filename,"rb"))==NULL){
		sprintf(tmp,"%s ファイルが見つかりません",filename);
		Quit(tmp);
	}
	fseek(fp,0x36,0);
	for(i=0;i<256;i++){
		peEntry[i].peBlue=fgetc(fp);
		peEntry[i].peGreen=fgetc(fp);
		peEntry[i].peRed=fgetc(fp);
		peEntry[i].peFlags=1;
		fgetc(fp);
	}
	fclose(fp);
	lpPalette->SetEntries(0,0,256,peEntry);
}

	略

	//呼び出し
	//パレット設定
	LoadPalette("test.bmp");

では、解説・・・って言っても見てわかりませんかねぇ?(爆)。私が解析したトコロ、BMP形式はパレット情報が0x36番地から格納されているので
fseekで読み込む位置をずらし、順番に青、緑、赤と読み込んでいます。256個読み込んだらlpPalette->SetEntries(0,0,256,peEntry);を実行して
DirectDrawのパレットを全て変更します(と言っても0、255番は変更できませんが・・・)。
ちなみにlpPalette->SetEntries(0,1,254,&peEntry[1]);でも良いでしょう(未確認)。

それと言っておきたい事は、これらの方法は1例にしか過ぎないという事です。
私もGDIはよく解らないので(というかよく解らない関数が多いので)適当にプログラムを組んでいます。
GDIに詳しい方ならもっと良い方法を知っているでしょう。
そういう場合は私にメールください(爆。

ビットマップ読み込み

ちうわけで、パレットの設定が終わったら、画像データ(?)を読み込みます。
パレットと同じようにデータを解析して適当に表示しても良いのですが、便利そうなシステムサービス関数を見つけたので今回はこれを使用してみました。

//----------[ ビットマップをサーフェイス上へ読み込む ]------------------------------------------
void LoadBitmap(LPDIRECTDRAWSURFACE sf,char *filename,int x,int y,int x_size,int y_size){
	HDC hdcs, hdcd;
	HANDLE hbmp,hbmpold;

	//APIを使用した読み込み
	if((hbmp=LoadImage(NULL,filename,IMAGE_BITMAP,
		x_size,y_size,LR_CREATEDIBSECTION|LR_LOADFROMFILE))==NULL){
		sprintf(tmp,"%s ファイルが見つかりません",filename);
		Quit(tmp);
	}
	
	//サーフェイスへ転送
	hdcs=CreateCompatibleDC(NULL);
	hbmpold=SelectObject(hdcs,hbmp);
	sf->GetDC(&hdcd);
	BitBlt(hdcd,x,y,x_size,y_size,hdcs,0,0,SRCCOPY);
	sf->ReleaseDC(hdcd);
	SelectObject(hdcs,hbmpold);
	DeleteDC(hdcs);
	DeleteObject(hbmp);
}

	略

	//ビットマップをフロントバッファへ読み込む
	LoadBitmap(lpFront,"test.bmp",0,32,160,32);

んー、面倒ですが仕方ない(謎)のでちゃちゃっと説明しちゃいますね。

	//APIを使用した読み込み
	if((hbmp=LoadImage(NULL,filename,IMAGE_BITMAP,
		x_size,y_size,LR_CREATEDIBSECTION|LR_LOADFROMFILE))==NULL){
		sprintf(tmp,"%s ファイルが見つかりません",filename);
		Quit(tmp);
	}

まず、最初のLoadImage関数、ここではビットマップファイルをメモリ内に読み込むといった処理をしています。

書式 HANDLE LoadImage( HINSTANCE hinst, LPCTSTR lpszName , UINT uType , int cxDesired , int cyDesired , UINT fuLoad );
hinst イメージが格納されているアプリケーションのインスタンスを認識するハンドル。

そもそもこの関数はリソースと呼ばれる実行ファイル(*.EXE)に含まれるデータから読み込むものなので、関係ないからNULLぢゃ。

lpszName ファイル名
uType ロードするイメージのタイプを指定するのですが、ビットマップを読み込むのでIMAGE_BITMAPを指定。
cxDesired 横幅
cyDesired 縦幅
fuLoad ロード用のフラグ。今回は外部ファイルからビットマップを読み込むという事でLR_CREATEDIBSECTION | LR_LOADFROMFILEを指定。
戻り値 ロードされたイメージのハンドル
	hdcs=CreateCompatibleDC(NULL);
	hbmpold=SelectObject(hdcs,hbmp);

そうしたら、次にhdcs=CreateCompatibleDC(NULL);を実行し、適当なデバイスコンテキストを作成します(戻り値:デバイスコンテキストのハンドル)。
次に、hbmpold=SelectObject(hdcs,hbmp);を実行し、デバイスコンテキストに先ほど読み込んだビットマップを選択させます(戻り値:選択前のオブジェクト)。
これでビットマップが読み込まれているデバイスコンテキストへのハンドルが取得できた事になります。よくわかりませんが、GDIはこういうものです(爆)。
まぁ、細かい事は気にせず、こうすれば良いという事を覚えてしまえばいいでしょう。

	sf->GetDC(&hdcd);
	BitBlt(hdcd,x,y,x_size,y_size,hdcs,0,0,SRCCOPY);
	sf->ReleaseDC(hdcd);

で、第4回で記述したように、サーフェイスへのデバイスコンテキストハンドルを取得し、BitBltというGDI関数を使用してビットマップをサーフェイスに転送します。

書式 BOOL BitBlt( HDC hdcDest, int nXDest , int nYDest , int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop );
hdcDest 転送先のデバイスコンテキストのハンドル
nXDest 転送先の左上X座標
nYDest 転送先の左上Y座標
nWidth 画像の横幅
nHeight 画像の縦幅
hdcSrc 転送元のデバイスコンテキストのハンドル
nXSrc 転送元の左上X座標
nYSrc 転送元の左上Y座標
dwRop 転送時のオプションのようなものだが、ここは「そっくりそのまま転送」を意味するSRCCOPYを指定。
戻り値 成功するとTRUEが返ってくるらしい。
	SelectObject(hdcs,hbmpold);
	DeleteDC(hdcs);
	DeleteObject(hbmp);

最後に、後始末です。最初にSelectObject(hdcs,hbmpold);としていますが、これはhdcsに変更前のオブジェクトを選択していると言う事です(謎)。そうしたら
DeleteDCで適当に作成したデバイスコンテキストを消去し、DeleteObjectで、メモリ内に読み込んであるビットマップを消去しています。

だー、もうGDIはよーわからん(^^;こんなんだからMS-DOSからWindowsになかなか移行できんプログラマが多いのだよ・・・。
今回は(も?)カット&ペーストでそのまま使用してください(逝)。

記事検索

アーカイブ