<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TAKABO SOFT&#187; カテゴリー「DirectXゲーム作成講座　DirectDraw基礎編」｜TAKABO SOFT</title>
	<atom:link href="http://takabosoft.com/category/directx-draw/feed" rel="self" type="application/rss+xml" />
	<link>http://takabosoft.com</link>
	<description>ドット絵エディタ「EDGE2」、MIDI音楽編集ソフト「Domino」、楽曲などを配布している個人サイトです。</description>
	<lastBuildDate>Sun, 01 Jan 2012 03:56:35 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>第14回　長方形塗りつぶし・垂直帰線待ちをする</title>
		<link>http://takabosoft.com/20000924132819.html</link>
		<comments>http://takabosoft.com/20000924132819.html#comments</comments>
		<pubDate>Sun, 24 Sep 2000 04:28:19 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/20000924132819.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（ [...]]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<a href='http://takabosoft.com/wp-content/uploads/2000/09/ddraw_14.lzh'><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（「ddraw_14.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_14.exe」をダブルクリックし、実行してみてください。どうでしょう？画面が切り替わり、フルスクリーン化し、でかいスライムが2匹表示されていると思います(左のが垂直帰線待ち無し、右のが垂直帰線待ち有り）。</p>
<p>というわけで、今回は意図的に垂直帰線待ちをする方法を紹介します。</p>
<h3>垂直帰線おさらい</h3>
<p>以前フリップの所でも触れましたが、もう一度説明しておきます。<br />
ディスプレイは小さな電子銃からでる電子ビームを走査して、ビデオメモリの内容を連続的に反映しています。<br />
電子ビームは、左上から始まり、右へ進み、一番右まで行ったら一つ下へ下がり、一番左まで行き、また右へ進みます。<br />
それらを繰り返し、最後に右下端まで行ったら、一気に左上端に戻ります。<br />
この「右下端から左端上」に戻る間の事を「垂直帰線」とか言います。</p>
<p>で、フリップはこの垂直帰線中に行っているため、画面はちらつきません。<br />
しかしフリップ以外でフロントバッファにBltFastか何かで転送したい場合、垂直帰線中では無いため、画面がちらつく場合があります。<br />
そこで垂直帰線待ちをして、ちらつきを無くそうというわけです（謎</p>
<p>ただ、この垂直帰線中に処理しきれない場合はやっぱりちらつきますので（＾＾；</p>
<h3>というわけでコードの解説</h3>
<p>今回も順番に解説していきます。</p>
<p>まず、先に「長方形塗りつぶし」をする自作関数「Boxfill」を説明しましょうかね。</p>
<pre class="brush: cpp;">
//----------[ 長方形（塗りつぶし）描画 ]--------------------------------------------------------
void Boxfill(LPDIRECTDRAWSURFACE sf,int x,int y,int width,int height,BYTE color){
	DDBLTFX ddbltfx;
	ZeroMemory(&amp;ddbltfx,sizeof(DDBLTFX));
	ddbltfx.dwSize=sizeof(DDBLTFX);
	ddbltfx.dwFillColor=color;
	RECT rect={x,y,x+width,y+height};

	//クリッピング
	if(rect.left&lt;cx1)
		rect.left=cx1;
	if(rect.right&gt;cx2)
		rect.right=cx2;
	if(rect.top&lt;cy1)
		rect.top=cy1;
	if(rect.bottom&gt;cy2)
		rect.bottom=cy2;

    sf-&gt;Blt(&amp;rect,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT,&amp;ddbltfx);
}
</pre>
<p>サーフェイスのメンバ関数「Blt」については以前「DirectDraw基礎 第9回」でやっているので、構文等はそちらを参照してください。<br />
今回は、サーフェイスの一部を一色で塗りつぶしたいので、<br />
Blt関数の最初の引数にRECT構造体のアドレスを引き渡してやります（RECT構造体の解説は「DirectDraw基礎 第8回」でやりました）。<br />
・・・ってもう説明する事無いですね（汗</p>
<p>では次は、今回の本題「垂直帰線待ち」をする自作関数「VsyncWait」の説明～。</p>
<pre class="brush: cpp;">
//----------[ 垂直帰線待ち ]--------------------------------------------------------------------
void VsyncWait(void){
	lpDD-&gt;WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,NULL);
}
</pre>
<p>見て解る通りDirectDrawオブジェクト（lpDD)がメンバ関数である「WaitForVerticalBlank」を呼び出します。</p>
<p>構文は以下の通りです。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT WaitForVerticalBlank( DWORD dwFlags, HANDLE hEvent );
</td>
</tr>
<tr>
<th>dwFlags</th>
<td>以下のどれかを指定します。</p>
<table class="data">
<tr>
<th>DDWAITVB_BLOCKBEGIN</th>
<td>垂直帰線が開始するまで待つ</td>
</tr>
<tr>
<th>DDWAITVB_BLOCKBEGINEVENT</th>
<td>垂直帰線が開始したらイベントを起動するらしいが、現在はサポートしてないらしい。</td>
</tr>
<tr>
<th>DDWAITVB_END</th>
<td>垂直帰線が終了するまで待つ</td>
</tr>
<p></TABLE></p>
</td>
</tr>
<tr>
<th>hEvent</th>
<td>サポートされていないので、とりあえずNULL</td>
</tr>
<tr>
<th>戻り値</th>
<td>成功するとDD_OKが返ってくるらしい。</td>
</tr>
</table>
<p>そんでもって、これらを使用した今回のメインコードはこれ。</p>
<pre class="brush: cpp;">
//----------[ メイン関数 ]----------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow){

	略

	//DirectDraw開始
	StartDirectDraw(hw);

	//パレット設定
	LoadPalette(&quot;slime.bmp&quot;);

	//ビットマップを作業用サーフェイスへ読み込む
	LoadBitmap(lpWork,&quot;slime.bmp&quot;,0,0,32,32);
	//拡大
	BltStretch(lpWork,0,0,320,480,lpWork,0,0,32,32,FALSE);

	int wid=320,hei=480;

	DWORD tim;
	while(1){
		//疑似タイマー処理
		tim=timeGetTime();

		//左側のスライム（垂直帰線待ち無し）
		Boxfill(lpFront,0,0,wid,hei,0);
		Blt(lpFront,0,0,wid,hei,lpWork,0,0,FALSE);

		//右側のスライム（垂直帰線待ち有り）
		VsyncWait();
		Boxfill(lpFront,320,0,wid,hei,0);
		Blt(lpFront,320,0,wid,hei,lpWork,0,0,FALSE);

		do{
			//メッセージループ
			while(PeekMessage(&amp;msg,NULL,0,0,PM_NOREMOVE)){
				if(!GetMessage(&amp;msg,NULL,0,0))
					Quit();
				TranslateMessage(&amp;msg);
				DispatchMessage(&amp;msg);
			}
		}while(timeGetTime()&lt;tim+50);	//今回は適当
	}
</pre>
<p>ただひたすら「同じ場所に書いたり消したり」するだけで、右のスライムは垂直帰線待ちをし、垂直帰線待ちがどういう働きをするかが一目で解るようなプログラムになっているのである。えっへん(ﾟo゜)＼ばき☆ </p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/20000924132819.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第13回　低解像度（ModeX）を使ってみる</title>
		<link>http://takabosoft.com/19991103132415.html</link>
		<comments>http://takabosoft.com/19991103132415.html#comments</comments>
		<pubDate>Wed, 03 Nov 1999 04:24:15 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/19991103132415.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（ [...]]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<a href='http://takabosoft.com/wp-content/uploads/1999/11/ddraw_13.lzh'><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（「ddraw_13.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_13.exe」をダブルクリックし、実行してみてください。<br />
どうでしょう？画面が切り替わり、フルスクリーン化し、1ドットの荒いタイル（謎）がスクロールしていると思います。</p>
<p>というわけで、今回は低解像度（MODE X）モードを使ってみたいと思います。</p>
<h3>ModeX</h3>
<p>DirectDrawでは320×240、320×200と言った低解像度のディスプレイモードをサポートしています。<br />
こういった特殊（？）なディスプレイモードを使用する場合には、ModeXとよばれるものを使用しなければなりません。<br />
「ModeX」が一体何を意味するかは謎として、とにかく320×240モードを使用したい場合にはModeXの設定をすればいいのです（ｫ。</p>
<p>使い道として、秒間60枚くらいは画面更新をしたいゲーム（ハデなアクションや格闘）、3D等で描画時間を少しでも減らせるように低解像度にするといった事が考えられます。<br />
ただ、私が試したところ、ModeXを使用すると、一部の環境で不都合が生じる事があります。<br />
そんな時はコントロールパネルのDirectXのアイコンをダブルクリックし、DirectDrawの項目の中の「Use ModeX for 320 for X（？）」みたいな感じのチェックを外してみてください。<br />
たぶん正常に動作すると思います。</p>
<p>では実際にプログラムするにはどうしたら良いでしょう。コードを見てみましょう。</p>
<pre class="brush: cpp;">
BOOL StartDirectDraw(HWND hw){

	&lt;略&gt;

	//協調レベル設定
	if(lpDD-&gt;SetCooperativeLevel(hw,DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_ALLOWMODEX)!=DD_OK)
		return FALSE;

	//解像度設定
	if(lpDD-&gt;SetDisplayMode(320,240,8)!=DD_OK)
		return FALSE;
</pre>
<p>自作関数「StartDirectDraw」内の協調レベル設定部分の引数に、「DDSCL_ALLOWMODEX」を追加してやります。<br />
これで、DirectDrawがModeXを使用するように設定出来ました。<br />
次に、解像度設定で、320×240×8（256）を指定し、この瞬間に画面が切り替わります。<br />
とりあえず、DirectDrawの設定はこれで終わりです(^^;</p>
<p>ただ、ModeXにはいくつか制約があります。<br />
まず、プライマリサーフェイスへデータを転送出来ないという点、次にプライマリサーフェイスのロック、最後にプライマリサーフェイスに対するGetDCの使用です。<br />
要するにプライマリサーフェイスにアクセス出来ないと言う事です。<br />
ですから、普段は複合プライマリサーフェイスを作成してバックバッファからフリップしてフロントバッファに表示させるしか方法がありません。<br />
これらを除けばバックバッファやオフスクリーンサーフェイスの扱いは今まで通り出来ます。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19991103132415.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第12回　サーフェイスに直接アクセスする</title>
		<link>http://takabosoft.com/19990905131852.html</link>
		<comments>http://takabosoft.com/19990905131852.html#comments</comments>
		<pubDate>Sun, 05 Sep 1999 04:18:52 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/19990905131852.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、をお持ちの方はVisual C++でプロジェクトファイルを開いてください [...]]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<a href='http://takabosoft.com/wp-content/uploads/1999/09/ddraw_12.lzh'><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、をお持ちの方はVisual C++でプロジェクトファイルを開いてください（「ddraw_12.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_12.exe」をダブルクリックし、実行してみてください。<br />
どうでしょう？画面が切り替わり、フルスクリーン化し、流れ星のようなものが表示されると思います。</p>
<p>というわけで、今回はサーフェイスへ直接アクセスする方法を書いていきたいと思います。</p>
<h3>ダイレクトアクセス</h3>
<p>まずサーフェイスへ直接アクセスするとはどういう事なのかを簡単に説明します。<br />
サーフェイスは、ビデオメモリもしくはシステムメモリ内に作成されます。<br />
メモリは1次元配列で管理されており、DirectDrawでは、サーフェイスが存在しているメモリの先頭アドレスを取得する事が出来ます。<br />
ですから、このアドレスを使って、1次元配列と同じようにサーフェイス扱う事ができると言うわけです。<br />
と言っても、使用するのは「点を描く」と言った処理程度でしょう。</p>
<p>では、実際にサーフェイスへの先頭アドレスを取得する方法を記述します。<br />
サンプルコードを見てみましょう。</p>
<pre class="brush: cpp;">
	unsigned char *p;
	DDSURFACEDESC desc;

	&lt;略&gt;

		//サーフェイスをロック
		ZeroMemory(&amp;desc,sizeof(DDSURFACEDESC));
		desc.dwSize=sizeof(DDSURFACEDESC);
		lpBack-&gt;Lock(NULL,&amp;desc,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL);
		p=(unsigned char *)desc.lpSurface;

		//データを書き込む
		for(i=0;i&lt;STAR;i++){
			p[x[i]+(int)y[i]*desc.lPitch]=sp[i];
			if((y[i]+=sp[i]/4.0f)&gt;=480)
				y[i]-=480;
		}

		//ロックを解除
		lpBack-&gt;Unlock(desc.lpSurface);
</pre>
<p>今回はサーフェイス作成時にも使用した構造体「DDSURFACEDESC」型を使用するので、最初にこれを初期化しておきます（ZeroMemory等)。<br />
そうしたら、サーフェイスのメンバである「Lock」という関数を呼び出します。<br />
サーフェイスをロックする事により、サーフェイスへの先頭アドレスが取得出来ます。</p>
<p>では、Lockの構文を書いておきます。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT Lock( LPRECT lpDestRect, LPDDSURFACEDESC lpDDSurfaceDesc, DWORD dwFlags, HANDLE hEvent );
</td>
</tr>
<tr>
<th>lpDestRect</th>
<td>ロックしたい領域を識別するRECT構造体のアドレス。NULLであれば、全サーフェスがロックされる</td>
</tr>
<tr>
<th>lpDDSurfaceDesc</th>
<td>サーフェスについての情報を格納する DDSURFACEDESC 構造体へのポインタ。</td>
</tr>
<tr>
<th>dwFlags</th>
<td>
<table class="data">
<tr>
<th>DDLOCK_SURFACEMEMORYPTR</th>
<td>指定した矩形の先頭への有効なメモリ ポインタを返さなければならないことを表すフラグ。矩形が指定されない場合、一番上のサーフェスへのポインタが返される。</td>
</tr>
<tr>
<th>DDLOCK_WAIT</th>
<td>何らかの原因によってロック（アドレス取得）が出来ない場合に、出来るまで待つという指定</td>
</tr>
</table>
</td>
</tr>
<tr>
<th>hEvent</th>
<td>現在は使用していないのでNULLを指定しなければならないらしい</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功した場合はDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>こうすると、DDSURFACEDESC構造体のメンバであるlpSurfaceに、サーフェイスの先頭アドレスが格納されるので、そのアドレスをあらかじめ用意しておいたunsigned char型（256色なので）のポインタ変数pへ代入してやります。</p>
<p>では、このポインタの扱い方（サーフェイスへのアクセス）を説明します。<br />
前にも記述しましたが、メモリは1次元配列で構成されているので、「座標X、Yへ5を代入」という場合にp[y][x]=5;とは書けません。<br />
メモリは座標（0,0）から右へ順に行き、突き当たったらY座標が1ドット下へいき、X座標が0になる・・・を繰り返す形で存在しています（謎。<br />
ですから、p[0]が（0,0）になります。<br />
それで、本来ならばp[640]が座標（0,1）つまりp[x+y*640]というように考えるはずなのですがビデオカードによっては、自動的にサーフェイスの横幅を少し増やして、そこをキャッシュとして使用するものがあります。<br />
そして、DDSURFACEDESC構造体のメンバであるlPitchには、このキャッシュの部分を含めた正確な横幅が格納されています。<br />
ですから、サーフェイスメモリへアクセスするにはp[x+y*desc.lPitch]と表すのが正確となります。</p>
<p>一通り、アクセスし終えたら、ロックを解除してやる必要があります。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT Unlock( LPVOID lpSurfaceData );
</td>
</tr>
<tr>
<th>lpSurfaceData</th>
<td>Lockによって取得され、アンロックすべきサーフェスのアドレス。このパラメータは、対応する Lock 呼び出しで lpDestRect パラメータに NULL を渡して全サーフェスをロックした場合に限り、NULL とする。</p>
<p>ちなみに、全体をロックしなかった場合は、desc.lpSurfaceを引き渡す事になります。
</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功した場合はDD_OKが返ってくるらしい。</p>
</td>
</tr>
</table>
<p>これで、一通り終わりです。<br />
実際にサーフェイスへアクセスするのは、ロックからアンロックする間だけにしてください。<br />
ロックしてサーフェイスポインタを取得し、直ぐにアンロックしてしまった後に、サーフェイスへアクセスする事は一応出来ますが、<br />
ビデオカードによっては上手くいかない場合があるので、止めた方がいいです（確認済み）。<br />
それと、ロックという処理は、結構遅いので1ループに1度というのが理想です。<br />
1ループに何度もロック、アンロックを繰り返すのは速度低下の原因となります。<br />
それから、ロックしたあと、アンロックしないと、そのサーフェイスへの書き込み（GDIやBltFast等による転送）が不自由になるので注意してください。</p>
<p>ちなみに、ビデオメモリ内のサーフェイスへのアクセス（読み込み&#038;書き込み）は非常に遅いので、一度システムメモリ内へコピーし、システムメモリ内をいじってから、ビデオメモリ内のサーフェイスへ転送する方がいいかもしれません。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990905131852.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第11回　画像転送時にDirectDraw側でクリッピングする</title>
		<link>http://takabosoft.com/19990901131409.html</link>
		<comments>http://takabosoft.com/19990901131409.html#comments</comments>
		<pubDate>Wed, 01 Sep 1999 04:14:09 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/19990901131409.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（ [...]]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<a href='http://takabosoft.com/wp-content/uploads/1999/09/ddraw_11.lzh'><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（「ddraw_11.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_11.exe」をダブルクリックし、実行してみてください。<br />
どうでしょう？画面が切り替わり、フルスクリーン化し、SLIME（？）と書かれた画像がタイル状に敷き詰められ、どんどん小さくなりながら左上へスクロールするのが解ると思います。</p>
<p>というわけで今回は、DirectDraw側で画像転送時にクリッピングしたいと思います。</p>
<h3>DirectDrawクリッパー</h3>
<p>DirectDrawにクリッピングをさせるには、DirectDrawクリッパーというものを使用します。<br />
クリッパー作成は、自作関数「StartDirectDraw」内に追加してあります。</p>
<pre class="brush: cpp;">
//グローバル変数宣言
LPDIRECTDRAWCLIPPER lpClipper=NULL;	//クリッパーオブジェクト

略

	//クリッパーの設定
	if(lpDD-&gt;CreateClipper(0,&amp;lpClipper,NULL)!=DD_OK)
		return FALSE;
	if(lpClipper-&gt;SetHWnd(0,hw)!=DD_OK)
		return FALSE;
	if(lpBack-&gt;SetClipper(lpClipper)!=DD_OK)
		return FALSE;
</pre>
<p>意外とソースは短いですかねぇ（＾＾；。<br />
では、順番に説明していきたいと思います。<br />
まず、DirectDrawオブジェクト（lpDD）のメンバ関数である「CreateClipper」を呼び出し、DirectDrawクリッパーオブジェクトを作成します。<br />
構文は以下の通りです。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT CreateClipper( DWORD dwFlags, LPDIRECTDRAWCLIPPER FAR *lplpDDClipper, IUnknown FAR *pUnkOuter );
</td>
</tr>
<tr>
<th>dwFlags</th>
<td>このフラグは使用していないらしく、0を指定する必要があるらしい</td>
</tr>
<tr>
<th>*lplpDDClipper</th>
<td>新しいDirectDrawClipperオブジェクトを示すポインタへのポインタ。<br />
例によって、LPDIRECTDRAWCLIPPER型自体がポインタ型になっているので、「ポインタへのポインタ」と言っています（たぶん）。
</td>
</tr>
<tr>
<th>*pUnkOuter</th>
<td>将来拡張のために使用するらしいので今はNULLを指定。</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功した場合はDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>これで、DirectDrawClipperオブジェクトが出来ました。<br />
で次にこいつのメンバ関数である「SetHWnd」を呼び出します。<br />
これは、クリッピング範囲をウィンドウハンドルを参照して設定するというものです。<br />
つまり、プライマリサーフェイスと同じ範囲に設定されるわけです。</p>
<p>というわけで、構文。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT SetHWnd( DWORD dwFlags, HWND hWnd );
</td>
</tr>
<tr>
<th>dwFlags</th>
<td>このフラグは使用していないらしく、0を指定する必要があるらしい</td>
</tr>
<tr>
<th>hWnd</th>
<td>クリッピング情報を含むウィンドウ ハンドル
</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功した場合はDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>これで、クリッピング範囲を設定し終えたら、次にサーフェイスのメンバ関数である「SetClipper」を呼び出します。<br />
SetClipperによってサーフェイスへクリッパーを関連付けさせれば、そのサーフェイスに対し、クリッピングが可能となります。<br />
一応構文も載せておきます。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT SetClipper( LPDIRECTDRAWCLIPPER lpDDClipper );
</td>
</tr>
<tr>
<th>lpDDClipper</th>
<td>関連づけさせるクリッパー。ここを0にしてやると、今まで関連付けられていたクリッパーが外されるらしい（未確認）。</td>
</tr>
<tr>
<th>hWnd</th>
<td>クリッピング情報を含むウィンドウ ハンドル
</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功した場合はDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>設定は以上です。<br />
このクリッパーは、関連付けさせたサーフェイスへ、サーフェイスのメンバ関数「Blt」（<font color=red>自作関数の方では無いので注意してください</font>）で転送した場合にのみ有効となります。<br />
それと、クリッパーが関連づけさせられているサーフェイスへBltFast（自作関数Blt）による転送は出来ません。</p>
<p>今回は、クリッパーをバックバッファ（lpBack）に関連付けさせていますが、ここへBlt（自作関数BltStretch）による転送をしたときにだけ、クリッピングされます。<br />
まぁ、このクリッパーによるクリッピングは私の環境では速度が遅いので使用していません。<br />
ですから詳しいこたぁ、よくわかりましぇ～ん。</p>
<h3>後始末</h3>
<p>いつも通り、終了する時にはlpClipper->Release();を実行してやらなければなりません。<br />
マクロ使用ではRELEASE(lpClipper);ですね。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990901131409.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第10回　画像転送時に自分でクリッピングする</title>
		<link>http://takabosoft.com/19990827130944.html</link>
		<comments>http://takabosoft.com/19990827130944.html#comments</comments>
		<pubDate>Fri, 27 Aug 1999 04:09:44 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/19990827130944.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（ [...]]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<a href='http://takabosoft.com/wp-content/uploads/1999/08/ddraw_10.lzh'><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（「ddraw_10.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_10.exe」をダブルクリックし、実行してみてください。<br />
どうでしょう？画面が切り替わり、フルスクリーン化し、SLIME（？）と書かれた画像がタイル状に敷き詰められ、左上へスクロールするのが解ると思います。</p>
<p>というわけで今回は、自分で画像転送時にクリッピングしたいと思います。</p>
<h3>プログラム側でクリッピング</h3>
<p>今回のサンプルの注目すべき点は「スクロール」では無く、画面の端っこのほうに表示している「完全でない画像」です（謎。<br />
今まで、BltFast関数を使用した自作関数Bltでは、転送先で少しでも画像がはみ出てしまうと、何も表示されなくなってしまいます。<br />
で、画面から少しでもはみ出してしまった場合、はみ出ていない部分を表示させる処理がクリッピングと言われています（たぶん）。</p>
<pre class="brush: cpp;">
int cx1=0,cy1=0,cx2=640,cy2=480;	//自前クリッピング処理に使用する範囲

//----------[ クリッピング付きのデータ転送 ]----------------------------------------------------
void BltClip(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};
	if(sx&lt;cx1){
		mx+=cx1-sx;
		width-=cx1-sx;
		sx=cx1;
		if(width&lt;1)
			return;
	}
	if(sy&lt;cy1){
		my+=cy1-sy;
		height-=cy1-sy;
		sy=cy1;
		if(height&lt;1)
			return;
	}

	if(sx&gt;=cx2 || sy&gt;=cy2)
		return;
	if(sx+width&gt;cx2)
		width=cx2-sx;
	if(sy+height&gt;cy2)
		height=cy2-sy;
	RECT rec={mx,my,mx+width,my+height};
	saki-&gt;BltFast(sx,sy,moto,&amp;rec,key[trans] | DDBLTFAST_WAIT);
}
//----------[ クリッピングする範囲を変更 ]------------------------------------------------------
void SetClipArea(int x,int y,int width,int height){
	cx1=x;
	cy1=y;
	cx2=x+width;
	cy2=y+height;
}
</pre>
<p>この自作関数では、転送前に転送先の座標と縦幅、横幅からはみ出している部分を検出し、うまく表示出来るように値を変更しています。<br />
まぁ、見りゃ解りますね（＾＾；<br />
ついでなのでクリッピングの範囲を変更出来るようにもしておきました。この自作関数では、どこのサーフェイスでも適応されます。</p>
<p>使用例はこんな感じでしょうかね</p>
<pre class="brush: cpp;">
//クリッピング範囲が全画面(0,0)～(639,479)の場合
SetClipArea(0,0,640,480);	//width,heightは0（ゼロ）も1ドットと考えるため639,479にはならない

//転送
BltClip(lpBack,-5,0,32,32,lpWork,0,0,0);
Flip();
</pre>
<p>今回は、プログラム側でクリッピングを行いました。<br />
その理由として、DirectDraw側でクリッピングを行うと、家の環境で試したところ、速度がガタ落ちしたからです。<br />
プログラムで処理した方がよっぽど早いですし、応用も利きます。<br />
ただし、この方法にも欠点はあります。それは拡大縮小を行った時にクリッピング出来ないという点です。<br />
というわけで、次回では一応DirectDrawでのクリッピング方法を説明します（私は使ってませんけど）。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990827130944.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第9回　サーフェイスの全消去、拡大縮小付きデータ転送</title>
		<link>http://takabosoft.com/19990822130242.html</link>
		<comments>http://takabosoft.com/19990822130242.html#comments</comments>
		<pubDate>Sun, 22 Aug 1999 04:02:42 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/19990822130242.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずddraw_09]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<a href='http://takabosoft.com/wp-content/uploads/1999/08/ddraw_09.lzh'>ddraw_09</a<b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、<br />
お持ちの方はVisual C++でプロジェクトファイルを開いてください（「ddraw_09.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_09.exe」をダブルクリックし、実行してみてください。<br />
どうでしょう？画面が切り替わり、フルスクリーン化し、スライム（？）らしき絵が段々小さくなっていくのが解ると思います。</p>
<p>というわけで今回は、サーフェイスの全消去と、拡大縮小付きの転送について書いていきたいと思います。</p>
<h3>サーフェイスの全消去</h3>
<p>シューティングゲーム等では、バックバッファを一度全て消し、そこに全てキャラクターを配置して、フリップという処理を繰り返し行います（たぶん）。<br />
このとき、もしバックバッファを消さないと、前に書き込んだ分が残ったままになってしまいます（まぁ、当たり前の話なのですが（＾＾；）。<br />
DirectDrawでは、この場合矩形領域を何かの色で塗りつぶすという処理をすることになります（矩形塗りつぶし）。</p>
<p>では、コードを見てみましょう。</p>
<pre class="brush: cpp;">
//----------[ サーフェイス全消去 ]--------------------------------------------------------------
void ClearScreen(LPDIRECTDRAWSURFACE sf){
	DDBLTFX ddbltfx;
	ZeroMemory(&amp;ddbltfx,sizeof(DDBLTFX));
	ddbltfx.dwSize=sizeof(DDBLTFX);
	//ddbltfx.dwFillColor=0;
	sf-&gt;Blt(NULL,NULL,NULL,DDBLT_COLORFILL | DDBLT_WAIT,&amp;ddbltfx);
}
</pre>
<p>塗りつぶしには、<b>サーフェイスのメンバ関数</b>である「Blt」を呼び出します（<font color=red>前回作成した自作関数Bltと名前が同じですが、全く違うものなので注意してください</font>）。<br />
Blt関数はもともと転送用（拡大縮小にも使用）なのですが、<br />
いろいろな機能がついていて、良いような悪いような（謎）関数です。<br />
で、いろいろな機能を使用したい場合はDDBLTFX構造体にいろいろデータをぶち込んで、Blt関数に引き渡してやります。<br />
ZeroMemoryという関数はデータを指定したバイト分0にするというものです。<br />
dwSizeにはデータのサイズを入れてやります。<br />
で、塗りつぶしたい色のパレット番号をメンバdwFillColorに入れてやるのですが、今回は黒（パレット0番）なので何もしなくていい事になります。<br />
Bltの構文は以下の通りです。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT Blt( LPRECT lpDestRect, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags, LPDDBLTFX lpDDBltFx );
</td>
</tr>
<tr>
<th>lpDestRect</th>
<td>ブロック転送する転送先のサーフェス上の矩形の左上および右下の位置を定義した RECT 構造体へのポインタ。このパラメータが NULL であると、転送先の全サーフェスが使われる。</td>
</tr>
<tr>
<th>lpDDSrcSurface</th>
<td>ブロック転送操作の転送元である DirectDraw サーフェスへのポインタ。</td>
</tr>
<tr>
<th>lpSrcRect</th>
<td>ブロック転送される転送元サーフェス上の矩形の左上および右下の場所を定義した RECT 構造体へのポインタ。このパラメータが NULL であると、転送元の全サーフェスが使われる。</td>
</tr>
<tr>
<th>dwFlags</th>
<td>指定できる主なフラグは以下の通りです。</p>
<table class="data">
<tr>
<th>DDBLT_COLORFILL</th>
<td>転送先サーフェス上の転送先矩形を埋めるRGB 色として DDBLTFX構造体のdwFillColor メンバを使用する。</td>
</tr>
<tr>
<th>DDBLT_KEYSRC</th>
<td>転送元サーフェスと関連づけられたカラーキーを使用する（透明色）。</td>
</tr>
<tr>
<th>DDBLT_WAIT</th>
<td>何らかの原因で転送出来ない時に転送できるまで待つ。</td>
</tr>
</table>
<p>これらはOR演算子（｜）を使用して複数同時に指定可能です。
</td>
</tr>
<tr>
<th>lpDDBltFx</th>
<td>DDBLTFX構造体へのポインタ。</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功するとDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>今回は、サーフェイスの全領域を黒（パレット0番）で塗りつぶすのでlpDestRectはNULLになっていますが、RECT構造体を使用して部分的に塗りつぶす事も出来ます。</p>
<h3>拡大縮小付きデータ転送</h3>
<p>拡大縮小付きデータ転送は自作関数「BltStretch」にまとめました。</p>
<pre class="brush: cpp;">
//----------[ 拡大縮小付きデータ転送 ]----------------------------------------------------------
void BltStretch(LPDIRECTDRAWSURFACE saki,int sx,int sy,int swidth,int sheight,
		        LPDIRECTDRAWSURFACE moto,int mx,int my,int mwidth,int mheight,char trans){
	DWORD key[2]={0,DDBLT_KEYSRC};
	RECT r_saki={sx,sy,sx+swidth,sy+sheight};
	RECT r_moto={mx,my,mx+mwidth,my+mheight};
	saki-&gt;Blt(&amp;r_saki,moto,&amp;r_moto,key[trans] | DDBLT_WAIT,NULL);
}
</pre>
<p>Bltの構文については上で説明した通りです。<br />
転送先のサーフェイスがBlt関数を呼び出すことになります。<br />
BltFast関数（第8回参照）と似てる部分もあるのですが、転送先の指定にRECT構造体を使用していたり、透明色を使用しない時に特に指定が無いという事が違う点ですかね。<br />
転送元と転送先のサイズが違うときに拡大縮小を行います。<br />
サイズが同じ時はそのまま転送するのですが、ハードウェアの転送であればBltFastと速度は同じらしいです。</p>
<p>まぁ今回は、特別な機能を使用していないのでDDBLTFX構造体へのポインタはNULLを指定してます。<br />
拡大縮小機能は普通のビデオカードではまず対応していないでしょう。<br />
その場合、ソフトウェアでエミュレートするのですが、ビデオメモリ内に作成されたサーフェイス間のデータ転送は非常にたるいです。<br />
ですからシステムメモリ内のサーフェイス間で拡大縮小をした後でビデオメモリ内のサーフェイスへ転送する方がいいかもしれませんね。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990822130242.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第8回　作業用サーフェイスを作成し、データ転送</title>
		<link>http://takabosoft.com/19990819125618.html</link>
		<comments>http://takabosoft.com/19990819125618.html#comments</comments>
		<pubDate>Thu, 19 Aug 1999 03:56:18 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/19990819125618.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、
お持ちの方はVisual C++でプロジェクトファイルを開いてください [...]]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<a href='http://takabosoft.com/wp-content/uploads/1999/08/ddraw_08.lzh'><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、<br />
お持ちの方はVisual C++でプロジェクトファイルを開いてください（「ddraw_08.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_08.exe」をダブルクリックし、実行してみてください。<br />
どうでしょう？画面が切り替わり、フルスクリーン化し、<br />
<img src="http://takabosoft.com/wp-content/uploads/1999/08/slime.jpg" alt="slime" title="slime" width="64" height="32" class="alignnone size-full wp-image-48" />が作業用サーフェイスに読み込まれ、そこから部分的にバックバッファにデータが転送されていると思います（謎</p>
<p>というわけで、今回は作業用サーフェイスを作成し、データ転送をしたいと思います。</p>
<h3>作業用サーフェイスの作成</h3>
<p>普段、ゲームを作成する場合は、オフスクリーンサーフェイス（作業用サーフェイス）と呼ばれる目に見えないサーフェイスを作成し、そこへビットマップを読み込み、そこからバックバッファへデータ転送し、フリップし、画面に表示させます・・・というのは何度も書いているので既に解っていると思います。<br />
んでは、まずオフスクリーンサーフェイスの作成方法を記しておきます。</p>
<p>オフスクリーンサーフェイスの作成は自作関数「StartDirectDraw」に追加してあります。</p>
<pre class="brush: cpp;">
LPDIRECTDRAWSURFACE lpWork=NULL;	//オフスクリーンサーフェイス（作業用バッファ）

	略

	//オフスクリーンサーフェイス作成
	ZeroMemory(&amp;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-&gt;CreateSurface(&amp;ddsd,&amp;lpWork,NULL))!=DD_OK)
		return FALSE;
</pre>
<p>DirectDrawオブジェクトのメンバである「CreateSurface」については第3回のプライマリサーフェイス作成時に多少説明しました。<br />
今回はオフスクリーンサーフェイスを作成するという事で、dwFlagsには更に DDSD_WIDTH | DDSD_HEIGHT を追加指定し、サーフェイスの縦幅、横幅を指定出来るようにします。<br />
そうしたら、dwWidthとdwHeightに縦幅、横幅を指定（今回はプライマリサーフェイスと同じ640×480）します。<br />
んで、ddsCaps.dwCapsにDDSCAPS_OFFSCREENPLAINを指定し、「CreateSurface」を呼び出せば、サーフェイスが作成されます。<br />
作成したいサーフェイスのサイズは自由に変更可能ですが、プライマリサーフェイスよりも大きなサーフェイスを作成しようとするとDirectXのバージョンによっては失敗する可能性があるのでやめた方が良いですね。</p>
<p>ちなみに、オフスクリーンサーフェイスはビデオメモリに作成されますが、ビデオメモリが足りなくなると、自動的にシステムメモリ内に作成されます。<br />
また、意図的にシステムメモリ内へサーフェイスを作成したい場合はddsd.ddsCaps.dwCapsにDDSCAPS_OFFSCREENPLAIN | <b>DDSCAPS_SYSTEMMEMORY</b>;を指定してやります。</p>
<p>例によって、オフスクリーンサーフェイス（lpWork）は、ビデオメモリだろうがシステムメモリだろうが関係なしに、フロントバッファやバックバッファと同じように扱う事が出来ます（GDIの描画等含む）。</p>
<h3>サーフェイス間のデータ転送</h3>
<p>では、オフスクリーンサーフェイスにキャラクターイメージを読み込んだ後、このイメージを他の場所へ転送します。<br />
で、ただ転送するだけでなく、透明色を使用した転送が出来ます。その場合、どの色を透明色にするかをサーフェイス毎に設定しておかなければなりません。<br />
では、透明色の指定方法を以下に記します。</p>
<pre class="brush: cpp;">
//----------[ 透明色の設定 ]--------------------------------------------------------------------
void SetTransColor(LPDIRECTDRAWSURFACE sf,int palette_number){
	DDCOLORKEY ddck={palette_number,palette_number};
	sf-&gt;SetColorKey(DDCKEY_SRCBLT,&amp;ddck);
}

略
	//呼び出し
	//透明色の指定（パレット1番の色を透明色にする）
	SetTransColor(lpWork,1);
</pre>
<p>まず、DDCOLORKEY構造体のメンバに透明色にしたい色を指定します。DDCOLORKEY構造体は以下のようになっています。</p>
<pre class="brush: cpp;">
typedef struct _DDCOLORKEY{
    DWORD dwColorSpaceLowValue;
    DWORD dwColorSpaceHighValue;
} DDCOLORKEY;
</pre>
<p>メンバ変数は2つあります。パレット番号のLowValueからHighValueの範囲を透明色とするらしいのですが（未確認）、普段は1色しか透明色として使用しないので、LowもHighも同じ値にします。<br />
そうしたら、DirectDrawサーフェイスのメンバである「SetColorKey」を呼び出します。構文は以下の通りです。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT SetColorKey( DWORD dwFlags, LPDDCOLORKEY lpDDColorKey );
</td>
</tr>
<tr>
<th>dwFlags</th>
<td>透明色を指定する場合はDDCKEY_SRCBLTを指定する。これは、転送元サーフェイスの指定した色以外を転送する事を意味する。転送元カラーキーとも言う。</p>
<p>他にもDDCKEY_DESTBLTというのがあるが、これは転送先の指定した色の部分にのみ転送する。転送先カラーキーとも言う。こっちは滅多に使用しないので解説省略だぃ（いつか解説するかも）。</p>
</td>
</tr>
<tr>
<th>lpDDColorKey</th>
<td>DirectDrawSurface オブジェクトの新しいカラーキー値を含んでいる DDCOLORKEY 構造体へのポインタ。</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功するとDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>さて、今回はパレット1番の紫色（パレット番号は0から始まります）を透明色として使用する事にします。<br />
そうしたら、今度はデータ転送です。</p>
<pre class="brush: cpp;">
//----------[ データ転送 ]----------------------------------------------------------------------
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-&gt;BltFast(sx,sy,moto,&amp;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);	//透明色有り
</pre>
<p>データ転送をするには、転送先のサーフェースがメンバ関数「BltFast」を呼び出します。<br />
「BltFast」の構文は以下の通りです。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT BltFast( DWORD dwX, DWORD dwY, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans );
</td>
</tr>
<tr>
<th>dwX,dwY</th>
<td>転送先のXおよびY座標</td>
</tr>
<tr>
<th>lpDDSrcSurface</th>
<td>転送元のサーフェイスへのポインタ。言い忘れてたかもしれませんがLPDIRECTDRAWSURFACE型は、これだけでポインタなので&#038;はいりません。
</td>
</tr>
<tr>
<th>lpSrcRect</th>
<td>転送元の領域を指定したRECT構造体へのポインタ。RECT構造体については下で詳しく解説しています。</td>
</tr>
<tr>
<th>dwTrans</th>
<td>転送タイプ。</p>
<p>DDBLTFAST_NOCOLORKEYは、透明色無しの転送。</p>
<p>DDBLTFAST_SRCCOLORKEYは、透明色有り（転送元カラーキーを使用）の転送</p>
<p>DDBLTFAST_WAITは、何らかの原因で転送出来ない時に、転送できるまで待つという指定。</p>
<p>これらはOR演算（|）で同時に複数指定できます。</p>
</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功するとDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>BltFastを使用するには、RECTと呼ばれる構造体のメンバに転送元の領域を指定する必要があります。RECT構造体は<br />
以下のように定義されています。</p>
<pre class="brush: cpp;">
typedef struct tagRECT {
	LONG left;
	LONG top;
	LONG right;
	LONG bottom;
} RECT;

left	四角形の左上隅の x 座標を指定します。
top	四角形の左上隅の y 座標を指定します。
right	四角形の右下隅の x 座標を指定します。
bottom	四角形の右下隅の y 座標を指定します。
</pre>
<p>例えば、転送元の画像のX,Y座標が32,0から64,32だとする場合は</p>
<pre class="brush: cpp;">
//初心者用
RECT rec;
rec.left=32;
rec.top=0;
rec.right=64;
rec.bottom=32;

//中級者用
RECT rec={32,0,64,32};
</pre>
<p>というように指定します。<br />
こうして転送元の範囲を指定したらBltFastを呼び出します。<br />
転送先がバックバッファ(lpBack)、転送先のX、Y座標32,32、転送元がオフスクリーンサーフェイス(lpWork)とした場合の転送（透明色を使用 する/しない）の書き方は以下の通りです。</p>
<pre class="brush: cpp;">
//透明色無しの転送（そのまま転送）
lpBack-&gt;BltFast(32,32,lpWork,&amp;rec,DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT);

//透明色有りの転送
lpBack-&gt;BltFast(32,32,lpWork,&amp;rec,DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);
</pre>
<p>ただ、転送タイプの指定「DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT」というのが非常に長いため、ソースの無駄遣いのような気になります（爆）。<br />
このフラグをテーブル化し、数値で指定するようにしたのが自作関数「Blt」というわけです。</p>
<h3>後始末</h3>
<p>作成したオフスクリーンサーフェイス(lpWork)は解放してやらなきゃいけません。<br />
「lpWork->Release();」というふうにしてやります。<br />
いつも通り、マクロを使用するならば「RELEASE(lpWork);」ですかね。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990819125618.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第7回　ビットマップをサーフェイス上に読み込む</title>
		<link>http://takabosoft.com/19990816124831.html</link>
		<comments>http://takabosoft.com/19990816124831.html#comments</comments>
		<pubDate>Mon, 16 Aug 1999 03:48:31 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/19990816124831.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、
お持ちの方はVisual C++でプロジェクトファイルを開いてください [...]]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<a href='http://takabosoft.com/wp-content/uploads/1999/08/ddraw_07.lzh'><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、<br />
お持ちの方はVisual C++でプロジェクトファイルを開いてください（「ddraw_07.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_07.exe」をダブルクリックし、実行してみてください。<br />
どうでしょう？画面が切り替わり、フルスクリーン化し、<br />
<img src="http://takabosoft.com/wp-content/uploads/1999/08/test0.gif" alt="test0" title="test0" width="160" height="32" class="alignnone size-full wp-image-45" />がフロントバッファに読み込まれると思います。</p>
<p>というわけで、今回は256色のビットマップ形式（*.bmp）をサーフェイスを読み込みたいと思います。</p>
<h3>パレット設定</h3>
<p>さて、256色のビットマップを正確に表示するためには、まずビットマップファイルが持つパレットを読み込む必要があります。<br />
これをサボると、ビットマップの色がバケてしまいますからね。</p>
<p>ちなみに、256色の場合は、パレットが256個あり、サーフェイスの1ドット1ドットは表示しているパレット番号（色）を記憶しているだけです。これはビットマップ画像(*.bmp)も同じ構造です。</p>
<p>であ、よく解らない解説いってみよう！</p>
<pre class="brush: cpp;">
//----------[ ビットマップファイルからパレットを読み込む ]--------------------------------------
void LoadPalette(char *filename){
	int i;
	FILE *fp;
	if((fp=fopen(filename,&quot;rb&quot;))==NULL){
		sprintf(tmp,&quot;%s ファイルが見つかりません&quot;,filename);
		Quit(tmp);
	}
	fseek(fp,0x36,0);
	for(i=0;i&lt;256;i++){
		peEntry[i].peBlue=fgetc(fp);
		peEntry[i].peGreen=fgetc(fp);
		peEntry[i].peRed=fgetc(fp);
		peEntry[i].peFlags=1;
		fgetc(fp);
	}
	fclose(fp);
	lpPalette-&gt;SetEntries(0,0,256,peEntry);
}

	略

	//呼び出し
	//パレット設定
	LoadPalette(&quot;test.bmp&quot;);
</pre>
<p>では、解説・・・って言っても見てわかりませんかねぇ？（爆）。私が解析したトコロ、BMP形式はパレット情報が0x36番地から格納されているので<br />
fseekで読み込む位置をずらし、順番に青、緑、赤と読み込んでいます。256個読み込んだらlpPalette->SetEntries(0,0,256,peEntry);を実行して<br />
DirectDrawのパレットを全て変更します（と言っても0、255番は変更できませんが・・・）。<br />
ちなみにlpPalette->SetEntries(0,1,254,&#038;peEntry[1]);でも良いでしょう（未確認）。</p>
<p>それと言っておきたい事は、これらの方法は1例にしか過ぎないという事です。<br />
私もGDIはよく解らないので（というかよく解らない関数が多いので）適当にプログラムを組んでいます。<br />
GDIに詳しい方ならもっと良い方法を知っているでしょう。<br />
そういう場合は私にメールください（爆。</p>
<h3>ビットマップ読み込み</h3>
<p>ちうわけで、パレットの設定が終わったら、画像データ（？）を読み込みます。<br />
パレットと同じようにデータを解析して適当に表示しても良いのですが、便利そうなシステムサービス関数を見つけたので今回はこれを使用してみました。</p>
<pre class="brush: cpp;">
//----------[ ビットマップをサーフェイス上へ読み込む ]------------------------------------------
void LoadBitmap(LPDIRECTDRAWSURFACE sf,char *filename,int x,int y,int x_size,int y_size){
	HDC hdcs, hdcd;
	HANDLE hbmp,hbmpold;

	//APIを使用した読み込み
	if((hbmp=LoadImage(NULL,filename,IMAGE_BITMAP,
		x_size,y_size,LR_CREATEDIBSECTION|LR_LOADFROMFILE))==NULL){
		sprintf(tmp,&quot;%s ファイルが見つかりません&quot;,filename);
		Quit(tmp);
	}

	//サーフェイスへ転送
	hdcs=CreateCompatibleDC(NULL);
	hbmpold=SelectObject(hdcs,hbmp);
	sf-&gt;GetDC(&amp;hdcd);
	BitBlt(hdcd,x,y,x_size,y_size,hdcs,0,0,SRCCOPY);
	sf-&gt;ReleaseDC(hdcd);
	SelectObject(hdcs,hbmpold);
	DeleteDC(hdcs);
	DeleteObject(hbmp);
}

	略

	//ビットマップをフロントバッファへ読み込む
	LoadBitmap(lpFront,&quot;test.bmp&quot;,0,32,160,32);
</pre>
<p>んー、面倒ですが仕方ない（謎）のでちゃちゃっと説明しちゃいますね。</p>
<pre class="brush: cpp;">
	//APIを使用した読み込み
	if((hbmp=LoadImage(NULL,filename,IMAGE_BITMAP,
		x_size,y_size,LR_CREATEDIBSECTION|LR_LOADFROMFILE))==NULL){
		sprintf(tmp,&quot;%s ファイルが見つかりません&quot;,filename);
		Quit(tmp);
	}
</pre>
<p>まず、最初のLoadImage関数、ここではビットマップファイルをメモリ内に読み込むといった処理をしています。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HANDLE LoadImage( HINSTANCE hinst, LPCTSTR lpszName , UINT uType , int cxDesired , int cyDesired , UINT fuLoad );
</td>
</tr>
<tr>
<th>hinst</th>
<td>イメージが格納されているアプリケーションのインスタンスを認識するハンドル。</p>
<p>そもそもこの関数はリソースと呼ばれる実行ファイル(*.EXE)に含まれるデータから読み込むものなので、関係ないからNULLぢゃ。</td>
</tr>
<tr>
<th>lpszName</th>
<td>ファイル名</td>
</tr>
<tr>
<th>uType</th>
<td>ロードするイメージのタイプを指定するのですが、ビットマップを読み込むのでIMAGE_BITMAPを指定。</td>
</tr>
<tr>
<th>cxDesired</th>
<td>横幅</td>
</tr>
<tr>
<th>cyDesired</th>
<td>縦幅</td>
</tr>
<tr>
<th>fuLoad</th>
<td>ロード用のフラグ。今回は外部ファイルからビットマップを読み込むという事でLR_CREATEDIBSECTION | LR_LOADFROMFILEを指定。</td>
</tr>
<tr>
<th>戻り値</th>
<td>
ロードされたイメージのハンドル
</td>
</tr>
</table>
<pre class="brush: cpp;">
	hdcs=CreateCompatibleDC(NULL);
	hbmpold=SelectObject(hdcs,hbmp);
</pre>
<p>そうしたら、次にhdcs=CreateCompatibleDC(NULL);を実行し、適当なデバイスコンテキストを作成します（戻り値：デバイスコンテキストのハンドル）。<br />
次に、hbmpold=SelectObject(hdcs,hbmp);を実行し、デバイスコンテキストに先ほど読み込んだビットマップを選択させます（戻り値：選択前のオブジェクト）。<br />
これでビットマップが読み込まれているデバイスコンテキストへのハンドルが取得できた事になります。よくわかりませんが、GDIはこういうものです（爆）。<br />
まぁ、細かい事は気にせず、こうすれば良いという事を覚えてしまえばいいでしょう。</p>
<pre class="brush: cpp;">
	sf-&gt;GetDC(&amp;hdcd);
	BitBlt(hdcd,x,y,x_size,y_size,hdcs,0,0,SRCCOPY);
	sf-&gt;ReleaseDC(hdcd);
</pre>
<p>で、第4回で記述したように、サーフェイスへのデバイスコンテキストハンドルを取得し、BitBltというGDI関数を使用してビットマップをサーフェイスに転送します。</p>
<table class="data">
<tr>
<th>書式</th>
<td>BOOL BitBlt( HDC hdcDest, int nXDest , int nYDest , int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop );
</td>
</tr>
<tr>
<th>hdcDest</th>
<td>転送先のデバイスコンテキストのハンドル</td>
</tr>
<tr>
<th>nXDest</th>
<td>転送先の左上X座標</td>
</tr>
<tr>
<th>nYDest</th>
<td>転送先の左上Y座標</td>
</tr>
<tr>
<th>nWidth</th>
<td>画像の横幅</td>
</tr>
<tr>
<th>nHeight</th>
<td>画像の縦幅</td>
</tr>
<tr>
<th>hdcSrc</th>
<td>転送元のデバイスコンテキストのハンドル</td>
</tr>
<tr>
<th>nXSrc</th>
<td>転送元の左上X座標</td>
</tr>
<tr>
<th>nYSrc</th>
<td>転送元の左上Y座標</td>
</tr>
<tr>
<th>dwRop</th>
<td>転送時のオプションのようなものだが、ここは「そっくりそのまま転送」を意味するSRCCOPYを指定。</td>
</tr>
<tr>
<th>戻り値</th>
<td>成功するとTRUEが返ってくるらしい。</td>
</tr>
</table>
<pre class="brush: cpp;">
	SelectObject(hdcs,hbmpold);
	DeleteDC(hdcs);
	DeleteObject(hbmp);
</pre>
<p>最後に、後始末です。最初にSelectObject(hdcs,hbmpold);としていますが、これはhdcsに変更前のオブジェクトを選択していると言う事です（謎）。そうしたら<br />
DeleteDCで適当に作成したデバイスコンテキストを消去し、DeleteObjectで、メモリ内に読み込んであるビットマップを消去しています。</p>
<p>だー、もうGDIはよーわからん（＾＾；こんなんだからMS-DOSからWindowsになかなか移行できんプログラマが多いのだよ・・・。<br />
今回は（も？）カット&#038;ペーストでそのまま使用してください（逝）。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990816124831.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第6回　パレットを作成する</title>
		<link>http://takabosoft.com/19990813124348.html</link>
		<comments>http://takabosoft.com/19990813124348.html#comments</comments>
		<pubDate>Fri, 13 Aug 1999 03:43:48 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/19990813124348.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、
お持ちの方はVisual C++でプロジェクトファイルを開いてください [...]]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<a href='http://takabosoft.com/wp-content/uploads/1999/08/ddraw_06.lzh'><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、<br />
お持ちの方はVisual C++でプロジェクトファイルを開いてください（「ddraw_06.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_06.exe」をダブルクリックし、実行してみてください。<br />
どうでしょう？画面が切り替わり、フルスクリーン化し、「フロントバッファ」と「バックバッファ」がカラフルに交互に表示されると思います（謎。<br />
今回は、パレットを作成したいと思います。</p>
<h3>パレット作成</h3>
<p>まず初めに、StartDirectDraw自作関数内へパレットオブジェクト作成部分を追加します<br />
（ディスプレイの色数が256色以下になっている時にだけ、パレットを使用する事が出来ます）。</p>
<pre class="brush: cpp;">
	//パレットの作成
	if(lpDD-&gt;CreatePalette(DDPCAPS_8BIT,peEntry,&amp;lpPalette,NULL)!=DD_OK)
		return FALSE;
	lpFront-&gt;SetPalette(lpPalette);
</pre>
<p>まず、DirectDrawオブジェクト（lpDD）のメンバである「CreatePalette」関数を呼び出します。構文は以下の通りです。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT CreatePalette( DWORD dwFlags, LPPALETTEENTRY lpColorTable, LPDIRECTDRAWPALETTE FAR *lplpDDPalette, IUnknown FAR *pUnkOuter );</p>
</td>
</tr>
<tr>
<th>dwFlags</th>
<td>このフラグでは、作成したいパレットの種類（2,4,16,256色）をマクロで指定するらしいのですが、私は256しか使用したことがないので（というかこれが最適）DDPCAPS_8BITを指定します。</td>
</tr>
<tr>
<th>lpColorTable</th>
<td>このDirectDrawPaletteオブジェクトを初期化するための2、4、16、256色分のPALETTEENTRY型配列へのポインタ。今回はあらかじめ定義しておいたPALETTEENTRY peEntry[256];のポインタを引き渡します。</td>
</tr>
<tr>
<th>lplpDDPalette</th>
<td>作成するDirectDrawPaletteオブジェクトの格納先をアドレスで指定するらしい。今回は、あらかじめ定義しておいたLPDIRECTDRAWPALETTE lpPaletteのアドレスを引き渡します。</td>
</tr>
<tr>
<th>pUnkOuter</th>
<td>将来拡張した時使用するらしいので、NULLを指定。</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功した場合はDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>そうしたら、次にサーフェイスのメンバ「SetPalette」関数を呼び出し、フロントバッファに作成したパレットを関連付けます。</p>
<h3>色の設定</h3>
<p>さて、パレットを256個作成したら、その中に色を設定してやります。考え方としては、美術で256個の皿（部屋？）のあるパレットの中に、絵の具で色を作成するが、何故か絵の具が赤、緑、青の3つしか無く、その3つの絵の具の量を調整して様々な色を作成するというもの（わけわからん）。</p>
<p>まぁ、とりあえずコードを見てみますか。</p>
<pre class="brush: cpp;">
PALETTEENTRY peEntry[256];			//パレット情報

略

//----------[ パレット情報設定 ]----------------------------------------------------------------
void SetPaletteColor(unsigned char no,unsigned char r,unsigned char g,unsigned char b){
	if(no&lt;0 || no&gt;255)
		return;
	peEntry[no].peRed=r;
	peEntry[no].peGreen=g;
	peEntry[no].peBlue=b;
	peEntry[no].peFlags=1;

	lpPalette-&gt;SetEntries(0,no,1,&amp;peEntry[no]);
}

略

	//パレット設定
	SetPaletteColor(1,26,70,255);
	SetPaletteColor(2,255,255,0);
</pre>
<p>自作関数SetPaletteColorでは、256個のパレットの内、no番目の色を「赤」、「緑」、「青」によって設定します。</p>
<p>ここではPALETTEENTRY構造体を使用します。この構造体のメンバ「BYTE peRed」(BYTE = unsigned char)、「BYTE peGreen」、「BYTE peBlue」<br />
にそれぞれ「赤」、「緑」、「青」の量を0～255の間で指定します（peFlagsメンバは1固定）。例えば、「赤」、「緑」、「青」を255,0,255にすると、赤と青が混ざった紫、127,127,127にすると、灰色というような感じです。</p>
<p>そうしたら、前に作成したDirectDrawPaletteオブジェクト「lpPalette」のメンバ<br />
であるSetEntriesという関数を呼び出して、パレットの色を変更します。SetEntriesの構文は以下の通りです。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT SetEntries( DWORD dwFlags, DWORD dwStartingEntry, DWORD dwCount, LPPALETTEENTRY lpEntries );
</td>
</tr>
<tr>
<th>dwFlags</th>
<td>このフラグは現在使用していないらしいので0を指定しなければいけないらしい。</td>
</tr>
<tr>
<th>dwStartingEntry</th>
<td>何番のパレットから設定するか（変更開始パレット番号）。</td>
</tr>
<tr>
<th>dwCount</th>
<td>変更したいパレット数</td>
</tr>
<tr>
<th>lpEntries</th>
<td>パレットエントリ（PALETTEENTRY構造体）へのポインタ</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功した場合はDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>この関数は、今回作成した自作関数のように1個1個パレットを設定するのでは無く、複数一気に変更出来るように<br />
設計されています。ですから、peEntry[0]～peEntry[255]を全て変更し、lpPalette->SetEntries(0,0,256,peEntry);とでもすれば、全部一括してパレットを変更できます。</p>
<p>ただ、DirectDrawの特性上（？）0番（黒固定）と255番（白固定）のパレットは変更不可能になっています。<br />
まぁ、白と黒は99%ゲームで使うと思うので変更出来ないからと言って気にはならないでしょう。</p>
<h3>設定した色をGDI（テキスト）で使用してみる</h3>
<p>今回は、自作関数DdTextOutを改造して、色を指定できるようにします。</p>
<pre class="brush: cpp;">
//----------[ GDI関数を使用してテキストの出力 ]----------------------------------------------
void DdTextOut(LPDIRECTDRAWSURFACE sf,int x,int y,char *str,unsigned char col){
	HDC hdc;
	sf-&gt;GetDC(&amp;hdc);
	SetBkMode(hdc,TRANSPARENT);
	SetTextColor(hdc,RGB(peEntry[col].peRed,peEntry[col].peGreen,peEntry[col].peBlue));
	TextOut(hdc,x,y,str,strlen(str));
	sf-&gt;ReleaseDC(hdc);
}

略

	DdTextOut(lpFront,0,0,&quot;フロントバッファ&quot;,1);
	DdTextOut(lpBack ,0,0,&quot;バックバッファ&quot;  ,2);
</pre>
<p>まず、最初に付け加えたのがSetBkMode(hdc,TRANSPARENT);です。これは文字の背景を透明にするというもの。第5回までは、字の色が黒、背景が白という状態だったので<br />
変な風に表示されていましたが、今回は背景を表示しないようにします。</p>
<p>次にSetTextColorという関数を呼び出しています。ここで色を設定しています。GDIで色を指定する場合はRGB値（COLORREF型）という1つの数値を用いるのですが<br />
、なんやよーわからんのでマクロ「RGB(赤,緑,青）」という便利なものを使用してRGB値を指定します。RGB(255,0,255)とすれば紫のRGB値という感じです。で、GDIでDirectDrawPaletteの色をそのまま色番号で指定する事は出来ないので<br />
前に設定したpeEntry構造体のメンバ値を使用してRGB値を設定しています。</p>
<h3>パレット後始末</h3>
<p>アプリケーション終了時には作成したDirectDrawPaletteオブジェクト（lpPalette）を解放しなければなりません。ですから自作関数EndDirectDrawの中に<br />
「lpPalette->Release();」を追加する必要があります。まぁ、今まで通りマクロを使用する場合は「RELEASE(lpPalette);」ですが。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990813124348.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第5回　バックバッファを作成してページフリップを行う</title>
		<link>http://takabosoft.com/19990810123759.html</link>
		<comments>http://takabosoft.com/19990810123759.html#comments</comments>
		<pubDate>Tue, 10 Aug 1999 03:37:59 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/19990810123759.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、
お持ちの方はVisual C++でプロジェクトファイルを開いてください [...]]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<a href='http://takabosoft.com/wp-content/uploads/1999/08/ddraw_05.lzh'><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、<br />
お持ちの方はVisual C++でプロジェクトファイルを開いてください（「ddraw_05.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_05.exe」をダブルクリックし、実行してみてください。<br />
どうでしょう？画面が切り替わり、フルスクリーン化し、「フロントバッファ」と「バックバッファ」が交互に表示されると思います。<br />
今回は、バックバッファ（複合サーフェイス）を作成し、ページフリップを行いたいと思います。</p>
<h3>バックバッファ作成</h3>
<p>バックバッファを作成するには、プライマリサーフェイスを<b>複合プライマリサーフェイス</b>として作成します。複合プライマリサーフェイスとして作成すると<br />
、プライマリサーフェイス以外に、指定した数のサーフェイス（バックバッファ）が自動作成されます。<br />
その後、バックバッファ（サーフェイス）の情報を取得すれば、<br />
バックバッファへ描画する事ができます。</p>
<p>では、まず複合プライマリサーフェイスを作成します。</p>
<pre class="brush: cpp;">
	//複合プライマリサーフェイスの作成
	ZeroMemory(&amp;ddsd,sizeof(ddsd));
	ddsd.dwSize=sizeof(ddsd);
	ddsd.dwFlags=DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
	ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
	ddsd.dwBackBufferCount=1;

	if(lpDD-&gt;CreateSurface(&amp;ddsd,&amp;lpFront,NULL)!=DD_OK)
		return FALSE;
</pre>
<p>第3回でも記述した通り、サーフェイスを作成するにはDDSURFACEDESC構造体のdwFlagに使用するメンバを指定します。<br />
プライマリサーフェイスだけなら、DDSD_CAPSだけでも良いのですが、今回は複合プライマリサーフェイスとしてバックバッファも作成するので<br />
DDSD_BACKBUFFERCOUNTも同時に指定します。そうしたらdwBackBufferCountに1を指定します。<br />
ここは作成するバックバッファの数を指定するのですが、今回は1つだけ作成します。<br />
バックバッファは複数あると、管理しにくくなるという私の独断です（゜゜）☆O(--;)oばこ</p>
<p>さて、ddsCaps.dwCapsは3つ指定しています。DDSCAPS_PRIMARYSURFACEは、作成するサーフェイスがプライマリサーフェイスである事、DDSCAPS_FLIPは、フリッピングを行えるサーフェイスである事、DDSCAPS_COMPLEXは複合サーフェイスである事をそれぞれ表します。<br />
というか、ここらは応用のしようが無いので丸暗記で結構です。</p>
<p>この後、lpDD->CreateSurface(&#038;ddsd,&#038;lpFront,NULL);を実行すると、同時にフロントバッファ、バックバッファを作成し、lpFrontにはフロントバッファ（兼プライマリサーフェイス）が格納されます。<br />
で、これだけではバックバッファへ描画できないので、次にバックバッファを取得します。</p>
<pre class="brush: cpp;">
	ddscaps.dwCaps=DDSCAPS_BACKBUFFER;
	if(lpFront-&gt;GetAttachedSurface(&amp;ddscaps,&amp;lpBack)!=DD_OK)
		return FALSE;
</pre>
<p>GetAttachedSurfaceを使用すると、DDSCAPS構造体のメンバdwCapsへ指定した能力を持つサーフェイスを取得する事が出来ます。<br />
ですから、この関数を使用して、さきほど作成したバックバッファを取得します。ちなみに構文は以下の通りです。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT GetAttachedSurface( LPDDSCAPS lpDDSCaps, LPDIRECTDRAWSURFACE FAR *lplpDDAttachedSurface );
</td>
</tr>
<tr>
<th>lpDDSCaps</th>
<td>取得したいサーフェイス情報を詰め込んだDDSCAPS構造体へのポインタ。<br />
今回はddscapsのアドレスを引き渡しています。</td>
</tr>
<tr>
<th>lplpDDAttachedSurface</th>
<td>取得したサーフェイスを格納する変数へのポインタ。<br />
今回はlpBackのアドレスを引き渡す。</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功した場合はDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>これで、lpBackにサーフェイスを取得出来ました。また、このサーフェイスは、プライマリサーフェイス等と同じような扱いが出来ます。<br />
ですから、GDIを使用して描画すると言った事も、なんなく出来ます。</p>
<h3>フリッピング</h3>
<p>では、コードを見てみましょう。</p>
<pre class="brush: cpp;">
void Flip(void){
	lpFront-&gt;Flip(NULL,DDFLIP_WAIT);
}
</pre>
<p>フリップを行うと、フロントバッファとバックバッファに描かれている内容がそっくりそのまま入れ替わります。<br />
ですから、バックバッファにいろいろ書き込んでおき、フリップを行うと、フロントバッファとバックバッファの内容が入れ替わるので書き込んだ内容が画面に瞬時に表示されます。<br />
んで、もう一度フリップすると、また入れ替わり、元の状態に戻ります。では、Flipの構文を見てみましょう。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT Flip( LPDIRECTDRAWSURFACE3 lpDDSurfaceTargetOverride, DWORD dwFlags );
</td>
</tr>
<tr>
<th>lpDDSurfaceTargetOverride</th>
<td>サーフェイスを示すポインタです。ここは次の順番のバックバッファ以外のバッファにフリップする時に使用するらしいのですが、普段はNULLを指定して順番通りにフリップさせます。</td>
</tr>
<tr>
<th>dwFlags</th>
<td>フリップオプションを指定するフラグです。ここはDDFLIP_WAIT固定と考えて良いでしょう。これは、何らかの原因によって直ぐにフリップ出来ない場合に、フリップ出来るまで待つという指定です。
</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功した場合はDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>このFlipは、複合サーフェイス（フロントバッファ）のメンバとしてのみ呼び出すことが出来ます。<br />
ですからlpBack->Flip・・・と呼び出すことは出来ません。</p>
<p>フリップは、垂直帰線中（走査線が右下から左上に戻る間）に瞬時に行われるため、ちらつく事がありません。<br />
ちなみに、垂直帰線を<b>待ってから</b>フリップを行うという事なので、ディスプレイの構造上、フリップは秒間60回程度行うのが限界です。</p>
<h3>後始末について</h3>
<p>後始末は、今まで通りです。なんとなく「lpBack->Release();」とやりたくなる人もいるかもしれませんが、必要ありません。<br />
というかコレ実行するとフリーズするので良い子はマネしないでね（謎。<br />
バックバッファは複合サーフェイスとしてフロントバッファと同時に作成されたため、フロントバッファさえ解放してしまえば同時にバックバッファも解放される事になります（たぶん）。</p>
<h3>疑似タイマー処理</h3>
<p>さて、今回のサンプルプログラムはどうでしょう？1秒間隔でフリップを実行していると思います。<br />
普段、このようなタイマー処理は、APIを使用して一定時間毎にある関数を呼び出すように設定します。<br />
ですが、これが結構面倒なので、今回は擬似的な処理をしてます。<br />
まず、ビルド → 設定 → リンク → オブジェクト/ライブラリモジュールに「winmm.lib」を書き込む → OK をします。<br />
そして、プログラムの最初のほうで「mmsystem.h」をインクルードします。これでマルチメディア系のAPIが使用できるようになります。<br />
その中にはtimeGetTime();という関数が用意されており、これを呼び出した時点での時間がミリ秒単位で取得出来ます（1000ミリ秒=1秒）。<br />
ですから、メッセージループ周辺を改造して、</p>
<pre class="brush: cpp;">
	DWORD tim;
	while(1){
		//疑似タイマー処理
		tim=timeGetTime();			//①
		//フリッピング
		Flip();
		do{
			//メッセージループ
			while(PeekMessage(&amp;msg,NULL,0,0,PM_NOREMOVE)){
				if(!GetMessage(&amp;msg,NULL,0,0))
					Quit();
				TranslateMessage(&amp;msg);
				DispatchMessage(&amp;msg);
			}

		}while(timeGetTime()&lt;tim+1000);	//②
	}
</pre>
<p>とします。こうすると、1番で取得した時間から1000ミリ秒経つまで、ひたすらメッセージループを回す事になります。<br />
ちなみに、こういう一定時間で処理する場合にメッセージループを忘れてしまうと、キー処理がなされなくなり、終了出来ない→電源強制切断という最悪の事態を招くことになります（逝。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990810123759.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第4回　サーフェイスにGDI関数を使用して描画</title>
		<link>http://takabosoft.com/19990808120627.html</link>
		<comments>http://takabosoft.com/19990808120627.html#comments</comments>
		<pubDate>Sun, 08 Aug 1999 03:06:27 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/19990808120627.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしているので、
お持ちの方はVisual C++でプロジェクトファイルを開いてください [...]]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<a href='http://takabosoft.com/wp-content/uploads/1999/08/ddraw_04.lzh'><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、<br />
お持ちの方はVisual C++でプロジェクトファイルを開いてください（「ddraw_04.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_04.exe」をダブルクリックし、実行してみてください。<br />
どうでしょう？画面が切り替わり、フルスクリーン化し、『GDIによるテキストの表示』という文字列が表示されると思います。<br />
今回は、サーフェイスにGDI関数を使用して描画をします。</p>
<h3>GDI概要</h3>
<p>GDIとはGraphic Device Interfaceの略であり、ウィンドウプログラミングには欠かせないグラフィックライブラリです。<br />
第1回でも記述しましたが、DirectDrawの関数には文字や線、円などの描画関数が用意されていません。その場合、GDIを使用してサーフェイスに描画する事になります。<br />
ただ、GDIの描画速度はあまり速くないので、速度重視ゲームの場合、多用は控えた方が良いでしょう。</p>
<h3>デバイスコンテキストハンドルの作成、解放</h3>
<p>今回は、テキストを出力する部分を『DdTextOut』関数にまとめました。さぁコードを見てみましょう。</p>
<pre class="brush: cpp;">
//----------[ GDI関数を使用してテキストの出力 ]----------------------------------------------
void DdTextOut(LPDIRECTDRAWSURFACE sf,int x,int y,char *str){
	HDC hdc;
	sf-&gt;GetDC(&amp;hdc);
	TextOut(hdc,x,y,str,strlen(str));
	sf-&gt;ReleaseDC(hdc);
}

略

//関数の呼び出し
DdTextOut(lpFront,0,0,&quot;GDIによるテキストの表示&quot;);
</pre>
<p>GDIで描画するためには、デバイスコンテキストを認識するハンドルというものを取得しなければなりません。<br />
デバイスコンテキストを認識するハンドルとは、描画可能なメモリのパスを収納しておくような感じのもので、GDI関数呼び出し時によく引数として使用します。<br />
では、ハンドルの取得方法を説明します。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT GetDC( HDC FAR *lphDC );
</td>
</tr>
<tr>
<th>lphDC</th>
<td>
デバイス コンテキストが返されるハンドルへのポインタ。
</td>
</tr>
<tr>
<th>戻り値</th>
<td>
DirectDrawオブジェクトの作成に成功するとDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<p>「lpFront->GetDC(&#038;hdc);」のように、途中「->」を記述しています。これらはC++で使われるクラスというものですが、ここでは解説省略。クラスについては他のHPを参照してください。</p>
<p>こうして、GetDCを実行すると、そのサーフェイス（今回はプライマリサーフェイス）のデバイスコンテキストを認識するハンドルを取得出来ます。</p>
<p>では、次にGDI関数の『TextOut』について説明します。</p>
<table class="data">
<tr>
<th>書式</th>
<td>BOOL TextOut( HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cbString );
</td>
</tr>
<tr>
<th>hdc</th>
<td>デバイスコンテキストを認識するハンドル<br />
今回は「hdc」を引き渡す。</td>
</tr>
<tr>
<th>nXStart</th>
<td>描画先のX座標</td>
</tr>
<tr>
<th>nYStart</th>
<td>描画先のY座標</td>
</tr>
<tr>
<th>lpString</th>
<td>描画したい文字列</td>
</tr>
<tr>
<th>hdc</th>
<td>文字列のバイト数（文字数とも言うかも）</td>
</tr>
<tr>
<th>戻り値</th>
<td>
成功した場合はTRUEが返ってくるらしい。
</td>
</tr>
</table>
<p>こうして、一通りGDI関数を使用したら、今度はハンドルを解放しなければなりません。<br />
解放には、次の関数（サーフェイスのメンバ関数）を呼び出します。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT ReleaseDC( HDC hDC );
</td>
</tr>
<tr>
<th>hDC</th>
<td>
GetDCを使用して取得したデバイスコンテキストのハンドル。</p>
<p>今回はhdcを引き渡す。GetDCとは違い、ポインタでは無いことに注意しましょう。
</td>
</tr>
<tr>
<th>戻り値</th>
<td>
DirectDrawオブジェクトの作成に成功するとDD_OKが返ってくるらしい。
</td>
</tr>
</table>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990808120627.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第3回　フルスクリーン化</title>
		<link>http://takabosoft.com/19990807091203.html</link>
		<comments>http://takabosoft.com/19990807091203.html#comments</comments>
		<pubDate>Sat, 07 Aug 1999 00:12:03 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/19990807091203.html</guid>
		<description><![CDATA[サンプルコードのダウンロード
では、まずサンプルコードをダウンロードし、解凍してください。
私はVisual C++6.0でコンパイルしていますので、
お持ちの方Visual C++でプロジェクトファイルを開いてください [...]]]></description>
			<content:encoded><![CDATA[<h3>サンプルコードのダウンロード</h3>
<p>では、まず<b><a href='http://takabosoft.com/wp-content/uploads/1999/08/ddraw_03.lzh'>サンプルコード</a></b>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしていますので、<br />
お持ちの方Visual C++でプロジェクトファイルを開いてください<br />
（「ddraw_03.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「ddraw_03.exe」をダブルクリックし、実行してみてください。<br />
どうでしょう？画面が切り替わり、フルスクリーン化すると思います<br />
（何かキーを押すと終了します）。<br />
今回は、DirectDrawを使用した画面のフルスクリーン化について解説したいと思います。  </p>
<h3>Windowsプログラミング基礎</h3>
<p>いくらDirectDrawを使うとは言え、結局はWindows上で動作しています。<br />
ですから多少Windowsプログラミングの知識が必要になります。<br />
ここでは、「ウィンドウ作成」と「ウィンドウメッセージ」について適当に説明します。 </p>
<pre class="brush: cpp;">
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow){
	WNDCLASS wc;
	MSG msg;
	if(!hPrevInstance){
		wc.lpszClassName=&quot;dd&quot;;
		wc.lpfnWndProc=WndProc;
		wc.style=CS_HREDRAW | CS_VREDRAW;
		wc.hInstance=hInstance;
		wc.hIcon=NULL;
		wc.hCursor=NULL;
		wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
		wc.lpszMenuName=NULL;
		wc.cbClsExtra=0;
		wc.cbWndExtra=0;
		if(!RegisterClass(&amp;wc)) return FALSE;
	}

	//ウィンドウ作成
	hw=CreateWindowEx(WS_EX_APPWINDOW,&quot;dd&quot;,&quot;DD簡易講座第3回&quot;, WS_POPUPWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL);

	//ウィンドウの表示
	ShowWindow(hw,nCmdShow);
	UpdateWindow(hw);

	続く
</pre>
<p>UNIX(Linux)やMS-DOSのC言語では、一番始めに実行されるのは「main」関数でした。<br />
ですが、Windowsでは「WinMain」から始まります。<br />
ウィンドウ作成については、あまり考えずに、こうすればとりあえずウィンドウを作成、<br />
表示出来ると覚えてしまった方が良いです。<br />
と言うより、私自身ウィンドウには興味が無いのでよく解りません（゜゜）☆O(--;)oばこ</p>
<p>Windowsには「ウィンドウメッセージ」というものが有り、OSとアプリケーションがコミュニケーションをとるために使用します。<br />
例えば、ユーザーがアプリケーションのウィンドウを動かそうとした場合、OSはアプリケーションに対し、「ウィンドウが動くぞ」みたいな感じのメッセージを送信します。<br />
そしてアプリケーションは、そのメッセージを受信し、なんらかの処理を行うことになります。<br />
ここで、もしもアプリケーションがこのメッセージを無視してしまうと、ウィンドウが動かせないという状況が生まれます。</p>
<p>では、どうやってメッセージを処理するのでしょうか。コードを見てみましょう。</p>
<pre class="brush: cpp;">
	while(1){
		while(PeekMessage(&amp;msg,NULL,0,0,PM_NOREMOVE)){
			if(!GetMessage(&amp;msg,NULL,0,0))
				Quit();
			TranslateMessage(&amp;msg);
			DispatchMessage(&amp;msg);
		}
	}
</pre>
<p>この処理は、一般的にメッセージループと呼ばれ、OSが送ってくるメッセージをひたすら待ち、<br />
メッセージを受信したら、「WndProc」（コールバック）関数が呼ばれるようになっています。</p>
<pre class="brush: cpp;">
//----------[ ウィンドウプロシージャ ]----------------------------------------------------------
HRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam){
	switch(iMessage){

	//キー押された
	case WM_KEYDOWN:
		Quit();
		break;

	省略
</pre>
<p>WndProc関数では、このようにメッセージiMessageをswitchによって分岐させ、<br />
それぞれ処理しています。<br />
例えば、ユーザーが、アプリケーションに対し、<br />
何かキーを押した場合、OSが「キーが押されたぞ」みたいな感じのメッセージを送信し、<br />
アプリケーションは、メッセージループ処理中、このメッセージを受信し、<br />
WndProcを呼び出します。<br />
WndProcでは、「キーが押された」というメッセージは「WM_KEYDOWN」<br />
というように表されます（マクロ）。<br />
この辺はWindows関連のHPに行けば、丁寧に解説されているのでそちらを参照してください。<br />
手抜きすぎかも（゜゜）☆O(--;)oばこ </p>
<h3>DirectDraw初期化</h3>
<p>では、DirectDrawの初期化をします。</p>
<p>サンプルコードを見てみましょう。 </p>
<pre class="brush: cpp;">
#include &lt;ddraw.h&gt;

略

LPDIRECTDRAW lpDD=NULL; 	//DirectDrawオブジェクト
LPDIRECTDRAWSURFACE lpFront=NULL;	//サーフェイス

略

BOOL StartDirectDraw(HWND hw){
	DDSURFACEDESC ddsd;

	//DirectDrawオブジェクト作成
	if(DirectDrawCreate(NULL,&amp;lpDD,NULL)!=DD_OK)
		return FALSE;

	//協調レベル設定
	if(lpDD-&gt;SetCooperativeLevel(hw,DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE)!=DD_OK)
		return FALSE;

	//解像度設定
	if(lpDD-&gt;SetDisplayMode(640,480,8)!=DD_OK)
		return FALSE;

	//プライマリサーフェイスの作成
	ZeroMemory(&amp;ddsd,sizeof(ddsd));
	ddsd.dwSize=sizeof(ddsd);
	ddsd.dwFlags=DDSD_CAPS;
	ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE;

	if(lpDD-&gt;CreateSurface(&amp;ddsd,&amp;lpFront,NULL)!=DD_OK)
		return FALSE;

	return TRUE;
}
</pre>
<p>第2回でも記述しましたが、メニューの「ビルド」　→　「設定」　→　「リンク」タブ　→　オブジェクト／ライブラリモジュールに「ddraw.lib」を書き込む　→　「OK」 、ソースの始めの方で「ddraw.h」をインクルードしてください。<br />
これでDirectDrawの関数が使用可能となります（サンプルのプロジェクトでは、既に設定済みです）。</p>
<p>では、順番に解説していきたいと思います。 </p>
<pre class="brush: cpp;">
	if(DirectDrawCreate(NULL,&amp;lpDD,NULL)!=DD_OK)
		return FALSE;
</pre>
<p>ここでは、DirectDrawオブジェクトを作成します。<br />
とか言ってるけど、DirectDrawオブジェクト言われてもよーわからんて。<br />
とりあえず、DirectDrawを使うために最初に実行しなきゃいけないらしいです。</p>
<p>では、構文を見てみましょう。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT DirectDrawCreate( GUID FAR* lpGUID,LPDIRECTDRAW FAR* lplpDD,IUnknown FAR* pUnkOuter );</td>
</tr>
<tr>
<th>lpGuid</th>
<td>
DirectDrawオブジェクトを作成するディスプレイデバイスのGUIDを指定します。</p>
<p>とか言ってるけど、よくわからん（爆）。どうやら、表示したいディスプレイを変更できるらしいのですが、変更する必要が無いのでNULLにしてまう。
</td>
</tr>
<tr>
<th>lplpDD</th>
<td>
DirectDrawオブジェクトを指すポインタのアドレスを指定します。</p>
<p>ここでは、グローバル変数として定義した「LPDIRECTDRAW lpDD;」のアドレスを引き渡します。</p>
</td>
</tr>
<tr>
<th>pInkOuter</th>
<td>
将来拡張される時に使うらしいので、とりあえずNULL。DirectXの関数にはこういう物が多いが、使う時が来るのか謎。
</td>
</tr>
<tr>
<th>戻り値</th>
<td>
DirectDrawオブジェクトの作成に成功するとDD_OKが返ってくるらしい。
</td>
</tr>
</table>
<pre class="brush: cpp;">
	if(lpDD-&gt;SetCooperativeLevel(hw,DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE)!=DD_OK)
		return FALSE;
</pre>
<p>ここでは、さきほど作成したDirectDrawオブジェクト（lpDD）とやらを使用して<br />
協調レベルを設定しています。<br />
またしてもよくわからん（爆）＜協調。<br />
というか私に言語能力が無いだけかも（死。</p>
<p>どうやら、ウィンドウに対する設定をいろいろと変更できるらしい。</p>
<p>というわけで構文いってみよぅ。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT SetCooperativeLevel( HWND hWnd , DWORD dwFlags );</td>
</tr>
<tr>
<th>hWnd</th>
<td>
アプリケーションのメインウィンドウへのHWNDハンドルを指定します。これはDirectDrawオブジェクトと関連付ける<br />
ウィンドウです。ここでは、ウィンドウ作成時に使用した「hw」を引き渡します。
</td>
</tr>
<tr>
<th>dwFlags</th>
<td>
設定する協調レベルを表すDWORD値を指定します。下に指定できる値の一覧を記述します。これらはビット毎のOR演算子（|）を使って組み合わせて使用します。<br />
ここでは、フルスクリーンに必要な2つの値「DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE」を指定します。
</td>
</tr>
<tr>
<th>戻り値</th>
<td>成功するとDD_OKが返ってくるらしい。</td>
</tr>
</table>
<p>
SetCooperativeLevelに指定できるDWORD値</p>
<table class="data">
<tr>
<th>DDSCL_ALLOWREBOOT</th>
<td>排他的（フルスクリーン）モード時に、CTRL+ALT+DELの機能の許可。</td>
</tr>
<tr>
<th>DDSCL_EXCLUSIVE</th>
<td>排他的レベルの要求。このフラグは、DDSCL_FULLSCREENフラグと共に用いる必要がある。</p>
<p>どうやら、このフラグを使用すると、他のアプリケーションでこのフラグを使用した時に、エラーが発生するようになるらしい。同時に2つ以上のアプリケーションがフルスクリーン化出来なくするためとか。</td>
</tr>
<tr>
<th>DDSCL_FULLSCREEN</th>
<td>フルスクリーン化出来ます。必ずDDSCL_EXCLUSIVEと組み合わせて使用しなければならない。</td>
</tr>
<tr>
<th>DDSCL_NORMAL</th>
<td>アプリケーションが、通常のWindowsアプリケーションとして機能することを表す。このフラグは、DDSCL_ALLOWMODEX、 DDSCL_EXCLUSIVE、またはDDSCL_FULLSCREENフラグと共に用いることはできない。</td>
</tr>
<tr>
<th>DDSCL_NOWINDOWCHANGES</th>
<td>アクティベート時、DirectDrawがアプリケーションウィンドウを最小化したりリストアしたりさせない。</td>
</tr>
</table>
<pre class="brush: cpp;">
	if(lpDD-&gt;SetDisplayMode(640,480,8)!=DD_OK)
		return FALSE;
</pre>
<p>ここでは、DirectDrawオブジェクト（lpDD）を使用して、ディスプレイの解像度、色数を設定します。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT SetDisplayMode( DWORD dwWidth, DWORD dwHeight, DWORD dwBPP );
</td>
</tr>
<tr>
<th>dwWidth</th>
<td>画面解像度の横幅を指定します。</td>
</tr>
<tr>
<th>dwHeight</th>
<td>画面解像度の縦幅を指定します。</td>
</tr>
<tr>
<th>dwBpp</th>
<td>使用したい色数をビット数で指定します。例えば、8を指定すると、256色、16を指定するとHigh Colorとなります。</td>
</tr>
<tr>
<th>戻り値</th>
<td>成功するとDD_OKが返ってくるらしい。</td>
</tr>
</table>
<p>
画面解像度は、適当に指定できるわけではありません。指定できる解像度は、主に640×480、800×600、1024×768と言った一般的な解像度です（謎。色数も8(256色)、16(High Color)、24(True Color)、32(True Color)<br />
です。ゲームでは、主に640×480×8（256色）を使用します。これよりも広かったり色数が多いと、<br />
キャラクターデータを置くビデオメモリが足りなくなったり、画像転送速度に影響したりします。<br />
また、256色モードの時だけは、パレットの変更が出来ます。パレットについては後で説明します。<br />
それから、320×240（MODE X）と言った特別な解像度も指定出来ますが、これはいろいろと面倒なので後で説明しますパート2（ぉ。</p>
<pre class="brush: cpp;">
	ZeroMemory(&amp;ddsd,sizeof(ddsd));
	ddsd.dwSize=sizeof(ddsd);
	ddsd.dwFlags=DDSD_CAPS;
	ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE;

	if(lpDD-&gt;CreateSurface(&amp;ddsd,&amp;lpFront,NULL)!=DD_OK)
		return FALSE;
</pre>
<p>ここでは、プライマリサーフェイスを作成します。サーフェイスとは、ビデオメモリを意味し、実際に描画を行う場所となります。<br />
プライマリサーフェイスは、画面に表示されているビデオメモリを意味します。ですから、ここへなんらかの描画を行った瞬間、画面に<br />
表示される事になります。一般的には、複数作業用のサーフェイス（オフスクリーンサーフェイスと呼ぶ）を作成し、そこへキャラクターイメージを配置し、それらのデータを一度バックバッファと呼ばれるサーフェイスへ転送し、フリッピングという作業をすると、バックバッファとフロントバッファ（この場合プライマリサーフェイスの事）の内容がそっくりそのまま入れ替わり、画面へ表示される事になります。<br />
オフスクリンサーフェイスや、バックバッファを作成する方法は、また後で説明します。ここではとりあえずプライマリサーフェイスだけを作成します。</p>
<p>まず、DDSURFACEDESCという構造体を使用して、作成するサーフェイスの情報をここへ詰め込みます。</p>
<p>DDSURFACEDESC構造体の<b>主な</b>内容は以下の通りです。</p>
<table class="data">
<tr>
<th>dwSize</th>
<td>この構造体のサイズ（バイト数）</td>
</tr>
<tr>
<th>dwFlags</th>
<td>有効なメンバをDWORD値で指定します。どうやら、ここで使用したいメンバを指定し、そのメンバへ値を代入するようです。<br />
指定できるメンバは下の方に記述してあります。</td>
</tr>
<tr>
<th>dwHeight</th>
<td>サーフェイスの縦幅</td>
</tr>
<tr>
<th>dwWidth</th>
<td>サーフェイスの横幅</td>
</tr>
<tr>
<th>lPitch</th>
<td>メモリの水平行間のピクセル数</td>
</tr>
<tr>
<th>dwBackBufferCount</th>
<td>作成するバックバッファの数</td>
</tr>
<tr>
<th>ddsCaps</th>
<td>サーフェイスの機能を指定します。</td>
</tr>
<p></TABLE></p>
<p>dwFlagsで指定できる<b>主な</b>メンバは以下の通りです。これらはビット毎のOR演算子（|）を使って組み合わせて使用します。</p>
<table class="data">
<tr>
<th>DWORD値</th>
<th>対応するメンバ</th>
</tr>
<tr>
<td>DDSD_DDSCAPS</td>
<td>ddsCaps</td>
</tr>
<tr>
<td>DDSD_HEIGHT</td>
<td>dwHeight</td>
</tr>
<tr>
<td>DDSD_WIDTH</td>
<td>dwWidth</td>
</tr>
<tr>
<td>DDSD_BACKBUFFERCOUNT</td>
<td>dwBackBufferCount</td>
</tr>
<p></TABLE></p>
<p>ここでは、プライマリサーフェイスを作成するために、DDSURFACEDESC ddsd構造体を使用し、ddsd.dwFlagsにDDSD_CAPSを指定し、ddsd.ddsCaps.dwCaps（何故かメンバの中にまたメンバ）にDDSCAPS_PRIMARYSURFACEを指定します。ここは、丸暗記ですかね(^^;<br />
そうしたら、次にサーフェイスを実際に作成するためにCreateSurfaceを呼び出します。この構文は以下の通りです。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HRESULT CreateSurface( LPDDSURFACEDESC lpDDSurfaceDesc, LPDIRECTDRAWSURFACE FAR *lplpDDSurface, IUnknown FAR *pUnkOuter );</td>
</tr>
<tr>
<th>lpDDSurfaceDesc</th>
<td>要求されたサーフェスを記述するDDSURFACEDESC構造体のアドレス。</p>
<p>今回は、先ほど設定したddsdのアドレスを引き渡しています。</td>
</tr>
<tr>
<th>lplpDDSurface</th>
<td>呼び出しが成功した場合、有効なDirectDrawSurfaceポインタによって初期化されるサーフェスへのポインタへのポインタ。</p>
<p>ややこしいですが、今回はあらかじめ宣言しておいた「LPDIRECTDRAWSURFACE lpFront;」のアドレスを引き渡しています。</td>
</tr>
<tr>
<th>pUnkOuter</th>
<td>将来拡張される時に使うらしいので、とりあえずNULL。</td>
</tr>
<tr>
<th>戻り値</th>
<td>成功するとDD_OKが返ってくるらしい。</td>
</tr>
</table>
<h3>DirectDraw後始末</h3>
<p>コードを見てみましょう。</p>
<pre class="brush: cpp;">
#define RELEASE(i) if(i){i-&gt;Release();i=NULL;}
BOOL EndDirectDraw(void){
	RELEASE(lpFront);
	RELEASE(lpDD);
	return TRUE;
}
</pre>
<p>サーフェイスや、DirectDrawオブジェクトはRelease();を実行すると終了する事が出来ます。<br />
例えば、プライマリサーフェイスなら「lpFront->Release();」となります。<br />
ここは、マクロ（define）を使用すると、簡潔に記述する事が出来ます。<br />
プログラムを終了したい場合は、必ずこれらを実行しなければなりません。これを忘れてしまうと、Windowsに戻ったとき、パソコンが正常に動作しない可能性があります。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990807091203.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第2回　DirectDraw導入</title>
		<link>http://takabosoft.com/19990806230805.html</link>
		<comments>http://takabosoft.com/19990806230805.html#comments</comments>
		<pubDate>Fri, 06 Aug 1999 14:08:05 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/?p=17</guid>
		<description><![CDATA[DirectXのSDK入手
さて、DirectXを使用したソフトウェアを作成するためには、DirectX SDKと言うものが必要になります。これは、DirectXを処理するためのライブラリ群であり、インクルードファイルや [...]]]></description>
			<content:encoded><![CDATA[<h3>DirectXのSDK入手</h3>
<p>さて、DirectXを使用したソフトウェアを作成するためには、DirectX SDKと言うものが必要になります。これは、DirectXを処理するためのライブラリ群であり、インクルードファイルや、ライブラリファイルが含まれています。ちなみに、Visual C++4.x以降のバージョンでは、既にDirectX2（未確認）辺りのSDKがあらかじめ含まれているため、「Visual C++6.0の設定」へ飛んで下さい。</p>
<p>一体DirectX SDKは何処で入手出来るのでしょうか。一応、MicrosoftのDirectX開発者ページにて、配布していますが、最近はファイルサイズが膨大になったため（100M以上）、そこからダウンロードするのは、あまり現実的ではありません。<br />
<span style="color: #999999;">（2004/05/30追記：いやほら、書いた当時はダイアルアップだったの。現在はブロードバンドの時代ですから、200MぐらいサクッとDLしましょう） </span></p>
<p>一番手っ取り早い方法は、SDKの入った雑誌を買ってくる事です。メジャーなトコロでCマガジンでしょうか。それか、DirectX入門系の本を購入し、こんなHPチマチマ見てないで自分で勉強する事です（爆）。</p>
<h3>DirectX SDKのインストール</h3>
<p>DirectX SDKを自分のコンピュータにインストールしたら、VC側にDirectX SDKの「有りか」を教えてあげる必要があります。</p>
<p>まず、VCのメニュ→ツール→オプションを実行し、その中の「ディレクトリ」タブを選びます。<br />
<a href="http://takabosoft.com/wp-content/uploads/1999/08/setup05.gif"><img class="alignnone size-full wp-image-22" title="setup05" src="http://takabosoft.com/wp-content/uploads/1999/08/setup05.gif" alt="setup05" width="483" height="299" /></a></p>
<p>「表示するディレクトリ」を「インクルードファイル」にし、「新規作成」ボタン（画像の赤丸）を押し、そこへインストールしたDirectX SDKのinlcludeフォルダを指定してやります。<br />
同様に、「表示するディレクトリ」を「ライブラリファイル」にし「新規作成」ボタンを押して、そこへインストールしたDirectX SDKのlibフォルダを指定してやります。</p>
<p>この設定は一度行えばOKです。</p>
<h3>DirectX SDKを使ったアプリケーションを新規作成する手順</h3>
<p>Visual C++6.0の環境で、DirectXを使用するアプリケーションを新規作成するには、以下の手順が必要です。</p>
<p>1.メインメニュー → 「新規作成」 を選び、下のように設定し、OKをクリックします。<br />
<a href="http://takabosoft.com/wp-content/uploads/1999/08/setup00.gif"><img class="alignnone size-full wp-image-23" title="setup00" src="http://takabosoft.com/wp-content/uploads/1999/08/setup00.gif" alt="setup00" width="560" height="322" /></a></p>
<p>2.本当はどれでも良いのですが、とりあえずそのまま「終了」をクリックします。<br />
<a href="http://takabosoft.com/wp-content/uploads/1999/08/setup01.gif"><img class="alignnone size-full wp-image-24" title="setup01" src="http://takabosoft.com/wp-content/uploads/1999/08/setup01.gif" alt="setup01" width="536" height="357" /></a></p>
<p>3.単なる確認画面が出ますので、そのままOKをクリックします。<br />
<a href="http://takabosoft.com/wp-content/uploads/1999/08/setup02.gif"><img class="alignnone size-full wp-image-25" title="setup02" src="http://takabosoft.com/wp-content/uploads/1999/08/setup02.gif" alt="setup02" width="482" height="393" /></a></p>
<p>4.もう一度 メインメニュー → 「新規作成」 を選び、下のように設定し、OKをクリックします。<br />
<a href="http://takabosoft.com/wp-content/uploads/1999/08/setup03.gif"><img class="alignnone size-full wp-image-26" title="setup03" src="http://takabosoft.com/wp-content/uploads/1999/08/setup03.gif" alt="setup03" width="560" height="322" /></a></p>
<p>ここへプログラムをタラタラ書くことになります。<br />
普通はCPPファイルを複数作成するのですが、この講座では見やすくするために、基本的には1ファイルで進めていきます。</p>
<p>5.メインメニュー → 「プロジェクト」→ 「設定」 を選び、「リンク」タブをクリックします。<br />
<a href="http://takabosoft.com/wp-content/uploads/1999/08/setup04.gif"><img class="alignnone size-full wp-image-27" title="setup04" src="http://takabosoft.com/wp-content/uploads/1999/08/setup04.gif" alt="setup04" width="560" height="312" /></a></p>
<p>設定の対象を「すべての構成」にします。<br />
オブジェクト／ライブラリモジュールへ、「ddraw.lib」を書き加えます。</p>
<p>これで設定は終わりです。<br />
ちなみに、この講座で配布しているサンプルコードは、こうした設定を既にやってあります。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990806230805.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第1回　DirectDraw概要</title>
		<link>http://takabosoft.com/19990805225316.html</link>
		<comments>http://takabosoft.com/19990805225316.html#comments</comments>
		<pubDate>Thu, 05 Aug 1999 13:53:16 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　DirectDraw基礎編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/?p=10</guid>
		<description><![CDATA[はじめに
さぁ、始まりました第1回DirectDraw講座！DirectXで描画を担当するのがDirectDrawです。最近オンラインゲームで起動時に画面がフルクリーンに切り替わるものが増えてきましたが、これらは全部Di [...]]]></description>
			<content:encoded><![CDATA[<h3>はじめに</h3>
<p>さぁ、始まりました第1回DirectDraw講座！DirectXで描画を担当するのがDirectDrawです。最近オンラインゲームで起動時に画面がフルクリーンに切り替わるものが増えてきましたが、これらは全部DirectDrawを使用していると考えて結構です。とりあえず私が今まで制作してきたゲーム並の事は出来ると言うことで、それ以上の事は出来ません（謎。今までGDIやらWinGやらで地味なゲームを作っていたあなた！たまにはDirectX使ってド派手なゲーム作りましょう！みたいな。</p>
<h3>DirectDrawの長所</h3>
<p>DirectDrawが今までのGDIやWinGと異なる点は、ハードウェアを使用するという点です。フルスクリーン化して色数を256色なんかにすれば、画面に表示するために必要なビデオメモリは640×480で300K程度です。現在世界で普及しているビデオメモリは最低でも2Mはあるので、残りの1．7Mに必要な画像を読み込んでおき、後はビデオメモリ間のハードウェア転送機能を使用して高速に描画すれば、派手なゲームもたぶん、作れます。まぁ、描画がいくら速くても、その他の部分でプログラム出来なければ、お話になりませんが・・・。とりあえず、DirectDrawでは、透過色付きの転送も出来ます。GDIのようにマスクイメージを用意してBitBltでAND、XORする必要もありません（WinGの場合は関係ないですけど）。DirectDrawでやる事といえば、長方形領域の転送くらいなものです。 </p>
<h3>DirectDrawの短所</h3>
<p>DirectDrawではハードウェアが対応していない場合、ソフトウェアでエミュレートします。DirectDrawで、拡大、縮小付きの長方形領域転送があるのですが、現在対応しているビデオカードが少なく、めっちゃ描画遅いです。GDIのStretchBltとやらよりも遅いです（爆。また、ビデオメモリに直接アクセスする事も出来るのですが、そのデータ転送速度が遅すぎます。使わない方が良いです。それから、DirectDrawには円や線、文字と言った描画関数は用意されていません。その代わり、デバイスコンテキストとやらを取得出来るので、これを使用してGDIで描画します。 </p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/19990805225316.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

