I decided to port a program of mine that uses OpenGL from C++ to C#. I haven’t done any work using OpenGL with C# yet, and this is what I went through to get started.
The first place to look for OpenGL help is usually NeHe. He has a bunch of tutorials for various OpenGL features, plus some good frameworks to get started. And sure enough, in the Basecode section, there’s NeHeGL C#, plus many of the articles have source code ported to C#.
Download. Compile. Run. The familiar colorful rotating NeHe object shows up. Perfect. Now to look at what it does.
I already knew how I wanted the program to be structured. I wanted a custom UserControl for the “base” OpenGL stuff that can be shared across different applications - setting up the window context, etc. Then I wanted a control that inherits the base control to do app-specific stuff - actually drawing what needs to be drawn. And that control would be embedded on the form.
And lo and behold, that’s exactly what NeHe has. There’s
BaseGL.cs, which is the UserControl that sets of the OpenGL window. The significant portion of the code comes straight from the C++ NeHe basecode: get the HWnd1 and DC2, set up the pixel format descriptor, and set the rendering context. And there’s
TestGL.cs, the control specific to the app, which is basically just an OnPaint method and a keypress event handler.
But what I was really looking for was how to communicate to opengl32.dll. The solution comes in the form of three interop classes: OpenGL.cs, GLU.cs, and WGL.cs, courtesy of Colin Fahey and Chris Hegarty. I don’t know much about interops, but as I understand it, they’re like wrappers around unmanaged code. They’re just there to say, “over here, in this dll, is a function that looks like this”.
OpenGL.cs is for opengl32.dll; GLU.cs is for glu32.dll; and WGL.cs has a selection of functions from user32.dll (GetDC, ReleaseDC), gdi32.dll (ChoosePixelFormat, SetPixelFormat) , and opengl32.dll (wglCreateContext, wglMakeCurrent, wglDeleteContext, wglSwapBuffers).
In the end, this just means all OpenGL calls need to use one of these classes, so you have
By including these classes in my project, and making my custom UserControl, I was up and running with a window with a colorful triangle. The only problem is is doesn’t move. Windows doesn’t repaint unless is needs to, or you tell it to. This is as simple as calling
Control.Invalidate(). The NeHe code puts this in a timer, so it happens repeatedly:
I don’t need this for what I’m working on, so I just set up event handlers for things like
There’s just one more thing I need for now: image loading. In C++ I’ve always been able to find functions for loading different image formats into raw data, but I was sure the .NET framework can do this itself. So I go to lesson 6 at NeHe’s texture mapping tutorial, ported to C#.
Load a bitmap, get the data, and create an OpenGL texture using the data.
Unfortunately, this didn’t quite work.
BitmapData.Scan0 returns an
GL.glTexImage2D expects an
object. The lesson 6 code works because it’s using the CsGL library, something I wanted to avoid for now. But since I have the source code for the interop, I can just change it to something that works, which matches up with what’s in CsGL. Compile and run, and that’s all I need for now.
I said I wanted to avoid using CsGL at first. That’s because I wanted to learn what needs to be done, rather than just use a library to do it for me. But I don’t want to have to include those three interop classes in every future project, so let’s see what CsGL has to offer.
I was hoping I could just change my control to inherit the CsGL OpenGLControl, instead of the NeHe base control, but it doesn’t work. ‘CsGL.OpenGL.OpenGLControl does not contain a definition for AutoScaleMode’ on a line Visual Studio inserted into
InitializeComponent. If I remove the line it’ll compile, but it doesn’t run and I can’t load the form in the designer. CsGL is doing something differently than the NeHe basecode. After a quick look at CsGL, I think it has to do with
UserControl. A couple quick searches make it clear that I shouldn’t be using CsGL; it’s been discontinued and the Tao Framework is its successor.
Tao is pretty easy to implement. Just add
Tao.Platform.Windows in the using list and make the control inherit
SimpleOpenGlControl. A few changes to the code are needed again: in the control constructor you need to call
InitializeContexts(), and the Tao class with all the OpenGL definitions is named
After all this, what have I learned? Mostly, getting started is a lot harder than it should be. A search for OpenGL C# should take me straight to the Tao Framework. OpenGL.org should have a giant “How to use OpenGL in .NET” link on it’s front page. And a place like NeHe should have a tutorial or article for using OpenGL with .NET, although the ported source code was very helpful. It’s not that getting everything working took too long, it’s just that I was expecting a simple list telling me what to do. So…
How to use OpenGL in a .NET program (Visual Studio 2005 edition):
- Download and install the Tao Framework.
- Create a new Windows application project.
- Create a new User Control in the project.
- In the User Control, make the following changes:
- Make the User Control inherit
- Add a call to
InitializeContexts()to the constructor.
- Add a method to override
OnPaintand add your rendering code.
- (Optional) Add a method to override
- Add an instance of the User Control to your form.
- To force the control to redraw, call
Invalidateon the User Control.