画像を回転しながら描画する

PlgBlt() で BMP 画像をタイマ割り込みで回転しながら描画します。
DirectX では画像の回転は常識ですが、Windows API では提供されていないものと思っていましたが、 透明色を調べているとき PlgBlt() がひっかかり、この関数で回転できることが解かりました。

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

プロジェクトの設定

  1. 新規プロジェクト(Rotate)を作成して下さい。
  2. PlgBlt() 関数を使うときは wingdi.h をインクルードして下さい。
    回転座標の計算に三角関数を使うので math.h をインクルードしています。
    ID_TIMER はタイマのIDです。
        #include    <windows.h>
        #include    <wingdi.h>
        #include    <math.h>
        #define     ID_TIMER    (WM_APP + 0)
        
  3. Org[3] は PlgBlt() で描画する平行四辺形の元座標で、0,0 を基準に定義しています。
    画像サイズが縦横共に 128 なので 64 はその半分です。
    座標が3点しか定義されていませんが、平行四辺形なので4点目は自動的に計算されます。
    Pnt[] は Org[] から val 度回転した座標を求めて格納する領域で、これを使って描画します。
    val は座標の回転角度で、タイマ割り込みでアップされます。
        //画像を描画する平行四辺形の座標計算
        POINT   Org[3]= { { -64, -64 }, { 64, -64 }, { -64, 64 } };
        POINT   Pnt[3];
        float   val= 0.0f;
        
  4. 画像を回転して描画する関数です。
    PlgBlt() の Pnt が描画する平方四辺形の座標です。
        //★ BMP ファイルを入力して PlgBlt() で描画する
        HRESULT  LoadBMP(HWND hWnd, LPCSTR szBitmap)
        {   HBITMAP     hbmp;
            BITMAP      bmp;
            HDC         hdc,hmdc;
                          :
            PlgBlt(hdc,Pnt,hmdc,0,0,bmp.bmWidth,bmp.bmHeight,NULL,0,0);
        
  5. WM_CREATE: でタイマをセットします。
    WM_TIMER: で回転角度(val) をアップします。
    InvalidateRect() を FALSE に設定しているので、ページ先頭の画像のように上書きして描画されます。
    TRUE を指定するとクリアされるのですが、画面が多少「ちらつき」ます。
        {   case WM_CREATE:
                SetTimer(hWnd,ID_TIMER,300,NULL);
                break;
            case WM_TIMER:
                val+= 3.0f;
                if (val>360.0f) val-= 360.f;
                InvalidateRect(hWnd,NULL,FALSE);
                break;
        
  6. WM_PAINT: では、元の座標(Org) から val 回転した座標を Pnt に求めて、LoadBMP で描画します。
    回転計算は 0,0 を基準に行っているので、100 を加えて表示位置を設定します。
    "kishi.bmp" が描画する BMP ファイルです。
            case WM_PAINT:
                hdc= BeginPaint (hWnd, &ps);
                for(i=0; i<3; i++)
                {   Rot(val,(float)Org[i].x,(float)Org[i].y,&Pnt[i]);
                    Pnt[i].x+= 100;
                    Pnt[i].y+= 100;
                }
                LoadBMP(hWnd, "kishi.bmp");
                EndPaint(hWnd, &ps);
                break;
        
  7. WM_DESTROY: ではタイマを止めて終了して下さい。
            case WM_DESTROY:
                KillTimer(hWnd,ID_TIMER);
                PostQuitMessage(0);
                return 0L;
        

【演習】

  1. Rot() 関数を作成してプログラムを完成させて下さい。
    座標の回転は 5本の線で星の形を描きます を参照して下さい。
  2. InvalidateRect(hWnd,NULL,FALSE); を TRUE にして試して下さい。
    この後のページで、DirectX と同じように完全に「ちらつき」を無くして描画する方法を説明しています。
  3. 平行四辺形の座標を左右(上下)反転して定義すると、鏡面反転で描画することができます。
  4. PlgBlt() には直接透明色を設定するマスクを指定することができます。
    透明色のマスクを設定して描画して下さい。
    PlgBlt(hdc,平行四辺形の座標,hBmpDC,0,0,Width,Height,透明色hBmp,0,0);
    但し、PlgBlt() のマスクは透明部分を黒で、描画部分を白で塗りつぶすので NOTSRCCOPY を使います。
    マスクの作成は 透明色とマスク画像の作成 を参照して下さい。
    BitBlt(hMBmpDC,0,0,Width,Height,hBmpDC,0,0,NOTSRCCOPY);

【注意】

PlgBlt() は NT 系でないと動かないかも知れません。
私は Windows XP を使っていますが Windows ME では動きませんでした。 (;_;)

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