I've been working on application development with a lot of "retained" GUI systems (below more about what I mean by that) like MFC, QT, Forms, SWING and several web-GUI frameworks some years ago. I always found the concepts of most GUI systems overly complicated and clumsy. The amount of callback events, listeners, data copies, something to string to something - conversions (and so on) were always a source of mistakes and headaches compared to other parts in the application. (Even with "proper" use of Data Bindings/Models).
Now I am writing computer games :). I worked with one GUI so far: Miyagi (not well-known, but basically the same Idea as all the other systems.)
It was horrible.
For real-time rendering environments like Games, I get the feeling that "retained" GUI systems are even more obsolete. User interfaces usually don't need to be auto-layouted or have resizable windows on-the-fly. Instead, they need to interact very efficiently with always-changing data (like 3d-positions of models in the world)
A couple of years ago, I stumbled upon "IMGUI" which is basically like an Immediate Graphics mode, but for user interfaces. I didn't give too much attention, since I was still in application development and the IMGUI scene itself seemed to be not really broad nor successfull. Still the approach they take seem to be so utterly sexy and elegant, that it made me want to write something for the next project using this way of UI (I failed to convince anyone at work :(...)
let me summarize what I mean by "retained" and "immediate":
Retained GUI: In a separate initialization phase, you create "GUI controls" like Labels, Buttons, TextBoxes etc. and use some descriptive (or programmatical) way of placing them on screen - all before anything is rendered. Controls hold most of their own state in memory like X,Y location, size, borders, child controls, label text, images and so on. You can add callbacks and listeners to get informed of events and to update data in the GUI control.
Immediate GUI: The GUI library consists of one-shot "RenderButton", "RenderLabel", "RenderTextBox"... functions (edit: don't get confused by the Render prefix. These functions also do the logic behind the controls like polling user input, inserting characters, handle character-repeat-speed when user holds down a key and so on...) that you can call to "immediately" render a control (doesn't have to be immediately written to the GPU. Usually its remembered for the current frame and sorted into appropiate batches later). The library does not hold any "state" for these. If you want to hide a button... just don't call the RenderButton function. All RenderXXX functions that have user interaction like a buttons or checkbox have return values that indicate whether e.g. the user clicked into the button. So your "RenderGUI" function looks like a big if/else function where you call or not call your RenderXXX functions depending on your game state and all the data update logic (when a button is pressed) is intermangled into the flow. All data storage is "outside" the gui and passed on-demand to the Render functions. (Of course, you would split up the big functions into several ones or use some class abstractions for grouping parts of the gui. We don't write code like in 1980 anymore, do we? ;))
Now I found that Unity3D actually uses the very same basic approach to their built-in GUI systems. There are probably a couple of GUI's with this approach out there as well?
Still.. when looking around, there seem to be a strong bias towards retained GUI systems? At least I haven't found this approach except in Unity3D and the original IMGUI community seems to be rather .... .. quiet.
So anyone worked with both ideas and have some strong opinion?
Edit: I am most interested in opinions that stem from real-world experience. I think there is a lot of heated discussions in the IMGUI-forum about any "theoretical weakness" of the immediate GUI approach, but I always find it more enlightening to know about real-world weaknesses.
Answer
Nay. I've done paid gamedev work on an awful 'retained mode' GUI and on an awful 'immediate mode' GUI and although both made me want to tear my eyes out, the retained mode approach is still clearly the better one.
The downsides of immediate mode are many:
- they don't make it easy for artists and designers to configure the layout;
- they make you mix logic with presentation;
- they make it harder to have a single consistent input model;
- they discourage complex controls of dynamic data (eg. list views);
- layering becomes very awkward (eg. if I call RenderComboBox, the drop-down box can't possibly render yet because it needs to go above the rest of the window - same for tool-tips)l
- configuring rendering style ends up being done with globals (ick) or extra function arguments (ick);
- performance can be poor because calling all these functions to query values that may or may not have changed tends to create many small objects, stressing the memory manager;
- ...and I can't even imagine how painful it would be to allow someone to drag bits the GUI around and re-order them. You'd have to maintain a data structure telling you where to render everything - which is much like rewriting a retained mode system yourself.
Immediate mode GUIs are tempting for lone programmers who want a quick HUD system, and for that purpose they are great. For anything else... just say no.
No comments:
Post a Comment