logo头像
Snippet 博客主题

Windows Graphics

Windows Graphics

Overview of the Windows Graphics Architecture

Hardware Acceleration, The term hardware acceleration refers to graphics computations performed by the graphics processing unit (GPU), rather than the CPU.
While GDI supports hardware accleration for certain operations, many GDI operations are bound to the CPU.
Transparency and Anti-aliasing, Direct2D supports fully hardware-accelerated alpha-blending (transparency).
GDI has limited support for alpha-blending. Most GDI functions do not support alpha blending, although GDI does support alpha blending during a bitblt operation.
GDI+ supports transparency, but the alpha blending is performed by the CPU, so it does not benefit from hardware acceleration.

The Desktop Window Manager

Retained Mode Versus Immediate Mode

Your First Direct2D Program

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include <windows.h>
#include <d2d1.h>
#pragma comment(lib, "d2d1")

#include "basewin.h"

template <class T> void SafeRelease(T **ppT)
{
if (*ppT) {
(*ppT)->Release();
*ppT = NULL;
}
}

class MainWindow : public BaseWindow<MainWindow>
{
ID2D1Factory *pFactory;
ID2D1HwndRenderTarget *pRenderTarget;
ID2D1SolidColorBrush *pBrush;
D2D1_ELLIPSE ellipse;

void CalculateLayout();
HRESULT CreateGraphicsResources();
void DiscardGraphicsResources();
void OnPaint();
void Resize();

public:

MainWindow() : pFactory(NULL), pRenderTarget(NULL), pBrush(NULL)
{
}

PCWSTR ClassName() const { return L"Circle Window Class"; }
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
};

// Recalculate drawing layout when the size of the window changes.

void MainWindow::CalculateLayout()
{
if (pRenderTarget != NULL)
{
D2D1_SIZE_F size = pRenderTarget->GetSize();
const float x = size.width / 2;
const float y = size.height / 2;
const float radius = min(x, y);
ellipse = D2D1::Ellipse(D2D1::Point2F(x, y), radius, radius);
}
}

HRESULT MainWindow::CreateGraphicsResources()
{
HRESULT hr = S_OK;
if (pRenderTarget == NULL) {
RECT rc;
GetClientRect(m_hwnd, &rc);

D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);

hr = pFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(m_hwnd, size),
&pRenderTarget);

if (SUCCEEDED(hr)) {
const D2D1_COLOR_F color = D2D1::ColorF(1.0f, 1.0f, 0);
hr = pRenderTarget->CreateSolidColorBrush(color, &pBrush);

if (SUCCEEDED(hr)) {
CalculateLayout();
}
}
}
return hr;
}

void MainWindow::DiscardGraphicsResources()
{
SafeRelease(&pRenderTarget);
SafeRelease(&pBrush);
}

void MainWindow::OnPaint()
{
HRESULT hr = CreateGraphicsResources();
if (SUCCEEDED(hr)) {
PAINTSTRUCT ps;
BeginPaint(m_hwnd, &ps);

pRenderTarget->BeginDraw();

pRenderTarget->Clear( D2D1::ColorF(D2D1::ColorF::SkyBlue) );
pRenderTarget->FillEllipse(ellipse, pBrush);

hr = pRenderTarget->EndDraw();
if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET) {
DiscardGraphicsResources();
}
EndPaint(m_hwnd, &ps);
}
}

void MainWindow::Resize()
{
if (pRenderTarget != NULL) {
RECT rc;
GetClientRect(m_hwnd, &rc);

D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);

pRenderTarget->Resize(size);
CalculateLayout();
InvalidateRect(m_hwnd, NULL, FALSE);
}
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR, int nCmdShow)
{
MainWindow win;

if (!win.Create(L"Circle", WS_OVERLAPPEDWINDOW)) {
return 0;
}

ShowWindow(win.Window(), nCmdShow);

// Run the message loop.

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

return 0;
}

LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory)))
{
return -1; // Fail CreateWindowEx.
}
return 0;

case WM_DESTROY:
DiscardGraphicsResources();
SafeRelease(&pFactory);
PostQuitMessage(0);
return 0;

case WM_PAINT:
OnPaint();
return 0;

case WM_SIZE:
Resize();
return 0;
}
return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}

Render Targets, Devices, and Resources

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
HRESULT MainWindow::CreateGraphicsResources()
{
HRESULT hr = S_OK;
if (pRenderTarget == NULL) {
RECT rc;
GetClientRect(m_hwnd, &rc);

D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);

hr = pFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(m_hwnd, size),
&pRenderTarget);

if (SUCCEEDED(hr)) {
const D2D1_COLOR_F color = D2D1::ColorF(1.0f, 1.0f, 0);
hr = pRenderTarget->CreateSolidColorBrush(color, &pBrush);

if (SUCCEEDED(hr)) {
CalculateLayout();
}
}
}
return hr;
}

Drawing with Direct2D

DPI and Device-Independent Pixels

Using Color in Direct2D

Applying Transforms in Direct2D

Appendix: Matrix Transforms