スポットライトで照らす

Sprite で描いた背景画像をスポットライトで照らします。
Sprite で描いたあとの Back Buffer を取得して、Surface の画像をマスクとして AND 演算します。
3Dの環境ではスポットライトが提供されているのですが、今回は2D(Sprite)の環境で実現します。

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

プログラムの説明

  1. #define と #include と Direct3D の領域です。
    WIDTH, HEIGHT はウインドウの幅と高さです。
    myd3d が MyD3D Object Class の定義です。
    g_pBackBuffer に BackBuffer の Surface を取得します。
    g_pSurface には背景画像に重ねあわせるスポットライトの画像を描きます。
    g_pSprite と g_pTexture は背景画像を描画する領域で、ImgFile[] が画像ファイルの名前です。
    xp,yp はキーの操作で移動する小さなスポットライトの座標です。
        /********************************************/
        /*  Spot Light  Sprite & Surface   前田 稔  */
        /********************************************/
        #define     NAME        "SpotLight"
        #include    "MyD3D.h"
        #define     WIDTH       800
        #define     HEIGHT      600
    
        // Global Area
        MyD3D               *myd3d        = NULL;       // MyD3D Object Class
        HWND                g_hWnd        = NULL;
        LPDIRECT3DDEVICE9   g_pDEV        = NULL;       // 描写用デバイス
        LPDIRECT3DSURFACE9  g_pBackBuffer = NULL;       // バックバッファ
        LPDIRECT3DSURFACE9  g_pSurface    = NULL;       // マスク画像
        LPD3DXSPRITE        g_pSprite     = NULL;       // スプライト
        LPDIRECT3DTEXTURE9  g_pTexture    = NULL;       // 背景画像テクスチャ
        bool                g_bActive     = false;      // アクティブ状態
        char                ImgFile[] = "ff512.jpg";    // 512*512 の画像
        long                xp=460, yp=120;
        RECT                RC= {0, 0, WIDTH, HEIGHT};
        
  2. WinMain() 関数はウインドウサイズを WIDTH, HEIGHT に設定する以外は何時もと同じです。
  3. Direct Graphics の初期化です。
    Object Class をインスタンス化して、DirectX のインターフェースを取得します。
    スプライトを作成してテクスチャ(背景画像)を読み込みます。
    バックバッファを取得して、同じ形式の Surface を生成します。
    DrawSurface() で g_pSurface にスポットライトが当たっている場所以外を塗りつぶすマスクを描画します。
        // デバイス/モード等の初期化
        HRESULT InitDevices(void)
        {   HRESULT  hr;
    
            // Direct3D デバイスの設定
            myd3d= new MyD3D(g_hWnd);
            myd3d->InitD3D(&g_pDEV);
            // スプライト作成
            hr = D3DXCreateSprite(g_pDEV, &g_pSprite);
            if (FAILED(hr))
            {   MessageBox(NULL,"InitDXGraphics D3DXCreateSprite","Sprite Error",MB_OK);
                return  FALSE;
            }
            // テクスチャの読み込み
            hr= D3DXCreateTextureFromFile(g_pDEV,ImgFile,&g_pTexture);
            if (FAILED(hr))
            {   MessageBox(NULL,ImgFile,"Bmp File Error",MB_OK);
                return  FALSE;
            }
            // バックバッファを取得
            if (FAILED(g_pDEV->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&g_pBackBuffer)))
            {   MessageBox(NULL,"GetBackBuffer Error","Sprite Error",MB_OK);
                return FALSE;
            }
            // バックバッファの状態を取得
            D3DSURFACE_DESC desc;
            g_pBackBuffer->GetDesc(&desc);
            // 画像ファイル用オフスクリーンサーフェースの作成
            if (FAILED(g_pDEV->CreateOffscreenPlainSurface(WIDTH,HEIGHT,desc.Format,
                               D3DPOOL_DEFAULT,&g_pSurface,NULL)))
            {   MessageBox(NULL,"CreateOffscreenSurface Error","Sprite Error",MB_OK);
                return FALSE;
            }
            DrawSurface(xp,yp);          // 図形を描画
            return  TRUE;
        }
        
  4. マスク画像を描く DrawSurface() 関数です。
    Surface 全体を黒でクリアして、スポットライトを当てる部分だけを白丸で描画します。
    今回は大きなスポットは固定して、小さなスポットを矢印キーで操作しています。
        // 図形を描画
        HRESULT DrawSurface(long xp, long yp)
        {   HDC             hDC;
            HBRUSH          hOldBrush;
            HRESULT         hr;
    
            hr= g_pSurface->GetDC(&hDC);
            if (!FAILED(hr))
            {   FillRect(hDC,&RC,(HBRUSH)GetStockObject(BLACK_BRUSH));
                hOldBrush= (HBRUSH)SelectObject(hDC,GetStockObject(WHITE_BRUSH));
                Ellipse(hDC,180,120,380,320);
                Ellipse(hDC,xp,yp,xp+50,yp+50);
                SelectObject(hDC,hOldBrush);
                g_pSurface->ReleaseDC(hDC);
            }
            else    MessageBox(NULL,"GetDC Error","Surface Error",MB_OK);
            return hr;
        }
        
  5. 描画処理のソースコードです。
    キーを検出して小さなスポットを矢印キーで移動します。
    DrawSurface() でマスク画像を描きます。
    Sprite で背景画像を描画します。
    背景画像を描画したあとの BackBuffer の HDC と Surface の HDC を取得します。
    失敗すれば背景画像のまま描画しています。
    BackBuffer に対してマスク画像を AND 演算で描画します。
    これにより大小の円形以外は黒く塗りつぶされます。
        // 描画処理
        VOID  Render()
        {   D3DXMATRIX  matWorld,matWork;
            HDC         hDC,hDCS;
            HRESULT     hr;
    
            if (!g_pDEV || !g_bActive)  return;
            if (GetKeyState(VK_LEFT)<0)     xp-= 4;
            if (GetKeyState(VK_RIGHT)<0)    xp+= 4;
            if (GetKeyState(VK_UP)<0)       yp-= 4;
            if (GetKeyState(VK_DOWN)<0)     yp+= 4;
            DrawSurface(xp,yp);
    
            g_pDEV->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(100,80,0),1.0f,0);
            // スプライトの描画
            if (SUCCEEDED(g_pDEV->BeginScene()))
            {
                g_pSprite->Begin(D3DXSPRITE_ALPHABLEND);
                g_pSprite->Draw(g_pTexture,NULL,&D3DXVECTOR3(-120,-30,0),NULL,0xFFFFFFFF);
                g_pSprite->End();
                g_pDEV->EndScene();
            }
            if (g_pBackBuffer==NULL)
            {   g_pDEV->Present(NULL,NULL,NULL,NULL);
                return;
            }
            //BackBuffer の HDC を取得
            hr= g_pBackBuffer->GetDC(&hDC);
            if (FAILED(hr))
            {   MessageBox(NULL,"BackBuffer GetDC Error","Surface Error",MB_OK);
                g_pDEV->Present(NULL,NULL,NULL,NULL);
                return;
            }
            //Surface の HDC を取得
            hr= g_pSurface->GetDC(&hDCS);
            if (FAILED(hr))
            {   MessageBox(NULL,"Surface GetDC Error","Surface Error",MB_OK);
                g_pBackBuffer->ReleaseDC(hDC);
                g_pDEV->Present(NULL,NULL,NULL,NULL);
                return;
            }
            //スポットライトを照らす
            BitBlt(hDC,0,0,800,600,hDCS,0,0,SRCAND);
            g_pBackBuffer->ReleaseDC(hDC);
            g_pSurface->ReleaseDC(hDCS);
            g_pDEV->Present(NULL,NULL,NULL,NULL);
        }
        

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

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

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

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