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内部に描くことができましたか?