機械学習基礎理論独習

誤りがあればご指摘いただけると幸いです。数式が整うまで少し時間かかります。リンクフリーです。

勉強ログです。リンクフリーです
目次へ戻る

【VS2022】Direct2D の導入方法【C++】

インストールは不要

Windows SDK に含まれているらしいので Direct2D はインストール不要です。

2D の描画ならこれでいいんじゃないでしょうか?

ちなみに DirectX12 を使って 2D 描画するより、Direct2D による 2D 描画の方が速いそうです。
もちろん GDI より速いそうです。
やや初期化が面倒なので、GDI で描いてみて遅かったら使うぐらいの感じでよいと思います。

サンプル

Windows Application のコードを全て貼り付けておきます。

#include <windows.h>
#include <d2d1.h>
#include <dwrite.h>
#include "resource.h"

#pragma comment(lib, "d2d1")
#pragma comment(lib, "dwrite")

#define MAX_LOADSTRING 100

// グローバル変数
HINSTANCE hInst;
WCHAR szTitle[MAX_LOADSTRING];
WCHAR szWindowClass[MAX_LOADSTRING];

// Direct2D/DirectWrite リソース
ID2D1Factory* pD2DFactory = nullptr;
ID2D1HwndRenderTarget* pRenderTarget = nullptr;
ID2D1SolidColorBrush* pBrush = nullptr;
IDWriteFactory* pDWriteFactory = nullptr;
IDWriteTextFormat* pTextFormat = nullptr;

// 関数プロトタイプ
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

HRESULT InitDirect2D(HWND hWnd) {
    HRESULT hr;

    hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
    if (FAILED(hr)) return hr;

    RECT rc;
    GetClientRect(hWnd, &rc);
    D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);

    D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties();
    D2D1_HWND_RENDER_TARGET_PROPERTIES hwndProps =
        D2D1::HwndRenderTargetProperties(hWnd, size);

    hr = pD2DFactory->CreateHwndRenderTarget(props, hwndProps, &pRenderTarget);
    if (FAILED(hr)) return hr;

    hr = pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &pBrush);
    if (FAILED(hr)) return hr;

    hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
        __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&pDWriteFactory));
    if (FAILED(hr)) return hr;

    hr = pDWriteFactory->CreateTextFormat(
        L"Segoe UI", nullptr,
        DWRITE_FONT_WEIGHT_NORMAL,
        DWRITE_FONT_STYLE_NORMAL,
        DWRITE_FONT_STRETCH_NORMAL,
        36.0f, L"ja-jp", &pTextFormat);
    return hr;
}

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_SAMPLEDIRECT2DWIN32, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    if (!InitInstance(hInstance, nCmdShow)) return FALSE;

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SAMPLEDIRECT2DWIN32));

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0)) {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int)msg.wParam;
}

ATOM MyRegisterClass(HINSTANCE hInstance) {
    WNDCLASSEXW wcex = {};
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.hInstance = hInstance;
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszClassName = szWindowClass;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SAMPLEDIRECT2DWIN32));
    wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SAMPLEDIRECT2DWIN32);
    wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    return RegisterClassExW(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
    hInst = hInstance;

    HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

    if (!hWnd) return FALSE;

    if (FAILED(InitDirect2D(hWnd))) {
        MessageBox(hWnd, L"Direct2D 初期化失敗", L"エラー", MB_OK);
        return FALSE;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
    case WM_COMMAND: {
        int wmId = LOWORD(wParam);
        switch (wmId) {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    }
    case WM_CREATE: {
        HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
        if (FAILED(hr)) {
            MessageBox(nullptr, L"COM初期化失敗", L"エラー", MB_OK);
            break;
        }
        break;
    }
    case WM_PAINT: {
        PAINTSTRUCT ps;
        BeginPaint(hWnd, &ps);

        if (pRenderTarget) {
            pRenderTarget->BeginDraw();

            // 背景を白でクリア
            pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));

            // 塗りつぶし(灰色)
            D2D1_SIZE_F size = pRenderTarget->GetSize();
            D2D1_RECT_F fullRect = D2D1::RectF(0, 0, size.width, size.height);
            pBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Gray));
            pRenderTarget->FillRectangle(fullRect, pBrush);

            // テキスト描画(青)
            const wchar_t* text = L"Hello, Direct2D!";
            D2D1_RECT_F layoutRect = D2D1::RectF(50, 50, 500, 150);
            pBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Blue));
            pRenderTarget->DrawText(text, wcslen(text), pTextFormat, &layoutRect, pBrush);

            // 線分(黒)
            pBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Black));
            pRenderTarget->DrawLine(
                D2D1::Point2F(100, 200),
                D2D1::Point2F(300, 200),
                pBrush,
                2.0f
            );

            // 矩形(緑枠)
            D2D1_RECT_F rect = D2D1::RectF(100, 220, 300, 270);
            pBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Green));
            pRenderTarget->DrawRectangle(rect, pBrush, 2.0f);

            // 多角形(紫線)
            ID2D1PathGeometry* pGeometry = nullptr;
            ID2D1GeometrySink* pSink = nullptr;
            if (SUCCEEDED(pD2DFactory->CreatePathGeometry(&pGeometry))) {
                if (SUCCEEDED(pGeometry->Open(&pSink))) {
                    pSink->BeginFigure(D2D1::Point2F(100, 300), D2D1_FIGURE_BEGIN_FILLED);
                    pSink->AddLine(D2D1::Point2F(150, 350));
                    pSink->AddLine(D2D1::Point2F(200, 300));
                    pSink->AddLine(D2D1::Point2F(250, 350));
                    pSink->AddLine(D2D1::Point2F(300, 300));
                    pSink->EndFigure(D2D1_FIGURE_END_OPEN);
                    pSink->Close();
                    pSink->Release();
                }
                pBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Purple));
                pRenderTarget->DrawGeometry(pGeometry, pBrush, 2.0f);
                pGeometry->Release();
            }

            // 多角形塗りつぶし(オレンジ)
            if (SUCCEEDED(pD2DFactory->CreatePathGeometry(&pGeometry))) {
                if (SUCCEEDED(pGeometry->Open(&pSink))) {
                    pSink->BeginFigure(D2D1::Point2F(100, 380), D2D1_FIGURE_BEGIN_FILLED);
                    pSink->AddLine(D2D1::Point2F(150, 430));
                    pSink->AddLine(D2D1::Point2F(200, 380));
                    pSink->AddLine(D2D1::Point2F(250, 430));
                    pSink->AddLine(D2D1::Point2F(300, 380));
                    pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
                    pSink->Close();
                    pSink->Release();
                }
                pBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Orange));
                pRenderTarget->FillGeometry(pGeometry, pBrush);
                pGeometry->Release();
            }

            // 三次ベジェ曲線(シアン)
            if (SUCCEEDED(pD2DFactory->CreatePathGeometry(&pGeometry))) {
                if (SUCCEEDED(pGeometry->Open(&pSink))) {
                    pSink->BeginFigure(D2D1::Point2F(100, 460), D2D1_FIGURE_BEGIN_HOLLOW);
                    D2D1_BEZIER_SEGMENT bezierSegment = {
                        D2D1::Point2F(150, 510),
                        D2D1::Point2F(250, 410),
                        D2D1::Point2F(300, 460)
                    };
                    pSink->AddBezier(&bezierSegment);
                    pSink->EndFigure(D2D1_FIGURE_END_OPEN);
                    pSink->Close();
                    pSink->Release();
                }
                pBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Cyan));
                pRenderTarget->DrawGeometry(pGeometry, pBrush, 2.0f);
                pGeometry->Release();
            }

            pRenderTarget->EndDraw();
        }

        EndPaint(hWnd, &ps);
        break;
    }

    case WM_SIZE: {
        D2D1_SIZE_U oPixelSize = { LOWORD(lParam), HIWORD(lParam) };

        // ターゲットリサイズ
        pRenderTarget->Resize(&oPixelSize);
        break;
    }
    case WM_DESTROY:
        if (pTextFormat) pTextFormat->Release();
        if (pDWriteFactory) pDWriteFactory->Release();
        if (pBrush) pBrush->Release();
        if (pRenderTarget) pRenderTarget->Release();
        if (pD2DFactory) pD2DFactory->Release();
        // 最後に COM を終了
        CoUninitialize();
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
    UNREFERENCED_PARAMETER(lParam);
    switch (message) {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;
    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

実行結果は以下です。

目次へ戻る