DIRECTX1 DirectDraw 3 Windowを持つDirectDrawアプリケーション
今までの説明は、フルスクリーンで行いました。実行すると、ハングして何回かリセットボタンを押した人もいるでしょう。ご苦労様です。ゲームを作るときにちょいちょいハングすると思うので、そのたびにリセットボタンではたまらないので、通常は、ウィンドウモードで開発を行います。その後、フルスクリーンにして動作チェックを行います。フルスクリーンのバグに関してはリモートデバッグという方法を使うのが一般的です。リモートデバッグとは、2台のパソコンをネットでつないで片方でデバッガを動かし、もう一台でフルスクリーンのゲームを動かしてデバッグする方法です。これについては別な章で解説します。
では、WindouモードのDirectXアプリの作成方法です。CDxDrawを使うのは同じです。
1 プロジェクトの新規作成
2 CDxDraw.CPPと、CDxDraw.hを作ったディレクトリにコピーする
3 プロジェクト >> プロジェクトに追加>ファイル で、上の二つのファイルを指定してOKを押す
4 Viewクラスに dxdraw.h をインクルードする
5 Viewクラスのインプリメンテーションにオブジェクトを作る CDxDraw ddx;
6 ビルドすると、CDxDRAWでエラーが出るので、その行を新しく作ったファイル名に変更する
7 ViewクラスのOnCreateにてサーフェスを作成する。コードはいかの通り。
int CDx12View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: この位置に固有の作成用コードを追加してください
HWND m_hWnd=NULL;
ddx.InitDxDraw(m_hWnd);
HRESULT ret;
//----- サーフェスの生成
ret = ddx.MakePrimarySurface();
if (ret != DD_OK){
AfxMessageBox("Surface error");
return -1;
}
return 0;
}
プロジェクトはSDI、ステップ4/6で、全ての設定をはずします。詳細設定ではシステムメニュー以外のチェックをはずします。インクルードファイルと設定のリンクに関してはフルスクリーンモードと同じです。
CmainFrameのPreCreateWindowの中身。
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: この位置で CREATESTRUCT cs を修正して、Window クラスやスタイルを
// 修正してください。
cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE
| WS_SYSMENU;
RECT rc;
SetRect(&rc, 0, 0, 640+2, 480+2); // なぜか2Dot小さくなるので増やす
//----- クライアント領域を設定する
AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW ,
TRUE,
GetWindowLong(m_hWnd, GWL_EXSTYLE));
cs.cx = rc.right - rc.left;
cs.cy = rc.bottom - rc.top;
return TRUE;
}
CdxDraw内のInitDxDraw()は以下の通り。
int CDxDraw::InitDxDraw(HWND hWnd)
{
HRESULT ret;
ret=DirectDrawCreate(NULL, &lpDD, NULL);
if (ret != DD_OK){
AfxMessageBox("Create error");
return -1;
}
/*
ret = lpDD->SetCooperativeLevel(hWnd,
DDSCL_ALLOWREBOOT |
DDSCL_EXCLUSIVE |
DDSCL_FULLSCREEN |
DDSCL_ALLOWMODEX);
//*/
ret = lpDD->SetCooperativeLevel(hWnd,
DDSCL_NORMAL);
if (ret != DD_OK){
AfxMessageBox("SetCooperativLevel error");
return -1;
}
}
CDxDraw内のMakePrimarySurfaceは以下の通り
int CDxDraw::MakePrimarySurface()
{
HRESULT ret;
lpDDSFrontBuffer = NULL;
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
//* Windiow 表示 の場合
ddsd.dwFlags = DDSD_CAPS; // 必要
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
//バックバッファを作成(オフスクリーンサーフェース)
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwWidth = 800;
ddsd.dwHeight = 600;
if(lpDD->CreateSurface(&ddsd,&lpBackBuffer,NULL) != DD_OK){
return FALSE;
}
/*-----クリッピング領域を作る OK
lpDD->CreateClipper(0,&pClipper,NULL);
RGNDATAHEADER* pRgn;
// RECT* pRect;
// int i;
pRgn = (RGNDATAHEADER*)GlobalAlloc(GPTR,sizeof(RGNDATAHEADER) + sizeof(RECT)
* 20);
// pRect = (RECT*)(pRgn + 1);
pRgn->dwSize = sizeof(RGNDATAHEADER);
pRgn->iType = RDH_RECTANGLES;
pRgn->nCount = 20;
pRgn->nRgnSize = sizeof(RECT);
pRgn->rcBound.left = 0;
pRgn->rcBound.top = 0;
pRgn->rcBound.right = 300;
pRgn->rcBound.bottom = 200;
// for(i=0;i<20;i++){
// SetRect(pRect + i,0,480 * i / 20,640,480 * i / 20 + i);
// SetRect(pRect, 0,0,200,200);
// }
pClipper->SetClipList((RGNDATA*)pRgn,0);
lpDDSFrontBuffer->SetClipper(pClipper);
GlobalFree(pRgn);
//---------------------------------------------*/
//----- サーフェスのクリア
DDBLTFX ddbltfx;
ZeroMemory(&ddbltfx, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(DDBLTFX);
lpBackBuffer->Blt(NULL, NULL, NULL, DDBLT_COLORFILL |
DDBLT_WAIT, &ddbltfx);
lpDDSFrontBuffer->Flip(NULL, DDFLIP_WAIT);
ZeroMemory(&ddbltfx, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(DDBLTFX);
lpBackBuffer->Blt(NULL, NULL, NULL, DDBLT_COLORFILL |
DDBLT_WAIT, &ddbltfx);
return DD_OK;
}
これでビルドして実行してみてください。ウィンドウで起動するはずです。
実際にサーフェスが働いているのかどうか分からないのでキーダウンの以下のコードで確認しましょう、適当なビットマップをリソースに読み込むのは一緒です。
if(nChar == VK_UP){
ddx.MakeOff1();
//----- ビットマップをロードする
CBitmap Bitmap;
CDC DC;
DC.CreateCompatibleDC(0);
Bitmap.LoadBitmap(IDB_BITMAP2);
DC.SelectObject(&Bitmap);
//----- ビットマップをバックバッファに転送
HDC hdcSurf;
if(ddx.lpOS1->GetDC(&hdcSurf)== DD_OK){
BitBlt(hdcSurf, 0,0,640, 480,DC,0,0,SRCCOPY);
ddx.lpOS1->ReleaseDC(hdcSurf);
DeleteDC(DC);
}
}
if(nChar == VK_DOWN){
RECT rcSrc, objRect;
rcSrc.top = 0; //--------(1)
rcSrc.bottom = 100;
rcSrc.left = 0;
rcSrc.right = 100;
<--------(0)
ddx.lpDDSFrontBuffer->BltFast(objRect.left, objRect.top, ddx.lpOS1, &rcSrc,
----(2)
DDBLTFAST_NOCOLORKEY);
}
これはカーソルUPにてビットマップを読み込んでダウンで表示します。
実行してください。
ウィンドウの外に描画されましたか?
Windowを持つDirectDrawアプリケーションは、画面全体がプライマリサーフェスになってしまうので座標00は、画面の座標00になっているのです。これを利用すると、面白いプログラムが掛けそうですが、ここではちゃんとWindou内部に描けるようにしておきます。
(0)の部分に以下のコードを追加してください。
objRect.top = 0;
objRect.left = 0;
objRect.bottom = 200;
objRect.right = 200;
ClientToScreen(&objRect);
ちゃんとWindow内部に描くことができましたか?