ホーム < ゲームつくろー! < DirectX10技術編

その1 DirectX10版極短初期化プログラム


 ○×もいよいよDirectX10に突入。その1発目はやはり初期化です。
 DirectXはバージョンが上がるにつれて初期化が楽になり、Windows XPで最高のバージョンだったDirectX9では相当に短いプロセスで描画デバイスを取得できるようになりました。Windows Vistaで動作するDirectX10はDirectX9に比べると初期化に必要な設定項目が少し増えましたが、それでも割と簡単に初期化ができます。

 この章では○×恒例極短プログラムでデバイスの取得からウィンドウ表示までの初期化作業をやってみたいと思います。



@ プロジェクト設定

 プログラムを組む前に、Visual Studioのプロジェクトを設定する必要があります。DirectX10は専用のライブラリを使うため、そのライブラリへのパス指定が必要です。

 まずは空のWin32プロジェクトを作り、メニューの[ツール]→[プロジェクト]→[****のプロパティ]でプロパティーページを開きます。次に構成プロパティにあるC/C++の[全般]にある追加のインクルードディレクトリにDirectX10のインクルードファイルが格納されているフォルダパスを指定します。デフォルト設定でDirectXSDKをインストールしたならC:\program Files\Microsoft SDK(November 2007)\Includeになります(SDKのバージョンによってパスは変わりますので注意!)。
 続いてライブラリファイルへのパスも設定します。構成プロパティの[リンカー]→[全般]にある追加のライブラリディレクトリーに先のパスにあるLib/x86もしくはLib/x64を追加します。x86はWin32構成の場合(32bit Windows用)、x64はx64構成(64bit Windows用)なので注意して下さい。これでDirectX10を使用する準備は完了です。



@ DirectX10のライブラリ・ヘッダーファイル

 空のプロジェクトには何もコードが無いので、main.cppをプロジェクトに追加しましょう。取り敢えず以下の最低限の記述をします:

main.cpp
#include <Windows.h>
#include <tchar.h>

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
   return 0;
}

 DirectX10は専用ライブラリ(.lib)を使用します。どのプログラムでも以下のライブラリを読み込んでおく必要があります:

・ d3d10.lib
・ dxguid.lib

これらは必須です。また拡張ライブラリとして、

・ d3dx10.lib

を読み込んでおくと便利です。このライブラリは必須ではありません。

 d3d10.libはDirectX10のコアとなるライブラリで、ここにすべてが集約されています。d3dx10.libはプログラムを組みやすくするための拡張インターフェイス群が揃っています。d3d10.libだけでももちろんプログラム出来ますが、色々と面倒が多いためd3dx10.libの力を借りた方が良いと思います。dxguid.libはインターフェイス識別コードなど固有ID(GUID)が登録されているライブラリで、DirectX9でもお馴染みです。10でもやっぱり必要です。

 以上の必須ライブラリをプロジェクトに組み込むには2つの方法があります。一つは#pragma commentディレクティブを使う方法です:

DirectX10ライブラリ読み込み
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3d10.lib")

これをmain関数等の.cppのどこかに記載するとコンパイラがリンクしてくれます。もう一つはプロジェクトのプロパティで設定する方法です。構成プロパティの[リンカー]→[入力]にある追加の依存ファイルに上記の.libを記載します。

 拡張ライブラリにはデバッグバージョン(d3dx10d.lib)とリリースバージョン(d3dx10.lib)があります。デバッグバージョンは細かなエラー処理とエラー通知が含まれています。リリースバージョンではそれらが省略されて高速化がはかられています。気を付けたいのが、デバッグバージョンを使ったままリリースしてしまう事です。それを防ぐには次のような場合分けでライブラリの読み込みを管理します:

拡張ライブラリのターゲット別読み込み
#if _DEBUG
 #pragma comment(lib, "d3dx10d.lib")
#else
 #pragma comment(lib, "d3dx10.lib")
#endif

さらにエラーをより詳しく知るための拡張エラーライブラリとしてdxerr.libを読み込んでおくと何かと助かります。

 続くヘッダーファイルですが、DirectX10とWindows固有のヘッダーを定義する必要があります。次の通りです:

ヘッダーファイル
#include <windows.h>
#include <tchar.h>
#include <d3d10.h>
#include <d3dx10.h>
#include <dxerr.h>

d3d10.hとd3dx10.hはそれぞれのライブラリに対応したヘッダーです。



A ウィンドウの作成

 DirectX10もDirectX9と同様にWindows APIでウィンドウを作成する必要があります。これは割とメンドクサイのですが、○×ではProgramming TIPs編に「ここまでできる超極短Windows基盤プログラム」として超短いウィンドウ表示プログラムを紹介しております。ここではそれをちょっとだけ改良して使用します:

ウィンドウを表示する極短コード
TCHAR gName[] = _T("DirectX10極短初期化サンプルプログラム");

LRESULT CALLBACK WndProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam){
   if(mes == WM_DESTROY || mes == WM_CLOSE) {PostQuitMessage(0); return 0;}
   return DefWindowProc(hWnd, mes, wParam, lParam);
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
   MSG msg; HWND hWnd;
   WNDCLASSEX wcex ={sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance,
         NULL, NULL, (HBRUSH)(COLOR_WINDOW+1), NULL, (TCHAR*)gName, NULL};
   if(!RegisterClassEx(&wcex)) return 0;

   if(!(hWnd = CreateWindow(gName, gName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,
         CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL)))
      return 0;

   // ここでDirectX10の初期化をします //

   ShowWindow(hWnd, nCmdShow);

   // メッセージ ループ
   do{
      if( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ){ DispatchMessage(&msg);}
      else{
             // ここでDirectX10の描画処理 //
      }
   }while(msg.message != WM_QUIT);

   return 0;
}

 細かい意味については先のリンク先に詳しく説明がありますのでご参照下さい。DirectX10を動作させるには描画先のウィンドウを表すウィンドウハンドル(HWND)が必要です。



B 初期化の1歩目:描画デバイスとスワップチェインの作成

 ここからいよいよDirectX10の初期化です。ウィンドウハンドルを取得した後、メインとなる幾つかのインターフェイスを取得します。DirectX9の時にはIDirect3D9という統括インターフェイスを得てからD3DPRESENT_PARAMETERS構造に必要な情報を登録してIDirect3DDevice9という描画デバイスを得ていました。DirectX10ではこの仕組みは無くなり、新しい初期化方法が採用されています。

 DirectX10では描画デバイスであるID3D10Device(DirectX9に慣れている方は名前に注意です)に加えて「スワップチェイン(IDXGISwapChain)」というインターフェイスも作成する事になりました。DirectX9ではバックバッファなどのバッファ管理やそれに書き込むための描画指示は描画デバイスが全部担っていましたが、DirectX10になって描画指示はID3D10Device、描画先となるバッファの管理はIDXGISwapChainと描画に関する仕事が明確に分離されるようになりました。


【トピック】
 なぜ描画デバイスとスワップチェーンに分離したのか?
 端的に言うとマルチスレッドへの対応を容易にするためと考えられます。DirectX9の時は最初にIDirect3DDevice9::Beginメソッドを呼び出し描画デバイスへ描画指示を与えた後Endメソッドで終了宣言をしてからPresentメソッドで実際に描画を走らせていました。一つのインターフェイスが描画指示(描画の順番をリスト化する事)と描画処理(描画リストを元に実際に描画パイプラインを通して描画する事)を担っていたため、双方を分離する事がやや難しい状態でした。
 DirectX10になって描画指示はID3D10Device、描画処理はIDXGISwapChainがそれぞれ分担する事になり、ID3D10Deviceを通して積み上げた描画リストをIDXGISwapChainに投げると勝手に描画してくれる…という分かりの良い分業が成せるようになりました。IDXGISwapChain側を別スレッドで回しておけば、描画更新されている間に新しい描画リストを作成する事が出来ます。結果として待ち時間を有効活用できパフォーマンスを向上させる事につなげられます。同様の事はDirectX9でも出来るのですが、よりやりやすくなったという事です。
 この描画デバイスとスワップチェインの分離は以後のDirect3D11、Direct3D12でも継承されていく事になります。

 2つの描画関連インターフェイスを取得するにはD3D10CreateDeviceAndSwapChain関数を用います:

D3D10CreateDeviceAndSwapChain関数
HRESULT D3D10CreateDeviceAndSwapChain(
   IDXGIAdapter         *pAdapter,
   D3D10_DRIVER_TYPE    DriverType,
   HMODULE              Software,
   UINT                 Flags,
   UINT                 SDKVersion,
   DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,
   IDXGISwapChain       **ppSwapChain,
   ID3D10Device         **ppDevice
);

 沢山変数があります。
 pAdapterにはディスプレイアダプタ(要はビデオカード)を表すIDXGIAdapterインターフェイスを渡します。これはビデオカードを2枚差している場合などにどちらかのビデオカードを指定する場合などに使います。普通はプライマリビデオカードで良いのでNULLで構いません。
 DriverTypeには描画をハードウェアで行う(D3D10_DRIVER_TYPE_HARDWEAR)かソフトウェアで行う(D3D10_DRIVER_TYPE_REFERENCE)かを指定します。サポート環境を仮定するならD3D10_DRIVER_TYPE_HARDWEARですね。
 SoftwareにはDriverTypeにD3D10_DRIVER_TYPE_SOFTWAREというフラグを立てた時に必要なソフトウェアラスタライザ(点打ち屋さん)のDLLを指定します。DirectX10ではこのフラグは立てられないので、Softwareも使いません。NULLでOKです。
 FlagsはDirect3D10(コア)が使うAPIの種類や使い方を決めます。デフォルト(ハードウェアAPI)
で良いなら0で構いません。D3D10_CREATE_DEVICE_SINGLETHREADEDにするとシングルスレッドAPIになります。DirectXはスレッドセーフなマルチスレッドをサポートしているのでこれを指定する事はあまりありません。D3D10_CREATE_DEVICE_DEBUGにするとデバッグや妥当性検証が入ったAPIが使われます。デバッグ環境ではより詳細なエラー情報が得られます。D3D10_CREATE_DEVICE_SWITCH_TO_REFにするとハードウェアAPIとリファレンスAPIとが切り替わる環境になります。これはデバッグする時に役立ちます。
 SDKVersionにはDirectXのSDKバージョンを渡します。これはよほどの理由が無い限りはD3D10_SDK_VERSIONにして下さい(マニュアルにはD3D_SDK_VERSIONと記載されていますがミスプリです、多分)。
 pSwapChainDescにはスワップチェインの能力を登録したDXGI_SWAP_CHAIN_DESC型の変数へのポインタを渡します。これについては後述します。
 関数が成功するとppSwapChainppDeviceにそれぞれスワップチェインと描画デバイスが返ります。


 以上を見ると、殆どがデフォルト値で良い事がわかります。典型的な設定例は例えば次のようになりそうです:

D3D10CreateDeviceAndSwapChain関数の設定例
DXGI_SWAP_CHAIN_DESC SwapChainDesc;
// SwapChainDescを設定したとします・・・

if ( FAILED( D3D10CreateDeviceAndSwapChain( 0, D3D10_DRIVER_TYPE_HARDWEAR, 0, 0, D3D10_SDK_VERSION, &SwapChain_Desc, &pSwapChain, &pDev ) ) )
   return false;

DirectX10はビデオカードの能力の一定性が保証されていますので、デバイスの作り方に場合分けをする必要が殆どなくなりました。D3D10CreateDeviceandSwapChain関数が成功すると、自動的にバックバッファが作成されます。

 気になるDXGI_SWAP_CHAIN_DESC構造体については次の節で説明します。



C 初期化の2歩目:DXGI_SWAP_CHAIN_DESC構造体

 先の構造体はスワップチェインの能力を指定します。具体的に見てみましょう:

DXGI_SWAP_CHAIN_DESC構造体
typedef struct DXGI_SWAP_CHAIN_DESC {
   DXGI_MODE_DESC    BufferDesc;
   DXGI_SAMPLE_DESC  SampleDesc;
   DXGI_USAGE        BufferUsage;
   UINT              BufferCount;
   HWND              OutputWindow;
   BOOL              Windowed;
   DXGI_SWAP_EFFECT  SwapEffect;
   UINT              Flags;
} DXGI_SWAP_CHAIN_DESC;

 BufferDescにはバックバッファの能力を表すDXGI_MODE_DESC構造体を指定します。後述しますが例えばバックバッファの幅とか高さ、フォーマットなどが入ります。
 SampleDescにはマルチサンプリングの能力を表すDXGI_SAMPLE_DESC構造体を指定します。マルチサンプルというのは、ざっくり言えば「アンチエイリアス」の事です。これを高く設定するほどジャギが消えて見えますが、処理負荷は高くなってしまいます。この構造体にはDXGI_SAMPLE_DESC::CountとDXGI_SAMPLE_DESC::Qualityの2つのメンバがあります。Countには1ピクセルの色を決めるためのサンプリング数、Qualityには精度レベルを指定します。精度レベルはビデオカードによってサポートが異なるためID3D10Device::CheckMultisampleQualityLevelsメソッドが返す値以下にしなければなりません。面倒ならばマルチサンプルをしないCount=1、Quality=0に設定して構いません。
 BufferUsageにはバックバッファの使用制限についてのフラグをDXGI_USAGE列挙型で指定します。DirectX10からバックバッファのハードウェア制限がゆるくなりアクセス権が広がりました。例えばシェーダの入力に使えるようにするにはDXGI_USAGE_SHADER_INPUTを指定します。シェーダの出力に使えるようにするにはDXGI_USAGE_RENDER_TARGET_OUTPUTなどが指定されます。
 BufferCountにはスワップ(交換)するバッファの枚数を指定します。通常は1枚ですが沢山持たせることもできます。
 OutputWindowには出力先のウィンドウハンドルを指定します。これはお馴染みですね。
 Windowedにはウィンドウモード(true)かフルスクリーンモード(false)かのフラグを指定します。
 SwapEffectにはスワップ方法をフラグで指定します。通常は単純なスワップを実行するDXGI_SWAP_EFFECT_DISCARDで構いません。
 Flagsにはスワップチェインの付加能力を指定します。重要なのはDXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCHです。このフラグを指定するとフルスクリーン⇔ウィンドウモードの切り替えができるようになり、切り替え時のあれやこれやを自動的に行ってくれます。


 バックバッファの能力をまとめたBufferDesc構造体を次に見てみましょう:

DXGI_MODE_DESC構造体
typedef struct DXGI_MODE_DESC {
   UINT                       Width;
   UINT                       Height;
   DXGI_RATIONAL              RefreshRate;
   DXGI_FORMAT                Format;
   DXGI_MODE_SCANLINE_ORDER   ScanlineOrdering;
   DXGI_MODE_SCALING          Scaling;
} DXGI_MODE_DESC, *LPDXGI_MODE_DESC;

 WidthHeightはバックバッファの幅と高さを指定します。
 RefreshRateはいわゆるリフレッシュレートをDXGI_RATIONAL構造体で指定します。この構造体はDXGI_RATIONAL::NumeratorとDXGI_RATIONAL::Denominatorの2つのメンバを持っていて、例えば60フレームにしたい場合はNumerator=60、Denominator=1と指定します。
 FormatはバックバッファのフォーマットをDXGI_FORMATで指定します。これはマニュアルをご覧になると分かると思いますがたっっっくさんあります!!!DirectX10時代の標準である浮動小数点テクスチャを指定する場合は例えばDXGI_FORMAT_R16G16B16A16_FLOAT(64bit浮動小数点テクスチャ)などと指定します。
 ScanlineOrderingにはスキャンラインの方法、つまりバックバッファをフリップした時にハードウェアがパソコンのモニターに点をどう描くかを指定します。プログレッシブとかインターレスなど選択が可能ですが、特段理由が無ければ0でOKです。
 Scalingはバックバッファの絵を描画する時にウィンドウの大きさにスケーリングするかどうかを指定します。バックバッファの大きさを遵守するならDXGI_MODE_SCALING_CENTERED、ウィンドウサイズに引き伸ばすならばDXGI_MODE_SCALING_STRETCHEDを指定します。ゲームにもよりますが、引き伸ばしはあまりしない方が良いかなと思いますのでDXGI_MODE_SCALING_CENTEREDを指定しても良いかなと思います。


 中々沢山の設定項目があり大変ですが、典型的な設定例を以下に示します:

DXGI_SWAP_CHAIN_DESC構造体の設定例
DXGI_SWAP_CHAIN_DESC SwapChainDesc;
SwapChainDesc.BufferDesc.Width = 800;
SwapChainDesc.BufferDesc.Height = 600;
SwapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
SwapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
SwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT;
SwapChainDesc.BufferDesc.ScanlineOrdering = 0;
SwapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
SwapChainDesc.SampleDesc.Count = 1;
SwapChainDesc.SampleDesc.Quality = 0;
SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
SwapChainDesc.BufferCount = 1;
SwapChainDesc.OutputWindow = hWnd;
SwapChainDesc.Windowed = true;      // ウィンドウモード
SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
SwapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

これをD3D10CreateDeviceAndSwapChain関数に渡せばOKです。



D 初期化の3歩目:レンダーターゲットビューの生成

 DirectX9には無かった概念として、DirectX10には「ビュー」というのが追加されました。これはバッファの属性を表します。バッファは極論すれば単なるメモリブロックです。私達が数字の羅列を見ても何のことやらと思うのと一緒で、プログラムも単なる数字の羅列をそのままでは解釈できません。そこでビューを用いて単純なメモリブロックであるバッファに対して意味を与えてあげます。
 スワップチェインには描画先であるバックバッファが作成されています。しかしそれは単純なメモリブロックに過ぎません。このバックバッファに対して「あなたはレンダーターゲット(描画専用のメモリ)ですよ」と意味付けする事で初めてバックバッファをレンダーターゲットとして扱えるようになります。この意味付けの役を担うのがレンダーターゲットビューです。レンダーターゲットビューを作成するにはID3D10Device::CreateRenderTargetViewメソッドを用います:

ID3D10Device::CreateRenderTargetViewメソッド
HRESULT CreateRenderTargetView(
   ID3D10Resource                         *pResource,
   const D3D10_RENDER_TARGET_VIEW_DESC    *pDesc,
   ID3D10RenderTargetView                 **ppRTView
);

pResouceにはビューに関連付けるリソースであるID3D10Resouceインターフェイスへのポインタを渡します。
pDescには描画ターゲットビューの能力をD3D10_RENDER_TARGET_VIEW_DESC構造体で指定します。この中で指定しているのは3つ、フォーマット、ビューの次元(1Dテクスチャの配列など)そしてリソースの使い方を表す構造体群です。かなりややこしい部分なのですが、今回のような2Dバッファの時に限りここにNULLが指定できます。
関数が成功するとppRTViewに描画ターゲットビューインターフェイスへのポインタが返ります。


 バックバッファは2DなのでpDescに何も指定しなくても描画ターゲットビューインターフェイスが取得できます。

 肝心のバックバッファはIDXGISwapChainが持っているGetBufferメソッドで取得できます:

スワップチェインが持つバックバッファをレンダーターゲットとして意味付け
ID3D10Texture2D *pBackBuffer;
ID3D10RenderTargetView *pRenderTargetView;

pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID*)&pBackBuffer );
pDev->CreateRenderTargetView( pBackBuffer, NULL, &pRenderTargetView );

pBackBuffer->Release();

 IDXGSwapChain::GetBufferメソッドの第2引数が見慣れない感じですが、ここにはバックバッファのインターフェイスのGUIDを渡します。そのために__uuidofキーワードを使いID3D10Texture2Dを表すGUID(グローバルユニークID)を得ます。お決まりだと思って構いません。メソッドが成功すれば第3引数にバックバッファが戻ります。
 続いてIDirect3D10Device::CreateRenderTargetViewメソッドでレンダーターゲットビューを作成し、「バックバッファをレンダーターゲットとして扱う」という意味付けを行います。
取得したバックバッファに対してReleaseメソッドを呼び出していますが、これは必須ではありません。ただここで呼び出しておくとスワップチェインが破棄された時にバックバッファも破棄されるため寿命管理について気にしなくて済みます。もし呼び出さないなら、スワップチェインを破棄する前に必ずReleaseメソッドを呼ぶ必要があります。GetBufferメソッドを呼び出した時にCOM参照カウンタが一つ増えるため、その寿命の管理に気を付ける必要があります。

 ここで意味付けしたレンダーターゲットビューを描画デバイスに設定すると描画先がバックバッファーに切り替わります:

描画先をバックバッファに設定
pDev->OMSetRenderTargets( 1, &pRenderTargetView, 0 );

描画先を常にバックバッファにするなら初期化時に設定してしまって構いません。描画先をテクスチャにするなど切り替える場合は描画時に都度差し替える必要があります。

これで描画先の初期化ができました。最後に描画の範囲を決めるビューポートの設定が必要になります。



E 初期化の4歩目:ビューポートの設定

 ビューポートというのは単純には「描画範囲」を表します。内部的には射影変換された頂点をスクリーン座標に変換するための行列です。DirectX9ではデフォルトのビューポートが内部設定されていたため、ビューポートについて殆ど意識する事はありませんでした。しかしDirectX10では初期化時にビューポートは何も設定されていません(単位行列だと思いますが)ので、初期化時に設定する必要があります。

 ビューポートの設定は殆どお決まりです。ざっと見てみましょう:

ビューポート行列の設定
D3D10_VIEWPORT vp;
vp.Width = 800;
vp.Height = 600;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
pDev->RSSetViewports( 1, &vp );

D3D10_VIEWPORT構造体に対して各種値を設定して描画デバイスに設定しているだけです。変える部分があるとすればWidthとHeightです。これはスクリーンサイズを設定する部分ですが、普通はバックバッファの大きさに合わせます。凝った事をしないならば機械的に設定して良い部分です。これでようやくバックバッファに何かを描画する所までたどり着きました。

 起動時に行う初期化としてはここまでが一区切りかなと思います。以上を踏まえて、○×恒例の超極短初期化プログラムを作成してみます。



F 終了処理

 DirectX10での終了処理の殆どは確保したインターフェイスを解放するだけですが、もう1つ描画デバイスの状態をクリアします。これにはID3D10Device::ClearStateメソッドを呼び出します:

描画デバイスのクリア
pDev->ClearState();



G 超極短初期化プログラム

 @〜Fまでを考慮して、ウィンドウを作成してから描画準備が出来るまでの極短プログラムは次のようになりました:

極短初期化プログラム
// DirectX10極短初期化サンプルプログラム

#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3d10.lib")
#if _DEBUG
   #pragma comment(lib, "d3dx10d.lib")
#else
   #pragma comment(lib, "d3dx10.lib")
#endif
#pragma comment(lib, "dxerr.lib")

#include <windows.h>
#include <tchar.h>
#include <dxerr.h>
#include <d3d10.h>
#include <d3dx10.h>

_TCHAR gName[] = _T("DirectX10極短初期化サンプルプログラム");

// ウィンドウプロシージャ
LRESULT CALLBACK WndProc( HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam ) {
   if( mes == WM_DESTROY || mes == WM_CLOSE ) { PostQuitMessage( 0 ); return 0; }
   return DefWindowProc( hWnd, mes, wParam, lParam );
}

int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow )
{
   MSG msg; HWND hWnd;
   WNDCLASSEX wcex = { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, NULL, NULL,
         (HBRUSH)(COLOR_WINDOW+1), NULL, (_TCHAR*)gName, NULL };
   if( !RegisterClassEx( &wcex ) )
      return 0;

   if( !( hWnd = CreateWindow( gName, gName, WS_OVERLAPPEDWINDOW & ~( WS_MAXIMIZEBOX | WS_SIZEBOX ),
         CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInstance, 0) ) )
      return 0;

   DXGI_SWAP_CHAIN_DESC SwapChainDesc =
      { { 800, 600, {60, 1}, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED, DXGI_MODE_SCALING_CENTERED},
         {1, 0}, DXGI_USAGE_RENDER_TARGET_OUTPUT, 1, hWnd, true, DXGI_SWAP_EFFECT_DISCARD, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
      };

   ID3D10Device* pDev;
   IDXGISwapChain* pSwapChain;
   if( FAILED( D3D10CreateDeviceAndSwapChain( 0, D3D10_DRIVER_TYPE_HARDWARE, 0, 0, D3D10_SDK_VERSION, &SwapChainDesc, &pSwapChain, &pDev ) ) )
      return 0;

   ID3D10Texture2D *pBackBuffer;
   ID3D10RenderTargetView *pRenderTargetView;
   pSwapChain->GetBuffer( 0, __uuidof(ID3D10Texture2D), (void**)&pBackBuffer );
   if ( FAILED ( pDev->CreateRenderTargetView( pBackBuffer, 0, &pRenderTargetView ) ) ) {
      pSwapChain->Release(); pDev->Release();
      return 0;
   };
   pDev->OMSetRenderTargets( 1, &pRenderTargetView, 0 );
   pBackBuffer->Release();

   D3D10_VIEWPORT vp = { 0, 0, 800, 600, 0.0f, 1.0f };
   pDev->RSSetViewports( 1, &vp );

   ShowWindow( hWnd, SW_SHOW );

   do{
      if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){ DispatchMessage( &msg ); }
      else {
         // DirectX10の処理 //
         float ClearColor[4] = { 0.0f, 0.125f, 0.6f, 1.0f }; // RGBA
         pDev->ClearRenderTargetView( pRenderTargetView, ClearColor );
         pSwapChain->Present( 0, 0 );
      }
   }while( msg.message != WM_QUIT );

   pDev->ClearState();
   pRenderTargetView->Release();
   pDev->Release();
   pSwapChain->Release();

   return 0;
}


 このプログラムはコピペして直ぐに使えます。実行してブルーバックのウィンドウが出れば成功です。


 DirectX10の初期化はDirectX9よりも少しボリュームが増えました。これはそれだけゲームを作るのに多くの事が必要になってきた事を意味していると思います。ゲームプログラムを初めて作る方にとってはちょっと敷居が高いライブラリですが、最新の環境にいち早く慣れるのは悪い事ではありません。ただ楽に3Dゲームを気軽に作りたいという方はDirectX9を選んだ方が良いかもしれません。
 
 私もまだ始めたばかりですが、今後楽しみながら少しずつ章を増やしていきます。どうぞ気長にお待ち下さい(^-^;。