When I started with nifty, there was virtually no documentation for the version that JME had just adopted. Everything I learned was by extracting the examples from the demo jar file and through hours of trial and error. To me, everything always felt 10x harder than I thought it should be. I’ve since been made to feel stupid and that it was my own failings. That’s fine. I’ve only coded to about half a dozen GUI APIs without issue and written at least as many myself. No worries. When it comes to nifty, I am completely stupid. I won’t argue there.
Other than the lingering bad taste in my mouth, the way nifty and JME interact is pretty inefficient. Nifty basically wants to write to an immediate mode “canvas” and JME tries to emulate that with scene graph components. We’ve made a lot of optimizations to make that better but it still seems like a lot of work if all I’m doing is putting a few buttons on a HUD screen. So for simple things, I wanted something JME-based that could interact with regular nodes and controls. Where parts of it could be batched or whatever.
Now that I’ve gotten the more contentious reasons out of the way, the final straw was that I wanted 3D support. I’d already been creating hybrid 3D+2D GUIs for Mythruna and it was becoming painful to essentially reinvent the wheel every time. A core of common components was slowly developing. I already had some pretty nice mouse event support (See below) and felt like it wouldn’t be much to take the next step.
So, now I have a UI toolkit that works in 2D or 3D or both. It uses a couple app states and a couple controls at the base level and then wraps that in some nice wrapper classes (Label, Button, Slider, etc.) but really these are just hooking up the CSS-like style support to the underlying pure JME concepts.
There is a GuiControl that when added to a node can manage a stack of GuiComponents. These are responsible for creating the geometry children that represent the node. So if you stack a QuadComponent with a TextComponent then you get a label with a box around it. And so on. There is an interaction between the layers that is too much to explain here. But the QuadComponent is automatically sized for the TextComponent… and if you add two QuadComponents the first one will be big enough for the second and the second will be big enough for the text.
The GuiControl can also take a layout that can be used for managing the position of child nodes that have GuiControls. Layouts are 3D but the default implementations are 2D so far… though they let you pick which 2 axes.
There is also a MouseEventControl that can be added to any Spatial. Combine this with an app state that handles mouse events and picking and any spatial (2D or 3D) that has a MouseEventControl will get classic enter/exit/move/button events. I’ve created entire GUIs with just this control and app state. All of the in game non-nifty Mythruna GUIs in the last release are built this way.
The Label, Button, etc. style elements and the style support are just wrappers above all of that… either of which is useful on its own without the wrappers.