32BPP窗口模式下24位位图的像素操作(1)

刚学习了几天DirectDraw,书中作者示例多是8位调色板的全屏程序,而且是读取8位位图,可以很方便的使用SetDisplayMode来改变显示模式,按字节写入像素。而在窗口模式中,现在普遍的32BPP和使用24位位图就没有那么方便了,而且书中没有很完整的示例。

使用窗口模式的DirectDraw主要有以下几个问题:

1.24位位图的像素格式到32位像素格式的转换

2.不能使用Flip,需要使用Blt从离屏表面来复制到主显示表面。

3.确定真正的用户窗口。

4.剪裁。

后3个问题书中给了很好的示例,但是对于第1点,像素操作没有说的太多,作者的意思是不要立刻陷于技术细节。但是在今天我想独立写一个窗口的DD程序时确实遇到像素操作上的问题。

0.本来我是这样想的

24位位图数据区[RR][GG][BB] ……

映射在32位BPP的每个像素时在前面的A位补零即可:[00][RR][GG][BB]

但却出现了颜色怎么都不对的情况。

1.24位位图的数据区是如何存放的

位图的14Bytes+40Bytes+4*nBytes的三个头就不说了。直接用_lread或者ReadFile读入Microsoft相应的结构就OK了。因为颜色不对,所以我用UltraEdit查看了一个我画的全紫色的24位位图,数据区如下:

[FF][00][80] ……

查了一下颜色表,等于是:

[BB][GG][RR]。

可以发现,顺序与RGB正相反。

2.显示表面的像素格式

于是修改程序,在显示表面也反序写入:

[BB][GG][RR][AA] ……

试验成功。

3.用法

使用宏,生成一个DWORD:

#define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))

_RGB32BIT(0, 128, 0, 255) 等价于 00 80 00 FF。

由于是littleendian,所以这个DWORD在内存的表示顺序是 [FF][00][80][00]。

使用下面的语句就可以在(x,y)上进行相应对24位位图的着色:

for (int y = 0; y < SCREEN_HEIGHT; ++y) { for (int x = 0; x < SCREEN_WIDTH; ++x) { UCHAR blue = (bitmap.buffer[y*SCREEN_WIDTH*3 + x*3 + 0]), green = (bitmap.buffer[y*SCREEN_WIDTH*3 + x*3 + 1]), red = (bitmap.buffer[y*SCREEN_WIDTH*3 + x*3 + 2]); DWORD pixel = _RGB32BIT(0,red,green,blue); *((DWORD *)(video_buffer + x*4 + y*mempitch)) = pixel; } }

4.补充

上面的代码只适用于位图像素宽度为4的倍数的情况,而当位图像素个数不是4的倍数则会在每行补适当的0,所以在计算索引时要有相应的改动,下面的代码实现了将按bmp中倒行排序的buffer转成正常顺序,并且计算了补零,读取一个BITMAP24的示例。

typedef struct BITMAP24_TYP { BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; UCHAR *buffer; } BITMAP24, *BITMAP24_PTR; int LoadBitmap24(BITMAP24_PTR bitmap, char *fileName) { HANDLE hFile; DWORD dwBytesRead = 0; hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { return 0; } if( FALSE == ReadFile(hFile, &(bitmap->fileHeader), sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL) ) { CloseHandle(hFile); return 0; } if( FALSE == ReadFile(hFile, &(bitmap->infoHeader), sizeof(BITMAPINFOHEADER), &dwBytesRead, NULL) ) { CloseHandle(hFile); return 0; } UCHAR *orgBuffer = (UCHAR *)malloc(bitmap->infoHeader.biSizeImage); if( FALSE == ReadFile(hFile, orgBuffer, bitmap->infoHeader.biSizeImage, &dwBytesRead, NULL) ) { CloseHandle(hFile); return 0; } CloseHandle(hFile); LONG pixelWidth = bitmap->infoHeader.biWidth; LONG pixelHeight = bitmap->infoHeader.biHeight; LONG rowByteWidth; if (pixelWidth % 4 == 0) { rowByteWidth = pixelWidth * 3; } else { rowByteWidth = pixelWidth * 3 + (pixelWidth % 4); } bitmap->buffer = (UCHAR *)malloc(pixelWidth * pixelHeight * 4); for (int y = 0; y < pixelHeight; ++y) { for (int x = 0; x < pixelWidth; ++x) { UCHAR blue = orgBuffer[y * rowByteWidth + x * 3 + 0]; UCHAR green = orgBuffer[y * rowByteWidth + x * 3 + 1]; UCHAR red = orgBuffer[y * rowByteWidth + x * 3 + 2]; DWORD pixel = _RGB32BIT(0, red, green, blue); *((DWORD *)(bitmap->buffer + x * 4 + (pixelHeight - y - 1) * pixelWidth * 4)) = pixel; } } free(orgBuffer); return 1; } void UnloadBitmap24(BITMAP24_PTR bitmap) { free(bitmap->buffer); bitmap->buffer = NULL; }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值