Yesky首页| 产品报价| 行情| 手机 | 数码 | 笔记本 | 台式机 | DIY硬件 | 外设 | 网络 | 数字家庭 | 评测 | 软件 | e时代 | 游戏 | 图片 | 壁纸 | 群乐 | 社区 | 博客 | 下载
您现在的位置: 天极网 > 开发频道 > 游戏开发新手入门之位图化图形
全文

游戏开发新手入门之位图化图形

2005-05-11 09:51 作者: ant3000 出处: 编程论坛 责任编辑:方舟
  使用位块传输

  位块传输是显示卡操控位图数据的一部分,你同样可以用它来进行颜色填充。就像我们过一会儿看到的,随着硬件的性能提高,会有很多经典的技巧。DirectX有权使用硬件的加速功能,但要记住,如果DirectX使用的加速功能不被机器硬件支持,将自动启用硬件仿真层(HEL),但这也并非万无一失,因为有些功能靠硬件仿真层是无法实现的(否则谁还买3D加速卡^_^),所以你需要检测你的函数是否调用成功。

  GDI位块传输可以在DirectDraw编程中使用,而且有时也的确是这样做的。然而DirectDraw具有其自身的位块传输函数,它们通常更加适合于编程环境,而且比GDI的相应的函数执行得更快。DirectDraw位块传输函数名为Blt()和BltFast(),都是有IDirectDrawSurface7接口提供的。两者不同处是BltFast()不处理剪切、放缩等其它Blt()做的有趣的事情。如果在硬件仿真层上,BltFast()要比Blt()快10%左右,但如果有硬件加速卡支持(硬件加速卡主要就是为位块传输服务的),二者的速度就差不多了,而且现在大多数的机器都有硬件加速卡,所以我总是使用Blt()。让我们仔细看看这个神奇的东东:

HRESULT Blt(
 LPRECT lpDestRect,
 LPDIRECTDRAWSURFACE7 lpDDSrcSurface,
 LPRECT lpSrcRect,
 DWORD dwFlags,
 LPDDBLTFX lpDDBltFx
);

  由于Blt()所拥有的最后一个参数,使其能做很多特殊的事儿。该参数配有一个标志常量列表,我将会向你介绍其中最有用的几个。另外,注意在把位图从一个表面向另一个表面传递时,你应该调用目的表面的Blt(),不是源表面的。好了吗?以下是函数的参数说明:

  ※ LPRECT lpDestRect:参数lpDestRect为指向结构RECT的指针,它给出了位块传输操作的目标表面的左上角和右下角的坐标。如果源表面和目标(目的)表面的大小不一致,Blt()将把源表面的图象自动按照比例适应目标表面的大小。如果此参数为NULL,则使用整个目标表面。

  ※ LPDIRECTDRAWSURFACE7 lpDDSrcSurface:参数lpDDSrcSurface为指向DirectDraw表面的指针,该DirectDraw表面为位块传输之源表面。如果你只是要用颜色填充目的表面,你可以把它设置为NULL。

  ※ LPRECT lpSrcRect:参数lpSrcRect为指向结构RECT的指针,它给出了位块传输(有的书上也叫作“位转换”)操作的源表面的左上角和右下角的坐标。如果此参数为NULL,则使用整个源表面。

  ※ DWORD dwFlags:对于这个参数有一个巨大的标志常量列表,可以用“|”组合使用标志常量。其中一些是为Direct3D服务的,所以我将把我们常用的列出来: · DDBLT_ASYNA:位块传输异步的以先入先出(FIFO)的顺序接收。如果没有空间可用于FIFO硬件,则该调用失败。

  · DDBLT_COLORFILL:使用DDBLTFX结构的数据成员dwFillColor作为RGB颜色填充目标表面的矩形。

  · DDBLT_DDFX:DDBLTFX结构的dwDDFX成员指定了位块传输的使用效果。

  · DDBLT_DDROPS:DDBLTFX结构的dwDDROP成员指定了光栅操作(ROPS),该操作不是Win32 API的一部分。

  · DDBLT_KEYDEST:颜色键与目标表面相关联。

  · DDBLT_KEYDESTOVERRIDE:DDBLTFX结构的dckDestColorkey成员是目标表面的颜色键。

  · DDBLT_KEYSRC:颜色键与源表面相关联。

  · DDBLT_KEYSRCOVERRIDE:DDBLTEX结构的dckSrcColorkey成员是源表面的颜色键。

  · DDBLT_ROP:DDBLTFX结构的dwROP成员是位块传输的ROP(光栅操作代码),这些ROP与Win32 API中定义的那些相同。

  · DDBLT_ROTATIONANGLE:DDBLTFX结构的dwRotationAngle成员是表面的旋转角度,其单位为1/100度。

  · DDBLT_WAIT:在位块传输器忙的情况下,推迟DDERR_WASSTILLDRAWING返回值(位块传输函数调用失败返回的值之一),而当位块传输开始或发生另一个错误时立即返回。

  我几乎总是使用DDBLT_WAIT标志。颜色键标志也是很重要的,我们过一会儿再说它。现在,还有最后一个Blt()参数需要说一下:

  ※ LPDDBLTFX lpDDBltFX:这是一个指向DDBLTFX结构的指针,它可以包含各种特殊要求的信息。如果没有什么特殊要求,你就设置为NULL好了。让我们仔细看看这个结构。我警告你,它是很魁梧的:^_^

typedef struct _DDBLTFX{
 DWORD dwSize;
 DWORD dwDDFX;
 DWORD dwROP;
 DWORD dwDDROP;
 DWORD dwRotationAngle;
 DWORD dwZBufferOpCode;
 DWORD dwZBufferLow;
 DWORD dwZBufferHigh;
 DWORD dwZBufferBaseDest;
 DWORD dwZDestConstBitDepth;

 union {
  DWORD dwZDestConst;
  LPDIRECTDRAWSURFACE lpDDSZBufferDest;
 };

 DWORD dwZSrcConstBitDepth;

 union {
  DWORD dwZSrcConst;
  LPDIRECTDRAWSURFACE lpDDSZBufferSrc;
 };

 DWORD dwAlphaEdgeBlendBitDepth;
 DWORD dwAlphaEdgeBlend;
 DWORD dwReserved;
 DWORD dwAlphaDestConstBitDepth;

 union {
  DWORD dwAlphaDestConst;
  LPDIRECTDRAWSURFACE lpDDSAlphaDest;
 };

 DWORD dwAlphaSrcConstBitDepth;

 union {
  DWORD dwAlphaSrcConst;
  LPDIRECTDRAWSURFACE lpDDSAlphaSrc;
 };

 union {
  DWORD dwFillColor;
  DWORD dwFillDepth;
  DWORD dwFillPixel;
  LPDIRECTDRAWSURFACE lpDDSPattern;
 };

 DDCOLORKEY ddckDestColorkey;
 DDCOLORKEY ddckSrcColorkey;
} DDBLTFX, FAR* LPDDBLTFX;

  如果我整个详细的介绍这个结构,恐怕我们都会受不了的,并且也没有这个必要。所以我只告诉你一些重点的部分。谢天谢地,该结构的大部分都是为z缓冲区(z-buffers)和α消息服务的,我们不用理会它。嘻嘻,我的工作量变得很小了:

  ※ DWORD dwSize:象所有的DirectX的结构一样,当你初始化这个结构时,该成员放置结构的大小。

  ※ DWORD dwDDFX:这些是位块传送所能接受的一些特殊操作。列表并不长,别担心喔!

  · DDBLTFX_ARITHSTRETCHY:位块传输时,在Y轴算术拉伸位图。

  · DDBLTFX_MIRRORLEFTRIGHT:y轴上的镜像变换。表面从左到右完成镜像效果。

  · DDBLTFX_MIRRORUPDOWN:x轴上的镜像变换。表面从上到下完成镜像效果。

  · DDBLTFX_NOTEARING:把动画图像块转移到前段缓存时可以使用这个参数,这样位块传输操作的时间会与屏幕刷新率相一致,并使画面撕裂的可能性减小到最小。

  · DDBLTFX_ROTATE180:位块传输时,把表面顺时针旋转180度。

  · DDBLTFX_ROTATE270:位块传输时,把表面顺时针旋转270度。

  · DDBLTFX_ROTATE90:位块传输时,把表面顺时针旋转90度。

  需要详细解释的可能只有DDBLTFX_NOTEARING。游戏离不开动画,动画制作者主要关心的通常是动画的速度和性能,速度太快会导致图象质量的恶化。光栅扫描显示系统(我们基本上用的都是这种显示器)利用电子束扫描每一条水平线上的屏幕象素点。象素行从屏幕的左上角开始更新,到屏幕的右下角结束。各象素行都被称为扫描线。电子束在每一行扫描线的末端被关掉,而电子枪重新瞄准下一行的起始点,这个过程成为水平回扫。当过程执行到屏幕扫描线的最后一行时,电子束再次被关掉,电子枪重新瞄准屏幕的左上角。电子枪从屏幕的右下角重新瞄准到左上角的过程所需的时间被称为垂直回归或者屏幕空白周期。如果在视频控制器显示视频数据的同时,视频数据被CPU做了更改,这时就会产生问题。在PC机中,屏幕的刷新率通常在60Hz到100Hz之间,而现在的CPU则可以在每秒处理成百上千的指令,这样就很可能导致位于视频内存区的图象在视频系统完成显示之前发生更改。图象断裂的结果被称为图象撕裂。就我的经验而言,使用了DDBLTFX结构的DDBLTFX_NOTEARING后,图象撕裂就不是什么问题了。

  ※ DWORD dwROP:使用这个标志来指定Win32模式的光栅操作代码。同GDI函数BitBlt()和StretchBlt()中的相对应参数的功能一样。可以通过IDirectDraw7::GetCaps()函数得到可能的光栅操作列表,可以通过“|”组合标志常量,确定源矩形表面和目标矩形表面是怎样结合的。

  ※ DWORD dwRotationAngle:这是用来旋转位图角度的,可以旋转任意角度。这是非常棒的,但不幸的是,它只能在HAL层(硬件抽象层)上工作,这就意味着用户的显示卡要支持加速旋转,否则……,但不能保证每个用户都有这种高档的显示卡,所以你需要考虑周全。如果你真的需要旋转处理,你只好自己写这样的函数了,这可是一个大话题,需要另写一部指南了,所以我们就越过它。但请注意,如果是90度倍数的角度,你可以使用DDBLTFX_ROTATE90等。这将使你回避显示卡不干活的风险。

  ※ DWORD dwFillColor:如果你要使用位块传输来填充颜色,你必须把颜色放入到这个参数中。

  ※ DDCOLORKEY ddckDestColorKey,ddckSrcColorKey:你要使用颜色键时必须要指定这些成员。这两个家伙是很重要的。但暂时我们还不讨论它们,因为我们过一会儿才讲颜色键。

  以上这些就是DDBLTFX结构中比较有用的成员了,这就意味着你现在拥有足够的知识进行位块传输了!如果你现在感觉有些混乱,不要紧,你实践过一段时间就会好了。让我们看看几个例子。假设你已经有了一个叫作lpddsBack的后缓冲区,你想把它里面的内容传输到主表面,很简单的,你看:

lpddsPrimary->Blt(NULL, lpddsBack, NULL, DDBLT_WAIT, NULL);

  再轻轻回忆一下,第一个参数和第三个参数分别是位块传输的目标矩形和源矩形。由于我把它们都设置为NULL,就说明是对全部的表面进行拷贝。现在,让我们在看看,假设你有一个在离屏表面里的名字叫作lpddsTileset的16×16大小的图形,你想把它传输到后缓冲区,变成32×32大小的,你需要这样做:

RECT dest, src;
SetRect(&src, 0, 0, 16, 16); // the coordinates of the tile
SetRect(&dest, 0, 0, 32, 32); // where you want it to end up on the back buffer
lpddsBack->Blt(&dest, lpddsTileset, &src, DDBLT_WAIT, NULL);

  这个例子同上一个例子不同处在与这个例子设置了位块传输的坐标。由于这两个矩形区的大小不同,Blt()依照比例适当的变更了图形的大小。最后,我们还得举例说明一下DDBLTFX结构,就做一个颜色填充的例子吧。假设你在16-bit色彩模式下,是565象素格式,你要把你的后缓冲区填充为蓝色。下面就是你应该做的:

DDBLTFX fx;
INIT_DXSTRUCT(fx); // zero out the structure and set dwSize
fx.dwFillColor = RGB_16BIT565(0, 0, 31); // set fill color to blue
lpddsBack->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &fx);

  注意参数的设置,前三个都是NULL,你自己想想原因吧!好了,让我们看看另一个位块传输函数BltFast()吧。它只是Blt()的简化版本,所以我们不需要太多的时间解释它。下面是它的原形:

HRESULT BltFast(
 DWORD dwX,
 DWORD dwY,
 LPDIRECTDRAWSURFACE7 lpDDSrcSurface,
 LPRECT lpSrcRect,
 DWORD dwTrans
);

  你可以看得出来,它同Blt()极其相似。它也是IDirectDrawSurface7接口的成员函数,被目标表面调用。来看看它的参数:

  ※ DWORD dwX,dwY:这是Blt()和BltFast()之间不同的地方。是目标表面上进行位块传输的x和y坐标。如果源矩形大于目标矩形,则调用失败,因为BltFaxt()不能干按比例变换的事儿及其它能够通过Blt()完成的工作。

  ※ LPDIRECTDRAWSURFACE7 lpDDSrcSurface:这是源表面,同Blt()的一样。

  ※ LPRECT lpSrcRect:这个也同Blt()的一样。是在源表面中定义了矩形左上角和右下角的RECT结构。

  ※ DWORD dwTrans:定义了位块传输类型,它的标志列表很简单,只有四个标志:

  · DDBLTFAST_DESTCOLORKEY:使用目标颜色键的透明位块传输。

  · DDBLTFAST_NOCOLORKEY:没有透明的普通复制位块传输。

  · DDBLTFAST_SRCCOLORKEY:使用源颜色键的透明位块传输。

  · DDBLTFAST_WAIT:如果位块传输忙的话,不产生DDERR_WASSTILLDRAWING消息。一旦位块传输能够开始或者发生另一个错误时返回。

  就这些!BltFast()支持颜色键。下面让我们看一个简单的示例。把整个后缓冲区拷贝到主表面:

lpddsPrimary->BltFast(0, 0, lpddsBack, NULL, DDBLTFAST_WAIT);

  到现在为止,你已经是一个位块传输的专家了,还有几件事情对于DirectX程序很重要:颜色键和剪裁板。你可能知道在某些情况下关于颜色键有上百万种标志,那么到底怎样使用它呢?让我们一起看看吧!

共5页。 9 1 2 3 4 5 :
网友关注
最新上市
编辑推荐
文章阅读排行
周排行
月排行
欢迎订阅天极网RSS聚合资讯:http://www.yesky.com/index.xml