一.DirectX简介
1_1.DirectX的特性
1_2.DirectX是一种Windows环境下标准的高性能游戏、多媒体开发工具包,使用DirectX开发的程序能够与操作系统默契地配合成为“真正”的桌面应用程序;可以利用硬件厂商提供的驱动程序接口,充分最佳的设备性能;通过直接底层硬件操作,实现最快速、短延时、设备无关的底层接口。
1_3.DirectX采用了组件对象模型(COM)标准,因此对于不同对象的版本可以有不同的接口,这使得用DirectX开发的程序在未来将得到完全兼容和支持的保证。
1_4.DirectX的结构
DirectX需要以设备无关的方法提供设备相关的性能,所以DirectX的结构是由两个驱动程序构成:硬件抽象层(HAL)和硬件模拟层(HEL),当Direct对象创建时,会同时建立一张“兼容表”,其中记录了当前硬件系统支持的功能,当DirectX需要实现某个功能时就查询该表,得到硬件对功能的支持信息,如果功能能够得到硬件支持,则向HAL发出求,以得到硬件的支持,否则向HEL发出请求,以模拟方式实现功能。
1_5.DirectX的主要组成
:直接访问图形硬件,管理用于显示的内存(显示内存和系统内存),提供高速图形和页面切换动画;
(2)Direct3D:提供3D硬件接口;
(3)DirectInput:主要支持输入服务,同时支持输出设备;
(4)DirectSound:提供3D声音效果,管理声卡内存;
(5)DirectPlay:提供网络多人游戏的通讯、组织功能;
(6)DirectSetup:自动安装DirectX驱动程序。DirectX的上述组成,分别以实例介绍其在C++ Builder中的实现方法。
本文将按照
二.DirectDraw程序设计
2.1 DirectDraw实现的基础—显示方式的设置DOS下开发图形应用程序,这将是很简单的事,只要调用DOS的中断服务程序即可实现,但是使用用DirectDraw就比较复杂。由于DirectDraw的设计目标是提供设备无关的编程接口和高效、多功能的硬件访问支持,所以DirectDraw需要考虑更多的问题。
设计图形程序首先遇到的问题是将屏幕设置成一种合适的图形显示方式,然后把图形绘画到屏幕页面上。如果您在
DirectDraw在Windows环境下支持两种图形方式:全屏幕独占方式和窗口方式。这里我先以全屏幕独占方式,介绍DirectDraw设置屏幕显示方式步骤,函数具体使用格式和编程方法将在2.2中介绍:
2.1.1 选择硬件设备DirectDraw硬件抽象设备,例如,一台计算机可能有两台或更多的显示器,那么DirectDraw对象与哪个HAL对应呢?我们可以使用DirectDrawEnumerate函数来枚举系统所有已安装的设备,以供选择,并返回设备的唯一标识GUID。DirectDraw默认主显示设备的GUID为NULL;
计算机系统不一定只有一个
2.1.2 创建DirectDraw对象DirectX是使用面向对象的程序设计技术,因此,使用DirectDraw编程就首先要创建DirectDraw对象。使用DirectDrawCreate函数及将第一步获得的设备GUID作为参数可以创建基于所选设备的DirectDraw对象;
由于
2.1.3 获取DirectDraw更高版本的COM接口DirectX5以上版本提供的功能则可以跳过本步骤,否则必须使用新创建DirectDraw对象的QueryIntrface方法来获得IDirectDraw2或更高的COM接口。在2.2例中将介绍如何获得DirectX5以上版本提供的IDirectDraw2接口;
如果您不打算使用
2.1.4 设置协作级别DirectDraw对象的SetCooperativeLevel方法;
协作方式可以控制程序与系统其他应用程序之间的交互关系,典型的例子是:设置为全屏独占方式还是窗口普通方式。设置协作级别可以用
2.1.5 枚举设备支持的各种显示方式,选择并设置合适的显示分辩率、色彩深度和刷新频率等。DirectDraw的EnumDisplayModes方法可以枚举设备支持的所有图形方式供用户选择,在某些已确定图形显示方式的应用程序中可以通过此枚举功能来检查系统设备是否支持指定的图形显示方式。DirectDraw的SetDisplayMode方法可以设置所需要的图形显示方式。
使用
使用
2.2 用DirectDraw设置屏幕图形显示方式的实例dx1,首先我们将在这里讨论C++ Builder中进行DirectX编程的有关问题,然后再详细介绍实现程序每一步骤的相关技术。
现在我们开始编写第一个示例程序“设置全屏幕独占图形显示方式的程序”
2.2.1 dx1程序运行过程介绍
dx1是根据DirectDraw设置屏幕图形方式的过程设计的,运行界面如图2.1所示。在窗口右边有六个功能按钮,它们按照屏幕图形显示方式设置实现的步骤自上而下排列,程序开始运行时,除第一个按钮“显示设备的枚举”是可用的,其它按钮均不可用。由于用户必需按照固定的步骤操作,所以,当一个按钮任务完成后,dx1程序会将下一步任务的2.1 dx1 屏幕显示方式设置程序运行界面Enumerate devices OK!”,否则显示“Enumerate devices failed!” ,同时在状态组中的设备枚举下拉框中可以看到枚举的设备(一般系统只有一个”主显示设备—Display);确定设备枚举选择为“主显示设备”后,可以进行“创建DirectDraw对象”、“获得COM的IDIRECT2接口”、“设置协作级别”,每个步骤的运行状态都会显示在“运行状态”右边的文本框中;在执行了“DDraw2显示模式的枚举”后,状态组下方“显示模式DDraw2”下拉框中将列出所有显示设备支持的显示方式,选择需要的图形显示方式,再按“设置DDraw2”的显示方式,屏幕就会立刻切换为指定的显示方式。
图
按钮设为可用。
按下“显示设备枚举”按钮后,窗口左上方“运行状态”对应的文本框中将显示任务完成情况,若成功则显示“
2.2.2 dx1编程实现C++ Builder后在窗口Form1中设计如图2.1的操作界面,各对象相关属性设置如表2.1:
启动
控件对象类型 | 控件对象名称 | 相关属性 | 属性值 |
TForm | Form1 | Caption | DirectX 练习程序1 |
TLabel | Label1 | Caption | 运行状态: |
TLabel | Label2 | Caption | 设备的枚举 |
Tlabel | Label3 | Caption | 显示模式 DDraw2 |
TEdit | Edit1 | Text | (空) |
ReadOnly | true | ||
TGroupBox | GroupBox1 | Caption | 状态 |
TCombBox | ComboBox1 | Text | (空) |
TCombBox | ComboBox2 | Text | (空) |
TGroupBox | GroupBox2 | Caption | 协作级别 |
TCheckBox | CheckBox1 | Caption | DDSCL_ALLOWMODEX |
TCheckBox | CheckBox2 | Caption | DDSCL_ALLOWREBOOT |
TCheckBox | CheckBox3 | Caption | DDSCL_EXCLUSIVE |
Checked | true | ||
TCheckBox | CheckBox4 | Caption | DDSCL_FULLSCREEN |
Checked | true | ||
TCheckBox | CheckBox5 | Caption | DDSCL_NORMAL |
TCheckBox | CheckBox6 | Caption | DDSCL_NOWINDOWCHANGES |
Checked | true | ||
TButton | Button1 | Caption | 设备的枚举 |
TButton | Button2 | Caption | 创建 DirectDraw对象 |
Enabled | false | ||
TButton | Button3 | Caption | 获得 COM的IDIRECT2接口 |
Enabled | false | ||
TButton | Button4 | Caption | 设置协作级别 |
Enabled | false | ||
TButton | Button5 | Caption | DDraw2显示模式的枚举 |
Enabled | false | ||
TButton | Button6 | Caption | 设置 DDraw2的显示方式 |
Enabled | false |
2.1 dx1控件对象属性设置一览表DirectX5以上的SDK,且在C++Builder中已经将Project/Options/中标签页“Directories/Conditionals”上的“Include Path”和“Library Path”添加了DirectX5或以上SDK的路径。 #include "ddraw.h" 头文件。
表
确定已安装了
在窗口模块中包含
现在可以开始编写代码了,我们按照按钮的顺序逐个实现每个步骤的任务。
2.2.2.1 设备的枚举
DirectDraw提供了一个函数DirectDrawEnumerate 来实现设备枚举功能,此函数的调用格式为:
HRESULT DirectDrawEnumerate (LPDDENUMCALLBACK lpcallback LPVOID lpContext)
(1)参数lpcallback是一个回调函数的地址指针。所谓回调函数是程序员自己编写的函数,当枚举函数每枚举一个设备时就调用这个回调函数一次,并把当前枚举的设备有关信息通过参数传递给回调函数处理。dx1程序中,回调函数命名为EnumDeviceCallBack,负责将每次枚举出的设备的描述和名称加入到ComboBox1的列表中去,并把设备标识地址指针保存到一个lpDevices数组中以便创建DirectDraw对象时使用。
在
(2)参数lpContext是一用户定义的上下文变量,我们仅取值NULL就可以了。
(3)DirectDrawEnumerate为回调函数指针,该函数的格式为:
BOOL WINAPI EnumDeviceCallBack (GUID FAR *lpGUID,
LPSTR lpDevice,
LPSTR lpDeviceName,
LPVOID lpContex)lpGUID 为当前枚举设备标识地址指针;参数lpDevice 为设备描述的地址指针;参数lpDeviceName 为设备名称的地址指针;参数 lpContext 为上下文变量地址指针,这里我们不使用它。在dx1程序中,此回调函数负责将所枚举设备的名称和描述显示在ComboBox1中,并将设备标识地址保存到lpDevices数组中。为了简化程序,这里的lpDevices数组只采用了静态数组,最多允许保存10个元素。后面在保存显示模式枚举信息时使用的DisplayModes数组也是为了简化程序,在实际编程时可以考虑动态分配。 需要说明的是,回调函数应该是一个独立的函数,不要把它们声明为窗口类的成员函数(否则回调不能进行),而只要声明为普通函数就可以了。
2.2.2.2 创建DirectDraw对象DirectDraw编程之前,必需首先用DirectDrawCreate函数创建DirectDraw对象,并获得该对象的入口指针。该函数格式如下:
在进行
HRESULT DirectDrawCreate(GUID FAR *lpDD,
LPDIRECTDRAW FAR &lplpDD,
Iunknown FAR *p)
(1)参数lpDD为指定的设备标识指针(为NULL时是主设备),在dx示例程序中的第一个按钮“设备的枚举”采用静态数组保存枚举设备的标识指针,在第二个按钮创建DirectDraw对象时,可根据用户在ComboBox1中的选择,提供一个设备标识指针,以便对该设备创建DirectDraw对象。
(2)参数 lplpDD 为对象创建成功后的获得IditrctDraw接口指针。
(3)参数p未使用,直接为NULL。
2.2.2.3 获得COM的IDIRECT2接口DirectX采用了对象组件模型COM技术(这里不再介绍),因此如果我们需要使用DirectX5或以上版本提供的功能,就需要获得更高的IDirectDraw接口,例如:如果我们使用DirectX5开发包,就需要获得IDirectDraw2接口。HRESULT IdirectDraw::QueryInterface方法获得高版本接口:
由于
可以利用
lpDD->QueryInterface(IID_IDirectDraw2,
(LPVOID *)LPDIRECTDRAW2 &lpDD2)
- 参数
- lpDD2是为获得的IdDrectDraw2接口指针。
- IID_IDirectDraw2 是一个常量。
如果您需要使用更高版本的开发包,也可以用此方法获得IDirectDraw3或更高的接口。高版本接口获得后,就可以释放低版本的接口了,方法是:lpDD->Release();
2.2.2.4 设置协作级别DirectX游戏的朋友可能都领略过“全屏独占”和“窗口”两种图形模式,这就可以称为不同的协作级别,它控制应用程序与系统及其它应用程序的交互程度,因此我们必需用HRESULT IDIRECTDRAW2::SetCooperateLevel方法设置应用程序的协作级别。
玩过
LpDD2->SetCooperateLevel(HWND handle,DWORD dwFlag)
(1)参数handle是当前应用程序窗口的句柄,在C++Builder中,TForm类的Handle属性就是当前应用程序窗口的句柄。
(2)参数dwFlag是协作标志,可以为表2.2中定义之一或多个之和。
序号 | 标志 | 说明 |
( 1) | DDSCL_ALLOWMODEX | 允许使用 Mode X模式。必须与(3)、(4)组合使用 |
( 2) | DDSCL_ALLOWREBOOT | 当使用 (3)、(4)时允许用户进行热启动 |
( 3) | DDSCL_EXCLUSIVE | 使用独占方式,与 (4)一起使用 |
( 4) | DDSCL_FULLSCREEN | 全屏方式,与 (3)一起使用 |
( 5) | DDSCL_NORMAL | 以普通应用程序窗口方式运行 |
( 6) | DDSCL_NOWINDOWCHANGES | DirectDraw不能自动最小化或恢复窗口 |
2.2 dwFlag标志定义dx1示例程序中,默认设置为:
表
在我们的
DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN|DDSCL_NOWINDOWCHANGES
2.2.2.5 DDraw2显示模式的枚举
利用HRESULT IDIRECTDRAW2::EnumDisplayModes方法及其相应的回调函数可以列出系统显示设备所支持的显示方式。您开发的应用程序可以判定当前运行的计算机是否支持所需的显示方式,也可以提供用户选择显示方式的功能。
lpDD2->EnumDisplayModes(DWORD dwFlag,
LPDDSURFACEDESC lpDDSurfaceDesc,
LPVOID lpContext,
LPDDENUMMODESCALLBACK EnumDisplayModesCallBack
(1)参数dwFlag是标志参数,可以为DDEDM_REFRESHRATES(枚举不同刷新频率的刷新模式)和DDEDM_STANDARDVGAMODES(枚举模式中包含Mode13)两者之一或之和,在dx1程序中采用了后者。
(2)参数lpDDSurfaceDesc是一个过滤显示模式的结构,只要设置为NULL就可以获得全部显示模式的枚举,否则只获得满足指定模式的枚举。
LPDDSURFACEDESC是一个结构,其中包含了显示模式有关信息,主要有:
屏幕点阵 DWORD dwWidth、DWORD dwHeight;
色彩深度
屏幕刷新频率
(3)参数lpContex为用户上下文变量,设为NULL就可以了。
(4)参数EnumDisplayModesCallBack为回调函数指针,该回调函数规定有如下参数格式:
BOOL WINAPI EnumDisplayModesCallBack(LPDDSURFACEDESC lpDDSurfaceDesc
LPVOID lpContext)
其中:lpDDSurfaceDesc为当前所枚举显示模式的信息,lpContext为用户上下文变量。dx1程序中,此回调函数负责将每次回调的显示模式信息显示到ComboBox2中,并记录到一个结构数组DisplayModes中。
在
2.2.2.6 设置DDraw2的显示方式DDraw2的显示方式”按钮后,dx1将使用RESULT IdirectDraw2::SetDisplayMode方法改变显示方式。
每当用户选择了一个显示模式并点击“设置
lpDD2->SetDisplayModes(DWORD dwWidth,
DWORD dwHeight,
DWORD dwRGBCount,
DWORD dwRefreshRate,
DWORD dwFlags)
(1)参数dwWidth和dwHeght为显示指定方式的点阵。
(2)参数dwRGBCount为颜色深度,如:8(256色)、16(16位色)、24(真彩色)。
(3)参数dwRefreshRate为刷新频率,不关心时可以设置为0。
(4)参数dwFlags为使用DDSDM_STANDARDVGAMODE来设置Mode13。在dx1程序中始终设为0。IdirectDraw接口中,设置显示模式方法不支持dwRefreshRate和dwFlags这两个参数,所以,在有些资料中(包括C++Builder4的示例)均只介绍了DirectX3支持的IDirectDraw::SetDisplayMode(dwWidth,dwHeight,dwRGBCount)方法,请读者注意它们的区别。
需要注意的是在
2.2.2.7 退出dx1程序需要做的事
不要忘记释放lpDD2接口。LpDD2->Release();
2.2.3 dx1源程序
2.2.3.1 dx1主要文件的组成为:工程文件(dx1.bpr)、窗口文件(main.cpp)、头文件(main.h)。
2.2.3.2 头文件main.h
#ifndef mainH
#define mainH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
(略)
private: // User declarations
LPDIRECTDRAW FAR lplpDD; /* 获得的 DirectDraw 接口指针
LPDIRECTDRAW2 FAR lplpDD2; /* 获得的 DirectDraw2 接口指针
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
2.2.3.3 程序文件main.cpp
#include <vcl.h>
#include "d:/tools/dx5sdk/sdk/inc/ddraw.h"
#pragma hdrstop
#include "main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
LPGUID FAR lpDevices[10]; /* 保存枚举设备的标识指针
struct DisplayModes { DWORD Width,Height,Depth,Rate; } DisplayMode[100];
/* 保存显示设备支持的显示方式
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//设备枚举回调函数---------------------------------------------------------------------------
BOOL WINAPI EnumDeviceCallBack(GUID FAR *lpGUID,LPSTR lpDevice,
LPSTR lpDeviceName,
LPVOID lpContext)
{ static char i=0;
lpDevices[i]=lpGUID;
i++;
Form1->ComboBox1->Items->Add((AnsiString)lpDevice+"--"+(AnsiString)lpDeviceName);
if(i<10)
return(DDENUMRET_OK);
else
return(DDENUMRET_CANCEL);
}
//枚举设备---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ComboBox1->Clear();
if(FAILED(DirectDrawEnumerate(EnumDeviceCallBack,NULL)))
Edit1->Text="Enumerate Devices failed!";
else
Edit1->Text="Enumerate Devices OK!";
ComboBox1->ItemIndex=0;
Button1->Enabled=false;
Button2->Enabled=true;
}
//创建DirectDraw对象---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
LPGUID FAR lpD=lpDevices[ComboBox1->ItemIndex];
if(FAILED(DirectDrawCreate(lpD,&lplpDD,NULL)))
Edit1->Text="DirectDraw Create failed!";
else
{
Edit1->Text="DirectDraw Create OK!";
ComboBox1->Enabled=false;
Button2->Enabled=false;
Button3->Enabled=true;
}
}
//获得IDirectDraw2接口---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
if(FAILED(lplpDD->QueryInterface(IID_IDirectDraw2,(LPVOID *)&lplpDD2)))
Edit1->Text="Get IDriectDraw2 Interface Failed!";
else
{
Edit1->Text="Get IDriectDraw2 Interface OK!";
lplpDD->Release(); /* 释放IdirectDraw接口
Button3->Enabled=false;
Button4->Enabled=true;
}
}
//设置协作级别---------------------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
DWORD dwFlags=0;
if(CheckBox1->Checked) dwFlags=dwFlags|DDSCL_ALLOWMODEX;
if(CheckBox2->Checked) dwFlags=dwFlags|DDSCL_ALLOWREBOOT;
if(CheckBox3->Checked) dwFlags=dwFlags|DDSCL_EXCLUSIVE;
if(CheckBox4->Checked) dwFlags=dwFlags|DDSCL_FULLSCREEN;
if(CheckBox5->Checked) dwFlags=dwFlags|DDSCL_NORMAL;
if(CheckBox6->Checked) dwFlags=dwFlags|DDSCL_NOWINDOWCHANGES;
if(FAILED(lplpDD2->SetCooperativeLevel(Handle,dwFlags)))
Edit1->Text="Set set cooperative level Failed!";
else
{
Edit1->Text="Set cooperative level OK!";
GroupBox2->Enabled=false;
Button4->Enabled=false;
Button5->Enabled=true;
}
}
//枚举显示模式的回调函数---------------------------------------------------------------------------
BOOL WINAPI EnumDisplayModesCallBack(LPDDSURFACEDESC lpDesc,
LPVOID lpContext)
{
static int i=0;
char buff[256];
wsprintf(buff,"%dx%dx%dx%d",
lpDesc->dwWidth,
lpDesc->dwHeight,
lpDesc->ddpfPixelFormat.dwRGBBitCount,
lpDesc->dwRefreshRate);
Form1->ComboBox2->Items->Add(buff);
DisplayMode[i].Width=lpDesc->dwWidth;
DisplayMode[i].Height=lpDesc->dwHeight;
DisplayMode[i].Depth=lpDesc->ddpfPixelFormat.dwRGBBitCount;
DisplayMode[i].Rate=lpDesc->dwRefreshRate;
i++;
if(i<100)
return(DDENUMRET_OK);
else
return(DDENUMRET_CANCEL);
}
//枚举显示模式---------------------------------------------------------------------------
void __fastcall TForm1::Button5Click(TObject *Sender)
{
ComboBox2->Clear();
if(FAILED(lplpDD2->EnumDisplayModes(DDEDM_STANDARDVGAMODES,
NULL,
NULL,
(LPDDENUMMODESCALLBACK)EnumDisplayModesCallBack)))
Edit1->Text="Enumerate Display Modes failed!";
else
{
Edit1->Text="Enumerate Display Modes OK!";
ComboBox2->ItemIndex=0;
Button5->Enabled=false;
Button6->Enabled=true;
}
}
//设置显示模式---------------------------------------------------------------------------
void __fastcall TForm1::Button6Click(TObject *Sender)
{
if(ComboBox2->ItemIndex<0)
{
ShowMessage("请先在DDraw2下拉框中选择一种显示方式");
return;
}
if(FAILED(lplpDD2->SetDisplayMode(
DisplayMode[ComboBox2->ItemIndex].Width,
DisplayMode[ComboBox2->ItemIndex].Height,
DisplayMode[ComboBox2->ItemIndex].Depth,
DisplayMode[ComboBox2->ItemIndex].Rate,
0)))
Edit1->Text="Set DisplayMode failed!";
}
//退出dx1---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
if(lplpDD2) lplpDD2->Release();
}
2.3 装入并显示图形文件
为了简明地说明采用DirectDraw图形文件的显示技术,我们以示例程序dx2介绍图面、图形文件装入、图形缩放、图形在图面上显示等的初步概念和实现技术。
2.3.1 DirectDraw显示图形的技术DirectDraw必需首先拥有类似画布(canvas)的绘图空间,DirectDraw并不向在DOS下那样简单地将显示缓存作为绘画的对象,而是通过DirectDraw对象创建各种不同种类的“图面”(Suerface),图面上的内容可以被应用程序自由地拷贝、组合,生成千变万化的图形。
为了显示图象,
2.3.1.1图面分以下几种类型:
(1)主图面(Primary图面):即在屏幕上显示出来的图面,就是GDI用于绘制Windows用户界面的图面。每个DirectDraw对象只能有一个主图面,主图面的尺寸、位置和格式由系统当前的显示模式决定,不能改动。
(2)后台图面(Off-screen图面):此类图面不能被直接看到。一般来说,后台图面往往用于作为游戏精灵动画、背景图形等部件的存储缓冲区。后台图面的尺寸是可以调整的,且可以有多个后台图面,其大小根据实际情况调整,不要太大或太小。一种典型的例子是:有一个精灵的动画由4张128点阵图形组成,那么可以将后台图面定义为256点的方阵,将这个动画序列存储下来读者可能认为可以创建一个比主图面大的后台图面以便保存游戏背景,这样可以方便地实现滚屏,但是,DirectDraw限制后台图面的尺寸不能比主图面大,除非系统的显示卡支持。能否实现大的后台图面我们将在以后叙述。
(3)复合图面(Complex图面)和翻转链(Flipping Chain):这种图面主要用于生成平滑动画。有关技术待制作动画时介绍。
(4)覆盖图面(Overlay图面):这是一种由硬件支持的图面,DirectDraw不能仿真。有关技术在后面介绍。
DirectDraw可以把图面创建在显示内存或系统内存中,而显示内存又分为常规显示内存和AGP加速图形接口内存。由于显示内存容量是有限的,所以每个图面具体应该创建在哪部分存储区域中应该统筹规划,一般将使用频繁,需要硬件加速或实现功能的图面安排在显示内存。如果您不指定图面创建的位置,DirectDraw将首先在常规显示内存创建图面,当常规显示内存不够时,若系统支持AGP内存,则先使用AGP内存,最终使用系统内存。
2.3.1.2 图形文件的装入Windows的设备无关位图,我们可以考虑使用Windows的功能实现:
图形文件装入到图面并不象想象的那么简单,因为装入的图形的点阵可能与、图面的点阵不同,这就存在图形的缩放。另外,图形数据在内存中的移动、复制,也是需要处理的内容。对于
(1)采用LoadImage函数装入图形文件
(2)采用图面的GetDC方法获得图面与GDI兼容的设备上下文
(3)采用BitBlt函数将图形数据拷贝到图面中
有关GDI编程请参看有关Windows编程资料,这里读者只需要知道固定的用法就可以了。
2.3.1.3 图面的丢失
在DirectDraw应用程序被最小化、屏幕显示方式改变或用户按Alt+Tab键切换当前应用程序时,图面将会丢失,因此在重新回到DirectDraw应用程序中时,必需用Restore方法恢复图面。遗憾的是,虽然图面被恢复了,但其中图形数据却丢失了,需要重新绘制。
其中:参数