今日やったこと

アバター
TOMY
記事: 53
登録日時: 13年前
住所: 愛知県
連絡を取る:

今日やったこと

投稿記事 by TOMY » 11年前

もう一度DirectXを使用したプログラムの基本的な流れを再学習するために学生時代のプログラムを見ながら、極力最低限の内容を一から組み直してみた。
以下ソースコード。注釈文だらけでクッソ汚いのは学習用だから。ごめんなさい。
あと色々本とかサイトとかで調べながら作業してたけど、注釈文の内容間違っている部分あるかもしれない。

CODE:

//まずはゲームの基本処理と空ウィンドウを出すプログラムを書いて、基本的な雛形を理解する。
//(何事もまずは第一歩から!)
//あくまで内容を理解するためなので多少コメントの嵐になるのは覚悟する。
//追記:やったーーーーーー動いたーーー--!!! 次はファイル分割をする

#define _CTR_SECURE_NO_DEPRECATE

//インクルードファイルの読み込み-------------------------------------------------------------------
#include
#include
#include

//ライブラリファイルの読み込み---------------------------------------------------------------------
//(dxguid.lib  d3d9.lib  d3dx9.lib の3つは最低限必要)
#pragma comment(lib , "dxguid.lib")					//必須。「GUID(グローバルユニークID)」に関わる実体が納められている。
													//GUIDはインターフェイスについた番号のようなもので、これが無いとDirectXはうまく動かない
#pragma comment(lib , "d3d9.lib")					//Direct3Dのコアライブラリ低レベルインターフェイスのみの提供(IDirect3D**系のインターフェイス)
#pragma comment(lib , "d3dx9.lib")					//上記と一緒だが、コッチはID3DX**系を使用するのに必要
#pragma comment(lib , "winmm.lib")					//WINAPIの一部機能を使うのに必要みたい。(詳細分からなかった)

//解放処理簡略用インライン関数(テンプレート)-----------------------------------------------------
template
inline void SAFE_RELEASE(T*&a)
{
	if(a != NULL){
		a->Release();
		a = NULL;
	}
}

//ユーザー定義関数のプロトタイプ-------------------------------------------------------------------
void	GameLoop(void);																//ゲーム処理の核となるループ処理
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);		//WINAPIウィンドウプロシージャ(コールバック関数)
BOOL	CreateD3D(HWND hWnd);														//Direct3DDevice作成
void Release(void);																	//終了時の各種解放処理

void StartInit(void);										//GameLoop内指定Scene初期化時の処理
void StartWork(void);										//GameLoop内指定Scene座標更新時の処理
void StartUpdate(void);										//GameLoop内指定Sceneその他更新時の処理
void StartDrawBack2D(void);									//GameLoop内指定Scene描画時の処理(背景等再背面の2D描画処理)
void StartDraw3D(void);										//GameLoop内指定Scene描画時の処理(3D空間上での表示(メッシュ,3Dポリゴン等))
void StartDrawFront2D(void);								//GameLoop内指定Scene描画時の処理(UI等最前面で出したい2D描画処理)
void StartEnd(void);										//GameLoop内指定Scene終了時の処理

//アプリケーションの設定--------------------------------------------------------------------------
#define APPNAME  "GameBaseStudy"							//アプリケーション名の定義
#define WINTITLE "練習用雛形(超最低限・・・のつもり)"		//ウィンドウタイトルの定義

//カメラ用関連情報

struct CAMINFO{
	D3DXVECTOR3 look,at,up;

	CAMINFO(){
		look = D3DXVECTOR3(-0.8f, 1.25f, -8.0f);			//注視点(カメラが見ている先の)座標
		at	 = D3DXVECTOR3(0.0f, 0.0f, 0.0f);				//カメラの位置(座標)
		up	 = D3DXVECTOR3(0.0f, 1.0f, 0.0f);				//上方向(法線?)
	}
};

float aperture= D3DXToRadian(45.0f);						//視野角の指定(DegreeからRadianに変換)

//計算の際に多用するマクロ------------------------------------------------------------------------
#define PI 3.1415926535897932384626433832795f
#define mPI (PI/1000.0f)
#define fPI 3.1415926535897932384626433832795f
#define fmPI (fPI/1000.0f)

//フレーム切替用列挙型----------------------------------------------------------------------------
enum FRAME					//ゲームの規模や内容に応じて変更可。
{
	START_INIT,
	START_UPDATE,
	START_END,
	MENU_INIT,
	MENU_UPDATE,
	MENU_END,
	ERROR_CHECK,
};

#define	WIN_WIDTH  640							//ウィンドウのWidth指定
#define	WIN_HEIGHT 480							//ウィンドウのHeight指定
FRAME				g_FrameNo	= START_INIT;	//シーン切り替えフラグ
BYTE				g_KeyTbl[256];				//キーボードの状態を格納
bool				g_KeyFlg[256];				//キーボードの状態フラグ
DWORD				g_NowTime;					//現在の時間を保存
LPDIRECT3D9			g_pd3d		= NULL;			//D3D9オブジェクト
LPDIRECT3DDEVICE9	g_pd3ddev	= NULL;			//D3D9デバイス

CAMINFO				g_cam;						//カメラ情報

//GameLoop (この関数がWinMainから呼ばれる)また、ゲームの基本となるループ処理を行う関数。--------
void GameLoop(void)
{
	g_NowTime = timeGetTime();		//現在の時間を取得

	GetKeyboardState(g_KeyTbl);		//現在のキー情報を取得

	switch(g_FrameNo){
		case START_INIT:			//Startシーン初期化	
			StartInit();						
			break;
		case START_UPDATE:			//Startシーン更新
			StartWork();			//(各種更新と描画を一気に行う)
			StartUpdate();

			//描画。一つの関数で全部をつらつら書くと物によっては読みにくくなる為、3分割してみた。
			StartDrawBack2D();		//描画順に合わせて関数分割したが、
			StartDraw3D();			//エフェクトなどで描画順を変えたい場合はこの限りではない。
			StartDrawFront2D();		//(要するにやりたいことに合わせて描画順に関数自由を作ればいいってこと)
			break;
		case START_END:
			StartEnd();				//終了時の処理(解放等)
			break;

		case ERROR_CHECK:
			break;
		default:
			break;
	}
}

//WinProc	(Windowsメッセージ処理)---------------------------------------------------------------
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg){
		case WM_DESTROY:			//ウィンドウ画面が削除され破棄される時(要するに終了時)
			Release();				//解放
			PostQuitMessage(0);		//終了処理
			return 0;
		case WM_KEYDOWN:			//何かのキーが押された時
			switch(wParam){
			case VK_ESCAPE:			//ESCキーが押された時の処理(強制終了させる)
				Release();
				PostQuitMessage(0);	
				return 0;
			}
			return 0;
	}
	return DefWindowProc(hwnd, msg, wParam, lParam);	//デフォルトの処理を提供
}

//Create3D  Direct3Dデバイスの作成
BOOL CreateD3D(HWND hwnd)
{
	//Direct3Dオブジェクトの作成
	if(!(g_pd3d = Direct3DCreate9(D3D_SDK_VERSION))){			//作成に失敗したら0を返す
		MessageBox(hwnd, "Direct3DCreate9 Failed!","CreateD3D",MB_OK);
		return FALSE;
	}

	//Direct3Dデバイスオブジェクトの作成
	D3DPRESENT_PARAMETERS d3dpp = {};
	d3dpp.Windowed				= TRUE;
	d3dpp.SwapEffect			= D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat		= D3DFMT_UNKNOWN;

	//Zバッファの指定
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;

	//Direct3Dデバイスオブジェクトの作成
	if(FAILED(g_pd3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3ddev))){
		if(FAILED(g_pd3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3ddev))){
			MessageBox(hwnd, "g_pD3D->CreateDevice Failed!", "Create", MB_OK);
			return FALSE;
		}
	}
	return TRUE;
}

//Release プログラム終了時のDirectX関連オブジェクト解放-------------------------------------------
void Release(void)
{
	SAFE_RELEASE(g_pd3ddev);		//Direct3Dデバイス
	SAFE_RELEASE(g_pd3d);			//Direct3Dオブジェクト
}
//InitRender  レンダリングの設定(必要に応じてレンダリングの設定を追加する)------------------------
//下記の設定は一時的なものであり、状況に応じて適時変更する必要がある。(特定のオブジェクトだけライト当てたい時とか当てたくない時とかetc...)
void InitRender(LPDIRECT3DDEVICE9 d)
{
	//雛形のためだけの固定パイプライン
	d->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);			//アルファブレンディング設定
	d->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);	//透過色設定
	d->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);		//半透明処理
	d->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);				//カリング設定(CCW = 左手座標系でカリングON)
	d->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);//テクスチャの設定
	d->SetRenderState(D3DRS_ZENABLE, TRUE);						//Z比較を行う
	d->SetRenderState(D3DRS_DITHERENABLE, TRUE);				//ディザリング
	d->SetRenderState(D3DRS_SPECULARENABLE, TRUE);				//スペキュラオン
	d->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);		//グローシェーディング
	d->SetRenderState(D3DRS_LIGHTING, FALSE);					//ライトOFF
}

//WinMain  エントリーポイントプログラムはここから始まる-------------------------------------------
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszCmdParam, int nCmdShow)
{
	MSG			msg;
	HWND		hwnd;
	WNDCLASSEX	wc;
	char		szAppName[] = APPNAME;

	//ウィンドウクラスの初期化
	wc.cbSize			= sizeof(WNDCLASSEX);
	wc.style			= CS_DBLCLKS;
	wc.lpfnWndProc		= WinProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
	wc.hInstance		= hInst;
	wc.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wc.hIconSm			= NULL;
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName		= NULL;
	wc.lpszClassName	= szAppName;

	if(!RegisterClassEx(&wc)){			//ウィンドウクラス登録(異常時は0を返す)
		return FALSE;
	}

	//ウィンドウのクライアント領域をWIN_WIDTH * WIN_HEIGHTにするための計算
	int w = WIN_WIDTH  + GetSystemMetrics(SM_CXDLGFRAME) * 2;
	int h = WIN_HEIGHT + GetSystemMetrics(SM_CYDLGFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION);

	//ウィンドウを作成
	hwnd = CreateWindowEx(
		0,
		szAppName,
		WINTITLE,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		w,								//ウィンドウ幅
		h,								//ウィンドウ高さ
		NULL,
		NULL,
		hInst,
		NULL
	);

	if(!hwnd) return FALSE;				//ウィンドウ作成失敗時の処理

	//Direct3Dオブジェクト作成
	if(!CreateD3D(hwnd)) return FALSE;	//Direct3Dオブジェクト作成失敗時の処理

	ShowWindow(hwnd,nCmdShow);			//ウィンドウを表示
	UpdateWindow(hwnd);					//ウィンドウを更新

	//レンダリングの"初期設定"
	InitRender(g_pd3ddev);

	//ゲーム作成には必須の乱数の初期設定
	srand((unsigned int)time(NULL));

	while(1){
		if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
		{
			if(!GetMessage(&msg,NULL,0,0))break;
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}else{
			GameLoop();						//画面更新処理(ゲームループ更新処理)
		}
	}
	//D3DXデバイス・オブジェクトの開放
	Release();

	return (int)msg.wParam;
}

//StarInit  初期化処理
void StartInit(void)
{
	g_FrameNo = START_UPDATE;
	OutputDebugString("StartInit関数通過。\n");
}

//StartWork  座標更新処理
void StartWork(void)
{
	//今回は何もしない
}

//StarUpdate  座標以外の更新処理
void StartUpdate(void)
{
	//今回は何もしない
}

//StartDrawBack2D  再背面2D描画処理(スクリーン座標系)
void StartDrawBack2D()
{
	//描画クリア
	g_pd3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0x40, 0x30,0x50,0x60), 1.0f, 0);

	//描画スタート
	g_pd3ddev->BeginScene();

	//
	//なんか色々描画する場所(描画順序には気をつけよう)
	//

	//描画終了
	g_pd3ddev->EndScene();

	//フリップ
	g_pd3ddev->Present(NULL, NULL, NULL, NULL);
}

//StartDraw3D  メインとなる(かも知れない)描画処理。(ワールド座標系)3D使わないんだったらいらない。
void StartDraw3D(void)
{
	//今回は何もしない
}

//StartDrawFront2D  最前面における2D描画処理(スクリーン座標系)
void StartDrawFront2D(void)
{
	//今回は何もしない
}

//StartEnd  シーン終了時の解放処理
void StartEnd(void)
{
	//ここでシーンに使用したオブジェクトの開放処理を追加

	g_FrameNo = START_INIT;

	OutputDebugString("StartEnd関数通過\n");
}

コメントはまだありません。