分享
 
 
 

DirectX学习手记(二)

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

DirectX学习手记(二)

happyfire 2002/8/11

此回说说怎样用DirectDraw向表面上贴图,包括创建离屏表面,设置调色板,载入位图到表面,透明色,页面丢失等。

二. 用DirectDraw贴图

先让我们回忆一下上一回的内容。为了初始化DirectDraw我们首先创建了一个DirectDraw对象,然后

设置了协作模式(全屏+独占),设置显示模式,然后创建主表面,提取后台缓冲表面指针。至此可以在后台

表面上进行操作,然后flip到前台显示出来。最后程序结束前释放所有的directdraw对象。好了,现在说说怎

样向后台表面贴图,即让屏幕显示图片。

第一步:创建离屏表面

离屏表面是你永远看不到的表面(所谓离屏),它通常被用来存放位图。通常的做法是把离屏表面

上的位图用Blt的方法贴到后台表面,后台表面再flip为前台表面。看看它的创建方法:

//声明用来存放图像的离屏表面(声明为全局变量)

LPDIRECTDRAWSURFACE lpDDSPic ;

//在InitDDraw()中创建保存图像的离屏表面

ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH ;

ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN ;

ddsd.dwHeight = 480 ;

ddsd.dwWidth = 640 ;

if ( lpDD->CreateSurface(&ddsd,&lpDDSPic,NULL)!=DD_OK )

return FALSE ;

首先要声明一个表面,然后填充DDSURFACEDESC表面描述结构体。dwFlags填DDSD_CAPS表示ddsCaps域有效,

DDSD_HEIGHT和DDSD_WIDTH表示要指定页面的大小。ddsCaps.dwCaps填DDSCAPS_OFFSCREENPLAIN表示创建

的是离屏表面。dwHeight和dwWidth填页面的大小,单位是像素。然后就可以用DirectDraw对象的CreateSurface

方法创建lpDDSPic了。注意CreateSurface的第三个参数必须填NULL,该参数将允许与今后的 COM 集合特性相兼容。

整个创建过程和创建主表面非常相似,只是ddsd的填充不同。这里稍微谈一下离屏表面的大小问题。

在 DirectX 5.0 以前的版本中,离屏表面的宽度的最大值不能超出于主表面的宽度.而从 DirectX 5.0 版开始,你

可以创建任何宽度的离屏页面,只要你的显存和内存足够大.缺省情况下,离屏表面是被创建在显存中的,但如果

显存不够用,它就会被置于内存中,当然你可以指明只在显存中创建表面(可在 DDSCAPS 结构的 dwCaps 成员中

包含进 DDSCAPS_SYSTEMMEMORY 或 DDSCAPS_VIDEOMEMORY 标志符,以明确的表明你希望将表面置于何处),如果

这样的话,当表面太大而超出显存的容纳范围时,就会创建失败。

另外,以上面的方法创建的离屏表面的像素格式(可以简单理解为表示几位的颜色)是和主表面相同的,当然

也可以创建一个像素格式与主表面不同的离屏表面.然而,在这种情况下,该离屏表面将被限制于系统内存中。具体的

做法有点烦,各位感兴趣的可以查一下手册,:) 。

第二步:读入调色板并设置上

我们的主表面被设置为基于调色板(8位色深度)。一个基于调色板的表面是一些数字的集合,

其中的每一个数字代表一个像素.每一个数字的值都对应于一个色彩表(color table)中的项,这个表告诉 DirectDraw

对这个像素使用什么样的颜色. 这个表就是调色板(Palette)。使用调色板是为了尽量降低对显存的需求,它用一个

颜色索引(Color Index)来代表各个像素点的颜色,而不是直接用红,绿,蓝三基色的亮度值来确定每个像素点的颜色。

调色板包含了若干颜色索引和该索引所对应的真实颜色值。调色板的颜色索引主要采用4或8两种位深度。要在表面上

正常显示图像就必须将表面的调色板设置为该图像的调色板。如下面的代码片断:

//先声明调色板对象(其实是指针类型,就这么说吧,上面提到的各个对象都是这样的)

LPDIRECTDRAWPALETTE lpDDPal ;

//从位图设置调色板

lpDDPal = DDLoadPalette(lpDD, szBitmap);

if (lpDDPal)

lpDDSPrimary->SetPalette(lpDDPal);

else

return FALSE ;

DDLoadPalette是DDutil.cpp里面的函数,happyfire也不大懂,作为初学者拿来用就是了。

第三步:将位图文件读入已创建好的离屏表面中

这一步我们用DirectDraw APIs里面的一个函数DDLoadBitmap来实现,具体用法是:

lpDDSPic = DDLoadBitmap ( lpDD, szBitmap, 0, 0 ) ; //szBitmap是位图文件名,例如".\\pic\\background.bmp"

使用了DDLoadBitmap这一步变得非常简单,但是要把Ddutil.cpp和Ddutil.h加到工程中才行。你可以看看

Ddutil.cpp中该函数的实现,它调用了Windows的API LoadImage,并且用作为参数传进来的directdraw对象

创建了一个表面并返回了它的指针。

第四步:使用blit的方法,将离屏表面上的图片传送到后台缓冲

何谓blit?Bit block transfer(位块传送),即将内存中的数据块从一处传送到另一处。DirectDraw

提供了两个方法,Blt和BltFast。Blt功能强大,BltFast速度较快。这里我们先不讨论Blt,只用BltFast。看如何实现:

RECT rcRect ;

rcRect.left= 0;

rcRect.top= 0 ;

rcRect.right= 640;

rcRect.bottom=480;

lpddsBack->BltFast( 0, 0, lpddsPic, &rcRect, DDBLTFAST_SRCCOLORKEY|DDBLTFAST_WAIT);

RECT是windows的矩形结构(所以要包含windows.h),rcRect这个矩形用来确定源表面(这里是离屏表面)上的哪

一块区域要被传送到目标表面(这里是后台缓冲表面)上去。BltFast的前两个参数是两个DWORD值,表示目标表面

上的一个点的坐标x和y,它决定了传送过去的图形在目标表面上所处的位置。你可以改变x,y和rcRect看看效果。

最后一个参数是传送类型:

DDBLTFAST_DESTCOLORKEY

指定进行一次带透明的位块传送,使用目标表面的关键色(color key)。

DDBLTFAST_NOCOLORKEY

指定进行一次普通的复制,不带透明成分。

DDBLTFAST_SRCCOLORKEY

指定进行一次带透明的位块传送,使用源表面的关键色。

DDBLTFAST_WAIT

如果位块传送器正忙,延迟 DDERR_WASSTILLDRAWING 消息的发送,直到位块传送器准备好或发生其它错误时才返回。

看看这个color key,这可是很有用的!所谓关键色,即我们说的透明色,如果在源表面上指定了一个颜色为关键色,

那么在blit操作中,将视具有这种颜色的区域为透明,不会被传送到目标页面上。这样的话,虽然传送过去的是一个

矩形,但矩形上是关键色的部分是不会传送的,从而看上去是有轮廓的图形,比如一个精灵。

当然必须先为一个表面设置关键色才行。在InitDDraw中我们用DDSetColorKey ( lpDDSPic, RGB(255,0,255) ) ;为

创建好的离屏表面lpDDSPic设置了紫红色的关键色。你可以在图片中画一个精灵,然后把所有非精灵的部分用紫红色

填充。然后将BltFast的最后一个参数设为DDBLTFAST_SRCCOLORKEY.这样传送过去的就是一个精灵的样子了。

用DDBLTFAST_DESTCOLORKEY可以为目标表面设置关键色,有所不同的是,目标表面上颜色只有为关键色才能被覆盖,即

染色。

最后在说说目标表面和原表面的区别。其实它们都是相对的。调用BltFast的为目标表面,作为参数的为源表面。一般的

用法,后台表面调用BltFast,参数为离屏表面。

贴图的问题就说这么多吧,其实这里面的内容还是挺多的。还有非调色板模式的16位,24位,32位RGB格式,16位RGB对应于

不同的显卡还有555,565两种模式。但我们是初学者嘛,这些东西...:) 有待研究。(如果你真的立志于作游戏,呵呵,

准备学汇编吧,以后还要和MMX处理器的指令什么的打交道啊)

最后要说的是第四步的操作要放在MainLoop中,这样让它不停的Blt再Flip,如果你在程序中设计按了某个键贴不同的图并改

变贴图的位置,就可以做出精灵动画了,基本的原理就是这样的。

三.浅谈表面丢失的处理

如果你的程序从全屏模式下用Alt+Tab切出去,再切回来,你可能发现图片不见了。因为当代表页面内存的

DirectDrawSurface对象被不得已的释放时,与该对象相关联的页面内存也会被释放。当一个DirectDrawSurface对象丢失其

页面内存的时候,它的许多函数将返回DDERR_SURFACELOST,并且不进行任何其它操作。先看一下这个片断:

while (1){

hRst = lpDDSPrimary->Flip(NULL,0) ;

if ( hRst==DD_OK )

break ;

if ( hRst==DDERR_SURFACELOST ){

if ( RestoreAllDDS()!=DD_OK )

break ;

}

if (hRst != DDERR_WASSTILLDRAWING){

break;

}

}

上回flip中没提到flip有失败的可能,上面的片断是解决的方法。如果flip返回DDERR_WASSTILLDRAWING,那么是由于上一次flip

操作尚未完成(flip指令已发出,但directX还没有完成操作),我们可以做的只能是让while循环下去,直到

hRst != DDERR_WASSTILLDRAWING。如果flip返回DD_OK,那表示flip操作完成,可以break出去了。如果flip返回

DDERR_SURFACELOST,表示发生了表面失效,这时我们需要自己处理它。看看我的RestoreAlDDS()函数是怎么工作的:

HRESULT RestoreAllDDS( void )

{

HRESULThRst ;

hRst = lpDDSPrimary->Restore();

if (hRst)

hRst = lpDDSBack->Restore () ;

if (hRst)

hRst = lpDDSPic->Restore() ;

DDReLoadBitmap ( lpDDSPic,szBitmap ) ;

return hRst ;

}

在这个函数里面,我们先后调用了主表面,后台表面,离屏表面的Restore方法。Restore方法可以为这些丢失了内存的页面重新

分配内存,并且将这些内存与DirectDrawSurface对象联系上。但重建内存并不会使以前存在于该页面上的图象重新显现出来,

因此在调用Restore函数重建之后,必须亲手重新绘制所有的图象。在这里我用了DDReLoadBitmap函数,这个函数也是

Ddutil.cpp里面的。需要说明的是,如果用DDLoadBitmap代替DDReLoadBitmap是不行的!你可以看看这两个函数的实现,比较一下。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有