MSSDKサンプルの描画方法を学ぶ

ビットマップファイルから読み込んだ画像をサーフェイスに転送するにはBltFast関数、またはBlt関数を利用してきた。授業では次のように利用してきた。

rcRect.left = 0;
rcRect.top = 0;
rcRect.right = 640;
rcRect.bottom = 480;
hRet = g_pDDSBack->BltFast(0, 0, g_pDDSOne, &rcRect, DDBLTFAST_NOCOLORKEY);

MSSDKにはサンプルプログラムと、そのソースがある。では、サンプルプログラムではどのように描画処理を行っているのだろうか?

1 MSSDKのサンプルを見てみる

MSSDKのDDraw Samplesにある「Ex4 Page Flipping」のソース(C:\mssdk\samples\Multimedia\DDraw\src\DDex4\ddex4.cpp)を見てみると、BltFast関数を次のように実行している。

【ddex4.cppの描画部分】

// Blit the stuff for the next frame
rcRect.left = 0;
rcRect.top = 0;
rcRect.right = 640;
rcRect.bottom = 480;
while (TRUE)
{
    hRet = g_pDDSBack->BltFast(0, 0, g_pDDSOne,
                                &rcRect, DDBLTFAST_NOCOLORKEY);

    if (hRet == DD_OK)
        break;
    if (hRet == DDERR_SURFACELOST)
    {
        hRet = RestoreAll();
        if (hRet != DD_OK)
            return;
    }
    if (hRet != DDERR_WASSTILLDRAWING)
        return;
}
if (hRet != DD_OK)
    return;

このプログラムから、次のことが分かる。

  1. BltFast関数がDD_OKを返すまでループを繰り返す。
  2. 要求されたサーフェスがアタッチできなかった(DDERR_SURFACELOST)場合、RestoreDraw関数を実行(サーフェイスを開放し、再生成)し、失敗したら関数を抜ける。
  3. このサーフェスから、またはサーフェスへの前回のブリット処理が完了していない(DDERR_WASSTILLDRAWING)場合はループを繰り返し、それ以外のエラーなら関数を抜ける。
  4. ループ終了後にhRetの中身を調べ、DD_OK以外なら関数を抜ける。(理論的にはこのif文にくるときはDD_OKが入っているはず)

この方法を使えば、描画の失敗をある程度減らすことが可能になり、描画の失敗による画面のちらつきを減少させることができる。

※エラーメッセージの意味についてはHelpを参照

2 自分のプログラムに組み込む

上記の通り組み込んでもいいが、BltFast関数のたびに同じ処理を行うとプログラムが巨大になってしまうため、関数化すると便利である。たとえば次のように作成し、myDraw.cppに配置する。

//-----------------------------------------------------------------------------
// 関数名 : myBltFast()
// 機能概要: サーフェース間の画像転送
// 引 数 : lpDDSOne:転送先サーフェース	dwX,dwY:転送先座標 
//             lpDDSSrc:転送元サーフェース	lpSrcRect:転送元の矩形
//             dwTrand:転送フラグ
//-----------------------------------------------------------------------------
HRESULT myBltFast(
    LPDIRECTDRAWSURFACE7 lpDDSOne,
    DWORD dwX, DWORD dwY,
    LPDIRECTDRAWSURFACE7 lpDDSSrc,
    LPRECT lpSrcRect,
    DWORD dwTrand)
{
    HRESULT     hRet;

    while (TRUE)
    {
        hRet = lpDDSOne->BltFast(dwX, dwY, lpDDSSrc, lpSrcRect, dwTrand);
        if (hRet == DD_OK)
           break;
        if (hRet == DDERR_SURFACELOST)
        {
            hRet = RestoreDraw();
            if (hRet != DD_OK)
                break;
        }
        if(hRet != DDERR_WASSTILLDRAWING)
            break;
    }

    return hRet;

}

※LPRECTは、RECT構造体のポインタ型であり、「RECT *」と同じ意味。

※BltFast関数を実行し、正常に実行されたらループを抜け、DD_OKを返す。エラーが起きたときは、エラー内容に従って様々な処理を行う。
※プロトタイプ宣言をmyDraw.hに行えば、他のソースからこの関数を呼び出すことができる。

■使い方

myBltFast関数の引数は次の通りである。

myBltFast(
  転送先サーフェイス,
  転送先x座標,
  転送先y座標,
  転送元サーフェイス,
  転送する画像の矩形,
  転送時のオプション
);
転送先サーフェイス
画像を転送するサーフェイスを指定。通常はバック・サーフェイス。
転送先x座標、y座標
サーフェイスのどの位置に画像を転送するかを指定。DWORD(unsigned int)型。
転送元サーフェイス
転送したい画像があるオフスクリーン・サーフェイスを指定。
転送する画像の矩形
オフスクリーン・サーフェイス上のどの矩形を転送するのかをRECT構造体により指定。
転送時のオプション
カラーキーを使うかどうか。DDBLTFAST_NOCOLORKEYまたはDDBLTFAST_SRCCOLORKEY。

■使用例

たとえば次のようにBltFastを実行しているプログラムがある。

hRet = g_pDDSBack->BltFast(0, 0, g_pDDSGame, &ScreenRect, DDBLTFAST_NOCOLORKEY);
if (hRet != DD_OK)
  return;

これを、myBltFast関数を使って、次のように置き換える。

hRet = myBltFast(g_pDDSBack, 0, 0, g_pDDSGame, &ScreenRect, DDBLTFAST_NOCOLORKEY);
if (hRet != DD_OK)
  return;

このようにプログラムすることにより、スムーズに移行を行える。


[ TOP ]