DirectDraw 游戏编程基础(3)

本文介绍了DirectDraw在DirectX中的应用实例,详细解析了DDEX2和DDEX3例程中如何实现表面的创建、位图加载及表面间的切换。通过具体代码展示了位图动画效果的实现方法。

 例一的扩展(DDEX2和DDEX3)

DDEX1包含了一个最基本的DirectDraw的实现方法。它生成了DirectDraw和DirectDrawSurface对象,同时也生成了一个主表面(Surface)和与之相关的后台缓冲区,并在后台缓冲区打印文本,并可以在表面(Surface)之间进行切换。

在DirectX 3 SDK(DDEX2)中的第二个DirectDraw 例程扩展了关于DDEX1应用程序。DDEX2包括将一个位图文件载入到后台缓冲区的函数。

第三个DirectDraw 例程将这一函数进一步地扩展了。除了主表面(Surface)和后台缓冲区之外,DDEX3还生成了两个隐屏表面(Surface),并且在每一个隐屏表面(Surface)之中都载入了一个位图文件。然后,DDEX3使用IDirectDrawSurface::BltFast方法,将一个隐屏的内容复制到后台缓冲区中。之后,弹出这些缓冲区,并且将下一个隐屏表面(Surface)的内容复制到后台缓冲区。

以下的部分将更详细地检查这一新的函数。

在一个表面(Surface)上载入一个位图(Bitmap)

就与DDEX1一样,dolnit是DDEX2应用程序的初始化函数。虽然,在DDEX2中,DirectDraw的初始化方式表面上与在 DDEX1中的DirectDraw的初始化方式不太一样,但它们的实质是一样的。这一过程如下列的程序代码所示:

LPddPal = DDLoadPalette(LpDD, szBackground);

if (LpddPal == NULL)

goto error;

ddrval = LpDDSprimary->SetPalette(LpDDPal);

if( ddral != DD_OK )

goto error;

// Load a bitmap into the back buffer。

ddrval = DDReLoadBitmap(LpDDSBack, szBackground);

if( ddrval != DD_OK )

goto error;

生成调色板

这个程序代码的第一行是:从DDLoadPalette函数返回一个值。如果你想知道在哪能找到DDLoadPalette,你可以在/DXSDK|SAMPLES|MISC目录中的Ddutil.cpp文件中找到它。你会发现,在DirectX 3 SDk的大部分DirectDraw例程中都使用了Ddutil.cpp文件。最为关键的是:该文件上包括了能从文件中或是从资源中载入位图和调色板的函数。这些函数的代码并非一遍遍地重复出现在例程文件中,而且被放置在能被重复使用的同一文件之中。

注意:如果你正在使用MS Developer Studio(微软开发工作室)编辑DDEX2和用DirectX 3 SDK提供的其它工具,你必须把Ddutil.cpp文件插入到DDEXx文件工作区的文件表中。重申一遍:在工作区中必须包括Ddutil.cpp:

1. 在插入(insert)菜单上,单击Files进入Projeects。

2. 单击Browse.

3. 单击DXSDK/SDK/SAMPLES/MISC/目录。

4. 单击Ddutil.cpp

5. 单击ADD

对于DDEX2来说,从Back.bmp文件中,DDLoadPalette创建了一个DirectDraew对象。DDLoadPalette函数实际上是来检查用以产生调色板的一个文件或资源是否存在。如果不存在的话,该函数就创建一个缺省的调色板,对于DDEX2 来说,DDLoadPalette函数从文件中提取调色板信息,并通过ape指针将其存储在一个指定的结构中,然后它生成DirectDrawPalette 对象。如下面的代码所示:

pdd->CreatePalette(DDPCAPS_8BIT, ape, &ddpal, NULL);

return ddpal;


当IDirectDraw::Createpalette方法返回后,ddpal参数将指向DirectDrawPalette对象,其中,对象DirectDrawPalette是从DDLoadPalettede的调用返回的。

ape参数是一个指针,它可以包括2,4,16或256个入口,呈直线分布。这些入口的数目由IDirctDraw::CreatePalette参数决定。在这种情况下,dwFLags参数被设置为DDPCAPS_8BIt,它表示:在这个结构中有256个入口。每个入口包括4位(一位红通道,一位绿通道,一位兰通道和一个标志位)。

设置调色板

在生成调色板之后,你要通过调用IDirectDrawSurface::SetPalette方法,将DirectDrawPalette对象的指针转到主表面(Surface)上,如下列代码所示:

ddrval = LpDDSPrimary->SetPalette(LpDDPal);

if( ddrval != DD_Ok )

// SetPalette failed

一旦你已经调用了IdirectDrawSurface::SetPalette,DirectDrawPalette对象就被嵌入到DirectDrawSurface对象中了。不论何时你需要改变这一调色板,你要作的就是生成一个新的调色板并重新设置该调色板。(这就如例程中所做的一样。然而,也有其它的改变调色板的方式。我们可以在其它例程中看到)。

在后台缓冲区中载入一个位图文件

一旦DirectDrawPalette对象被嵌入到DirectDrawSurface对象之中,DDEX2就将Back.bmp bitmap载入到后台缓冲区中。使用下例的程序代码可实现该过程:

// Load a bitmap into the back buffer.

ddrval = DDReLoadBitmap(LpDDSBack, szBackground);

if( ddrval != DD_Ok )

// Load failed

DDReLoadBitmap是出现在Ddutil.cpp中的另一个函数。它从一个文件或资源中将一个位图文件载入到一个已经存在的DirectDraw表面(Surface)之中。(就象在DDEX5中那样,你可以使用DDLoadBitmap创造一个表面(Surface)并且将位图载入那个表面(Surface))。对于DDEX2来说,DDReLoadBitmap把szBackground指向的Back.bmp载入到ipDDSBack指向的后台缓冲区,DDReLoadBitmap调用DDCopyBitmap函数,将文件复制到后台缓冲区中,并且将缓冲区扩展到适当的。

DDCopyBitmap函数将位图复制到内存之中,然而利用GetObject函数得到位图的大小。DDCopyBitmap然后使用下列的代码得到后台缓冲区的大小(它可以放置位图):

//

// get size of surface

//

ddsd.dwSize = sizeof(ddsd);

ddsd.dwFlags = DDSD_HEIGHT DDSD_WIDTH;

pdds->GetSurfaceDesc(&ddsd);

ddsd是指向DDSRFACEDESC结构的一个指针。该结构存储了DirectDraw表面(Surface)的当前描述。在这种情况下,我们需要注意的是:DDSURFACEDESC的成员描述这个表面(Surface)的高度和宽度,分别表示为:DDSD_HEIGHT和 DDSD_WIDTH。调用IDirectDrawSurface::GetSurfaceDesc方法,把适当的值来载入到这个结构。对于DDEX2来说,这些值将是:高480和宽640。

DDCopyBitmap函数锁定表面(Surface)并将位图文件复制到后台缓冲区,使用StretchBit函数延伸或压缩后台缓冲区到可适用的大小。表示如下:

if ((hr = pdds->GetDC(&hdc)) == DD_OK)

{

StretchBlt(hdc, 0,0,ddsd.dwWidth, ddsd.dwHeight, hdcImage,x, y, dx, dy, SRCCOPY);

pdds->ReleaseDC(hdc);

}

弹出表面(Surface)

在DDEX2例程中的弹出表面(Surface)操作本质上与在DDEX1例程中的弹出操作是同样的过程。但是在表面(Surface)丢失的情况下,你必须通过调用DDReLoadBitmap函数,在表面(Surface)恢复之后,,将bitmap再次载入到后台缓冲区中。

从一个隐屏表面(Surface)按位隔行拷贝

DDEX2是在后台缓冲区中取出和放入位图的,然后在后台缓冲区和主缓冲区之间切换。这并不是一个展示位图的很实际的方法。DDEX3扩展了DDEX2的功能,它包括了两个隐屏缓冲区,且在其内部存放有两个位图(一个对应于偶行屏幕,另一个对应于奇行屏幕)。DDEX3把一个屏幕按位隔行拷贝到后台缓冲区中,再把另外一个屏幕按位隔行拷贝到另一个后台缓冲区中,然后弹出表面(Surface)。

生成隐屏表面(Surface)

下列的代码在DDEX3 中加到dolnit 函数可生成两个隐屏 缓冲区:

// Create an offscreen bitmap.

ddsd.dwFlags = DDSD_CAPS DDSD_HEIGHT DDSD_WIDTH;

ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;

ddsd.dwHeight = 480;

ddsd.dwWidth = 640;

ddrval = lpDD->CreateSurface( &ddsd,&lpm DDSOne,NULL);

if (ddrval != DD_OK)

{

return initFail(hwnd);

}

//Create another offscreen bitmap.

ddrval = lpDD->CreateSurface( &ddsd,&lpm DDSTwo,NULL);

if (ddrval != DD_OK)

{

return initFail(hwnd);

}

如代码中所示,dwFlags成员设定了应用程序将使用DDSAPS结构,并且设置缓冲区的高度和宽度。表面(Surface)是一个平面式隐屏缓冲区,就如同通过设置在DDSCAPS结构中的DDSCAPS_OFFSCREEN标志所表示的一样。在DDSURFACEDESc结构中,高度和宽度被分别设置为480和640。通过使用IDirectDraw::CreateSurface方法,表面(Surface)就这样被生成了。

因为两个隐屏缓冲区有着同样的大小,故生成第二个缓冲区的唯一要求就是再运行IDirectDraw::CreateSurface(当然,要用不同的指针名字)。

通过在DDSCAPS结构中,或是设置DDSCAPS_SYSTEMMEMORY,或是设置DDSCAP_VIDEOMEMORY的容量,你可以将该:隐屏缓冲区或是放置在系统内存中或是显存中。通过将位图存盘在显存中,你可以增加隐屏表面(Surface)和缓冲区之间切换的速度。当我们开始讨论位图动画时,速度将变得更加重要。但是,此时你应当注意:如果你仅为隐屏缓冲区设置DDScAPS_VIDEOMEMORY,而没有足够的显存来保存整个位图文件,那么,当你试图创建表面(Surface)时,就会返回一个DDERR_OUTOFVIDEOMEMORY的错误值。


将位图文件载入后台缓冲区

在两个隐屏表面(Surface)生成后,DDEX#使用INITSURFACES函数,从Frnt.bmp文件中将位图文件载入到表面(Surface)中。InitSurfaces函数使用Ddutil.cpp中的DDCopyBitmap载入这两个位图文件,如下列代码所示:

// Load our bitmap resource.

hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL),szBitmap,

IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);


if (hbm == NULL)

return FALSE;


DDCopyBitmap(lpDDSone,hbm,0,0,640,480);

DDCopyBitmap(lpDDSTwo,hbm,480,640,480);

DeleteObject(hbm);

return TRUE;

如果你在MS Paint(微软画笔)或是另一个绘画程序中看到Frnt.bmp文件,你可以看到位图文件是由两个屏幕组成的(其中一个在另一个的上部)。DDCopyBitmap函数在屏幕相汇点上将位图文件一分为二,并将第一份位图文件载入第一个隐屏表面(Surface)(IPDDSOne)中,同时将第二份位图载入第二个隐屏表面(Surface)(IPDDSTwo)中。

将隐屏表面(Surface)按位隔行拷贝到后台缓冲区

WM TIMER包含了写表面(Surface)和弹出表面(Surface)的代码。在DDEX3的情况下,它包含下列的代码,用来选择适当的隐屏表面(Surface),并将它按位隔行拷贝到后台缓冲区中。

rcRECT.LEFT =0;

RCRECT.TOP =0;

RCRECT.right =640;

rcRect.bottom =480;

if(phase)

{

pdds = lpDDSTwo;

phase = 0;

}

else

{

pdds = lpDDSOne;

phase = 1;

}

while(1)

{

ddrval =lpDDSBack->BltFast(0,0,pdds,&rcRect,FALSE);

if(ddrval == DD_OK)

{

break;

}


"phase"决定了将哪一个隐屏表面(Surface)按位隔行拷贝到后台缓冲区中。然后,IDirectDrawSurface::BltFAst方法被调用,并将已经被选择好的隐屏表面(Surface)按位隔行拷贝在后台缓冲区中,开始位置为(0,0),它位于屏幕的左上角。参数rcRect指向结构Rect,它定义了隐屏表面(Surface)的左上角和右下角。最后的参数被设置为FALSE(或0),这就表明了没有专门的转移标志以备使用。

在这里,我很想补充说明的是:在何种情况下应该选择IDirectDrawSurface::Blt方法,在何种情况下应该选择IDirectDrawSurface::BltFast方法。如果你正在从一个隐屏缓冲区中进行一次按位隔行拷贝,你应当使用IDirectDrawSurface::BltFast。如果你的系统显存中是使用硬件进行按位隔行拷贝,你虽然不会真正提高拷贝的速度,但是,它会节省系统模拟硬件时间,从而使整个按位隔行拷贝时间缩短约10%。因此,我推荐读者使用IDirectDrawSurface::BltFast进行所有的显示操作(从显存按位隔行拷贝到显存中)。如果你正在从系统内存中按位隔行拷贝,或者要求专门的硬件标志位,这样的话,你就必须使用IDirectDrawSurface::Blt。

一旦隐屏表面(Surface)被载入后台缓冲区中,后台缓冲区和主表面(Surface)就如同前边的例程中所显示的一样被弹出。

xxdd.net购物系统是一套自选网上商城精美模版,自主商品管理,自行网店经营的网上商城平台,系统具有强大的商品管理、购物车、订单统计、会员管理等功能,同时拥有灵活多变的商品管理、新闻管理等功能,功能强劲的后台管理界面,无需登录FTP,通过IE浏览器即可管理整个网站。xxdd.net企业购物平台经多方面权威调查和研究为您精心开发了很多特色实用功能。使商品展示、管理、服务全面升级。xxdd.net企业购物平台为您提供了多款专业美观的店面样式、俱备完整的购物网站功能、结构简单、容易使用、并设有促销广告和店标自定义功能。适合于企业及个人经营管理,操作简单,您不需懂得太多的计算机知识,也无需制作复杂网页,您只需订购这套系统,把网店代码及模板文件,通过FTP远程上传到您的网络空间,就完成网上商店初步设置。随后,登录到后台,点点鼠标,在线设置轻松设置各项功能及添加您要出售的商品,您的网上商店就这样轻松建设成功了。不同版本可以满足从小流量到大流量,从个人到企业各方面应用的要求,为你提供一个全新、快速和优秀的网上销售解决方案。 一、功能列表 系统特点    (1)用户无需考虑系统的安装维护;    (2)美观、友好的展示铺面;      (3)设计中应用了多种网络安全技术;      (4)顾客可以方便的查询并订购商品;      (5)用户可以方便的定义各种商品信息;      (6)系统选用强大的数据库保存各类信息;    (7)系统支持多种浏览器;    (8)功能模块清晰实用强大;    (9)系统有着良好的扩充性和升级性; 前台功能介绍   (1) 会员注册及登录模块 为了确保交易信息的有效性和网站功能拓展,购物网站需要以会员机制运作,浏览者必须成为会员,才能够在网站中购物。该模块通过与浏览者的交互,记录浏览者的基本信息,通过后台审核确定其信息的有效性。   (2) 商品分类展示模块 商品分门别类、分层次展示不仅方便浏览者迅速找到自己的目标商品,同时增强了网站的亲和力。该模块是浏览者与网站接触最频繁的部分,要突出用户性和流程性。   (3) 商品信息检索模块 信息检索是网站提供给消费者最基本的商品搜索工具,该功能可以根据商品特点细化,充分照顾浏览者的使用方式。   (4) 购物车模块 是一个人性化的工具,浏览者对于中意的商品,在购买前临时存放在购物车中,并可以随时增减购物车中的商品种类和数量,以提高购物效率。   (5) 生成订单模块 浏览者购物完毕,系统会引导其进行结账,在选择好结账方式后,系统会自动生成并交给客户一个唯一的订单号。   (6) 订单查询模块 客户可以根据自己的订单号,通过专门的入口跟踪订单的处理情况。   (7)商品排行模块 最新商品,销售排行,关注排行,推荐商品,特价商品,最新定购等,让客户一幕了然,非常方便的查看兴趣产品   (8)反馈留言模块 完善的客服功能,客户可通过反馈表或网上调查表中提出对产品的看法建议等,   (9)短信模块 站内短信功能,可定期向相关会员发送商业信息,定期向相关会员发送商业信息,发掘潜在客户。   (10) 商品品牌展示模块 商品分门别类、分层次展示不仅方便浏览者迅速找到自己的目标商品,同时增强了网站的亲和力。该模块是浏览者与网站接触最频繁的部分,要突出用户性和流程性。   (11) 商品类别管理模块 我们在网站中所看到的商品分类不是固定的,后台管理员可以根据自己商品种类的变化莱对目前的分类进行编辑修改,比如是否需要增加产品大类?是否需要删除某个产品小类?   (12) 商品管理模块 如果说商品类别管理确定了网上商品的结构框架,那么本模块则为这些框架增加内容,将商品按照预定的类别进行归类编辑,比如某类产品是否新到商品需要添加?某些商品已经过季,是否需要撤掉?   (13) 会员管理模块 该模块负责前台注册会员的信息审核,对于有效信息,网站准许其成为会员并购物;否则可以进行清理。同时该模块存储了会员的信息及购物纪录,是一个非常有价值的客户信息库。   (14) 定单管理模块 跟踪并记录订单情况,包括新订单提醒、订单处理纪录、订单查询及阶段性订单统计等功能。   (15) 新闻管理模块 该模块主要是管理前台网站发布的各种站内外的新闻、产品信息等。   (16)更多模块不一一介绍了,具体请看演示,感谢您的支持! 后台功能介绍 商品管理 /增加商品 /修改商品 /脱销商品 用户管理 /前台用户 /后台用户 /VIP 资格 /推荐用户 /会员等级 订单管理 /全部订单 /未作处理 /款已划出 /款已收到 /货已发出 /货已收到 分类管理 /大类管理 /小类管理 /类别转移 /添加品牌 /品牌管理 信息管理 /添加新闻 /编辑新闻 /公告设置 /查看反馈 /添加投票 /管理投票 /投票代码 /商品评论 /用户广播 常规设置 /初始设置 /高级设置 /基本信息 /付款方式 /支付方式 编辑管理 /样式管理 /获取代码 /上传管理 广告管理 /广告设置 /文字连接 /图片连接 其它管理 /登陆日志 /空间探测 /空间查看 数据管理 /备份数据 /还原数据 /压缩数据 全面的安全性处理 (1) 数据库防下载处理 (2) CONN防止暴库处理 (3) 防止跨站脚本攻击 (4) SQL注入式攻击防范 (5) 禁止脱机浏览工具浏览 (6) 后台登陆采用验证码验证 (7) 会员密码采用MD5方式加密 (8) 防范未知IP访问及软件攻击 (9) 管理员密码采用MD5方式加密 (10) 过滤sql注入代码及HTML代码防护 (11) 进行数据来源安全性监测,跨站脚本防范 (12) 管理员登陆日至记录,非法操作代码日至记录
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值