Ramilol
Ramilol

Reputation: 3462

Help with double-buffering

I have created an animation which works fine, but it flicks. I need help with double-buffering since I don't know anything about it.

This is the code in my onPaint():

VOID onPaint(HDC hdc)
{
    Graphics graphics(hdc);
    Pen      pen(Color(255, 0, 0, 255));
    graphics.DrawEllipse(&pen, sf , 0, 10, 10);
}

It works fine but with flicker. I tried this code but it didn't work:

VOID onPaint(HDC hdc,HWND hWnd)
{
    HDC hDC=GetDC(hWnd);;
    HDC memDC = CreateCompatibleDC(hDC);
    HBITMAP hMemBmp = CreateCompatibleBitmap(hDC,10,10);
    HBITMAP hOldBmp =  (HBITMAP)SelectObject(memDC,hMemBmp);
    BitBlt(hDC, 0, 0, 10, 10, memDC, 0, 0, SRCCOPY);
    Graphics graphics(memDC);
    Pen      pen(Color(255, 0, 0, 255));
    graphics.DrawEllipse(&pen, sf , 0, 10, 10);

    // Always select the old bitmap back into the device context
    SelectObject(memDC, hOldBmp);
    DeleteObject(hMemBmp);
    DeleteDC(memDC);
}

Upvotes: 2

Views: 4103

Answers (1)

JustJeff
JustJeff

Reputation: 12980

It looks like you're just prematurely copying the offscreen DC to the display. Try moving the call to BitBlt down four lines, to make it the last line before you start the clean-up, like so:

VOID onPaint(HDC hdc,HWND hWnd)
{
    // this line looks a little odd :
    HDC hDC = GetDC(hWnd);
    // .. usually the hdc parameter passed to onPaint would already refer to
    // the on-screen DC that windows wants updated. Also worth noting is that
    // when you use GetDC(), you should have a matching ReleaseDC()
    // As a quick test, you might just replace the above line with
    //     HDC hDC = hdc;

    HDC memDC = CreateCompatibleDC(hDC);
    HBITMAP hMemBmp = CreateCompatibleBitmap(hDC,10,10);
    HBITMAP hOldBmp =  (HBITMAP)SelectObject(memDC,hMemBmp);

    // draw to the off-screen map ..
    Graphics graphics(memDC);
    Pen      pen(Color(255, 0, 0, 255));
    graphics.DrawEllipse(&pen, sf , 0, 10, 10);

    // now that you've drawn on the offscreen map, go ahead
    // and put it on screen.
    BitBlt(hDC, 0, 0, 10, 10, memDC, 0, 0, SRCCOPY);

    // Always select the old bitmap back into the device context
    SelectObject(memDC, hOldBmp);
    DeleteObject(hMemBmp);
    DeleteDC(memDC);
}

Another thing about this code, you've passed the constant '10' as the width and height of your off-screen bitmap, as well as using it for the width and height params to the BitBlt() that does the copy. Chances are the window client area being updated is very much larger than that. The 'black square' is a consequence of blitting the 10x10 off-screen map onto the window client area. Instead of hard-coding 10 there, you might try using another GDI function to obtain the dimensions of the on-screen bitmap, or at the very least you could #define width and height values, and use these in the params.

The other thing killing you is probably the 'sf' in the line "graphics.DrawEllipse(&pen, sf , 0, 10, 10)" -- since you've created an incredibly tiny 10x10 map, if the value of 'sf' is anything outside of 0..10, the DrawEllipse() call will place the ellipse entirely outside of the available pixels in your offscreen map.

So, bottom line, you probably want to make the offscreen map the same size as the window client area, and be sure to move the BitBlt() call down so that it happens after all the drawing ops on the off-screen map.

Upvotes: 9

Related Questions