3

I'm having problems making smooth animations in GDI+. The problem as I understand it from Googling is that there is some kind of bug with the clock-ticks in .NET on a multi-core processor. Here's a simplified version of what I'm doing:

class Animation
{
  System.Diagnostics.Stopwatch sw = new Stopwatch();
  float AnimationTime = 1000; //time it takes the animation to complete

  public bool IsComplete
  { get { return sw.ElapsedMilliseconds > AnimationTime; } }

  public void StartAnimation()
  {
     sw.Reset();
     sw.Start();
  }

  public void DoFrame()
  {
     float PercentComplete = (float)sw.ElapsedMilliseconds / AnimationTime;
     //draw the animation based on PercentComplete
  }
}

DoFrame() is called like this:

Animation.Start();
do
{
  Animation.DoFrame();
  Application.DoEvents();
} while (!Animation.IsComplete);

The problem is that the animation is very smooth for about 15 frames then it jerks, it actually goes backward (sw.ElapsedMilliseconds gives a lesser value than the previous query). It's very annoying and it's ruining my otherwise smooth animation that looks great even on a Core 2 Duo (despite Microsoft saying this is a multicore bug). I have an i7 and the animation is smooth except for 2-3 frames per second that look "jerky".

I understand that this is a known issue and Microsoft blames it on the processor, so my question is, does anyone know any kind of solution for this? I tried using a Kalman filter and it sort of works. I was hoping maybe there is an established "correct" solution for this?

Oh b.t.w. I tried using DateTime instead of Stopwatch and got the same results.

I also tried:

double PercentComplete = (double)sw.ElapsedTicks / (double)Stopwatch.Frequency * 1000 / AnimationTime

It gives me the same results.

HypnoToad
  • 585
  • 1
  • 6
  • 18
  • DoFrame() is called from the main thread about 40-60x per second. It's not called again until it completes. – HypnoToad Oct 10 '12 at 09:14
  • Can you the actual code? It might be relevant. Are you using `System.Timers.Timer` or `System.Windows.Forms.Timer` or something completely different? – bitbonk Oct 10 '12 at 09:23
  • I'm not using System.Timers.Timer. I wasn't even aware of that class. I'm using Stopwatch and I also tried DateTime, got the same results with both. I'm sure the actual code isn't relevant because it looks perfect on a Core Duo processor. – HypnoToad Oct 10 '12 at 09:25
  • Try go with a Timer to trigger the `DoFrame`. That's the way animations in GDI+ are usually done. – bitbonk Oct 10 '12 at 09:26
  • Or maybe problems are because you using float? – Renatas M. Oct 10 '12 at 09:51
  • If you see time go backwards then you have a very different kind of problem. It's unguessable from the provided code. – Hans Passant Oct 10 '12 at 13:14
  • I guess I should have mentioned this isn't a sprite animation. It's a zooming animation. For each frame, it computes the level of zoom based on PercentComplete and then calls DrawImage. I found out the stopwatch issue was a known bug here: http://stackoverflow.com/questions/1008345/system-diagnostics-stopwatch-returns-negative-numbers-in-elapsed-properties – HypnoToad Oct 10 '12 at 22:09

1 Answers1

1

It probably has to do with the way you call DoFrame(). Using the following windows forms / GDI+ based algorithm you should alway get very smooth animations:

const double desiredFps = 500.0;
long ticks1 = 0;
var interval = Stopwatch.Frequency / desiredFps;
while (true)
{
    Application.DoEvents();
    var ticks2 = Stopwatch.GetTimestamp();
    if (ticks2 >= ticks1 + interval)
    {
        ticks1 = Stopwatch.GetTimestamp();

        // do the drawing here
    }
}
bitbonk
  • 48,890
  • 37
  • 186
  • 278
  • `Application.DoEvents();` in loop...why? – Renatas M. Oct 10 '12 at 09:58
  • DoEvents is from the main thread... the animation happens on a different thread... I will try your way. – HypnoToad Oct 10 '12 at 10:32
  • Controlling the framerate does seem to help, as long as the system is capable of doing better than the desired framerate. The constant jitter is gone, although there is new intermittent jitter but I think that my have something to do with what's going on on the other thread. Thanks! – HypnoToad Oct 10 '12 at 22:50