the Fiddler's picture

Investigate possible WinForms-based GameWindow implementation.

Project:The Open Toolkit library

A Windows.Forms implementation of GameWindow will significantly reduce the amount of code we have to maintain in OpenTK.Platform. It will also make new new features easier to implement and the code will be better tested.

I have spent some time implementing GameWindow2 using Windows.Forms, GLControl and Kamujin's InterleavedScheduler. The resulting code is, indeed, much simpler and supports several features missing from the current implementation:

  • Support for custom main loops.
  • Support for window icons.
  • Support for setting the window position.
  • Saner event interface (closer to the BCL conventions).

On the other hand, the new code is missing keyboard and mouse support, cannot run at unlimited update / render frequencies and is not compatible with GameWindow.

I'd love to hear your feedback:

  1. Does it run on your system? (which OS?) You should see a black 640x480 window with a fps counter on the top-left corner. I am especially interested in Mac OS X.
  2. Is your fps stable and close to 60?
  3. How is the CPU and memory usage compared to the old implementation?
  4. Try setting different pixel formats in the GameWindow2 constructor - does it still work?

Binaries and source code are attached. I won't be having much free time the next few weeks, so please feel free to make modifications and corrections (consider it released under the OpenTK license).

Edit: New version which suppresses WinForms Mouse & Keyboard messages and changes FrameEventArgs.Time from TimeSpan to double.

Edit 2: New version that allows you to choose between the old and new GameWindow implementation for comparison.

Edit 3: New version that forces VSync to off.

Edit 4: Please ignore the attachment below, it is outdated. Use the file located here.

GameWindow2.7z391.81 KB


Comment viewing options

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


Indeed, heh :)

objarni's picture


OK results:

GLSL 1: First shader: works
GLSL: GLSL Animated Julia Set: works

OpenAL: AL-examples (skipping these I don't have OpenAL in Ubuntu)

OpenGL 5: Vertex Arrays (hidden): see VertexArrays.png
OpenGL: Framebuffer Objects: works
OpenGL: GLU Tesselation Functions Test (hidden): see .png with same name
OpenGL: Vertex Lighting: Rotating quad, solid color, don't know if
this is expected, see .png

Test: Tests (skipping most)
Test: Test Resolution Changes: shows fullscreen 640x480, goes back

Tut 1: Simple Window: crasch, see .png
Tut 2: Immediate mode: crasch, see Simple Window.png (same)
Tut 3: Display Lists: works
Tut 3: (tut 3 comes two times!) Fonts: works
Tut 4: Texts: works (but show a flickering 3 or 6 only, don't
know what is expected behaviour)
(tut 6,7 missing!)
Tut 5: Texture mapping: works
Tut 8: Vertex Buffer Objects (hidden): works (I guess..)

WinForms 1: Simple GLControl: works
WinForms 2: GLControl game loop: works
WinForms 4: (where is 3?) Multiple GLControls test: works
WinForms: Font rendering sample, works (but the Change Font
windows is placed _behind_ the OpenTK window..)

GLSL_Cube_debug.log41.36 KB
GLU Tesselation Functions Test.png40.91 KB
Simple Window.png39.09 KB
VertexLighting.png10.09 KB
VertexArrays.png10.68 KB
the Fiddler's picture


Thanks for the extensive testing. At this point, tut 1 and 2 are the important ones (these rely on the new GameWindow). Progress is slower on Linux, due to the compilation problems on Mono (thankfully these will be fixed in Mono 2.4.1 and 2.6).

There's a lot of work left to do for this task, especially wrt to input handling, but this is the last large missing piece.

the Fiddler's picture


Status update: The more I work on this, the more it seems that this is not the way forward.

On the plus side, all the necessary functionality works out of the box (window size, position, visibility, icons, etc). On the other hand, I am getting weird threading issues, exceptions and (unmanaged) crashes on Mono.

@objarni and other Linux users: please try testing the latest gw-next code again. We only care about 'Test: InputLogger', 'Tutorial 1: Simple Window' and 'Tutorial 2: Immediate Mode'. Do they run? Do they crash? Try pressing some keys on the keyboard, do they react? (e.g. on Escape).

This branch should compile out of the box on Mono 2.0 (e.g. Ubuntu 9.04) and should also compile on Mono 1.9.2 (e.g. Ubuntu 8.10). It won't work on newer Mono versions but don't worry about that.

# Ubuntu 9.04 (MonoDevelop IDE):
sudo apt-get install subversion mono-gmcs libmono-winforms2.0-cil monodevelop monodevelop-versioncontrol monodevelop-debugger-mdb
svn co gw-next
cd gw-next/Build
mono Build.exe vs
monodevelop OpenTK.sln &

Make sure 'Examples' is set as the startup program and simply hit 'Run' (or 'Debug' if you are feeling lucky).

# Ubuntu 8.10 & 9.04 (terminal):
sudo apt-get install subversion mono-gmcs libmono-winforms2.0-cil nant
svn co gw-next
cd gw-next/Build
mono Build.exe mono debug
cd ../Binaries/Debug/Examples
mono --debug Examples.exe
objarni's picture


I can try this out this evening, will report back then.
(hooray will install Ubuntu 9.04 this weekend! fun stuff!)

Update: I stupidly enough tried installing Ubuntu 9.04 tonight, and got the same problem as half a year ago - read error after 33% or something has been installed. Will make a new try with the USB-stick method tomorrow.

Reporting back tomorrow night, hopefully with some test data to deliver..

kanato's picture


So I'm playing around with testing this on Windows.

Tutorial 1: Pressing escape closes the window and then gives a "No context is current in the calling thread (ThreadId: 10)." exception.
Tutorial 2: Doesn't have this problem, but doesn't respond to keystrokes.
Input Logger: Pressing any key results in a crash with the message "Object of type 'OpenTK.GameWindow2' cannot be converted to type 'OpenTK.GameWindow'."

Here is the stack trace:
at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.Form.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at Examples.Tests.InputLogger.Main() in C:\Users\Erik\Documents\devel\Games\Agate\OpenTK\gw-next\Source\Examples\Tests\InputLogger.cs:line 305

I've also tested in OpenSuse with Mono 2.0, and it seems like I get about the same results. It's a bit harder to investigate the details of the InnerException property of the TargetInvocationException there though. Have you thought about changing exceptions so that they implement an interface rather than using reflection to load the Main method? It would get rid of the TargetInvocationException and let the VS debugger break right where the exception is thrown.

flopoloco's picture


I got this bug...

opentk-gw-next-bug.png104.93 KB
the Fiddler's picture


@kanato: Ideally, the sample code should run without modifications outside Examples.exe - that's why there's no IExample interface. It's annoying when debugging, true.

I haven't tested on Windows, so I expect the new code to be broken there. Hope to stabilize everything the next few days.

@flopoloco: This seems to happen with recent Nvidia drivers. I haven't been able to reproduce it on Ati, no matter how hard I try, so I've written this off as a driver bug. Try launching Examples.exe again, it should run after a couple of tries.

kanato's picture


That's true. I suppose that could be gotten around but putting the interface in OpenTK.dll or OpenTK.Utilities.dll but that's rather hackish.

objarni's picture


I haven't come around to testing this yet.

I got as far as having mono 2.0 and winforms installed. Mono 2.0 hang on first boot, but second try it looked nice.

I'll do my home work asap!