关闭

DirectX学习手记(二)

2541人阅读 评论(0) 收藏 举报
			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 )
{
    HRESULT	hRst ;
  
    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是不行的!你可以看看这两个函数的实现,比较一下。

0
0
查看评论

综合评价书籍4--MATLAB GUI设计学习手记

引用格式:罗华飞.MATLAB GUI设计学习手记[M].北京:北京航空航天大学出版社,2014. 相关资源下载(配套光盘源程序):http://download.csdn.net/detail/snicolashe/9625615
  • snicolashe
  • snicolashe
  • 2016-09-08 23:52
  • 813

说说本人学习DirectX之路

决定不继续学DIRECTX/DXUT了,所以在这里总结一下,留一些经验,留一些遗憾...
  • davied9
  • davied9
  • 2016-07-13 09:41
  • 2643

DirectX学习手记(-)

DirectX学习手记(-) HappyFire 2002/8/2 题记:玩了很多的游戏,不禁萌发了自己做游戏的念头,于是7月份从网上收集了N多资料。7月20几号在家开始了闭关式的学习,一直到昨天,我的第一个地图类封装完毕,并乘胜追击到凌晨3点,做好了地图编辑器的0.9版。早上...
  • n5
  • n5
  • 2002-11-20 08:54
  • 2405

Directx :一些学习网站 和 博客

1: http://www.cnblogs.com/mikewolf2002/category/351011.html  这个是关于dx11的教程 很棒 每个实例都有yuanma
  • cq361106306
  • cq361106306
  • 2014-09-23 13:25
  • 1547

DirectX11与游戏编程学习路线自拟

最近学习了龙书(DX11版本)简要的翻了翻,对于初学者还是有很大的难度。 因此,制定了下关于学习游戏编程以及游戏引擎的路线。学习使用游戏引擎学习游戏引擎之前需要了解一下如何使用游戏引擎我打算从Unity3d入手,先了解游戏引擎所具备的功能,对于游戏引擎有初步的了解。 目标:实现demo,可以做出...
  • qq_23225317
  • qq_23225317
  • 2016-12-02 18:46
  • 1447

FPGA学习手记(三)准备工作-和谐ModuleSim10.0(已验证至10.0c)

FPGA学习手记(三)准备工作——和谐ModelSim10.0(已验证至10.0c) 2012-03-07@Beijing         ModelSim作为仿真利器,是做CPLD和FPGA不可或缺的一款软件。在进行仿真之前,先要说说和谐安装的问题。安装...
  • nightseas
  • nightseas
  • 2012-03-10 21:15
  • 1872

OPENGL学习笔记(六)

如何使用OPENGL分配顶点缓存对象,并绘制一个白色的三角形 添加Mesh类: class Vertex {   public:      Vertex(const glm::vec3& pos)   ...
  • u012181898
  • u012181898
  • 2016-11-06 06:54
  • 511

两天学会DirectX 3D之入门

环境配置以及背景知识环境 Windows 8.1 64bit VS2013 Microsoft DirectX SDK (June 2010) NVDIA Geforce GT755环境的配置参考 VS2008整合DirectX9.0开发环境一些背景知识 DirectX的和应用层与硬件层的...
  • qp120291570
  • qp120291570
  • 2015-07-05 11:32
  • 2841

FPGA笔记(二)

#对FPGA的一些理解 经过一周对FPGA的了解,对Verilog语法已经有一定的了解了,自己也写了些程序,但是感觉自己写出来的硬件描述语言程序不是那个味儿,就像一段式状态机跟三段式状态机相比一样,在我这所有的逻辑都放在一个always进程中,虽然目的都能达到,但是这么下去,越大的运用中会带来越大的...
  • Struggle_For_M
  • Struggle_For_M
  • 2016-05-19 14:26
  • 614

Directx9.0 学习教程1 - 第一个程序

在图书馆选了N本书,还是觉得直接讲代码的书更适合我,一个完整的列子加上些许注释,比那些一上来就是一大段一大段的文字阐述的教程容易懂的多。  因此我的笔记也开始用这种方式记录。 写在开头:  dx(我对directx简称) dx的版本主要有9 和11这两种系列。 API和功能差异还...
  • cq361106306
  • cq361106306
  • 2014-09-25 13:01
  • 14544
    个人资料
    • 访问:714898次
    • 积分:9379
    • 等级:
    • 排名:第2317名
    • 原创:212篇
    • 转载:12篇
    • 译文:0篇
    • 评论:339条
    博主链接
    最新评论
    同道中人