the Fiddler's picture

Investigate possible WinForms-based GameWindow implementation.

Project:The Open Toolkit library
Version:0.9.x-dev
Component:Code
Category:task
Priority:normal
Assigned:Unassigned
Status:closed
Description

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.

AttachmentSize
GameWindow2.7z391.81 KB

Comments

Comment viewing options

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

#11

Old 60.0/60.0 CPU 25% (one full CPU) memory stable at 19.5 MB
New 60.2/60.0 CPU 0% memory stable at 20 MB
(Note: Goes straight to 60 FPS and stays there.)

martinsm's picture

#12

Does this still occur if you set CPU affinity?

Yes, same result. Setting affinity doesn't change anything.

objarni's picture

#13

@Kamujin et al

Is it possible that the delay until 60 fps is reached is a feature of the new Run Loop Scheduler? Is there an easy way to verify whether that is the case or not?

the Fiddler's picture

#14

Try running the latest version of the code, which gives you the option of switching between the old and the new implementations. If this behaviour only occurs with the new one, there's a good chance this is an artifact of calling Thread.Sleep in the new scheduler.

objarni's picture

#15

Bingo.

It is 60 from start with the old implementation.

Suggestion: Let Kamujin hack away some to fix this (or someone else) because I really think his algorithm for "stable FPS rate" is a good feature to have in games programming.

the Fiddler's picture

#16

Status:open» in progress

I have integrated, but not committed, the code from the opening post into OpenTK. The implementation is slightly different: you can either create a NativeWindow, which is (as an abstraction) roughly at the same level as a Form+GLControl, or you can create a GameWindow which is also includes a main loop.

Additional perks:

  • GameWindowExitException is now gone.
  • You can completely replace the main loop with your own implementation.
  • Mouse and Keyboard input are no longer bound to the GameWindow (you can use them along with e.g. GLControl or anything else).
  • New events will report unicode input (this will not go through OpenTK.Input).
Kamujin's picture

#17

Sorry guys, I missed this thread. I'll take a look at it and see what I can come up with.

FWIW, The interleaved scheduler is a fuzzy algorithm, so it does take a certain amount of time to learn the correct sequence to generate the target frame rate. This should be a matter of seconds, not minutes.

Kamujin's picture

#18


JTalton wrote:
"Old 60.0/60.0 CPU 25% (one full CPU) memory stable at 19.5 MB
New 60.2/60.0 CPU 0% memory stable at 20 MB
(Note: Goes straight to 60 FPS and stays there.)"

I get the same results for my tests with GameWindow2

objarni's picture

#19

FIddler: Is there any example of the do-it-yourself-mainloop way of using OpenTK? I mean in Examples.exe.

the Fiddler's picture

#20

As I mentioned above, this code is not yet in SVN so no examples yet. However, right now the code looks similar to the GLControl: the NativeWindow provides an Idle event where you can place your game loop. The GameWindow is simply a child of the NativeWindow that implements a predefined game loop.

In other words, the inheritance tree looks something like this:

public interface INativeWindow : IDisposable
{
    string Title { get; set; }
    Point Location { get; set; }
    Size Size { get; set; }
    // Several other properties
 
    event EventHandler<EventArgs> Load;
    event EventHandler<EventArgs> Unload;
    event EventHandler<EventArgs> Idle;
    // Several other events
}
 
public interface IGameWindow : INativeWindow
{
    event EventHandler<FrameEventArgs> UpdateFrame;
    event EventHandler<FrameEventArgs> RenderFrame;
}
 
public class NativeWindow : INativeWindow
{
    ...
}
 
public class GameWindow : NativeWindow, IGameWindow
{
    protected override OnIdle(...)
    {
        ...
    }
}

In other words, a GameWindow is just a NativeWindow with a main loop. You can provide your own implementation by inheriting from either class and overriding the OnIdle method.