拡大した画像の上を元の画像が動き回る

DirectX の GetBackBuffer で BackBuffer を取得して 直接 StretchBlt() で拡大して描画します。
その上から元のサイズの BMP 画像を CSurface* を使って動き回りながら描画します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. プロジェクトのフォルダーに次のファイルを格納して下さい。
    見つからないときは Object Class Library から取得して下さい。
    ファイル名 ファイルの説明
    Main.cpp Main Program File
    Ddutil.cpp c:\Dx90SDK\Samples\C++\Common からコピー
    Ddutil.h c:\Dx90SDK\Samples\C++\Common からコピー
    Dxutil.h c:\Dx90SDK\Samples\C++\Common からコピー
    Kishi.bmp 透明色(黒)を使った BMP 画像
  2. Direct Draw と描画に関係する領域の定義です。
    g_pBmpSurface に画面を動き回る画像を設定します。
    xp, yp は動き回る画像の座標を記憶します。
    xd, yd は画像が動き回る方向と速度を設定します。
    g_hMdc は StretchBlt() で拡大して描画する画像のハンドルです。
    g_Width, g_Height は画像の幅と高さです。
        CDisplay*   g_pDisplay    = NULL;
        CSurface*   g_pBmpSurface = NULL;
        float       xp=100,  yp=50;         //画像の座標
        float       xd=1.0f, yd=0.5f;       //移動の方向
        BOOL        g_bActive     = FALSE;
        HDC         g_hMdc        = NULL;
        LONG        g_Width;                //画像の幅
        LONG        g_Height;               //画像の高さ
        
  3. WinMain() はいつもと同じです。
    InitDraw(hWnd) で DirectDraw の初期化を行います。
    メッセージループの中から DisplayFrame() で描画します。
        int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int nCmdShow)
        {   MSG     msg;
                  :
                  :
            if (FAILED(InitDraw(hWnd)))
            {   if (g_pDisplay)
                    g_pDisplay->GetDirectDraw()->SetCooperativeLevel(NULL, DDSCL_NORMAL);
                ERMSG("DirectDraw init failed. The sample will now exit.");
                return FALSE;
            }
                  :
                else
                {   if (g_bActive)
                    {   if (FAILED(DisplayFrame()))
                        {   SAFE_DELETE(g_pDisplay);
                            ERMSG("Displaying the next frame failed");
                            return FALSE;
                        }
                    }
                    else    WaitMessage();
                }
            }
        }
        
  4. CALLBACK 関数です。
    何かキーが押されるとプログラムを終了します。
    g_pDisplay->UpdateBounds() が描画をウインドウサイズに合わせる関数です。
    この行をコメントにすると、ウインドウサイズが変わっても描画サイズは変わりません。
        LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
        {   switch (msg)
            {   case WM_KEYDOWN:
                    PostMessage(hWnd,WM_CLOSE,0,0);
                    return 0L;
                case WM_PAINT:
                    if (g_pDisplay)
                    {   if (DisplayFrame() == DDERR_SURFACELOST)
                        {   PostMessage(hWnd,WM_CLOSE,0,0);
                        }
                    }
                    break;
                case WM_MOVE:
                    if (g_pDisplay)    g_pDisplay->UpdateBounds();
                    return 0L;
                case WM_SIZE:
                    if (SIZE_MAXHIDE==wParam||SIZE_MINIMIZED==wParam)  g_bActive= FALSE;
                    else   g_bActive= TRUE;
                    if (g_pDisplay)    g_pDisplay->UpdateBounds();
                    break;
                case WM_DESTROY:
                    FreeDraw();
                    PostQuitMessage(0);
                    return 0L;
            }
            return DefWindowProc(hWnd, msg, wParam, lParam);
        }
        
  5. Direct Draw の初期化です。
    CreateWindowedDisplay() で DisplayMode を設定します。
    CreateSurfaceFromBitmap() で動き回る画像を設定します。
    SetColorKey(0) で動き回る画像の黒を透明色に設定します。
    LoadBMP() で拡大する画像を入力して、そのハンドルを取得します。
        HRESULT InitDraw(HWND hWnd)
        {   HRESULT     hr;
    
            g_pDisplay = new CDisplay();
            if (FAILED(hr = g_pDisplay->CreateWindowedDisplay(hWnd,640,480)))
            {   ERMSG("Failed initializing DirectDraw");
                return hr;
            }
            if (FAILED(hr=g_pDisplay->CreateSurfaceFromBitmap(&g_pBmpSurface,"kishi.bmp",0,0)))
                return hr;
            if (FAILED(hr=g_pBmpSurface->SetColorKey(0)))   return hr;
            LoadBMP(hWnd,"Kishi.bmp");
            return S_OK;
        }
        
  6. 描画は DisplayFrame() 関数で行います。
    xp, yp が画像の座標で、xd, yd が動く方向と速度です。
    X座標が5~500、Y座標が5~350の範囲を動き回ります。
    範囲を超えると方向を反転してから乱数で進行方向を少しずらします。
    g_pDisplay->GetBackBuffer(); で BackBuffer を取得して StretchBlt() で拡大して描画します。
    その上から g_pDisplay->Blt() で動き回る画像を描画します。
        HRESULT DisplayFrame()
        {   HRESULT                 hr;
            LPDIRECTDRAWSURFACE7    pBack;   // DirectDraw back surface
            HDC                     hdc;
    
            xp+= xd;
            if (xp<5 || xp>500)
            {   xd= 0-xd;
                xd+= (rand()%100+1)/150;
            }
            yp+= yd;
            if (yp<5 || yp>350)
            {   yd= 0-yd;
                yd+= (rand()%100+1)/150;
            }
            g_pDisplay->Clear(RGB(60,20,10));
            pBack= g_pDisplay->GetBackBuffer();
            if (pBack->GetDC(&hdc)==DD_OK)
            {
                StretchBlt(hdc,80,60,g_Width*3,g_Height*3,g_hMdc,0,0,
                           g_Width,g_Height,SRCPAINT);
                pBack->ReleaseDC(hdc);
            }
            g_pDisplay->Blt((ULONG)xp,(ULONG)yp,g_pBmpSurface,NULL);
            if (FAILED(hr= g_pDisplay->Present())) return hr;
            return S_OK;
        }
        
  7. 取得したオブジェクトは全て開放して下さい。
        VOID FreeDraw()
        {   DeleteDC(g_hMdc);
            SAFE_DELETE(g_pBmpSurface);
            SAFE_DELETE(g_pDisplay);
        }
        

超初心者の方のために全ソースコードを掲載します。 (^_^;)
全ソースコード

超初心者のプログラム入門(DirectX9 game program)