Win32APIの描画処理には、Graphics Device Interface (GDI) という仕組みが使われてますが
10年ぐらい前からDirect2Dという描画方法が現れ今更触ってみました。
Direct・・と聞くとDirectXを連想してしまい、とても難しいコーディングが
必要なのでは・・?と思いきや、とても簡単に実装できました。
[主な実装方法]
・ID2D1Factoryを作成
・ID2D1HwndRenderTargetを作成
・WM_PAINT内でID2D1HwndRenderTargetを用いBeginDraw()~EndDraw()
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
~
EndPaint(hwnd, &ps);
Direct2Dで描画する場合は、Win32APIでのお約束である上記コードも不要です。
これは、試しに消してみたら問題なかったです。
WM_CREATE内でhwndと連携させてるからですかね。
サンプル用の全ソースコード
#include <Windows.h>
#include <tchar.h>
#include <d2d1.h>
// lib Direct2D
#pragma comment( lib, "d2d1.lib" )
#define WINDOW_WIDTH 1080
#define WINDOW_HEIGHT 720
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
#define CLASS_NAME "CLASS TEST01"
#define PROC_NAME "test01"
template<class T>
inline void safe_release(T& p) {
if (p) {
p->Release();
p = nullptr;
}
}
// グローバル変数として定義
// Direct2D用のファクトリ
ID2D1Factory* g_pD2d1Factory = nullptr;
// RenderTarget
ID2D1HwndRenderTarget* g_pRenderTarget = nullptr;
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPTSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG msg;
if (!hPreInst) {
WNDCLASS my_prog;
my_prog.style = CS_HREDRAW | CS_VREDRAW;
my_prog.lpfnWndProc = WndProc;
my_prog.cbClsExtra = 0;
my_prog.cbWndExtra = 0;
my_prog.hInstance = hInstance;
my_prog.hIcon = NULL;
my_prog.hCursor = LoadCursor(NULL, IDC_ARROW);
my_prog.hbrBackground = NULL;
my_prog.lpszMenuName = NULL;
my_prog.lpszClassName = _T(CLASS_NAME);
if (!RegisterClass(&my_prog)) {
return FALSE;
}
}
RECT rect = {
static_cast<LONG>(0),
static_cast<LONG>(0),
static_cast<LONG>(WINDOW_WIDTH),
static_cast<LONG>(WINDOW_HEIGHT)
};
AdjustWindowRect(
&rect, // クライアント矩形
WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION, // ウィンドウスタイル
FALSE // メニューフラグ
);
hwnd = CreateWindow(_T(CLASS_NAME),
_T(PROC_NAME),
// WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION,
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_THICKFRAME | WS_MAXIMIZEBOX,
CW_USEDEFAULT,
CW_USEDEFAULT,
rect.right - rect.left, // ウィンドウの幅
rect.bottom - rect.top, // ウィンドウの高さ
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
do {
if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} while (msg.message != WM_QUIT);
return (int)(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_SIZE: {
D2D1_SIZE_U oPixelSize = { LOWORD(lParam), HIWORD(lParam) };
// ターゲットリサイズ
g_pRenderTarget->Resize(&oPixelSize);
break;
}
case WM_DESTROY: {
// ID2D1HwndRenderTargetの破棄
safe_release(g_pRenderTarget);
// ID2D1Factoryの破棄
safe_release(g_pD2d1Factory);
PostQuitMessage(0);
break;
}
case WM_CREATE: {
CREATESTRUCT* tpCreateSt = (CREATESTRUCT*)lParam;
HRESULT hResult = S_OK;
// Direct2D用のファクトリーの作成
hResult = D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &g_pD2d1Factory);
if (SUCCEEDED(hResult)) {
// RenderTargetのサイズを指定
D2D1_SIZE_U oPixelSize = {
static_cast<UINT32>(tpCreateSt->cx)
, static_cast<UINT32>(tpCreateSt->cy)
};
D2D1_RENDER_TARGET_PROPERTIES oRenderTargetProperties = D2D1::RenderTargetProperties();
D2D1_HWND_RENDER_TARGET_PROPERTIES oHwndRenderTargetProperties = D2D1::HwndRenderTargetProperties(hwnd, oPixelSize);
// Direct2DのRenderTargetの作成
hResult = g_pD2d1Factory->CreateHwndRenderTarget(
oRenderTargetProperties
, oHwndRenderTargetProperties
, &g_pRenderTarget
);
}
break;
}
case WM_PAINT: {
D2D1_SIZE_F oTargetSize = g_pRenderTarget->GetSize();
// 描画開始(Direct2D)
g_pRenderTarget->BeginDraw();
// 初期化マトリクスを行列にセット
g_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
// 背景の色を赤でクリア
D2D1_COLOR_F oBKColor = { 1.0f, 0.0f, 0.0f, 1.0f };
g_pRenderTarget->Clear(oBKColor);
// ブラシの作成
ID2D1SolidColorBrush* pLineBrush = nullptr;
ID2D1SolidColorBrush* pFillBrush = nullptr;
// 青いブラシを作成
g_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(0.0f // R
, 0.0f // G
, 1.0f // B
, 1.0f // A
)
, &pLineBrush
);
// 緑ブラシを作成
g_pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(0.0f // R
, 1.0f // G
, 0.0f // B
, 1.0f // A
)
, &pFillBrush
);
// 描画矩形
D2D1_RECT_F tRectF = D2D1::RectF(
0.0f
, 0.0f
, static_cast<FLOAT>(oTargetSize.width/2)
, static_cast<FLOAT>(oTargetSize.height/2)
);
// 線の幅
float fStrokeWidth = 4.0f;
// 四角形を塗りつぶす
g_pRenderTarget->FillRectangle(&tRectF, pFillBrush);
// 四角形の線を引く
g_pRenderTarget->DrawRectangle(&tRectF, pLineBrush, fStrokeWidth);
// ラインを引く
g_pRenderTarget->DrawLine(
D2D1::Point2F(static_cast<FLOAT>(oTargetSize.width / 2), static_cast<FLOAT>(oTargetSize.height / 2)),
D2D1::Point2F(static_cast<FLOAT>(oTargetSize.width- oTargetSize.width / 4), static_cast<FLOAT>(oTargetSize.height- oTargetSize.height / 4)),
pLineBrush,
fStrokeWidth
);
// ブラシの破棄
safe_release(pFillBrush);
safe_release(pLineBrush);
// 描画終了(Direct2D)
g_pRenderTarget->EndDraw();
break;
}
default:
return(DefWindowProc(hwnd, msg, wParam, lParam));
}
return (0L);
}
ソースコードをコンパイルすると以下のような見た目が表示されます。
参考サイト: