Search code examples
c#openglanimationtao-framework

Simple animation with Tao.Framework (C# - Open GL) update buffer not work


Hello I'm starting with OpenGL using C#, Tao.Framework and Tao.Plataform.Windows SimpleOpenGlControl, so far I came with this snippet:

// in Form.Load handler
Gl.glOrtho(0, 10, 0, 10, -1, 1);

Gl.glClearColor(0f, 0f, 0f, 0f);
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);

Gl.glBegin(Gl.GL_POLYGON);

Gl.glVertex2f(0f, 0f);
Gl.glVertex2f(0f, 1f);
Gl.glVertex2f(1f, 1f);
Gl.glVertex2f(1f, 0f);

Gl.glEnd();

So far, so good. Now I'm trying to add some animation effect. I'm trying to move the square like a ball that bounce in extremities of my client area. My code is this:

Gl.glOrtho(0, 10, 0, 10, -1, 1);

new Thread(() =>
{
    int x = 3, incX = 1;
    int y = 7, incY = 1;

    while (true)
    {
        Gl.glClearColor(0f, 0f, 0f, 0f);
        Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);

        Gl.glBegin(Gl.GL_POLYGON);

        Gl.glVertex2f(x + 0f, y + 0f);
        Gl.glVertex2f(x + 0f, y + 1f);
        Gl.glVertex2f(x + 1f, y + 1f);
        Gl.glVertex2f(x + 1f, y + 0f);

        Gl.glEnd();

        simpleOpenGlControl1.SwapBuffers();

        if (x == 0 || x == 9) incX *= -1;
        if (y == 0 || y == 9) incY *= -1;

        x += incX;
        y += incY;

        Thread.Sleep(1000);
    }
}).Start();

But there is something very wrong. My picture keep switching between two specific frames. I printed the two frames. Check it out:

http://www.jonataspiazzi.xpg.com.br/outpost/example_frame.png

Still has a following detail. As much as the first frame above is correct it shows no variation, I mean the square doesn't move.

How can I fix it? Or how to build a simple animation?


Solution

  • You may not issue OpenGL commands from a thread that does not have an OpenGL context.

    You have two options:

    • use wglMakeCurrent to move the OpenGL context to your new thread. (In that case, the main thread may no longer issue OpenGL commands.)
    • Hook the Application.Idle event and loop within that. Break from the loop whenever a new windows message arrives.

    Tao SimpleOpenGlControl does not offer a way to check for incoming windows messages. As one of the original maintainers of the Tao framework, I would suggest switching to OpenTK.GLControl instead. In that case, you would write:

    // in Form.Load handler - separate thread
    glControl.Context.MakeCurrent(null);
    Thread thread = new Thread(() =>
    {
        glControl.MakeCurrent();
        while (!exit)
        {
            GL.ClearColor(0f, 0f, 0f, 0f);
            GL.Clear(ClearBufferMode.ColorBufferBit);
    
            GL.Begin(PrimitiveType.Quads);
    
            GL.Vertex(x + 0f, y + 0f);
            GL.Vertex(x + 0f, y + 1f);
            GL.Vertex(x + 1f, y + 1f);
            GL.Vertex(x + 1f, y + 0f);
    
            GL.End();
    
            glControl.SwapBuffers();
    
            if (x == 0 || x == 9) incX *= -1;
            if (y == 0 || y == 9) incY *= -1;
    
            x += incX;
            y += incY;
        }
    };
    

    or (if you do not wish to use a separate thread):

    // in Form.Load handler - main thread
    Application.Idle += (sender, e) =>
    {
        while (glControl.IsIdle)
        {
            GL.ClearColor(0f, 0f, 0f, 0f);
            GL.Clear(ClearBufferMode.ColorBufferBit);
    
            GL.Begin(PrimitiveType.Quads);
    
            GL.Vertex(x + 0f, y + 0f);
            GL.Vertex(x + 0f, y + 1f);
            GL.Vertex(x + 1f, y + 1f);
            GL.Vertex(x + 1f, y + 0f);
    
            GL.End();
    
            glControl.SwapBuffers();
    
            if (x == 0 || x == 9) incX *= -1;
            if (y == 0 || y == 9) incY *= -1;
    
            x += incX;
            y += incY;
        }
    };
    

    Edit: in both cases, you need the following using directives.

    using OpenTK;
    using OpenTK.GLControl;
    using OpenTK.Graphics;
    using OpenTK.Graphics.OpenGL;
    using OpenTK.Input;
    

    You can ask Visual / Xamarin Studio to add the missing using directives by right-clicking the unknown identifier and selecting "Resolve".