読者です 読者をやめる 読者になる 読者になる

やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

描画Frameworkをつくってみた1

描画Frameworkをつくってみた。

入手先

GitHub MEGA

問題

WindowsXPでグラフィクスを描画するとき、3つの描画アーキテクチャがある。

  • GDI
  • GDI+
  • DirectX9

これらは初期処理などの違いがあり、WndProc内の処理がかなり異なる。

初期化処理など毎回おなじ処理を書くのは面倒。Framework化したい。

WindowMessageを意識することなく描画を実装できるインタフェースがほしい。

解決

描画アーキテクチャ インタフェース関数 インタフェースclass
GDI void Draw(HDC); IGdiDrawer
GDI+ void Draw(Gdiplus::Graphics*); IGdiPlusDrawer
DirectX void Draw(LPDIRECT3DDEVICE9); IDirectX9Drawer

このインタフェースをFrameworkとして用意したい。 以後、これを継承して描画内容を実装できるようになれば、初期化処理などを書かずに済んで楽になる。

以下、Framework化したい枠組み。

GDI

LRESULT CALLBACK GdiWndProc::PartWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL* pIsReturn)
{
    switch (uMsg) {
        case WM_PAINT:
            HDC hdc;
            PAINTSTRUCT ps;
            hdc = BeginPaint(hWnd , &ps);
            m_drawer->Draw(hdc);
            EndPaint(hWnd , &ps);
            break;
        default:
            break;
    }
    return (0L);
}
void GdiWndProc::Initialize() { m_drawer->Initialize(); }
void GdiWndProc::Finalize() { m_drawer->Finalize(); }

GDI+

LRESULT CALLBACK GdiPlusWndProc::PartWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL* pIsReturn)
{
    switch (uMsg) {
        case WM_CREATE:
            Initialize();
            break;
        case WM_DESTROY:
            Finalize();
            break;
        case WM_ERASEBKGND:
            *pIsReturn = TRUE;
            return TRUE;
        case WM_PAINT:
            {
            HDC hdc;
            PAINTSTRUCT ps;
            hdc = BeginPaint(hWnd , &ps);
            Graphics g(hdc);
            m_drawer->Draw(m_OffScreenGraphics);
            g.DrawImage(m_OffScreenBitmap, 0, 0);
            EndPaint(hWnd , &ps);
            }
            break;
        default:
            break;
    }
    return (0L);
}
void GdiPlusWndProc::Initialize()
{
    if (NULL == m_gdiSI) {
        m_gdiSI = new Gdiplus::GdiplusStartupInput;
        GdiplusStartup(&m_gdiToken, m_gdiSI, NULL);
    }
    if (NULL == m_OffScreenBitmap) {
        m_OffScreenBitmap = new Bitmap(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
        m_OffScreenGraphics = Graphics::FromImage(m_OffScreenBitmap);
    }

    if (NULL != m_drawer) { m_drawer->Initialize(); }
}
void GdiPlusWndProc::Finalize()
{
    if (NULL != m_drawer) { m_drawer->Finalize(); }

    if (NULL != m_OffScreenGraphics) {
        m_OffScreenGraphics->Flush();
    }
    if (NULL != m_OffScreenBitmap) {;
        delete m_OffScreenBitmap;
        m_OffScreenBitmap = NULL;
    }
    if (NULL != m_OffScreenGraphics) {
        delete m_OffScreenGraphics;
        m_OffScreenGraphics = NULL;
    }
    if (NULL != m_gdiSI) {
        delete m_gdiSI;
        m_gdiSI = NULL;
        GdiplusShutdown(m_gdiToken);
    }
}

DirectX9

LRESULT CALLBACK DirectX9WndProc::PartWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL* pIsReturn)
{
    switch (uMsg) {
        case WM_CREATE:
            Initialize();
            break;
        case WM_DESTROY:
            Finalize();
            break;
        case WM_ERASEBKGND:
            *pIsReturn = TRUE;
            return TRUE;
        default:
            if (NULL == m_pD3DDev) { return (0L); }
            m_drawer->Draw(m_pD3DDev);
            break;
    }
    return (0L);
}
void DirectX9WndProc::Initialize()
{
    // 事前にCreateWindow()されていなければDirectX9を初期化できない
    HWND hWnd = GetActiveWindow();
    if (NULL == hWnd) { return; }

    if (NULL != m_pD3D) { return; }

    if( !(m_pD3D = Direct3DCreate9( D3D_SDK_VERSION )) )
    {
        throw "Direct3DCreate9関数に失敗しました。";
    }
    D3DPRESENT_PARAMETERS d3dpp = { 0, 0, D3DFMT_UNKNOWN, 0, D3DMULTISAMPLE_NONE, 0, D3DSWAPEFFECT_DISCARD, NULL, TRUE, 0, D3DFMT_UNKNOWN, 0, 0 };

    if( FAILED( m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &m_pD3DDev ) ) )
    {
        m_pD3D->Release();
        throw "DIRECT3D9.CreateDevice関数に失敗しました。";
    }

    if (NULL != m_drawer) { m_drawer->Initialize(); }
}
void DirectX9WndProc::Finalize()
{
    if (NULL != m_drawer) { m_drawer->Finalize(); }

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

ソースコード一覧

ソース一覧

課題

DrawerSetter

GraphicsArchitectureSetter class で Drawer の生成や設定もしてしまっている。 しかも Drawer は固定である。

本来は Drawer も変動する。 この Drawer を任意につくることができるからこそFrameworkたりえるのに固定になってしまっている。 DrawerSetterのような class を生成して変動することができるようにすべき。