スポットライトで照らす

VC++ で背景画像をスポットライトで照らします。

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

プロジェクトの設定

  1. 宣言とグローバル領域の定義です。
    Jpeg 画像を使っているので、Jpeg.cpp と Jpeg.h をプロジェクトに加えて下さい。
    BMP 画像を使うときは Jpeg Object Class は不要です。
    Object Class のソースコードは Object Class Library から取得して下さい。
    WMPAINT: から描画するとチラツクので、BackBuffer を使って Render() 関数で描画しています。
    hBackDC, hBackBitmap は BackBuffer の定義です。
    BackBuffer と同じ形式のスポットライトを当てるためのマスク画像を使います。
    hMaskDC, hMaskBitmap がマスク画像の Surface の定義です。
    大小二つのスポットライトを使いますが、xp,yp はキーの操作で移動する小さなスポットライトの座標です。
        /***************************************************/
        /*★ 背景画像にスポットライトを当てる    前田 稔 ★*/
        /***************************************************/
        #define     NAME    "SpotLight"
        #include    <windows.h>
        #include    "Jpeg.h"
    
        #define     SAFE_DELETE(p)  { if (p) { delete (p);      (p)=NULL; } }
        #define     SAFE_DELDC(p)   { if (p) { DeleteDC (p);    (p)=NULL; } }
        #define     SAFE_DELOBJ(p)  { if (p) { DeleteObject(p); (p)=NULL; } }
        #define     WIDTH       800
        #define     HEIGHT      600
    
        HDC         hBackDC=NULL;       //Back Buffer DC
        HBITMAP     hBackBitmap=NULL;   //Back Buffer HBitMap
        HDC         hMaskDC=NULL;       //Mask Surface DC
        HBITMAP     hMaskBitmap=NULL;   //Mask Surface HBitMap
        JPEG        *Jpeg= NULL;        //JPEG Object Class
    
        char        ImgFile[]= "ffx2.jpg";
        long        xp=460, yp=120;
        RECT        RC= { 0, 0, WIDTH-1, HEIGHT-1 };
        
  2. WinMain() 関数はウインドウサイズを WIDTH, HEIGHT に設定する以外は何時もと同じです。
  3. CALLBACK 関数の WM_CREATE: で初期化を行います。
    CreateBuf() で BackBuffer と Surface を生成します。
    Jpeg Object Class を生成して画像を入力します。
    WM_PAINT: では Render() 関数でコールして画像を描画します。
    キー操作による描画は画面がチラツクので、ここからは描画されません。
    //★ CALLBACK 関数
    LRESULT  CALLBACK  WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
    {   PAINTSTRUCT ps;
        HDC         hdc;
    
        switch(msg)
        {   case WM_CREATE:
                CreateBuf(hWnd);
                Jpeg= new JPEG(hWnd);
                Jpeg->Load(ImgFile);
                break;
            case WM_PAINT:
                hdc= BeginPaint(hWnd, &ps);
                Render(hWnd);
                EndPaint(hWnd, &ps);
                break;
        
  4. 矢印キーの操作で小さなスポットライトを移動します。
    描画のチラツキを抑えるために、直接 Render() 関数をコールします。
            case WM_KEYDOWN:            //KEY が押された
                switch(wParam)
                {   case VK_ESCAPE: 
                        PostMessage(hWnd,WM_CLOSE,0,0);
                        return 0L;
                    case VK_DOWN:
                        yp++;
                        Render(hWnd);
                        return 0L;
                    case VK_UP:
                        yp--;
                        Render(hWnd);
                        return 0L;
                    case VK_LEFT:
                        xp--;
                        Render(hWnd);
                        return 0L;
                    case VK_RIGHT:
                        xp++;
                        Render(hWnd);
                        return 0L;
                }
        
  5. プログラムの終了前に作成したリソースを開放して下さい。
            case WM_DESTROY:
                SAFE_DELETE(Jpeg);
                SAFE_DELDC(hBackDC);
                SAFE_DELOBJ(hBackBitmap);
                SAFE_DELDC(hMaskDC);
                SAFE_DELOBJ(hMaskBitmap);
                PostQuitMessage(0);
                return 0L;
        
  6. BackBuffer とマスクに使う Surface を作成する関数です。
        // BackBuffer とマスクに使う Surface を作成する
        void  CreateBuf(HWND hWnd)
        {   HDC     hDC;
    
            hDC= GetDC(hWnd);   //この HDC は現在表示中の画面
            //表画面と同じ BackBuffer を生成
            hBackDC= CreateCompatibleDC(hDC);
            hBackBitmap= CreateCompatibleBitmap(hDC,WIDTH,HEIGHT);
            SelectObject(hBackDC,hBackBitmap);  //DC と画面本体を関連付ける
            //表画面と同じ MaskSurface を生成
            hMaskDC= CreateCompatibleDC(hDC);
            hMaskBitmap= CreateCompatibleBitmap(hDC,WIDTH,HEIGHT);
            SelectObject(hMaskDC,hMaskBitmap);
            ReleaseDC(hWnd,hDC);
        }
        
  7. マスクに使う画像を描く関数で、xp,yp は小さなスポットの座標です。
    Surface 全体を黒でクリアして、スポットライトを白で描画します。
    この画像を背景画像と重ね合わせる(AND 演算)ことでスポットライトが当たっている部分だけが描画されます。
        // マスクに使う図形を描く
        void  PaintMask(long xp, long yp)
        {   HBRUSH  hOldBrush;
    
            FillRect(hMaskDC,&RC,(HBRUSH)GetStockObject(BLACK_BRUSH));
            hOldBrush= (HBRUSH)SelectObject(hMaskDC,GetStockObject(WHITE_BRUSH));
            Ellipse(hMaskDC,180,120,380,320);
            Ellipse(hMaskDC,xp,yp,xp+50,yp+50);
            SelectObject(hMaskDC,hOldBrush);
        }
        
  8. BackBuffer を使ってチラツキを抑えて描画します。
    最初に画像全体を BackBuffer に描画して、上からマスク画像を SRCAND で重ね合わせます。
    完成した画像を一挙に BitBlt() でフロントバッファに転送します。
        // BackBuffer を使ってチラツキを抑えて描画
        VOID  Render(HWND hWnd)
        {   HDC     hDC;
    
            hDC= GetDC(hWnd);
            Jpeg->Show(hBackDC,0,0);
            //スポットライトを照らす
            PaintMask(xp,yp);
            BitBlt(hBackDC,0,0,WIDTH,HEIGHT,hMaskDC,0,0,SRCAND);
            BitBlt(hDC,0,0,WIDTH,HEIGHT,hBackDC,0,0,SRCCOPY);
            ReleaseDC(hWnd,hDC);
        }
        

【課題】

  1. プログラムを完成させて下さい。
  2. スポットライト(円)だけでなく、様々な形状で画像をマスクすることができます。
    試してみて下さい。

超初心者のプログラム入門(Win32API C++)