进英雄联盟时,它显示dirext错误或显卡未更新,但是我的direct和显卡驱动都重新安装了最新的

第一章 DirectX基础(初级篇)

由于本教程的所有示例都是用DirectX5.0编译成功的所以读者最好也使用DirectX的5.0版。安装方法如下:

运行SDK中的Setup.exe文件出现Welcome窗口,按Next按钮出现软件许可协议窗口,按YES按钮此时出现Setup Type对话框,有三种安装选择选择其中的Compelete(完全安装),然后按Next

在这里有两个安装选择:一个是Retail(零售)安装,推荐給仅用于单独运行游戏的用户并不会帮助程序员在编译过程中发现错误;另一个是Debug(调试)安装,推荐给开发者运行虽然较前者稍慢,但可以帮助调试程序选中Force Install,表示将覆盖这台电脑上的任何更新的DirectX版本

在出现的对话框中,让你选择是否安装IE和ActiveMovie读者请随意。然后按Next按钮

在余下的步骤中,让你选择安装路径和快捷方式夹名称按Next即可。设置完毕后安装程序开始正式安装直至结束。

安装完毕后伱将在你的SDK路径中看到以下目录:

SDK:软件开发工具包。

BIN:例程的可执行文件

可以看到一个完整的SDK已经安装至你的电脑。但是为了让VC能够調用到SDK中的头文件和库文件你还要做以下的工作以打通路径。有两种方法供你选择:

方法一:将sdk\inc和sdk\lib目录中所有的文件分别复制到VC的include和lib目錄中去这是最简单也是最有效的方法。

必须把这两个路径加在最开头是因为:VC在寻找头文件和库文件时是按照列表中的先后顺序VC以前所打通的路径中已经包含了DirectX3.0的头文件和库文件,如果把这两个路径加在最后VC在编译时所使用的仍是旧版的DirectX 3.0的文件。

好了一切就绪,DirectX已經在向你招手如果你想赶紧实验你的第一个程序,可以跳过下面的部分直接进入下一章。

如果按照缺省路径安装DirectX将在C:\Program Files\directx\setup目录中加入三個可执行文件:DxInfo.exe、DxSetup.exe、DxTool.exe。对那些谙熟DirectX的人来说运行这些个文件并加以评价和指点,是很容易在同事中建立起高手形象的这三个文件用来透视和评价电脑硬件系统2D、3D、音频等加速性能的高低。

DxInfo.exe:显示计算机的软、硬件信息极其驱动程序文件信息从这里你可以了解到你的计算机的显卡、声卡、芯片、操作系统和DirectX各组件的驱动程序和特性。

DxSetup.exe:DirextX安装程序可以设置是否启用Direct3D硬件加速以及还原音频、显示器驱动程序。

DxTool.exe:这是DirectX中最有用的一个文件从它你可以对你的电脑的DirectX硬件加速特性有一个全面而深入的了解,还可以设置是否启用Direct3D硬件加速以及DirectDraw硬件加速

这三个文件随着版本不同,也会与其上所述不尽相同

由于DirectX驱动程序自己不带反安装程序,所以一旦安装之后是无法将其卸载嘚,只有一步一步往上升级否则只能重新安装Windows95,这就象一旦你选择了一条道路就要贯穿始终的走下去一样。试着打开“控制面板”里嘚“添加/删除程序”会发现“DirectX驱动程序”赫然其中,小心翼翼的按过“删除”按钮弹出的却是DirextX的安装程序,你始终无法用常规的方法將其卸载

是不是就无能为力了呢?当然不是本站的软件下载中提供了一个反安装DirectX的软件,可以用来删除你的电脑上的DirectX(它只是卸载DirectX驱動程序并不会卸载其SDK)。目录位于光盘:\dxuninstall

应该注意的是,由于某些显卡和声卡几乎包括现在出的所有显卡或声卡,它们的驱动程序Φ都已经自带了DirectX驱动程序所以,除非你重新启动Win95切换到安全模式下,再运行DirectX的卸载程序否则,你始终无法将DirectX完全卸载

在正式进入夲章主题之前,先对读者进行一次小小的入学考试不用紧张,其实几道题都非常的简单

1、根据你对左边这三个函数的直观感觉,选出咜们的正确对应关系

2、找出与其它三个没有共同点的一个。

3、HWND之于窗口相当于什么之于苹果。

4、如果要创建一个最普通的窗口应该鼡以下的哪一个标志。

如果你有一道题做错了说明你对Win32编程还不是十分了解,那么你需要事先预习一下请跳转到本教程的“Win32编程基础知识”一章,学习一下Win32编程的基础知识(这四道题的答案分别是:cab、d、c、a。其实它们真的是非常简单只要你仔细阅读一下题目,就是猜也能猜出来)

如果这些题对你来说不成问题,祝贺你你可以继续本章的内容了。

只要是介绍编程的书似乎有一个不成文的规定,即第一个例子由“Hello World”开始本教程也不例外。那么如果你早已迫不及待想初尝DirectDraw程序编译成功后的“0 error(s), 0 warning(s)”的喜悦,就让我们开始吧!

应用程序开发环境熟悉VC++的读者可能会问,为什么舍先进的MFC工具不用而去使用最原始的方法呢?这是因为MFC主要是用于基于窗口和文档的应用軟件的编程,它集成了大量的数据和方法将许多烦琐的任务,如:应用程序初始化、文档处理、磁盘IO封装起来虽然这样可以给你的编程带来了极大的便利,但是在你编制基于图形显示和多媒体的应用程序的时候这却会给你带来极大的麻烦。首先你无法触及系统的内核,如:你需要自己来处理每一个消息循环时而MFC并没有为你留出这样一个接口;而且,MFC为你事先建好的类它们的许多功能对你来说是沒用和低效率的,使用它们只会给你的程序带来冗余和不便

总之,MFC为你隐藏了太多技术细节而DirectDraw编程需要系统对于开发者具有一定的透奣度。 所以在大多数情况下,我们用最基本的Win32应用程序开发环境来开发我们的DirectDraw应用程序本教程中几乎所有的例程都是使用Win32开发环境。當然这并不是说用MFC就不能编制基于DirectDraw的应用程序了,它也是可以的这将在本教程的“用MFC创建DirectDraw应用程序”一章中做介绍。

使用Win32开发环境表奣你必须从WinMain()开始编程,自己写每一个消息的处理程序这的确是一项很繁重的工作。但是当你理解和熟悉了这一套方法时你会发現它其实是相当直观和容易的。

选择File菜单的New在出现的对话框中,选择Projects栏目(新建工程)并点取其下的Win32 Application项,表示使用Win32环境创建应用程序先在Locatin(路径)中填入“c:\”,然后在Project Name(项目名称)中填入“Hello”其它按照缺省设置,使对话框如图所示单击OK按钮。

此时一个基于Win32的工程已经创建完毕,但是它还没有包括任何文件你需要新建一个C++文件增加到工程中。

再次选择File菜单的New在出现的对话框中,选择Files栏目(新建文件)并点取其下的C++ Source File项,表示新建一个C++源文件在右边的File栏中输入“Hello”,最后确定让Add to project检查框打上勾使整个对话框如图所示。单击OK按鈕

在Hello.cpp文件中输入以下源程序代码,当然你最好的做法是将以下的代码复制到你的文件中去,确保能用

//功能:Win32应用程序入口函数。进荇初始化工作处理消息循环

//功能:创建主窗口。

//功能:处理主窗口消息

//功能:初始化DirectDraw环境并实现其功能包括:创建DirectDraw对象,

// 设置显示模式创建主页面,输出文字

为了简化代码,这第一个入门程序没有头文件在进行编译之前,还得进行最后的设置选择Project菜单的Settings…,出現工程设置对话框选择Link栏,在Object/Library modules中添入“Ddraw.lib”使对话框如图所示。

请注意:这一步骤是将DirectDraw的静态连接库文件连接到工程中否则,程序虽嘫可以正常编译但是在连接时会产生一个“unresolved external symbol”(没有定义的外部符号)的错误。在以后所有的DirectDraw程序中都必须将与你所用到的DirectDraw组件相应嘚静态连接库添入到这个设置中。

至此一个最基本的DirectDraw应用程序已创建完毕,你现在不必去深究这些代码的含义在下面及以后的章节中峩们会对它们进行详细的分析。这虽不是一个最简单的DirectDraw应用程序但它确实是一个能够实现最基本的输出功能的DirectDraw程序。

按F7编译成功后按Ctrl+F5,执行该程序显示器将切换到640*480*256色模式,黑屏后屏幕中央会打印出蓝底黄字“Hello World, I am DirectDraw boy !”,除了输出这些字符外这个程序什么也不做。按ESC可退絀程序程序运行结果如下图

这就是DirectDraw?有的人也许会对DirectDraw感到很失望因为它并没有为我们表现出神奇的功能啊?但有的人却会对此感到异瑺兴奋他们觉得一扇充满诱惑的房间的大门正向他们打开。这就象透过天窗有些人只会看到黑暗的夜空,有些人却能看见满天的星星┅样第一个例子,为了使程序不至于太长而让那些初学者望而生畏所以只能一再简化(尽管这样,整个程序还是占用了相当大的篇幅)在后续章节的例子中,你们会看到程序会一个比一个更精彩

下面,让我们来逐一分析一下这个程序

分析程序应该是一个由外而内,逐步求精的过程首先从大的方面来看,这个程序一共用到了五个函数如果按照正常顺序,排除程序中出错的可能它们的调用顺序依次是这样的。

WinMain:所有Win32应用程序的入口函数它也是应用程序关闭时的出口,一个应用程序的全生命周期就是在它的控制之下所以,确切的说其它四个函数是被包括在WinMain之内的。消息循环也是在这个函数中启动

InitWindow:初始化和创建一个与程序的HINSTANCE(实例句柄)相关联的主窗口,这个窗口的HWND(窗口句柄)在初始化DirectDraw环境时需要用到

InitDDraw:初始化和创建DirectDraw对象,并执行一定的功能它里面包括了创建DirectDraw对象,创建页面设置显示模式,创建主页面输出文字。

WinProc:是应用程序感知外来动作和产生反应的神经中枢相当于人的大脑。这是程序中最主要的部件之┅它和在WinMain中所启动的消息循环是一起工作的。

FreeDDraw:释放DirectDraw的各种对象以使其不再占用内存空间。

上面这段话如果使你感到迷惑就象是在伱小学的时候有人给你讲什么是微积分,那么你仍需要事先预习一下Win32编程请跳转到本教程的“Win32编程基础知识”一章,复习一下Win32编程的基礎知识

如果你对Win32编程和Windows的消息机制有一定的了解的话,以上概念是比较容易理解的

分析完程序的总结构,再让我们从最开头看起

这昰把DirectDraw的头文件包含到文件里来。这一步在以后所有的例程中都是必不可少的

接着定义了三个全局指针变量,它们都是指向对象的指针苐一个是DirectDraw对象,表示显示硬件它包括了显示器和显卡还有显存,用它来代表整个显示系统第二个是DirectDrawSurface对象,表示页面你可以在大脑中紦它想象成一张矩形的白纸,你可以在上面绘制图象现在你暂且不用去深究它们的含义,看下去就是了在后面的课程中,我还会更加詳细的介绍

给一个变量命名时,在变量名前加上该变量的类型标志在Windows编程中是一个默认约定,称为匈牙利表示法该名称来源于微软嘚一个匈牙利籍资深程序员,因为他惯用此表示法后来便成了规范。如lpDD表示一个长型指针变量dwHeight代表一个DWORD型变量。这样的好处就在于你鈳以一眼就辨认出某变量的类型而不用去追溯它的定义。

这里所说的“对象”(Object)并不完全等同于C++中对象的概念,尽管它们使用的是同一個英文单词Object这里的对象指的是COM,COM是Component Object Model 的缩写代表“部件对象模型”,它在DirectX中贯穿始终无处不是它的身影。

       在DirectX SDK中大多数APIs(应用程序编程接口)由对象和基于COM的接口组成。COM是致力于可重复利用接口资源的面向对象系统的基础并且是OLE编程的核心模型。它也是一个接口规范通过它可以设计出许多接口。它是建立在操作系统层次的对象模型

COM与C++类也有许多相同之处。对一个C++程序员来说COM接口就象是一个抽象基础类。这就是说它定义了一套关键符号(signatures)和语法(semantics),但不是执行语句并且没有与接口相关联的状态数据。在C++抽象类中所有的方法被定义成纯虚(pure virtual)函数,它们并没有实际的代码在这一点上,COM和基础类是一致的

COM对象与C++对象的另一个相似点是:一个函数的第一個引用是接口或类的名称,在C++中叫做this引用因为COM对象和C++对象是完全二进制兼容的,编译器把COM接口当作C++抽象类来看而且采取同样的语法。這样就可以减少代码的复杂程度例如,this引用在C++中被当作可识元素并且被暗中的操作,COM中也是如此

COM 是DirectX的基础,虽然它和C++中的类不近相哃但你完全可以把它当成C++的类来看待,在实际编程中它们的语法和接口也是完全一样的。所以对于C++程序员,进行DirectX编程并不需要你去學习新的编程方法继续沿用你所熟知的C++,DirectX也能为你所用

只要是你要用到DirectDraw接口的特性,都必须创建一个DirectDraw对象它是DirectDraw接口的核心。它是这樣被创建的:

DirectDrawCreate()函数是在ddraw.h中定义的关于这个函数的详细解释,请参看本教程的“DirectDraw参考手册”一章它的原型如下:

第二个参数是lplpDD:这个参數是用来接受初始化成功的DirectDraw对象的地址。在这里我们给它&lpdd。

第三个参数是pUnkOuter:千万不要追问这个参数是干嘛使的如果你不想惹麻烦,就給它NULL吧Microsoft的说明书上是这么写的“考虑到与将来的COM集合特性保持兼容,当前不管怎样,如果这个参数不是NULL DirectDrawCreate将返回一个错误”。

所有的DirectDraw函数的返回值都是HRESULT类型它是一个4字节(32位)的值,用来代表某个错误或警告DirectDraw头文件中已经预定义了所有可能的返回值常量,仅函数返囙成功的值是用 “DD_OK”表示所有的错误值标志开头都为“DDERR”,如:

Windows编程中有一项让中国软件开发者大挠其头的就是函数名、常量名和数據结构名称中往往有长串的字符。这时就要考验读者的英文断句水平了。如:DDERR_OVERLAYCOLORKEYONLYONEACTIVE应该断为:DDERR-OVERLAY-COLORKEY-ONLY-ONE-ACTIVE。这对于老外来说也许并不成什么问题但對于我们,有时候要看懂一个语句简直就象在做一道英文题。除非你对一个名称有十足的把握否则就应该尽量使用CP规则(原是离散数學里的一条规则,现引申为Copy-Paste即:复制-粘贴)。而且给读者一点忠告,在起函数、变量或常量名称时也应该沿用老外的这条原则,以盡量清楚的表达意义为宗旨不要担心它是否太长(当然,对于那些重复利用率很高的函数、变量或常量还应该尽量使用缩写),否则总是以i、n为变量,程序的可读性会变得极差而在编程的初学者当中,这是很常见的

3)设置控制程度和显示模式

DirectDrawCreate函数调用成功后,lpDD已經指向了一个DirectDraw对象它是整个DirectDraw接口的最高层领导,以后的步骤都是在它的控制之下

第一个参数是hWnd,我们调用Win32的API函数GetActiveWindow获得应用程序主窗口嘚句柄这将使DirectDraw对象与主窗口的消息挂上勾。

这个函数有很多用法而且它必须在创建DirectDraw对象之后,立即调用你可以用它来设置应用程序昰运行于全屏还是窗口模式,是独占还是共享模式具体用法将在以后逐步介绍。可参阅“DirectDraw参考手册”

显而易见,这是设置显示器的显礻模式它把显示模式设为640*480,8位色彩模式(即256色)这是绝大多数显示器所能够支持的显示模式,所以我们不用担心它会出什么问题在鉯后的例程中,我们将看到可以调用EnumDisplayModes()来列举出显示器所支持的所有显示模式绝不要轻易尝试直接设置一个新的显示模式,而应从列举出嘚显示模式中选择这也将在后续章节讲到。

要注意的是只有当DirectDraw对象为独占访问的控制程度时才能改变显示器的显示模式,如果DirectDraw对象运荇为窗口模式调用该函数会返回一个错误。

DirectDrawSurface对象代表了一个页面页面可以有很多种表现形式,它既可以是可见的(屏幕的一部分或全蔀)称之为主页面(Primary Surface);也可以是作换页用的不可见页面,称之后台缓存(Back Buffer)在换页后,它成为可见;还有一种始终不可见的称之為离屏页面(Off-screen Surface),用它来存储图象其中,最重要的页面是主页面每个DirectDraw应用程序都必须创建至少一个主页面,用它来代表屏幕上可见的區域说白了,就是你的显示屏幕

创建一个页面要分两步走,这里我们以创建主页面为例,简要介绍一下这两个步骤其它类型页面嘚创建也与之类似,在以后的例程中还会着重讲解

       这就象是你到银行取款,必须事先填写一张取款单你要在上面详细描述你的姓名,伱的存折序号以及你要取的钱数等等,然后把它递给银行工作人员

页面描述填充完毕后,把它传递给CreateSurface()函数即可

CreateSurface()函数的第一个参数是被填充了页面信息的DDSURFACEDESC结构的地址,为&ddsd;第二个参数是接收主页面指针的地址此处为&lpDDSPrimary;第三个参数现在必须为NULL,为该函数所保留

如果函數调用成功,lpDDSPrimary将代表一个合法的主页面对象由于在前面已经设置了该程序的工作模式为独占和全屏,所以此时主页面所代表的实际上昰你的整个显示屏幕。在主页面上所绘制的图形将立即反映到你的显示屏幕上

下面开始在主页面上输出文字。

如果你十分熟悉Windows的GDI(图形設备接口)你会发现上面这段程序居然和在窗口中输出文字一模一样。这是因为DirectDraw页面和GDI的设备环境(DC)其实是兼容的。在调用主页面嘚GetDC()函数获得页面的设备环境句柄(HDC)之后就可以使用Win32的API绘图函数来进行绘图操作了。同样最后也必须调用主页面的ReleaseDC()函数来释放设备环境资源。

在程序结束之前DirectDraw还必须做一项扫尾工作,即:把已经创建的所有DirectDraw对象从内存中清除出去这就是FreeDDraw()函数的作用。

每一个DirectDraw接口的对潒都有Release()函数以将其所引用的对象释放。这其实相当于C++中的delete方法及时的将不用的对象释放掉是每一个优秀的程序员都应当养成的良好习慣。

以上关于DirectDraw接口的编程似乎与应用程序的主窗口没有一点联系而且执行后,也看不到窗口的影子是不是就可以不用创建程序的主窗ロ了呢?当然不是

其实,程序执行后漆黑的背景就是程序的主窗口。在注册窗口类时已经给hbrBackground成员指定了黑色。

而且在创建主窗口時,窗口的类型用的是WS_POPUP表明创建的是一个没有标题栏,没有边框的窗口;而不是常用的WS_OVERLAPPEDWINDOW

值得特别注意的是:在设置DirectDraw对象控制级的时候,使用了主窗口的句柄(HWND)这就是说,DirectDraw将用主窗口来接收各种消息这样,就可以利用主窗口来实现DirectDraw对用户操作的反馈如,用户想用咣标键来控制游戏图象的运动光标键按下的消息被发往主窗口,然后在主窗口的消息处理过程中操作DirectDraw使之对光标键产生反应。所以茬大多数情况下,创建一个主窗口是必不可少的

DirectX是一个功能强大而且使用复杂的工具,在这一章里我们仅学习了一个最简单的利用DirectDraw接ロ的例子,对于庞大的DirectX来说它只是冰山一角。要掌握DirectDraw编程是一个复杂的过程需要从大量的实践中摸索出经验,任何读者想一蹴而就是鈈可能的但是,好的开端意味着成功的一半如果你能理解和掌握本章所学到的内容,继续下去坚持不泄,你会发现你将一天比一天哽加充实

通过本章的学习,读者应能掌握:

  • 在VC++5.0环境中使用Win32应用程序开发环境新建一个DirectDraw工程以及添加源文件
  • 只有在独占的控制级下才能調用SetDisplayMode()以改变显示器的显示模式。
  • 页面对象的种类只有主页面代表了显示屏幕,为可见页面
  • 用GetDC()获得主页面的HDC,然后可以使用Windows API的GDI函数进行繪图或输出文字最后必须调用ReleaseDC()以释放资源。

    在上一章里我们尝试了一个非常简单的DirectDraw应用程序,可以看到DirectDraw编程对一个C或C++程序员来说并鈈是陌生和难以接近的。在这一章里我们将介绍Directdraw编程中所经常用到的图形方面的知识,在深入进行DirectDraw编程之前领悟这些最基本的图形概念是非常必要的。

首先让我们从电脑显示器屏幕上的基本单位棗像素说起。对用户来说像素指的是显示器在某种分辨率状态下所能表達图象的最小单位。你可以把它简单的理解为一种类似于马赛克的东西像素的大小与你当前的显示分辨率有关,现在所有的SVGA显示器都支歭多种分辨率比如通常所说的640x480、800x600等。许多人错误的将像素的大小与显示器的点间距(Dot Pinch)混淆了其实它们指的不是同一个东西。当你用放大镜观察显示器屏幕时你会发现图象实际是由许许多多红,绿蓝整齐排列的小点组成,你可能会认为这就是像素那么你就错了。這实际上是显示器光栅的一个扫描点它是荧光屏后部的三束电子枪发射电子透过一层致密的网打到荧屏反面而发出的荧光,人们常说的0.28嘚彩显意即:屏幕上相临两个扫描点的平均间距为0.28毫米一个像素是由若干个这样的扫描点组成的。专业的说在某种分辨率状态下,显礻器的水平(垂直)像素的个数实际上等于一次水平(垂直)扫描期间,电子束的通短强弱状态能够发生变化的次数一台彩显所能达箌的最大分辨率受到这台彩显的尺寸和点距的限制。

显然显示器型号越大,点间距越小则它所能达到的分辨率就越高,那么它所显礻的图象就越清晰,表现得越细腻

现实生活中,我们所能分辨的所有颜色都能用三原色:红、绿、蓝合成出来称为RGB色彩模式。用RGB方式匼成颜色主要用于发光设备如计算机显示器。通过分别调节红绿,蓝三束电子枪的强度就可产生一个广泛的色彩范围。由于色彩的產生来源于RGB三种色彩光强度的叠加所以,这种方法被称为彩色叠加

值得一提但与我们的DirectDraw编程基本上没有什么关系的另一种色彩表示模式是CMYK色彩模式,代表青粉,黄三种可减基色加上黑色作对比,常用于打印感光材料,胶片等每种基本色从照射到打印页的白光中吸取某些色彩,由于CMYK方式通过从白光中吸取特定的色彩所以被称为彩色削减。此外还有HSI(也称HSL)色彩模式,它代表Hue Saturation 和 Intensity 。Hue 是我们所认为嘚色调如红橙黄绿青蓝紫等,Saturation描述该色调颜色的饱和度Intensity 描述亮度。

RGB 颜色方式对于显示器来说是唯一适用的彩色混合方法而CMYK则是适用於打印和印刷的彩色混合方法,HSI 则是一个很直观的定义彩色的方法现在的许多图形软件中都同时具有这三种定义颜色方法的应用。但是不论用那种方法给颜色取值,最终都必须转化为RGB方式才能为显示器所认识接收并显示出来

在几乎所有的编程中,当然也包括DirectDraw都是采鼡标准的24位RGB模式定义一个颜色,用三个从0到255的数值来分别代表R、G、B三个分量每个分量都有256种亮度级别。当三种元素全被置为0像素显示嫼,通常表示为RGB(00,0);当全部置为255像素显示为白,表示为RGB(255255,255)

三、设备无关位图(DIB)

位图图象(也称点阵图象)准确的说是什么呢?咜们是数据元素的集合这些数据元素决定在了在图片的某个具体位置是什么颜色。这就好比我们用许许多多的马赛克来拼图案一样每個马赛克虽然只有一种颜色,但你看到的只是整个美丽的图案而不是某一个马赛克。当图象显示在显示器屏幕上时正如前面提到的那樣,这一个个的马赛克就是像素

之所以称之为设备无关位图(DIB),其实是为了与设备相关位图(DDB:Device dependent bitmap)相区别由于只有Windows 3.0以前的版本才广泛使用设备相关位图DDB,Windows 95和Windows NT及以后的版本使用的都是设备无关位图DIB所以,“设备无关位图”这个名称在当前已没有其现实的含义在大多數情况下,我们将其简称为位图(Bitmap)

从本质上说,DIB是一个包含了图象的各种信息的文件包括图象的尺寸,使用的颜色个数及其颜色值还有每个像素的颜色数据等。此外一个DIB中还包含了一些极少使用的参数,象文件压缩类型、重要颜色还有图象的物理维数等。DIB文件通常具有“.bmp”扩展名偶尔也会将“.dib”作为其扩展名。

Windows对DIB位图有规定的格式在我们学习了位深度和调色板的概念之后,对DIB格式再做详细嘚解释

与位图格式相对的是矢量格式,由于它是用形状和相互关系来描述图象WMF文件就是一种典型的矢量图,它的特点是具有极大的灵活性可以任意缩放不失真,且存储空间相对较小但矢量图由于其描述图象的方式与位图完全不同,不适用于图象处理的领域在以后嘚DirectDraw编程中,我们所指的图象特指位图图象

计算机中,一个字节(Byte)是由8个位(Bit)组成的位深度指的是用来描述某状态值所使用的计算機位的个数。在DirectDraw中通常用位深度来代表位图中的颜色值所使用的位个数,从另一个意义上讲位深度表示了位图中颜色的丰富程度。

1字節等于8位二进制数所以一字节所能表达的十进制整数的范围是从0到255,即一字节能且最多只能反映出256(2的8次方)种不同的状态在位图中,如果用其中每一种状态代表图象中某一个点的颜色那么最多可以得到256种不同的颜色,这就是我们常见的8位(256色)的位图同理,如果鼡1位二进制数来表示某一点的颜色那么只能得两种(2的1次方)颜色,这就是一幅两位的黑白位图;如果用四位二进制数则产生16种颜色(2嘚4次方)这是一幅4位(16色)的位图,用24位产生16M种颜色(2的24次方)等这就是一幅24位真彩位图。由于每幅图形文件都用确定的位数来代表顏色(1、2、4、8、16、24或32位)所以我们所见的图片颜色数都为2的n次方(n=位深度)。

显然一幅图象的位深度越高,那么它所能表现的颜色也樾多色彩也就越丰富。通常在一般情况下,8位(256色)的图片已可满足需要但在一些要求高质量图象的场合,16或24位的图象是必须的當然,颜色位深度的增加也势必带来所需存储空间的膨胀,没有经过压缩的相同大小的24位图象所需的存储空间是8位图象的3倍这也会带來文件读取和操作速度的降低,所以在需要高速度显示图象的场合使用低位深度的图象是必要的。

在低位深度的图象中由于颜色总数嘚限制,有些颜色无法显示出来为了模拟出那些颜色以提高显示效果,广泛采用了一种称作抖动处理(dithering)的方法也称半色调处理(Halftoning)。它是指用交替的点图案去模拟在图象中不能使用的颜色的过程单色图象是最简单的格式,一般由黑色和白色组成在一些单色图象如嫼白照片和有深浅的图案中,会使用各种灰度这种图象常被称为灰度图象(Grayscale Image)。由于人眼会把一个很细致的黑白相间的图案解释成灰色所鉯灰度图象也可使用单色文件格式,数据仍然可以是黑和白使用黑色或某一种单色的点获得连续的该色灰度的过程就是抖动处理。抖动處理被更多的用在那些低位数彩色图象文件中与不采用这种处理相比,它具有更好的显示效果

显示器及显示卡与显示器的接口都采用模拟方式来处理色彩,因此它们都具有几乎无限的色彩显示和传输能力,但主机和显示卡只能用数字方式来表示和处理色彩在用数字方式表示色彩时,如果要获得更丰富更细腻的色彩就需要增加色彩的位深度,这就需要更大容量的显示存储器相应的也就需要更高的處理速度,同时分辨率的提高也对显示存储器的容量提出了很高的要求

为了尽量降低对显存的需求,在Windows中可以使用一种间接的色彩表示方法这就是调色板(Palette)表示法。它的含义是:用一个颜色索引(Color Index)来代表各个像素点的颜色而不是直接用红,绿蓝三基色的亮度值來确定每个像素点的颜色。色彩表(Color table)是一个包含了若干颜色索引和该索引所对应的真实颜色值的表这个色彩表就是调色板。

这种方法僦好比给学校里的每一个学生规定一个专用的学号在很多场合,并不需要知道某个同学的实际姓名只要知道他的学号即可,显而易见使用学号无疑会给学校的学员管理工作带来了极大的便利。调色板就好比一张记载了学生学号及其姓名的名册颜色索引值就是学生的學号,RGB颜色值就是学生的姓名

使用调色板的好处就在于:索引值占用较少的数据位(1、2、4或8位),而真实颜色值占用较长的数据位(24位即3字節,分别代表红绿,蓝三基色的颜色亮度值从0到255)。由于使用了调色板既提高了图象显示效率,又减少了对显存的需求

调色板的颜銫索引主要采用4或8两种位深度:4位位深度可有16种不同取值,对应于显示器的16色显示模式这时一屏最多只能显示16种不同的颜色;8位位深度鈳有256种不同的取值,对应于显示器的256色显示模式一屏最多只能显示256种颜色。于是问题就开始出现了,当你在16色模式下显示一幅256色或更高位深度的的图象时你将会看到本应色彩鲜艳的图片变得面目全飞,罪魁祸首就是调色板由于它使得同时显示在屏幕上的不同颜色最哆只能有16种(对应于16色模式下),于是Windows首先从图象中挑选了16种使用频率最高的颜色指定给调色板对于所有其它的颜色,从调色板中挑选┅个最接近的颜色显示出来在256色模式下,要同时显示两幅不同调色板的256色位图时也会发生这种图象失真的情况。

在大多数的Windows编程中開发者们使用的是Win32的函数以获得访问绘图页面的能力,例如使用GetDC函数,可以获得设备环境(DC?/FONT>Device context)在获得设备环境之后,你就可以开始进荇对屏幕的绘图了Win32的所有图形函数都是由Windows系统的一个独立完整的模块所提供,这就是图形设备接口(GDI?/FONT>Graphics device interface)GDI为计算机用户和计算机硬件之間提供了一个抽象层,在此层的基础上用户可以通过简单的调用Win32的图形函数进行图形显示。

GDI的一大缺憾就是它不是为具有高表现力的哆媒体软件和游戏而设计的,设计者们开发它的主要用途是运行商业应用软件诸如:Word字处理软件、Excel电子表格、Explorer浏览器等GDI只提供了访问系統主存的能力,而不提供直接访问显存的能力并不能从具有某些加速特性的显卡中获得其优良特性。简而言之GDI对绝大多数的商业软件來说是相当完美的,但对于多媒体软件和游戏来说它却是低速和低效的。

另一方面DirectDraw可以提供给开发者代表了真实显示内存的绘图页面。这意味着只要你使用了DirectDraw,你就可以直接操纵显卡上的内存图形显示变得出奇的快速。而且这些页面代表了显存中连续的内存块使嘚在页面中寻址和读写变得非常方便。

八、位块传送(Blit)

“Blit”是“Bit block transfer”的缩写意为“位块传送”。顾名思义Blit的作用是:将某一内存块的數据传送到另一内存块,前一内存块被称为“源”后一内存块被称为“目标”。这里用的是“传送”一词而不是“复制”,因为在Blit过程中数据并不是被原封不动的转移,而是经过了一定的转换

在许多书籍中或程序中经常可以见到的“Bitblt”、“Blt"或“Bltting”,其实也是同一个意思前者读作['bitb'lit];后者读作[b'lit]。

在绝大多数情况下Blit操作是针对位图图象的,因此源数据代表的是“源位图”,目标数据代表的就是“目標位图”图象程序开发者使用Blit的函数在内存中将某页面上的一幅位图经过一定的变换转移到另一个页面上。这种变换有很多种每一种嘟有一个代码与之对应,我们称该代码为光栅操作代码(ROP?/FONT>Raster operation code)

int nXDest, //目标设备环境的矩形区域的左上角的x坐标

int nYDest //目标设备环境的矩形区域的左仩角的y坐标

int nWidth, //目标设备环境的矩形区域的宽度值

int nHeight //目标设备环境的矩形区域的高度值

int nXSrc, //源设备环境的矩形区域的左上角的x坐标

int nYSrc //源设备环境的矩形区域的左上角的y坐标

dwRop参数是光栅操作代码(Rop),它是指源位图与目标位图以及图案刷的颜色值进行布尔运算的方式以下列出了瑺用的光栅操作符。

NOTSRCERASE   先将源矩形图象与目标矩形图象进行布尔“或”运算然后再将

 再与目标矩形图象进行布尔“或”运算。

表中提到叻三种的基本布尔运算,分别是:反相(NOT)、与(AND)、或(OR)还提到了异或(XOR),学过数理逻辑的人都知道异或运算其实也是可以由湔三种组合出来的。可以看出所有的光栅操作代码都是由三种基本布尔运算组合而成。实际上一共有256种光栅操作代码,但最常用的就昰以上这15种若想使用这15种以外的任何一种时,可以查阅VC的帮助但在实际中,它们是极少被用到的

图案刷(英文是Pattern, 也可翻译成模式刷直接的意思是布料上图案的花样)是Windows资源的一种,属于Brush它其实是一个固定大小的位图(通常为8x8像素),用来平铺填充设备环境(DC)嘚某一区域它的用法与普通的刷子是没有区别的,当把一个图案刷用SelectObject函数选定给某设备环境再在该设备环境中进行填充操作,那么所填充的不是一个单纯的颜色(选用普通的刷子时的情况)而是连续平铺的图案。

DirectDraw中的Blt函数比GDI中的BitBlt函数虽然在形式上极为相似但在内容仩却有了质的飞跃。首先从运行速度上来比较,IDirectDrawSurface3::Blt可以利用到一切可以利用的硬件加速特性而且该操作在缺省情况下是异步执行的,这意味着程序不需要等待blit结束才返回而是在给系统发出了blit的指令后,立即返回然后系统在后台进行blit操作,这使程序的运行变得极为高效、快速;其次它还支持带源和目标关键色以及z缓存和alpha 通道的blit操作,这使得用该blit函数来完成各种效果变得极更为容易

该函数的目标页面僦是调用者本身,而且矩形区域用RECT结构表示第四个参数dwFlays表示该blit操作的类型,最后一个参数lpDDBltFx是一个包含了光栅操作代码和其它特效的结构其中的光栅操作代码成员与Win32的是兼容的。

要得到更多的关于DirectDraw中的blit函数的资料请参阅本教程的DirectDraw参考手册。

在多媒体动画、动感游戏等软件中翻页是一个相当关键的概念。与绘画师绘制动画片相比计算机中的翻页技术与其具有相似之处。例如:绘画师在一叠相同的纸上繪画画完一张再画下一张,在每一张上绘画师使画面有略微的改动,于是当你在这一叠纸上快速的翻页时,静止的图象便开始运动起来

DirectDraw中的翻页与上面这个过程极为相似。首先你得设置好一个翻页链结构,它由一组DirectDraw页面组成每一个页面都可以被轮流翻页至显示屏幕。当前正好位于显示屏幕的页面我们称之为主页面(primary surface),其后等待翻页至屏幕的页面我们称之为后台缓存(Back buffers)。应用程序在后台緩存上进行绘图操作然后“翻一页”,将此页面翻页成为主页面原来的主页面成为后台缓存,翻页后你所进行的修改可以立即显示茬屏幕上。与此同时你可以在下一个即将翻页成为主页面的后台缓存上进行绘图。将这个翻页过程一直持续下去直到动画结束。

有了DirectDraw整个翻页的任务并不是一件十分困难的工作。你既可以创建一个简单的双缓存翻页链结构(一个主页面和一个后台缓存)也可以创建┅个使用起来更为灵活的多后台缓存翻页链结构。

由于DirectDraw更多的使用的是硬件的特性使得翻页变得极为快速,这个过程在屏幕上不会产生絲毫的闪烁其速度可以达到与显示器的刷新率一样的数量级。在后面的DirectDraw教程中我们将具体介绍如何在DirectDraw程序中实现翻页。

在Windows编程中屏幕上的对象都是以一个封闭矩形的形状出现的。一个封闭的矩形可以用两个点来确定左上角和右下角。绝大多数应用程序使用RECT结构来定義一个封闭矩形用于blit操作或碰撞检测(hit detection)。RECT结构定义如下:

应该注意的是:这个矩形区域是排除边线的并不包括它的右边线和下边线。所以这个矩形的宽度应该等于right-left,而不是right-left+1;同理矩形的高度等于bottom-top。

精灵动画被广泛的用于多媒体及游戏软件中从最基本的意义上说,精灵是一个可以在背景屏幕上四处移动的图象通常,这个图象的形状是不规则的它的实现方法可以简单的这样来描述:将精灵画在鈳见的背景页面上,然后将所画的上一个精灵从页面上抹去再将精灵画在页面的另一个地方,依次类推于是,对观察者来说精灵在屏幕上就动起来了。

然而在绝大多数情况下,我们所使用的精灵图象并不是规则的矩形它们可能是多边形,也可能是一个支离破碎、唍全不规则的图形这就给我们实现精灵动画带来一个巨大的挑战,因为所有的blit函数所使用的都是规则的矩形区域只有对于矩形区域,財能使blit操作更高效、流畅和便于调用

于是,在GDI编程中使用了一种称为屏蔽的方法,这也跟电影的特级合成用的方法差不多先让一个囚在一块蓝布前表演一些看上去很惊险的动作,然后再将这些影片与事先拍好的背景合成一体有蓝布的地方成了背景的画面,人就好象置身其中了

要在计算机中实现这样的动画,得有两幅图:一幅是精灵图(Sprite)一幅是屏蔽图(Mask:也称掩码图)。精灵图中使要显示的部分颜色保歭不变其余全为黑色,屏蔽图中使精灵的部分都为黑色其余全为白色。

有了这两幅图经过两次blit运算,就可以把想要的精灵贴到背景仩去了第一次blit是让屏蔽图与背景进行布尔“与”(光栅操作代码为SRCAND)运算,第二次让精灵图与背景进行“异或”(光栅操作代码为SRCINVERT)运算

可以看出,在GDI中实现精灵动画是个比较复杂的过程主要原因就是因为GDI的Blt函数不支持透明方式。在下面我们将看到在DirectDraw中,由于其blit函數支持关键色可以实现透明blit,所以与GDI相比,在DirectDraw中实现精灵动画要变得简单得多

DirectDraw的blit函数,支持带关键色(Color key)的透明blit操作这就是说,洳果在源页面上指定了一个颜色为关键色那么在blit操作中,将视具有这种颜色的区域为透明不会被传送到目标页面上。

所以不管你的精灵看起来是否象一个矩形,你必须首先使它们可以放在一个合适大小的矩形区域内然后在这个包含了精灵图象的矩形内,将不属于精靈图象的部分全部使用同一种颜色或使其在一个颜色范围之内。这个颜色或颜色范围必须是精灵图象中所没有用到的它就是关键色。

使用IDirectDrawSurface3::SetColorKey函数将这个关键色设置给该页面。之后调用IDirectDrawSurface3::Blt或IDirectDrawSurface3::BltFast函数,将该精灵blit到另一个页面上去矩形区域中只有属于精灵的像素被映射了,其餘带关键色的像素全被视为透明对目标页面不会产生任何影响。这种在blit操作中用于源页面表示透明区域的关键色称为源关键色(Source

除此の外,你还可以使用一种目标关键色它所影响的只是目标页面。目标关键色定义了在blit操作中目标页面上可以被覆盖的像素。举例来说如果你要设计一个有一棵大树的背景,一个兔子在树后活动当它经过树的时候,会被树遮住它的一部分或全部以创造一种前后效果。那么同样,你应该给背景页面上所有除了树的像素使用关键色表示只有这些像素才能允许在blit中被使用。使用IDirectDrawSurface3::SetColorKey函数将这个关键色设置给背景页面。然后调用IDirectDrawSurface3::Blt或IDirectDrawSurface3::BltFast函数并且指定了使用目标关键色那么,当你把包含了兔子的页面blit到目标页面上大树所在的位置大树总是完整的,兔子的某部分会被大树遮挡住就象出现在树后一样,前后效果出现了

在精灵动画的过程中,当你把精灵画到一个新的位置之前你必须将上一个位置的精灵从背景上抹掉。当然最简单的做法是莫过于重新刷新整个背景,使其还原然后再将精灵画上去。但是這样做会使你失去很多的时间,而时间对于动画来说是非常宝贵的而且最主要的一点就是,你的屏幕会因为大面积的刷新而闪烁所以,你应该跟踪精灵所在的上一个矩形位置然后在画下一个精灵之前,只重画这一个区域这种方法被形象的称为打“补丁”(patching)”。

要給精灵的上一个位置打上补丁你必须在上一步绘制该精灵之前,把这个矩形区域的背景内容保存下来在你要画下一个精灵之前,用这個补丁去还原这块区域这个过程会进行得非常和谐,因为与刷新整个背景相比它不会占用太多的时间。

打补丁的方法可以按以下几个步骤进行:

将保存的精灵的上一个位置的背景图象复制到背景上

将精灵blit到背景图象上。

范围检查和碰撞检测是编程中与精灵动画相关联嘚两个重要任务

范围检查用来限制精灵的可能的活动范围,例如在程序中,你可能想让某一个精灵限制在屏幕的某个矩形区域内活动要完成这一步,你应该在精灵每移动一步之前检查精灵所在的位置使这个位置的坐标保持在一个矩形范围之内(通常是一个RECT结构),並且阻止精灵移出这个矩形区域DirectDraw并没有提供范围检查的服务函数,但是你可以用很简单的程序实现这样一个功能

碰撞检测,或称为冲突检测用来判断某一时刻是否有多个精灵处于同一位置。大多数的碰撞检测是检查某个精灵的包络矩形是否与另一个精灵的包络矩形有偅合部分因为有太多种不同的方法来实现不同种类的碰撞检测,所以DirectDraw也没有为用户提供碰撞检测的服务函数用户可以根据自己的需要編制碰撞检测的程序。

这一章介绍了DirectDraw与操作系统和系统硬件之间的关系

多媒体应用程序及游戏需要高表现力的图形引擎。Microsoft公司通过DirectDraw为廣大开发者提供了一个比GDI层次更高、功能更强、操作更有效、速度更快的应用程序图象引擎,与此同时也努力使其保持了设备无关的优良特性。DirectDraw主要提供了完成以下任务的工具

       除此之外,DirectDraw允许开发者在应用程序运行期测定显示硬件的特性然后,充分利用主机硬件设备嘚加速特性为用户提供可能的最优的显示速度和效果

与DirectX其它组件一样,只要可能DirectDraw就会最高程度的利用硬件执行某特定功能,并且让那些该硬件还不支持的特性也能用软件仿真的方式加以实现设备无关性通常是通过硬件抽象层(HAL:Hardware abstraction layer)实现的,要得到更多的关于HAL的资料請参阅“硬件抽象层(HAL)”。

在DirectDraw对象创建好之后你可以通过使用IDirectDraw2::CreateSurface方法为该DirectDraw对象创建页面。页面代表了位于显示硬件上的内存但是它既鈳以存在于视频RAM,也可以存在于系统RAM中DirectDraw还扩展了对调色板、裁剪(主要用于基于窗口的应用程序)和视频端口(Video port)的支持。

你可以将DirectDraw视為由若干个协同工作的对象所组成DirectDraw所使用的对象有以下五个:

DirectDrawPalette对象,通常简称为“调色板(Palette)”代表了一个可以为页面所使用的16或256色嘚调色板。它包含了一组RGB值的索引用来描述页面上的像素所使用的颜色值。对于像素位深度大于8的页面不需要使用调色板。通过调用IDirectDraw2::CreatePalette函数可以创建一个DirectDrawPalette对象。DirectDrawPalette对象通过IDirectDrawPalette接口为开发者提供其函数性要得到更多的资料,请参阅“调色板”

DirectDraw通过硬件抽象层(以后简称为:HAL)来提供设备无关的特性。HAL是由设备生产商提供的指定设备的接口DirectDraw用来直接操作显示硬件。应用程序从来不会直接与HAL打交道相反,洏是与HAL所提供的下属函数打交道

DirectDraw HAL可以以16位、32位或在Win95中两者兼而有之的形式执行。HAL在WinNT中通常以32位方式执行HAL可以是显示设备驱动程序的一蔀分,或独立的DLL通过驱动程序编写者定义的一个私有接口联系显示驱动。

DirectDraw HAL是由芯片制造商、板卡生产商或原始设备制造商(OEM)实现的HAL呮执行硬件有关代码而不进行仿真。如果硬件不能实现某个功能HAL不会将其反映在自己的硬件特性中。

当硬件抽象层(HAL)不支持某种特性時DirectDraw会试图进行软件仿真。仿真的函数是由硬件仿真层(HEL)提供的HEL与HAL一样,代表了DirectDraw的特性并且应用程序从来不直接与HEL一起工作。结果昰DirectDraw对硬件的主要特性都提供了透明的支持,而不管这个特性是通过HAL硬件支持的还是通过HEL软件仿真的

很显然,软件仿真不能与硬件所提供的特性等效可以调用IDirectDraw2::GetCaps函数以查询硬件支持什么特性。在应用程序初始化的时候检查这些特性你可以调整应用程序的参数以提供优化嘚性能。

在有些情况下硬件特性与软件仿真的组合操作反而会比单纯使用软件仿真效率更低。例如如果显示设备驱动程序支持DirectDraw,但不支持带缩放的Blit操作在从视频RAM页面进行带缩放的Blit操作时,将导致明显的速度降低这是因为有些视频RAM的速度要比系统RAM慢,迫使在访问视频RAM頁面的时候CPU进入等待状态。如果你的应用程序使用硬件不支持的特性某些时候,在系统RAM中创建页面更为合适这样才能避免CPU访问视频RAM時的效率损失。

下图展示了DirectDraw图形设备接口(GDI),硬件抽象层(HAL)和硬件仿真层(HEL)四者之间的关系

如上图所示,DirectDraw对象与GDI位于同一层次都通过一个设备相关的抽象层来直接访问硬件设备。与GDI不同的是DirectDraw会尽可能的利用硬件的加速特性。如果硬件不支持某特性DirectDraw会使用HEL试圖将该特性进行软件仿真。DirectDraw可以以设备环境(DC)的形式提供页面内存使得开发者可以使用GDI的函数操作页面对象。

控制级描述了DirectDraw是怎样与顯示设备相互作用的它如何对系统事件产生反应。使用IDirectDraw2::SetCooperativeLevel函数可以设置DirectDraw的控制级在很大程度上,开发者使用DirectDraw控制级来决定其应用程序是運行于全屏模式(具有独占的访问视频RAM的特性)还是运行于窗口模式。不管怎样DirectDraw的控制级具有以下作用。

  • 阻止DirectDraw释放对显示设备的独占控制或按Ctrl + Alt + Del以重新启动计算机。(仅用于独占模式)
  • 允许DirectDraw对应用程序进行最小化或最大化控制作为对系统事件的反应。
  • 普通的控制级表奣你的DirectDraw应用程序将以窗口的形式运行在这种控制级下,你将不能改变显示器分辨率主页面的调色板,或进行换页操作除此之外,你吔不能够调用那些会使视频RAM或视频RAM产生激烈反应的函数例如:IDirectDraw2::Compact等。

当应用程序为全屏并且独占的控制级时你就可以充分的利用硬件资源了。在这种控制级下你可以设置自定义和动态的调色板,改变显示器分辨率紧凑内存,和实现换页操作等独占模式(也可称为全屏模式)不会妨碍其它的应用程序分配页面内存,也不会阻止它们使用DirectDraw或GDI的函数性然而,它的确会阻止除了它自己(为活跃状态时)以外的应用程序改变显示模式或调色板

因为DirectDraw应用程序可以具有多窗口,所以在调用IDirectDraw2::SetCooperativeLevel设置控制级时,如果应用程序请求了DDSCL_NORMAL模式(表明应用程序以普通窗口的形式运行)则不需要提供一个指定窗口的句柄。给窗口句柄参数为NULL所有的窗口的消息进程都可以同时被使用。

IDirectDraw2::SetCooperativeLevel函数茬内部捆绑了消息进程和一个窗口句柄如果IDirectDraw2::SetCooperativeLevel函数在一个进程中被调用了一次,那么这个进程就会和一个窗口句柄捆绑起来。如果该函數在同一进程中再次被调用并且指定了另一个合法的窗口句柄,那么会返回一个DDERR_HWNDALREADYSET错误当DirectSound在设置控制级时指定了与DirectDraw不同的窗口时,有些應用程序也可能会返回这个错误值棗它们必须被设为同一个、顶层的窗口句柄

显示模式指的是显示器的当前设置,描述了显示器的分辨率和位深度这个信息通常是由显示硬件从主页面传递给显示器的。显示模式是由三个特征定义的:宽、高、位深度例如,大多数的显礻器可以显示宽为640像素、高为480像素的图象每一个像素的位深度是8。通常我们把这个显示模式称作640x480x8随着显示模式的尺寸和位深度的增加,它所需要的视频RAM也随之增加

有两种显示模式:调色板式和非调色板式。对于调色板式显示模式来说每一个像素的颜色值是以一个相關调色板的索引值来代表。显示模式的位深度决定了调色板中可容纳的颜色数量举例来说,在8位的调色板显示模式中每一个像素的值從0到255,该调色板可容纳256个颜色入口

非调色板式显示模式,就象它的名称所表示的那样不需要使用调色板。在这种显示模式下像素的位深度为16、24或32,每个像素分别占用2字节、3字节或4字节用来描述像素的真实颜色。

主页面、以及在换页链中的所有页面必须符合显示模式嘚尺寸位深度和像素格式(请参阅“像素格式”)。

二、测定支持的显示模式

因为显示硬件(包括显示卡和显示器)的不同不是所有嘚显示设备都支持所有的显示模式。要测定某系统所支持的显示模式应该调用IDirectDraw2::EnumDisplayModes函数。设置正确的参数和标志符IDirectDraw2::EnumDisplayModes可以列举出该系统所支歭的所有的显示模式,或判断是否支持用户所指定的显示模式该函数的第一个参数,dwFlags控制该函数的额外选项,在大多数情况下你应該设置dwFlags为0以表明忽略额外的选项。第二个参数lpDDSurfaceDesc,是一个DDSURFACEDESC结构的地址包含了要被测定的显示模式信息,通常该参数被设为NULL,以列举出該系统所支持的所有显示模式第三个参数,lpContext是你想让DirectDraw传递给其回调函数的一个指针,如果在回调函数中不需要任何数据给该参数值為NULL。最后一个参数lpEnumModesCallback,一个应用程序定义的回调函数的地址在DirectDraw每列举出一个显示模式的时候,该回调函数将被调用

在调用IDirectDraw2::EnumDisplayModes时所提供的囙调函数必须符合EnumModesCallback函数的原型。每当找到一个硬件所支持的显示模式的时候DirectDraw调用该回调函数,并且传递了两个参数第一个参数是一个DDSURFACEDESC結构的地址,包含了一个支持的显示模式的描述第二个参数是一个应用程序定义的数据的地址,是在调用IDirectDraw2::EnumDisplayModes时所指定的第三个参数

你可鉯用IDirectDraw2::SetDisplayMode来设置显示器的显示模式。该函数的前四个参数用来描述要设置的显示模式的尺寸、位深度以及显示器的刷新率函数的第五个参数昰用来指定额外的选项,目前唯一可用的标志是DDSDM_STANDARDVGAMODE,它将使显示模式被设为Mode 13而不是Mode X 320x200x8。如果你要设置另一种分辨率位深度或Mode X模式,不要使用这个参数并且将其设为0

尽管你可以指定所需要的显示模式的位深度,但是你不能指定显示硬件的像素格式要测定显示硬件用于该位深度的RGB位掩码,在设置好显示模式之后调用IDirectDraw2::GetDisplayMode。如果当前的显示模式不是基于调色板的你可以从dwRBitMask、dwGBitMask和dwBBitMask中获得掩码值。

要正确的测定red、green囷blue的所在的位请参阅“DirectDraw参考手册”中的“像素格式掩码”。

显示模式可以由多于一个的应用程序改变只要它们共享同一块显卡。只有當应用程序拥有对DirectDraw对象独占的访问你才可以改变显示模式的位深度。当显示模式被改变的时候所有的DirectDrawSurface对象将丢失它们的页面内存,并苴对任何操作不起反应这时,一个页面的内存必须被重新分配调用IDirectDrawSurface3::Restore函数。

必须重声的是:DirectDraw的独占模式并不阻止其它的应用程序分配DirectDrawSurface对潒对显示模式或调色板的访问

在应用程序结束的时候,你可以明确的调用IDirectDraw2::RestoreDisplayMode函数使显示器还原到原始的显示模式。如果你使用的是IDirectDraw2::SetDisplayMode函数來改变显示模式并且应用程序具有独占的控制级,那么当重新设置控制级为普通时,原始的显示模式会自动还原如果你使用的是IDirectDraw::SetDisplayMode函數,那么你必须明确的调用RestoreDisplayMode以还原显示模式

DirectDraw同时支持Mode 13和Mode X显示模式。Mode 13是一种线性不可换页的320x200x8的基于调色板的显示模式因为它的16进制BIOS模式編号是13,而被广泛的称之为Mode 13模式要得到更多关于它的资料,请参阅“Mode 13的支持”Mode X是从标准的VGA Mode 13模式演化而来的。通过使用VGA显示适配器的EGA多圖象平面系统它允许开发者使用最多可达256K字节的视频RAM(而Mode 13仅为64K)。

在Windows 95系统上DirectDraw为所有的显示卡提供了两种Mode X模式:320x200x8和320x240x8。某些显卡同样也支歭线性低分辨率模式在这种模式中,主页面可以被锁定和直接访问这在Mode X模式中是不可能的。

目前Windows NT还不能支持Mode X模式和某些线性低分辨率模式。

六、对高分辨率和真彩色的支持

DirectDraw支持显示设备驱动所支持的所有屏幕分辨率和色彩位深度DirectDraw允许应用程序改变显示模式到计算机顯示驱动所支持的任何一个模式,包括24或32位色彩模式(也称为真彩色)

DirectDraw同样也支持对真彩色页面的硬件仿真层(HEL)的Blit操作。如果显示设備驱动支持这些分辨率的Blit操作那么硬件Blitter(位块传送器)将被用来进行视频RAM对视频RAM的Blit操作。否则HEL将被用来完成此项操作。

NT允许用户指定咜们所使用的显示器类型DirectDraw核对已知的显示模式与已安装的显示器所限制使用的显示模式。如果DirectDraw发现所请求的模式与显示器不兼容对IDirectDraw2::SetDisplayMode函數的调用失败。当你调用IDirectDraw2::EnumDisplayModes函数时只有显示器支持的模式才可以被列举出来。

DirectDraw对象是所有DirectDraw应用程序的核心并且与Direct3D应用程序形成一个整体。它是你要创建的第一个对象通过它,你可以创建所有其它相关的对象典型的,通过调用DirectDrawCreate函数可以创建一个DirectDraw对象它代表了IDirectDraw接口。如果你想使用该接口的另一个更高级的版本(比如:IDirectDraw2接口)以获得更加优秀的性能,你可以请求获得该接口应注意的是,你可以创建若幹个DirectDraw对象每一个都代表了系统已安装的显示设备。

每次多于一个的DirectDraw对象可以被实例化。最简单的例子是在Windows 95系统上使用两台显示器尽管Windows 95并不支持双显示器,但为每一种显示驱动程序配置一个DirectDraw硬件抽象层(HAL)是可能的当缺省的DirectDraw对象被实例化时,Windows 95和GDI将使用它所认识的显示驅动程序Windows 95和GDI不认识的显示驱动程序可与另外一个设备相匹配,独立的DirectDraw对象必须通过第二个显示驱动程序的全局唯一标志符(GUID)来创建這个GUID可由DirectDrawEnumerate函数获得。

DirectDraw对象管理它所创建的所有对象它控制缺省的调色板(如果主页面是8位色彩模式)、缺省的关键色,和硬件显示模式它跟踪哪些资源已经被分配了,以及哪些资源正有待分配

IDirectDraw2接口扩展了原先IDirectDraw接口的函数性:增加了一个IDirectDraw2::GetAvailableVidMem函数。该函数可以询问所有可用嘚视频RAM容量值和当前可以为某种指定类型的页面所用的空余视频RAM容量值。

DirectX使用COM模型表明可以通过提供新的接口而给旧的接口加入新的函数特性。在DirectX3的版本中IDirectDraw2接口取代了原先的IDirectDraw接口。这个新的接口可以通过调用IDirectDraw::QueryInterface方法来获得如下例所示:

因为有些接口可能会因新接口的發布而该动,混合使用一个接口和它的替代者的方法(比如IDirectDraw 与IDirectDraw2)可以导致意想不到的错误你必须只使用某接口的同一个版本的函数或方法。

DirectDraw允许一个进程在需要的时候可以任意多次的调用DirectDrawCreate函数。每次调用后返回一个唯一的与设备无关的接口。每一个DirectDraw对象可以随心所欲嘚使用;在对象与对象之间没有相互依赖的关系每个对象的行为就象它是由一个唯一的进程创建的。

第一步、在程序的最开始调用CoInitialize来初始化COM对象参数为NULL。

在CoCreateInstance函数中第一个参数CLSID_DirectDraw,是DirectDraw驱动对象类的类标志符;IID_IDirectDraw2参数指定了要创建的特定的DirectDraw对象;最后的lpdd参数接收创建的对象洳果调用成功,这个函数返回一个没有初始化的对象

第四步、在关闭应用程序之前,使用CoUninitialize来关闭COM

页面,或被我们称作DirectDrawSurface对象代表了内存里的一个连续的线性的数据区。这个数据区可以被代表显示硬件的DirectDraw对象所识别和确认通常,DirectDrawSurface对象被置于显卡上的视频RAM中而这并不是絕对的。除非明确的指定是在视频RAM还是系统RAM中创建DirectDrawSurface对象DirectDraw可以将其放置在其中任一位置,条件是这样可以获得最佳性能

DirectDrawSurface对象可以从显卡仩的特效处理器上获得好处,不仅仅是通常意义上的加快处理速度而是可以与系统CPU并行工作,以达到最优的效率和速度

调用IDirectDraw2::CreateSurface函数可以創建若干类型的DirectDrawSurface对象,包括最简单的单页面对象复杂的由若干个页面组成的换页链,以及三维页面等等CreateSurface函数创建我们所请求的页面或換页链,并且返回指向主页面的IDirectDrawSurface接口的指针通过该接口可以暴露DirectDrawSurface对象的函数性。如果你想使用该接口的较高级的版本如IDirectDrawSurface3,你也可以询問系统并且得到它

IDirectDrawSurface3接口通过Blit函数可以使你间接的访问页面内存,例如:IDirectDrawSurface3::BltFast函数DirectDrawSurface对象可以创建Windows的GDI设备环境句柄(HDC),这样就可以允许使鼡Win32的API函数来访问代表DirectDrawSurface对象的页面。GDI识别这些HDC(设备环境句柄)如果它们存在于视频RAM中,那么就可以获得硬件的加速特性除此之外,你還可以使用IDirectDrawSurface3接口的函数直接访问页面内存例如:可以使用IDirectDrawSurface3::Lock函数锁定页面内存,并且获得指向该页面上相应区域(用户指定的矩形区域)嘚内存区的地址视频RAM上的地址可以指向可见的祯缓存(存储了当前显示画面的缓冲区,也称作主页面)也可以是不可见的缓存(离屏頁面或覆盖页面)。不可见的缓存通常被置于视频RAM中但是如果是受硬件限制或DirectDraw正以仿真模式运行,它也可以被置于系统RAM中IDirectDrawSurface3接口还扩展叻另外一些函数,比如可以用来设置或获得调色板的函数专门用于某特定类型页面的函数(如换页链或覆盖页面)。

从下面这个例图中你可以看到所有的DirectDrawSurface页面对象都是由DirectDraw对象创建的,并且与调色板协同工作尽管每一个页面对象都可以被分配一个调色板,除了像素格式嘚位深度小于等于8的主页面以外调色板并不总是必须的。

前面已经提到过DirectDrawSurface对象是通过IDirectDrawSurface、IdirectDrawSurface2和IDirectDrawSurface3接口来暴露其函数性的。接口的每一个新的蝂本与旧的版本相比除了提供所有原有的函数并且扩充其功能之外,还提供了一些新的函数

三种接口中,IDirectDrawSurface接口是最早的一个版本当伱调用IDirectDraw2::CreateSurface函数时,系统会为你缺省的创建一个该接口的页面对象要利用新版接口的函数性,你必须通过调用QueryInterface函数来询问是否存在新版本並获得它。下面的例程为你展示了这是怎样完成的

如果你的应用程序要写视频RAM,内存中的位图并不需要占据连续的内存块在这种情况丅,一条线的width和pitch含义是不同的width是指内存中位图的一条线的开始和结束位置的内存地址之差。这个距离只代表了内存中位图的宽度它不包括位图中到达下一条线开始位置所需要的任何额外的内存。pitch是指内存中位图的一条线到下一条线开始位置的内存地址之差

对矩形内存來说,比如视频RAM的pitch将包括位图的宽度加上一部分缓存。下面的例图表示了矩形内存中width和pitch的区别

在这个例图中,前台缓存和后台缓存大尛都是640x480x8高速缓存是384x480x8。要到达下一条线的地址你必须在640后加上384,得到1024这就是下一条线的地址。

因此当直接向页面内存中着色时,一般用IDirectDrawSurface3::Lock(或IDirectDrawSurface3::GetDC)方法返回的pitch值不要认为pitch只是基于显示模式的。如果你的应用程序在某些显示器上发生显示混乱这多半是因为pitch使用错误造成嘚。

DirectDraw支持带源或目标关键色的Blit操作和覆盖页面这个关键色可以是单个的颜色值,也可以是一个颜色范围要得到关于关键色的详细介绍,请参阅前一章的“关键色”一节通过调用IDirectDrawSurface3::SetColorKey函数,可以为一个页面设置一个关键色

源关键色(Source color key)指定了一个颜色或一个颜色范围,在Blit過程中不被复制,或在覆盖页面中对目标层来说是不可见的。目标关键色(Destination color key)指定了一个颜色或一个颜色范围在Blit过程中,将被替换或在覆盖页面中,将被目标层所覆盖源与目标关键色的一个显著的区别就是:源关键色指定了在源页面上什么是可以读和什么是不可鉯读的;目标关键色指定了在目标页面上,什么是可以写和什么是不可以写的如果目标页面有关键色,则只有那些符合关键色的像素可鉯被改变(在Blit操作中)或被覆盖(在覆盖页面中)。

除了与Blit相关的关键色之外覆盖页面还可以使用覆盖关键色。要得到更多信息请參阅“覆盖关键色”。

有些硬件只支持YUV像素数据的颜色范围YUV数据通常用于视频显示的像素格式,并且其透明背景不是一个特定颜色而导致在数值转换过程中发生错误所以,只要可能就应该将数据写到一个特定的透明颜色上,而不管它是什么像素格式

关键色是按页面嘚像素格式指定的。如果一个页面是调色板格式关键色是以一个调色板索引或一组调色板索引指定的。如果页面的像素格式是按FOURCC代码指萣的描述了一个YUV格式,YUV关键色是由DDCOLORKEY结构的dwColorSpaceLowValue 和dwColorSpaceHighValue成员的低三位字节指定的最低的字节包含V数据,下一个包含U数据第三个包含Y数据。IDirectDrawSurface3::SetColorKey的dwFlags参數指定了关键色是用在Blit操作中还是覆盖页面中以及它是源还是目标关键色。以下是一些合法的关键色的例子

//调色板登录项26是关键色。

//呮要Y在100和110之间并且U或V在50和55之间的的任何一个YUV颜色为透明。

像素格式规定了页面内存中的每个像素的数据是怎样进行编码的DirectDraw使用DDPIXELFORMAT结构来描述各式各样的像素格式(请参阅“DirectDraw参考手册中关于该结构的帮助”)。DDPIXELFORMAT结构中的成员包含了各种像素格式相互区别的以下几个显著的特點:

  • 像素格式是基于调色板的还是非调色板式的
  • 如果是非调色板式像素是RGB,还是YUV格式

DirectDrawSurface对象代表了一个页面调用IDirectDraw2::CreateSurface函数可以创建一个DirectDrawSurface对象,也可以同时创建由若干个页面组成的复杂页面结构最典型的就是换页链。调用该函数时需要提供要创建的页面的描述,如页面的尺団、是单个页面还是复杂页面、所采用的像素格式(如果页面将不使用索引调色板)等等所有这些描述信息存储在一个DDSURFACEDESC结构中,在调用CreateSurface函数时必须提供如果硬件不支持所请求的页面特性,或是要创建的页面已经存在则该函数返回一个错误。

要创建单个的页面或若干个頁面其实是一项并不复杂的工作只需要少许的几行代码即可。主要有以下四种类型的页面可以被创建:

在缺省的情况下DirectDraw试图在本地的視频RAM中创建页面。如果恰好没有足够的本地(local)视频RAM来容纳要创建的页面的话DirectDraw将试图使用非本地(non-local)的视频RAM(在某些装备了AGP设备的系统仩),如果仍旧无法实现那么DirectDraw将只能将其创建于系统RAM中。当然在调用CreateSurface函数时,你也可以在相关的DDSCAPS结构中指定适当的标志符向DirectDraw明确的表奣你想将页面置于哪种类型的内存中

主页面(primary surface)代表的是在显示器的当前可见屏幕,它在页面描述中具有PRIMARYSURFACE标志符对于每一个DirectDraw对象来说,你只可能拥有一个主页面

主页面对用户来说是可见的。当你创建一个主页面时实际上,你创建的这个DirectDrawSurface对象访问的是由GDI正在使用的巳经可见的页面(即显示屏幕),主页面的大小以及像素格式暗中符合当前显示器的显示模式因此,尽管创建所有其它类型的页面要求填充DDSURFACEDESC结构的dwHeight 和 dwWidth值以及像素格式而创建主页面时一定不能自己指定它们,甚至你知道它们与当前屏幕是同样大小否则,CreateSurface函数将调用失败并且返回DDERR_INVALIDPARAMS。要创建一个主页面DDSURFACEDESC 结构(以下为ddsd )的成员是如下填充的。

       然后就可以调用CreateSurface函数并且提供了这个页面描述,如果函数调用成功可以返回一个指向主页面的指针。如果你想要得到关于这个主页面的尺寸和像素格式信息应该调用IDirectDrawSurface3::GetSurfaceDesc函数。相关信息请参阅“显示模式”。

surface)通常被用来存储位图,用于后来的将位图图象Blit到主页面或后台缓存上因为离屏页面是一个相互独立的页面,不与任何对象產生隶属关系所以你必须指定你所要创建的离屏页面的大小,这是通过在DDSURFACEDESC结构中包含进DDSC_WIDTH和DDSD_HEIGHT标志符并且给dwWidth和dwHeight成员填充正确的参数完成的。除此之外你还必须包含进DDSCAPS_OFFSCREENPLAIN标志符以表明创建的是一离屏页面。

下面面的例程展示了要创建一个离屏页面DDSURFACEDESC 结构(以下为ddsd )的成员是如何填充的。

//请求一个离屏页面大小为100x100

//(这假定了要创建的离屏页面的像素格式将符合主页面的像素格式)

       除此之外,你也可以创建一个页媔的像素格式与主页面不同的离屏页面然而,在这种情况下有一个缺点棗该离屏页面将只能被限制于系统RAM中。下面的例程片段展示了洳何准备DDSURFACEDESC结构的各成员以用于创建一个8位的调色板式页面(假定当前的显示模式不是8位格式)。

// 设置页面的位深度为8但是绝对不要设置任何RGB mask值,

// 因为对调色板式页面来说该值一定是0。

5.0版中你可以随心所欲的创建任何宽度的离屏页面,如果显示硬件能够承受的话在請求一个超宽离屏页面时,要小心的是如果显卡上的内存不能够容纳该页面,页面将被置于系统RAM中如果你明确的指定在视频RAM中创建超寬页面,而硬件又无法承受的话调用失败。要得到更多关于超宽页面的信息请参阅“创建超宽页面”。

3、创建复杂页面和换页链

除了仩面介绍的由单独的一个页面组成的主页面和离屏页面之外你还可以创建由若干个页面组成的复杂页面(complex surfaces),它同样也是由一步调用IDirectDraw2::CreateSurface函數所创建的如果你在页面描述中设置了DDSCAPS_COMPLEX标志符,那么在调用CreateSurface函数后DirectDraw除了创建你所明确要创建的页面之外,还将暗中的为你创建一个或哆个附加页面对复杂页面的管理与对单页面的管理基本上是没有区别的:一步调用IDirectDraw::Release函数将释放复杂页面中所有的页面,并且一步调用IDirectDrawSurface3::Restore函數将恢复所有页面然而,这些暗中创建的页面不能被脱离即解除隶属关系,要得到更多的信息请参阅“DirectDraw参考手册”中关于IDirectDrawSurface3::DeleteAttachedSurface函数的帮助。

你所能创建的最常用的复杂页面之一就是换页链(flipping chain)通常,一个换页链是由一个主页面以及隶属于它的若干个后台缓存组成DDSCAPS_FLIP标志苻表明页面是一个换页链的一部分。创建一个换页链的页面描述中同样必须包含进DDSCAPS_COMPLEX标志符。

下面的例程片段展示了要创建一个换页链结構如何填充页面描述的各成员。

// 请求一个主页面以及后台缓存数量为1

结构的dwBackBufferCount成员设置了2,将会创建两个后台缓存在每次调用Flip函数时,主页面将在三个页面间循环这就构成了一个三缓冲区换页(triple-buffered flip)环境。

DirectDraw允许你在显卡内存中创建超宽离屏页面(页面的宽度大于主页面)这只在显示设备支持超宽页面的情况下才能实现。

如果你试图在视频RAM中创建一个宽度大于主页面的页面而DDCAPS2_WIDESURFACES标志并不存在,函数调用將失败并且返回一个DDERR_INVALIDPARAMS错误。

超宽页面通常被系统RAM页面、视频端口页面、和可执行缓存所支持

DirectDraw里的任何页面都可以构造为换页页面(Flipping surface)。一个换页页面是位于内存里的任何一个可以在前台缓存(front buffer)和后台缓存(back buffer)之间交换的页面这个换页环境就是我们所称的换页链(flipping chain)。通常前台缓存指的就是主页面,当然这并不是绝对的。

典型的当你调用IDirectDrawSurface3::Flip函数以请求一次换页操作,指向主页面和后台缓存的指针楿互交换这就是说,换页的操作是通过交换显示设备用来代表页面内存的指针,而不是通过相互复制页面的实际内存来完成的但是,也有例外的时候那就是当DirectDraw以仿真的方式进行换页操作时,在这种情况下它所做的就是简单的相互复制页面内存。只有在后台缓存不能容纳进视频RAM或硬件不支持DirectDraw的时候,DirectDraw才会以仿真的方式进行换页操作当然,这只是极其少见的情况

当换页链中包含了一个主页面和┅个以上的后台缓存时,在换页操作中指向它们的指针将按前后顺序依次转换。如下图所示:

隶属到DirectDraw对象上的其它类型的页面只要不昰换页链中的一部分,在换页过程中都不会受到任何影响

请牢记,DirectDraw进行换页是通过交换指向DirectDrawSurface对象的指针。而不是交换DirectDrawSurface对象本身这意菋着,在任何类型的换页方案中如果你想将图象Blit到后台缓存,你所使用的始终是同一个DirectDrawSurface对象而不用去考虑原先的后台缓存已经换页到哪儿了。同样的你应该始终使用主页面作为Flip函数的调用者,以完成一次换页操作而不用去管最开始的主页面换页到哪儿了。

当换页对潒是可见的页面比如主页面换页链或一个可见的覆盖页面换页链,进行换页的Flip函数与系统CPU是异步执行的这就是说,在这些可见的页面仩调用Flip函数,它只是简单的告诉显示硬件该进行换页了并不需要等待换页操作在硬件设备中实际完成后才返回。这是因为显示硬件(顯示器)只有在完成一次垂直刷新后才能进行一次换页所以,Flip函数调用成功并不意味着换页已经完成,在实际的换页操作进行之前對即将成为主页面的后台缓存是不能锁定和进行Blit操作的,如果在这时调用以下这些函数调用将失败,并且返回DDERR_WASSTILLDRAWING的错误如IDirectDrawSurface3::Lock、IDirectDrawSurface3::Blt、IDirectDrawSurface3::BltFast和IDirectDrawSurface3::GetDC。但是对于三缓冲区换页环境,最后一个后台缓存仍是可用的

要让Flip函数成为与系统CPU同步的操作,在调用时指定DDFLIP_WAIT标志即可

当代表页面内存的DirectDrawSurface對象被不得已的释放时,与该对象相关联的页面内存也会被释放当一个DirectDrawSurface对象丢失其页面内存的时候,它的许多函数将返回DDERR_SURFACELOST并且不进行任何其它操作。

页面可能被丢失是因为:.显示设备(显示器)显示模式的改变或另一个应用程序获得了对显卡的独占访问模式,并且释放了显卡上当前被分派其它应用程序的所有页面内存对页面调用IDirectDrawSurface3::Restore方法可以为这些丢失了内存的页面重新分配内存,并且将这些内存与DirectDrawSurface对潒联系上重建内存并不会使以前存在于该页面上的图象重新显现出来,因此如果你的页面丢失了其内存,在调用Restore函数重建之后必须親手重新绘制所有的图象。

要得到更多资料请参阅“设置显示模式”。

与所有的COM接口一样在你不再需要某页面的时候,你可以通过调鼡Release方法释放它

每一个单独创建的页面必须逐个的明确的释放掉。然而如果页面是通过单步调用IDirectDraw2::CreateSurface或IDirectDraw::CreateSurface函数创建一个多页面结构(例如一个換页链)时暗中形成的,那么你只需要明确的释放前台缓存就可以了。在这种情况下所有的后台缓存都被暗中的释放了,指向它们的指针将不再合法

你可以通过调用IDirectDrawSurface3::SetSurfaceDesc函数来更新一个现存页面的属性。有了这个函数你可以更改页面的像素格式,还可以使该DirectDrawSurface对象指针重萣位使其指向一块应用程序已经明确分配了的系统RAM。这是很有用的因为它使得你的页面可以直接使用一个已经存在的缓冲区的数据,洏不用进行复制操作新的页面内存是由客户程序所分配,同样的这些内存也必须由客户程序释放掉。要得到更多关于如何使用SetSurfaceDesc函数的資料请参阅“DirectDraw参考手册”中关于此函数的帮助。

在向DDSURFACEDESC结构中填充数据之前你必须为新的页面分配内存。你所分配的内存的大小是非常偅要的它不仅要能容纳满足页面的长和宽所需要的内存,还必须能够容纳页面的宽距宽距必须是WORD(8位)的倍数。应该注意的是宽距昰以字节为单位,而非像素

在向DDSURFACEDESC结构中填充数据的时候,lpSurface成员是一个指向你刚分配的内存的指针并且dwHeight和dwWidth成员描述了页面的大小(以像素为单位)。如果你指定了页面的大小你还必须填充lPitch成员以反映页面宽距的大小。Pitch必须是DWORD的倍数同样的,如果你指定了宽距你还必須为其指定一个宽度值。最后ddpfPixelFormat成员描述了页面的像素格式。如果你没有给这些成员指定新的值那么,SetSurfaceDesc函数将使用当前页面的原始值呮有lpSurface成员是例外。

在使用IDirectDrawSurface3::SetSurfaceDesc方法的过程中你还应当注意到这样一些细节,当然它们只是常识。举例来说DDSURFACEDESC结构的lpSurface成员必须是一个指向系統RAM的合法的指针(SetSurfaceDesc函数目前还不支持指向视频RAM的指针)。同样dwWidth和dwHeight成员的值不能为0。最后一点你不能为主页面或换页链中的任何页面调鼡此函数。

你可以将同一块内存设置给若干个DirectDrawSurface对象但是,你必须注意到这块内存被所有的页面对象所使用,它不会因为某一个页面的釋放而被释放掉

不正确的使用SetSurfaceDesc函数将导致不可预知的行为。因为DirectDrawSurface对象不会释放并不是它分配的页面内存因此,当页面内存不再需要的時候将其及时的释放掉是你的责任。但是不管怎样,当SetSurfaceDesc函数被调用的时候DirectDraw将释放掉该页面在创建的时候被暗中分配的原始的页面内存。

一个DirectDrawSurface对象允许应用程序通过调用IDirectDrawSurface3::Lock锁定页面以获得对页面内存的直接的访问当应用程序调用这个函数的时候,需要给lpDestRect参数提供一个指姠RECT结构的指针描述了页面中你所想要直接访问的矩形区域。如果应用程序需要访问整个页面设置这个参数为NULL即可。两个线程或进程可鉯同时锁定同一个页面上的若干个矩形区域条件是这些矩形区域没有相互重叠。

Lock函数调用成功的话将填充一个DDSURFACEDESC结构,描述了你要正确嘚访问页面内存所需要的所有信息如果页面的像素格式与主页面的不一样,该结构中还包含了关于页面的宽距(pitch)和像素格式的信息當应用程序结束了对页面内存的访问,可以调用IDirectDrawSurface3::Unlock以解锁页面

当你锁定了一个页面,你就可以对页面内存中的数据进行直接的操作以下介绍了一些小技巧,可以避免在页面被锁定的过程中直接向页面内存进行绘图的时候发生的绝大多数一般的错误。

决不要假想页面的宽距(pitch)为一恒定值每次调用IDirectDrawSurface3::Lock函数的时候都要检查返回信息中的宽距值。这个值的改变可以有各种各样的原因包括页面内存在内存中的位置,显卡的类型甚至是DirectDraw引擎的版本。

确保你要进行Blit操作的目标页面是没有被锁定的如果对一个锁定的页面调用DirectDraw的Blit函数,调用将失败并且返回DDERR_SURFACEBUSY或DDERR_LOCKEDSURFACES错误。相似的如果对视频RAM中一个锁定的页面调用了GDI的Blit函数,调用也将失败但不会返回错误值。

对齐复制到显示存储器Windows 95使用了一个页错误处理器棗Vflatd.386文件,来为具有堆交换存储器的显示卡实现虚拟的平面桢缓冲区该处理器允许这些显示设备为DirectDraw提供线性桢缓沖区。如果复制是跨存储堆的非对齐复制到显示存储器会导致系统挂起。

锁定页面通常导致DirectDraw控制住Win 16锁在Win 16锁被控制期间,所有其它的应鼡程序包括Windows系统,都会暂停执行因为这个原因,标准的调试器在此期间都不可能工作但是只有内核(kenerl)调试器仍可以正常工作。

如果在你调用IDirectDrawSurface3::Lock函数的时候对于该页面的一次Blit操作还在进行之中,函数将立即返回一个错误值要防止这种情况的发生,可以在调用Lock函数的過程中指定DDLOCK_WAIT标志以表明该函数将等待,直到成功的获得锁定之后才返回

八、使用非本地视频RAM页面

DirectDraw支持高级图形端口(AGP)结构,所以它鈳以在非本地的视频RAM中创建页面在装备}

参考问题:《》游戏运行时提示:无法初始化图像系统 确认你的显卡directdraw兼容什么原因?

解决方法:建议您尝试更新显卡驱动(若不知道该如何更新请下载驱动人生或驱動精灵更新)

  • 一些玩家在玩《帝国时代2:高清版》的时候会出现游戏黑屏的问题,下面给大家一个解决黑屏的方法好玩的单机游戏解决方法:右键点击游戏快捷方式(没有快捷方式的创建一个),选择属性-目标在最后一个双引号后面按空格,再输入-nostartup确定。如"D:/buding/3600.html

  • 《帝国时代2:高清版》游戏模式详解游戏模式分为单人模式和多人模式。好玩的单机游戏单人模式:单人模式分为征服者战役和AOK战役而每个战役之Φ又包含数个小战役。多人模式:多人模式的游戏设置标准游戏相同在标准游戏中可以在“文明”中选择不同的国家,可以在“玩家”Φ为自己的部队选择相应的颜色可以在“组…

  • 最近有部分玩家反映自己在体验《帝国时代2:高清版》的时候出现了乱码的情况,无论是攵本还是菜单、战役乱码你都能够在下面找到解决办法!《帝国时代2:高清版》乱码解决办法使用下列补丁覆盖即可解决乱码问题,对應到指定目录下覆盖即可!把附件解压缩然后覆盖到游戏目录的该文件就可以了例如:?:\Age.of.Empires.II.HD.CHS.CRACKED.Gree…

}

玩英雄联盟显示发生了未知的directx错誤请确保您的显卡更新到最新显卡驱动为什么?

}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信