tags:

views:

170

answers:

3

I've got some animations running in an OpenGL context window, so I need to constantly redraw it. So I came up with the following code:

    void InitializeRedrawTimer()
    {
        var timer = new Timer();
        timer.Interval = 1000 / 60;
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();
    }

    void timer_Tick(object sender, EventArgs e)
    {
        glWin.Draw();
    }

That only gives me 40 FPS though. If I set the interval to 1 ms however, I can achieve 60. So where did the other 20 ms go? Is that just due to poor accuracy of the timer or what? What if I wanted to let my program run as fast as possible, is there a way to continuously call the draw func?

+2  A: 

You could try implementing a game loop.

http://blogs.msdn.com/tmiller/archive/2005/05/05/415008.aspx

This link describes one that uses the application's Idle event. It may be of use. You can simply perform a little time test or sleep to slow it down to your required fps. Try using the System.Diagnostics.StopWatch class for the most accurate timer.

I hope this helps a little.

Nanook
Nice! Using `Application.Idle` seems a lot more elegant than a 1 ms timer. I'll have to try this `StopWatch` out tomorrow too. Thanks! **Edit:** Actually, I lied. When you're resizing or moving the window, it appears to stop idling, and thus stops redrawing. This basically lowers to priority of drawing. Maybe I'll stick with a timer to enforce a minimum redraw rate... no reason I couldn't combine both methods either.
Mark
Also, StopWatch is only good for timing things, not for callback events.
Mark
You can try starting your timer when the idle even ends, then stop / check it again when the idle event fires. You can get quite close this way.
Nanook
+1  A: 

The Windows Forms Timer is ultimately limited in resolution to the standard system clock resolution of your computer. This varies from computer to computer, but is generally between 1 ms and 20 ms.

In WinForms, whenever you request a timer interval in code, Windows will only guarantees that your timer will be called no more often then the number of milliseconds specified. It makes no guarantee that your Timer will be called at exactly the milliseconds you specify.

This is because Windows is a time-sharing OS, not real-time. Other processes and threads will be scheduled to run concurrently and so your thread will be forced to wait regularly for usage of the processor. Therefore you shouldn't write WinForms timer code that relies on exact intervals or delays of milliseconds.

In your situation, setting the interval to 1 ms is really just telling Windows to trigger this timer as often as it can. As you have seen this is definitely much less often than 1 ms (60fps = about 17 ms).

If you need a more accurate and higher resolution timer, the Windows API does provide high resolution/performance timers, if your hardware supports it, see How to use the high resolution timer. A drawback of this is that your application CPU usage will be increased to support the higher performance.

Overall I think you're better off implementing a hardware/system independent game loop. That way the perceived animation of your scene appears constant regardless of the actual frame-rate achieved. For more information these articles give a good background.

Ash
+1  A: 

Depending on what you are doing, have a look at WPF and it's animation support, it may be a better solution that writing your own amimations in WinForms.

Also consider using DirectX as it now has a .NET wrapper and is very fast, however it is harder to use the WPF or WinForms.

To continuously call your draw function:

  • Do the drawing in the repaint method
  • Add at the end of the repaint method do a BeginInvoke
  • In the delegate you passed to BeginInvoke, invalidate the control you are drawing

However your users may not like you killing their computer!

Application.Idle is also another good option, however I like the fact windows will slow down the rate it send WmPaint messages when needed.

Ian Ringrose