<?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ゲーム作成講座　演出・エフェクト編」｜TAKABO SOFT</title>
	<atom:link href="http://takabosoft.com/category/directx-effect/feed" rel="self" type="application/rss+xml" />
	<link>http://takabosoft.com</link>
	<description>ドット絵エディタ「EDGE2」、MIDI音楽編集ソフト「Domino」、楽曲などを配布している個人サイトです。</description>
	<lastBuildDate>Wed, 04 Apr 2012 14:30:01 +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>第8回　画像を溶かす</title>
		<link>http://takabosoft.com/20001010171551.html</link>
		<comments>http://takabosoft.com/20001010171551.html#comments</comments>
		<pubDate>Tue, 10 Oct 2000 08:15:51 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　演出・エフェクト編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/20001010171551.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/10/effec_08.lzh"><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（「effec_08.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「effec_08.exe」をダブルクリックし、実行してみてください（何かキーを押すと終了します）。<br />
どうでしょう？画面が切り替わり、Takabo Softの文字が徐々にデロ～ンと熔けて（？）いくと思います。</p>
<p>というわけで、今回は画像を溶かすような処理について説明していきたいと思います。</p>
<h3>早速サンプルコードの解説</h3>
<p>というわけで、今回も順番に説明していきまーす。</p>
<pre class="brush: cpp;">
//----------[ メイン関数 ]----------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow){

	略

	//DirectDraw開始
	StartDirectDraw(hw);

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

	//ビットマップを作業用サーフェイスへ読み込む
	LoadBitmap(lpWork,&quot;takabo.bmp&quot;,0,0,548,90);//46,195
</pre>
<p>んで、まずメインループ内で使用するデータを初期化します。</p>
<pre class="brush: cpp;">
	int i;
	//画像の高さが90だから90個分用意する
	float dy[90],dy_add[90];
	int dy_count[90];

	//準備
	for(i=0;i&lt;90;i++){
		dy[i]=i+195.f;	//画面中央にくるように補正しておく
		dy_add[i]=0.f;
		dy_count[i]=(89-i)*3+60*2;
	}
</pre>
<p>今回は、画像の横一列（548 x 1)につき1つのデータを作成し、高さが90あるので、90個分のデータを<br />
作成します。「dy」はy座標、「dy_add」は（y座標の）毎ループ毎の増加量、「dy_count」は<br />
処理を開始するまでの残りカウントです。</p>
<pre class="brush: cpp;">

	int y;
	DWORD tim;
	while(1){

		tim=timeGetTime();		//疑似タイマー処理
		ClearScreen(lpBack);	//バックバッファクリア

		//座標更新
		for(i=0;i&lt;&lt;90;i++){
			if(dy_count[i]==0){
				dy_add[i]+=0.02f;	//加速
				dy[i]+=dy_add[i];
			} else
				dy_count[i]--;
		}
</pre>
<p>ここ（↑）でまずデータの座標を更新します。</p>
<p>dy_addに適当な定数を加えていくことで「重力」っぽい処理が再現できます。</p>
<p>（ゲーム制作基礎でもやりましたね）</p>
<pre class="brush: cpp;">
		//表示
		for(i=0;i&lt;90;i++){
			//一番下の画像は普通に表示
			if(i==89){
				y=(int)dy[i];
				if(y&lt;480)
					Blt(lpBack,46,y,548,1,lpWork,0,i,FALSE);
			}
			//それ以外は、一つ下の画像の座標まで補間（謎
			else {
				for(y=(int)dy[i];y&lt;(int)dy[i+1];y++)
					if(y&lt;480)
						Blt(lpBack,46,y,548,1,lpWork,0,i,FALSE);
			}
		}
</pre>
<p>データの座標を更新し終えたら次は表示です。</p>
<p>そのまま「dy」の示す座標に画像を貼り付けていくと、「穴」が空きます。</p>
<p>ですから、その穴を埋めるようにfor文とかで間を補ってやります。</p>
<pre class="brush: cpp;">
		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+16);	//1000/60=16.666（60FPS）
	}

	return(FALSE);
}
</pre>
<p>前回に比べれば簡単ですね（＾＾；</p>
<p>あんまり「熔ける」という感じでは無いですが（爆</p>
<p>これを更に1ドットずつに区切って処理すればもっと本物っぽくなるかなぁ？</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/20001010171551.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第7回　画像を粉々にする</title>
		<link>http://takabosoft.com/20001002171121.html</link>
		<comments>http://takabosoft.com/20001002171121.html#comments</comments>
		<pubDate>Mon, 02 Oct 2000 08:11:21 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　演出・エフェクト編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/20001002171121.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/10/effec_07.lzh"><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（「effec_07.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「effec_07.exe」をダブルクリックし、実行してみてください（何かキーを押すと終了します）。<br />
どうでしょう？画面が切り替わり、Takabo Soft Networkのロゴが左から徐々に粉々になり落ちていくと思います。</p>
<p>というわけで、今回は徐々に画像を粉々にする方法を紹介します。</p>
<h3>早速サンプルコードの解説</h3>
<p>というわけで、今回は順番に説明していきまーす。</p>
<p>今回は、なんとなく構造体を使っています。</p>
<pre class="brush: cpp;">
略

//破片データの作成
struct _dust{
	float x;		//x座標
	float y;		//y座標
	float x_add;	//x増加値
	float y_add;	//y増加値
	BYTE color;	//色番号
	int left;		//動作までの残りカウント
}*dust=NULL;
</pre>
<p>サンプルプログラムを実行すれば解ると思いますが、画像は左から段々と1ドットずつに分解され、それぞれが独立して動いています。<br />
ですから、1ドットにつき、1データ(上の構造体の場合たぶん28バイト)が必要となります。<br />
今回使用している画像サイズは612×145ですから、計612x145x28=2484720バイト必要となります。<br />
このサイズを配列として「struct _dust dust[145][612]」などとすると、VCの場合、実行時にエラー（スタックオーバーとかその辺）が出てしまい、正常に動作しません。<br />
ですから、「動的に確保」するようにします。</p>
<pre class="brush: cpp;">
略

//----------[ 終了 ]----------------------------------------------------------------------------
void Quit(char *str=NULL){
	EndDirectDraw();
	if(str!=NULL)
		MessageBox(hw,str,&quot;Message&quot;,MB_OK);
	if(dust)
		GlobalFree(dust);
	dust=NULL;
	exit(1);
}
</pre>
<p>んでもって、プログラム中に「_dust」構造体を動的に確保すると仮定した場合、<br />
プログラムを終了する前にデータを解放しなければなりません。「GlobalFree」については<br />
後でちょっと触れます（＾＾；</p>
<pre class="brush: cpp;">
略

//----------[ メイン関数 ]----------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow){

	略

	//DirectDraw開始
	StartDirectDraw(hw);

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

	//ビットマップを作業用サーフェイスへ読み込む
	LoadBitmap(lpWork,&quot;takabo.bmp&quot;,0,0,612,145);//15,168

	BYTE *p;
	DWORD tim;

	//サーフェイスのロックで使用
	DDSURFACEDESC desc;
	ZeroMemory(&amp;desc,sizeof(DDSURFACEDESC));
	desc.dwSize=sizeof(DDSURFACEDESC);

	//メモリ確保
	dust=(struct _dust *)GlobalAlloc(GMEM_FIXED,sizeof(struct _dust)*145*612);
	if(dust==NULL)
		Quit(&quot;メモリを確保出来ませんでした&quot;);
</pre>
<p>ここでメモリを動的に確保しています。</p>
<p>動的に確保する方法は「malloc」だとか「new」だとか色々ありますが、今回はなんとなく「GlobalAlloc」を使用します。<br />
これはAPIだったかな？まぁ、この関数についての詳細はヘルプを参照してください。<br />
とにかく「GlobalAlloc(GMEM_FIXED,データサイズ);」<br />
としてやれば、データサイズ分のメモリを確保し、確保したメモリの先頭アドレスを返してくれます。<br />
この関数で確保したメモリを解放するのが「GlobalFree(メモリの先頭アドレス);」です(Quit()関数内で使用）。</p>
<pre class="brush: cpp;">
	int dust_max=0;

	//作業用サーフェイスロック
	lpWork-&gt;Lock(NULL,&amp;desc,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL);
	p=(BYTE *)desc.lpSurface;
</pre>
<p>この辺から、先程確保した構造体を初期化します。</p>
<p>まずここで、画像を読み込んである作業用サーフェイスをロックしておきます。</p>
<p>ロックについては「DirectDraw基礎 第12回」でやりました。</p>
<pre class="brush: cpp;">
	int x,y;

	for(y=0;y&lt;145;y++){
		for(x=0;x&lt;612;x++){
			BYTE col=p[y*desc.lPitch+x];
			//黒(0番)以外を処理する
			if(col!=0){
				dust[dust_max].x=float(x+15);	//中央へ持ってくるため、ちょっと補正
				dust[dust_max].y=float(y+168);
				float angle=(rand()%36000)/100.f;
				//float speed=(rand()%3000)/100.f+2;
				float speed=10.f/(rand()%30);
				dust[dust_max].x_add= (float)cos(angle*3.141592/180)*speed;
				dust[dust_max].y_add=-(float)sin(angle*3.141592/180)*speed;
				dust[dust_max].color=col;
				dust[dust_max].left=x/6+rand()%10;
				dust_max++;
			}
		}
	}
</pre>
<p>上の方でも触れたように、画像の1ドット1ドット全てに対して1つのデータを作成します。<br />
ただ、画像の黒い部分「色番号0」は表示しないので、データは作成しません。<br />
あとはランダム値によって速度と角度を決め、そこから三角関数を使用してX、Yの増加値を決定します。</p>
<p>ちなみに「指定した角度の方向に進む」ような処理は「ゲーム制作基礎 第4回」でやりました。</p>
<pre class="brush: cpp;">
	//ロックを解除
	lpWork-&gt;Unlock(NULL);

	int count=0,i;

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

		count++;

		//爆破前は普通に表示
		if(count&lt;60*2){
			Blt(lpBack,15,168,612,145,lpWork,0,0,FALSE);
		}
		//爆破
		else {
			//サーフェイスをロック
			lpBack-&gt;Lock(NULL,&amp;desc,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL);
			p=(BYTE*)desc.lpSurface;

			//データを書き込む
			for(i=0;i&lt;dust_max;i++){
				if(dust[i].left&lt;=0){
					dust[i].x+=dust[i].x_add;
					dust[i].y+=dust[i].y_add;
					dust[i].y_add+=0.1f;
				} else
					dust[i].left--;

				x=int(dust[i].x);
				y=int(dust[i].y);
				if(x&gt;=0 &amp;&amp; x&lt;640 &amp;&amp; y&gt;=0 &amp;&amp; y&lt;480)
					p[y*desc.lPitch+x]=dust[i].color;
			}

			//ロックを解除
			lpBack-&gt;Unlock(NULL);
		}

		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/60);	//60fps
	}

	return(FALSE);
}
</pre>
<p>データを作成してしまえば、あとは毎回各データのx,y座標にx,y増加量を足していき、画面に表示するだけです。<br />
簡単ですね。</p>
<p>ただ、今回はビデオメモリ（lpBack）を直接操作しているので、ビデオカードによっては「やたら遅い！」<br />
という事もあると思います。<br />
そういった場合は、作業用バッファ（その2）としてオフスクリーンサーフェイスをシステムメモリ内に作成し、そこを直接操作してデータを書き込み、バックバッファへBltFastで転送、Flip・・・とすれば、多少は速くなると思いますのでやってみてください。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/20001002171121.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第6回　画像を徐々に表示する</title>
		<link>http://takabosoft.com/20000929170536.html</link>
		<comments>http://takabosoft.com/20000929170536.html#comments</comments>
		<pubDate>Fri, 29 Sep 2000 08:05:36 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　演出・エフェクト編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/20000929170536.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/effec_06.lzh"><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（「effec_06.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「effec_06.exe」をダブルクリックし、実行してみてください（何かキーを押すと終了します）。<br />
どうでしょう？画面が切り替わり、Takabo Soft Networkのロゴが下から徐々に表示されると思います。</p>
<p>というわけで、今回は徐々に画像を表示する方法を説明していきます。</p>
<h3>早速サンプルコードの解説</h3>
<p>今回の主なコードはこれ。</p>
<pre class="brush: cpp;">
//----------[ メイン関数 ]----------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow){

	略

	//DirectDraw開始
	StartDirectDraw(hw);

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

	//ビットマップを作業用サーフェイスへ読み込む
	LoadBitmap(lpWork,&quot;takabo.bmp&quot;,0,0,612,145);

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

		//徐々に下から表示
		if(count&lt;=145){
			ClearScreen(lpBack);	//バックバッファ全消去

			//既に表示済みのものを表示
			Blt(lpBack,15,168+145-count,612,count,lpWork,0,145-count,FALSE);

			//一番上に表示しているものを縦に連続させて表示
			for(i=0;i&lt;168+145-count;i++)
				Blt(lpBack,15,i,612,1,lpWork,0,145-count,FALSE);

			Flip();					//画面更新
		}
		//普通に表示
		else {
			ClearScreen(lpBack);
			Blt(lpBack,15,168,612,145,lpWork,0,0,FALSE);
			Flip();
		}

		count++;

		if(count&gt;300)
			count=1;

		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+33);	//1000/30=33.333(30FPS)
	}

	return(FALSE);
}
</pre>
<p>今回のプログラムは簡単なので、すぐに解ると思います。</p>
<p>下から順番に表示しつつ、新しく表示される部分は上から降ってくるかのように表示する、というよくあるやつですね？</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/20000929170536.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第5回　256色パレットを操作して画像の明度を変更する</title>
		<link>http://takabosoft.com/20000926165526.html</link>
		<comments>http://takabosoft.com/20000926165526.html#comments</comments>
		<pubDate>Tue, 26 Sep 2000 07:55:26 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　演出・エフェクト編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/20000926165526.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/effec_05.lzh"><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（「effec_05.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「effec_05.exe」をダブルクリックし、実行してみてください（何かキーを押すと終了します）。<br />
どうでしょう？画面が切り替わり、写真が表示され、その明度が徐々に変わっていくのが解ると思います。</p>
<p>というわけで、今回はパレットを操作して画像のメイドを変更するぜっ！（壊</p>
<h3>明度のお勉強</h3>
<p>さて、明度を変更するというテクニックはよく見かけますよね？<br />
例えばゲームで何か表示していて、次のシーン（場面）に移りたい場合に、画面を段々暗くし（フェード・アウト）、画面が真っ暗な間に次の画像を読み込んでおき（まだ表示はしない）準備が終わったら段々明るくしていき（フェード・イン）新しいシーンが始まる・・・というのがあります。<br />
まず、こういったものは「パレットを操作」して明度を変更していると考えて良いでしょう。<br />
というか、256色環境で明度を変更する方法はパレット操作以外まず無いです（近似色検索という解答は未定義）。</p>
<p>では、パレットをどうやって変化させたらいいか、についでですが、簡単です。<br />
明るくしたければ各RGB値を増やしてやればいいし、暗くしたければRGB値を減らしてやればいいのです。<br />
例えばRGB値が(100,25,30)だとして、1明るくしたいのなら各RGB値に1を足して(101,26,31)という感じ。<br />
ただ、ここで注意してもらいたいのが、各RGB値は0～255でなければならないと言うことです。255を越えた場合は255、0より小さくなった場合は<br />
0という風にです。あとはこの作業を256色パレット全てに行えばいい・・・はずですが、<br />
パレット0番と255番は白・黒固定色なので、それ以外を全て変更すればいいのです。</p>
<p>今回はもうちょっと突っ込んでおきましょうかね。<br />
例えば</p>
<pre class="brush: cpp;">
	int bright=50;	//明度を変更する値（50は適当
	BYTE red=230;	//パレットの値（赤のみ) BYTE = unsigned char

	red+=bright;
	if(red&gt;255)
		red=255;
	if(red&lt;0)
		red=0;
</pre>
<p>というような事はしないようにしてくださいね。</p>
<h3>今週のコードチェック（壊</h3>
<p>今回の主なコードはコレ。</p>
<pre class="brush: cpp;">
略

//----------[ パレットの明るさ変更 ]------------------------------------------------------------
//面倒なのでマクロでやってまう（良い子はマネしないでね）
#define SET_PAL(dest,src,bright) do{int v=src+bright;if(v&gt;255)v=255;if(v&lt;0)v=0;dest=v;}while(0)
void SetPaletteBright(int bright){
	PALETTEENTRY pal_tmp[256];

	for(int i=1;i&lt;255;i++){	//0:黒固定 1:白固定
		SET_PAL(pal_tmp[i].peRed  ,peEntry[i].peRed  ,bright);
		SET_PAL(pal_tmp[i].peGreen,peEntry[i].peGreen,bright);
		SET_PAL(pal_tmp[i].peBlue ,peEntry[i].peBlue ,bright);
	}

	//垂直帰線待ち（ちらつき防止）
	VsyncWait();
	//更新
	lpPalette-&gt;SetEntries(0,1,254,&amp;pal_tmp[1]);
}
</pre>
<p>パレットの設定については「DirectDraw基礎 第6回」でやりました。</p>
<p>また垂直帰線については「DirectDraw基礎 第14回」でやりました。</p>
<pre class="brush: cpp;">
略

//----------[ メイン関数 ]----------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow){

	略

	//DirectDraw開始
	StartDirectDraw(hw);

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

	//ビットマップをバックバッファへ読み込む
	LoadBitmap(lpBack,&quot;bridge.bmp&quot;,0,0,320,240);

	//フリッピング（画面へ表示）
	Flip();

	DWORD tim;
	int bright=0,b_add=1;
	while(1){
		//疑似タイマー処理
		tim=timeGetTime();

		//明るさ変更
		bright+=b_add;
		if(bright6gt;=255 || bright&lt;=-255)
			b_add=-b_add;
		SetPaletteBright(bright);

		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+16);	//1000/60=16.666(60FPS)
	}

	return(FALSE);
}
</pre>
<p>見て解るとおり、一度画面に写真を表示したら、後はパレットを変更しているだけです。<br />
明度を変更する関数でマクロを使ってしまったので、初心者にはちょっと解りにくいかもしれませんが、これを機、マクロの勉強をしてみてください。マクロを使うとホント楽なので・・・</p>
<p>あ、ちなみにビデオカードによっては、この「パレットを設定」する時間がやたらかかるものがあるので、「パレットを使えば高速に出来る！」とか思いこまないようにしてください。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/20000926165526.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第4回　サインカーブを使用して画像を揺らす その3</title>
		<link>http://takabosoft.com/20000922164155.html</link>
		<comments>http://takabosoft.com/20000922164155.html#comments</comments>
		<pubDate>Fri, 22 Sep 2000 07:41:55 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　演出・エフェクト編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/20000922164155.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/effec_04.lzh"><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（「effec_04.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「effec_04.exe」をダブルクリックし、実行してみてください（何かキーを押すと終了します）。<br />
どうでしょう？画面が切り替わり、写真が波紋のような歪み方をすると思います（謎。<br />
というわけで、今回もサインカーブを使用して画像を歪ませたいと思います。</p>
<h3>今回は解りづらいかも</h3>
<p><img src="http://takabosoft.com/wp-content/uploads/2000/09/hmn.jpg" align=right>さて、今まで演出講座2・3回にてサインカーブを使用して地球を揺らしてきましたが、今回は右の写真のように、写真を波紋のように歪めてみます。<br />
今まで真面目に演出講座2・3回を勉強された方なら、おそらく写真を見ただけで「だいたいこうやっているのだろう」という見当は付いていると思います。</p>
<p>んー、ちょっと初心者にはきつい内容かもしれないので、こんなものもあるんだぁーぐらいに流してください。</p>
<p>というかゲーム関連で、波紋使うかどうかは謎です。</p>
<h3>まずは数学のお勉強</h3>
<p><img src="http://takabosoft.com/wp-content/uploads/1999/12/sankaku0.gif" align=left>さて今回はプログラム中に「直線距離の算出」をするので、まずここでざっと説明しておきます。<br />
左の図のように直角三角形がある場合、</p>
<p><img src="http://takabosoft.com/wp-content/uploads/2000/09/pita0.gif"></p>
<p>という公式があります（ピタゴラスの定理だったか？）。<br />
高校1年くらいには習うと思いますが（詳しくは数学の先生に聞いてください）。</p>
<p>実際は、x座標,y座標があるので、点A（ax,ay）から点B（bx,by）の直線距離は<br />
以下の図のようになります。</p>
<p><img src="http://takabosoft.com/wp-content/uploads/2000/09/pita1.gif"></p>
<p>パソコン上の座標はY軸の方向が逆になるのですが、今回は2乗しているため符号が必ずプラスになるので<br />
その辺を考える必要はありません。</p>
<p>これを実際にC言語で記述すると、</p>
<pre class="brush: cpp;">
length = sqrt((ax-bx)*(ax-bx) + (ay-by)*(ay-by));
</pre>
<p>みたいな感じになりますね。</p>
<h3>DirectDraw初期化</h3>
<p>さて、サンプルコードを見ながら順番に説明していきます。<br />
今回は基本的な部分はWinMain()内で全てやっていますが、DirectDrawの初期化の部分も少し変更していますので注意してください。<br />
ちなみにDirectDraw関連の基本的なコードは「DirectDraw基礎 第13回」のサンプルコードを<br />
使用しています（MODE Xを使用します）。</p>
<p>ではまず、グローバル変数としてlpGraphを宣言しておきます。<br />
これは写真を読み込んでおく場所として使用します。</p>
<pre class="brush: cpp;">
LPDIRECTDRAWSURFACE lpBack=NULL;	//オフスクリーンサーフェイス（バックバッファ）
LPDIRECTDRAWSURFACE lpWork=NULL;	//オフスクリーンサーフェイス（作業用バッファ）
LPDIRECTDRAWSURFACE lpGraph=NULL;	//オフスクリーンサーフェイス（作業用バッファ その2）
</pre>
<p>宣言しただけでは意味が無いので、StartDirectDraw自作関数内でオフスクリーンサーフェイスを作成します。</p>
<pre class="brush: cpp;">
BOOL StartDirectDraw(HWND hw){

	略

	//作業用オフスクリーンサーフェイス作成
	ZeroMemory(&amp;ddsd,sizeof(ddsd));
	ddsd.dwSize=sizeof(ddsd);
	ddsd.dwFlags=DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
	//強制的にシステムメモリ内に作成する
	ddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
	ddsd.dwWidth=320;
	ddsd.dwHeight=240;
	if((lpDD-&gt;CreateSurface(&amp;ddsd,&amp;lpWork,NULL))!=DD_OK)
		return FALSE;
	if((lpDD-&gt;CreateSurface(&amp;ddsd,&amp;lpGraph,NULL))!=DD_OK)
		return FALSE;
</pre>
<p>今回の場合、オフスクリーンサーフェイスへは、頻繁に直接アクセスするのでDDSCAPS_SYSTEMMEMORYを指定して強制的に<B>システムメモリ内</b>へ作成します（ビデオメモリ内サーフェイスへの直接アクセスは速度が遅い）。</p>
<p>さて、DirectDrawの設定はこれぐらいです。<br />
あ、ちなみに最後にlpGraphを解放するのを忘れないようにしてくださいね。</p>
<h3>よく解らない解説</h3>
<p>まず写真（bridge.bmp)をあらかじめ作成しておいたオフスクリーンサーフェイス（lpGraph)へ読み込んでおきます。</p>
<pre class="brush: cpp;">
//----------[ メイン関数 ]----------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow){

	略

	//DirectDraw開始
	StartDirectDraw(hw);

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

	//ビットマップを作業用サーフェイスへ読み込む
	LoadBitmap(lpGraph,&quot;bridge.bmp&quot;,0,0,320,240);
</pre>
<p>次に、高速化のためにサイン・コサインテーブルを作成します。</p>
<pre class="brush: cpp;">
	//サイン、コサインテーブル作成(256で一周とする）
	float fsin[256],fcos[256];
	for(int i=0;i&lt;256;i++){
		fsin[i]=(float)sin(i*3.1415926535/128);
		fcos[i]=(float)cos(i*3.1415926535/128);
	}
</pre>
<p>普通は360度で一周ですが、今回は256度で一周とします。<br />
こうすることで fsin[BYTE(...)] と、BYTE型(unsigned char型)にキャストするだけで不正なアクセスを防ぐことが出来ます。</p>
<p>次に、あらかじめ各座標毎に、中心からの距離・中心への角度(0-255度)を算出しておきます。<br />
これも高速化のためです。</p>
<pre class="brush: cpp;">
	float length[240][320];
	BYTE angle[240][320];

	int x,y;
	for(y=0;y&lt;240;y++)
		for(x=0;x&lt;320;x++){
			length[y][x]=(float)sqrt((160-x)*(160-x)+(120-y)*(120-y));
			angle[y][x]=BYTE(atan2(-double(120-y),double(160-x))/3.141592*128+256);
		}
</pre>
<p>距離の算出については、上の方でやりましたね？<br />
また、角度の算出については「ゲーム制作基礎 第11回」でやりました。</p>
<pre class="brush: cpp;">
	//サーフェイスのロックで使用
	DDSURFACEDESC desc_src,desc_dest;
	ZeroMemory(&amp;desc_src,sizeof(DDSURFACEDESC));
	ZeroMemory(&amp;desc_dest,sizeof(DDSURFACEDESC));
	desc_src.dwSize=desc_dest.dwSize=sizeof(DDSURFACEDESC);
	BYTE *p_src,*p_dest;	//ちなみに src=参照元  dest=転送先
	int sx,sy;
	int pitch_src,pitch_dest;

	int count=0;
	float width=0.f,width_max=20,width_add=0.15f;
	BYTE color;

	while(1){
		//疑似タイマー処理
		tim=timeGetTime();
		count++;				//カウンタ

		//ゆれの大きさを時間によって変化させる
		if(width_add&gt;0){
			if((width+=width_add)&gt;width_max)
				width_add=-width_add;
		} else {
			//0まで戻してしまうとちょっと歪むのでやめる
			if((width+=width_add)&lt;=0.05f){
				width=0.05f;
				width_add=-width_add;
			}
		}
</pre>
<p>↑のは大体解ると思います。<br />
ゆれの大きさの部分に関しては前回・前々回と大体同じです。</p>
<p>次に、あらかじめ画像を読み込んでおいたサーフェイス(lpGraph）と、作業用サーフェイス(lpWork)をロックし、そのサーフェイスへの先頭アドレスを取得します。</p>
<pre class="brush: cpp;">
		//ロック
		lpGraph-&gt;Lock(NULL,&amp;desc_src,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL);
		p_src=(BYTE*)desc_src.lpSurface;
		pitch_src=desc_src.lPitch;

		lpWork-&gt;Lock(NULL,&amp;desc_dest,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL);
		p_dest=(BYTE*)desc_dest.lpSurface;
		pitch_dest=desc_dest.lPitch;
</pre>
<p>サーフェイスのロックについては「DirectDraw基礎 第12回」でやりました。</p>
<p>そんでもって次のが心臓部。</p>
<pre class="brush: cpp;">
		BYTE *p_angle=&amp;angle[0][0];
		float *p_length=&amp;length[0][0];

		for(y=0;y&lt;240;y++){
			for(x=0;x&lt;320;x++){
				//参照元をずらす
				float len=fsin[BYTE((-count+*p_length)*15)]*width;
				sx=int(x+fcos[*p_angle]*len);
				sy=int(y-fsin[*p_angle]*len);
				color=0;
				if(sx&gt;=0 &amp;&amp; sx&lt;320 &amp;&amp; sy&gt;=0 &amp;&amp; sy&lt;240)
					color=*(p_src+pitch_src*sy+sx);
				*(p_dest++)=color;
				p_angle++;
				p_length++;
			}
			p_dest+=pitch_dest-320;
		}
</pre>
<p>ポインタいじりまくりですね。<br />
ポインタの概念がしっかり解っていないと理解出来ないと思います。</p>
<p>まず、今までの演出は「転送先の座標を計算する」というパターンですが今回はこれでは穴が空くので逆に「転送先が転送元の座標を計算する」方法でやっています。<br />
ですから画面全体（320x240)について全て計算を行います。</p>
<p>おおまかに説明すると、「画面中心からの距離(p_length)+時間（count)」を使ってサインカーブを参照し、ゆれの幅を計算します。<br />
その揺れの幅分だけ転送元の座標を中央に向かってずらします。あとは転送元の色を転送先へ転送します。</p>
<p>一通り終わったらロックを解除し、一度バックバッファへ転送し、フリップして画面に表示させます。</p>
<pre class="brush: cpp;">
		//アンロック
		lpWork-&gt;Unlock(desc_dest.lpSurface);
		lpGraph-&gt;Unlock(desc_src.lpSurface);

		Blt(lpBack,0,0,320,240,lpWork,0,0,FALSE);

		Flip();		//フリッピング

		あとは省略（爆
</pre>
<p>解ってしまえば簡単ですね（＾＾；</p>
<p>細かい部分で何か解らない事があれば掲示板へどうぞ。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/20000922164155.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第3回　サインカーブを使用して画像を揺らす その2</title>
		<link>http://takabosoft.com/20000919163803.html</link>
		<comments>http://takabosoft.com/20000919163803.html#comments</comments>
		<pubDate>Tue, 19 Sep 2000 07:38:03 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　演出・エフェクト編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/20000919163803.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/effec_03.lzh"><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（「effec_03.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「effec_03.exe」をダブルクリックし、実行してみてください（何かキーを押すと終了します）。<br />
どうでしょう？画面が切り替わり、うねうね揺れた地球の画像が2パターン表示されると思います。<br />
というわけで今回も、サインカーブを使用して画像を揺らす方法ついて説明したいと思います。</p>
<h3>地球を歪ませる その2</h3>
<p>さて、みなさん「波」と言われて何を思い浮かべるでしょう？真夏の砂浜？ビーチバレー？水着？<br />
前回紹介した「揺れる地球」は、「輪ゴムを伸ばして弦をはじいたような上下の揺れのようなもの。」<br />
今回の揺れる地球」は、「音波のように伸びたり縮んだりする波（横波？）」です（超謎）。<br />
高校の物理でそんなのを習ったような気がしましたが忘れました・・・。</p>
<p>というわけで、サンプルコードを見てみましょう。</p>
<pre class="brush: cpp;">
//----------[ メイン関数 ]----------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow){

	略

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

	//ビットマップを作業用サーフェイスへ読み込む
	LoadBitmap(lpWork,&quot;earth.bmp&quot;,60,15,200,210);

	//透明色を設定
	SetTransColor(lpWork,0);

	int count=0,i;
	float width=0.f,width_max=50,width_add=0.15f;

	DWORD tim;
	while(1){

		tim=timeGetTime();		//疑似タイマー処理
		ClearScreen(lpBack);	//バックバッファクリア
		count++;				//カウンタ

		//ゆれの大きさを時間によって変化させる（各パターン共通）
		if(width_add&gt;0){
			if((width+=width_add)&gt;width_max)
				width_add=-width_add;
		} else {
			if((width+=width_add)&lt;0){
				width=0;
				width_add=-width_add;
			}
		}

		//ゆらすパターン4（補間無し）
		for(i=0;i&amp;lt240;i++)
			BltClip(lpBack,0,120+i+int(sin((count+i)/10.f)*width),
				320,1,lpWork,0,i,TRUE);

		//ゆらすパターン5（補間有り）
		int y,y_old,y_new=0;
		for(i=0;i&lt;240;i++){
			y_old=y_new;
			y_new=120+i+int(sin((count+i)/10.f)*width);
			if(i!=0){
				if(y_old&lt;y_new)
					for(y=y_old;y&lt;y_new;y++)
						BltClip(lpBack,320,y,320,1,lpWork,0,i,TRUE);
				else
					for(y=y_old;y&gt;y_new;y--)
						BltClip(lpBack,320,y,320,1,lpWork,0,i,TRUE);
			}
		}

		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+16);	//1000/60=16.666（秒間60回更新予定）
	}

	return(FALSE);
}
</pre>
<p>さて、順番に説明していきましょうか。</p>
<p>まずパレットを読み込み、地球の画像をlpWorkサーフェイスへ読み込んでおきます。<br />
この辺は前回と全く同じですが、今回は透明色付きの転送を使用するので透明色の設定をしておきます。</p>
<p>サンプルプログラムを実行すると、2種類表示されますが、左のものがパターン4、右のがパターン5です。<br />
横に薄く切った画像を縦にずらしながら表示する感じです。<br />
ただ、このままパターン4のようにやってしまうと、サンプルプログラム実行時の左の画像のように「画像が切れる（隙間が出来る）」ため、美しくありません（？）</p>
<p>そこで、その間を補ったものがパターン5となります。</p>
<pre class="brush: cpp;">
	//ゆらすパターン4（補間無し）
	for(i=0;i&amp;lt240;i++)
		BltClip(lpBack,0,120+i+int(sin((count+i)/10.f)*width),
			320,1,lpWork,0,i,TRUE);

	//ゆらすパターン5（補間有り）
	int y,y_old,y_new=0;
	for(i=0;i&lt;240;i++){
		y_old=y_new;
		y_new=120+i+int(sin((count+i)/10.f)*width);
		if(i!=0){
			if(y_old&lt;y_new)
				for(y=y_old;y&lt;y_new;y++)
					BltClip(lpBack,320,y,320,1,lpWork,0,i,TRUE);
			else
				for(y=y_old;y&gt;y_new;y--)
					BltClip(lpBack,320,y,320,1,lpWork,0,i,TRUE);
		}
	}
</pre>
<p>お、今回は短い（＾＾；</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/20000919163803.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第2回　サインカーブを使用して画像を揺らす その1</title>
		<link>http://takabosoft.com/20000918163126.html</link>
		<comments>http://takabosoft.com/20000918163126.html#comments</comments>
		<pubDate>Mon, 18 Sep 2000 07:31:26 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　演出・エフェクト編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/20000918163126.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/effec_02.lzh"><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、お持ちの方はVisual C++でプロジェクトファイルを開いてください（「effec_02.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「effec_02.exe」をダブルクリックし、実行してみてください（何かキーを押すと終了します）。<br />
どうでしょう？画面が切り替わり、うねうね揺れた地球の画像が3パターン表示されると思います。<br />
というわけで今回は、サインカーブを使用して画像を揺らす方法ついて説明したいと思います。</p>
<h3>三角関数は怖くない（謎</h3>
<p><img src="http://takabosoft.com/wp-content/uploads/2000/09/sin.gif" align=right><br />
三角関数というと、なんだか難しく考える人もいるかもしれませんが、今回は別にムツカシー計算をするわけではありません。</p>
<p>右の図を見てください。<br />
これはだいぶ　いびつ　ではありますが、サインカーブっぽいものです。<br />
ここでまず覚えて欲しいのは、sin関数は「波形」という事と、最大値・最小値が+1・-1という事です。</p>
<p>それから前にも書きましたが、C言語の場合sin関数の引数の単位はラジアンなので、</p>
<p> 360度=2π</p>
<p> 1度=π/180</p>
<p>となります(今回はあんまり関係ありませんが）。</p>
<h3>地球を歪ませる</h3>
<p>さて、ここらでサンプルプログラムを見てみましょう。</p>
<p>今回は、画面中に3パターンの歪む地球を表示させています。</p>
<p>また、DirectDrawに関しては、「DirectDraw基礎 第10回」のサンプルコードを使用しています。</p>
<pre class="brush: cpp;">
//----------[ メイン関数 ]----------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow){

	略

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

	//ビットマップを作業用サーフェイスへ読み込む
	LoadBitmap(lpWork,&quot;earth.bmp&quot;,60,15,200,210);

	int count=0,i;
	float width=0.f,width_max=50,width_add=0.15f;

	DWORD tim;
	while(1){

		tim=timeGetTime();		//疑似タイマー処理
		ClearScreen(lpBack);	//バックバッファクリア
		count++;				//カウンタ

		//ゆれの大きさを時間によって変化させる（各パターン共通）
		if(width_add&gt;0){
			if((width+=width_add)&gt;width_max)
				width_add=-width_add;
		} else {
			if((width+=width_add)&amp;lt0){
				width=0;
				width_add=-width_add;
			}
		}

		//ゆらすパターン1
		SetClipArea(0,0,320,240);
		for(i=0;i&lt;240;i++)
			BltClip(lpBack,int(sin((count+i)/10.f)*width),
				i,320,1,lpWork,0,i,FALSE);

		//ゆらすパターン2
		SetClipArea(320,0,320,240);
		for(i=0;i&lt;320;i++)
			BltClip(lpBack,320+i,int(sin((count+i)/10.f)*width),
				1,240,lpWork,i,0,FALSE);

		//ゆらすパターン3
		SetClipArea(0,240,320,240);
		for(i=0;i&lt;240;i++)
			BltClip(lpBack,
				((i%2)?-1:1)*int(sin((count+i)/10.f)*width),
				240+i,320,1,lpWork,0,i,FALSE);

		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+16);	//1000/60=16.666（秒間60回更新予定）
	}

	return(FALSE);
}
</pre>
<p>順番に説明していきましょうか。</p>
<p>まずパレットを読み込み、地球の画像をlpWorkサーフェイスへ読み込んでおきます。</p>
<pre class="brush: cpp;">
	//パレット設定
	LoadPalette(&quot;earth.bmp&quot;);

	//ビットマップを作業用サーフェイスへ読み込む
	LoadBitmap(lpWork,&quot;earth.bmp&quot;,60,15,200,210);
</pre>
<p>ここで、画像は320x240内の中央へ来るように、読み込んだ画像の転送先をずらしています(60,15)。<br />
（解りやすくなると思ったので（＾＾；））</p>
<p>そんでもって今日の本題の部分</p>
<pre class="brush: cpp;">
	//ゆらすパターン1
	SetClipArea(0,0,320,240);
	for(i=0;i&lt;240;i++)
		BltClip(lpBack,int(sin((count+i)/10.f)*width),i,320,1,lpWork,0,i,FALSE);
</pre>
<p>1つ前の段落でサインカーブについて触れましたが、ここではサインカーブの図を90度右へ回転させたような感じで見ると直ぐに解ると思います（下図参照）。</p>
<p><IMG SRC="http://takabosoft.com/wp-content/uploads/2000/09/sin2.gif"></p>
<p>ここでは画像を、ズバシュァァァ！！と薄く横に切り刻みまくり、それらを横にずらしながら置いていく感じです（謎）。</p>
<p>毎回countをインクリメントする事で、使用する波形の「開始位置」をずらす事が出来ます。<br />
これにより、「動く」うねりを実現出来ます。また、・・・)/10.fと適当に割っていますが、大きな数字で割ると、波の間隔が広くなります。<br />
まぁ、いろいろ変数をいじってみて、「どこを変えるとどうなる」というのを試してみてください（＾＾；説明するより、そうした方が早いです。</p>
<p>あと、パターン2・パターン3がありますが、これはもう説明するまでもありませんね。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/20000918163126.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第1回　True Typeフォントを使用した文字列の描画</title>
		<link>http://takabosoft.com/20000901155739.html</link>
		<comments>http://takabosoft.com/20000901155739.html#comments</comments>
		<pubDate>Fri, 01 Sep 2000 06:57:39 +0000</pubDate>
		<dc:creator>takabosoft</dc:creator>
				<category><![CDATA[DirectXゲーム作成講座　演出・エフェクト編]]></category>

		<guid isPermaLink="false">http://takabosoft.com/20000901155739.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/effec_01.lzh"><b>サンプルコード</b></a>をダウンロードし、解凍してください。<br />
私はVisual C++6.0でコンパイルしているので、をお持ちの方はVisual C++でプロジェクトファイルを開いてください（「effec_01.dsw」をダブルクリックすれば開けます）。<br />
圧縮ファイルに含まれる「effec_01.exe」をダブルクリックし、実行してみてください（何かキーを押すと終了します）。<br />
どうでしょう？画面が切り替わり、文字が表示されると思います。<br />
というわけで今回は、True Typeフォントを使用した文字列描画について説明したいと思います。</p>
<h3>やっぱり苦手なGDI</h3>
<p>何のフォントも設定しないまま文字列を出力する方法は「DirectDraw基礎 第4回」、「DirectDraw基礎 第6回」で既にやりました。<br />
今回は、True Typeを使用するという事で、フォントを作成しなければなりません。</p>
<p>ではサンプルコードを順番に説明していきます。</p>
<p>TextOutFont関数が今回作成した自作関数です。</p>
<pre class="brush: cpp;">
//----------[ True Typeフォントを使用したテキストの出力 ]---------------------------------------
void TextOutFont(LPDIRECTDRAWSURFACE surface, int x, int y, int height, char *text_str, char *font_name, unsigned char col){

	HFONT new_font,old_font;
	HDC hdc;

	//フォント作成
	new_font=CreateFont(
		height,	//高さ
		0,	//横幅
		0,	//角度
		0,	//よくわからなんだ
		FW_NORMAL,	//太さ
		0,	//斜体
		0,	//下線
		0,	//打ち消し
		DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY,DEFAULT_PITCH,font_name);

	surface-&gt;GetDC(&amp;hdc);			//デバイスコンテキスト取得
	SetBkMode(hdc,TRANSPARENT);			//背景モード設定
	old_font=(HFONT)SelectObject(hdc,new_font);	//フォント選択
						//フォントカラー設定
	SetTextColor(hdc,RGB(peEntry[col].peRed,peEntry[col].peGreen,peEntry[col].peBlue));
	TextOut(hdc,x,y,text_str,strlen(text_str));	//出力
	SelectObject(hdc,old_font);			//フォント復元
	surface-&gt;ReleaseDC(hdc);			//デバイスコンテキスト解放
	DeleteObject(new_font);			//フォント消去
}

略

//----------[ メイン関数 ]----------------------------------------------------------------------
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow){

	略

	//メッセージループ
	while(1){
		//テキスト出力
		ClearScreen(lpBack);

		//ノーマル
		TextOutFont(lpBack,0,0,60,&quot;Takabo Soft 2000&quot;,&quot;Comic Sans MS&quot;,1);

		略

		Flip();
</pre>
<p>まず、CreateFont関数を呼び出して、フォントを作成します。書式は以下の通りです。</p>
<table class="data">
<tr>
<th>書式</th>
<td>HFONT CreateFont( int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight, DWORD fdwItalic, DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD fdwCharSet, DWORD fdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality, DWORD fdwPitchAndFamily, LPCTSTR lpszFace );  ながっ！
</td>
</tr>
<tr>
<th>nHeight</th>
<td>フォントの高さを論理単位で指定。ドット数では無いらしい。0を指定すると、デフォルトの高さになる。</td>
</tr>
<tr>
<th>nWidth</th>
<td>フォントの横幅を指定。0を指定すると、高さにあった横幅になる。</td>
</tr>
<tr>
<th>nEscapement</th>
<td>文字列全体の角度を1/10度単位で指定します。</td>
</tr>
<tr>
<th>nOrientation</th>
<td>各文字の角度を1/10度単位で指定します。とか言ってるけど、うちじゃうごかなんだ・・・。</td>
</tr>
<tr>
<th>fnWeight</th>
<td>フォントの太さを指定します。指定する値は0～1000ですが、400で通常、700でボールド体です。</td>
</tr>
<tr>
<th>fdwItalic</th>
<td>1を指定すると斜体になります。</td>
</tr>
<tr>
<th>fdwUnderline</th>
<td>1を指定すると下線が付きます。</td>
</tr>
<tr>
<th>fdwStrikeOut</th>
<td>1を指定すると打ち消し線が付きます。</td>
</tr>
<tr>
<th>fdwCharSet</th>
<td>フォントの文字セットを指定するらしい。よく解らないのでDEFAULT_CHARSETを指定（爆</td>
</tr>
<tr>
<th>fdwOutputPrecision</th>
<td>出力精度を指定するらしい。よく解らないのでOUT_DEFAULT_PRECISを指定（爆2</td>
</tr>
<tr>
<th>fdwClipPrecision</th>
<td>クリッピング精度を指定するらしい。やっぱりよく解らないのでCLIP_DEFAULT_PRECISを指定（爆3</td>
</tr>
<tr>
<th>fdwQuality</th>
<td>出力品質を指定するらしい。・・・よく解らないのでDEFAULT_QUALITYを指定（爆4</td>
</tr>
<tr>
<th>fdwPitchAndFamily</th>
<td>フォントのピッチとファミリを指定するらしい。なんじゃそりゃ！というワケでDEFAULT_PITCHを指定（爆5</td>
</tr>
<tr>
<th>lpszFace</th>
<td>フォント名を指定します。</td>
</tr>
<tr>
<th>戻り値</th>
<td>成功すると、論理フォントのハンドルが返るらしい。</td>
</tr>
</table>
<p>というように、私にも一部ワケが解りませんが、フォントが作成し終わったら、デバイスコンテキスト取得し、「SelectObject」を呼び出しています。<br />
この関数は、指定したデバイスコンテキストにGDIのオブジェクト（フォント・ペン・ブラシ等）を選択する（関連づけさせるというべきか・・・）ものです。<br />
この関数の戻り値は、今まで選択されていたGDIのオブジェクトです（新しくフォントを指定したら、今まで選択されていたフォントが戻り値となる）。</p>
<p>こうしてTextOut関数を呼び出してやれば、設定したフォントで文字列を描画してくれるわけです。<br />
描画し終えたら、後始末としてSelectObjectで元のフォントを選択してやります。<br />
昔この作業をサボったら動作がおかしくなったような気がしましたが今やってみると、そんなこともありませんねぇ・・・。<br />
いらなくなったフォントとかを消す前にこうして、元のフォントをSelectObjectで選択させるというのが正しい方法なので、一応やっておいた方が良いと思います。</p>
<p>最後に、DeleteObject関数で、最初に作成したフォントを削除してやります。この作業をサボルと間違いなくウィンドウズはおかしくなります（爆。<br />
ウィンドウズにはGDIリソースというのがあり、CreateFont関数のようにGDIの何かを作成する度に<br />
GDIリソースが減っていきます。このリソースは普段のウィンドウズでも使用しているため、どっかのアプリケーションでこれを使い尽くしてしまうと、他のアプリケーションまで動かなくなるという事態が起きるので、要らなくなったら、ちゃんと消してやりましょう。</p>
<h3>ちょっとした飾り付け</h3>
<p>True Typeフォントで描画した場合、だいぶ陳腐なものになりがちですが、影や縁を付ける事で多少ながらマシになるかもしれません。</p>
<pre class="brush: cpp;">
//影付き
TextOutFont(lpBack,0+2,100+2,60,&quot;影付き&quot;,&quot;MS ゴシック&quot;,0);
TextOutFont(lpBack,0,100,60,&quot;影付き&quot;,&quot;MS ゴシック&quot;,1);

//縁付き
TextOutFont(lpBack,0,200-1,60,&quot;縁付き&quot;,&quot;MS 明朝&quot;,0);
TextOutFont(lpBack,0,200+1,60,&quot;縁付き&quot;,&quot;MS 明朝&quot;,0);
TextOutFont(lpBack,0-1,200,60,&quot;縁付き&quot;,&quot;MS 明朝&quot;,0);
TextOutFont(lpBack,0+1,200,60,&quot;縁付き&quot;,&quot;MS 明朝&quot;,0);
TextOutFont(lpBack,0,200,60,&quot;縁付き&quot;,&quot;MS 明朝&quot;,1);
</pre>
<p>今回は、TextOutFontを並べて影を付けたりしていますが、この関数を呼ぶ毎にフォント作成したり<br />
しているので、アルゴリズム上よくないですよね？影を付ける機能なんかは、TextOutFont関数内に組み込んでしまった方が良いですね。<br />
この辺は各自改造していってください。</p>
<h3>フォントの注意点</h3>
<p>True Typeフォントを使用する場合、実行するパソコンに使用するフォントがインストールされていなければなりません。<br />
また、制作者のパソコンにフォントがあるからと言ってそれを使用した場合でも、そのプログラムを配布した先のパソコンにそのフォントがインストールされているかも解りません。<br />
ですから、ウィンドウズに標準でインストールされているフォント以外の使用はお薦めできません（自作のフォントなら配布出来ると思いますが）。</p>
<p>「MS P明朝」だとか「MS Pゴシック」ならまず入ってると思います。</p>
<p>また、このような問題の解決策として、絵（BMP)で描いた文字を使用するという手もあります。<br />
これもまたいつか紹介しましょうか。</p>
]]></content:encoded>
			<wfw:commentRss>http://takabosoft.com/20000901155739.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

