プログラミングのメモ帳(C/C++/HSP)

日々のプログラミングで気づいた点や小技集を紹介します。(Windows 10/XP/Vista、VC2017、HSP)

ダブル・バッファリングの方法(2)

2010年08月12日 20時50分00秒 | グラフィック関連
前回の記事でちらつきを防止するための[ダブル・バッファリングの方法(1)]を紹介しました。 今回の記事では、DIBセクションという方法で[ダブル・バッファリング]を構築します。 こちらの利点は、DIBセクションで作成するため、オフスクリーンをピクセル単位で操作できます。 通常ピクセル単位で描画するには SetPixelSetPixelV 関数を利用します。 しかし、この関数を多用して図形を描画すると極端に処理速度が遅くなります。 そこで DWORD 型の配列をDIBセクションで用意して、その配列に色情報を独自に書き込むことができます。 この方法なら直接ピクセル情報を書き換えてるので、高速で独自の図形を描画できます。 このDIBセクションを使って[ダブル・バッファリング]を構築すると、きめ細かい処理ができて便利です。 特にピクセル単位での描画をしない場合は、前回の記事で紹介した[ダブル・バッファリングの方法(1)]を利用して下さい。 個人的にはピクセル単位での描画が欲しいので、[ダブル・バッファリング]は今回の方法で構築します。 それでは具体的なプロシージャの記述を紹介します。

サンプル

// break付きのキーワード
#define CASE            break;case
#define DEFAULT         break;default

// オフスクリーンの画面サイズ
#define MAX_WIDTH       (640)
#define MAX_HEIGHT      (480)

// ウインドウ・プロシージャの関数
LRESULT CALLBACK mainWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    static BITMAPINFO   bmpInfo;    // ビットマップ情報
    static LPDWORD      lpPixel;    // ピクセル配列
    static HBITMAP      hBitmap;    // ビットマップ
    static HDC          hMemDC;     // オフスクリーン
    static UINT         saveX;
    static UINT         saveY;
    
    switch ( uMsg ){
        CASE WM_CREATE:
        {
            HDC hDC;
            
            // DIB構造体の初期化
            bmpInfo.bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
            bmpInfo.bmiHeader.biWidth           = +MAX_WIDTH;
            bmpInfo.bmiHeader.biHeight          = -MAX_HEIGHT;      // マイナス値で上下逆転の座標
            bmpInfo.bmiHeader.biPlanes          = 1;
            bmpInfo.bmiHeader.biBitCount        = 32;
            bmpInfo.bmiHeader.biCompression     = BI_RGB;
            
            // DIBセクションの作成
            hDC         = GetDC( hWnd );
            hMemDC      = CreateCompatibleDC( hDC );
            hBitmap     = CreateDIBSection( NULL, &bmpInfo, DIB_RGB_COLORS, (LPVOID*)&lpPixel, NULL, 0 );
            SelectObject( hMemDC, hBitmap );
            SelectObject( hMemDC, GetStockObject(DC_PEN) );
            SelectObject( hMemDC, GetStockObject(DC_BRUSH) );
            ReleaseDC( hWnd, hDC );
        }
        CASE WM_CLOSE:
            // DIBセクションの破棄
            DeleteDC( hMemDC );
            DeleteObject( hBitmap );
            DestroyWindow( hWnd );
        CASE WM_DESTROY:
            PostQuitMessage( 0 );
        CASE WM_PAINT:
        {
            PAINTSTRUCT     ps;
            HDC             hDC;
            
            // DIBセクションの描画
            hDC = BeginPaint( hWnd, &ps );
            BitBlt( hDC, 0, 0, MAX_WIDTH, MAX_HEIGHT, hMemDC, 0, 0, SRCCOPY );
            EndPaint( hWnd, &ps );
        }
        CASE WM_ERASEBKGND:
            // 何も処理しない⇒塗り潰した
            return 1;
        CASE WM_LBUTTONDOWN:
        case WM_LBUTTONDBLCLK:
        {
            UINT cx = (SHORT)LOWORD(lParam);
            UINT cy = (SHORT)HIWORD(lParam);
            
            if ( GetKeyState(VK_SHIFT) < 0 ){
                cx = saveX += 16;
                cy = saveY += 16;
            }
            SetDCPenColor(   hMemDC, RGB(0xFF,0xFF,0x00) );
            SetDCBrushColor( hMemDC, RGB(0x00,0x00,0xFF) );
            Rectangle( hMemDC, cx, cy, (cx + 16*5), (cy + 16*3) );
            
            // ピクセル単位で描画
            for ( UINT no = 0 ; no < (16 * 3) ; no++ ){
                lpPixel[ MAX_WIDTH * (cy + no) + (cx + no) ] = 0xFFCC33;        // 橙色
            }
            InvalidateRect( hWnd, NULL, FALSE );
        }
        CASE WM_RBUTTONUP:
            saveX = 0;
            saveY = 0;
            PatBlt( hMemDC, 0, 0, MAX_WIDTH, MAX_HEIGHT, BLACKNESS );
            InvalidateRect( hWnd, NULL, FALSE );
        DEFAULT:return DefWindowProc( hWnd, uMsg, wParam, lParam );
    }
    return 0;
}

解説

WM_CREATE でオフスクリーンであるDIBセクションを CreateDIBSection 関数で作成します。 ここの部分だけが[ダブル・バッファリングの方法(1)]との相違点です。 WM_CLOSE でオフスクリーンである hMemDC、hMemDC に関連付けた hBitmap を破棄します。 WM_PAINT でオフスクリーンである hMemDC を BitBlt 関数で一気にコピーします。 WM_ERASEBKGND の処理を無効にするため何も記述しません。そして処理したから 1 を返す。 これで常にオフスクリーンである hMemDC の内容が表画面(クライアント領域)にコピーされます。 ちなみにオフスクリーンである hMemDC には別のタイミングで背景やキャラクタを描画します。 ゲームの場合は、一定の間隔であるタイマー(スレッド)で背景やキャラクタを描画します。

その他

上記では WM_LBUTTONDOWN と WM_LBUTTONDBLCLK で長方形の図形を描画してます。 [SHIFT]キーを押しながらクリックすると左上隅から順番に長方形を描画します。 さらにピクセル単位で描画する部分も付け加えました。 WM_RBUTTONUP でオフスクリーンの画面を全て消去してます。

コメント    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« ダブル・バッファリングの方... | トップ | 指定領域のビットマップ保存 »
最新の画像もっと見る

コメントを投稿

グラフィック関連」カテゴリの最新記事