2013年6月24日星期一(离屏表面blitter)

来源:互联网 发布:仿淘宝app首页 编辑:程序博客网 时间:2024/05/18 03:47

粗略看了一下,感觉这章也是个大餐,把所有以前的全屏过程综合起来了。

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()一致