A Simple, Flicker-Free 2D Animation Demo

Environment: VC6

This project generates a simple, flicker-free 2D animation demo. It loads two pictures—a background (big one) and a foreground (small one). The user can select and move the small picture over the big one without any flickering. Resizing the window does not produce any flickering of its contents, either. The idea is very simple and it could be used for different purposes. It could be implemented in different programming languages as well. I used it with Borland C++ Builder to create a multimedia picture slider for a catalogue program and Delphi to create a program for creating moving and resizing dialog box controls. Of course, it is better there to use "Canvas" rather than "Device context," but the principle is the same.

All the interesting code is located in xdrawView.h and xdrawView.cpp. It creates two memory dc and three bitmap objects:

  • CDC* m_PicDC;
  • CDC* m_CanvasDC;
  • CBitmap* m_BkgBitmap;
  • CBitmap* m_Bitmap;
  • CBitmap* m_CanvasBitmap;

The coordinates and size of the foreground picture on the screen are in the following code:

struct PICTURE
{
  CPoint topleft;       // top-left corner of the pic.
  int height, width;    // pic. width, height
};
PICTURE m_picture;

Background picture width and height:

int m_hBkg, m_wBkg;

When a user moves the foreground picture over the background one, the program calculates a "dirty rectangle." The "dirty rectangle" combines the new and old position of the foreground picture and sends it to be invalidated. The OnDraw() function is doing this flicker-free invalidation.

//---------------------------------------------------------------
// Draws a flicker-free content of the window—when requested.
//---------------------------------------------------------------
void CXdrawView::OnDraw(CDC* pDC)
{
// CXdrawDoc* pDoc = GetDocument();
// ASSERT_VALID(pDoc);
  // TODO: add draw code for native data here

  CBitmap* pOldBmp1;
  CBitmap* pOldBmp2;
  CRect cr;
  //selects canvas
  pOldBmp1 = m_CanvasDC->SelectObject(m_CanvasBitmap);
  //selects background, blits into canvas
  pOldBmp2 = m_PicDC->SelectObject(m_BkgBitmap);
  m_CanvasDC->BitBlt(0, 0, m_wBkg, m_hBkg, m_PicDC, 0, 0, SRCCOPY);
  //selects small pic, blits into canvas
  m_PicDC->SelectObject(m_Bitmap);
  m_CanvasDC->BitBlt(m_picture.topleft.x,
    m_picture.topleft.y,
    m_picture.width,
    m_picture.height,
    m_PicDC,
    0, 0, SRCCOPY);
  //blits canvas on screen. Well, only part of it—the
  // "dirty rectangle" part.
  pDC->GetClipBox(cr);
  pDC->BitBlt(cr.left, cr.top, cr.right, cr.bottom, m_CanvasDC,
                 cr.left, cr.top, SRCCOPY);
  //deselects all the bitmaps
  m_CanvasDC->SelectObject(pOldBmp1);
  m_PicDC->SelectObject(pOldBmp2);
}

//---------------------------------------------------------------
// if user clicks in the small picture, he captures this event
// for consecutive handling.
//---------------------------------------------------------------
void CXdrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
  CRect PicRc(m_picture.topleft,
    CPoint(m_picture.topleft.x + m_picture.width,
    m_picture.topleft.y + m_picture.height));
  if (PicRc.PtInRect(point))
  {
    SetCapture();
    m_Btndown = true;
    m_offs = point - m_picture.topleft;
    ::SetCursor(::LoadCursor(NULL, IDC_CROSS));
  }
}

//---------------------------------------------------------------
// Release user input.
//---------------------------------------------------------------
void CXdrawView::OnLButtonUp(UINT nFlags, CPoint point) 
{
  ::ReleaseCapture();
  m_Btndown = false;
}

//---------------------------------------------------------------
// if we have mouse down captured, then calculate a dirty rect
// that combines the old and new position of the small picture
// and invalidates it
//---------------------------------------------------------------
void CXdrawView::OnMouseMove(UINT nFlags, CPoint point)
{
  if (m_Btndown)
  {
    CRect DirtyRc = CalcDirtyRect(m_picture.width,
      m_picture.height,
      m_picture.topleft,
      point - m_offs);
    m_picture.topleft = point - m_offs;
    InvalidateRect(DirtyRc, false);
  }


}

//---------------------------------------------------------------
// calculates dirty rect. that combines 2 rect., expresing old
// and new position of the small picture.
//---------------------------------------------------------------
CRect CXdrawView::CalcDirtyRect(int pic_w, int pic_h,
                                CPoint p1, CPoint p2)
{
  CSize PicSize(pic_w,pic_h);
  CRect r1(p1,PicSize);
  CRect r2(p2,PicSize);

  return r1 | r2;
}

//---------------------------------------------------------------
// Try commenting my code and uncommenting the standard one,
// then try to resize the app. window to see the diference.
//---------------------------------------------------------------
BOOL CXdrawView::OnEraseBkgnd(CDC* pDC) 
{
  return false;
// return CView::OnEraseBkgnd(pDC);
// the original code
}

Downloads

Download demo project - 150 Kb
Download source - 82 Kb


Comments

  • My Game

    Posted by Legacy on 11/04/2002 12:00am

    Originally posted by: Tanatos

    I haven`t seen your sources yet, but I hope they`ll help me out with the problem I faced assembling my first GDI game. It flickers a lot when my game receives constant input from keyboard.
    P.S.
    I avoided the WM_PAINT already, but still the frame rate is low for the game...

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: March 19, 2015 @ 1:00 p.m. ET / 10:00 a.m. PT The 2015 Enterprise Mobile Application Survey asked 250 mobility professionals what their biggest mobile challenges are, how many employees they are equipping with mobile apps, and their methods for driving value with mobility. Join Dan Woods, Editor and CTO of CITO Research, and Alan Murray, SVP of Products at Apperian, as they break down the results of this survey and discuss how enterprises are using mobile application management and private …

  • Finance leaders have been talking about expanding the value-added role of their teams for a long time. The debate is no longer whether the finance and accounting function needs to become a more strategic partner to the rest of the business but rather how to get there. Technology innovation has caught up to this ambition, and what was once aspiration can be a reality – and the choice is now yours. Read this research report to learn how to make the most of information tools to enable innovation and growth.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date