LoginSignup
0
0

More than 1 year has passed since last update.

DirectWriteを使いGraphics Device Interface (GDI)代わりにテキストを描画する方法

Last updated at Posted at 2022-08-17

前回に引き続きDirect2Dの機能を使い、今度はテキストを描画します。
テキストはDirectWriteという方法で描画でき、GDIよりも高速かつ綺麗な表示が可能だそうです。
本当に綺麗かどうかは、後日検証をしたいと思います。
高速かも怪しいです。

DirectWriteも難しくありません。

凡その概要を書くと・・

・ID2D1Factoryの作成
・ID2D1HwndRenderTargetの作成
・IDWriteFactoryの作成
・IDWriteTextFormatでフォントを作成
・DrawText(~)で描画

です。
※但し、テキストの描画する違う方法として、文字の外枠の線をパス(曲線)に変換し、
 そのパスを描画する方法などもあります。(これは後日)

ソースコード
#include <Windows.h>
#include <tchar.h>
#include <iostream>
//	Direct2DのHeader
#include <d2d1.h>
//	DirectWriteのHeader
#include <dwrite.h>
// lib	Direct2D
#pragma comment( lib, "d2d1.lib" )
//	lib DirectWrite
#pragma comment( lib, "dwrite.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;
//	DirectWrite用のファクトリー
IDWriteFactory* g_pDWFactory = 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_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);
		//	IDWriteFactoryの破棄
		safe_release(g_pDWFactory);
		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
			);
			//	DirectWriteのFactryを作成
			if (SUCCEEDED(hResult)) {
				hResult = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&g_pDWFactory));
			}
		}
		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);

		//	テキストフォーマットの作成
		IDWriteTextFormat* pTextFormat = nullptr;
		{
			g_pDWFactory->CreateTextFormat(
				L"Meiryo"
				, NULL
				, DWRITE_FONT_WEIGHT_NORMAL
				, DWRITE_FONT_STYLE_NORMAL//DWRITE_FONT_STYLE_OBLIQUE
				, DWRITE_FONT_STRETCH_NORMAL
				, 64
				, L""
				, &pTextFormat
			);
		}


		//	ブラシの作成
		ID2D1SolidColorBrush* pFontBrush = nullptr;

		//	青いブラシを作成
		g_pRenderTarget->CreateSolidColorBrush(
			D2D1::ColorF(0.0f        // R
				, 0.0f                                          // G
				, 1.0f                                          // B
				, 1.0f                                          // A
			)
			, &pFontBrush
		);


		std::wstring strText = L"コワーキングスペースでの開発";
		// テキストの描画
		g_pRenderTarget->DrawText(
			strText.c_str()   // 文字列
			, strText.size()    // 文字数
			, pTextFormat
			, &D2D1::RectF(0, 0, oTargetSize.width, oTargetSize.height)
			, pFontBrush
			, D2D1_DRAW_TEXT_OPTIONS_NONE
		);


		// ブラシの破棄
		safe_release(pFontBrush);
		//	フォントの破棄
		safe_release(pTextFormat);
		//	描画終了(Direct2D)
		g_pRenderTarget->EndDraw();

		break;
	}
	default:
		return(DefWindowProc(hwnd, msg, wParam, lParam));
	}
	return (0L);
}

[ソースコードをコンパイルできると以下のような画面になります]
スクリーンショット 2022-08-18 003600.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0