内存DC是一种提高绘图效率,避免屏幕闪烁的好办法,几乎所有的绘图都必须使用到内存DC,可是在MSDN里一切都不是那么明显.
为了为以后的游戏制作更加顺利,我研究了一下内存DC的标准用法,然后贴在这里也是一个备忘.
其实所有的内存DC的原理都像下图所示:
要装载的图片 背景 蒙板 人物
| | |
| /
| /
| /
| /
+------------+
| 暂存DC1 |
+------|-----+
暂存DC2
|
操作窗口
简单解释一下这个图片,这里的两个暂存DC都是内存DC,他们的作用不同,第一个暂存DC是用来载入图片,而第二个则是当前屏幕在内存中的一个镜像(所有 的显示处理都先在这里处理),这就是所谓内存DC的原理了.
我们来看代码,首先我们在类的头文件中声明所有要使用的类,比如内存DC和位图.
{
public:
//内存DC(主DC,临时DC(用来装载位图))
CDC *m_PrimaryMemDC;
CDC *m_TempMemDC;
//位图对象
CBitmap *m_bgMap; //背景
CBitmap *m_bitMap; //人物
CBitmap *m_tempMap; //临时
CRect m_rect;
}
{
m_TempMemDC = new CDC;
m_PrimaryMemDC = new CDC;
m_bitMap = new CBitmap;
m_tempMap = new CBitmap;
m_bgMap = new CBitmap;
}
{
CClientDC dc(this);
//创建与内存兼容的DC
m_PrimaryMemDC->CreateCompatibleDC(&dc);
m_TempMemDC->CreateCompatibleDC(&dc);
//创建兼容位图
m_tempMap->CreateCompatibleBitmap(&dc,1024,768);
//装载位图
HBITMAP bitmap = (HBITMAP)::LoadImage(NULL,"pic/bgmap.bmp",
IMAGE_BITMAP,1024,768,
LR_LOADFROMFILE);
m_bgMap->Attach(bitmap);
bitmap = (HBITMAP)::LoadImage(NULL,"pic/AppExit_enu.bmp",IMAGE_BITMAP,61,67,
LR_LOADFROMFILE);
m_bitMap->Attach(bitmap);
//载入位图
m_PrimaryMemDC->SelectObject(m_tempMap);
return 0;
}
提醒一点就是创建兼容位图,然后把他载入内存DC中这个过程的理解,我是这么理解的只有你的DC中已经有了一张图片,然后才能够往上面贴图片.就像我们画 画的时候先要有一张白纸,然后才能画画.
还是拿画画做例子,再解释另外一个东西,使用SelectObject函数可以看成是换画纸,而BitBlt函数我们就可以看作是把其他画纸上的东西复印 到现在的这个画纸上,所以你的DC必须先有画纸才能用BitBlt.这也就是为什么我刚才试了很多次都不能BitBlt成功的原因.
再往下看,当然到了最关键的OnDraw函数了。
{
CMemDCTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
GetClientRect(&m_rect);
// TODO: add draw code for native data here
BITMAP map;
m_bgMap->GetBitmap(&map);
m_TempMemDC->SelectObject(m_bgMap);
m_PrimaryMemDC->BitBlt(0,0,map.bmWidth,map.bmHeight,m_TempMemDC,0,0,SRCCOPY);
//m_PrimaryMemDC->TextOut(0,0,"Hello");
m_bitMap->GetBitmap(&map);
m_TempMemDC->SelectObject(m_bitMap);
m_PrimaryMemDC->BitBlt(0,0,map.bmWidth,map.bmHeight,m_TempMemDC,0,0,SRCCOPY);
pDC->BitBlt(0,0,m_rect.Width(),m_rect.Height),m_PrimaryMemDC,0,0,SRCCOPY);
}
好了,这就是内存DC绘图的标准用法,只是繁琐,并不是很难,大家用的时候一定要细心再细心,特别是对于选择默认位图的部分,很容易遗漏。