Сообщений 6 Оценка 25 Оценить |
Двойная буферизация с использованием GDI+ Двойная буферизация с использованием GDI |
В статье Виталия Брусенцева GDI+: графика нового поколения приводится пример устранения мерцания при помощи двойной буферизации в Win32 приложении (Demo.exe):
void OnPaint(HDC hdc, RECT& rc)
{
Graphics g(hdc);
Rect paintRect(0, 0, rc.right, rc.bottom);
Bitmap backBuffer(rc.right, rc.bottom, &g);
Graphics temp(&backBuffer);
PaintBackground(temp, paintRect);
PaintFlower(temp, paintRect);
PaintBatterfly(temp, paintRect);
g.DrawImage(&backBuffer, 0, 0, 0, 0, rc.right, rc.bottom, UnitPixel);
}
|
Я попробовал написать однооконное MFC приложение, которое рисовало бы то же самое, что и в примере Виталия Брусенцова Demo.exe (бабочка, летящая за цветком). В этом случае функция OnPaint() выглядит так:
Пример Anim1.void CAnim1View::OnPaint() { CPaintDC dc(this); // TODO: Add your message handler code here Graphics g(this->m_hWnd,true); Bitmap backBuffer(winRect.right, winRect.bottom, &g); Graphics temp(&backBuffer); OnDrawMy(temp); g.DrawImage(&backBuffer, 0, 0, 0, 0, winRect.right, winRect.bottom, UnitPixel); } |
Где функция OnDrawMy(Graphics& g) для рисования в стиле GDI+:
void CAnim1View::OnDrawMy(Graphics& g){ // Рисование в стиле GDI+ if(bBackGround){ WCHAR text[]=L"Демонстрация работы \n" L"с прозрачными \n" L"и анимированными \n" L"файлами формата GIF."; HatchBrush brush(HatchStyleCross, Color(255, 140, 140, 255), Color(255, 200, 200, 200)); g.FillRectangle(&brush,winRectF); Font font(L"Arial", 20); SolidBrush textBrush1(Color(180, 0, 0, 255)); StringFormat stringFormat1; stringFormat1.SetAlignment(StringAlignmentCenter); stringFormat1.SetLineAlignment(StringAlignmentCenter); g.DrawString(text, -1, &font, PointF((winRectF.Width/2), (winRectF.Height/2)), &stringFormat1, &textBrush1); } else g.Clear(Color(255, 255, 255, 255)); if(pf.X-bpf.X>0) bpf.X++; else bpf.X--; if(pf.Y-bpf.Y>0) bpf.Y++; else bpf.Y--; if(flower){ g.DrawImage(flower,pf.X,pf.Y); } if(image){ image->SelectActiveFrame(&FrameDimensionTime, activeFrame); g.SetInterpolationMode(InterpolationModeHighQualityBicubic); g.DrawImage(image,bpf.X, bpf.Y, (REAL)image->GetWidth(), (REAL)image->GetHeight()); activeFrame=(activeFrame+1)%frameCount; } } |
Функция, учитывающая изменение размеров окна:
void CAnim1View::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); // TODO: Add your message handler code here winRect.SetRect(0,0,cx,cy); winRectF = RectF(0,0,(REAL)cx,(REAL)cy); } |
После запуска приложения стало ясно, что FPS (количество кадров в секунду) по сравнению с Win32 приложением несколько снизилось.
Данные приведены в таблице.
Тогда я попробовал применить двойную буферизацию, используемую в обычном GDI. Для этого использовал объекты CDC *m_pdcDisplayMemory и CBitmap *m_pBitmap. В этом случае конструктор и деструктор CAnim2View:
Пример Anim2.CAnim2View::CAnim2View() { m_pdcDisplayMemory = 0;//new CDC m_pBitmap = 0;//new CBitmap .. .. } CAnim2View::~CAnim2View() { if(m_pBitmap)delete m_pBitmap; if(m_pdcDisplayMemory) delete m_pdcDisplayMemory; } |
Функция рисования OnPaint():
void CAnim2View::OnPaint() { CPaintDC dc(this); CRect rectUpdate; dc.GetClipBox(&rectUpdate); CBitmap* pOldBitmap = m_pdcDisplayMemory->SelectObject(m_pBitmap); m_pdcDisplayMemory->PatBlt(rectUpdate.left, rectUpdate.top, rectUpdate.Width(), rectUpdate.Height(), PATCOPY); OnDraw(m_pdcDisplayMemory); dc.BitBlt(rectUpdate.left, rectUpdate.top, rectUpdate.Width(), rectUpdate.Height(), m_pdcDisplayMemory, rectUpdate.left, rectUpdate.top, SRCCOPY); } |
В этом случае используется также и функция OnDraw(CDC* pDC):
void CAnim2View::OnDraw(CDC* pDC) { .. .. Graphics *pgr = Graphics::FromHDC(pDC->m_hDC); OnDrawMy(*pgr); delete pgr; } |
Функция OnDrawMy(Graphics& g) используется та же, что и в предыдущем примере.
Функция, учитывающая изменение размеров окна:
void CAnim2View::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); // TODO: Add your message handler code here winSizeX = cx; winSizeY = cy; if(m_pBitmap)delete m_pBitmap; if(m_pdcDisplayMemory) delete m_pdcDisplayMemory; m_pdcDisplayMemory = new CDC; m_pBitmap = new CBitmap; CRect winRect(0,0,winSizeX,winSizeY); winRectF = RectF(0,0,(REAL)winSizeX,(REAL)winSizeY); if (m_pdcDisplayMemory->GetSafeHdc() == NULL) { CClientDC dc(this); m_pdcDisplayMemory->CreateCompatibleDC(&dc); m_pBitmap->CreateCompatibleBitmap(&dc, winRect.right,winRect.bottom); } } |
После того, как это было сделано, выяснилось, что перерисовка экрана пошла значительно быстрее. Особенно это заметно, когда отключается отрисовка background. В случае использования двойной буферизации в стиле GDI+ отключение background практически не увеличивает FPS.
То есть, если требуется написать графическое приложение с использованием линий, “резиновых нитей”, небольших картинок и пр. можно использовать удобство GDI+ и двойную буферизацию в стиле GDI.
С отрисовкой background | Без background | |
Demo (Win32) | 9 | 10 |
Anim1(MFC) | 5 | 5 |
Anim2(MFC) | 11 | 100 |
С отрисовкой background | Без background | |
Demo (Win32) | 54 | 65 |
Anim1(MFC) | 24 | 26 |
Anim2(MFC) | 60 | 64 |
С отрисовкой background | Без background | |
Demo (Win32) | 13 | 15 |
Anim1(MFC) | 6 | 6 |
Anim2(MFC) | 10 | 40 |
Сообщений 6 Оценка 25 Оценить |