做三角剖分的时候所计算的顶点都是float或者double型变量,而在GDI里画图都是INT型输入参数,这便产生了精度损失的矛盾。找了一圈浮动绘图渲染引擎,发现还是MS的Direct2D更方便些,而且还支持硬件加速,理论上渲染效率比GDI软解的要高。
-win8.1 x64
-VS2010
-MFC
可以从MS官网上下载最新的DXSDK
我这里嫌弃这个SDK太大(600MB)没直接安装,而是从中提取了lib和include文件夹来配置,一样可以使用。整个环境配置如下:
a. 在站内下载头文件和库文件压缩包
b. 新建MFC对话框工程
c. 解压缩到该工程目录
d. 工程右键-Properties-Configuration Properties-VC++ Directories的include Directories里添加$(ProjectDir)Include
e. library Directories里添加$(ProjectDir)lib
f. 工程右键-Properties-Configuration Properties-Linker-Additional Deppendencies里添加d2d1.lib;dxguid.lib;dwrite.lib
这里写了一个很简单的封装D2D的类,可以创建销毁各种资源,画文本,画矩形等。代码如下
#ifndef _CD2D_H
#define _CD2D_H
#include <D2D1.h>// header for Direct2D
#include <Dwrite.h>
#define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}
class CD2D
{
public:
CD2D();
~CD2D();
public:
BOOL CreateD2DResource(HWND hWnd);
BOOL DrawText(CString sFontName,FLOAT fFontSize,
FLOAT left,FLOAT top,FLOAT right,FLOAT bottom,CString sText);
BOOL DrawRectangle(FLOAT left,FLOAT top,FLOAT right,FLOAT bottom);
void Cleanup(void);
protected:
private:
ID2D1Factory* pD2DFactory; // Direct2D factory
ID2D1HwndRenderTarget* pRenderTarget; // Render target
ID2D1SolidColorBrush* pBlackBrush; // A black brush, reflect the line color
IDWriteFactory* pDWriteFactory; //Dwrite
RECT rc ; // Render area
HWND hwnd ; // Window handle
};
#endif
#include "stdafx.h"
#include "CD2D.h"
CD2D::CD2D()
{
pD2DFactory = NULL;
pRenderTarget = NULL;
pBlackBrush = NULL;
pDWriteFactory = NULL;
hwnd = NULL;
}
CD2D::~CD2D()
{
if (hwnd)
{
Cleanup();
}
}
BOOL CD2D::CreateD2DResource(HWND hWnd)
{
if (!pRenderTarget)
{
HRESULT hr ;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory) ;
if (FAILED(hr))
{
AfxMessageBox(_T("创建factory失败!"));
return (FALSE) ;
}
hwnd = hWnd;
// Obtain the size of the drawing area
GetClientRect(hWnd, &rc) ;
// Create a Direct2D render target
hr = pD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hWnd,
D2D1::SizeU(rc.right - rc.left,rc.bottom - rc.top)
),
&pRenderTarget
) ;
pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
if (FAILED(hr))
{
AfxMessageBox(_T("创建target失败!"));
return (FALSE) ;
}
// Create a brush
hr = pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&pBlackBrush
) ;
if (FAILED(hr))
{
AfxMessageBox(_T("创建brush失败!"));
return (FALSE) ;
}
//
// Create DirectWrite Factory
hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&pDWriteFactory)
);
if(FAILED(hr))
{
AfxMessageBox(_T("创建DirectWrite失败!"));
return (FALSE) ;
}
return (TRUE) ;
}
return (FALSE) ;
}
BOOL CD2D::DrawText(CString sFontName,FLOAT fFontSize,
FLOAT left,FLOAT top,FLOAT right,FLOAT bottom,CString sText)
{
IDWriteTextFormat* g_pTextFormat = NULL;
HRESULT hr ;
GetClientRect(hwnd, &rc) ;
hr = pDWriteFactory->CreateTextFormat(
sFontName, // Font family name
NULL, // Font collection(NULL sets it to the system font collection)
DWRITE_FONT_WEIGHT_REGULAR, // Weight
DWRITE_FONT_STYLE_NORMAL, // Style
DWRITE_FONT_STRETCH_NORMAL, // Stretch
fFontSize, // Size 50.0f
L"en-us", // Local
&g_pTextFormat // Pointer to recieve the created object
);
if(FAILED(hr))
{
AfxMessageBox(_T("创建DirectWrite失败!"));
return(FALSE);
}
// Create text layout rect
D2D1_RECT_F textLayoutRect = D2D1::RectF(left,top,right,bottom);
// Draw text
pRenderTarget->BeginDraw() ;
pRenderTarget->DrawText(
sText, // Text to render
sText.GetLength(), // Text length
g_pTextFormat, // Text format
textLayoutRect, // The region of the window where the text will be rendered
pBlackBrush // The brush used to draw the text
);
pRenderTarget->EndDraw() ;
return (TRUE) ;
}
BOOL CD2D::DrawRectangle(FLOAT left,FLOAT top,FLOAT right,FLOAT bottom)
{
pRenderTarget->BeginDraw() ;
// Clear background color white
pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
// Draw Rectangle
pRenderTarget->DrawRectangle(
D2D1::RectF(left,top,right,bottom),
pBlackBrush
);
HRESULT hr = pRenderTarget->EndDraw() ;
if (FAILED(hr))
{
AfxMessageBox(_T("创建Direct失败!"));
return (FALSE);
}
return (TRUE);
}
void CD2D::Cleanup(void)
{
SAFE_RELEASE(pRenderTarget) ;
SAFE_RELEASE(pBlackBrush) ;
SAFE_RELEASE(pD2DFactory) ;
SAFE_RELEASE(pDWriteFactory) ;
}
#include "CD2D.h"
.....
private:
CD2D m_D2DC;
......
BOOL CxxxDlg::OnInitDialog()
{
......
HWND hwnd = GetSafeHwnd();
m_D2DC.CreateD2DResource(hwnd);
......
}
void CxxxDlg::OnPaint()
{
....
else
{
if (GetSafeHwnd() != NULL)
{
m_D2DC.DrawRectangle(50.0,50.0,75.0,75.0);
m_D2DC.DrawText(_T("微软雅黑"),20.0,30.0,30.0,250.0,25.0,_T("D2D Hello World!"));
CPaintDC dc(this);//GDI画图
dc.MoveTo(300,150);
dc.LineTo(250 ,200);
dc.LineTo(350 ,300);
dc.LineTo(300 ,150);
}
CDialogEx::OnPaint();
}
}
根据
pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
的设置,得到2个结果
可以看到D2D的抗锯齿效果还是很好的,不过注意,这是以效率下降为代价的,虽然这种损失在工作量小的时候基本感觉不到。
- Direct2D教程(外篇)环境配置
- Direct2D入门
- Direct2D
- direct2D 画出来的图形为什么会发虚
现在MS系统里默认的是96DPI,但目前很多设备高分辨率在这个DPI下字体很小,根本看不清,只能调高DPI,我的15寸笔记本分辨率是1080p,调整到150% 即使120DPI就很舒服了,但随之而来了一个问题就是MFC里的视图也跟着缩放了150%,解决方法很简单,在D2D初始化的时候添加一行命令
pRenderTarget->SetDpi(96.0,96.0);
参考文献
1.Direct2D and High-DPI
2.How to Ensure That Your Application Displays Properly on High-DPI Displays
3.ID2D1DeviceContext::SetUnitMode method