1

Topic: Higher Precision Timers

Higher Precision Timers: A Better, But Not Excessive Timer

When doing time-based animation, you have several options for tracking the amount of time that has passed between frames:

* Timer Control
* Timer object
* GetTickCount (API)
* timeGetTime (API)
* QueryPerformanceCounter (API)[/list]

The first four are not very precise, and the fourth has a tendency to suddenly jump ahead a few seconds to correct itself. So what's a programmer to do? Cheat.

You can set the timer control to an interval of one, but it's accuracy is at best 55 ms. The timer function only returns hundredths. GetTickCount reports ms, but is also only accurate to 12-58 (depending on OS) ms, and timeGetTime's resolution seems to vary by machine (15.625 ms resolution on my development rig, about 30 ms on another). QueryPerformanceCounter is incredibly precise...but can suddenly jump ahead several seconds to correct itself, and without warning.

On the surface, you might think GetTickCount or timeGetTime might be the way to go. After all, 15.625 ms should be plenty fast, right? Even 30 ms seems good. That is, until you do a little math:

1 sec / 15.625ms = 64 FPS 1 sec / 30.000ms = 33.333 FPS

Note that you might actually draw MORE than 64 FPS, but any animation will only be updated 64 FPS, which is actually noticeable. The discrepancy will cause strange hops and jumps in your animation, since you'll get numerous frames where the timers tell you that no time has passed since the last frame. If no time has passed, no changes are made and the exact same frame is drawn again.

Envision this scenario: 14 ms has passed since the last frame, so the timer tells you no time has passed at all (not up to 15.625 ms yet). The next time around, Windows took a little bit and an additional 18 ms has passed. The timer tells you that 32 ms has passed since the last frame, and your animation plays catch-up. On a slower machine (IE: 30 ms resolution...or even 58), this jump becomes REALLY noticeable. Given that on a decent machine a single frame could be handled in 2 or 3 ms, we're missing out on a lot of potential smoothness. What we really need is a reliable timer with 1 ms precision or so. Fortunately, that's what we have with timeGetTime.

What's that? I said that timeGetTime is only accurate to 15 ms or so? Well, that's true...by default. It's actually accurate to 1 ms, but is updated much less often! Happily, we do have a way to correct this.

    Public Declare Function timeBeginPeriod Lib "winmm.dll" (ByVal uPeriod As Long) As Long
    Public Declare Function timeEndPeriod Lib "winmm.dll" (ByVal uPeriod As Long) As Long

These two API calls were surprisingly difficult to find out about, and they're not in the API-Guide.

At the beginning of your code, you make this call:

    timeBeginPeriod 1

This sets the update period of timeGetTime to 1 ms.

When your program is exiting, you make this call:

    timeEndPeriod 1

This restores the update period of timeGetTime to whatever it was when you started.

Between these two calls, your calls to timeGetTime are actually accurate to 1 ms, and all is well. For most applications, this is more than enough.

Are you playing?
http://www.atomicmonks.com/sig.php?a=av&pname=Brother%20Erryn