您的位置:首页 > 编程语言

2D游戏编程笔记-4

2010-04-10 11:57 155 查看
本人同意他人对我的文章引用,但请在引用时注明出处,谢谢.作者:蒋志强

对Windows平台来说,位图是一种非常特殊的图像格式,位图是windows操作系统直接从底层所支持的图像格式。位图分为DIB(设备无关位图)和DDB(设备相关位图两类),这两种位图彼此是有关系的,DIB和DDB之间是可以相互转换的。DDB(即设备相关位图)是windows的GDI对象的一种,他所表示的图像与具体的显示图像的系统相关,也就是说一样的DDB在不同的显示设备上显示的效果可能是不一样的,所以DDB是不用于存储的。我们常见的以文件格式保存的位图,也就是那些以bmp或dip作为后缀名的文件是设备无关位图。DIB之所以称为设备无关位图,就是因为它记录了图像的所有信息,在不同的设备上显示都会是一样的。

在具体的编程中,我们有时需要将以文件格式(bmp或dip为后缀名的文件)的位图在程序运行过程中,进行载入并使用载入的位图。在这个时候,从DIB到DDB的转换就发生了。在windows平台下,我们必须使用HBITMAP这种被称为位图句柄的变量来进行引用和操作GDI位图对象,HBITMAP类型变量所引用的位图就是DDB,它与具体的显示设备相关,在具体需要显示或操作的时候DDB产生。我们可以使用LoadImage函数从文件中装载DIB,该函数返回DDB位图的句柄,从DIB到DDB的转换在调用该函数时发生。这个转换过程不用我们操心,LoadBitmap函数返回的也是DDB位图的句柄。如果你还没有搞明白DIB和DDB的区别,你可以参考《windows程序设计》的相应章节。我们要在程序中使用位图有两种方式:1从BMP文件中加载;2从程序的资源中加载(如果你还不太理解程序资源的相关概念,请参考《windows程序设计》的第十章)。

LoadImage函数可以从指定目录加载位图文件,返回DDB位图句柄;该函数也可以从程序资源中加载位图返回DDB位图句柄,LoadBitmap只能从程序资源中加载位图返回DDB位图句柄。下面的代码将程序资源中的位图加载,把返回的DDB句柄赋给了一个HBITMAP变量:

if((bitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_NPC))) == NULL)

return FALSE;

下面的代码将指定位图文件(颜色选择32.bmp)加载到程序中,并把返回的DDB句柄赋给了一个HBITMAP变量:

if((bitmap = (HBITMAP)LoadImage(NULL,TEXT("test//颜色选择32.bmp"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE)) == NULL)

return FALSE;

具体函数各个参数的意义,请查阅MSDN文档说明。当我们将位图转载以后(无论你是从文件中装载还是从程序的资源中装载),也就是我们获得一个DDB句柄以后,我们就可以做下面的事情了:将该位图放到我们离屏页面中去,下面的代码完成这样的工作:

BITMAP bitmapInfor;

GetObject(bitmap,sizeof(BITMAP),&bitmapInfor);

if((p_PicResourceSurface->GetDC(&hdc)) != DD_OK)

return FALSE;

HDC compataleDC = CreateCompatibleDC(hdc);

SelectObject(compataleDC,bitmap);

DDCOLORKEY picColorKey;

picColorKey.dwColorSpaceLowValue = picColorKey.dwColorSpaceHighValue = RGB(255,0,255);

if((p_PicResourceSurface->SetColorKey(DDCKEY_SRCBLT ,&picColorKey)) != DD_OK)

return FALSE;

BitBlt(hdc,0,0,bitmapInfor.bmWidth,bitmapInfor.bmHeight,compataleDC,0,0,SRCCOPY);

p_PicResourceSurface->ReleaseDC(hdc);

上面的代码中的BITMAP是一个用于描述DDB位图属性的结构体,GetObject函数根据bitmap这个我们在上面载入的DDB位图的属性填充该结构体。GetDC是IDirectDrawSurface接口中的方法,用于获得页面的DC,要注意的是该方法内部调用了Lock方法,将该页面内存区域锁定,在锁定期间从锁定页面往其他地方Blit将失效(刚才我就是由于这个原因程序老是不能正常运行,大家要注意)。然后我们创建一个与从离屏页面所得到的DC相兼容的DC,并将得到的DDB位图bitmap选入该兼容DC中。然后我们使用GDI的BitBlt函数,将兼容DC中的内容传送到离屏页面的DC中,这样就完成了将DDB位图装入离屏页面的操作。要特别注意,一定要使用ReleaseDC释放,我们用GetDC所得到的离屏页面的DC,因为在GetDC时,页面将会被锁定,调用ReleaseDC将对所锁定的页面解锁。

你肯定会注意到上面SetColorKey的代码,这是设置页面的关键色。因为图片资源都是矩形的,但是我们在程序中往往不想显示整个矩形的内容方框,而只是显示矩形图片中踢出背景颜色后的内容。这个时候我们设定页面的关键色,然后从该页面往其他页面(比如后台页面)进行图像Blit的时候,就可以指定关键色不进行传送。关键色可以不只一种(虽然我们平时一般都只指定一种关键色),在关键色DDCOLORKEY结构体的LowValue和HighValue之间的所有颜色都是关键色(RGB宏将颜色转换为一个整型数值)

现在我们可以用BitBlt函数完成将兼容DC中的内容传送到主页面DC中,在主页面的内容就会马上显示在屏幕上.很令人兴奋吧,忙了半天,终于在屏幕上显示出内容了!

上面将图像装载到主页面的方法对后台页面同样适用,操作代码完全是一样的,我就不在重复了.当后台页面装载图像后,通过换页操作,主页面与后台页面交换,以前的主页面变成现在后台页面,以前的后台页面变成现在的主页面,这样后台页面上的内容就变成主页面内容显示在了屏幕上了.

当使用上面的方法把图片装载到页面后,就可以先在后台页面把绘图操作完成以后在进行页面的Flip,使用Flip函数将使以前的主页面变为后台页面,以前的后台页面变为当前的主页面,因为主页面上面的内容将会直接显示到屏幕上,这样之前在后台页面绘制的内容将在屏幕上显示出来。而且由于绘图是在后台页面上操作的,所以绘图的中间过程不会显示出来,程序运行时,也就不会有闪烁现象了。该函数的原型如下:

HRESULT Flip(

LPDIRECTDRAWSURFACE7 lpDDSurfaceTargetOverride,

DWORD dwFlags

);

在代码中直接使用p_FrontSurface->Flip(NULL,0),就可以实现上面的操作了。我们需要注意的是,DDraw程序独占显示设备时,如果跳出该程序,比如按下alt+tab切换到其它程序时,或者最小化当前Ddraw程序时,DDraw程序将失去对显示设备的独占,所以这个时候Flip操作肯定会出丢失页面的错,丢失页面后,以前页面中装载的图象都会丢失需要重新装入,所以我们一定要处理这个情况。我们可以在代码中这样进行处理:

HRESULT ddrval;

ddrval=lpDDSPrimary->Flip(NULL,DDFLIP_WAIT);

if (ddrval==DDERR_SURFACELOST)

{

lpDD->RestoreAllSurfaces( );

ReloadResourceImages( ); //自定义的函数,将资源图片装载到页面中

}

这次笔记至此讲解了Ddraw编程的最基础的知识,在后续的笔记中我将实现一个DDraw的俄罗斯方块的游戏。很吸引人吧,下次再见哦^_^

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gamer_gerald/archive/2006/09/02/1160905.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: