分享
 
 
 

DirectX游戏开发入门(二)

王朝c/c++·作者佚名  2006-01-06
窄屏简体版  字體: |||超大  

作者:wing         出处: C++学习资源网

八.作等级和显示模式

我不需要说太多。Windows编程设置协作级别你只需要调用IDirectDraw7::SetCooperativeLevel()函数;设置显示模式你就调用IDirectDraw7::SetDisplayMode()函数。就这么简单!先来看看协作级别。这就是函数原形:

HRESULT SetCooperativeLevel(

HWND hWnd,

DWORD dwFlags

);

返回的类型是HRESULT,你应该已经熟悉它了。对于所有的DirectX函数调用,你都可以用SUCCEEDED()和FAILED()宏检测调用的结果。以下是函数SetCooperativeLevel()的参数:

· HWND hWnd:很熟悉吧!传递主窗口的句柄给它,使Windows知道谁将使用它的资源。

· DWORD dwFlags:这个也很眼熟吧!每次我们看到dwFlags参数,几乎都有一个大的标志常量列表供我们选择,并且可以用“|”组合。这次也不会让你失望的哦!

1.SCL_ALLOWMODEX:启用Mode X 显示模式(如320×200,320×240或者320×400)。该标志只能用于DDSCL_EXCLUSIVE和DDSCL_FULLSCREEN模式。

2.SCL_ALLOWREBOOT:在独占模式中启用Ctrl+Alt+Del组合键功能。

3.SCL_EXCLUSIVE:请求独占模式,必须与DDSCL_FULLSCREEN同时使用。

4.SCL_FULLSCREEN:独占模式的拥有者负责整个主表面,GDI被忽略,必须与DDSCL_EXCLUSIVE同时使用。

5.SCL_NORMAL:表示常规的Windows应用程序,不能与DDSCL_ALLOWMODEX、DDSCL_EXCLUSEIVE或DDSCL_FULLSCREEN标志同时使用,在该模式下运行的应用程序不能进行页交换或者更改主调色板。

6.SCL_NOWINDOWCHANGES:防止DirectDraw最小化或恢复应用程序窗口。

还有几个标志常量我们暂时用不到,就不说了。由于我们要建立一个全屏的640×480×16的显示模式,所以我们得这样设置:

lpdd7->ooperativeLevel(hwnd, DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);

现在协作级别已经设置好了,让我们再看看改变显示模式的函数:

HRESULT SetDisplayMode(

DWORD dwWidth,

DWORD dwHeight,

DWORD dwBPP,

DWORD dwRefreshRate,

DWORD dwFlags

);

别忘了用宏去检测调用函数的成功或失败!大多数的参数同你料想的差不多:

· DWORD dwWidth,dwHeight:以象素为单位,新显示模式的尺寸。

· DWORD dwBPP:新显示模式的色彩深度。就是每一个象素有多少位字节。可以设置为8,16,24或32。警告:很多显示卡不支持24-bits。

· DWORD dwRefreshRate:屏幕的刷新频率。但你最好设置为0,使用默认的刷新频率。

· DWORD dwFlags:对不起,这次没有列表了^_^,唯一的选择是DDSDM_STANDARDVGAMODE,它把显示模式设置为0x13(DOS程序员的好朋友),取代了Mode X的320×200×8的模式。如果你还想使用其它的模式(你可能经常需要),没有问题,把它设置为0好了。

这些就是显示模式的设置,事先最好了解你的显示卡支持的显示模式,它们通常都支持640×480,800×600,1024×768等等,这些都是标准的模式。但是如果你非得设置成542×366的模式,你可能就会得到错误的反馈。科技在发展吗,什么都是可能的。让我们继续吧!

九.创建表面

这一次,我们需要比调用一个函数多一点点的东东。创建表面不是很难的,实际上,也是由一个单独的函数完成的,但是首先你要填充一个描述你所要创建的表面的结构。给你看这个结构之前,我只想告诉你,你不必填满所有的成员。^_^这就是它,DDSURFACEDESC2:

typedef struct _DDSURFACEDESC2 {

DWORD dwSize;

DWORD dwFlags;

DWORD dwHeight;

DWORD dwWidth;

union

{

LONG lPitch;

DWORD dwLinearSize;

} DUMMYUNIONNAMEN(1);

DWORD dwBackBufferCount;

union

{

DWORD dwMipMapCount;

DWORD dwRefreshRate;

} DUMMYUNIONNAMEN(2);

DWORD dwAlphaBitDepth;

DWORD dwReserved;

LPVOID lpSurface;

DDCOLORKEY ddckCKDestOverlay;

DDCOLORKEY ddckCKDestBlt;

DDCOLORKEY ddckCKSrcOverlay;

DDCOLORKEY ddckCKSrcBlt;

DDPIXELFORMAT ddpfPixelFormat;

DDSCAPS2 ddsCaps;

DWORD dwTextureStage;

} DDSURFACEDESC2, FAR *LPDDSURFACEDESC2;

坦率的说,编写DirectDraw的应用程序其实并不难。但是事情往往是这样,80%的工作只需要我们花费20%的时间就可以完成,而剩下的20%的工作却需要我们花费80%的时间来完成。DirectDraw编程比这还要严重,就笔者的看法,至少90%的工作只需要我们不到10%的时间来完成,而剩下的不到10%的工作却至少需要我们90%的时间!结构DDSURFACEDESC就是10%的一部分,它较为复杂,它嵌套了其它的结构。让我们看看这个怪物到底做了什么。我只说说重点的部分:

· DWORD dwSize:任何DirectX结构都有dwSize这个成员,表示结构的大小。有了它,当函数接收到指向这些结构的指针时,就可以测定结构的大小了。

· DWORD dwFlags:太好了,又有一大堆标志常量了^_^ !这些标志告诉接收函数哪些数据成员是有效的。要想使需要的数据成员有效,就必须传递相对应的标志常量给dwFlags,你当然可以用“|”组合它们。以下是列表:

◎ DDSD_ALL:所有的数据成员都有效。

◎ DDSD_ALPHABITDEPTH:表示数据成员dwAlphaBitDepth有效。

◎ DDSD_BACKBUFFERCOUNT:表示数据成员dwBackBufferCount有效。

◎ DDSD_CAPS:表示数据成员ddsCaps有效。

◎ DDSD_CKDESTBLT:表示数据成员ddckCKDestBlt有效。

◎ DDSD_CKDESTOVERLAY:表示数据成员ddckCKDestOverlay有效。

◎ DDSD_CKSRCBLT:表示数据成员ddckCKSrcBlt有效。

◎ DDSD_CKSRCOVERLAY:表示数据成员ddckCKSrcOverlay有效。

◎ DDSD_HEIGHT:表示数据成员dwHeight有效。

◎ DDSD_LINEARSIZE:表示数据成员dwLinearSize有效。

◎ DDSD_LPSURFACE:表示数据成员lpSurface有效。

◎ DDSD_MIPMAPCOUNT:表示数据成员dwMipMapCount有效。

◎ DDSD_PITCH:表示数据成员lPitch有效。

◎ DDSD_PIXELFORMAT:表示数据成员ddpfPixelFormat有效。

◎ DDSD_REFRESHRATE:表示数据成员dwRefreshRate有效。

◎ DDSD_TEXTURESTAGE:表示数据成员dwTextureStage有效。

◎ DDSD_WIDTH:表示数据成员dwWidth有效。

· DWORD dwheight,dwWidth:表示要创建表面的尺寸。以象素为单位。

· LONG lPitch:这个需要好好解释一下。lPitch表示从画面一行行首数据到下一行行首数据的距离,以字节为单位。例如,640×480×16,每一行有640个象素,每个象素需要两个字节装颜色的信息,所以pitch应该是1280个字节,对不对?可能有一些显示卡要多于1280,这每行多于的内存没有装置任何的图形数据,但是防备有些显示卡不能在线性内存模式显示图形,你还是把多于地放在那吧。这种情况很少发生,但你最好还是考虑在内。

· LPVOID lpSurface:指向表面内存开始地址的指针。不管你使用什么显示模式,你都可以用DirectDraw创建的线性地址模式操作表面象素。要想这样,你必须锁住表面,但这已经超出我们现在所学的了。

· DWORD dwBackBufferCount:后缓冲区的数目。以后我们会在提到它。

· DWORD ddckCKDestBlt,ddckCKSrcBlt:前者为描述位转换操作的目标颜色值,后者是源颜色值。我们将在以后的文章中具体介绍。

· DDPIXELFORMAT ddpfPixelFormat:这个结构包含了描述显示模式的象素格式标识符。以后会具体介绍,现在就不多说了。

· DDSCAPS2 ddsCaps:这是最后一个重要的结构。它是一个充满控制标志的结构。感谢菩萨,这是一个小结构,结构成员中只有一个很重要。让我们看一看:

typedef struct _DDSCAPS2{

DWORD dwCaps;

DWORD dwCaps2;

DWORD dwCaps3;

DWORD dwCaps4;

} DDSCAPS2, FAR* LPDDSCAPS2;

最重要的就是dwCaps了。第三个和第四个成员从来没有用过,是为将来准备的。总之,dwCaps可以使用如下的值,当然可以用“|”组合。以下是最为常用的,其它的你若有兴趣,自己查好了。

· DDSCAPS_BACKBUFFER:指出这个表面是需要表面切换结构的后缓冲区。

· DDSCAPS_COMPLEX:是一个复杂表面,由主表面,一个或多个粘贴表面组成,通常是为了页面切换。

· DDSCAPS_FLIP:指出这个表面是表面切换结构的一部分。前缓冲区紧跟着一个或多个建立好的后缓冲区。

· DDSCAPS_FRONTBUFFER:是关于表面切换结构的前缓冲区。

· DDSCAPS_LOCALVIDMEM:指出在true、local video memory【不知怎么翻译】中建立表面。如果使用该标志,必须也同时使用DDSCAPS_VIDEOMEMORY标志,但不能同DDSCAPS_NONLOCALVIDMEM标志同时使用。

· DDSCAPS_MODEX:指出这个表面是Mode X模式(320×200或320×240)的表面。

· DDSCAPS_NONLOCALVIDMEM:指出表面建立在non-local video memory【不知怎么翻译】中。如果定义该标志,必须也同时使用DDSCAPS_VIDEOMEMORY标志。但是不能同DDSCAPS_LOCALVIDMEM同时使用。

· DSCAPS_OFFSCREENPLAIN:这是一个简单的离屏表面。

· DDSCAPS_OWNDC:这个表面将具有长周期的设备上下文。

· DDSCAPS_PRIMARYSURFACE:主表面。

· DDSCAPS_STANDARDVGAMODE:是标准的VGA模式表面。不能同DDSCAPS_MODEX同用。

· DDSCAPS_SYSTEMMEMORY:建立在系统内存里的表面。

· DDSCAPS_VIDEOMEMORY:这个表面建立在显示内存里。

天啊,终于介绍完了这个结构。现在我们准备建立表面吧。第一步当然是填充DDSURFACEDESC2结构。Microsoft推荐大家当你使用一个结构之前,你应该把它先初始化为0。有鉴于此,我经常使用这样一个宏:

#define INIT_DXSTRUCT(dxs) { ZeroMemory(&dxs, sizeof(dxs)); dds.dwSize = sizeof(dxs); }

它可以用于任何一个DirectX结构,因为它们都有dwSize成员,所以这是很方便的。如果你以前从来没有看过ZeroMemory()这个函数,它只是由函数memset()扩充来的宏,在Windows的头文件中用#define定义好了,所以你不需要用#indlude添加任何东西就可以用它。

初始化了结构之后,你得根据实际情况设置表面了。对于主表面,你需要ddsCaps和dwBackBufferCount,对于离屏缓冲区,你也需要dwHeight和dwWidth,但不需要dwBackBufferCount。对于一些表面你可能还需要颜色值,但我们不把它弄得太复杂了。填充完结构后,你需要调用IDirectDraw7::CreateSurface()函数,原形是这样:

HRESULT CreateSurface(

LPDDSURFACEDESC2 lpDDSurfaceDesc,

LPDIRECTDRAWSURFACE7 FAR *lplpDDSurface,

IUnknown FAR *pUnkOuter

);

这些参数的意义可能你也能猜出个大概了,毕竟我们已经习惯了这些疯狂的DirectX素材:

· LPDDSURFACEDESC2 lpDDSurfaceDesc:表示要创建表面的描述结构。当然是个指针了。

· LPDIRECTDRAWSURFACE7 FAR *lplpDDSurface:为指向表面指针的指针。此参数在此函数调用成功后填充。为什么要使用指向指针的指针呢?这是因为我们的任务就是分配一片表面内存区域,这样只能使用指针(表面指针)作为操作该表面内存区域的标志,返回值应该是该指针值而不是该指针所表示的内容(具体的表面)。当我们使用函数参数传递该值时,又只能使用指针(即指针的指针)修改表面指针的内容而不是表面指针所代表的表面内存区域。(理论复杂,使用简单,不明白不要太在意)

· IUnknown FAR *pUnkOuter:看过这个模式吧,无论何时调用pUnkOuter,都是关于COM应用的,我们不想在这儿浪费时间,设置为NULL好了。

来个实例吧,你会明白一切的。希望在实例里,我们要一个主表面和一个紧随主表面的后缓冲区,还有一个离屏缓冲区用来放置位图。假设我们已经得到了IDirectDraw7接口指针,代码如下:

DDSURFACEDESC2 ddsd; // surface description structure

LPDIRECTDRAWSURFACE7 lpddsPrimary = NULL; // primary surface

// set up primary drawing surface

INIT_DXSTRUCT(ddsd); // initialize ddsd

ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; // valid flags

ddsd.dwBackBufferCount = 1; // one back buffer

ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | // primary surface

DDSCAPS_COMPLEX | // back buffer is chained

DDSCAPS_FLIP | // allow page flipping

DDSCAPS_VIDEOMEMORY; // create in video memory

// create primary surface

if (FAILED(lpdd7->CreateSurface(&ddsd, &lpddsPrimary, NULL)))

{

// error-handling code here

}

你当然还可以用CreateSurface()函数创建复杂表面,只是使用DDSCAPS_COMPLEX标志罢了。由于刚才我们创建了一个后缓冲区,所以我们还得必须得到指向它的指针。那就得调用IDirectDrawSurface7::GetAttachedSurface()函数了:

HRESULT GetAttachedSurface(

LPDDSCAPS2 lpDDSCaps,

LPDIRECTDRAWSURFACE7 FAR *lplpDDAttachedSurface

);

参数很简单啦:

· LPDDSCAPS2 lpDDSCaps:指向创建后缓冲区表面的DDSCAPS2结构。你就可以使用DDSCAPS2结构中相应的成员了。

· LPDIRECTDRAWSURFACE7 FAR *lplpDDAttachedSurface:后缓冲区表面指针的地址。简单理解为声明一个指针,然后把指针的地址传递给该参数。

看看下面的代码就明白了:

LPDIRECTDRAWSURFACE7 lpddsBack = NULL; // back buffer

// get the attached surface

ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;

if (FAILED(lpddsPrimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsBack)))

{

// error-handling code here

}

感觉有点儿入门了吗?如果你很难记住以上步骤,那么你是一个正常人,反复运用就会熟悉了。没有人能记住所有的庞大的结构成员和标志常量,这就是我们手边总是准备程序员参考手册或者拥有MSDN Library CD的原因了^_^ !OK,最后一步是建立离屏缓冲区。假设它的宽400,高300,(单位是象素)代码如下:

LPDIRECTDRAWSURFACE7 lpddsOffscreen = NULL; // offscreen buffer

// set up offscreen surface

INIT_DXSTRUCT(ddsd); // initialize ddsd

ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; // valid flags

ddsd.dwWidth = 400; // set width

ddsd.dwHeight = 300; // set height

ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | // offscreen buffer

DDSCAPS_VIDEOMEMORY; // video memory

// create offscreen buffer

if (FAILED(lpdd7->CreateSurface(&ddsd, &lpddsOffscreen, NULL)))

{

// error-handling code here

}

表面这些学问就介绍到这儿,还有好多东西要介绍,可是唯一的问题是文章太长了,我们先暂停吧。你现在可以建立一个最基本的,但是什么也不显示的表面。

千万记住了,你使用的每一个DirectDraw接口和所有的表面,用完后一定要释放(Release)它们啊!切记、切记!!!!!!!

十.总结

很抱歉在这里中断了,尤其是你还没有看到显示的图形,但关于图形有太多的内容了,不是三言两语就能说清除的,所以放到下两章。下一章讨论DirectDraw中的调色板和象素,再下下一章讨论DirectDraw中的位图。精彩在后面哦!请耐心期待。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有