News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Need som expertise here

Started by CodeDog, October 12, 2012, 01:03:21 AM

Previous topic - Next topic

CodeDog

When using sprites in GDI and the sprite is moving within the refresh frequency rate of the current display it should move flickerfree if you do it right, prevent background erasing and use double buffer and it is flickerfree indeed, but the sprite moves uneven, some times it is smooth but sometimes it moves too far. WM_TIMER isn't that accurate, GetTickCount is not accurate either, performance counters are very accurate but they can be corrupted due to overclocking, multimedia timers are very accurate but have limited resolution down to a millisecond (which is plenty enough in my case).

But my question is this, is there more to timing that what I am aware of, I think maybe I need to synchronize wm_paint messages a bit more or count frames being drawn to avoid the sprite from jumping too far from time to time?

If anyone can tell me here.

jj2007

The WM_TIMER message is unreliable, but SetTimer with callback might perform better.
The QueryPerformanceCounter family is worth a try.

dedndave

you can diddle with the timer resolution
but, for games, i think i would use the multi-media timer   :t
http://msdn.microsoft.com/en-us/library/windows/desktop/dd743609%28v=vs.85%29.aspx

Tedd

Part of your problem will come from relying on WM_PAINT.
The issue is that it's sent lazily. You expect your window to be updated every frame, but it's not. You only receive WM_PAINT when your message queue is otherwise empty (and there's at least one dirty region to be updated.)
Try doing your drawing directly when the timer signals and ignore WM_PAINT. Draw to a back buffer, then BitBlt your buffer directly to the window (use GetDC to get the DC to blt to.)
Potato2

dedndave

i usually agree with Tedd   :t

but, in this case, i have to disagree
there are a few instances where you can correctly draw outside of WM_PAINT
but, generally speaking, it is best to keep your drawing code in WM_PAINT
when windows are repositioned by the user, the OS signals your app via WM_PAINT, as required
if your code for drawing to the screen is outside WM_PAINT, it may not be properly updated

one way to force the update immediately is to use RedrawWindow with the RDW_UPDATENOW flag

dedndave

after giving that some thought....

i suppose you could design your code so that it updates the screen immediately (directly)
and - the same code is called if a WM_PAINT message is received
that would seem to be a good solution
i may try that on the project i am currently working on

jj2007

Dave,

Where timing matters, Tedd's proposal is more likely to succeed:
- get the DC
- draw whenever you feel like
- ValidateRect to prevent WM_PAINT messages

You can even, when handling WM_PAINT messages, return zero and set a flag that triggers your drawing in the SetTimer callback.

dedndave

still - there is an issue if another window is placed on top, then yours (as an example)
you want to handle the WM_PAINT message to update the rectangle as requested by the OS

as for validation...
if you paint it "manually" (i.e., outside of WM_PAINT), you simply don't invalidate that region or rectangle   :biggrin:

dedndave

i see that they have an example of timed painting at MSDN
they draw directly to the DC during WM_TIMER   :P

http://msdn.microsoft.com/en-us/library/windows/desktop/dd162481%28v=vs.85%29.aspx

they also back it up in WM_PAINT
it's a pretty simple paint job, though - one line of code - lol

Tedd

Agreed - don't fully ignore WM_PAINT or dirty regions will build up :P

What I meant was that you probably won't need to do any drawing on WM_PAINT if you're already drawing every timer-period, as long as you're redrawing frequently (multiple times per second.) But for handling WM_PAINT, you should still minimally ValidateRect(hwnd,NULL) to discard dirty regions.

Arguably, you may as well also redraw your frame on WM_PAINT (just BitBlt directly from your buffer, since it shouldn't have changed since the previous timer event); which will be necessary anyway if you don't redraw frequently enough.
Potato2