この授業ではまず640×480の8ビット(256色)のフルスクリーンモードでゲームを作成する。その場合のDirectDrawの使用方法は次のとおり。
- DirectDrawの主要オブジェクトの生成と初期化
- ビットマップ関連オブジェクトの生成と初期化
- パレットオブジェクトの生成とパレット情報の設定
***ここまでがDirectDraw使用前準備***- 画像の描画
- フリップ
***ここまでがゲームループ内の処理***- DirectDrawの主要オブジェクト、ビットマップ関連オブジェクトの開放
***ここまでがプログラム終了時に行う処理***※オブジェクトについては用語集の「オブジェクトの項」を参照
DirectDrawの主要オブジェクトの生成と初期化を行うプログラムを紹介する。なお、エラー処理は含まれていない。
/* グローバル変数として宣言 */ LPDIRECTDRAW7 g_pDD = NULL; // DirectDraw オブジェクト LPDIRECTDRAWSURFACE7 g_pDDSPrimary = NULL; // プライマリ・サーフェイス LPDIRECTDRAWSURFACE7 g_pDDSBack = NULL; // バック・サーフェイス /* プログラム */ HRESULT hRet; // IDirectDraw7インターフェイスの取得 hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, IID_IDirectDraw7, NULL); // 協調レベルの設定 hRet = g_pDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT); // ビデオモードの設定 640x480x8 hRet = g_pDD->SetDisplayMode(640, 480, 8, 0, 0); // プライマリ・サーフェイスの生成 ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddsd.dwBackBufferCount = 1; hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL); // バック・サーフェイスの生成 ZeroMemory(&ddscaps, sizeof(ddscaps)); ddscaps.dwCaps = DDSCAPS_BACKBUFFER; hRet = g_pDDSPrimary->GetAttachedSurface(&ddscaps, &g_pDDSBack);《解説》
- 1.IDirectDrawインターフェイスの取得
- DirectDrawを使うにはまずIDirectDraw7インターフェイスを取得する。通常はアプリケーションで1つ。
DirectDrawCreateEx関数はIDirectDraw7インターフェイスの取得に成功するとDD_OKを返す。- 2.画面モードの設定
- アプリケーションがどのような状態で実行されるかをセットする。まず、フルスクリーン・モードかウィンドウ・モードかを決め(協調レベルの設定)、次に画面サイズと色数を決める(ビデオ・モードの設定)。
- 3.プライマリ・サーフェイスの生成
- ディスプレイに表示されるサーフェイスを生成する。
- 4.バック・サーフェイスの生成
- ダブル・バッファリングを行うためにバック・サーフェイスを生成する。
正確には、プライマリ・サーフェイス作成時にバック・バッファを生成するよう指定しているため、GetAttachedSurface関数でバック・サーフェイスを取得する。《ここまでで何ができたのか?》
![]()
- ビデオメモリにプライマリ・サーフェイス、バック・サーフェイスが確保された。
用意したビットマップをDirectDrawで使うためのプログラムを紹介する。この処理は通常、用意した画像の数だけ行う。なお、エラー処理は含まれていない。
/* グローバル変数として宣言 */ LPDIRECTDRAWSURFACE7 g_pDDSBackimg = NULL; // 背景画像用オフスクリーン・サーフェイス char szBackimgBmp[] = "BACKIMG"; // 背景画像データ名 /* プログラム */ HRESULT hRet; // オフスクリーン・サーフェイスを生成する(画像毎) /* 背景画像 */ g_pDDSBackimg = DDLoadBitmap(g_pDD, szBackimgBmp, 0, 0);《解説》
DDLoadBitmap関数は、Microsoftが作成したDirectDraw汎用モジュール「
ddutil.cpp」に入っている関数で、以下の機能を持つ。
- オフスクリーン・サーフェイス・オブジェクトを生成し、そのオブジェクトへのポインタを返す。
- リソースに用意したビットマップを、オフスクリーン・サーフェイスへ転送する。
《ここまでで何ができたのか?》
![]()
- ビデオメモリに背景画像用のオフスクリーン・サーフェイスが確保され、ビットマップデータが読み込まれた。
256色のゲームを考えるため、パレットを用意しなければならない。パレットは
元となるビットマップから作成し、プライマリ・サーフェイスに設定する。なお、エラー処理は含まれていない。
/* グローバル変数として宣言 */ LPDIRECTDRAWPALETTE g_pDDPal = NULL; // プライマリサーフェイスパレット /* プログラム */ HRESULT hRet; // パレットの生成(指定した画像を元に、パレット情報を作成する) g_pDDPal = DDLoadPalette(g_pDD, szBackimgBmp); // プライマリー・サーフェイスにパレットを設定する。 hRet = g_pDDSPrimary->SetPalette(g_pDDPal);《解説》
DDLoadPalette関数は、Microsoftが作成したDirectDraw汎用モジュール「
ddutil.cpp」に入っている関数で、以下の機能を持つ。
- パレット・オブジェクトを生成し、そのオブジェクトへのポインタを返す。
- リソースに用意したビットマップを参照してパレット情報を取り出し、ビデオメモリに転送する。
SetPalette関数は、プライマリ・サーフェイス・オブジェクトが持つメンバー関数で、以下の機能を持つ。
- 作成されたパレット情報をプライマリ・サーフェイスのパレットとして設定する。
(デフォルトのパレットを無視する)《ここまでで何ができたのか?》
![]()
- 背景画像(BITMAP)からパレット情報を取り出し、パレット・オブジェクトに格納。
- パレット・オブジェクトをプライマリ・サーフェイスに設定。
画像の描画は、
描画したい画像(オフスクリーン・サーフェイス)の矩形をバック・サーフェイスに転送することで行われる。なお、エラー処理は含まれていない。
/* プログラム */ HRESULT hRet; RECT lpSrcRect = {0, 0, 640, 480}; // 画像の矩形 DWORD x = 0; // 転送先のx座標 DWORD y = 0; // 転送先のy座標 hRet = g_pDDSBack->BltFast(x, y, g_pDDBackimg, lpSrcRect, DDBLTFAST_XXXXXX);《解説》
BltFast関数は、バック・サーフェイス・オブジェクトが持つメンバー関数で、以下の機能を持つ。
- ビデオメモリ内のデータ転送を行う。
- 3つ目の引数に指定したオフスクリーン・サーフェイスから4つ目の引数に指定した矩形を取り出し、バック・サーフェイスのx、y座標に転送する。
- 転送の際、5つ目の引数でパラメータを指定する(詳細は後期で説明)。
《ここまでで何ができたのか?》
![]()
- オフスクリーン・サーフェイス上の画像がバック・サーフェイスの指定した位置に転送された。
バック・サーフェイスに転送した画像をディスプレイに表示するには、プライマリ・サーフェイスとバック・サーフェイスを切り替える、つまり
フリップを行う。この処理は、表示したい画像を全てバック・サーフェイスに転送してから一度だけ行う。なお、エラー処理は含まれていない。
/* プログラム */
HRESULT hRet;
hRet = g_pDDSPrimary->Flip(NULL, 0);《解説》
Flip関数は、プライマリ・サーフェイス・オブジェクトが持つメンバー関数で、プライマリ・サーフェイスとバック・サーフェイスを入れ替えるの機能を持つ。
《ここまでで何ができたのか?》
![]()
- オフスクリーン・サーフェイスとバック・サーフェイスが切り替わった。
プログラム終了時、作成済みのDirectDrawオブジェクトを開放しなければならない。
開放するDirectDrawの各種オブジェクト
- プライマリ・サーフェイス
- 画像ごとのオフスクリーン・サーフェイス
- パレット
- DirectDrawオブジェクト
※バック・サーフェイスはプライマリ・サーフェイスにアタッチして作成されているため、プライマリ・サーフェイスを開放すればバック・サーフェイスも自動的に開放される。
《プログラム例》
//----------------------------------------------------------------------------- // 関数名 : ReleaseDraw() // 機能概要: Direct Draw オブジェクトの削除 //----------------------------------------------------------------------------- void ReleaseDraw(void) { if (g_pDD != NULL) { if (g_pDDSPrimary != NULL) // プライマリーサーフェイス { g_pDDSPrimary->Release(); g_pDDSPrimary = NULL; } if (g_pDDSStart != NULL) // スタート画像用サーフェイス { g_pDDSStart->Release(); g_pDDSStart = NULL; } if (g_pDDPal != NULL) // パレット { g_pDDPal->Release(); g_pDDPal = NULL; } g_pDD->Release(); // DirectDrawオブジェクト g_pDD = NULL; } }《解説》
- オブジェクトに対してRelease()を実行すると、ビデオ・メモリから開放される。
- オブジェクトにNullを代入すると、メイン・メモリから開放される。
- この関数は、ウィンドウを閉じるときに一度だけ実行する。
《ここまでで何ができたのか?》
- ビデオメモリからすべてのサーフェイス、パレットが開放された。