Up

DirectX 10 /Visual C++ 2010 試用記

 

 DirectX10を使って図1のようなウィンドウを表示するプログラムをVisual C++2010で作成してみた(他のバージョン、Visual C++ 2008Visual C++11 Betaでも同様である)。

図1

 

プログラム・ソース・コードを以下に示す。このプログラムの新規作成方法は本ウェブサイトの後半で説明する。

DirectXの個々の関数の説明はVisual C++のヘルプから得ることができる。DirectXは、マイクロソフト社のウェブサイト

http://msdn.microsoft.com/ja-jp/directx/default.aspx

からダウンロード・インストールすることができる。インストール後、Windowsのスタートメニュから

Microsoft DirectX SDK (June 2010) | DirectX Documentation for C++

を選んで起動すると、DirectXについての説明(ドキュメント)が表示される。

======================================================

#include <windows.h>

#include <tchar.h>

#include <d3d10.h>                      //              DirectX用: ディレクトリーの設定(このサイトの後半で説明)の必要あり

#include <d3dx10.h>                     //              DirectX用: ディレクトリーの設定の必要あり

 

HWND hMnWnd;

 

int width = 500;                                //              ウィンドウの幅

int height = 300;                               //              ウィンドウの高さ

ID3D10Device * pD3Dvc = NULL;

IDXGISwapChain * pswChn = NULL;

ID3D10RenderTargetView * pRndrTgtVw = NULL;

ID3DX10Font * pfnt = NULL;

 

//

//                      コールバック関数

//

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){

        switch(msg){

                case WM_KEYDOWN: MessageBox(hWnd, "キーが押されました。\n終了します。", "Good-by !", MB_OK);;

                case WM_DESTROY: PostQuitMessage(0);            //              WM_QUITメッセージの送出

                                                 break; ;

                default:        ;

        }

        return DefWindowProc(hWnd, msg, wParam, lParam);

}

 

 

//

//              DirectXの後始末

//

void ClearDX(){

        if (pfnt != NULL) pfnt->Release();

        if (pRndrTgtVw != NULL) pRndrTgtVw->Release();

        if (pswChn != NULL) pswChn->Release();

        if (pD3Dvc != NULL) pD3Dvc->Release();

}

 

 

//

//                              メイン関数

//

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow){

        /***************************************

 

                Windowsの準備

 

        ****************************************/

 

        //                      ウィンドウの設定

        WNDCLASSEX wc;

        wc.cbSize                       = sizeof(WNDCLASSEX);

        wc.style                        = CS_HREDRAW | CS_VREDRAW;

        wc.lpfnWndProc          = (WNDPROC)WndProc;                     //              コールバック関数の登録;  DispatchMessage(&msg) の実行でmsgを受け取り、処理する。

        wc.cbClsExtra           = 0;

        wc.cbWndExtra           = 0;

        wc.hInstance            = hInstance;

        wc.hIcon                        = 0;

        wc.hCursor                      = LoadCursor(NULL, IDC_ARROW);

        wc.hbrBackground        = (HBRUSH)(COLOR_WINDOW+1);

        wc.lpszMenuName         = NULL;

        wc.lpszClassName        = "SimpleExample";

        wc.hIconSm                      = 0;

       

        if (! RegisterClassEx(&wc) ) return false;

 

        RECT rect = {0, 0, width, height};

        AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);

 

        //

        //                      Windowの作成と表示

        //

        hMnWnd = CreateWindow(  "SimpleExample", "Simple Example",

                                                        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,

                                                        rect.right - rect.left,

                                                        rect.bottom - rect.top,

                                                        NULL, NULL,

                                                        hInstance, NULL);

 

        if (!hMnWnd) return false;

 

        ShowWindow(hMnWnd, SW_SHOW);

        UpdateWindow(hMnWnd);

 

 

        /***********************************************

 

                DirectXの初期化

 

        ************************************************/

       

        //

        //              ダブル・バッファリングの設定

        //

        DXGI_SWAP_CHAIN_DESC swChn;

        ZeroMemory(&swChn, sizeof(swChn));

 

        swChn.BufferCount                                                       = 1;

        swChn.BufferDesc.Width                                          = width;

        swChn.BufferDesc.Height                                         = height;

        swChn.BufferDesc.Format                                         = DXGI_FORMAT_R8G8B8A8_UNORM;

        swChn.BufferDesc.RefreshRate.Numerator                          = 60;

        swChn.BufferDesc.RefreshRate.Denominator                                = 1;

        swChn.BufferUsage                                                       = DXGI_USAGE_RENDER_TARGET_OUTPUT;

        swChn.OutputWindow                                                      = hMnWnd;

        swChn.SampleDesc.Count                                          = 1;

        swChn.SampleDesc.Quality                                                = 0;

        swChn.Windowed                                                  = TRUE;

       

        HRESULT hr = D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_HARDWARE,            //      ハードウェア(GPU)使用

                                                NULL, 0, D3D10_SDK_VERSION,

                                                &swChn, &pswChn, &pD3Dvc);

        if (FAILED(hr)){

                hr = D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_REFERENCE,           //      エミュレーション使用

                                                NULL, 0, D3D10_SDK_VERSION,

                                                &swChn, &pswChn, &pD3Dvc);

                if (FAILED(hr)) {

                        MessageBox(hMnWnd, "Some error in InitDirect3D.", "Error", MB_OK);

                        ClearDX();

                        return false;

                }

        }; 

 

        ID3D10Texture2D * pBBffr;

        hr = pswChn->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBBffr);

        if (FAILED(hr)){

                ClearDX();     

                return false;

        }

 

        hr = pD3Dvc->CreateRenderTargetView(pBBffr, NULL, &pRndrTgtVw);

        pBBffr->Release();

        if (FAILED(hr)){

                ClearDX();

                return false;

        }

 

        pD3Dvc->OMSetRenderTargets(1, &pRndrTgtVw, NULL);

 

        D3D10_VIEWPORT vwPort;

        vwPort.Width            = width;

        vwPort.Height           = height;

        vwPort.MinDepth         = 0.0;

        vwPort.MaxDepth         = 1.0;

        vwPort.TopLeftX         = 0;

        vwPort.TopLeftY         = 0;

        pD3Dvc->RSSetViewports(1, &vwPort);

 

        hr = D3DX10CreateFont(pD3Dvc, 70, 0, FW_BOLD, 1, FALSE,DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,

                                DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "MS 明朝", &pfnt);

        if (FAILED(hr)){

                ClearDX();

                return false;

        }

       

        //

        //                      描画

        //

        if (pD3Dvc != NULL){

                pD3Dvc->ClearRenderTargetView(pRndrTgtVw, D3DXCOLOR(0.0, 0.0, 0.5, 0.0));

                //

                //              描画位置をrctに設定

                //

                RECT rct;

                SetRectEmpty(&rct);

                //              描画文字列の大きさの取得

                pfnt->DrawText(NULL, "こんにちは", -1, &rct, DT_CALCRECT | DT_LEFT, D3DXCOLOR(1.0, 1.0, 1.0, 1.0));

                //              rctの設定

                int rct_w = rct.right - rct.left;

                int rct_h = rct.bottom - rct.top;

                rct.top = (height - rct_h) / 2;

                rct.left = (width - rct_w) / 2;

                rct.bottom = rct.top + rct_h;

                rct.right = rct.left + rct_w;

                //              文字列の描画

                pfnt->DrawText(NULL, "こんにちは", -1, &rct, DT_LEFT, D3DXCOLOR(1.0, 1.0, 1.0, 1.0));

 

                pswChn->Present(0, 0);

        }

 

       

        //

        //                      WM_QUITメッセージを受け取るまでループ; 

        //                      コールバック関数内で PostQuitMessage(0) が実行されるとWM_QUITメッセージが送出される。;

        //

        MSG msg = {0};

        while (msg.message != WM_QUIT){

                while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){

                        TranslateMessage(&msg);

                        DispatchMessage(&msg);                  //     msgがコールバック関数に渡されて処理される。

 

                }

        }

 

        ClearDX();              //              DirectXの後始末

 

        return (int)msg.wParam;

}

 

======================================================

 上のプログラムをWindowsアプリケーションとして新規作成するときは以下の手順で行う。まず、「ファイル|新規作成|プロジェクト」を選ぶ(図2)。

図2

 

「新しいプロジェクト」ダイアログウィンドウが表示されるので、「Visual C++|全般」をクリックして選ぶ(図3)。

図3

 

Visual C++」の下に「全般」が表示されていないときは、「Visual C++」の左の白い横向き3角形をクリックすると表示される。「空のプロジェクト」を選び、「名前」、「場所」、「ソリューション名」を適当に設定する。「場所」として設定したフォルダの下にソリューション名のフォルダ、その下に「名前」で設定したプロジェクト名のフォルダが作成される。「名前」で設定した文字列が「ソリューション名」にも設定されるが、このソリューション名は他のものに設定し直すことができる。これらについては<岡本安晴「大学生のための心理学VC++プログラミング入門」勁草書房、第0章「はじめに」>などを参照されたい。

OK」ボタンをクリックすると図4の画面になる(図4のウィンドウはドラッグして小さくしてある)。

図4

 

メニュ「プロジェクト|新しい項目の追加」を選ぶ(図5)。

図5

 

表示された「新しい項目の追加」ダイアログボックスから「C++ファイル(.cpp)」を選び、名前を適当に設定する(図6)。「C++ファイル(.cpp)」が中央のリストにないときは、左の「インストールされたテンプレート」から「Visual C++」あるいは「Visual C++ | コード」を選んでクリックすると中央のリストに「C++ファイル(.cpp)」が表示される。左の「Visual C++」の下に項目が表示されていないときは、左に白い三角形が表示されているので、それをクリックすると白い三角形は黒の三角形になり、図6のように「Visual C++」の下に項目が表示される。

図6

 

名前の設定後、「追加」ボタンをクリックすると図7の画面になる。図6で設定した名前のファイルがエディタで表示されている。

図7

 

 

 

図3において「空のプロジェクト」を選んだのは、Windowsアプリケーション用の簡単なメイン関数を用意するためである。

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

がメイン関数頭部である

図7のエディタ内に、上のサンプルプログラムのソースコードを打ち込んでいく。このウェブサイトのテキストをコピー・貼り付けしてもよいが、行間隔が不自然になる場合がある。しかし、プログラムとしては問題ない。

ソースコードを打ち込んでいくときは、まず、以下のインクルード「#include」を書き込み、

#include <windows.h>

#include <tchar.h>

#include <d3d10.h>                     

#include <d3dx10.h>    

DirectXのヘッダーファイル「d3d10.h」と「d3dx10.h」の存在するディレクトリーの設定を行う。インクルードされているヘッダーファイルの設定をしておくと、エディタにコードを打ち込んでいくときにコード支援機能が働くので便利である。

インクルードされるヘッダーファイル(ただし、名前が<>で挟まれているもの)用のディレクトリー設定は以下のように行う。

プロジェクト名がマークされていることを確認する(図8)。マークされていないときはクリックしてマークする。

図8

 

メニュ「プロジェクト|プロパティ」を選ぶ(図9)。

図9

 

「プロパティページ」ダイアログボックスが表示される(図10)。

図10

 

C/C++」の下の欄の「全般」をクリックしてマークする。「C/C++」の下位の項目が表示されていないときは、「C/C++」の左に横向きの白い三角形が表示されているので、それをクリックすると下位の項目が表示される。右下向きの黒い三角形をクリックすると下位の項目リストは閉じられる。

「追加のインクルードディレクトリ」の欄をクリックすると、右端に三角形の印の付いたボタンが表示される(図11)。

図11

 

この右端に現れたボタンをクリックすると<編集>と表示されたセルが表示される(図12)。

図12

 

「<編集>」の所をクリックすると、「追加のインクルードディレクトリ」ダイアログボックスが表示される(図13)。

図13

 

図13の赤で囲んだ左端のボタンをクリックすると図14のように「」印のボタンが表示される。

図14

 

」印のボタンをクリックすると「ディレクトリの選択」ダイアログボックスが表示される(図15)。

図15

 

DirectXのヘッダーファイルのあるディレクトリーを設定する。図15は筆者のPCの場合である。「フォルダーの選択」ボタンをクリックすると図16のフォームになる。

図16

 

OK」ボタンをクリックすると図17のフォームになる。

図17

 

「適用」ボタンをクリックした後、「OK」ボタンをクリックする。

ヘッダーファイル用のディレクトリーの設定に続いて、リンク時にリンクされるライブラリーの設定を行う。このために、メニュ「プロジェクト|既存項目の追加」を選ぶ(図18)。

 

 

図18

 

「既存項目の追加」ダイアログボックスが表示される(図19)。

 

図19

 

上のサンプルプログラムの場合は「d3d10.lib」と「d3dx10.lib」を追加すればよいが、すべてを選んで追加してもよい。DirectXのそれぞれの関数に必要なライブラリーとヘッダーファイルは、Visual C++のヘルプで当該の関数の説明を見ると、最後の方に示されている。必要なファイルを選んだら「追加」ボタンをクリックする。追加したファイルが、ソリューション エクスプローラに「外部依存関係」として表示される(図20)。

図20

 

これで、ソースコードをすべて書き込めば、ビルド・実行できる。

 

上のソースコードなどをソリューションファイルとしてまとめたものは、圧縮ファイルSimpleSample.zipとして用意した。圧縮ファイル名SimpleSample.zipをクリックしてダウンロードすることができる。ダウンロードしたファイルをマウスの右ボタンでクリックして表示されるメニュから「解凍」あるいは「展開」を選んで解凍すれば、Visual C++2010で開く事が出来る。ただし、このファイルのプログラムは、筆者のPCに合わせてインクルードファイルのディレクトリーとライブラリーの追加が行われているので、読者が利用するときには、自分のPCに合わせて設定しなおす必要がある。PCの構成が筆者のものと異なる場合は、インクルードファイルのディレクトリーと追加ライブラリーの設定をまず消去しておかなければならない。残しておくと、コンパイラあるいはリンカーがそのようなファイルはないというエラーメッセージを出す。

 

プログラムを実行すると図1のウィンドウが表示される。キーボードのキーを押すと、メッセージボックスが表示され、「OK」ボタンのクリック(あるいは、Enterキーの押下)で、ウィンドウは消えてプログラムの実行終了となる。

 

なお、既にあるヘッダーファイルやソースコードファイルを利用するときは、プログラムと同じフォルダにコピー後、メニュ「プロジェクト|既存項目の追加」を選んでプロジェクトに追加する必要があるが、このことは<岡本安晴「大学生のための心理学VC++プログラミング入門」勁草書房p. 139>でも説明している。このウェブサイトからダウンロードしたプログラムSimpleSample.zipのソースコードファイルSimpleSample.cppVisual C++ 2008Visual C++ 11 で利用するときは、まず空のプロジェクトを作成する。その後、ソースコードファイルをプロジェクトディレクトリーにコピーし、プロジェクトに「既存項目」の追加として加え、インクルードディレクトリーとライブラリーの追加の設定を行えばよい。

 

Up