9:Windowモード

今回は、今まで作ったプログラムをフルスクリーンではなくウィンドウモードで動かしてみます。 なかなかややこしいんですね、これが。

まずは、Alt+Enterを押したときにフルスクリーンとウィンドウを切り替えるようにしてみようと思います。 自分の場合、使っていないメニューに項目を追加してIDを作り、それをアクセラレータでキーボードと関連づけ、 最後にWindowProc中の WM_COMMAND の所にそのIDの処理を記述しています。

// WindowProc中…
case WM_COMMAND:
	{
		// メニューコマンド振り分け
		switch(LOWORD(wp))
		{
		case IDM_FPS30: iFps=(iFps)?0:30; break;
		case IDM_ALPHA: bAlpha^=1; break;
		case IDM_FULLSCREEN:
			bFull^=1; // 反転
			destroyDD();
			createDD();
			break;
		・・・
		}
	}break;

bFull というのはフルスクリーンかどうかを保持している bool型変数です。 destroyDD で一旦削除し、再び createDD で作り直しています。 次はこの createDD の中に、ウィンドウモード用のコードを追加します。

// ウィンドウのスタイルを変更
DWORD dwStyle = GetWindowLong(hWnd,GWL_STYLE);
dwStyle |= WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX;
SetWindowLong(hWnd, GWL_STYLE, dwStyle);

・・・

// 協調レベル
lpDD->SetCooperativeLevel(hWnd,DDSCL_NORMAL);

// PrimarySurface
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
lpDD->CreateSurface(&ddsd,&lpDDSPrimary,0);

// BackBuffer
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwBackBufferCount = 0;
ddsd.dwWidth = szWnd.cx;
ddsd.dwHeight = szWnd.cy;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
lpDD->CreateSurface(&ddsd,&lpDDSBack,0);

// Clipper
LPDIRECTDRAWCLIPPER lpDDClip;
lpDD->CreateClipper(0,&lpDDClip,0);
lpDDSPrimary->SetClipper(lpDDClip);
lpDDClip->SetHWnd(0, hWnd);
if(lpDDClip) lpDDClip->Release(); lpDDClip=0;

ウィンドウスタイルは、今までのポップアップにタイトルバーと最小化ボタンを付けます。 フルスクリーンのコードの方にも似たようなモノを追加します。 協調レベルは、他のアプリケーションといっしょに動くようにするので DDSCL_NORMAL を指定します。 プライマリサーフィスにはバックバッファはつけません、フリップが出来ないからです。 その代わりにバックバッファはオフスクリーンバッファとして作ります。サイズはプライマリと同じです。 んでクリッパーはプライマリの方に取り付けます。ウィンドウモードの時は必ずクリッパーを付けてください、 付けないと他のウィンドウの上に描画しちゃったり、画面外に出たときにフリーズしたりします。
では次に、ウィンドウモード用の描画コードを追加します。 ウィンドウモードでは画面全体を占有する事が出来ないので、フリップは不可能です。 その為、プライマリにバックバッファを全部転送します。

// フリップ or ブリット
・・・
if(bFull) ddrval=lpDDSPrimary->Flip(0,DDFLIP_WAIT);
else	  ddrval=lpDDSPrimary->Blt(&rcWnd,lpDDSBack,0,DDBLT_WAIT,0);

if(ddrval==DD_OK) break;
if(ddrval==DDERR_SURFACELOST)
{
	// サーフィスリストア
	if(lpDDSPrimary && lpDDSPrimary->IsLost() == DDERR_SURFACELOST
	   || lpDDSBack &&    lpDDSBack->IsLost() == DDERR_SURFACELOST)
	{
		if( !lpDDSPrimary || lpDDSPrimary->Restore()!=DD_OK) break;
		if(!bFull) if( !lpDDSBack || lpDDSBack->Restore()!=DD_OK) break; // WindowModeのみ

		・・・
	}
}

見ての通り、プライマリに全部ブリットします。 サーフィスのリストア部分では、ウィンドウモードの時はプライマリだけでは バックバッファはリストアされないので、バックバッファもちゃんとリストアします。

さて、プログラムを起動するとちゃんとウィンドウモードで動いてるのが分かります。 クリッピングしてるので画面外に移動してもフリーズしません。 ただウィンドウ内の画面の端すれすれにまた黒い部分ができてます。 バックバッファにクリッピングしてないからなんですが、これがまた問題なんです… まぁそれはまた次回にということで。ではまたっヽ(´ー`)ノ

Download dd009.lzh - ウィンドウモード


★TOP★

Copyright(C) へぽぽ