Moonlighting with OpenTK

Wednesday, April 14, 2010

The OpenTK bindings for OpenGL are clean, lightweight, and complete. Definitely recommended for any .NET developer interested in taking a swing at 3D graphics programming under OpenGL.

// Draw a gradient quad...
GL.Begin(BeginMode.Quads);
GL.Color4(Color4.Black);
GL.Vertex3(-1, -1, -1);
GL.Color4(Color4.Red);
GL.Vertex3(1, -1, -1);
GL.Color4(Color4.Black);
GL.Vertex3(1, 1, -1);
GL.Color4(Color4.LimeGreen);
GL.Vertex3(-1, 1, -1);
GL.End();

OpenTK exposes the entire OpenGL frequency spectrum to your .NET app, including deprecated functions, extensions, and satellite libraries like GLUT. With few exceptions, if it exists in OpenGL, you can call it effortlessly via OpenTK.

And when I say effortlessly, I mean that when you expect a certain function to be there, it's there, usually in a type-safe way. And I also mean that certain things that are a pain in C++ plus OpenGL become very, very easy under C# plus OpenTK.

For example: those pesky OpenGL extensions. Here's a bit of code I have from an old C++ OpenGL project. This code attempts to enable v-sync, using the WGL_EXT_swap_control extension. It ends up having to do some string comparisons, look up and store a raw function pointer, and then call the pointed-to function.

//Funcs to set up vsync
void GraphicsManager::InitVSync()
{
   char* extensions = (char*)glGetString(GL_EXTENSIONS);
   if (strstr(extensions,"WGL_EXT_swap_control"))
   {
      wglSwapIntervalEXT = (PFNWGLEXTSWAPCONTROLPROC) wglGetProcAddress("wglSwapIntervalEXT");
      wglGetSwapIntervalEXT = (PFNWGLEXTGETSWAPINTERVALPROC) wglGetProcAddress("wglGetSwapIntervalEXT");
  }
}
void GraphicsManager::SetVSync(bool VSync)
{
	if (wglSwapIntervalEXT)
		wglSwapIntervalEXT(VSync ? 1 : 0);
}
bool GraphicsManager::GetVSync() const
{
	if (wglGetSwapIntervalEXT)
		return wglGetSwapIntervalEXT()==0 ? false : true;
	return false;
}

So that's the C++ version. Meanwhile in OpenTK:

VSync = VSyncMode.On;

Syntactic sugar, yes. And yet, OpenTK doesn't conceal anything from you. You could, if you wanted, call the extension functions directly. If you'd rather not, there are convenience properties like this to save you some time. Or this one, to set the app into full-screen mode (something that's always been a little messy under C++ OpenGL):

WindowState = WindowState.Fullscreen;

Speaking of windows, I like the way OpenTK handles windows and rendering contexts. There are basically three ways to set things up:

  • Use the built-in GameWindow class (or a class derived from it), designed for raw speed, and typical game-loop (update/render) behaviors.
  • Use WinForms-friendly GLControl class, which allows you to host an OpenGL-friendly window as a standard .NET WinForms control.
  • Use an external window/context created elsewhere.

So whether you want to handle all aspects of window and context creation yourself, or have OpenTK handle them for you, your choice. For the CardsFall visualizer (implemented in C# and OpenTK)...

...I started off with a standard GameWindow, shown here in its basic skeleton form.

	class MainWindow : GameWindow
	{
		public MainWindow( GraphicsMode mode )
			: base(1280, 720, mode, "My OpenTK Demo App")
		{
			VSync = VSyncMode.On;
			WindowState = WindowState.Fullscreen;
		}
		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);
			// Initialize OpenGL properties
			// Subscribe to mouse events
		}
		protected override void OnResize(EventArgs e)
		{
			base.OnResize(e);
			// Set up OpenGL viewport
			// Set up projection/modelview matrices
		}
		// Called when it's time to update the state of our game
		protected override void OnUpdateFrame(FrameEventArgs e)
		{
			base.OnUpdateFrame(e);
			if (Keyboard[Key.Escape])
				Exit();
			// Update logic goes here.
		}
		// Called when it's time to render the game
		protected override void OnRenderFrame(FrameEventArgs e)
		{
			base.OnRenderFrame(e);
			// Painting logic goes here.
			SwapBuffers();
		}
		// The application entry point
		[STAThread]
		public static void Main(string[] args)
		{
			GraphicsMode mode = new GraphicsMode(new OpenTK.Graphics.ColorFormat(32), 24, 0, 2, new OpenTK.Graphics.ColorFormat(32));
			// Request 60 UpdateFrame events per second and as many RenderFrame events as will fit
			using (MainWindow game = new MainWindow(mode))
			{
				game.Run(60.0);
			}
		}
	}

That should look more or less familiar to you WinForms/Win32 cats. The big difference is that the GameWindow enforces a classic update/render cycle:

  • OnUpdateFrame is called to give you a chance to update the state of your game.
  • OnRenderFrame is called to give you a chance to draw your game to the screen.

You'll get frame time indicators with both of those, so you can figure out where your game objects and particles and explosions need to be. And if you don't like how any of this works, again, you can always build your window (and your game loop) yourself.

Now, speaking for myself, I still prefer native C++ and DirectX/OpenGL for intensive, fry-your-graphics-card stuff.

And if I'm developing in .NET, I'll often go with XNA by default, which is a world unto itself, and has the energy of an entire world, and a "fun" factor that's through the roof.

That said, OpenTK offers an amazingly clean 3D programming experience. Maybe the cleanest ever.

No, it's not going to give you all the bells and whistles that XNA gives you. No, it's not going to be quite as performant as native OpenGL (although I was surprised at just how small the differences were). No, it doesn't have all the built-ins that for example Processing has. But OpenTK is unequivocally tidy, and provided you're familiar with OpenGL, completely intuitive.

Which makes it an extraordinarily productive stack. In the words of the guy who introduced me to OpenTK:

Anything you can do in OpenGL, you can do in OpenTK in half the time.

Depending on what you're building, and whether platform independence is a goal, that may be worth more than bells and whistles.

Tags: OpenGL, OpenTK, 3D graphics, .NET, game programming, C#, generative graphics, graphics, code

13 comment(s)

yo holmes

So does this mean you're going to be doing some game programming-related posts? That would be a welcome change.

Another great option is the TAO framework.

http://www.mono-project.com/Tao

From what I hear it's not as clean as OpenTK, but its complete, and has a larger community. (I think). Anyway I've had good results with it.

TAO is similar to OpenTK, but not as clean. I think OpenTK was actually based on TAO. Somebody wanted a cleaner TAO. OpenTK is the result.

Whatever, though. I agree with the basic point.

I spent four years programming OpenGL in C++ & finally "made the switch" to OpenTK. This library deserves way more attention than it's been getting. TAO is crap. SDL.NET is crap. OpenTK will kick TAO's and SDL.NET's ass up and down the block, every time. Highly recommended.

Basically all the mappings, delegates, helper methods, ErrorHelper. It was a copy from the windows OpenTK.Graphics.OpenGL. The bindings are all there and can load them all from a CglContext which is a new Platform backend OpenGL context I created.

There are something like 2700 method bindings that are delivered with the Windows OpenGL implementation of which only about 600 are used on the mac.

Reading a good airtcle made me learn musc from it,that there are many defferent ideas of authors,share with us and affact us at the same time.Then happy to move your mouse and log in the web to visit my online store.

How do I subscribe to mouse event in OpenTK?

protected override void OnLoad(EventArgs e) { base.OnLoad(e); // Initialize OpenGL properties // Subscribe to mouse events }

Thanks for building it clear! I have been searching about valentine messages topic. I am glad to have found it here. Always keep up the good work love facebook status and always keep endeavor towards the top!

trend and fashion franklin and marshall clothing . I seems to be great and fashion

Reading a good airtcle made me learn musc from it,that there are many defferent ideas of authors,share with us and affact us at the same time. www.jerseysdiscount.net

鈴木克昌幹事長代理、樋高剛総括副幹事長、古賀敬章副幹事長、村上史好、萩原仁、畑浩治、京野公子、大西孝典=以上、幹事長補佐、松崎哲久、階猛、横山北斗、中村哲治=以上、政策調査会副会長、大谷啓、菅川洋、木内孝胤、笠原多見子、石山敬貴、友近聡朗=以上、政策調査会長補佐、玉城デニー、岡本英子、大山昌宏、三宅雪子=以上、広報副委員長、水野智彦、木村剛司、金子健一=以上、企業団体対策副委員長

Use the form below to leave a comment.






Coding the Wheel has appeared on the New York Time's Freakonomics blog, Jeff Atwood's Coding Horror, and the front page of Reddit, Slashdot, Digg.

On Twitter

Thanks for reading!

If you enjoyed this post, consider subscribing to Coding the Wheel by RSS or email. You can also follow us on Twitter and Facebook. And even if you didn't enjoy this post, better subscribe anyway. Keep an eye on us.

Question? Ask us.

About

Poker

Coding the Wheel =
Code, poker, technology, games, design, geekery.


Hire

You've read our technical articles, you've tolerated our rants and raves. Now you can hire us anytime, day or night, for any project large or small.

Learn more

We Like

Speculation, by Edmund Jorgensen.