您的位置:首页 > 其它

Direct2D+MFC学习笔记

2015-09-08 15:13 447 查看

0.学习初衷

做三角剖分的时候所计算的顶点都是float或者double型变量,而在GDI里画图都是INT型输入参数,这便产生了精度损失的矛盾。找了一圈浮动绘图渲染引擎,发现还是MS的Direct2D更方便些,而且还支持硬件加速,理论上渲染效率比GDI软解的要高。

1.环境配置

1.1开发平台

-win8.1 x64

-VS2010

-MFC

1.2D2D SDK

可以从MS官网上下载最新的DXSDK

1.3环境配置

我这里嫌弃这个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

2.CD2D简单操作类

这里写了一个很简单的封装D2D的类,可以创建销毁各种资源,画文本,画矩形等。代码如下

2.1 CD2D.h

[code]#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


2.2 CD2D.cpp

[code]#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 ;

    CreateD2DResource(hwnd) ;

    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)
{
    CreateD2DResource(hwnd) ;

    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) ;
}


3.在MFC里画图

3.1 XXXDlg.h里声明变量

[code]#include "CD2D.h"
.....
private:
    CD2D m_D2DC;
    ......


3.2 XXXDlg.cpp里

[code]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();
    }
}


4.结果

根据

[code]pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);


的设置,得到2个结果







可以看到D2D的抗锯齿效果还是很好的,不过注意,这是以效率下降为代价的,虽然这种损失在工作量小的时候基本感觉不到。

5.参考文献

Direct2D教程(外篇)环境配置

Direct2D入门

Direct2D

direct2D 画出来的图形为什么会发虚



6.后记

6.1 高DPI下Direct2D显示不全问题

现在MS系统里默认的是96DPI,但目前很多设备高分辨率在这个DPI下字体很小,根本看不清,只能调高DPI,我的15寸笔记本分辨率是1080p,调整到150% 即使120DPI就很舒服了,但随之而来了一个问题就是MFC里的视图也跟着缩放了150%,解决方法很简单,在D2D初始化的时候添加一行命令

[code]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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: