Not too long ago, I was brought on as a maintainer on the OpenTK project - I had been building some contributions which were in the process of being reviewed. I took the time to delve into some of the more arcane parts of the library to fix an additional compilation step which had broken due to the move from .dll.mdb to .pdb in Mono.

I'd been using OpenTK for a while, and they were low on manpower, so I offered to help. Thus far, it's proven to be fairly interesting work - OpenTK is an old and (to me) very large codebase with a lot of inconsistencies and bizarre magic. It's a great project, but in severe need of some love.

Currently, we have a number of fairly hefty plans for the library - primarily, we want to target .NET Standard 2.0 instead of the ancient .NET Framework 2.0, giving all platforms equal opportunity to use the library. Second, we want to split the library into smaller assemblies. At present, the library is a massive beast with mixed concerns, implementations and responsibilities, all jammed together into one large clump. Splitting it into smaller assemblies would alleviate a lot of these issues, and force some much-needed refactoring.

This post is the first of a series of devlogs (a fancy term for putting thoughts on paper while not actually providing any value to anyone else), and will focus on laying out my initial plans for the library split. These plans are, as everything is this early in a development cycle, subject to change and may be shuffled around. It's going to be a large breaking change, and will not be backwards compatible. It's still going to be the same old low-level OpenTK we've grown used to, just better laid out.

Splitting a library

The primary goals of the split project are as follows:

  • Allowing the end user to only pull in what they need
  • Reducing tight coupling between parts of the library

My secondary goals are:

  • Using the split as an opportunity to refactor and restructure code
  • Standardizing and normalizing the codebase as a part of the split

Hopefully, these goals should have been achieved by the end of the split.

Without having had the time to do more than some cursory experimentation, these are some of the issues I expect us to hit while working:

  • Cyclical dependencies between unrelated concerns. The Input and Graphics portions of the library are very guilty of this.
  • Interface multitasking - a number of interfaces deal with multiple concerns at the same time.
  • Cross-platform gotchas - the .NET ecosystem is no longer just a Windows platform, and other systems have to be taken into consideration
  • Mobile support

Xamarin currently has their own fork of OpenTK which will not be compatible at all with this new layout. Either they're going to have to do some house cleaning in very much the same manner as we are, or they'll have to maintain their fork as is (which they've been doing up until now). This does prevent users from using the new OpenTK on mobile platforms without some major hoops, though, and we'll have to see what we can do about it. Frankly, it's worthy of its own post.

Now, as for the actual parts the library will be split into, in my original experiments I tried to adhere to the existing separations inside the library. It became clear fairly quickly that this would not be sufficient, so after a bit of discussion with another member of the project (Frassle - thanks!), we've concluded that we need to do a far more fine-grained separation than we anticipated.

Primarily, the library will be split into three levels of API - high, medium and low.

High-level libraries

These libraries take on the role of very abstracted API for the user - platform-agnostic windowing systems, input systems, mathematics, etc. They should be equally usable on any platform OpenTK targets and supports (factoring in things like Android and iOS, for example).

At present, I see the following libraries as being split out with their respective concerns:

  • OpenTK.Display : High-level graphics API - windowing, mouse cursors, etc
  • OpenTK.Android : Android-specific functionality. This may depend on Display
  • OpenTK.iOS : Same as above
  • OpenTK.Forms : ẀinForms controls and API
  • OpenTK.GTK.Widgets : GTK widgets and API
Medium-level libraries

In general, the medium-level libraries are perfectly serviceable for the end developer, but do not provide as much of an abstraction as the high-level libraries do. High-level libraries almost certainly depend heavily on use of these.

Generally, they're still abstracted, but will not be plug and play. Furthermore, they also create medium-level wrapping functions for the low-level libraries - for instance, a native method which takes three consecutive floats might get a wrapper method which takes a Vector3 instead.

  • OpenTK.Graphics : Base graphics API - GraphicsContext, WindowInfo, etc
  • OpenTK.Input : Input API - mice, keyboards, controllers, etc
  • OpenTK.Audio : Audio API - AudioContext, binding wrappers, etc
  • OpenTK.Math : Assorted mathematics which are not present in the standard. Linear algebra, floating-point comparisons, etc.
Low-level libraries

Finally, we have low-level libraries. These contain no abstractions whatsoever, and are very thin wrappers and bindings around native libraries. These are pulled in by the medium-level libraries and are used to build abstractions.

Of note is that they will have a public API and can be used independently by applications. However, they will not receive the same support priority as the other libraries. You're expected to know what you're doing and have enough mojo to troubleshoot if you hit any issues.

  • OpenTK.GL : OpenGL bindings
  • OpenTK.GLES : OpenGL: ES bindings
  • OpenTK.X11 : : X11 display server bindings
  • OpenTK.Cocoa : OSX Cocoa bindings
  • OpenTK.SDL2 : SDL2 bindings
  • OpenTK.NT : Windows NT kernel bindings
  • OpenTK.AL : OpenAL bindings

We've also got Vulkan and Wayland support in mind, so despite the fact that OpenTK does not currently have any Vulkan or Wayland bindings, it's worth mentioning.

  • OpenTK.Vulkan : Vulkan bindings
  • OpenTK.Wayland : Wayland bindings

Hopefully, this split will improve the usability of OpenTK, as well as making maintenance of the individual portions much easier.

I'll be writing more posts about specific parts as the work progresses. To get involved, discuss the changes, present thoughts and ideas, etc, come by Gitter or the repository - the more, the merrier!