MinGW32 で DirectX プログラミングしてみる

最近全然やってないことに気付いて書いてみた。
あと、MinGW32 でもコンパイルできるようにしてみた。

MinGW32 には、 d3dx9.h が無い代わりに、direct.h ってヘッダーファイルがあるってのを知った。*1
なので、d3d9.h しかインクルードしてない。

// dir01.cpp
#include <windows.h>
#include <tchar.h>
#include <d3d9.h>

#if !defined(_MINGW)
#    pragma comment(lib,  "d3d9.lib")
#    pragma comment(lib, "d3dx9.lib")
#endif  /* !defined(_MINGW) */


IDirect3D9*         directx_graphics     = NULL;
IDirect3DDevice9*   graphic_device       = NULL;

static const _TCHAR* application_title    = _T("見習い魔法使いでもよく分かるかもしれないDirectX");


LRESULT CALLBACK   wndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT            init_DirectX_Graphics(HWND);
void               onRender();


#define  WS_GAMESCREEN    WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hUnused, LPSTR szCommandLine, INT nCommandCount)
{
    HWND        window_handle = NULL;
    MSG         msg;

    WNDCLASSEX  wx;
    wx.cbSize         = sizeof(WNDCLASSEX);
    wx.style          = CS_HREDRAW | CS_VREDRAW;
    wx.lpfnWndProc    = wndProc;
    wx.cbClsExtra     = 0;
    wx.cbWndExtra     = 0;
    wx.hInstance      = hInstance;
    wx.hIcon          = LoadIcon( NULL, IDI_APPLICATION );
    wx.hCursor        = LoadCursor( NULL, IDC_ARROW );
    wx.hbrBackground  = reinterpret_cast<HBRUSH>( GetStockObject( BLACK_BRUSH ) );
    wx.lpszMenuName   = NULL;
    wx.lpszClassName  = application_title;
    wx.hIconSm        = LoadIcon( NULL, IDI_APPLICATION );

    RegisterClassEx( &wx );

    RECT rc = { 0, 0, 640, 400 };
    AdjustWindowRect( &rc, WS_GAMESCREEN, false );

    window_handle = CreateWindow( application_title,
                                  application_title,
                                  WS_GAMESCREEN,
                                  300,
                                  300,
                                  rc.right - rc.left,
                                  rc.bottom - rc.top,
                                  NULL,
                                  NULL,
                                  hInstance,
                                  NULL
                                );
    ShowWindow( window_handle, SW_SHOW );
    UpdateWindow( window_handle );

    HRESULT hr;
    if ( FAILED( hr = init_DirectX_Graphics( window_handle ) ) ) {

        return hr;
    }

    ZeroMemory( &msg, sizeof(MSG) );
    while ( msg.message != WM_QUIT ) {
        if ( PeekMessage( &msg, NULL, 0u, 0u, PM_REMOVE ) ) {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        } else {
            onRender();
        }
    }
    graphic_device->Release();
    directx_graphics->Release();

    return static_cast<int>(msg.wParam);
}


LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch ( msg ) {
        case WM_DESTROY:
            PostQuitMessage( 0 );
            break;
    }
    return DefWindowProc( hWnd, msg, wp, lp );
}


HRESULT init_DirectX_Graphics(HWND hWnd)
{
    if ( NULL == ( directx_graphics = Direct3DCreate9( D3D_SDK_VERSION ) ) ) {
        MessageBox( NULL, _T("Direct3D 作成に失敗したよ!"), _T("もうだめぽ"), MB_OK );

        return E_FAIL;
    }

    D3DPRESENT_PARAMETERS  present_box;
    ZeroMemory( &present_box, sizeof(D3DPRESENT_PARAMETERS) );

    present_box.BackBufferFormat        = D3DFMT_UNKNOWN;
    present_box.BackBufferCount         = 1;
    present_box.SwapEffect              = D3DSWAPEFFECT_DISCARD;
    present_box.Windowed                = true;
    present_box.EnableAutoDepthStencil  = true;
    present_box.AutoDepthStencilFormat  = D3DFMT_D16;

    if ( FAILED( directx_graphics->CreateDevice( D3DADAPTER_DEFAULT,
                                                 D3DDEVTYPE_HAL,
                                                 hWnd,
                                                 D3DCREATE_HARDWARE_VERTEXPROCESSING,
                                                 &present_box,
                                                 &graphic_device
                                               ) ) )
    {
        if ( FAILED( directx_graphics->CreateDevice( D3DADAPTER_DEFAULT,
                                                     D3DDEVTYPE_HAL,
                                                     hWnd,
                                                     D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                                     &present_box,
                                                     &graphic_device
                                                   ) ) )
        {
            MessageBox( NULL,
                        _T("HAL モードで directx3d デバイスを作成できなかったよ!。\nREFモードで再試行するからねっ☆。"),
                        _T("ちょっとヤバイ"),
                        MB_OK
                      );
            if ( FAILED( directx_graphics->CreateDevice( D3DADAPTER_DEFAULT,
                                                         D3DDEVTYPE_REF,
                                                         hWnd,
                                                         D3DCREATE_HARDWARE_VERTEXPROCESSING,
                                                         &present_box,
                                                         &graphic_device
                                                       ) ) )
                {
                    if ( FAILED( directx_graphics->CreateDevice( D3DADAPTER_DEFAULT,
                                                                 D3DDEVTYPE_REF,
                                                                 hWnd,
                                                                 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                                                 &present_box,
                                                                 &graphic_device
                                                               ) ) )
                        {
                            MessageBox( NULL,
                                        _T("direct3d デバイスの作成に失敗したよ!\n他のゲームも多分できないっぽいから、あきらめたほうがいいよ!!"),
                                        _T("ヤバイってもんじゃない"),
                                        MB_OK
                                      );
                            return E_FAIL;
                        }
                }
        }
    }
    return S_OK;
}


void onRender()
{
    graphic_device->Clear( 0,
                           NULL,
                           D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
                           D3DCOLOR_XRGB(0x33, 0x66, 0x99),
                           1.0f,
                           0
                         );
    if ( SUCCEEDED( graphic_device->BeginScene() ) ) {
        // 
        // ここに何か描画する処理を書く。
        // 
        graphic_device->EndScene();
    }
    graphic_device->Present( NULL, NULL, NULL, NULL );
}

エラーメッセージがあれなのはユーモアなので、サラッと流して欲しい。
さて、難しいのはここからで、オブジェクトファイルのリンクがよく分からないんだよね。
今回は、比較的すんなりいったのでよかった。
以下に makefile も晒しておく:

cc     = g++
cflags = -O2 -Wall -W 


ld     = g++
lflags = -gdi32 -mwindows
libs   = -ld3d9 -ldxguid

outdir = ./Debug

target = $(outdir)/dir01.exe


src0   = dir01.cpp


obj0   = $(outdir)/dir01.o
objs   = $(obj0) $(obj1)


all: $(target)


$(target): $(objs)
	$(ld) $(lflags) -o $@ $^ $(libs)


$(obj0): $(src0)
	$(cc) $(cflags) -c $< -o $@


clean:
	rm $(target) $(objs)

*1:バカを書いた。これはおそらく、DirectX 8 用の奴だろう。しかも direct.h じゃなくて、directx.h だし。