Direct2D教程(二)来看D2D世界中的Hello,World
引子
任何一门语言的第一个教程几乎都是Hello,world。我们也不例外,但是这里不是教大家打印Hello,world,而是编写一个简单的D2D绘制程序,让大家对Direct2D的程序结构及编程方法有一个基本的认识。下面我们来看如何一步一步绘制一个矩形。
基本概念
在开始之前,还是先介绍一些基本的概念,有助于大家理解程序,这些概念包括,Brush(画刷),Render target(渲染目标),Geometry(几何图形),它们会贯穿整个教程,所以越早介绍越好,对于有Windows GDI基础的人来说,理解这些概念很容易。没有基础的也没关系,我们可以先了解一下,随着学习的深入,会有更加深刻的认识。
Brush
Brush-画刷,画刷是绘图的工具,它管理图形的颜色,虚实,画刷可以绘制几何图形,也可以绘制位图。
Render target
Render target-渲染目标(姑且这么翻译吧)是绘制的场所,其实这就是一个surface,一个表面,再具体点就是一块内存,可以是显存,也可能是系统内存。所有的绘图操作都在这里完成。
Geometry, Bitmap, Text
Geometry-几何图形,Bitmap-位图, Text-文本。这三者是要绘制的内容,几何图形包括矩形,圆角矩形,椭圆等,当然Direct2D除了可以绘制几何图形之外,还可绘制位图和文本,D2D没有提供加载位图的接口,所以对位图的加载都是使用WIC来实现的。而对文本的绘制则是通过DirectWrite来实现的,DirectWrite在分类上属于D2D,但是目前已经独立成一个组件了。为了便于理解以上三者之间的关系,大家可以想象一个画家,他在作画的时候,都需要那些东西呢?第一,他需要一支画笔用来绘制,这相当于上面的画刷,第二,他需要一张纸或者一张画布用来承载绘制的东西,这就是上面的Render target,最后,他想画什么呢?山水?花鸟?亦或是人物?这就是绘制的内容,相当于上面的几何图形,位图或者文本。
Resource
在Direct2D中主要有两种资源,一是设备无关的资源,另一个是设备相关的资源。所谓设备无关,是指该资源不与特定的硬件渲染设备相关联,所以设备无关的资源都分配在CPU中,而设备相关是指该资源与特定的渲染硬件相关联,比如当硬件加速可用时,使用GPU渲染,否则使用CPU渲染。
设备无关的资源
- ID2D1DrawingStateBlock
- ID2D1Factory
- ID2D1Geometry及继承自它的接口
- ID2D1GeometrySink和ID2D1SimplifiedGeometrySink
- ID2D1StrokeStyle
除了ID2D1RenderTarget之外,所有使用ID2D1Factory创建的资源都是设备无关的。
设备相关的资源
- ID2D1Brush及继承自它的接口
- ID2D1Layer
- ID2D1RenderTarget及继承自它的接口
一般来说,使用ID2D1RenderTarget创建的资源都是设备相关的。
程序框架
一个简单的D2D程序大致包含下面三个核心函数。
1 创建资源(CreateResources) - 设备无关的资源可以一次性创建,永久使用,而设备相关的资源则需要随着设备改变而相应的改变。
2 渲染(Render) - 响应WM_PAINT消息进行绘制。
3 清理资源(Cleanup) - DX是基于COM的,所有COM对象在使用完毕时,都要释放。
为了便于大家理解,我画了一张图,这个图简单描述了D2D程序的基本渲染流程。
需要说明的是,Direct2D的渲染时机与D3D有些不同,D3D是在没有消息处理时进行渲染,而D2D则是响应WM_PAINT消息进行渲染。下面的代码中会有详细的解释。
代码
添加头文件
除了Win32编程需要的头文件(比如Windows.h)之外,任何D2D程序都需要头文件d2d1.h。
#include <windows.h>
#include <D2D1.h>
声明全局变量
首先我们需要一个ID2D1Factory*类型的对象,也就是D2D工厂接口,这个接口是所有D2D程序的起始点,几乎所有的D2D资源都是由这个接口创建的,其次我们需要一个渲染的场所,也就是Render Target,在D2D中有多种类型的Render Target,这里我们选择ID2D1HwndRenderTarget类型,用来在窗口中进行渲染。最后我们定义一个画刷,用来绘制图形,这里选择固定颜色的画刷,即ID2D1SolidColorBrush。
ID2D1Factory* pD2DFactory = NULL ; // Direct2D factory
ID2D1HwndRenderTarget* pRenderTarget = NULL; // Render target
ID2D1SolidColorBrush* pBlackBrush = NULL ; // A black brush, reflect the line color RECT rc ; // Render area
HWND g_Hwnd ; // Window handle
创建D2D工厂
接下来创建D2D工厂对象,有了这个对象才能创建后续的资源,这个函数有两个参数,第一个参数是工厂的类型,这里只有单线程和多线程两类,如果是单线程的话,意味着D2D不会为所创建的工厂的对象以及由这个对象创建的子对象提供同步机制,也就是说,如果有多个线程访问了这个资源,那么需要自己提供同步机制。如果是多线程类型,那么D2D会为你提供同步机制。第二个参数用来接收创建的工厂。
HRESULT hr ; hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory) ;
if (FAILED(hr))
{
MessageBox(hWnd, "Create D2D factory failed!", "Error", 0) ;
return ;
}
创建Render target
有了工厂对象以后,开始创建RenderTarget,CreateHwndRenderTarget函数有三个参数,第一个参数是Render target属性,包括渲染模式,象素格式,DPI等,D2D提供了一个函数D2D1::RenderTargetProperties(),可以用来生成默认的属性,我们这里直接使用这个函数。第二个参数是Hwnd类型的Render target属性,它包含三个参数,第一个是窗口句柄,第二个是Render target的大小,第三个参数是Present选项,这个参数有个默认值,这里我们使用它的默认值。CreateHwndRenderTarget函数的最后一个参数用来接收创建的Render target。
// Create a Direct2D render target
hr = pD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hWnd,
D2D1::SizeU(rc.right - rc.left,rc.bottom - rc.top)
),
&pRenderTarget
) ;
if (FAILED(hr))
{
MessageBox(hWnd, "Create render target failed!", "Error", 0) ;
return ;
}
创建画刷
有了Render target,再使用函数CreateSolidColorBrush创建画刷,这里创建一个固定颜色的画刷,第一个参数是画刷的颜色,第二个参数接收创建的画刷,画刷的颜色就是绘制线条所用的颜色,比如这里创建一个红色的画刷,那么后面绘制的矩形就是红色的。
// Create a brush
hr = pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Red),
&pBlackBrush
) ;
if (FAILED(hr))
{
MessageBox(hWnd, "Create brush failed!", "Error", 0) ;
return ;
}
绘制矩形
万事俱备,只欠渲染!渲染的代码很简单,首先调用CreateD2DResource函数来创建资源,这是个自定义函数,用来创建资源,比如Render target,画刷之类的,该函数包含了上面提到的代码。绘制的代码要放在BeginDraw和EndDraw函数之间,调用Clear函数可以将Render target清除为指定的背景色。DrawRectangle函数用来绘制矩形,它有两个参数,第一个是被绘制的矩形,第二个是绘制所用的画刷。函数EndDraw的返回值标识了渲染是否成功。
VOID DrawRectangle()
{
CreateD2DResource(g_Hwnd) ; pRenderTarget->BeginDraw() ; // Clear background color white
pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White)); // Draw Rectangle
pRenderTarget->DrawRectangle(
D2D1::RectF(100.f, 100.f, 500.f, 500.f),
pBlackBrush
); HRESULT hr = pRenderTarget->EndDraw() ; if (FAILED(hr))
{
MessageBox(NULL, "Draw failed!", "Error", 0) ;
return ;
}
清理资源
最后,在程序退出时,清理程序资源,每个COM对象都有一个Release方法,用来释放自己,这里我们定义一个宏来释放COM对象。
VOID Cleanup()
{
SAFE_RELEASE(pRenderTarget) ;
SAFE_RELEASE(pBlackBrush) ;
SAFE_RELEASE(pD2DFactory) ;
}
释放COM对象的宏。
#define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}
效果图如下
Happy Coding
== THE END ==
Direct2D教程(二)来看D2D世界中的Hello,World的更多相关文章
- MVC教程二:从控制器中获取URL的值
一.从控制器中获取URL的值有三种方式: 1.使用Request.QueryString[] 例如: string value = Request.QueryString["BookId&q ...
- Direct2D教程(外篇)环境配置
2014年世界杯首场淘汰赛马上开始了,闲着没事,整理以前的博客草稿打发时间,意外的发现这篇文章,本来是打算加入到Direct2D那个系列的,不知道为什么把它给遗漏了.环境配置,对于熟手来说,不是什么重 ...
- Laravel教程 二:路由,视图,控制器工作流程
Laravel教程 二:路由,视图,控制器工作流程 此文章为原创文章,未经同意,禁止转载. View Controller 上一篇教程我们走了那么长的路,终于把Laravel安装好了,这一篇教程我们就 ...
- SharpDX之Direct2D教程I——简单示例和Color(颜色)
研究Direct2D已经有一段时间了,也写了一个系列的文章 Direct2D ,是基于Windows API Code Pack 1.1.在前文 Direct2D教程VIII——几何(Geometry ...
- Direct2D教程IV——笔刷(Brush)对象
目前博客园中成系列的Direct2D的教程有 1.万一的 Direct2D 系列,用的是Delphi 2009 2.zdd的 Direct2D 系列,用的是VS中的C++ 3.本文所在的 Direct ...
- Direct2D教程II——绘制基本图形和线型(StrokeStyle)的设置详解
目前,在博客园上,相对写得比较好的两个关于Direct2D的教程系列,分别是万一的Direct2D系列和zdd的Direct2D系列.有兴趣的网友可以去看看.本系列也是介绍Direct2D的教程,是基 ...
- 无废话SharePoint入门教程二[SharePoint发展、工具及术语]
一.前言 1.由于上一篇文章的标题命名失误,此篇标题写给百度搜索”什么是SharePoint”. 2.关于什么是SharePoint,请参见本人的第一篇文章:http://www.cnblogs.co ...
- SharpDX之Direct2D教程II——加载位图文件和保存位图文件
本系列文章目录: SharpDX之Direct2D教程I——简单示例和Color(颜色) 绘制位图是绘制操作的不可缺少的一部分.在Direct2D中绘制位图,必须先利用WIC组件将位图加载到内存中,再 ...
- 【Visual C++】游戏开发五十六 浅墨DirectX教程二十三 打造游戏GUI界面(一)
本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/16384009 作者:毛星云 ...
随机推荐
- 1036: [ZJOI2008]树的统计Count(树链剖分)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 19830 Solved: 8067[Submit ...
- HDU 4871 Shortest-path tree 最短路 + 树分治
题意: 输入一个带权的无向连通图 定义以顶点\(u\)为根的最短路生成树为: 树上任何点\(v\)到\(u\)的距离都是原图最短的,如果有多条最短路,取字典序最小的那条. 然后询问生成树上恰好包含\( ...
- 什么是Maven?
Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具. 发文时,绝大多数开发人员都把 Ant 当作 Java 编程项目的标准构建工具.遗憾的是, ...
- Html开发小结
html部分 1.html标签 标签不区分大小写. 如:<!doctype html>与<!DOCTYPE html > <div></div>与< ...
- STW Family
序言 一次作业致使我们成为了一个团体,相聚即是缘分,让我们一起为STW绘制一幅完美的画卷,交一份满意的答卷. 这不是一个人的王者,是团队的荣耀. Team成员 队长:王筱哲 201631062220 ...
- SDOJ 3740 Graph
8.9 t3 [描述] 给你一个图,一共有 N 个点,2*N-2 条有向边. 边目录按两部分给出 1. 开始的 n-1 条边描述了一颗以 1 号点为根的生成树,即每个点都可以由 1 号点 到达. 2. ...
- NumPy数值计算(1)
NumPy数值计算(1) 将列表转为NumPy中的array from __future__ import print_function from numpy import * import oper ...
- The 18th Zhejiang University Programming Contest Sponsored by TuSimple
Pretty Matrix Time Limit: 1 Second Memory Limit: 65536 KB DreamGrid's birthday is coming. As hi ...
- Spring整合Junit进行单元测试
I. 加入依赖包 Spring Test (如spring-test-2.5.4.jar) JUnit 4 Spring 其他相关包 II.新建Junit Test Case III.读取配置文件 @ ...
- 【bzoj1014】[JSOI2008]火星人prefix Splay+Hash+二分
题目描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 ...