Skip to content

13. Contributor's Getting Started

Jon McGuire edited this page Nov 5, 2024 · 2 revisions

Welcome

If you're a .NET developer who is interested in fixes, changes, and improvements to Monkey Hi Hat or its related repos, this page will help you get oriented. I'd recommend creating a new Issue to discuss your ideas and plans before you spend much time working on the code, but I very definitely would welcome contributor PRs!

Getting Started

Working on MHH should be as simple as cloning the repo and firing up Visual Studio. I assume anyone interested in development has already installed and run the app, which means you should already have the volts-laboratory content (visualizers, FX, etc) in your C:\Program Data\mhh-content directory. You will want to modify your config file to point there. I won't accept PRs of the config files unless you're (a) adding something new or fixing something, and (b) have applied only those changes to the config files I distribute now. Read the wiki page on configuration to find out how to reference a stand-alone config that isn't part of source control.

Although I'm interested in supporting Linux, I'm not currently equipped to mess around with it, so I don't intend to accept Linux-oriented PRs of any kind in the near future. That being said, please open an Issue to discuss if you want to be The Linux Guy for MHH and you have time to devote to it.

You should probably have at least a passing familiarity with OpenGL programming (GLSL, or at least something like Shadertoy's WebGL). There are definitely areas of the codebase that never touch on that at all, but the bulk of it is really in the weeds on rendering sequences (particularly the intricacies of buffer-handling) and GL resource-handling.

If you're not familiar with multi-threaded applications, unsafe code, or careful disposal of unmanaged resources, I'd advise extreme caution here, and please mention that to me when you open an Issue. For the most part, if you understand async/await and Task usage (for example, you understand the difference between WhenAll and WhenAny and what "aggregate exception" means), you should be fine. OpenGL is not even a little bit thread-safe, and never will be, but most of the tricky stuff happens in the eyecandy audio/OpenGL library that MHH uses.

Solution Structure

The solution has a few Solution Folders which point to content in monkey-hi-hat\testcontent, so if you need to create a test visualizer or FX relating to some new feature, you'll have to manually create it there, then Add -> Existing Item to the appropriate Solution Folder for it to show up.

Apart from that, there is the install .NET Framework project (refer to the readme for some details), and the mhh project itself. Directories within the mhh project are described below.

Console Program

MHH is a .NET console program, so at the top level you'll find a Program.cs with the usual Main entry point. This is a pretty basic config parser and command-line switch parser. MHH is designed to be controlled remotely, so when the program runs, it uses CommandLineSwitchPipe to listen for incoming command switches either via local named pipes, or over TCP/IP from another machine (or Monkey Droid running on Android on the same network).

ConfigFiles Directory

This is where the default program configuration files are stored (mhh.conf and the debug variation), as well as version.txt used by the installer. Check out the readme for details. Notably, you'll see a lot of references to Program.AppConfig which is a public static object exposing the parsed program configuration.

Hosting Directory

The Hosting folder is where you'll find the HostWindow class which is the real program loop that runs MHH visualizations and orchestrates all the rest. This is globally accessible as Program.AppWindow. It exposes a bunch of functions such as Command_Load or Command_QueueCrossfade which the console program code invokes after processing command switches. Although MHH is an OpenGL program, it relies heavily on the wrapper library OpenTK, and HostWindow is where you'll find a few critical OpenTK event-handlers such as OnLoad, OnRender and OnUpdate.

The rest of the class files here are pretty self-explanatory. For example, FXConfig.cs handles parsing and storing the .config files that define post-processing effects, and PlaylistManager.cs handles playlist processing when MHH is running in that mode.

InternalShaders Directory

These are the bare-bones minimum shaders and config files that allow MHH to run without any additional content. There are also some utility files like the pass-through vertex and fragment files which get re-used all over the place. Most of this is compiled at start-up and stored in a cache.

Rendering Directory

Here you'll find RenderManager, which HostWindow exposes as Renderer (ie. Program.AppWindow.Renderer). This class mostly coordinates other specialized IRenderer implementations, which in turn know how to run different types of visualizers (such as single-pass or multi-pass), post-processing effects, crossfade transitions, and so on. If you're interested in this area of the code, start with SimpleRenderer for a bare-minimum example of how these rendering implementations work (particularly the RenderFrame method).

There is also TextManager which can handle displaying and hiding overlay text (which is just another buffer layer generated by a shader).

The static RenderingHelper class is a large collection of methods for common chores such as working with the shader caches, various OpenGL resources like textures and uniforms, and complex tasks like viewport calculations after window-resize events.

Utils\Caching Directory

MHH has a few types of caching, all of which is exposed through the Caching.cs static class. In some cases like IdleVisualizer or TextShader, the "cached" data is just an object directly held by the class. There are also several Least-Recently Used (LRU) caches for visualizer, FX, and library shaders, and a permanent List<> cache of the crossfade transition shaders, which are scanned, loaded, and compiled at start-up (because they're used very frequently).

The class also stores a MaxAvailableTextureUnit integer. This may seem like a strange place to store this value, but the thinking is that it's cached because it has to be read from OpenGL, and it's used often enough that we wouldn't want to be re-reading it all the time via native API calls (and it is specific to your GPU and won't change unless you physically swap hardware).

Utils\Global Directory

This directory is basically the dumping-ground for globally useful stuff -- constants, enumerations, extensions, logging, and path utilities. Pretty self-explanatory.

Utils\OpenGL Directory

Not surprisingly OpenGL-specific code and definitions are stored here. In particular, GLResourceManager.cs handles the fairly complicated processes around creating, resizing, and cleaning up textures and framebuffers, and keeping track of all the little details and numbers that OpenGL requires for each of these. Within MHH we have the concepts of GLResourceGroup and GLImageTexture, which are a field-only classes where all those OpenGL details are stored by the manager.

When you get into multi-pass buffer handling, particularly when you're talking about more than one of them running at once (such as a multi-pass visualizer plus a multi-pass post-processing effect), this can get pretty tricky -- especially when you're trying to sustain 60FPS at high resolution, all while tip-toeing around the non-thread-safe OpenGL API.

Definitely talk to me ahead of time if you think you want to mess around in this area of the program.

VertexSources Directory

In MHH parlance, a vertex source is what feeds data into the vertex stage of the shader pipeline. Currently there are only two, and these are documented elsewhere in the wiki. Pretty simple stuff.

Other Repositories

In addition Monkey Hi Hat itself, I have several related repos you should be at least passingly familiar with. (There are a few others not listed here, such as my CommandLineSwitchPipe library, plus some third-party dependencies like OpenTK, FFTSharp, and NAudio, but I don't really anticipate any need for anyone to mess with those much.)

Repository Description
eyecandy A library that does all the heavy lifting of analyzing audio data and converting it to OpenGL textures, which the shaders use for music reactivity.
volts-laboratory Storage for all of the visualizer, FX, crossfade, and library config and shader files that make up the content distributed with MHH.
monkey-see-monkey-do A Windows Service distributed with MHH that can start MHH over TCP/IP if MHH is not currently running (for remote-control convenience purposes).
monkey-droid A MAUI 1.0 remote-control application for Android and Windows. Unsure about the future of this one, it works and it's convenient, but MAUI is a train-wreck right now from the developer-experience standpoint.

Conclusion

For starters, check out Program.cs and HostWindow.cs, then follow your way into the rendering pipeline. I'm a big believer in explanatory comments, particularly when the code is doing something complicated.

I'm looking forward to your interest and assistance!