codingthewheel's picture

Drawing without GameWindow or GLControl

Hi,

Is there a way to use the GL.XXXXXX calls without a GameWindow or GLControl?
Failing that, is it possible to attach a GameWindow to an existing window (rather than creating a new window)?

Scenario: I'm writing a C# plugin that's handed a window by the host application (this is on Windows XP/Vista). This window is already prepared for OpenGL use, by the host application: pixel format, GL context, all set up and ready to go. C++ OpenGL calls work. C# calls to glXxxxx functions through P/Invoke work. But when I go through the TK bindings, I'm getting a crash.

What am I missing?

Many thanks,
James


Comments

Comment viewing options

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

Edit: I just realized this is already covered in the documentation: http://www.opentk.com/doc/graphics/graphicscontext. Leaving the code here for posterity.

You just need to inform OpenTK that an external context exists:

using OpenTK.Graphics;
 
// Make sure the context  is current and call:
IGraphicsContext context = GraphicsContext.CreateDummyContext();

Then store the IGraphicsContext somewhere so it isn't collected by the GC. This is a "dummy" context, which means it is not actually functional (i.e. calling IGraphicsContext.MakeCurrent(...) will do nothing). The real context belongs to the host application.

In some specific cases, you might wish to control the context through C#, too. In that case, you can create a fully functional context with:

using OpenTK.Graphics;
using OpenTK.Platform;
 
IntPtr windowHandle, contextHandle;
// Retrieve the handles from the host application, then:
IWindowInfo winfo = Utilities.CreateWindowsWindowInfo(windowHandle); // Similar methods exist for X11 and Carbon
IGraphicsContext context = new GraphicsContext(contextHandle, winfo);

You can now use any IGraphicsContext method, for example context.VSync = true. While this can be useful, it is also dangerous: it is your job to ensure the context remains valid (i.e. don't call MakeCurrent(null, null) or Dispose() while the host is using OpenGL!)

Unless you need to direct control through C#, I'd suggest following the first approach.

Edit 2: fixed the second code snipped to pass winfo correctly.

codingthewheel's picture

Hi. Thanks for the quick response. :)

What I'm not understanding from the docs is the relationship between OpenGL's internal notion of "current context" and OpenTK's notion of the same thing. I have studied that page and tried various combinations; can't seem to get it to gel.

So to simplify things, I'm now trying to create the OpenGL context entirely on the plugin side. It (the plugin) is handed an existing window which hasn't been prepped for OpenGL (SetPixelFormat/wglMakeCurrent/etc haven't been called). I want to "OpenGL-itize this window" in the usual manner: create a context, make it current, etc. Here's the C# code I'm using to init the window:

int handleVal; // has HWND raw value
IntPtr ptrHwnd = new IntPtr(handleVal);
IWindowInfo wi = Utilities.CreateWindowsWindowInfo(ptrHwnd);
_context = new GraphicsContext(GraphicsMode.Default, wi);
_context.MakeCurrent(wi);
 
// Set up some default OpenGL state...
GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f); <--- Blows up. Object null reference.
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.Texture2D);

So apparently, this would require me to actually know what I'm doing. Unfortunately I can't debug into the TK delegates type stuff right now. Also, when I try it the other way: initializing the OpenGL window on the host, and using:

_context = GraphicsContext.CreateDummyContext();

It blows up on the call to CreateDummyContext. And yet the external context is current and on the same thread so, not sure what I'm doing wrong. One way or another, no matter where I create the context or what I do with it, it blows up in the GL.XXXX calls.

the Fiddler's picture

Am I right to assume that the C# plugin is running in the same process as the host? (OpenGL contexts cannot function across processes.)

Assuming the above is true, creating a new context like you do should allow you to use GL methods right away. Can you please post the complete error message?

CreateDummyContext() will try to retrieve the current context using wglGetCurrentContext (or the relevant glx/agl methods). Apparently, this is failing for some reason. Again, the complete error message could give a clue about the cause.

Two other suggestions:

  • int handleVal is not valid for 64bit applications. Something to keep in mind if 64bit support is a concern.
  • The debug version of OpenTK.dll outputs a lot of debug information during startup (add a trace listener or simply look at the output window in Visual Studio (Ctrl+W, O) to read that information). Attaching that log would also help understand the issue.
codingthewheel's picture

Yep, they're in the same (32-bit) process. The error message was an "Object reference not set to an instance of an object" at the point of the GL.XXXXX call with an empty InnerException. Ie, no stack trace, and no indication of where inside the code the error may have happened. It was weird.

So I figured it was some funky entry point thing, and called GL.LoadAll before the first GL.Xxxx and everything works per your original answer. I notice that LoadAll is marked deprecated, though, so maybe this isn't the best way?

At any rate, it's working. Thanks!

the Fiddler's picture

GL.LoadAll() is deprecated because entry points are actually loaded by the context, not the GL class. The non-deprecated method is called _context.LoadAll() (in SVN) or (_context as IGraphicsContextInternal).LoadAll() (in 1.0 beta-3).

Now, the strange thing is that entry points are loaded automatically when you create a new context (GraphicsContext.cs, line 177), so you shouldn't have to do that manually. Will have to investigate what is going on here.

In any case, glad it's working.

tegetege's picture

(I'm not good at English, sorry.)

I had tried to initialize GraphicsContext with external OpenGL context (manually created by wglCreateContext() ) with these codes, and it works. (in 1.0 beta-2, windows7)
It seems to load the entry points automatically.

IntPtr hRC; // The handle of the OpenGL rendering context created by wglCreateContext()
GraphicsContext context = new GraphicsContext(
    new OpenTK.ContextHandle( hRC ),
    OpenTK.Platform.Utilities.CreateWindowsWindowInfo( IntPtr.Zero ) );