在游戏编程中,位图的处理是一个重要的环节,我将结合这几天我们小组制作游戏的具体情况,简单介绍一下我们小组对位图的处理方法。
首先我们采用的当然是双缓存策略,就是在缓存里面画好图后在用bitblt映射到client上,我们用的图片是bmp文件,采用的是设备无关位图,所以首先创建一个class DIBSection,用来操纵DIB,这里我们参考的是坂本千寻所写的一个类库。
我们定义一个位图头文件结构
struct {
BITMAPINFOHEADER Info;
DWORD BitField[3];
} Header; //位图头文件结构
然后进行DIBSection的创建,使用函数如下:
BOOL CDibSection::Create(int width, int height, int depth)
{
bytes_per_line = ScanBytes(width, depth);
bytes_per_pixel = PixelBytes(depth);
Header.Info.biSize = sizeof(BITMAPINFOHEADER);
Header.Info.biWidth = width;
Header.Info.biHeight = height;
Header.Info.biBitCount = depth;
Header.Info.biPlanes = 1;
Header.Info.biXPelsPerMeter = 0;
Header.Info.biYPelsPerMeter = 0;
Header.Info.biClrUsed = 0;
Header.Info.biClrImportant = 0;
Header.Info.biCompression = depth == 24? BI_RGB: BI_BITFIELDS;
Header.Info.biSizeImage = bytes_per_line * height;
switch (depth) {
case 16:
Header.BitField[0] = 0x7c00;
Header.BitField[1] = 0x03e0;
Header.BitField[2] = 0x001f;
break;
case 32:
Header.BitField[0] = 0xff0000;
Header.BitField[1] = 0x00ff00;
Header.BitField[2] = 0x0000ff;
break;
default:
Header.BitField[0] = 0;
Header.BitField[1] = 0;
Header.BitField[2] = 0;
break;
}
HDC dc = ::GetDC(0);
hBitmap = CreateDIBSection(dc, (BITMAPINFO *)&Header, DIB_RGB_COLORS, &Bits, NULL, 0);
::ReleaseDC(0, dc);
return hBitmap != 0;
}
在这个函数中,其实就是调用了CreateDIBSection的API来创建了一个DIBSection,该函数需要有一个BITMAPINFO结构体,具体的请自行参照MSDN。在这个函数中,可以实现16,24,以及32位位图的创建,在创建24为位图时biCompression需要设置成BI_RGB,且紧跟在BITMAPINFO后的色盘位字段为0。
然后就是显示BMP文件,Windows有一个自带的函数LoadImage,可是他的功能太过于强大,不能知道很多位图文件的内部信息,但只是可以使用GetObject,就可以从读入的图片中取得想要的信息,同时我们用GetModuleHandle取得调用LoadImage的实体代号,故函数如下:
//位图资源加载
BOOL CDibSection::LoadBmp(const char *path)
{
Destroy();
hBitmap = (HBITMAP)::LoadImage(::GetModuleHandle(0), path, IMAGE_BITMAP, 0, 0,
LR_CREATEDIBSECTION | LR_LOADFROMFILE);
if (!hBitmap)
return FALSE;
DIBSECTION dib;
if (::GetObject(hBitmap, sizeof(DIBSECTION), &dib) != sizeof(DIBSECTION)) {
::DeleteObject(hBitmap);
hBitmap = 0;
return FALSE;
}
Header.Info = dib.dsBmih;
for (int i=0; i<3; i++)
Header.BitField[i] = dib.dsBitfields[i];
bytes_per_pixel = PixelBytes(dib.dsBmih.biBitCount);
bytes_per_line = ScanBytes(dib.dsBmih.biWidth, dib.dsBmih.biBitCount);
Bits = dib.dsBm.bmBits;
return TRUE;
}
在我们通过一个bitblt函数,就可以把图像画到client上,Draw函数如下,
//图像绘制
inline void CDibSection::Draw(HDC dc, int x, int y, int w, int h, int ox, int oy)
{
BitBlt(dc, x, y, w, h, CDibDC(*this, dc), ox, oy, SRCCOPY);
}
inline void CDibSection::Draw(HDC dc, const CRect &rect, CPoint point)
{
Draw(dc, rect.left, rect.top, re