离屏表面有两类:第一种叫做后备缓冲(Back Buffer)。
后备缓冲是指一些用在动画链中的表面,它们具有和主表面相同的尺寸和色深。后备缓冲表面比较独特,因为当你创建主表面时
也创建也它们(通过设置一系列属性指示系统创建主表面同时也创建任意数量的后备缓冲)。
创建后备缓冲的目的是用DirectDraw的方式来实现双缓冲功能的仿真。如果创建了DirectDraw后备缓冲(通常它在VRAM中),读写会非常快。另外,
你可以将它和主表面进行页面切换,这比双缓冲方案下所需做的内存拷贝要快得多。
从技术上讲,你可以在切换链中开设任意多个后备缓冲,但是,有事VRAM会被用完,从而表面只能创建在系统内存,这会很慢!比较保险的做法是通过GetCaps函数测试视频卡上到底有多少可用显存。
创建一个关联有后备缓冲的主表面:
1、首先将DDSD_BACKBUFFERCOUNT加到dwFlags标志段,向DirectDraw表明DDSURFACEDESC2
结构中的dwBackBufferCount字段有效,其中含有后备缓冲的数目(本例中为1)。
2、其次,将控制标记DDSCAPS_COMPLEX和DDSCAPS_FILP加到DDSURFACEDESC2结构的特性描述字段ddsCaps.dwCaps上。
3、最后,像通常一样创建主表面。它调用IDIRECTDRAWSURFACE7::GetAttachedSurface()得到后备缓冲。
代码演示:
LPDIRECTDRAWSURFACE7 lpddsprimary = NULL; // dd primary surface
LPDIRECTDRAWSURFACE7 lpddsback = NULL; // dd back surface
DDSURFACEDESC2 ddsd; // a direct draw surface description struct
// clear ddsd and set size
DDRAW_INIT_STRUCT(ddsd);
// enable valid fields
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
// set the backbuffer count field to 1, use 2 for triple buffering 创建一个关联的后备缓冲
ddsd.dwBackBufferCount = 1;
// request a complex, flippable
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
// create the primary surface
if (FAILED(lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL)))
return(0);
// now query for attached surface from the primary surface
// this line is needed by the call
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
// get the attached back buffer surface 使lpddsback指向后备缓冲页面
if (FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback)))
return(0);
结果:lpddsprimary指向主表面,即当前可见的表面,而lpddsback指向后备缓冲表面,当前不了见!!
要对后备缓冲进行存取,你可以同对主表面一样将其加锁和解锁。
如:
int Game_Main(void *parms = NULL, int num_parms = 0)
{
// this is the main loop of the game, do all your processing
// here
// make sure this isn't executed again
if (window_closed)
return(0);
// for now test if user is hitting ESC and send WM_CLOSE
if (KEYDOWN(VK_ESCAPE))
{
PostMessage(main_window_handle,WM_CLOSE,0,0);
window_closed = 1;
} // end if
// lock the back buffer 对后备缓冲进行存取
DDRAW_INIT_STRUCT(ddsd);
lpddsback->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);
// alias pointer to back buffer surface
UCHAR *back_buffer = (UCHAR *)ddsd.lpSurface;
// now clear the back buffer out
// linear memory?
if (ddsd.lPitch == SCREEN_WIDTH)
memset(back_buffer,0,SCREEN_WIDTH*SCREEN_HEIGHT);
else
{
// non-linear memory
// make copy of video pointer
UCHAR *dest_ptr = back_buffer;
// clear out memory one line at a time
for (int y=0; y<SCREEN_HEIGHT; y++)
{
// clear next line
memset(dest_ptr,0,SCREEN_WIDTH);
// advance pointer to next line
dest_ptr+=ddsd.lPitch;
} // end for y
} // end else
// you would perform game logic...
// draw the next frame into the back buffer, notice that we
// must use the lpitch since it's a surface and may not be linear
// plot 5000 random pixels
for (int index=0; index < 5000; index++)
{
int x = rand()%SCREEN_WIDTH;
int y = rand()%SCREEN_HEIGHT;
UCHAR col = rand()%256;
back_buffer[x+y*ddsd.lPitch] = col;
} // end for index
// unlock the back buffer
if (FAILED(lpddsback->Unlock(NULL)))
return(0);
// perform the flip 页面切换,使其可见
while (FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT)));
// wait a sec
Sleep(500);
// return success or failure or your own return code here
return(1);
} // end Game_Main