サンプルコードのダウンロード

では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、
お持ちの方はVisual C++でプロジェクトファイルを開いてください(「ddraw_08.dsw」をダブルクリックすれば開けます)。
圧縮ファイルに含まれる「ddraw_08.exe」をダブルクリックし、実行してみてください。
どうでしょう?画面が切り替わり、フルスクリーン化し、
slimeが作業用サーフェイスに読み込まれ、そこから部分的にバックバッファにデータが転送されていると思います(謎

というわけで、今回は作業用サーフェイスを作成し、データ転送をしたいと思います。

作業用サーフェイスの作成

普段、ゲームを作成する場合は、オフスクリーンサーフェイス(作業用サーフェイス)と呼ばれる目に見えないサーフェイスを作成し、そこへビットマップを読み込み、そこからバックバッファへデータ転送し、フリップし、画面に表示させます・・・というのは何度も書いているので既に解っていると思います。
んでは、まずオフスクリーンサーフェイスの作成方法を記しておきます。

オフスクリーンサーフェイスの作成は自作関数「StartDirectDraw」に追加してあります。

LPDIRECTDRAWSURFACE lpWork=NULL;	//オフスクリーンサーフェイス(作業用バッファ)

	略

	//オフスクリーンサーフェイス作成
	ZeroMemory(&ddsd,sizeof(ddsd));
	ddsd.dwSize=sizeof(ddsd);
	ddsd.dwFlags=DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
	ddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN;
	ddsd.dwWidth=640;
	ddsd.dwHeight=480;
	if((lpDD->CreateSurface(&ddsd,&lpWork,NULL))!=DD_OK)
		return FALSE;

DirectDrawオブジェクトのメンバである「CreateSurface」については第3回のプライマリサーフェイス作成時に多少説明しました。
今回はオフスクリーンサーフェイスを作成するという事で、dwFlagsには更に DDSD_WIDTH | DDSD_HEIGHT を追加指定し、サーフェイスの縦幅、横幅を指定出来るようにします。
そうしたら、dwWidthとdwHeightに縦幅、横幅を指定(今回はプライマリサーフェイスと同じ640×480)します。
んで、ddsCaps.dwCapsにDDSCAPS_OFFSCREENPLAINを指定し、「CreateSurface」を呼び出せば、サーフェイスが作成されます。
作成したいサーフェイスのサイズは自由に変更可能ですが、プライマリサーフェイスよりも大きなサーフェイスを作成しようとするとDirectXのバージョンによっては失敗する可能性があるのでやめた方が良いですね。

ちなみに、オフスクリーンサーフェイスはビデオメモリに作成されますが、ビデオメモリが足りなくなると、自動的にシステムメモリ内に作成されます。
また、意図的にシステムメモリ内へサーフェイスを作成したい場合はddsd.ddsCaps.dwCapsにDDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;を指定してやります。

例によって、オフスクリーンサーフェイス(lpWork)は、ビデオメモリだろうがシステムメモリだろうが関係なしに、フロントバッファやバックバッファと同じように扱う事が出来ます(GDIの描画等含む)。

サーフェイス間のデータ転送

では、オフスクリーンサーフェイスにキャラクターイメージを読み込んだ後、このイメージを他の場所へ転送します。
で、ただ転送するだけでなく、透明色を使用した転送が出来ます。その場合、どの色を透明色にするかをサーフェイス毎に設定しておかなければなりません。
では、透明色の指定方法を以下に記します。

//----------[ 透明色の設定 ]--------------------------------------------------------------------
void SetTransColor(LPDIRECTDRAWSURFACE sf,int palette_number){
	DDCOLORKEY ddck={palette_number,palette_number};
	sf->SetColorKey(DDCKEY_SRCBLT,&ddck);
}

略
	//呼び出し
	//透明色の指定(パレット1番の色を透明色にする)
	SetTransColor(lpWork,1);

まず、DDCOLORKEY構造体のメンバに透明色にしたい色を指定します。DDCOLORKEY構造体は以下のようになっています。

typedef struct _DDCOLORKEY{ 
    DWORD dwColorSpaceLowValue; 
    DWORD dwColorSpaceHighValue; 
} DDCOLORKEY;

メンバ変数は2つあります。パレット番号のLowValueからHighValueの範囲を透明色とするらしいのですが(未確認)、普段は1色しか透明色として使用しないので、LowもHighも同じ値にします。
そうしたら、DirectDrawサーフェイスのメンバである「SetColorKey」を呼び出します。構文は以下の通りです。

書式 HRESULT SetColorKey( DWORD dwFlags, LPDDCOLORKEY lpDDColorKey );
dwFlags 透明色を指定する場合はDDCKEY_SRCBLTを指定する。これは、転送元サーフェイスの指定した色以外を転送する事を意味する。転送元カラーキーとも言う。

他にもDDCKEY_DESTBLTというのがあるが、これは転送先の指定した色の部分にのみ転送する。転送先カラーキーとも言う。こっちは滅多に使用しないので解説省略だぃ(いつか解説するかも)。

lpDDColorKey DirectDrawSurface オブジェクトの新しいカラーキー値を含んでいる DDCOLORKEY 構造体へのポインタ。
戻り値 成功するとDD_OKが返ってくるらしい。

さて、今回はパレット1番の紫色(パレット番号は0から始まります)を透明色として使用する事にします。
そうしたら、今度はデータ転送です。

//----------[ データ転送 ]----------------------------------------------------------------------
void Blt(LPDIRECTDRAWSURFACE saki,int sx,int sy,int width,int height,
		 LPDIRECTDRAWSURFACE moto,int mx,int my,char trans){
	DWORD key[2]={DDBLTFAST_NOCOLORKEY,DDBLTFAST_SRCCOLORKEY};
	RECT rec={mx,my,mx+width,my+height};
	saki->BltFast(sx,sy,moto,&rec,key[trans] | DDBLTFAST_WAIT);
}

//この自作関数はややこしいので、自分なりに使いやすい関数を作成してください(^^;

	略

	Blt(lpBack,32  ,64,32,32,lpWork,32,0,0);	//透明色無し
	Blt(lpBack,32*5,64,32,32,lpWork,32,0,1);	//透明色有り

データ転送をするには、転送先のサーフェースがメンバ関数「BltFast」を呼び出します。
「BltFast」の構文は以下の通りです。

書式 HRESULT BltFast( DWORD dwX, DWORD dwY, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans );
dwX,dwY 転送先のXおよびY座標
lpDDSrcSurface 転送元のサーフェイスへのポインタ。言い忘れてたかもしれませんがLPDIRECTDRAWSURFACE型は、これだけでポインタなので&はいりません。
lpSrcRect 転送元の領域を指定したRECT構造体へのポインタ。RECT構造体については下で詳しく解説しています。
dwTrans 転送タイプ。

DDBLTFAST_NOCOLORKEYは、透明色無しの転送。

DDBLTFAST_SRCCOLORKEYは、透明色有り(転送元カラーキーを使用)の転送

DDBLTFAST_WAITは、何らかの原因で転送出来ない時に、転送できるまで待つという指定。

これらはOR演算(|)で同時に複数指定できます。

戻り値 成功するとDD_OKが返ってくるらしい。

BltFastを使用するには、RECTと呼ばれる構造体のメンバに転送元の領域を指定する必要があります。RECT構造体は
以下のように定義されています。

typedef struct tagRECT {
	LONG left;
	LONG top;
	LONG right;
	LONG bottom;
} RECT;

left	四角形の左上隅の x 座標を指定します。
top	四角形の左上隅の y 座標を指定します。
right	四角形の右下隅の x 座標を指定します。
bottom	四角形の右下隅の y 座標を指定します。

例えば、転送元の画像のX,Y座標が32,0から64,32だとする場合は

//初心者用
RECT rec;
rec.left=32;
rec.top=0;
rec.right=64;
rec.bottom=32;

//中級者用
RECT rec={32,0,64,32};

というように指定します。
こうして転送元の範囲を指定したらBltFastを呼び出します。
転送先がバックバッファ(lpBack)、転送先のX、Y座標32,32、転送元がオフスクリーンサーフェイス(lpWork)とした場合の転送(透明色を使用 する/しない)の書き方は以下の通りです。

//透明色無しの転送(そのまま転送)
lpBack->BltFast(32,32,lpWork,&rec,DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT);

//透明色有りの転送
lpBack->BltFast(32,32,lpWork,&rec,DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);

ただ、転送タイプの指定「DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT」というのが非常に長いため、ソースの無駄遣いのような気になります(爆)。
このフラグをテーブル化し、数値で指定するようにしたのが自作関数「Blt」というわけです。

後始末

作成したオフスクリーンサーフェイス(lpWork)は解放してやらなきゃいけません。
「lpWork->Release();」というふうにしてやります。
いつも通り、マクロを使用するならば「RELEASE(lpWork);」ですかね。

記事検索

アーカイブ