Direct2D導入(ID2D1HwndRenderTarget)

今回はDirect2Dを用いて、下記のような描画を行うところまで実装してみたいと思います。

f:id:any-programming:20171026193608p:plain

ウィンドウ生成、表示関数

Direct2Dの描画先として、通常のWindowsのウィンドウを作成、実行する関数を準備します。

内容は一般的なもので、特に変わったものではありません。

HWND CreateHWND(WNDPROC wndProc)
{
    WNDCLASSEX wndclass;
    wndclass.cbSize = sizeof(WNDCLASSEX);
    wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
    wndclass.lpfnWndProc = wndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = GetModuleHandle(NULL);
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = NULL;
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = L"Main Window";
    wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClassEx(&wndclass);

    HWND hwnd = CreateWindow(
        L"Main Window",
        L"Main Window",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL,
        NULL,
        wndclass.hInstance,
        NULL
    );

    return hwnd;
}
void Run(HWND hwnd)
{
    ShowWindow(hwnd, SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}


Direct2D初期化

ID2D1HwndRenderTargetを生成する関数を作成します。

ID2D1Factory経由で作成を行います。

#include <d2d1.h>
#pragma comment(lib, "d2d1.lib")

#include <wrl\client.h>
using namespace Microsoft::WRL;

ComPtr<ID2D1HwndRenderTarget> CreateRenderTarget(HWND hwnd)
{
    ComPtr<ID2D1Factory> factory;
    AssertHR(D2D1CreateFactory<ID2D1Factory>(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory));

    ComPtr<ID2D1HwndRenderTarget> renderTarget;
    AssertHR(factory->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(), 
        D2D1::HwndRenderTargetProperties(hwnd), 
        &renderTarget
    ));

    return renderTarget;
}


楕円描画

RenderTargetいっぱいに楕円を描画する関数となります。

void Draw(ID2D1HwndRenderTarget* renderTarget)
{
    renderTarget->BeginDraw();

    renderTarget->Clear(D2D1::ColorF(D2D1::ColorF::LightYellow));

    D2D1_SIZE_F size = renderTarget->GetSize();
    float rx = size.width / 2;
    float ry = size.height / 2;
    D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(rx, ry), rx, ry);
    ComPtr<ID2D1SolidColorBrush> brush;
    AssertHR(renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Orange), &brush));
    renderTarget->FillEllipse(ellipse, brush.Get());

    AssertHR(renderTarget->EndDraw());
}


WndProc

WM_SIZEにてRenderTargetのサイズを変更し、WM_PAINTにて上記のDraw関数を呼ぶよう実装します。

ComPtr<ID2D1HwndRenderTarget> g_renderTarget;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_PAINT:
        Draw(g_renderTarget.Get());
        return 0;
    case WM_SIZE:
        g_renderTarget->Resize(D2D1::SizeU(LOWORD(lParam), HIWORD(lParam)));
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}


main

最終的にmain関数はこのようになります。

int main()
{
    HWND hwnd = CreateHWND(WndProc);
    g_renderTarget = CreateRenderTarget(hwnd);
    Run(hwnd);

    return 0;
}