DirectDraw的学习笔记(4)

使用IDirectDrawSurface::Lock( )就能让我们随心所欲,因为此函数可以允许我们直接修改页面。
  Lock( )函数的用法如下:

HRESULT Lock(
    LPRECT lpDestRect,
    LPDDSURFACEDESC lpDDSurfaceDesc,
    DWORD dwFlags,
    HANDLE hEvent
);

 

 第一个参数为一个指向某个RECT的指针,它指定将被锁定的页面区域。如果该参数为 NULL,整个页面将被锁定。
  第二个参数为一个 DDSURFACEDESC结构的地址,将被填充页面的相关信息。
  第三个参数,即dwFlags,还是象以前一样给它DDLOCK_WAIT。
  第四个参数规定要为NULL。
  现在举一个例子来说明怎样使用Lock( ),我们的目标是使lpDDSBack半透明地浮现在lpDDSBuffer上。先看看完整的锁屏部分(注意,这一节只讨论24和32位色下如何操作):

 

DDSURFACEDESC ddsd, ddsd2; //DirectDraw页面描述
ZeroMemory(&ddsd, sizeof(ddsd)); //ddsd用前要清空
ddsd.dwSize = sizeof(ddsd); //DirectDraw中的对象都要这样
ZeroMemory(&ddsd2, sizeof(ddsd2));
ddsd2.dwSize = sizeof(ddsd2);
lpDDSBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); //Lock!
lpDDSBack->Lock(NULL, &ddsd2, DDLOCK_WAIT, NULL);

BYTE *Bitmap = (BYTE*)ddsd.lpSurface; //Lock后页面的信息被存在这里,请注意
//这个指针可能每次Lock( )后都不同!
BYTE *Bitmap2 = (BYTE*)ddsd2.lpSurface;

锁完页面后,Bitmap数组的存储格式是这样的:如为32位色则页面上坐标为(x,y)的点的R/G/B值分别存在Bitmap的 y*ddsd.lPitch+x*4,y*ddsd.lPitch+x*4+1,y*ddsd.lPitch+x*4+2处;如为24位色则页面上坐标为 (x,y)的点的R/G/B值分别存在Bitmap的 y*ddsd.lPitch+x*3,y*ddsd.lPitch+x*3+1,y*ddsd.lPitch+x*3+2处。所以,现在我们就可以发挥想 象,做出想要的一切效果了,比如说动态光照(将一目标页面按光照表改变亮度即可)!下面是接下来的代码(32位色时):

int pos;
for (int y=0;y<480; y++)
{
    pos=y*ddsd.lPitch;
    for (int x=0; x<640; x++)
    {
        Bitmap[pos] =(Bitmap[pos]+Bitmap2[pos])>>1; //改R
        pos++;
        Bitmap[pos] =(Bitmap[pos]+Bitmap2[pos])>>1; //改G
        pos++;
        Bitmap[pos] =(Bitmap[pos]+Bitmap2[pos])>>1; //改B
        pos+=2;//到下一个R处
    }
}
lpDDSBack->Unlock(&ddsd2); //Unlock!
lpDDSBuffer->Unlock(&ddsd);

 

由于使用Lock后DirectDraw要锁定页面,在没有使用Unlock( )前我们是无法用其他办法如Blt来修改页面的。所以用完Lock( )要赶快象上面的程序那样Unlock( )。Unlock的方法很简单,lpDDSXXX->Unlock(LPDDSURFACEDESC lpDDSurfaceDesc)即可。

 

7.2 程序的提速
  上面的程序看起来好象很简单,但运行速度很可能会很慢,即使你直接用汇编重写也不会快多少。原因是读显存非常慢,写显存的速度也比写内存慢。解决这个问题的方法是:
(1) 把除了主页面外的所有页面放在内存中。(初始化页面时将ddsd.ddsCaps.dwCaps中的 DDSCAPS_OFFSCREENPLAIN后再或( | )一项"DDSCAPS_SYSTEMMEMORY")这样做的另一个好处是你Lock( )一次后就永远得到了页面指针,而且然后一Unlock( )就又可以使用Blt了,你就拥有了两种改变页面的手段。
(2)将后台缓冲改为一个普通的离屏页面。
(3)将Flip( )改用BltFast( )函数实现。当然你也可以直接用memcpy( )拷贝,这样做有时候会快一些。注意要一行一行地拷贝,比如说640x480x24位色全屏幕拷贝是这样的:

 

BYTE *pSrc=(BYTE *)ddsd_src.lpSurface;
BYTE *pDest=(BYTE *)ddsd_dest.lpSurface;

for (int y=0;y<480;y++)
{
    memcpy(pDest, pSrc, 1920); //若为32位色则为2560
    pSrc+=ddsd_src.lPitch;
    pDest+=ddsd_dest.lPitch;
}

  看起来好像要重写很多东西,其实改动的部分并不多。这样改了之后整个程序的速度就会快很多,但还不能很好地满足全屏幕特效的要求,因为全屏幕特效实在很耗时间,只有用MMX指令重写速度才能比较快。所以在下面一章中,我们将介绍内嵌汇编和MMX指令。

 

众所周知,从内存到显示内存的数据传送速度比从内存到内存的速度慢,也比从显示内存到显示内存的速度慢。我们如果把BackSurface开在系统 内存里面,这样要显示的时候,我们只要把BackSurface的数据送到PrimarySurface里面,也就是说,我们只要从内存传送一屏的的数据 到显示内存里面就可以了,而上面所说的组织数据的问题,则是在速度较快的内存到内存之间的操作。而假如我们把BackSurface开在显示内存里面,则 每次显示的时候,组织数据是通过速度较慢的显示内存到内存之间的操作,则2-3屏的数据足以使整体速度下降很多。   这样,如果要提高游戏的显示速度,应该尽可能的把BakcSurface开在系统内存里面。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值