ウィンドウモードへの対応。
フルスクリーンモードで作成されているプログラムを、 ウィンドウモードで動くよう修正する。
注)設問bでフルスクリーンモードの切り替えを行うため、myDraw.cpp内の変更点は変更前の状態をコメントアウトしておくとよい。手順1.Winmain.cppを変更する。
変更1.グローバル変数にウィンドウのハンドルを設定する。(InitializeWindow関数内のウィンドウハンドルの変数をグローバル変数にする。)
//----------------------------------------------------------------
// グローバル変数 Global data
//----------------------------------------------------------------
HWND hWnd;変更2.CalcScreenRect(HWND,LPRECT);を追加。
//----------------------------------------------------------------------------- // 関数名 : CalcScreenRect // 機能概要: クライアント領域のスクリーン座標を求める //----------------------------------------------------------------------------- void CalcScreenRect(HWND hWnd,LPRECT client_rect) { POINT client_point; // クライアント領域の左上座標のスクリーン座標を求める client_point.x = client_point.y = 0; ClientToScreen(hWnd, &client_point); // クライアント領域のサイズを求める GetClientRect(hWnd, client_rect); // クライアント領域のスクリーン座標を求める(client_rectに座標が計算される) OffsetRect(client_rect, client_point.x, client_point.y); }変更3.WinProc()関数にWM_SIZEの処理を追加
//----------------------------------------------------------------------------- // 関数名 : WinProc() // 機能概要: ウィンドウプロシージャ //----------------------------------------------------------------------------- LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT rect; switch (message) { case WM_SIZE: // ウィンドサイズを一定に保つ処理 GetWindowRect(hWnd, &rect); rect.right -= LOWORD(lParam); rect.bottom -= HIWORD(lParam); rect.right += 640; rect.bottom += 480; MoveWindow(hWnd,rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); break; case WM_KEYDOWN: 〜以下略〜 } return DefWindowProc(hWnd, message, wParam, lParam); }手順2.common.hに追加
extern HWND hWnd;
void CalcScreenRect(HWND,LPRECT); // クライアント領域のスクリーン座標を取得手順3.myDraw.cppを変更
変更1.ローカルデータにスクリーンモード格納用変数を作成
//----------------------------------------------------------------------------- // ローカルデータ Local data //----------------------------------------------------------------------------- static DWORD ncoop = DDSCL_NORMAL;// 現在のスクリーンモード格納用変数変更2.myFlip内を変更する
void myFlip(void) { HRESULT hRet; RECT rect1, rect2; if(ncoop == DDSCL_NORMAL) { CalcScreenRect(hWnd, &rect1); SetRect(&rect2, 0, 0, 640, 480); hRet = g_pDDSPrimary->Blt(&rect1, g_pDDSBack, &rect2, DDBLT_WAIT, NULL); if(hRet == DDERR_SURFACELOST) { g_pDDSPrimary->Restore(); g_pDDSBack->Restore(); } } else g_pDDSPrimary->Flip(NULL, DDFLIP_WAIT); }変更3.InitializeDraw内を変更する
// 協調レベルの設定(ウィンドウモード用) hRet = g_pDD->SetCooperativeLevel(NULL,DDSCL_NORMAL); // ビデオモードの設定 640x480x8(ウィンドウモードの時は必要ない)if(ncoop != DDSCL_NORMAL) {hRet = g_pDD->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, COLOR_MODE, 0, 0); if (hRet != DD_OK) return InitFail(hWnd, hRet, "SetDisplayMode FAILED"); OutputDebugString("SetDisplayMode OK\n");}// プライマリーサーフェイスの生成 ddsd.dwFlags =DDSD_CAPS;ddsd.ddsCaps.dwCaps =DDSCAPS_PRIMARYSURFACE;//ddsd.dwBackBufferCount = 1; // ウィンドウモードの時は必要ない // バックバッファの生成 ZeroMemory(&ddsd,sizeof(ddsd));ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; ddsd.dwWidth = 640; ddsd.dwHeight = 480; hRet = g_pDD->CreateSurface(&ddsd,&g_pDDSBack,NULL);if (hRet != DD_OK) return InitFail(hWnd, hRet, "GetAttachedSurface FAILED"); OutputDebugString("GetAttachedSurface OK\n");// クリッパーの設定(ウィンドウモードの時必要) if (ncoop == DDSCL_NORMAL) { g_pDD->CreateClipper(0,&g_pDDClip, NULL); if(g_pDDClip->SetHWnd(0,hWnd) != DD_OK) return NULL; if(g_pDDSPrimary->SetClipper(g_pDDClip) != DD_OK) return NULL; } if (ncoop != DDSCL_NORMAL) {// パレットの生成(指定した画像を元に、パレット情報を作成する) g_pDDPal = DDLoadPalette(g_pDD, szBackimgBmp); if (g_pDDPal == NULL) return InitFail(hWnd, hRet, "DDLoadPalette FAILED"); OutputDebugString("DDLoadPalette OK\n"); // プライマリー・サーフェイスにパレットを設定する。フルスクリーンのみ設定必要 hRet = g_pDDSPrimary->SetPalette(g_pDDPal); if (hRet != DD_OK) return InitFail(hWnd, hRet, "SetPalette FAILED"); OutputDebugString("SetPalette OK\n");}
ゲーム中にウィンドウモードとフルスクリーンモードをF11を押すたびに切り替えれるよう、 プログラムを改造する。
手順1
F11が押されるたびに呼び出されるモード切り替えるよう関数ChangeScreen()を作成する。(myDraw.cpp内)
この関数のプロトタイプはcommon.h内に記述する。(Winmain.cpp内で使用するため)
//----------------------------------------------------------------------------- // 関数名 : ChangeScreen() // 機能概要: 文字列表示 ポイント数、フォントの種類指定版 //----------------------------------------------------------------------------- BOOL ChangeScreen(void) { if (ncoop & DDSCL_FULLSCREEN) // フル−>ウィンドウ { ShowCursor(true); if(DD_OK != g_pDD->RestoreDisplayMode()) return FALSE; // 解像度を元に戻す
ncoop = DDSCL_NORMAL; } else // ウィンドウ−>フル { ShowCursor(false); ncoop = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT; } if(ncoop & DDSCL_EXCLUSIVE) { if(!SetWindowLong(hWnd, GWL_STYLE, WS_POPUP)) // フルスクリーンにあったウィンドウにする return FALSE; } if(g_pDD->SetCooperativeLevel(hWnd,ncoop) != DD_OK) // 強調 return FALSE; if(ncoop & DDSCL_EXCLUSIVE) // ディスプレイモードの変更・フルスクリーンにするときのみ { if(g_pDD->SetDisplayMode(640, 480, 8, 0, 0)!=DD_OK) return FALSE; } else { // ウィンドウモードにあったウィンドウに再定義する if (!SetWindowLong(hWnd, GWL_STYLE, WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_BORDER|WS_MINIMIZEBOX|WS_VISIBLE)) return FALSE; RECT rect = {0, 0, 640, 480}; // GetWindowStyle() <windowsx.h>が必要 AdjustWindowRect(&rect, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL); // ウィンドウを描画する位置をrect構造体へ入れます。 // ↓:ウィンドウ表示座標をセット
SetWindowPos(hWnd, NULL, 0, 0, (rect.right - rect.left), (rect.bottom - rect.top), SWP_NOMOVE|SWP_NOZORDER | SWP_NOACTIVATE); SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); }
InitializeDraw(hWnd); // サーフェイスをセットし直す
return TRUE;
}手順2
Winmain.cpp内でF11が押されたら、 ChangeScreen()関数を呼び出すように設定する。
手順3
設問aで設定したスクリーンモード格納用変数(ncoop)の値によってmyDraw.cpp内の設定をウィンドウモード用、フルスクリーンモード用の切り替えの設定をする。
[例]
if(ncoop == DDSCL_NORMAL)
{
ウィンドウモード用の設定
}
else
{
フルスクリーンモード用の設定
}ヒント1
DirectDrawオブジェクトの作成、協調レベルの設定はInitializeDraw関数内では1回だけ通るようにする。(ChangeScreen関数内でサーフェイスをセットし直すときには処理をさせない)また、InitializeDraw関数がChangeScreen()関数内から呼ばれるときは、プライマリーサーフェイスを開放(Release)し、NULLをセットする。
ヒント2
プライマリーサーフェイス、バックバッファの設定はウィンドウ用とフルスクリーン用で違うので設定を切り替えるプログラムが必要。