【Fr2D开发笔记】三、Direct2D初始化

创建好一个窗体后,就可以使用Direct2D绘制了。

Direct2D程序需要包含头文件d2d1.h,和静态库d2d1.lib。这里简单介绍一下Direct2D程序初始化过程。

一、ID2D1Factory

首先是ID2D1Factory类,是Direct2D其他对象的工厂类,需要首先创建。使用D2D1CreateFactory函数构造,第一个参数是程序线程类型。正常创建返回S_OK,否则返回的HRESULT包含错误信息。

1
2
3
4
5
ID2D1Factory * d2dFactory;
HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dFactory);
if (FAILED(hr)) {
MessageBox(hwnd, _T("Create D2D factory failed!"), _T("Error"), 0);
}

二、RenderTarget

Direct2D的渲染都在渲染目标(?)对象中进行,创建工厂类对象后就可以使用它创建一个RenderTarget。

Direct2D提供多种RenderTarget,这里使用窗口句柄渲染目标ID2D1HwndRenderTarget可以实现在目标窗口上的渲染。

使用ID2D1Factory对象的成员函数CreateHwndRenderTarget构造,第一个参数可以通过D2D1::RenderTargetProperties函数获得,第二个参数通过D2D1::HwndRenderTargetProperties获得,提供窗口句柄和大小:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ID2D1HwndRenderTarget* hdl;
RECT rc;
GetClientRect(hwnd, &rc);
HRESULT hr = d2dFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hwnd,
D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)
),
&hdl
);
if (FAILED(hr)) {
MessageBox(hwnd, _T("Create render target failed!"), _T("Error"), 0);
}

三、固体颜色刷

固体颜色画刷ID2D1SolidColorBrush是由渲染目标对象的成员函数CreateSolidColorBrush创建的:

1
2
3
4
5
6
7
8
ID2D1SolidColorBrush* brush;
hr = hdl->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Red),
&brush
);
if (FAILED(hr)) {
MessageBox(hwnd, _T("Create brush failed!"), _T("Error"), 0);
}

四、开始画图

现在,可以开始画图了。

调用渲染目标对象的成员函数BeginDraw开始绘图,Clear函数用某一颜色清屏;我们使用DrawRectangle函数用笔刷绘制一个矩形,最后调用EndDraw函数结束绘图。Direct2D的屏幕坐标以左上角为原点,x轴向右,y轴向下。

1
2
3
4
5
6
7
8
9
10
hdl->BeginDraw();
hdl->Clear(D2D1::ColorF(D2D1::ColorF::White));
hdl->DrawRectangle(
D2D1::RectF(10, 10, 100, 100),
brush
);
HRESULT hr = hdl->EndDraw();
if (FAILED(hr)) {
MessageBox(NULL, _T("Draw failed!"), _T("Error"), 0);
}

下面展示的就是Direct2D绘图的HelloWorld程序了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include"frwnd.h"
#include"d2d1.h"

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}

HWND hwnd;
ID2D1Factory * d2dFactory;
ID2D1HwndRenderTarget* hdl;
ID2D1SolidColorBrush* brush;
void Init() {
HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dFactory);
if (FAILED(hr)) {
MessageBox(hwnd, _T("Create D2D factory failed!"), _T("Error"), 0);
return;
}

RECT rc;
GetClientRect(hwnd, &rc);
hr = d2dFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hwnd,
D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)
),
&hdl
);
if (FAILED(hr)) {
MessageBox(hwnd, _T("Create render target failed!"), _T("Error"), 0);
return;
}

hr = hdl->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Red),
&brush
);
if (FAILED(hr)) {
MessageBox(hwnd, _T("Create brush failed!"), _T("Error"), 0);
return;
}
}

bool Display() {
hdl->BeginDraw();
hdl->Clear(D2D1::ColorF(D2D1::ColorF::White));
hdl->DrawRectangle(
D2D1::RectF(10, 10, 100, 100),
brush
);
HRESULT hr = hdl->EndDraw();
if (FAILED(hr)) {
MessageBox(NULL, _T("Draw failed!"), _T("Error"), 0);
return false;
}
return true;
}

FrWnd myWnd(640, 480, WndProc, Display, "HelloWorld");

int WINAPI WinMain(WINPARAMETERS) {
if (!myWnd.Create(INITPARAMETERS))
return 0;
hwnd = myWnd.GetHandle();
Init();
myWnd.Run();
return 0;
}

画出来了:

fr2dhelloworld.png

五、封装初始化过程

Fr2D封装Direct2D的初始化过程。将工厂类ID2D1Factory和ID2D1HwndRenderTarget封装到Fr2D类,是Fr2D的工厂类,完成对Fr2D中其他对象的创建;ID2D1SolidColorBrush封装为Fr2DBrush。如此,上面的HelloWorld程序就变成了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include"frwnd.h"
#include"fr2d.h"

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}

HWND hwnd;
Fr2D fr2d(hwnd);
Fr2DBrush redBrush;
void Init() {
fr2d.Create();
fr2d.CreateBrush(redBrush, _FR2DCOLOR(Red));
}

bool Display() {
fr2d.BeginDraw();
fr2d.Clear(_FR2DCOLOR(White));
fr2d.DrawRectangle(redBrush, 10, 10, 100, 100, 1);
fr2d.EndDraw();
return true;
}

FrWnd myWnd(640, 480, WndProc, Display, "HelloWorld");

int WINAPI WinMain(WINPARAMETERS) {
if (!myWnd.Create(INITPARAMETERS))
return 0;
hwnd = myWnd.GetHandle();
Init();
myWnd.Run();
return 0;
}