njz3's picture

Mixing OpenTK and a vtk render window on Win 32 bits.

Hello,

I have a Visual 2010 C# project that currently uses a render window control from ActiViz.NET (vtk.NET wrapper).
The ActiViz library uses vtk's OpenGl rendering engine to display objects and it offers a user-control that can be easily incorporated in the form designer of Visual Studio (control is a Kitware.VTK.RenderWindowControl). This control allows me to render my scene using vtk's commands, but now I would like to mix specific GL commands (using OpenTK) with the rendering done by vtk.

I have tried to set the current context of my vtk's renderwindow using vtk's function, then call GL.LoadAll() or creating a dummy GraphicsContext but it returns with an exception telling me that "No GraphicsContext is current on calling thread".

Is there anybody that has experience in vtk, its wrapper ActiViz.NET and OpenTK?

Thanks

Code 1:

  GraphicsContext glContext;
 
        private void renderWindowControl1_Paint(object sender, PaintEventArgs e)
        {
            renderWindowControl1.RenderWindow.MakeCurrent();
            try
            {
                if (glContext==null)
                    glContext = GraphicsContext.CreateDummyContext();
                GL.Begin(BeginMode.Points);
                GL.Vertex3(1.0, 1.0, 1.0);
                GL.End();
            }
            catch(Exception ex)
            {
             // Exception "No GraphicsContext is current on the calling thread." thrown by CreateDummyContext()
            }
        }

Code 2:

GraphicsContext glContext;
 
        [DllImport("GLContext.dll")]
        static extern IntPtr CreateGLContext(IntPtr hwnd);
 
        [DllImport("opengl32.dll")]
        static extern IntPtr wglGetCurrentContext();
 
        private void renderWindowControl1_Paint(object sender, PaintEventArgs e)
        {
            renderWindowControl1.RenderWindow.MakeCurrent();
            System.IntPtr context = wglGetCurrentContext(); // Context not null (=65536)
            try
            {
                ContextHandle handle = new ContextHandle(context);
                if (glContext==null)
                    glContext = GraphicsContext.CreateDummyContext(handle);
                glContext.LoadAll();
                GL.Begin(BeginMode.Points);
                GL.Vertex3(1.0, 1.0, 1.0);
                GL.End();
            }
            catch(Exception ex)
            {
                  // Exception thrown by glContext.LoadAll();
            }
        }

Comments

Comment viewing options

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

Please try compiling OpenTK from source (it's easy), because it contains several fixes for CreateDummyContext. The first code listing should work there (please file a bug if it doesn't).

mannyfm's picture

Hi,
I'm trying to do the same thing - render custom OpenGL objects to VTK Render Window, only on a 64 bit machine. I have tried both above solutions and neither works. I'm using the newest 1.1.0.0 OpenTK, 2013-12-15 build.
Has anyone managed to do this successfully?

My final aim is to render directly from OpenCL to VTK, which I suppose requires being able to render from OpenGL to VTK, but if another solution for OpenCL exists I would appreciate this as well.

Here is what happens when I try to run above code:

The first one throws exception 'Object reference not set to an instance of an object' in the CreateDummyContext:

at OpenTK.Graphics.GraphicsContext.CreateDummyContext() in c:\temp\opentk\Source\OpenTK\Graphics\GraphicsContext.cs:line 306

The second one also throws 'Object reference not set to an instance of an object' but in glContext.LoadAll:

 at OpenTK.Graphics.GraphicsContext.get_CurrentContext() in c:\temp\opentk\Source\OpenTK\Graphics\GraphicsContext.cs:line 365
   at OpenTK.Graphics.GraphicsContext.LoadAll() in c:\temp\opentk\Source\OpenTK\Graphics\GraphicsContext.cs:line 512

wglGetCurrentContext() also always returns the value 65536.

I would appreciate any help.

the Fiddler's picture

This is a bug in OpenTK, please file a bug report at https://github.com/opentk/opentk/issues

For plain OpenCL, I would suggest using Cloo, which offers a better OpenCL API than OpenTK. You can combine this with OpenTK if you also need to access OpenGL.

the Fiddler's picture

All issues with external contexts should now be fixed with as of https://github.com/opentk/opentk/commit/dc121286797f5fdd95221d4728d3937c...

Example code can be found here: https://github.com/opentk/opentk/blob/develop/Source/Examples/OpenTK/Tes...

IntPtr external_context = ...; // create or retrieve existing third-party context handle
GraphicsContext opentk_context = new GraphicsContext(
    new ContextHandle(external_context),
    null);

You can now use OpenTK GL functions normally.

If external_context is not a handle to a WGL, GLX or AGL/NSOpenGL/CGL context, you will have to specify a custom GetAddress and GetCurrentContext implementation in terms of the toolkit you are using. For instance, when using SDL2, the context handle returned by SDL_GL_CreateContext points to a SDL-specific structure. In this case:

IntPtr external_context = SDL_GL_CreateContext(...);
GraphicsContext opentk_context = new GraphicsContext(
    new ContextHandle(external_context),
    (name) => { return SDL_GL_GetProcAddress(name); }, // implement GetAddress via SDL
    () => { return SDL_GL_GetCurrentContext(); }); // implement GetCurrentContext via SDL

Note that GraphicsContext functions like context.SwapBuffers() will have no effect on external contexts. You *must* use the third-party toolkit to manage the external context.

mannyfm's picture

Thank you for your help!
It is now possible to render into VTK control!
Just in case someone looks for it someday:

[DllImport("opengl32.dll")]
static extern IntPtr wglGetCurrentContext();
(...)
// this must be called (once) before getting the context, so that OpenTK will know what platform we are using
Toolkit.Init();  
(...)
 
// we will need two events from VTK renderer object
renderer.StartEvt += new vtkObject.vtkObjectEventHandler(renMain_StartEvt);
renderer.EndEvt += new vtkObject.vtkObjectEventHandler(renMain_EndEvt);   
(...)
 
private void renMain_StartEvt(vtkObject sender, vtkObjectEventArgs e)
{
	renWin.SwapBuffersOff();   // turn off buffer swapping, so it will not be swapped directly after render
}
 
// EndEvt is used for drawing and buffer swapping
private void renMain_EndEvt(vtkObject sender, vtkObjectEventArgs e)
{
	renderControl.RenderWindow.MakeCurrent();   
	IntPtr context = wglGetCurrentContext();
 
	try
	{
 
	   if (glContext == null) glContext = new GraphicsContext(new ContextHandle(context), null);     // create OpenTK context from VTK context
 
		GL.Disable(EnableCap.Lighting);  // VTK uses lights per default, but we want a simple explicitly colored triangle 
		GL.MatrixMode(MatrixMode.Projection);
		GL.LoadIdentity();
		GL.Ortho(-1, 1, -1, 1, 0, 4);
 
		GL.Begin(BeginMode.Triangles);
		GL.Color3(Color.MidnightBlue);
		GL.Vertex2(-1, 1);
		GL.Color3(Color.SpringGreen);
		GL.Vertex2(0, -1);
		GL.Color3(Color.Ivory);
		GL.Vertex2(1, 1);
		GL.End();
 
		GL.Enable(EnableCap.Lighting);  // turn lights back on for VTK
 
		renWin.SwapBuffersOn();  // now we can finally render
	}
	catch (Exception ex)
	{
		// ...
	}
}

Of course making customly rendered object behave according to VTK interactor commands or handling overlapping 3D objects from OpenTK and VTK is quite another matter, but it is a good start :)

the Fiddler's picture

You can avoid the WGL DllImport by passing ContextHandle.Zero to the GraphicsContext constructor. In that case, OpenTK will try to retrieve the current context internally.

For this to work, OpenTK must be using the same platform backend as VTK. This means WGL on Windows, GLX on Linux and CGL on Mac OS X.

// Toolkit.Init() must be called (once) before getting the context,
// so that OpenTK will know what platform we are using.
// PlatformBackend.PreferNative instructs OpenTK to use
// wgl (windows), glx (linux) or cgl (macos) even if a different
// backend is available (e.g. sdl2).
var options = new ToolkitOptions { Backend = PlatformBackend.PreferNative };
Toolkit.Init(options);
(...)
 
renderControl.RenderWindow.MakeCurrent();
if (glContext == null)
{
    // Create OpenTK context from VTK context.
    // If you pass ContextHandle.Zero, OpenTK will retrieve
    // and use the current OpenGL context to initialize
    // OpenGL entry points.
    glContext = new GraphicsContext(ContextHandle.Zero, null);
}
// You can now use OpenTK.Graphics.OpenGL to render into the
// VTK context.