July 10th, 2003, 12:06 PM
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!
July 10th, 2003, 01:37 PM
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.
July 11th, 2003, 12:42 PM
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)
If my assumptions are correct above, then all I need to know is how to create the temporary, compatable hdc.
// create compatable hdc here?
// bitblt here I assume
EndPaint(hWnd, &pstruct );
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.
July 11th, 2003, 12:48 PM
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:
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);
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);
July 11th, 2003, 02:16 PM
THANKS! I'll save that to my HD and try it out when I reinstall Codewarrior.
July 12th, 2003, 12:07 PM
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.
July 15th, 2003, 11:57 AM
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? ;)
July 15th, 2003, 01:12 PM
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.
July 15th, 2003, 02:30 PM
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).
July 15th, 2003, 04:16 PM
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)
July 16th, 2003, 08:34 AM
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.
July 16th, 2003, 05:43 PM
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.
July 16th, 2003, 05:44 PM
Oops, I forgot the file! (edit doesn't allow me to add an attachment)
July 18th, 2003, 09:48 AM
Yes, you do:
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.
wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
Again, if you do not need the background brush, try this:
Or, pass FALSE as the final parameter to InvalidateRect()
wc.hbrBackground = NULL;
Let me know how it works.
July 18th, 2003, 12:05 PM
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!