gary kim
gary kim

Reputation: 11

Using glControl instead of Gamewindow. but how can i render automatically in another thread?

Thank you for your reading this question!

A program I used before has main window form. when I click a button , another thread creates Gamewindow form which displays frame data from a Camera. OnUpdateFrame(), OnRenderFrame() are automatically called, and process data and render in the created window.

I am working on the update vision of this software which has a glControl in the Main window form.

Yes, I am using glControl instead of Gamewindow. but problem is..

Because Main Window form need to handle user input, I have to control glControl in another thread which continually update and render Frame data. But glControl in created and displayed main window form. the glControl manipulated in the other thread is not applied to main window form. (I only can use glControl.Swapbuffers() or .invalidate() in other thread code)
I found a info which says glControl is controlled in only one thread. So how can I render frame data on the glControl automatically while using Mainwindow Form.

I have tried GL. functions to update an render frame data using timer , but the timer is also another thread, so changes are not applied to the glControl in the Main form.

And I have tried to new and create the glControl in the other thread but, it shows a exception when using GL. functions (: No GraphicsContext available in the calling thread)

How can I solve this problem?

==========

this is a way i tried, and found it doesn't work.. RenderFrame() called by a timer thread can not do anything for displaying on glControl1, even thought glcontrol1.Invalidate() is called periodically.

actually when using gamewindow before, OnRenderFrame() is periodically and displays objects in the window. but how can i do this on glControl in main window form. can Main thread periodically call RenderFrame()?? it seems a timer is also a thread, so RenderFrame() called by a timer thread do not work properly.

public partial class MainWindowForm : Form
{
System.Timers.Timer glControlTimer;
...
    private void InitializeComponent()
    {
        glcontrol1 = new OpenTK.GLControl();
    ...
    }

    private void btShowLive2_Click(object sender, EventArgs e)
    {   
    ...
            oHandleGLControl = new HandleGLControl(glcontrol1);
            glControlTimer = new System.Timers.Timer(300); 
            glControlTimer.Elapsed += TimerElapsed;
            glControlTimer.Start();
    }


    private void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        oHandleGLControl.UpdateFrame();   //processing frame data
        oHandleGLControl.RenderFrame(); //rendering
        glcontrol1.Invalidate();
    ...
    }
}

public class HandleGLControl
{
    public void UpdateFrame()
    {...
    }

    public void RenderFrame()
    {
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        GL.PushMatrix();

        GL.MatrixMode(MatrixMode.Modelview);
        GL.Translate(-cameraPosition[0], -cameraPosition[1], -cameraPosition[2]);
        GL.Rotate(g_pitch, 1.0f, 0.0f, 0.0f);
        GL.Rotate(g_heading, 0.0f, 0.0f, 1.0f);
    ....
     }
...
}

Upvotes: 1

Views: 1656

Answers (1)

JStefanelli
JStefanelli

Reputation: 143

I had the same exact issue a while ago, and the problem you are facing regards OpenGL contexts, specifically the fact that OpenGL contexts can only be bound to one thread.

However, despite popular belief, this thread doesn't have to be the main window thread, it can be any thread you want.

The process is simple but delicate:

  • first, unbind your OpenGL Context from the main thread
  • then start your thread and bind the OpenGL context there

In OpenTK this is how I do it:

private void glcontrol1_Load(object sender, EventArgs e){
    glcontrol1.Context.MakeCurrent(null); //Unbinds the context from the current thread.
    Thread renderThread = new Thread(() => {
        glcontrol1.Context.MakeCurrent(glcontrol1.WindowInfo); //Bimds the OpenGL context to this new thread
        while(DoRender) { RenderFrame(); }
    }
    renderThread.Start();
}

You can put the glcontrol1.SwapBuffers() call in the RenderFrame() method too, it hasn't given me any problems so far.

As a suggestion, I'd run the UpdateFrame() and RenderFrame() methods on different threads, so not to limit the update logic to the frame rate of the program.

Upvotes: 2

Related Questions