粗略看了一下,感觉这章也是个大餐,把所有以前的全屏过程综合起来了。
1, 总流程:SURFACE,不只是只有主缓冲和后备缓冲,还有离屏表面,离屏表面不只是一个,它装载各种位图,然后被blt到后备缓冲,再primarysurface->flip()页面切换到主表面。
2, 离屏表面blt到后备缓冲:离屏表面[(0,0), (宽度-1,高度-1)]blt到后备缓冲[(x,y),(x+宽度-1,y+高度-1 );(如果两个矩形大小不同,则缩放源图象以适应目的矩形)。
3, 创建离屏表面,标志DDSD_CAPS | DDSD_WIDTH|DDSD_HEIGHT|DDSD_CKSBLT(或者DDSD_CKDESTBLT,分别代表源色彩键或者目标色彩键),然后分别设定离屏表面的宽高、离屏表面标志DDSCAPS_OFFSCREENPLAIN|mem_flags,设定颜色键高低值,
4, 色彩键是位图所在矩形不要的颜色,分高低色,在这两者之间的颜色不要了。如果两者一样,则去掉一种颜色。8位则是这个范围的索引,或者某值的索引。如果是色彩范围,则加上标志DDCKEY_COLORSPACE。用surface->SetColorKey()设置色彩键。在blt时,则在backsurface->blt()中,加上DDBLT_KEYSRC标志。
依照惯例,先印屏
这是个3帧外星人图象。
结构体如下,分别说了3帧,位置和速度,目前帧,动画帧指针。
typedef struct ALIEN_OBJ_TYP
{
LPDIRECTDRAWSURFACE7 frames[3];
int x, y;
int velocity;
int current_frame;
int counter;
}ALIEN_OBJ, * ALIEN_OBJ_PTR;
加了几个函数
int Scan_Image_Bitmap(BITMAP_FILE_PTR bitmap, LPDIRECTDRAWSURFACE7 lpdds, int cx,int cy);
LPDIRECTDRAWSURFACE7 DDraw_Create_Surface(int width, int height, int mem_flags, int color_key);
int DDraw_Draw_Surface(LPDIRECTDRAWSURFACE7 source, int x, int y,
int width, int height, LPDIRECTDRAWSURFACE7 dest,
int transparent);
int Draw_Text_GDI(char *text, int x,int y,COLORREF color, LPDIRECTDRAWSURFACE7 lpdds);
设定了一个机器人数组和一个背景图片
ALIEN_OBJ aliens[3];
LPDIRECTDRAWSURFACE7 lpddsbackground = NULL;
int DDraw_Draw_Surface( LPDIRECTDRAWSURFACE7 source, int x, int y, int width, int height, LPDIRECTDRAWSURFACE7 dest, int transparent = 1 )
此函数就是从源矩形到目标矩形位置(x,y)的blt,并且判断是否为透明色
代码如下
int DDraw_Draw_Surface( LPDIRECTDRAWSURFACE7 source, int x, int y, int width, int height, LPDIRECTDRAWSURFACE7 dest, int transparent = 1 )
{
RECT dest_rect, source_rect;
dest_rect.left = x;
dest_rect.top = y;
dest_rect.right = x + width - 1;
dest_rect.bottom = y + height - 1 ;
source_rect.left = 0;
source_rect.top = 0;
source_rect.right = width - 1;
if( transparent )
{
if( FAILED( dest->Blt( & dest_rect, source, & source_rect, ( DDBLT_WAIT | DDBLT_KEYSRC ), NULL ) ) )
return ( 0 );
}
else
{
if( FAILED( dest->Blt( & dest_rect, source, & source_rect, ( DDBLT_WAIT ), NULL ) ) )
return ( 0 );
}
return ( 1 );
}
将位图信息读取到一个离屏表面上。
int Scan_Image_Bitmap( BITMAP_FILE_PTR bitmap, LPDIRECTDRAWSURFACE7 lpdds, int cx, int cy )
{
UCHAR * source_ptr, * dest_ptr;
DDSURFACEDESC2 ddsd;
ddsd.dwSize = sizeof( ddsd );
lpdds->Lock( NULL, & ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORY, NULL );
cx = cx * ( ddsd.dwWidth + 1 ) + 1;
cy = cy * ( ddsd.dwHeight + 1 ) + 1;
gwidth = ddsd.dwWidth;
gheight = ddsd.dwHeight;
source_ptr = bitmap->buffer + cy * bitmap->bitmapinfoheader.biWidth + cx;
dest_ptr = ( UCHAR * ) ddsd.lpSurface;
for( int index_y = 0; index_y < ddsd.dwHeight; index_y ++ )
{
memcpy( dest_ptr, source_ptr, ddsd.dwWidth );
dest_ptr += ( ddsd.lPitch );
source_ptr += bitmap->bitmapinfoheader.biWidth;
}
lpdds->Unlock( NULL );
return ( 1 );
}
下面创建离屏表面,带着颜色键,memory_flags指的是放到哪个内存(系统内存DDSCAPS_SYSTEMMEMORY或者显存DDSCAPS_VIDEOMEMORY )LPDIRECTDRAWSURFACE7 DDraw_Create_Surface( int width ,int height, int mem_flags, int color_key = 0 )
{
DDSURFACEDESC2 ddsd;
LPDIRECTDRAWSURFACE7 lpdds;
memset( & ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = width;
ddsd.dwHeight = height;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
lpdd->CreateSurface( & ddsd, & lpdds, NULL );
if( color_key >= 0 )
{
DDCOLORKEY color_key;
color_key.dwColorSpaceLowValue = 0;
color_key.dwColorSpaceHighValue = 0;
lpdds->SetColorKey( DDCKEY_SRCBLT, & color_key );
}
return lpdds;
}
下面就是写文字。
int Draw_Text_GDI( char * text, int x, int y, COLORREF color, LPDIRECTDRAWSURFACE7 lpdds )
{
HDC xdc;
lpdds->GetDC( & xdc );
SetTextColor( xdc, color );
SetBkMode( xdc, TRANSPARENT );
TextOut( xdc, x, y, text, strlen( text ) );
lpdds->ReleaseDC( xdc );
return 1;
}
在 GAME_MAIN()循环中,不再是缩定再复制,而是从离屏表面blt到内存中,再FLIP到主表面。在这个例子中,先把背景blt到后备缓冲,再把机器人移动位置计算好,blt机器人,最后都flip到主表面,sleep(30),
DDraw_Draw_Surface( lpddsbackground, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, lpddsback, 0 );
for( int index = 0; index < 3; index ++ )
{
aliens[index].x ++;
if( aliens[index].x > SCREEN_WIDTH )
aliens[index].x -= 80;
if( ++ aliens[index].counter >= ( 8 - aliens[index].velocity ) )
{
aliens[index].counter = 0;
if( ++ aliens[index].current_frame > 3 )
aliens[index].current_frame = 0;
}
}
for( int index = 0; index < 3; index ++ )
{
DDraw_Draw_Surface( aliens[index].frames[animation_seq[aliens[index].current_frame]],
aliens[index].x, aliens[index].y,
72, 80,
lpddsback );
}
while( FAILED( lpddsprimary->Flip( NULL, DDFLIP_WAIT ) ) );
Sleep( 30 );
在game_init()中,先加载了背景图片,并逐行扫描,
if( !Load_Bitmap_File( & bitmap, "alley8.bmp" ) )
return ( 0 );
lpddpal->SetEntries( 0, 0, MAX_COLORS_PALETTE, bitmap.palette );
lpddsbackground = DDraw_Create_Surface( 640, 480, 0, -1 );
UCHAR * image_buffer = ( UCHAR * ) ddsd.lpSurface;
if( ddsd.lPitch == SCREEN_WIDTH )
{
memcpy( ( void * ) image_buffer, ( void * ) bitmap.buffer, SCREEN_WIDTH * SCREEN_HEIGHT );
}
else
{
UCHAR * dest_ptr = image_buffer;
UCHAR * src_ptr = bitmap.buffer;
for( int y = 0; y < SCREEN_HEIGHT; y ++ )
{
memcpy( ( void * ) dest_ptr, ( void * ) src_ptr, SCREEN_WIDTH );
dest_ptr += ddsd.lPitch;
src_ptr += SCREEN_WIDTH;
}
}
lpddsbackground->Unlock( NULL );
Unload_Bitmap_File( & bitmap );
接下来产生随机数,
//产生随机数
srand( GetTickCount() );
再加载三个机器人。
aliens[0].x = rand() % SCREEN_WIDTH;
aliens[0].y = 116 -72;
aliens[0].velocity = 2 + rand() % 4;
aliens[0].current_frame = 0;
aliens[0].counter = 0;
aliens[1].x = rand() % SCREEN_WIDTH;
aliens[1].y = 246 - 72;
aliens[1].velocity = 2 + rand() % 4;
aliens[1].current_frame = 0;
aliens[1].counter = 0;
aliens[2].x = rand() % SCREEN_WIDTH;
aliens[2].y = 382 - 72;
aliens[2].velocity = 2 + rand() % 4;
aliens[2].current_frame = 0;
aliens[2].counter = 0;
for( int index = 0; index < 3; index ++ )
{
aliens[0].frames[index] = DDraw_Create_Surface( 72, 80, 0 );
Scan_Image_Bitmap( & bitmap, aliens[0].frames[index], index, 0 );
}
Unload_Bitmap_File( & bitmap );
for( int index = 0; index < 3; index ++ )
aliens[1].frames[index] = aliens[2].frames[index] = aliens[0].frames[index];
改掉几个笔误,终于运行OK了
现在看看如何封装这几个函数,到引擎中。
机器人结构属于特殊,故在main()函数里面写。
此时,出现问题,该问题是
在ddraw_init()中的
DDSCAPS2 ddscaps;,实际上,不应该这样弄,而是用ddsd.ddscaps,否则不是一回事。解决方法,直接删除变量ddscaps即可。
另外,ddsd随时使用,随时分配。.
现在进行下T3DLIB结合,到此时,应该是全屏图形有个大概了结了。
先看下,initdraw(),还有哪些没有弄进去的。发现除了窗口外,没有了。
DDraw_Attach_Clipper()一致了,
DDraw_Create_Surface()在设置色彩键时,更科学了,更改后一致了。
DDraw_Flip()一致
DDraw_Fill_Surface()基本一致
DDraw_Lock_Surface()一致。
DDraw_Unlock_Surface()一致。
DDraw_Lock_Back_Surface()一致,
DDraw_Lock_Primary_Surface()一致
DDraw_Unlock_Back_Surface()一致。
DDraw_Unlock_Primary_Surface()一致
Ddraw()接口函数,只剩下DDRAW_INIT()和DDRAW_SHUTDOWN()的窗口部分了。
位图部分:
Load_Bitmap_File()一致。
Flip_Bitmap()一致。
Draw_Text_GDI()一致