ホーム < ゲームつくろー! < IKD備忘録

COM
ATL版DirectX極短プログラム

(2009. 7. 19)


 下準備を色々としてきました。前章でHWNDが取得できたのは大きくて、DirectXの初期化ができます。やってみるです。

 まず自作のATLコントロールのヘッダーに次のメソッドを追加です:

DXWindow.h
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")

#include <d3d9.h>
#include <d3dx9.h>

class CDXWindow {
... // なんか色々ある部分ですよ

public:
    HWND m_hOurWnd;
    LPDIRECT3D9 pD3D;
    LPDIRECT3DDEVICE9 pD3DDev;

    HRESULT InPlaceActivate(LONG iVerb, const RECT* prcPosRect = NULL);
    HRESULT OnDraw(ATL_DRAWINFO& di);

private:
    void getOurHWnd();
    void initD3D();
};

 InPlaceActivateメソッドはATLコントロールがアクティブになった時に呼ばれるハンドラ、OnDrawは描画時に呼ばれるハンドラです。getOurHWndメソッドはATLコントロールのウィンドウハンドルを取得、initD3DメソッドはDirect3Dを初期化するメソッドです。

 それぞれの実装部はこうしてみました:

DXWindow.cpp
HRESULT CDXWindow::InPlaceActivate(LONG iVerb, const RECT* prcPosRect)
{
    HRESULT hr;

    hr = CComControlBase::InPlaceActivate(iVerb, prcPosRect);
    if ( !m_hOurWnd ) {
        getOurHWnd();
        initD3D();
    }
    return hr;
}

HRESULT CDXWindow::OnDraw(ATL_DRAWINFO& di)
{
    if ( pD3DDev ) {
        // Direct3Dの処理
        pD3DDev->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
        pD3DDev->BeginScene();

        // 描画
        pD3DDev->EndScene();
        pD3DDev->Present( NULL, NULL, NULL, NULL ) ) );
    }
    return S_OK;
}

void CDXWindow::getOurHWnd()
{
    if (m_bWndLess)
    {
        HDC hDC;

        m_spInPlaceSite->GetDC(NULL, OLEDC_NODRAW, &hDC);
        m_hOurWnd = WindowFromDC(hDC);
        RECT rect;
        ::GetClientRect(m_hOurWnd,&rect);
        HRGN hRegion = CreateRectRgn(rect.left,rect.top,rect.right,rect.bottom);
        SelectClipRgn(hDC,hRegion);
        m_spInPlaceSite->ReleaseDC(hDC);
    }
    else {
        m_hOurWnd = m_hWnd;
        RECT rect;
        ::GetClientRect(m_hOurWnd,&rect);
    }
}

void CDXWindow::initD3D() {

    // Direct3Dの初期化
    if( !(pD3D = Direct3DCreate9( D3D_SDK_VERSION )) ) {
        return;
    }

    D3DPRESENT_PARAMETERS d3dpp = {0,0,D3DFMT_UNKNOWN,0,D3DMULTISAMPLE_NONE,0,
        D3DSWAPEFFECT_DISCARD,NULL,TRUE,0,D3DFMT_UNKNOWN,0,0};

    if( FAILED( pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hOurWnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pD3DDev ) ) )
    {
        pD3D->Release();
        return;
    }
}

InPlaceActivateメソッドが呼ばれた時、ウィンドウハンドルが取得されていない場合はgetOurHWndメソッドを呼び出してATLコントロールのハンドルを格納します。続いてinitD3Dメソッドを呼び出してDirect3Dを初期化します。後はOnDrawメソッドが呼ばれた時に画面を更新します。

 こんなのでうまくいくのかなぁと半信半疑でVBに貼り付けてみたら・・・あらら、できたみたいですよ!!

おお・・・これでC++で作成したDirectXのアプリケーションをVB上で操作できる道が開けた気がします。ただ、きっとこのままでは更新がうまくいっていないはず。OnDrawが呼ばれるにはウィンドウサイズを変更するなどしなければならないからです。まぁ、その辺りの問題は後でなんとかするとして、こうなるとやっぱり「3Dモデル」を出したくなるわけですよ。次はここにSphereモデルを表示してみます。