Direct2D 是用來建立 2D 圖形的原生程式代碼立即模式 API。 本主題說明如何使用 Direct2D 繪製到 Windows::UI::Core::CoreWindow。
本主題包含下列各節:
- 繪製簡單矩形
- 步驟 1:包含 Direct2D 標頭
- 步驟 2:建立 ID2D1Factory1
- 步驟 3:建立 ID2D1Device 和 ID2D1DeviceContext
- 步驟 4:建立筆刷
- 步驟 5:繪製矩形
- 範例程式代碼
繪製簡單矩形
若要使用 GDI繪製矩形,您可以處理 WM_PAINT 訊息,如下列程式代碼所示。
switch(message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
// Obtain the size of the drawing area.
RECT rc;
GetClientRect(
hwnd,
&rc
);
// Save the original object
HGDIOBJ original = NULL;
original = SelectObject(
ps.hdc,
GetStockObject(DC_PEN)
);
// Create a pen.
HPEN blackPen = CreatePen(PS_SOLID, 3, 0);
// Select the pen.
SelectObject(ps.hdc, blackPen);
// Draw a rectangle.
Rectangle(
ps.hdc,
rc.left + 100,
rc.top + 100,
rc.right - 100,
rc.bottom - 100);
DeleteObject(blackPen);
// Restore the original object
SelectObject(ps.hdc, original);
EndPaint(hwnd, &ps);
}
return 0;
// Code for handling other messages.
使用 Direct2D 繪製相同矩形的程式代碼很類似:它會建立繪圖資源、描述要繪製的圖形、繪製圖形,然後釋放繪圖資源。 後續各節會詳細說明這些步驟。
步驟 1:包含 Direct2D 標頭
除了應用程式所需的標頭之外,還包含 d2d1.h 和 d2d1_1.h 標頭。
步驟 2:建立 ID2D1Factory1
任何 Direct2D 範例所做的第一件事之一,就是建立 ID2D1Factory1。
DX::ThrowIfFailed(
D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory1),
&options,
&m_d2dFactory
)
);
ID2D1Factory1 介面是使用 Direct2D 的起點;使用 ID2D1Factory1 建立 Direct2D 資源。
當您建立處理站時,可以指定它是多線程或單個線程。 (如需多線程處理站的詳細資訊,請參閱 ID2D1Factory 參考頁面的備註。此範例會建立單個線程處理站。
一般而言,您的應用程式應該建立工廠一次,並保留應用程式的整個生命周期。
步驟 3:建立 ID2D1Device 和 ID2D1DeviceContext
在建立工廠之後,請使用它來創建 Direct2D 裝置,然後利用該裝置來創建 Direct2D 裝置內容。 若要建立這些 Direct2D 物件,您必須擁有 Direct3D 11 裝置、DXGI 裝置,以及 DXGI 交換鏈結。 如需建立必要條件的詳細資訊,請參閱 裝置和裝置內容。
// Obtain the underlying DXGI device of the Direct3D11.1 device.
DX::ThrowIfFailed(
m_d3dDevice.As(&dxgiDevice)
);
// Obtain the Direct2D device for 2-D rendering.
DX::ThrowIfFailed(
m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice)
);
// And get its corresponding device context object.
DX::ThrowIfFailed(
m_d2dDevice->CreateDeviceContext(
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
&m_d2dContext
)
);
裝置上下文是一種裝置,可以執行繪圖操作並建立裝置依賴的繪圖資源,例如畫筆。 您也可以使用裝置內容將 ID2D1Bitmap 連結至 DXGI 表面,以此作為渲染目標。 裝置內容可以轉譯為不同類型的目標。
這裡的程式代碼宣告了與轉譯到 CoreWindow的 DXGI 交換鏈連結的點陣圖屬性。 ID2D1DeviceContext::CreateBitmapFromDxgiSurface 方法會從 DXGI 介面取得 Direct2D 表面。 如此一來,任何呈現在目標 ID2D1Bitmap 的內容,都會呈現在交換鏈結的表面。
擁有 Direct2D 表面之後,請使用 ID2D1DeviceContext::SetTarget 方法來將它設定為使用中的轉譯目標。
// Now we set up the Direct2D render target bitmap linked to the swapchain.
// Whenever we render to this bitmap, it will be directly rendered to the
// swapchain associated with the window.
D2D1_BITMAP_PROPERTIES1 bitmapProperties =
BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
m_dpi,
m_dpi
);
// Direct2D needs the dxgi version of the backbuffer surface pointer.
ComPtr<IDXGISurface> dxgiBackBuffer;
DX::ThrowIfFailed(
m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
);
// Get a D2D surface from the DXGI back buffer to use as the D2D render target.
DX::ThrowIfFailed(
m_d2dContext->CreateBitmapFromDxgiSurface(
dxgiBackBuffer.Get(),
&bitmapProperties,
&m_d2dTargetBitmap
)
);
// So now we can set the Direct2D render target.
m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());
步驟 4:建立筆刷
就像工廠一樣,設備上下文可以建立繪圖資源。 在此範例中,裝置內容會建立筆刷。
ComPtr<ID2D1SolidColorBrush> pBlackBrush;
DX::ThrowIfFailed(
m_d2dContext->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&pBlackBrush
)
);
筆刷是繪製區域的物件,例如圖形的筆劃或幾何圖形的填滿。 本範例中的筆刷會使用預先定義的純色黑色繪製區域。
Direct2D 也提供其他類型的筆刷:用於繪製線性和放射狀漸層的漸層筆刷、用於繪製位圖和圖樣的 位圖筆刷,以及從 Windows 8 開始,用於繪製已轉譯影像的 影像筆刷。
某些繪圖 API 提供畫筆來繪製外框和筆刷來填滿圖形。 Direct2D 不同:它不提供畫筆物件,而是使用筆刷繪製外框和填滿圖形。 繪製外框時,請使用 ID2D1StrokeStyle 介面,或者從 Windows 8 開始使用 ID2D1StrokeStyle1 介面,並搭配筆刷來控制路徑描邊操作。
筆刷只能與建立它的轉譯目標以及相同資源域中的其他轉譯目標搭配使用。 一般而言,您應該建立筆刷一次,並保留筆刷,以用於建立筆刷的轉譯目標。 ID2D1SolidColorBrush 是唯一的例外:因為建立成本相對較低,所以每次繪製框架時,您都可以建立 ID2D1SolidColorBrush,而不會有任何明顯的效能損失。 您也可以使用單一 ID2D1SolidColorBrush,並在每次使用時變更其色彩或不透明度。
步驟 5:繪製矩形
接下來,使用裝置內容來繪製矩形。
m_d2dContext->BeginDraw();
m_d2dContext->DrawRectangle(
D2D1::RectF(
rc.left + 100.0f,
rc.top + 100.0f,
rc.right - 100.0f,
rc.bottom - 100.0f),
pBlackBrush);
DX::ThrowIfFailed(
m_d2dContext->EndDraw()
);
DX::ThrowIfFailed(
m_swapChain->Present1(1, 0, ¶meters);
);
DrawRectangle 方法會採用兩個參數:要繪製的矩形,以及用來繪製矩形外框的筆刷。 或者,您也可以指定筆劃寬度、虛線圖樣、線條聯結和結束上限選項。
在發出任何繪圖命令之前,您必須先呼叫 BeginDraw 方法,而且您必須在完成發出繪圖命令之後呼叫 EndDraw 方法。 EndDraw 方法會傳回一個 HRESULT,指出繪圖命令是否成功。 如果不成功,輔助函式 ThrowIfFailed 將會擲回例外狀況。
IDXGISwapChain::Present 方法會將緩衝區表面與螢幕表面交換,以顯示結果。
範例程序代碼
本主題中的程式代碼會顯示 Direct2D 應用程式的基本元素。 為了簡潔起見,本主題會省略應用程式架構和錯誤處理程序代碼,這是撰寫良好應用程式的特性。