Mission2: Direct3D を実装する。


さて、Direct3D を実装してみよう。

【ステップ1】

 今度は、Mission1 の続きである。
 VisualC++ の画面は、以下のようになっているはずである。

【Misson1 画面】
図1 Mission1画面


【ステップ2】

 プロジェクトを改造して行く。 以下の指令に従うべし。

【ステップ2−1 ファイルのダウンロード】
解説
まず、左のリストより7つのファイルを、
mission1 プロジェクトのあるディレクトリに
ダウンロードして下さい。
ダウンロード


【ステップ2−2 ファイルをプロジェクトへ追加】
解説
ワークスペースに、
先ほどの、
  • DeviceInformation.cpp
  • DeviceInformation.h
  • d3dmain.cpp
  • d3dmain.h
  • HighResTimer.cpp
  • HighResTimer.h
を追加。
具体的には、左図の mission1ファイル という部分
を右クリック。

この様子をステップ2−3に示します。
図2 ワークスペース


【ステップ2−3 ファイルの追加その2】
解説
先ほど記したように、misson1ファイル という
部分をクリックすると、図3のような
ポップアップメニューが出てきます。

この中から、

ファイルをプロジェクトへ追加

を選びます。
図3 メニュー操作


【ステップ2−4 ファイルの追加その3】
解説
左のようにして、
DeviceInformation.cpp
DeviceInformation.h
d3dmain.cpp
d3dmain.h
HighResTimer.cpp
HighResTimer.h
の6つのファイルを選択し、OK ボタンを押すと
プロジェクトにファイルが追加されます。
図4 ファイル選択


【ステップ2−5 ライブラリのリンク】
解説
次に、「プロジェクト」メニューから
「設定」を選ぶ。

すると、ステップ2−6で説明する、図6の画面が出てきた
はずだ。

次へすすむ。
図5 設定メニュー


【ステップ2−6 ライブラリのリンク Part2】
解説
ウインドウの上部に、
"一般","デバッグ","C/C++"・・・・
といった表記があるが、「リンク」タブをクリック。

すると左の画面が出てきたはずだ、

オブジェクト/ライブラリ/モジュールという欄に、

d3d8.lib d3dx8.lib

と二つのファイル名を追加しておく。

できたら、「OK」ボタンをクリックしよう。

図6 リンカ設定


【ステップ2−7 アプリケーションの改造 Part1】
解説
ワークスペースより、"mission1.cpp"
をダブルクリックする。
すると左のような画面になったはずだ。

続いて、ファイル先頭近辺にある、

#include "stdafx.h"

の後に、

#include <d3d8.h>
#include <d3dx8.h>
#include "d3dmain.h"
の三行を書き足す。

図7 アプリケーションクラスの改造



【ステップ2−8 WinMain の改造】

mission1.cpp の中の関数 WinMain の一部に、以下のように3箇所書き足しを行う。

【変更前】

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow )
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX); 
    wcex.style            = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = (WNDPROC)WndProc;
    wcex.cbClsExtra        = 0;
    wcex.cbWndExtra        = 0;
    wcex.hInstance        = hInstance;
    wcex.hIcon            = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
    wcex.hCursor        = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
    wcex.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName    = NULL;
    wcex.lpszClassName    = "mission1";
    wcex.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);
    RegisterClassEx(&wcex);

    HWND hWnd;
    hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,wcex.lpszClassName,"Mission1",
                WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,
                CW_USEDEFAULT,0,640,480,NULL,NULL,hInstance,NULL);
    if( !hWnd )
        return FALSE;

    RECT    bounds,client;
    GetWindowRect(hWnd,&bounds);
    GetClientRect(hWnd,&client);
    MoveWindow(hWnd,bounds.left,bounds.top,
        640 * 2 - client.right,
        480 * 2 - client.bottom,
        false );

    ShowWindow( hWnd, nCmdShow );
    UpdateWindow( hWnd );

    MSG        msg;
    while(true){
        if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){
            if(msg.message == WM_QUIT)
                break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }else{
        }
    }

    return msg.wParam;
}


【変更後】

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow )
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX); 
    wcex.style            = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = (WNDPROC)WndProc;
    wcex.cbClsExtra        = 0;
    wcex.cbWndExtra        = 0;
    wcex.hInstance        = hInstance;
    wcex.hIcon            = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
    wcex.hCursor        = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
    wcex.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName    = NULL;
    wcex.lpszClassName    = "mission1";
    wcex.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);
    RegisterClassEx(&wcex);

    HWND hWnd;
    hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,wcex.lpszClassName,"Mission1",
                WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,
                CW_USEDEFAULT,0,640,480,NULL,NULL,hInstance,NULL);
    if( !hWnd )
        return FALSE;

    RECT    bounds,client;
    GetWindowRect(hWnd,&bounds);
    GetClientRect(hWnd,&client);
    MoveWindow(hWnd,bounds.left,bounds.top,
        640 * 2 - client.right,
        480 * 2 - client.bottom,
        false );

    ShowWindow( hWnd, nCmdShow );
    UpdateWindow( hWnd );

    InitD3D(hWnd);
    MSG        msg;
    while(true){
        if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){
            if(msg.message == WM_QUIT)
                break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }else{
            UpdateScreen();
        }
    }
    ReleaseD3D();

    return msg.wParam;
}

要するに赤文字の部分の三箇所を書き足すだけである。

関数 InitD3D / ReleaseD3D / UpdateScreen についてはいずれも、d3dmain.cpp の中で 定義されている関数である。

それぞれ以下の処理を行っている。

【ステップ2−9 WndProc の改造】

mission1.cpp の中の関数 WndProc を改造する。

【変更前】

LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    switch (message){
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return    0;
}


【変更後】

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

        case    WM_SIZE:
            if (SIZE_MAXIMIZED == wParam){
                ::ForceFullscreen();
            }
            break;
        case    WM_SETCURSOR:
            ::AdjustCursor();
            break;
        case    WM_SYSCHAR:
            if (lParam&0x20000000){
                if (wParam == '\x0d'){
                    ::ToggleFullscreen();
                    break;
                }
            }
            return DefWindowProc( hWnd, message, wParam, lParam );
        case    WM_SYSCOMMAND:
            if ((wParam != SC_CLOSE)&&(!IsWindowed()))
                break;
            return DefWindowProc( hWnd, message, wParam, lParam );

        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return    0;
}

要するに赤文字の部分を追加するのである。

この改造はしなくても動くのだが、これによりフルスクリーンに対応できる ようになる。



【ステップ3】

 次に、ワークスペースにリソースファイルを追加する。

【ステップ3−1 リソースの挿入 Part1】
解説
左の図のように、
「挿入」メニューより、
「リソース」を選択します。
図8 リソースの挿入


【ステップ3−2 リソースの挿入 Part2】
解説
すると図9のようなダイアログが開きます。
ここでは、「インポート」ボタンをクリック
します。
図9 リソースの挿入


【ステップ3−3 リソースのインポート】
解説
すると図10のようなダイアログが開きます。
ここではまず、「ファイルの種類」ポップアップメニュー
から、「すべて(*.*)」を選択した後、
先ほどダウンロードした、sample.bmpを
選択して、「OK」ボタンをクリックしましょう。
図10 ファイル選択


【ステップ3−4 画像データの表示】
解説
すると図11のような画面が表示されたはずです。
これで sample.bmp がインポートできました。

図11 BMP リソース


【ステップ3−5 リソースの保存 Part1】
解説
今度は図12のようにして、
「ファイル」メニューから、
「名前を付けて保存」を選びます。
図12 リソースの保存


【ステップ3−6 リソースの保存 Part2】
解説
すると、左のようなダイアログが
表示されます。

ファイル名はとりあえず、
mission1.rc とでも
しておきます。
図13 リソースの保存


【ステップ3−7 リソースをワークスペースへ登録 Part1】
解説
今度は、ワークスペースの、
「Resource Files」を右クリックします。

すると、図14のようにメニューがでてきますので、
「ファイルをフォルダに追加」を選びます。

図14 ワークスペース


【ステップ3−8 リソースをワークスペースへ登録 Part2】
解説
すると、図15のようなダイアログが
表示されますので、先ほど保存した、
「mission1.rc」を選択して、
「OK」ボタンをクリックします。

図15 ファイル選択


【ステップ3−9 リソースをワークスペースへ登録 Part3】
解説
図16のようになり、
「Resource View タブ」が表示されれば
完了です。
図16 ワークスペース


【ステップ4】

プロジェクトのビルドと実行を行う。
つまり、VisualC++ にプログラムを生成させ、実行して動作を確認する
のである。

以下の指令に従うべし。

「F・5キーを押す」

すると、下のような画面が表示されたはずだ。




これでDirectX アプリケーションができあがった。
今回はこれでおしまい。

戻る