这一节是个大餐,加上了位图。最主要的一点,是我知道了,不一定要按照字符串读取的方法,而是根据标识去做,
定义了位图标识
#define BITMAP_ID 0x4D42
位图(.BMP文件),分为几部分,位图文件头
typedef struct BITMAP_FILE_TAG
{
BITMAPFILEHEADER bitmapfileheader; //位图文件头
BITMAPINFOHEADER bitmapinfoheader;//位图信息头
PALETTEENTRY palette[256]; //调色板
UCHAR * buffer; //位图实际数据缓冲
}BITMAP_FILE, * BITMAP_FILE_PTR;
加了4个函数
int Flip_Bitmap( UCHAR * image,int bytes_per_line, int height );
int Load_Bitmap_File( BITMAP_FILE_PTR bitmap,char * filename );
int Unload_Bitmap_File( BITMAP_FILE_PTR bitmap );
int DDraw_Fill_Surface( LPDIRECTDRAWSURFACE7 lpdds,int color );
位图句柄
BITMAP_FILE bitmap;
加载位图过程,首先打开文件,读取位图文件头,如果是位图标识,则继续读取位图信息头。如果有调色板,则加载,并将调色板中的RB颜色互换,最后加载位图数据。在函数中,是适合于8,16,24位位图,方法是按照字节分配内存,并读进位图文件。然后关闭文件句柄,逐行读入位图。
加载位图代码如下:
int Load_Bitmap_File( BITMAP_FILE_PTR bitmap,char * filename )
{
int file_handle, index;
UCHAR * temp_buffer = NULL; //用来将位位图转为位
OFSTRUCT file_data; //文件数据信息
if( ( file_handle = OpenFile( filename, & file_data, OF_READ ) ) == -1 ) //打开文件
return ( 0 );
//读取位图文件头
_lread( file_handle, & bitmap->bitmapfileheader, sizeof( BITMAPFILEHEADER ) );
if( bitmap->bitmapfileheader.bfType != BITMAP_ID )
{
_lclose( file_handle );
return ( 0 );
}
_lread( file_handle, & bitmap->bitmapinfoheader, sizeof( BITMAPINFOHEADER ) );
//如果有颜色调色板,则加载
if( bitmap->bitmapinfoheader.biBitCount == 8 )
{
_lread( file_handle, & bitmap->palette, MAX_COLORS_PALETTE *sizeof( PALETTEENTRY ) );
//将调色板RB颜色互换
for( index = 0; index < MAX_COLORS_PALETTE; index ++ )
{
int temp_color = bitmap->palette[index].peRed;
bitmap->palette[index].peRed = bitmap->palette[index].peBlue;
bitmap->palette[index].peBlue = temp_color;
bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
}
}
//最后加载位图数据
_lseek( file_handle, - ( int ) ( bitmap->bitmapinfoheader.biSizeImage ), SEEK_END );
//在这里以指针形式可以读取,16,24位位图
if( bitmap->bitmapinfoheader.biBitCount == 8 || bitmap->bitmapinfoheader.biBitCount == 16 || bitmap->bitmapinfoheader.biBitCount == 24 )
{
if( bitmap->buffer )
free( bitmap->buffer );
//按照字节为位图分配内存
if( ! ( bitmap->buffer = ( UCHAR * ) malloc( bitmap->bitmapinfoheader.biSizeImage ) ) )
{
_lclose( file_handle );
return ( 0 );
}
//现在读进位图
_lread( file_handle, bitmap->buffer, bitmap->bitmapinfoheader.biSizeImage );
}
else
{
return ( 0 );
}
_lclose( file_handle );
Flip_Bitmap( bitmap->buffer, bitmap->bitmapinfoheader.biWidth * ( bitmap->bitmapinfoheader.biBitCount / 8 ), bitmap->bitmapinfoheader.biHeight );
return ( 1 );
}
在这里,疑问其实很多,
第一, 位图文件头有哪些?
Typedef struct tagBITMAPFILEHEADER
{
WORD bfType; //文件类型,.bmp必须是0x4D42
DWORD bfSize; //指定位图文件字节数
WORD bfReserved1; //保留字段,必须为0
WORD bfReserved2; //保留字段,必须为0
DWORD bfOffBits; //指定从文件头结构到 位图位数的偏移量
} BITMAPFILEHEADER;
第二, 位图信息段有哪些
Typedef struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader; //位图信息头
RGBQUAD bmiColors[1]; //调色板(如果有的话)
} BITMAPINFO;
位图信息头的结构
Typedef struct tagBITMAPINFOHEADER
{
WORD biSize; //指定位图信息头的结构字节数
LONG biWidth; //指定位图宽度像素数
LONG biHeight; //指定位图高度像素数,如果为正,则位图是自下到上,起点在左下角;如果为负,则位图是自上到下,起点在左上角。
WORD biPlanes; //指定颜色板数,必须为1
WORD biBitCount; //指定每像素的位数,必须是1,4,8,16,24,或者32
DWORD biCompression; //指定位图压缩类型,必须是BI_RGB
DWORD biSizeImage; //位图字节数
DWORD biXPelsPerMeter; //指定X轴的每米像素数
DWORD biYPelsPerMeter; //指定Y轴的每米像素数
DWORD biClrUsed ; //指定位图使用的颜色数
DWORD biClrImportant; //指定重要的颜色数
} BITMAPINFOHEADER;
第三,加载位图时为何RB互换?
因为位图调色板项RGBQUAD,是正常的PALETTEENTRYS的倒序
Typedef struct tagRGBQUAD
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved; //未用
} RGBQUAD;
下面进行
//处理上下颠倒的位图
int Flip_Bitmap( UCHAR * image, int bytes_per_line, int height )
{
UCHAR * buffer;
int index;
if( ! ( buffer = ( UCHAR * ) malloc( bytes_per_line * height ) ) )
return ( 0 );
memcpy( buffer, image, bytes_per_line * height );
for( index = 0; index < height; index ++ )
memcpy( & image[ ( ( height - 1 ) - index ) * bytes_per_line], & buffer[index * bytes_per_line], bytes_per_line );
free( buffer );
return ( 1 );
}
下面是清屏函数
int DDraw_Fill_Surface( LPDIRECTDRAWSURFACE7 lpdds,int color )
{
DDBLTFX ddbltfx;
DDRAW_INIT_STRUCT( ddbltfx );
ddbltfx.dwFillColor = color;
lpdds->Blt( NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, & ddbltfx );
return ( 1 );
}
Game_main()是逐行读取像素,
在设置DDRAW的调色板时,用到自己的调色板图像,用setentries().
但是,运行后代码不对。7-11,7-12代码复制过来也有问题。回来再在网上查下。注释掉下句OK
// _lseek( file_handle, - ( int ) ( bitmap->bitmapinfoheader.biSizeImage ), SEEK_END );