你的第一个 Direct2D 计划
让我们创建第一个 Direct2D 程序。 程序不执行任何花哨的事情 ,它只是绘制一个圆圈,填充窗口的工作区。 但此程序引入了许多基本的 Direct2D 概念。
下面是 Circle 程序的代码列表。 程序重新使用 BaseWindow
主题 管理应用程序状态中定义的 类。 后面的主题将详细介绍代码。
#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);
}
可以从 Direct2D Circle 示例下载完整的 Visual Studio 项目。
D2D1 命名空间
D2D1 命名空间包含帮助程序函数和类。 这些并非严格意义上的 Direct2D API 的一部分(无需使用它们即可对 Direct2D 进行编程),但它们有助于简化代码。 D2D1 命名空间包含:
- 用于构造颜色值的 ColorF 类。
- 用于构造转换矩阵的 Matrix3x2F 。
- 一组用于初始化 Direct2D 结构的函数。
你将在整个模块中看到 D2D1 命名空间的示例。
下一步
相关主题