siemonday's picture

Creating Animation With Timer

Hi, I'm trying to draw some math graphics using opentk.
I create a double[] array to store the numbers,
and when the first graphic displays, the numbers in the double will be changed,
and then display the next frame.

As Application.Idle do not work for me , I tried to use System.Timer,but it tells me that I can not swap buffers ( I thought the context calculated stays in the timer's thread instead of the main thread so I can not swap them)

SO do anyone have some advice for me,how to create an animation?


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
mOfl's picture

I don't know if I understand you correctly, but I assume you want to realize animation like in cartoons - draw a new image every few milliseconds, is that right? If so, than this is not what you do in OpenGL. You usually use a double-buffered display which are swapped for drawing, so you do continuous drawing to the back buffer, not only on changes. I don't understand what you mean with the timer's thread - for standard OpenGL drawing, you do not need multithreading, as OpenGL does not support multithreading.

For timers you should take a look at the Stopwatch class, which is much more accurate for timing purposes, the System.Timer is useless for millisecond precision.

If I understood you correctly and you want to do this incremental animation, what you would do is:
- Start your stopwatch
- Enter the game loop (i.e. a while loop with update(), render(), swapbuffers())
- Clear the back buffer
- In each iteration, check the stopwatch time: if it's greater than some time period p1, draw object o1. If it's greater than time period p2, draw object o1 and o2 and so on.

This way, you redraw each object in each frame continuously, but with your time period conditions you specify what objects to draw (additionally) depending on the elapsed time.

siemonday's picture

Thank you mOfl !
I write update and render function, trying to re-draw the image.
Code below ( Click button1 to update the values,and click button2 to re-draw , but it do not display the new values when updated. )

using System;
using System.Drawing;
using System.Windows.Forms;
 
using OpenTK;
using OpenTK.Graphics.OpenGL;
using System.Diagnostics;
using System.Numerics;
 
namespace FOXLI
{
    public partial class MainWindow : Form
    {
        bool loaded = false;
        double w, l, a, k;//wavelength,length,?,wave vector
        double[] x1 = new double[1000];
        int i;//for loop
        Complex[] y = new Complex[1000];
        Complex[] u = new Complex[1000];
        double[] uabs = new double[1000];//the values
 
        double x, Max;
        double[] temp = new double[1000];
        Complex c1;
        double vx = 0.0;//abscissa 
        int m = 0;//for the loop
 
        public MainWindow()
        {
            InitializeComponent();
            //Set Up Basic Parameters
            w = 6.328e-7;
            l = 100.0 * w;
            a = 25.0 * w;
            k = 2 * Math.PI / w;
            for (i = 0; i < 1000; i++)
            {
                x1[i] = -a + i * 3.164e-8;
            }
            c1 = new Complex(0, 1 / (Math.PI * l));
 
            //sw.Start();
            /*第一次运算*/
            for (i = 0; i < 1000; i++)
            {
                x = x1[i];
                temp = VectorSquare(VectorSub(x, x1));
                for (int j = 0; j < 1000; j++)
                {
                    y[j] = Complex.Exp(new Complex(0, -k * temp[j] / (2 * l)));
                }
                u[i] = Complex.Sqrt(c1 * Complex.Exp(new Complex(0, -k * l))) * ComplexSigma(y, 1000);
                uabs[i] = Complex.Abs(u[i]);
            }
 
            Max = FindMax(uabs);
            for (i = 0; i < 1000; i++)
            {
                u[i] /= Max;
                uabs[i] /= Max;
            }
        }
 
        double[] update(Complex[] prev)
        {
            Complex[] u2 = new Complex[1000];
            double[] r = new double[1000];
            for (int n = 0; n < 1000; n++)
            {
                x = x1[n];
                temp = VectorSquare(VectorSub(x, x1));
                for (int j = 0; j < 1000; j++)
                {
                    y[j] = (Complex.Exp(new Complex(0, -k * temp[j] / (2 * l)))) * prev[j];
                }
                u2[n] = Complex.Sqrt(c1 * Complex.Exp(new Complex(0, -k * l))) * ComplexSigma(y, 1000);
                r[n] = Complex.Abs(u2[n]);
            }
            for (int n = 0; n < 1000; n++)
            {
                prev[n] = u2[n];
            }
            Max = FindMax(r);
            for (int n = 0; n < 1000; n++)
            {
                r[n] /= Max;
            }
            return r;
        }
        void render(double[] ordinates)
        {
            SetupViewport();
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadIdentity();
            GL.Color3(Color.Yellow);
            GL.Scale(new Vector3(200f, 200f, 200f));
            GL.Begin(BeginMode.LineStrip);
            for (; m < 1000; m++)
            {
                vx += 0.002;
                GL.Vertex2(vx, ordinates[m]);
            }
            GL.End();
        }
 
        #region Calc-Methods
        static double FindMax(double[] myArray)
        {
            //假设第一项是最大的
            double max = myArray[0];
            //逐项比较,找出最大项
            for (int i = 0; i < myArray.Length; i++)
            {
                if (myArray[i] > max)
                {
                    max = myArray[i];
                }
            }
            return max;
        }
        static double[] VectorSub(double m, double[] Vector)
        {
            double[] r = new double[Vector.Length];
            for (int i = 0; i < Vector.Length; i++)
            {
                r[i] = m - Vector[i];
            }
            return r;
        }
        static double[] VectorSquare(double[] Vector)
        {
            double[] r = new double[Vector.Length];
            for (int i = 0; i < Vector.Length; i++)
            {
                r[i] = Vector[i] * Vector[i];
            }
            return r;
        }
        static Complex[] VectorSquare(Complex[] Vector1, double[] Vector2)
        {
            Complex[] r = new Complex[Vector1.Length];
            for (int i = 0; i < Vector1.Length; i++)
            {
                r[i] = Vector1[i] * Vector2[i];
            }
            return r;
        }
        static Complex ComplexSigma(Complex[] c, int Length)
        {
            Complex r = new Complex(0, 0);
            for (int i = 0; i < Length; i++)
            {
                r += c[i];
            }
            return r;
        }
        #endregion
 
        private void glControl1_Load(object sender, EventArgs e)
        {
            loaded = true;
            GL.ClearColor(Color.SkyBlue); // Yey! .NET Colors can be used directly!
            SetupViewport();
        }
        private void SetupViewport()
        {
            int w = glControl1.Width;
            int h = glControl1.Height;
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            GL.Ortho(0, w, 0, h, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
            GL.Viewport(0, 0, w, h); // Use all of the glControl painting area
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
            GL.Enable(EnableCap.Blend);
            GL.Enable(EnableCap.LineSmooth);
            GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            render(uabs);
            glControl1.SwapBuffers();
        }
 
        private void button2_Click(object sender, EventArgs e)
        {
            uabs=update(u);
            button2.Text = uabs[0].ToString();
        }
    }
}