« みふでもわかるWIN32API講座 | メイン | みふでもわかるC++番外篇 - ばらばらな物をまとめて扱う »

2005年08月28日

みふでもわかるWIN32API講座 - 簡単な描画編

単純な描画

(現時点での理解の仕方を平たく書いているので数多くの間違いがある筈です)

GDIは、ハードウェアを直接ドライバ経由で弄ると効率が悪いので、それを隠蔽するための関数群です。
APIの中における描画に特化した部分と考えておきます。

HDC

HDC(handle of device context)は、描画対象の情報を記録した構造体です?

ウィンドウ描画用のデバイスコンテキストを操作するには、

HDC GetDC(HWND hWnd); //HWNDに対応するHDCを取得
int ReleaseDC(HWND hWnd, HDC hDC); //HWND,HDCに対応するHDCを解放。HWNDも必要な点に注意

単調描画

単に取得しておいたHDCを関数に渡して描画させるだけです。
後で出てくるメモリ上のイメージを用いた一括描画でも基本は同じです。渡すHDCが直接的では無いだけで。

//LPCSTR(LONG POINTER TO STRING)は文字列へのポインタ、cbStringは文字列の長さ(lstrlenを使うべし)
BOOL TextOut(HDC hdc, int nXStart, int nYStart, LPCSTR lpString, int cbString);


描画補足

ウィンドウの再描画

無効状態を再描画する時のWM_PAINTメッセージをフックする。
ただし、この場合にはGetDCによるデバイスコンテキストは使えない。
恐らく、GetDCはウィンドウ全体のデバイスコンテキストを得る為の物であり、
再描画の時に必要なのは無効領域のデバイスコンテキストのみが必要だからではないだろうか。

//
HDC BeginPaint(HWND hWnd,LPPAINTSTRUCT lpPaint);

//無効領域描画用なのかな?メンバ変数的にはそんなイメージの構造体
typedef struct tagPAINTSTRUCT {
HDC hdc; //デバイスコンテキスト。無効領域大元のDC
BOOL fErase; //無効領域塗りつぶしフラグ
RECT rcPaint; //無効領域の座標
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgReserved[32];
} PAINTSTRUCT;

//とっても便利な四角形指定構造体
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT;

//BeginPaintがあれば当然EndPaintも……
BOOL EndPaint(HWND hWnd, CONST PAINTSTRUCT *lpPaint);

流れとしては、

PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
//hdcを使った何らかの描画処理
EndPaint(hWnd,&ps);

をWM_PAINTの処理の中で行うわけです。
ゲームの場合、大体がデータのアップデート、そして再描画となるので、
この間に描画処理をまとめておくわけですね。

メモリ上ビットマップとの連携

ビットブロックの転送

BOOL BitBlt(
//コピー先デバイスの情報
HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight,
//コピー元デバイスの情報
HDC hdcSrc, int nXSrc, int nYSrc,
//ラスタオペレーションの識別(普通に転送するならSRCCOPY)
DWORD dwRop
);

メモリデバイスの構築

最終的に描画したい対象のデバイスコンテキストを渡すと、メモリ上に構築された仮想デバイスのデバイスコンテキストを返す
HDC CreateCompatibleDC(HDC hdc);
DeleteDC(hdc);

仮想デバイス上にビットマップを生成
HBITMAP CreateCompatibleBitmap(HDC hdc, int nWidth, int nHeight);
DeleteObject(hBitmap);

ここで、仮想デバイスコンテキストに仮想ビットマップを

SelectObject(hdc,hbitmap);
といった感じでセットすると、メモリ上の仮想デバイスに描画する事ができるようになるのです。

流れとしては、

WM_CREATE
HDC hdc = GetDC(hWnd);
hMemDC = CreateCompatibleDC(hdc);
hBitmap = CreateCompatibleBitmap(hdc, BMP_WIDTH,BMP_HEIGHT);
ReleaseDC(hWnd,hdc); //この時点で直に参照するデバイスコンテキストは不要に

SelectObject(hMemDC,hBitmap);

WM_PAINT
PAINTSTRUCT ps;

//仮想デバイス上への描画はどのタイミングで行っても大丈夫(スコープの注意はあるけど)
Rectangle(hMemDC,0,0,BMP_WIDTH,BMP_HEIGHT);

//で、BeginPaintで得たデバイスコンテキストへ転送するわけです
HDC hdc = BeginPaint(hWnd,&ps);
BitBlt(hdc,0,0,BMP_WIDTH,BMP_HEIGHT,
hMemDC<0,0,SRCCOPY);
EndPaint(hWnd,&ps);

WM_DESTROY
DeleteDC(hMemDC);
DeleteObject(hBitmap);
PostQuitMessage(0);

こんなイメージで行けると思います。

投稿者 miff : 2005年08月28日 22:10



XREAAD