一个用于 DirectX 编程的现代 C++ 库2014-04-03 MSDN Kenny Kerr我写过很多 DirectX 代码,也写过很多关于 DirectX 的文章。我甚至还编写过关于 DirectX 的在线培训课程。它其实并不像某些开发人员所说的那么难以理解。学习曲线一定会有,但一旦您过了这道坎,就不难理解 DirectX 的工作方式及其为何要如此工作的原因了。不过我也承认,DirectX 系列 API 的易用性应该更高些。几天前,我决定着手修补一下这个缺陷。我熬了一整夜,编写了一个小头文件。随后几晚,我又将代码行扩展到了近 5,000 行。我的目标是提供一些可借助 Direct2D 更方便地构建应用程序的东西,并向如今盛行的所有“C++ 很难”或“DirectX 很难”之类的论断发起挑战。我并没打算再开发一个笨重的 DirectX 包装。实际上,我决定借助 C++11 制作一套更简便的 DirectX API,同时不在核心 DirectX API 之上产生任何空间和时间开销。您可以在下面的网址找到我开发的这个库:dx.codeplex.com。这个库本身只包含一个名为 dx.h 的头文件,CodePlex 上的其余源文件提供了有关该头文件使用方法的示例。在本专栏文章中,我将向您展示如何利用这个库更方便地执行各种与 DirectX 相关的常见活动。此外,我还将介绍这个库的设计方法,以便您了解 C++11 如何帮助提高传统 COM API 的易用性,而不必求助于 Microsoft .NET Framework 等会对性能产生很大影响的包装。显然,我们的重点是 Direct2D。要借助 DirectX 开发类别最为广泛的应用程序和游戏,Direct2D 仍是最简单也最有效的方式。许多开发人员似乎加入到了两个对立的阵营中。他们中有 DirectX 铁杆开发人员:他们不断学习各种版本的 DirectX API。他们在 DirectX 多年来的发展中历经磨练,并且乐于成为这一进入门槛极高的“贵宾俱乐部”的一员(很少有开发人员能加入该俱乐部)。而在另一阵营的开发人员听到了 DirectX 很难的消息,不想跟 DirectX 扯上一丁点关系。不用说,他们往往会拒绝使用 C++。我不属于任一阵营。我相信 C++ 和 DirectX 不必如此困难。在上月的专栏文章 (msdn.microsoft.com/magazine/dn198239) 中,我介绍了 Direct2D 1.1 和作为先决条件的 Direct3D 和 DirectX 图形基础结构 (DXGI) 代码,以创建一个设备并管理交换链。该代码利用 D3D11CreateDevice 函数创建 Direct3D 设备,适用于 GPU 或 CPU 呈现,长度约 35 行。不过,在我提供的小头文件的帮助下,可将其精简为:auto device = CreateDevice();CreateDevice 函数返回一个 Device1 对象。 由于所有 Direct3D 定义都位于 Direct3D 命名空间内,所以也可以这样写(更加明确):Direct3D::Device1 device = Direct3D::CreateDevice();
Device1 对象不过是对 ID3D11Device1 COM 接口指针(DirectX 11.1 版本引入的 Direct3D 设备接口)的包装。 Device1 类派生自 Device 类,后者是对原 ID3D11Device 接口的包装。 它代表一个引用,与直接获取该接口指针本身相比,不会带来任何额外开销。 请注意,Device1 及其父类 Device 是常规的 C++ 类,而不是接口。 您可以将它们看作智能指针,但这有些过于简单化。 当然,它们能够处理引用计数并提供“->”运算符直接调用您选择的方法,但在开始使用 dx.h 库提供的诸多非虚方法时,才是它们真正大放异彩之时。例如: 通常,您可能需要 Direct3D 设备的 DXGI 接口来传递其他某种方法或函数。 不怕麻烦的话,可以这样做:
auto device = Direct3D::CreateDevice();wrl::ComPtr<IDXGIDevice2> dxdevice;HR(device->QueryInterface(dxdevice.GetAddressOf()));
这当然可行,但现在您还必须直接处理 DXGI 设备接口。另外,您还需要牢记,IDXGIDevice2 接口是 DirectX 11.1 版本的 DXGI 设备接口。实际上,也可简单地调用 AsDxgi 方法:
auto device = Direct3D::CreateDevice();auto dxdevice = device.AsDxgi();
返回的 Device2 对象(此次是在 Dxgi 命名空间中定义的)包装 IDXGIDevice2 COM 接口指针,提供自己的一组非虚方法。再举一个例子,您可能需要使用 DirectX“对象模型”访问 DXGI 工厂:
auto device = Direct3D::CreateDevice();auto dxdevice = device.AsDxgi();auto adapter= dxdevice.GetAdapter();auto factory= adapter.GetParent();
当然,这是一种常见模式,是 Direct3D Device 类提供 GetDxgiFactory 方法作为捷径的一种手段:
auto d3device = Direct3D::CreateDevice();auto dxfactory = d3device.GetDxgiFactory();