Mission7: 文字、点および線を描画する。


【ステップ1 プログラム改造】

テクスチャを使わずに文字、点および線の描画を行うプログラムを作ります。

【ステップ1−1 フォント生成】
解説

ワークスペース(左図の部分)から、
d3dmain.cpp をダブルクリックして開きます。

すると画面は、図2の様になったはずです。
図1 ワークスペース


図2 d3dmain.cpp



次に、図3のようにして編集メニューから検索コマンドを選びます。

すると、図4のようなダイアログウィンドウが出てきます、

ここでは、RestoreDeviceObjects というキーワードで検索を実行。

すると、リスト1aのプログラムが出てくるはずです。
違うようなら、「次を検索」で検索を繰り返してみて下さい。
図4 検索ウィンドウ
図3 検索コマンド


改造前

HRESULT    RestoreDeviceObjects()
{
    LPDIRECT3DSURFACE8 pBackBuffer;

    g_lpD3DDEV->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
    pBackBuffer->GetDesc( &g_d3dsdBackBuffer );
    pBackBuffer->Release();
    D3DXCreateTextureFromResourceEx(g_lpD3DDEV,
            GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_BITMAP1),
            0,0,1,0,
            D3DFMT_A1R5G5B5,D3DPOOL_MANAGED,
            D3DX_FILTER_LINEAR,D3DX_FILTER_LINEAR,
            D3DCOLOR_XRGB(0,255,255),        //    Color key.
            NULL,NULL,&g_pTexture);
    g_fTexImageWidth = 1.0f;
    g_fTexImageHeight = 1.0f;
    return    S_OK;
}

リスト1a

改造後


HRESULT    RestoreDeviceObjects()
{
    LPDIRECT3DSURFACE8 pBackBuffer;

    g_lpD3DDEV->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
    pBackBuffer->GetDesc( &g_d3dsdBackBuffer );
    pBackBuffer->Release();
    D3DXCreateTextureFromResourceEx(g_lpD3DDEV,
            GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_BITMAP1),
            0,0,1,0,
            D3DFMT_A1R5G5B5,D3DPOOL_MANAGED,
            D3DX_FILTER_LINEAR,D3DX_FILTER_LINEAR,
            D3DCOLOR_XRGB(0,255,255),        //    Color key.
            NULL,NULL,&g_pTexture);

    HFONT    hf;
    hf = CreateFont(16,0,0,0,0,false,false,false,ANSI_CHARSET,
        OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
        DEFAULT_PITCH|FF_DONTCARE,"");
    if (hf != NULL){
        D3DXCreateFont(g_lpD3DDEV,hf,&g_pFont);
        DeleteObject(hf);
    }
    g_fTexImageWidth = 1.0f;
    g_fTexImageHeight = 1.0f;
    return    S_OK;
}

リスト1b

解説
リスト1bの明るい部分の内容を追加記入してください。
ここではデバイス依存オブジェクトとして、ID3DXFont型のインスタンスを
生成しています。詳しくは Microsoft のドキュメントを参照の事。


【ステップ1−2 フォント破棄】
解説

再度、図5のようにして編集メニューから検索コマンドを選びます。

すると、図6のようなダイアログウィンドウが出てきます、

こんどは、InvalidateDeviceObjects というキーワードで検索を実行。

図6 検索ウィンドウ
図5 検索コマンド


改造前

HRESULT    InvalidateDeviceObjects()
{
    if (g_pTexture != NULL){
        g_pTexture->Release();
        g_pTexture = NULL;
    }
    return    S_OK;
}

リスト2a
改造後

HRESULT	InvalidateDeviceObjects()
{

    if (g_pFont != NULL){
        g_pFont->Release();
        g_pFont = NULL;
    }

    if (g_pTexture != NULL){
        g_pTexture->Release();
        g_pTexture = NULL;
    }
    return    S_OK;
}
リスト2b

解説
リスト2bの明るい部分の内容を追加記入してください。
ここでは、ステップ1−1で生成したID3DXFontオブジェクトを
破棄しています。


【ステップ1−3 表示】
解説

次に、図7のようにして編集メニューから検索コマンドを選びます。

すると、図8のようなダイアログウィンドウが出てきます、

ここでは、UpdateScreen というキーワードで検索を実行。

図8 検索ウィンドウ
図7 検索コマンド


改造前

void    UpdateScreen()
{
    float    timeElapsed;
    HRESULT    hr;
    if (g_pHighResTimer == NULL)
        return;
    if (0.5 > g_pHighResTimer->GetElapsedTime())
        return;
    timeElapsed=g_pHighResTimer->GetElapsedTimeAndReset();
    // Test the cooperative level to see if it's okay to render
    if( FAILED( hr = g_lpD3DDEV->TestCooperativeLevel() ) )
    {
        // If the device was lost, do not render until we get it back
        if( D3DERR_DEVICELOST == hr )
            return;

        // Check if the device needs to be resized.
        if( D3DERR_DEVICENOTRESET == hr )
        {
            // If we are windowed, read the desktop mode and use the same format for
            // the back buffer
            if( g_bWindowed )
            {
                D3DAdapterInfo* pAdapterInfo = &g_Adapters[g_dwAdapter];
                g_lpD3D->GetAdapterDisplayMode( g_dwAdapter, &pAdapterInfo->d3ddmDesktop );
                g_d3dprm.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
            }

            if( FAILED( hr = Resize3DEnvironment() ) )
                return;
        }
        return;
    }

    if (g_bUseDepthBuffer)
        g_lpD3DDEV->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,g_bgColor,1.0f,0);
    else
        g_lpD3DDEV->Clear(0,NULL,D3DCLEAR_TARGET,g_bgColor,1.0f,0);

    g_lpD3DDEV->BeginScene();
    SetDefaultRenderState(g_lpD3DDEV);

    //    描画方法の設定
    
    g_lpD3DDEV->SetRenderState( D3DRS_ALPHABLENDENABLE,   TRUE );
    g_lpD3DDEV->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
    g_lpD3DDEV->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
    if (g_bCanGreaterEqual){
        g_lpD3DDEV->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
        g_lpD3DDEV->SetRenderState( D3DRS_ALPHAREF,        0x08 );
        g_lpD3DDEV->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
    }
    //    アニメーションの為の座標計算
    int    x,y;
    static double d1=0,d2=0;
    d1 += 0.07*timeElapsed;
    d2 += 0.05*timeElapsed;
    if (d1 > (D3DX_PI*2))
        d1 -= D3DX_PI*2;

    if (d2 > (D3DX_PI*2))
        d2 -= D3DX_PI*2;

    y = (int)(100*sin(d1));
    y += 240;
    x = (int)(200*sin(d2));
    x += 320;

    //    四角形の頂点の設定
    TLVERTEX2D    pV[4];
    pV[0].x = (float)x;pV[0].y=(float)y;pV[0].z=0.0f;pV[0].rhw=1.0f;
    pV[0].tu = 0.0f;pV[0].tv=0.0f;pV[0].color=D3DCOLOR_XRGB(255,255,255);
    pV[1].x = (float)(x + 64);pV[1].y=(float)y;pV[1].z=0.0f;pV[1].rhw=1.0f;
    pV[1].tu = 1.0f;pV[1].tv=0.0f;pV[1].color=D3DCOLOR_XRGB(255,255,255);
    pV[2].x = (float)(x + 64);pV[2].y=(float)(y + 64);pV[2].z=0.0f;pV[2].rhw=1.0f;
    pV[2].tu = 1.0f;pV[2].tv=1.0f;pV[2].color=D3DCOLOR_XRGB(255,255,255);
    pV[3].x = (float)x;pV[3].y=(float)(y + 64);pV[3].z=0.0f;pV[3].rhw=1.0f;
    pV[3].tu = 0.0f;pV[3].tv=1.0f;pV[3].color=D3DCOLOR_XRGB(255,255,255);

    //    描画の実行
    g_lpD3DDEV->SetTexture(0,g_pTexture);
    g_lpD3DDEV->SetVertexShader(FVF_TLVERTEX2D);
    g_lpD3DDEV->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,2,pV,sizeof(TLVERTEX2D));

    // ※ここを改造

    g_lpD3DDEV->EndScene();

    if (FAILED(g_lpD3DDEV->Present(NULL,NULL,NULL,NULL))){
        Resize3DEnvironment();
    }
}

リスト3a

解説
関数 UpdateScreen は、OnIdle 関数から呼び出している関数で、
I/O入力、座標計算などのアニメーション、あたり判定、画面表示
など(初期化と終了処理を除く)ゲームのメインとなるプログラムを
想定しています。

その為、ゲームのキャラクタの表示ルーチンなどはここに記入すれば
良い事になります。

改造後

void    UpdateScreen()
{
    float    timeElapsed;
    HRESULT    hr;
    if (g_pHighResTimer == NULL)
        return;
    if (0.5 > g_pHighResTimer->GetElapsedTime())
        return;
    timeElapsed=g_pHighResTimer->GetElapsedTimeAndReset();
    // Test the cooperative level to see if it's okay to render
    if( FAILED( hr = g_lpD3DDEV->TestCooperativeLevel() ) )
    {
        // If the device was lost, do not render until we get it back
        if( D3DERR_DEVICELOST == hr )
            return;

        // Check if the device needs to be resized.
        if( D3DERR_DEVICENOTRESET == hr )
        {
            // If we are windowed, read the desktop mode and use the same format for
            // the back buffer
            if( g_bWindowed )
            {
                D3DAdapterInfo* pAdapterInfo = &g_Adapters[g_dwAdapter];
                g_lpD3D->GetAdapterDisplayMode( g_dwAdapter, &pAdapterInfo->d3ddmDesktop );
                g_d3dprm.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
            }

            if( FAILED( hr = Resize3DEnvironment() ) )
                return;
        }
        return;
    }

    if (g_bUseDepthBuffer)
        g_lpD3DDEV->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,g_bgColor,1.0f,0);
    else
        g_lpD3DDEV->Clear(0,NULL,D3DCLEAR_TARGET,g_bgColor,1.0f,0);

    g_lpD3DDEV->BeginScene();
    SetDefaultRenderState(g_lpD3DDEV);

    //    描画方法の設定(描画エンジンの設定)
    g_lpD3DDEV->SetRenderState( D3DRS_ALPHABLENDENABLE,   TRUE );
    g_lpD3DDEV->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
    g_lpD3DDEV->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
    if (g_bCanGreaterEqual){
        g_lpD3DDEV->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
        g_lpD3DDEV->SetRenderState( D3DRS_ALPHAREF,        0x08 );
        g_lpD3DDEV->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
    }
    //    アニメーションの為の座標計算
    int    x,y;
    static double d1=0,d2=0;
    d1 += 0.07*timeElapsed;
    d2 += 0.05*timeElapsed;
    if (d1 > (D3DX_PI*2))
        d1 -= D3DX_PI*2;

    if (d2 > (D3DX_PI*2))
        d2 -= D3DX_PI*2;

    y = (int)(100*sin(d1));
    y += 240;
    x = (int)(200*sin(d2));
    x += 320;

    //    四角形の頂点の設定
    TLVERTEX2D    pV[4];
    pV[0].x = (float)x;pV[0].y=(float)y;pV[0].z=0.0f;pV[0].rhw=1.0f;
    pV[0].tu = 0.0f;pV[0].tv=0.0f;pV[0].color=D3DCOLOR_XRGB(255,255,255);
    pV[1].x = (float)(x + 64);pV[1].y=(float)y;pV[1].z=0.0f;pV[1].rhw=1.0f;
    pV[1].tu = 1.0f;pV[1].tv=0.0f;pV[1].color=D3DCOLOR_XRGB(255,255,255);
    pV[2].x = (float)(x + 64);pV[2].y=(float)(y + 64);pV[2].z=0.0f;pV[2].rhw=1.0f;
    pV[2].tu = 1.0f;pV[2].tv=1.0f;pV[2].color=D3DCOLOR_XRGB(255,255,255);
    pV[3].x = (float)x;pV[3].y=(float)(y + 64);pV[3].z=0.0f;pV[3].rhw=1.0f;
    pV[3].tu = 0.0f;pV[3].tv=1.0f;pV[3].color=D3DCOLOR_XRGB(255,255,255);

    //    描画の実行
    g_lpD3DDEV->SetTexture(0,g_pTexture);
    g_lpD3DDEV->SetVertexShader(FVF_TLVERTEX2D);
    g_lpD3DDEV->DrawPrimitiveUP(D3DPT_TRIANGLEFAN,2,pV,sizeof(TLVERTEX2D));


    //    文字描画
    char    str[64];
    static    int    count = 0;
    RECT    r;
    sprintf(str,"%08d",count++);
    r.left = 10;
    r.top = 10;
    r.right = r.left + 150;
    r.bottom = r.top + 16;
    g_pFont->DrawText(str,-1,&r,DT_BOTTOM | DT_LEFT,D3DCOLOR_XRGB(255,255,255));

    //    線の描画方法の設定
    g_lpD3DDEV->SetRenderState( D3DRS_ALPHABLENDENABLE,   FALSE );

    //    線を描画する座標の計算
    x = (int)(250 * sin(d1));
    x += 270;
    y = 240;

    //    線の描画
    LVERTEX2D    pV2[4];
    pV2[0].x = (float)x;pV2[0].y=(float)y;pV2[0].z=0.0f;pV2[0].rhw=1.0f;
    pV2[0].color=D3DCOLOR_XRGB(255,0,0);
    pV2[1].x = (float)(x + 100);pV2[1].y=(float)y;pV2[1].z=0.0f;pV2[1].rhw=1.0f;
    pV2[1].color=D3DCOLOR_XRGB(255,255,255);

    g_lpD3DDEV->SetTexture(0,NULL);
    g_lpD3DDEV->SetVertexShader(FVF_LVERTEX2D);
    g_lpD3DDEV->DrawPrimitiveUP(D3DPT_LINELIST,1,pV2,sizeof(LVERTEX2D));

    //    点の描画方法の設定
    g_lpD3DDEV->SetRenderState( D3DRS_ALPHABLENDENABLE,   FALSE );

    //    点を描画する座標の計算
    y = (int)(240 * sin(d1));
    y += 240;
    x = 128;

    //    点の描画
    pV2[0].x = (float)x;pV2[0].y=(float)y;pV2[0].z=0.0f;pV2[0].rhw=1.0f;
    pV2[0].color=D3DCOLOR_XRGB(255,127,255);
    pV2[1].x = (float)(x + 128);pV2[1].y=(float)y;pV2[1].z=0.0f;pV2[1].rhw=1.0f;
    pV2[1].color=D3DCOLOR_XRGB(255,255,255);
    pV2[2].x = (float)(x + 256);pV2[2].y=(float)y;pV2[2].z=0.0f;pV2[2].rhw=1.0f;
    pV2[2].color=D3DCOLOR_XRGB(255,255,255);
    pV2[3].x = (float)(x + 384);pV2[3].y=(float)y;pV2[3].z=0.0f;pV2[3].rhw=1.0f;
    pV2[3].color=D3DCOLOR_XRGB(255,255,255);

    g_lpD3DDEV->SetTexture(0,NULL);
    g_lpD3DDEV->SetVertexShader(FVF_LVERTEX2D);
    g_lpD3DDEV->DrawPrimitiveUP(D3DPT_POINTLIST,4,pV2,sizeof(LVERTEX2D));

    g_lpD3DDEV->EndScene();

    if (FAILED(g_lpD3DDEV->Present(NULL,NULL,NULL,NULL))){
        Resize3DEnvironment();
    }
}
リスト3b

解説
リスト3bの明るい部分の内容を追加記入してください。
ここでは、D3DXライブラリを使用して文字描画を行った後、
3Dのレンダリングエンジンを設定し、
続いて、アニメーションの為の座標計算を行っています。
最後に、実際のレンダリング(描画)を行っています。

構造体 LVERTEX2D および、マクロ定数 FVF_LVERTEX2D は
d3dmain.h の中で宣言されています。





【ステップ2 実行】

改造し終えたらF5キーを押して実行してみましょう。
図5 実行画面

これで点と線が表示できました。

戻る