BltFast関数もBlt関数も、画像を画面外に描画するとエラーになり、描画が失敗する。
はみ出した部分だけを切り取って、はみ出してない部分だけを描画させるにはどうすればよいかを考える。
![]() |
キャラクタの左上座標はゲーム領域内にあるが、左下座標がゲーム領域外にあるため、この描画は失敗する(エラー)。 |
![]() |
はみ出た部分を切り取って、このように描画させたい。 |
BltFast関数は、描画予定の左上の座標(x, y)と、描画する画像の矩形(left, top, right, bottom)を与え、バックバッファに転送する。このとき、バックバッファの領域をはみ出して描画した場合、エラーを返す。
つまり、BltFast関数を実行する前に、領域をはみ出しているかどうかを調べ、はみ出している部分があれば画像の矩形を調整し、はみ出さないような矩形にしてからBltFast関数を実行すればよい。
たとえば上の図は、ゲーム領域が640×480で、100×100の画像を(600, 300)の位置に描画すると仮定する。この場合、描画される画像の左上の座標は(600, 300)だが、右下の座標が(600+100, 300+100)で(700, 400)となり、右に700 - 640 = 60ピクセルはみ出してしまう。
そこで、画像の矩形(left, top, right, bottom)のうち、rightを60ピクセル縮めれば、ゲーム領域をはみ出さずに描画できる。私のサンプルプログラムの場合、画像の描画は「myDraw.cpp」内の
myBltFast関数で行っている。この関数を実行する前に、ゲーム領域をはみ出しているかどうかを調べ、矩形や描画座標を調整してからmyBltFast関数を実行すればよい。
しかしこの方法では、効率が悪いため、指定範囲を与えて、その領域をはみ出した部分を調節してから描画(BltFast)を行う関数を作成したほうがよい。
myBltFast関数を元に改造する。
//----------------------------------------------------------------------------- // 関数名 : myBltFastClip() // 機能概要: サーフェース間の画像転送(指定矩形内) // 引 数 : lpDDSOne:転送先サーフェース dwX,dwY:転送先座標 // lpDDSSrc:転送元サーフェース lpSrcRect:転送元の矩形 //lpClipRect:表示範囲dwTrand:転送フラグ //----------------------------------------------------------------------------- HRESULT myBltFastClip(LPDIRECTDRAWSURFACE7 lpDDSOne,intdwX,intdwY, LPDIRECTDRAWSURFACE7 lpDDSSrc, LPRECT lpSrcRect,LPRECT lpClipRect,DWORD dwTrand) { HRESULT hRet; int width, height; // 画像の幅と高さを計算 width = lpSrcRect->right - lpSrcRect->left; height = lpSrcRect->bottom - lpSrcRect->top; // 指定範囲を超えた画像を切り取る if (dwX < lpClipRect->left) { lpSrcRect->left += (lpClipRect->left - dwX); dwX = lpClipRect->left; } else if (lpClipRect->right < dwX + width) { lpSrcRect->right -= ((dwX + width) - lpClipRect->right); } if (dwY < lpClipRect->top) { lpSrcRect->top += (lpClipRect->top - dwY); dwY = lpClipRect->top; } else if (lpClipRect->bottom < dwY + height) { lpSrcRect->bottom -= ((dwY + height) - lpClipRect->bottom); } // 描画処理 while (TRUE) { hRet = lpDDSOne->BltFast((DWORD)dwX, (DWORD)dwY, lpDDSSrc, lpSrcRect, DDBLTFAST_WAIT | dwTrand); if (hRet == DD_OK) break; if (hRet == DDERR_SURFACELOST) { hRet = RestoreDraw(); if (hRet != DD_OK) break; } if(hRet != DDERR_WASSTILLDRAWING) break; } return hRet; }
私の基本プログラムの場合、myDraw.cppに関数を作成し、プロトタイプ宣言をmyDraw.cppとmyDraw.hの両方に行った。これにより、どのソースファイルからもmyBltFastClip関数を呼び出せる。
myBltFastClip関数の引数は次の通り
LPDIRECTDRAWSURFACE7 lpDDSOne 転送先サーフェイス intdwX画像転送先座標のX座標。引数がDWORD型ではなく int型であることに注意!!(DWORD型はunsigned int型、つまりマイナスの値を扱えないため、画面の上や左から現れる場合の座標を持てない) intdwY画像転送先座標のX座標。 LPDIRECTDRAWSURFACE7 lpDDSSrc 転送元サーフェイス LPRECT lpSrcRect 画像の矩形 LPRECT lpClipRect画像表示領域。この範囲を超えたかどうかで切り取りの処理を行う。 DWORD dwTrand BltFast関数のパラメータ(DDBLTFAST_〜)