我原来的代码是这么写的
HDC hdc,hMemDC;
hMemDC = ::CreateCompatibleDC(hdc);
HBITMAP hbmp = ::CreateCompatibleBitmap(hdc);
HBITMAP holdbmp = ::SelectObject(hMemDC,hbmp);
//draw something on the memory dc
::SetPixel(hMemDC,x,y,RGB(r,g,b);
BitBlt(hdc,...,hMemDC...);
::SelectObject(hMemDC,hOldbmp);
DeleteObject(hbmp);
DeleteDC(hMemDC);
一般的绘图都是这么干。本来我以为setpixel的第1个参数传memdc应该会快点,以为是用的直接象素存取。实际
上它做的事情远不是这么点,看书上实现,先要取得dc的属性,然后还有一些事情要做,最后才给象素上色,
应该还有个状态转换,能不慢嘛。书上说的比较快的方法是用CreateDibSection 这个来做。这样就可以在用户态
进行直接象素存取了。速度应该是原来的好几倍(应该会在10倍以上)。mesa里面的代码就这么干的。我把它摘抄下来。
struct wmesa_framebuffer
{
struct gl_framebuffer Base;
HDC hDC;
int pixelformat;
GLuint ScanWidth;
BYTE cColorBits;
/* back buffer DIB fields */
HDC dib_hDC;
BITMAPINFO bmi;
HBITMAP hbmDIB;
HBITMAP hOldBitmap;
PBYTE pbPixels;
struct wmesa_framebuffer *next;
};
typedef struct wmesa_framebuffer *WMesaFramebuffer;
BOOL wmCreateBackingStore(WMesaFramebuffer pwfb, long lxSize, long lySize)
{
HDC hdc = pwfb->hDC;
LPBITMAPINFO pbmi = &(pwfb->bmi);
HDC hic;
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = lxSize;
pbmi->bmiHeader.biHeight= -lySize;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = GetDeviceCaps(pwfb->hDC, BITSPIXEL);
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = 0;
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
pwfb->cColorBits = pbmi->bmiHeader.biBitCount;
pwfb->ScanWidth = (lxSize * (pwfb->cColorBits / 8) + 3) & ~3;
hic = CreateIC("display", NULL, NULL, NULL);
pwfb->dib_hDC = CreateCompatibleDC(hic);
pwfb->hbmDIB = CreateDIBSection(hic,
&pwfb->bmi,
DIB_RGB_COLORS,
(void **)&(pwfb->pbPixels),
0,
0);
pwfb->hOldBitmap = SelectObject(pwfb->dib_hDC, pwfb->hbmDIB);
DeleteDC(hic);
wmSetPixelFormat(pwfb, pwfb->hDC);
return TRUE;
}
static void wmSetPixelFormat(WMesaFramebuffer pwfb, HDC hDC)
{
pwfb->cColorBits = GetDeviceCaps(hDC, BITSPIXEL);
// Only 16 and 32 bit targets are supported now
assert(pwfb->cColorBits == 0 ||
pwfb->cColorBits == 16 ||
pwfb->cColorBits == 32);
switch(pwfb->cColorBits){
case 8:
pwfb->pixelformat = PF_INDEX8;
break;
case 16:
pwfb->pixelformat = PF_5R6G5B;
break;
case 32:
pwfb->pixelformat = PF_8R8G8B;
break;
default:
pwfb->pixelformat = PF_BADFORMAT;
}
}
static wmDeleteBackingStore(WMesaFramebuffer pwfb)
{
if (pwfb->hbmDIB) {
SelectObject(pwfb->dib_hDC, pwfb->hOldBitmap);
DeleteDC(pwfb->dib_hDC);
DeleteObject(pwfb->hbmDIB);
}
}
这样原来的setpixel可以这么写了
#define BGR16(r,g,b) ( (((unsigned short)b ) >> 3) | /
(((unsigned short)g & 0xf8) << 2) | /
(((unsigned short)r & 0xf8) << 7) )
#define BGR32(r,g,b) (unsigned long)((DWORD)(((BYTE)(b)| /
((WORD)((BYTE)(g))<<8))| /
(((DWORD)(BYTE)(r))<<16)))
#define WMSETPIXEL16(pwc, y, x, r, g, b) { /
LPWORD lpw = ((LPWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); /
*lpw = BGR16((r),(g),(b)); }
#define WMSETPIXEL32(pwc, y, x, r, g, b) { /
LPDWORD lpdw = ((LPDWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); /
*lpdw = BGR32((r),(g),(b)); }
void SetPixel(WMesaFramebuffer pwfb,int x,int y,DWORD clr)
{
if(pwfb->pixelformat == PF_5R6G5B){
WMSETPIXEL16(pwfb,x,pwfb->y,clr);
}
else if(pwfb->pixelformat ==PF_8R8G8B){
WMSETPIXEL32(pwfb,x,y,clr);
}
}
以前有个裂缝。后来看书说是要遵守一个填充规则。比较重要的一点是刚开始的时候一定全部转浮点数进去,到
最后一步再转成int。这样结果就会比较理想。昨天把纹理改了下。现在基本上算比较完善了。速度也还可以。
这周基本上就可以做完原来的计划了。