Общие сведения о взаимодействии Direct2D и GDI
В этом разделе описывается совместное использование Direct2D и GDI . Существует два способа объединения Direct2D с GDI: вы можете записать содержимое GDI в целевой объект отрисовки, совместимый с Direct2D GDI, или записать содержимое Direct2D в контекст устройства GDI (DC).
В этом разделе содержатся следующие подразделы.
- Предварительные условия
- Рисование содержимого Direct2D в контексте устройства GDI
- ID2D1DCRenderTargets, преобразования GDI и языковые сборки Windows справа налево
- Рисование содержимого GDI в целевой объект отрисовки GDI-Compatible Direct2D
- Связанные темы
Предварительные требования
В этом обзоре предполагается, что вы знакомы с основными операциями рисования Direct2D. Руководство см. в статье Создание простого приложения Direct2D. Также предполагается, что вы знакомы с операциями рисования GDI.
Рисование содержимого Direct2D в контексте устройства GDI
Чтобы рисовать содержимое Direct2D в контроллере домена GDI, используйте ID2D1DCRenderTarget. Чтобы создать целевой объект отрисовки контроллера домена, используйте метод ID2D1Factory::CreateDCRenderTarget . Этот метод принимает два параметра.
Первый параметр, D2D1_RENDER_TARGET_PROPERTIES структура, указывает отрисовку, удаленное взаимодействие, DPI, формат пикселей и сведения об использовании. Чтобы обеспечить работу целевого объекта отрисовки контроллера домена с GDI, задайте для формата DXGI значение DXGI_FORMAT_B8G8R8A8_UNORM , а для альфа-режима — D2D1_ALPHA_MODE_PREMULTIPLIED или D2D1_ALPHA_MODE_IGNORE.
Второй параметр — это адрес указателя, который получает ссылку на целевой объект отрисовки контроллера домена.
В следующем коде создается целевой объект отрисовки контроллера домена.
// Create a DC render target.
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_IGNORE),
0,
0,
D2D1_RENDER_TARGET_USAGE_NONE,
D2D1_FEATURE_LEVEL_DEFAULT
);
hr = m_pD2DFactory->CreateDCRenderTarget(&props, &m_pDCRT);
В приведенном выше коде m_pD2DFactory является указателем на ID2D1Factory, а m_pDCRT — на ID2D1DCRenderTarget.
Перед отрисовкой с целевым объектом отрисовки контроллера домена необходимо использовать его метод BindDC , чтобы связать его с контроллером домена GDI. Это можно сделать при каждом использовании другого контроллера домена или при изменении размера области, на которую вы хотите нарисовать.
Метод BindDC принимает два параметра: hDC и pSubRect. Параметр hDC предоставляет дескриптор контекста устройства, который получает выходные данные целевого объекта отрисовки. Параметр pSubRect — это прямоугольник, описывающий часть контекста устройства, в которую отображается содержимое. Целевой объект отрисовки контроллера домена обновляет свой размер в соответствии с областью контекста устройства, описанной в pSubRect, в случае изменения размера.
Следующий код привязывает контроллер домена к целевому объекту отрисовки контроллера домена.
HRESULT DemoApp::OnRender(const PAINTSTRUCT &ps)
{
// Get the dimensions of the client drawing area.
GetClientRect(m_hwnd, &rc);
C++ |
---|
|
После связывания целевого объекта отрисовки контроллера домена с контроллером домена его можно использовать для рисования. Следующий код рисует содержимое Direct2D и GDI с помощью контроллера домена.
HRESULT DemoApp::OnRender(const PAINTSTRUCT &ps)
{
HRESULT hr;
RECT rc;
// Get the dimensions of the client drawing area.
GetClientRect(m_hwnd, &rc);
//
// Draw the pie chart with Direct2D.
//
// Create the DC render target.
hr = CreateDeviceResources();
if (SUCCEEDED(hr))
{
// Bind the DC to the DC render target.
hr = m_pDCRT->BindDC(ps.hdc, &rc);
m_pDCRT->BeginDraw();
m_pDCRT->SetTransform(D2D1::Matrix3x2F::Identity());
m_pDCRT->Clear(D2D1::ColorF(D2D1::ColorF::White));
m_pDCRT->DrawEllipse(
D2D1::Ellipse(
D2D1::Point2F(150.0f, 150.0f),
100.0f,
100.0f),
m_pBlackBrush,
3.0
);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F(
(150.0f + 100.0f * 0.15425f),
(150.0f - 100.0f * 0.988f)),
m_pBlackBrush,
3.0
);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F(
(150.0f + 100.0f * 0.525f),
(150.0f + 100.0f * 0.8509f)),
m_pBlackBrush,
3.0
);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F(
(150.0f - 100.0f * 0.988f),
(150.0f - 100.0f * 0.15425f)),
m_pBlackBrush,
3.0
);
hr = m_pDCRT->EndDraw();
if (SUCCEEDED(hr))
{
//
// Draw the pie chart with GDI.
//
// Save the original object.
HGDIOBJ original = NULL;
original = SelectObject(
ps.hdc,
GetStockObject(DC_PEN)
);
HPEN blackPen = CreatePen(PS_SOLID, 3, 0);
SelectObject(ps.hdc, blackPen);
Ellipse(ps.hdc, 300, 50, 500, 250);
POINT pntArray1[2];
pntArray1[0].x = 400;
pntArray1[0].y = 150;
pntArray1[1].x = static_cast<LONG>(400 + 100 * 0.15425);
pntArray1[1].y = static_cast<LONG>(150 - 100 * 0.9885);
POINT pntArray2[2];
pntArray2[0].x = 400;
pntArray2[0].y = 150;
pntArray2[1].x = static_cast<LONG>(400 + 100 * 0.525);
pntArray2[1].y = static_cast<LONG>(150 + 100 * 0.8509);
POINT pntArray3[2];
pntArray3[0].x = 400;
pntArray3[0].y = 150;
pntArray3[1].x = static_cast<LONG>(400 - 100 * 0.988);
pntArray3[1].y = static_cast<LONG>(150 - 100 * 0.15425);
Polyline(ps.hdc, pntArray1, 2);
Polyline(ps.hdc, pntArray2, 2);
Polyline(ps.hdc, pntArray3, 2);
DeleteObject(blackPen);
// Restore the original object.
SelectObject(ps.hdc, original);
}
}
if (hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
DiscardDeviceResources();
}
return hr;
}
Этот код создает выходные данные, как показано на следующем рисунке (были добавлены выноски, чтобы подчеркнуть разницу между отрисовкой Direct2D и GDI).)
ID2D1DCRenderTargets, преобразования GDI и языковые сборки Windows справа налево
При использовании ID2D1DCRenderTarget он отрисовывает содержимое Direct2D во внутреннее растровое изображение, а затем отображает его в контроллере домена с помощью GDI.
GDI может применить преобразование GDI (с помощью метода SetWorldTransform ) или другой эффект к тому же контроллеру домена, который используется целевым объектом отрисовки. В этом случае GDI преобразует растровое изображение, созданное Direct2D. Использование преобразования GDI для преобразования содержимого Direct2D может привести к снижению качества визуального отображения выходных данных, так как вы преобразуете растровое изображение, для которого уже рассчитаны сглаживание и положение подпиксели.
Например, предположим, что вы используете целевой объект отрисовки для рисования сцены, содержащей сглаживание геометрических объектов и текста. Если вы используете преобразование GDI для применения преобразования масштабирования к контроллеру домена и масштабирования сцены таким образом, чтобы она была в 10 раз больше, вы увидите пикселизацию и зубчатые края. (Однако если вы применили аналогичное преобразование с помощью Direct2D, качество визуализации сцены не будет снижено.)
В некоторых случаях может быть не очевидно, что GDI выполняет дополнительную обработку, которая может ухудшить качество содержимого Direct2D. Например, в сборке Windows справа налево (RTL) содержимое, отображаемое id2D1DCRenderTarget , может быть горизонтально инвертировано, когда GDI копирует его в место назначения. Фактически ли инвертировано содержимое, зависит от текущих параметров контроллера домена.
В зависимости от типа отображаемого содержимого может потребоваться предотвратить инверсию. Если содержимое Direct2D содержит текст ClearType, это приведет к снижению качества текста.
Поведением отрисовки RTL можно управлять с помощью функции SetLayout GDI. Чтобы предотвратить зеркальное отображение, вызовите функцию SetLayout GDI и укажите LAYOUT_BITMAPORIENTATIONPRESERVED в качестве единственного значения для второго параметра (не объединяйте его с LAYOUT_RTL), как показано в следующем примере:
SetLayout(m_hwnd, LAYOUT_BITMAPORIENTATIONPRESERVED);
Рисование содержимого GDI в целевой объект отрисовки GDI-Compatible Direct2D
В предыдущем разделе описывается запись содержимого Direct2D в контроллер домена GDI. Вы также можете записать содержимое GDI в целевой объект отрисовки, совместимый с Direct2D GDI. Этот подход полезен для приложений, которые в основном отрисовывается с помощью Direct2D, но имеют модель расширяемости или другое устаревшее содержимое, требующее возможности отрисовки с помощью GDI.
Для отрисовки содержимого GDI в целевой объект отрисовки, совместимый с Direct2D GDI, используйте ID2D1GdiInteropRenderTarget, который предоставляет доступ к контексту устройства, который может принимать вызовы рисования GDI. В отличие от других интерфейсов, объект ID2D1GdiInteropRenderTarget не создается напрямую. Вместо этого используйте метод QueryInterface существующего целевого экземпляра отрисовки. В следующем коде показано, как это сделать.
D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties();
rtProps.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
// Create a GDI compatible Hwnd render target.
hr = m_pD2DFactory->CreateHwndRenderTarget(
rtProps,
D2D1::HwndRenderTargetProperties(m_hwnd, size),
&m_pRenderTarget
);
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->QueryInterface(__uuidof(ID2D1GdiInteropRenderTarget), (void**)&m_pGDIRT);
}
В приведенном выше коде m_pD2DFactory является указателем на ID2D1Factory, а m_pGDIRT — указатель на ID2D1GdiInteropRenderTarget.
Обратите внимание, что флагD2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE указан при создании целевого объекта отрисовки, совместимого с Hwnd GDI. Если требуется формат пикселей, используйте DXGI_FORMAT_B8G8R8A8_UNORM. Если требуется альфа-режим, используйте D2D1_ALPHA_MODE_PREMULTIPLIED или D2D1_ALPHA_MODE_IGNORE.
Обратите внимание, что метод QueryInterface всегда выполняется успешно. Чтобы проверить, будут ли методы интерфейса ID2D1GdiInteropRenderTarget работать для заданного целевого объекта отрисовки, создайте D2D1_RENDER_TARGET_PROPERTIES , указывающую совместимость GDI и соответствующий формат пикселей, а затем вызовите метод IsSupported целевого объекта отрисовки, чтобы узнать, совместим ли целевой объект отрисовки с GDI.
В следующем примере показано, как нарисовать круговую диаграмму (содержимое GDI) для целевого объекта отрисовки, совместимого с Hwnd GDI.
HDC hDC = NULL;
hr = m_pGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &hDC);
if (SUCCEEDED(hr))
{
// Draw the pie chart to the GDI render target associated with the Hwnd render target.
HGDIOBJ original = NULL;
original = SelectObject(
hDC,
GetStockObject(DC_PEN)
);
HPEN blackPen = CreatePen(PS_SOLID, 3, 0);
SelectObject(hDC, blackPen);
Ellipse(hDC, 300, 50, 500, 250);
POINT pntArray1[2];
pntArray1[0].x = 400;
pntArray1[0].y = 150;
pntArray1[1].x = static_cast<LONG>(400 + 100 * 0.15425);
pntArray1[1].y = static_cast<LONG>(150 - 100 * 0.9885);
POINT pntArray2[2];
pntArray2[0].x = 400;
pntArray2[0].y = 150;
pntArray2[1].x = static_cast<LONG>(400 + 100 * 0.525);
pntArray2[1].y = static_cast<LONG>(150 + 100 * 0.8509);
POINT pntArray3[2];
pntArray3[0].x = 400;
pntArray3[0].y = 150;
pntArray3[1].x = static_cast<LONG>(400 - 100 * 0.988);
pntArray3[1].y = static_cast<LONG>(150 - 100 * 0.15425);
Polyline(hDC, pntArray1, 2);
Polyline(hDC, pntArray2, 2);
Polyline(hDC, pntArray3, 2);
DeleteObject(blackPen);
// Restore the original object.
SelectObject(hDC, original);
m_pGDIRT->ReleaseDC(NULL);
}
Код выводит диаграммы, как показано на следующем рисунке с выносками, чтобы выделить разницу в качестве отрисовки. Правая круговая диаграмма (содержимое GDI) имеет более низкое качество отрисовки, чем левая круговая диаграмма (содержимое Direct2D). Это связано с тем, что Direct2D поддерживает отрисовку с сглаживание
Связанные темы