Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. Doggie
    Devshed Novice (500 - 999 posts)

    Join Date
    Jul 2003
    Location
    Seattle, WA
    Posts
    751
    Rep Power
    13

    Screen flicker with Windows API help


    I'm writting programs on Windows NT, using Codewarrior to display some animations. The animations are in a Windows window using standard Windows API calls.

    Of course, because of the refresh rate, the animations are flickering. I've checked all my documentation, and did searches online, but I can't seem to find information on how to do screen swapping, etc. for a window.

    I've found information on how to do it when in VGA full screen mode, but nothing on how to do it in a Windows enviroment. So far, I've just been putting up with it. But it'd be nice if I didn't get a headache everytime I ran one of my programs. :rolleyes:

    I'm sure there's a simple solution that I'll be hitting myself over. Heh

    Thanks for any help!
  2. #2
  3. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    i think what has to be done is creating an hDC buffer. you create a tmp HDC and draw the entire screen to it, then BitBlt() that hDC over your windows's hDC.
  4. #3
  5. Doggie
    Devshed Novice (500 - 999 posts)

    Join Date
    Jul 2003
    Location
    Seattle, WA
    Posts
    751
    Rep Power
    13
    I was working along those lines, but couldn't find how to make a temp hdc.

    Does bitblt automatically wait for the vertical retrace before copying?

    BTW: I recently had to reformat my computer, so I don't currently have my compiler installed at the moment. :( So I can't show what I've tried so far.

    Looking at my files, here's how I've been doing it: (pieced together from functions)
    Code:
    hPen=CreatePen(PS_SOLID,thickness,RGB(0,0,0));
    hdc=BeginPaint(hWnd, &pstruct);
    // create compatable hdc here?
    SelectObject(hdc, hPen);
    
    SetPixelV(hdc,x,y,RGB(rr,gg,bb));
    
    // bitblt here I assume
    EndPaint(hWnd, &pstruct );
    DeleteObject(hPen);
    If my assumptions are correct above, then all I need to know is how to create the temporary, compatable hdc.

    Ack! I'm looking all over for the source files I was experimenting with. Either I didn't save the changes, or I didn't back up the file.
  6. #4
  7. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    im on my bsd box right now, so i dont have the actual code i have written in front of me, but here is an excerpt from a tutorial that i reference:
    Code:
    void DrawBall(HDC hdc, RECT* prc)
    {
        HDC hdcBuffer = CreateCompatibleDC(hdc);
        HBITMAP hbmBuffer = CreateCompatibleBitmap(hdc, prc->right, prc->bottom);
        HBITMAP hbmOldBuffer = SelectObject(hdcBuffer, hbmBuffer);
    
        HDC hdcMem = CreateCompatibleDC(hdc);
        HBITMAP hbmOld = SelectObject(hdcMem, g_hbmMask);
    
        FillRect(hdcBuffer, prc, GetStockObject(WHITE_BRUSH));
    
        BitBlt(hdcBuffer, g_ballInfo.x, g_ballInfo.y, g_ballInfo.width, g_ballInfo.height, hdcMem, 0, 0, SRCAND);
    
        SelectObject(hdcMem, g_hbmBall);
        BitBlt(hdcBuffer, g_ballInfo.x, g_ballInfo.y, g_ballInfo.width, g_ballInfo.height, hdcMem, 0, 0, SRCPAINT);
    
        BitBlt(hdc, 0, 0, prc->right, prc->bottom, hdcBuffer, 0, 0, SRCCOPY);
    
        SelectObject(hdcMem, hbmOld);
        DeleteDC(hdcMem);
    
        SelectObject(hdcBuffer, hbmOldBuffer);
        DeleteDC(hdcBuffer);
        DeleteObject(hbmBuffer);
    }
  8. #5
  9. Doggie
    Devshed Novice (500 - 999 posts)

    Join Date
    Jul 2003
    Location
    Seattle, WA
    Posts
    751
    Rep Power
    13
    THANKS! I'll save that to my HD and try it out when I reinstall Codewarrior.
  10. #6
  11. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12
    Originally posted by dog135
    Does bitblt automatically wait for the vertical retrace before copying?
    No. You can prove this by calling it 1000's of times per second (with a small image), and seeing that they are all performed within a fraction of a second. This is faster than any monitor's refresh rate.
  12. #7
  13. Doggie
    Devshed Novice (500 - 999 posts)

    Join Date
    Jul 2003
    Location
    Seattle, WA
    Posts
    751
    Rep Power
    13
    Oh. So would that still cause screen flicker then? Or does bitblt at least NOT run while the screen's refreshing?

    I found my Codewarrior CD at home, but darn it, I forgot to bring it to work! How am I suppose to goof off at work without my Codewarrior CD? ;)
  14. #8
  15. pogremar
    Devshed Novice (500 - 999 posts)

    Join Date
    Jul 2003
    Location
    At Work
    Posts
    958
    Rep Power
    13
    lol. I hear you dog. Whenever I don't have anything to do at work, I program in visual C. My unknowing co-workers always think that this is a html IDE. I think they think is dreamweaver. I hope they don't ask me. Fools.
  16. #9
  17. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12
    Originally posted by dog135
    Oh. So would that still cause screen flicker then? Or does bitblt at least NOT run while the screen's refreshing?
    It runs with no regard to the current state of the retracing of the monitor. It doesn't wait to synch with it, nor does it wait to draw when it is not drawing.

    The possible flickering may be a result of having a background brush associated with your window. In this case, the OS automatically erases the background with this brush, and sends a WM_PAINT message for you to draw on it. This causes the background to temporarily be the color of the brush, up until you get the message and paint over it. If you are going to paint over the entire background every WM_PAINT message, there is no need to use a brush (unless what you are painting has 'see through' areas, which means you are NOT painting over the entire background).
  18. #10
  19. Doggie
    Devshed Novice (500 - 999 posts)

    Join Date
    Jul 2003
    Location
    Seattle, WA
    Posts
    751
    Rep Power
    13
    I currently capture the WM_Paint message to do my redrawing. It doesn't flicker as long as I don't redraw anything.

    On MouseMove, I call "InvalidateRect(hWnd, (LPRECT)NULL,TRUE);" to update the graphic, which is when the flicker occurs.

    The flicker also occurs on programs that use the timer ("SetTimer(hWnd, 1, 1, 0L)") for redrawing. In which case it shows classic "drawing while refreshing" type flicker.

    So you think if I don't use a brush, it'll stop flickering? I put the brush in there for some reason, though I don't remember why any more. I think the "LineTo" and "Ellipse" functions require it. (I wrote a single wrapper (class) for the graphic tools a few years ago)
  20. #11
  21. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12
    Originally posted by dog135
    On MouseMove, I call "InvalidateRect(hWnd, (LPRECT)NULL,TRUE);" to update the graphic, which is when the flicker occurs.
    You have 'true' for the last parameter which is the erase-background flag. Change this to false. Although, I think if you do not have a background brush (i.e. it is NULL), then this doesn't matter - since painting with a null brush is the same thing as not painting.

    What is the hbrBackground field in your WNDCLASS(EX) structure? This is the brush I am talking about. It should be NULL, unless you require the background to be erased before you draw, which means flickering. (of course, you can have a brush, and invalidate the rectangle with the erase background flag as false, and this is the same thing as not having a brush. I believe the only difference is when another window is moved out of the way - the background is erased immediately with the background brush if you have one, otherwise, whatever is there on the screen [the window border of the window just moved] will stay there. Finally when WM_PAINT is processed, whatever is drawn/left there will be overwritten). The brush required for drawing is not the background brush - it is another brush that you use to draw with. If it were the same brush, then you wouldn't be able to see what is drawn, since it is like drawing with a black pen on black paper.
  22. #12
  23. Doggie
    Devshed Novice (500 - 999 posts)

    Join Date
    Jul 2003
    Location
    Seattle, WA
    Posts
    751
    Rep Power
    13
    I don't set the hbrBackground property. So it's the default value.

    I'll attach my skeleton program if you want to see it. I don't expect you to read it, but it's small and you or someone else might find it usefull.

    skel.cpp - creates a window, sends events to app.h (windows)

    app.h - the application class (cross platform)

    gcross.h - graphical class (windows, standard tools for different platforms)

    Since I bring a lot of my work home, I have a Mac version of the Skel.cpp and gcross.h classes on my home computer. Then I just transfer the app.h and supporting files home. I can then recompile without modifying any code.
  24. #13
  25. Doggie
    Devshed Novice (500 - 999 posts)

    Join Date
    Jul 2003
    Location
    Seattle, WA
    Posts
    751
    Rep Power
    13
    Oops, I forgot the file! (edit doesn't allow me to add an attachment)
    Attached Files
  26. #14
  27. jasondoucette.com
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2003
    Location
    Canada
    Posts
    378
    Rep Power
    12
    Originally posted by dog135
    I don't set the hbrBackground property. So it's the default value.
    Yes, you do:

    Code:
    wc.hbrBackground	= (HBRUSH)GetStockObject( WHITE_BRUSH );
    If you didn't set it, then wouldn't it contain some random number? I think the least you should do when you do not set values it to fill the structure with 0's before setting the values you want.

    Again, if you do not need the background brush, try this:

    Code:
    wc.hbrBackground	= NULL;
    Or, pass FALSE as the final parameter to InvalidateRect()

    Let me know how it works.
  28. #15
  29. Doggie
    Devshed Novice (500 - 999 posts)

    Join Date
    Jul 2003
    Location
    Seattle, WA
    Posts
    751
    Rep Power
    13
    Oh, you're right, I do! How embarasing.

    Ok, I set it to NULL. That was a bad idea. My animation is still flickering, but my window now has a transparent background.

    I don't think the issue is the brush. It doesn't flicker off and on, it's a refresh type flicker, where the top with be animated in one frame, the the bottom animated in the next.

    What I need is a way to check, in Windows, for the screen refresh event. If I knew how to capture that, then I could do the bitblt only when the screen isn't refreshing.

    OH, BTW: I installed my compiler and tried your example. It worked, but it still had the flicker. The code will help me out though since it shows how to use bitblt properly. Thanks!
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo