双缓冲技术
双缓冲技术
在离屏缓冲绘制图像,然后将其拷贝到显示表面的处理过程被称作双缓冲技术。
实现:额外的一块同主DirectDraw表面具有同样尺寸的内存。并在这块内存上画每一帧动画之后拷贝双内在到主显示表面。
如:申请640X480X8的内存
UCHAR *double_buffer = (UCHAR *) malloc (640*480);
或者
UCHAR *double_buffer = new UCHAR[640*480];
实现:让后备缓冲显示出来,可以把后备缓冲拷贝到主显示页面代码如下:
DDSURFACEDESC2 ddsd; //directdraw 表面结构说明
LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;//主表面指针
LPDIRECTDRAWSURFACE7 lpddsback = NULL;//后备缓冲指针
DDRAW_INIT_STRUCT(ddsd);//初始化ddsd
//蓝色的表示ddsd的dwBackBufferCount字段有效
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount =1;//表示一个后备缓冲页面
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;//步骤第二条
if (FAILED(lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL);
return(0);//创建主表面
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
//主表面得到后备缓冲
if (FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback)))
return(0);
如果想操控后备缓冲信息
// 初始化ddsd
DDRAW_INIT_STRUCT(ddsd);
lpddsback->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR| DDLOCK_WAIT, NULL);//锁定后备缓冲
//这里可以对它进行读写操作
lpddsback->Unlock(NULL);//解锁
LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;//主表面指针
LPDIRECTDRAWSURFACE7 lpddsback = NULL;//后备缓冲指针
DDRAW_INIT_STRUCT(ddsd);//初始化ddsd
//蓝色的表示ddsd的dwBackBufferCount字段有效
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount =1;//表示一个后备缓冲页面
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;//步骤第二条
if (FAILED(lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL);
return(0);//创建主表面
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
//主表面得到后备缓冲
if (FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback)))
return(0);
如果想操控后备缓冲信息
// 初始化ddsd
DDRAW_INIT_STRUCT(ddsd);
lpddsback->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR| DDLOCK_WAIT, NULL);//锁定后备缓冲
//这里可以对它进行读写操作
lpddsback->Unlock(NULL);//解锁
离屏表面有两类
A) 后备缓冲 (Back Buffer) 当你创建主表面进也创建它们。目的是用DirectDraw的方式来实现对双缓冲功能的仿真。
读写会非常快。 可以和主表面进行页面切换。
创建一个关联有后备缓冲的主表面, 必须创建DirectDraw所谓的复杂表面(ComplexSurface) 创建步骤如下:
1先将 DDSD_BACKBUFFERCOUNT加到dwFlags标志字段,向DirectDraw表明DDSURFACESC2
结构的dwBackBufferCount字段有效,其中包括后备缓冲数目。
2再将控制标志DDSCAPS_COMPLEX和DDSCAPS_FLIP加到DDSURFACEDESC2结构的特性描述
字段ddsCaps.dwCaps上。
3最后像通常一样建立表面,用IDIRECTDRAWSURFACE7 :: GetAttachedSurface()得到后备缓冲。
例如:
DDSURFACEDESC2 ddsd; //directdraw 表面结构说明
LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;//主表面指针
LPDIRECTDRAWSURFACE7 lpddsback = NULL;//后备缓冲指针
DDRAW_INIT_STRUCT(ddsd);//初始化ddsd
//蓝色的表示ddsd的dwBackBufferCount字段有效
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount =1;//表示一个后备缓冲页面
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;//步骤第二条
if (FAILED(lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL);
return(0);//创建主表面
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
//主表面得到后备缓冲
if (FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback)))
return(0);
如果想操控后备缓冲信息
// 初始化ddsd
DDRAW_INIT_STRUCT(ddsd);
lpddsback->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR| DDLOCK_WAIT, NULL);//锁定后备缓冲
//这里可以对它进行读写操作
lpddsback->Unlock(NULL);//解锁
LPDIRECTDRAWSURFACE7 lpddsprimary = NULL;//主表面指针
LPDIRECTDRAWSURFACE7 lpddsback = NULL;//后备缓冲指针
DDRAW_INIT_STRUCT(ddsd);//初始化ddsd
//蓝色的表示ddsd的dwBackBufferCount字段有效
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount =1;//表示一个后备缓冲页面
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;//步骤第二条
if (FAILED(lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL);
return(0);//创建主表面
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
//主表面得到后备缓冲
if (FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback)))
return(0);
如果想操控后备缓冲信息
// 初始化ddsd
DDRAW_INIT_STRUCT(ddsd);
lpddsback->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR| DDLOCK_WAIT, NULL);//锁定后备缓冲
//这里可以对它进行读写操作
lpddsback->Unlock(NULL);//解锁
页面切换:前面有了主表面和后备缓冲表面,进行页面切换后就能实现动画了。
1清除后备缓冲。(初始化)
2将场景渲染到后备缓冲。
3用后备缓冲切换掉主显示表面。
4锁定帧速率。
5重复第一步。
用下面的函数来对关联表面和主表面进行切换。
HRESULT Flip (LPDIRECTDRAWSURFACE7 lpDDSurfaceTargetOverride, DWORD dwFlags);其中lpDDSurfaceTargetOverride
是个高级参数,用来覆盖切换链,实现切换到另一个表面,而不是切换到同主表面相关的后备缓冲,这里值为NULL。
后面的dwFlags是控制标志见p248
默认是1。这些要在DDCAPS结构中设置了DDCAPS2_FLIPINTERVAL后才起作用。
例如:
lpddsprimary->Fliy(NULL, DDFLIP_WAIT);
注意:切换之前主表面和后备缓冲表面都要解锁。代码例子p249