Here's a preview of Version 1 of Joan Feygran's portrait!
and a wizard lol
:D
(the text in the box is just something i tossed in and isnt actual in-game text)
Hattori's map is complete!
[Blog] Almost Practical IMGUI
Gooier Still
In the previous installment, I suggested some viewing and reading material to acquaint oneself with Immediate Mode GUIs. Hopefully you’ve checked that out but, if not, the following should still be easy to follow. I really wanted to get into the meat of the SilverQuest Gaiden implementation this time but as I was writing it seemed like a good idea to provide a very simple example to build from. So here it is.
A Very Simple Example
This example is based entirely on the pseudocode given by Casey Muratori in his talk.
Below are the IMGUI properties defined in the IMGUI object. These are shared by every element in the GUI.
/// IMGUI Properties{ // ID Tracking ACTIVE = -1; HOT = -1;}
ACTIVE and HOT can hold the value of an ID code unique to each GUI element or control. ACTIVE takes a value when a control is being clicked on. HOT takes a value when a control is being hovered over. A value of -1 is used to indicate that no ID has been set. These two properties are the full extent of state tracking in a canonical IMGUI design. This minimalism is part of what differentiate Immediate Mode from traditional Retained Mode GUIs.
Let’s take a look at a typical widget. This is a button with a text label. The function returns a boolean set to true if it has been clicked, false otherwise. The function is called with arguments to define the button’s unique id, label text, position, and size. This information isn’t retained anywhere, it’s just there for the duration of the function call. Again, this sets IMGUIs apart from traditional RMGUIs.
if (ACTIVE == ID) {
if (MOUSERELEASED) {
if (HOT == ID) {
result = true;
}
ACTIVE = -1;
}
}
else if (HOT == ID) {
if (MOUSEPRESSED) {
ACTIVE = ID;
}
}
if (point_in_rectangle(MOUSEX, MOUSEY, XPOS, YPOS, XPOS+WIDTH, YPOS+HEIGHT)) {
HOT = ID;
}
draw_set_color(c_red);
draw_rectangle(XPOS, YPOS, XPOS+WIDTH, YPOS+HEIGHT, HOT != ID);
if (ACTIVE == ID) draw_set_color(c_white) else draw_set_color(c_black);
draw_set_halign(fa_center);
draw_set_valign(fa_middle);
draw_text(XPOS+0.5*WIDTH, YPOS+0.5*HEIGHT, LABEL);
return result;
}
After setting the default return value to false, the first section of code sets the state of the GUI button. It references some global MOUSE variables: MOUSEX and MOUSEY is the pointer position; MOUSEPRESSED and MOUSERELEASED are mouse button states. I’ll explain this section of code in reverse order since it makes the state transitions a little easier to understand.
If the mouse is over the GUI button, it is made HOT. If the GUI button is HOT and the mouse button has been pressed, it is made ACTIVE. If the GUI button is ACTIVE and HOT and the mouse button has been released, the result returned will be true. This is a Windows-like GUI button behavior. If the GUI button is clicked on but the mouse is then moved away from the GUI button before the mouse button is released, the GUI button will act as if it were not clicked and it will be made inactive.
The second section draws the GUI button in different ways, depending on its state. The GUI button appears as a rectangle with a label centered within it. The rectangle is drawn in red. If the element is HOT, the rectangle is solid, otherwise it is just an outline. If the button is ACTIVE, the text inside will be drawn in white, otherwise it is black. The text itself is drawn in the center of the button. Of course this is very simple looking but the button display could animated or 3D or as fancy as you like.
Finally, the result is returned. A result of true means the GUI button was clicked.
So, how is this actually used? During every screen update of our application or game we do this.
if (imgui_do_button(0000, "Hello", 10, 10, 100, 20))
show_message("Hello World!");
if (imgui_do_button(0001, "Goodbye", 10, 40, 100, 20))
game_end();
And that’s it. Note that in the third button call, “live” data is passed to the button and is acted upon immediately if the button is used. As above, this informs the Immediate Mode name and concept. There is no information or state for the button to keep track of. There is no need to set this information or query it later. The GUI elements are not objects, there are simply function calls.
Virtually any common GUI component can be constructed using this same basic design philosophy. The advantage here is that everything is in one place. With a Retained Mode GUI, things tend to be split up into design, rendering, setters, getters, callbacks, and everything is very static, sterile, and compartmentalized. Decades of GUI inertia have conditioned us to believe this is a good idea.
B-b-but…
You may be thinking to yourself that it still looks a bit fiddly. I have to type in all those coordinates. And that could mean a lot of tedious iteration as elements are nudged around. And if I have to move a bunch of them — yikes! – that’s going to be a lot of work. And that can’t be better than using a GUI design tool to simply place widgets and drag them around the screen with a mouse, lickity-split, I’m done. And you’d be right. It’s not a magic bullet and it can’t solve every problem out-of-the-box.
HOWEVER there is also no reason you cannot extend this method to be more like a traditional RMGUI. That’s a strength, not a weakness. If you want to define your GUI with data and callbacks, go for it. Build a drawing tool for your layout or fashion an automatic layout engine, if that floats your boat. You can make it as complex as you want but it will never be more complex than it needs to be or the equivalent RMGUI. These are things I’ll be covering in the future.
Parting Shots
Developers often dismiss IMGUI as only useful for simple tasks and failing when it comes to dynamism, system scalability, or complex controls. This is demonstrably false. Take a look at this.
That’s Unity and that’s an Immediate Mode GUI.
Nicholas Francis, Unity Technologies co-founder and GUI programmer, gave a talk about it at GDC Europe 2009. You can listen to it here. Unfortunately it isn’t video and doesn’t have slides but it’s a valuable listen.
Johannes ‘johno’ Norneby has a book-in-progress where he gets into more sophisticated concepts for a hybrid MVC-IMGUI. You can read it here.
This GDNet discussion debates the merits of IMGUI versus RMGUI. Read at your peril.
And this is just over-the-top. Anti-OO zealotry? Really? As if OOP was something to aspire to. (runs for cover)
-Xot
[Feedback] Hattori first look
[Feedback]
Which sign is better for a library? :P
[Blog] Immediate Mode GUIs
I’m taking a big a detour today. I expected to post the next installment of the dungeon generation series. But another aspect of SilverQuest: Gaiden I’m currently dealing with are GUIs.
When I talk about GUIs in SQG, these are things like the player character generator and the options menu. The way they were written is a little scatter-shot and difficult to modify. I had decided what I needed is a proper GUI library. This seems a daunting prospect. I’ve made them before and never been wholly satisfied with the results. I think this is a pretty common feeling, if social media is anything to go by.
When I think about GUI libraries, I immediately gravitate to GEM-style systems. This is not because I think they are particularly good. Rather it is because GEM is the first “modern” GUI I was exposed to as an Atari ST programmer. So, I’ve been reading my dot matrix printout of Tim Oren’s Professional GEM and once again its scope is giving me the heebie-jeebies.
As it happens, yesterday a friend on Twitter asked about best practices for implementing GUIs. And this morning while I was sorting through old downloads, I found the helpfully named “867.mp4”. It turns out it was Casey Muratori’s talk on Immediate Mode GUIs.
It’s a very interesting talk but it led me down a frustrating rabbit hole of internet transience due to missing and broken links. I spent some time this morning tracking down this lost information.
If the name Casey Muratori sounds familiar, maybe it’s because he’s made quite a splash with his Handmade Hero streaming educational video series in which he builds an entire 3D game from scratch in C++, showing it live, every day, every step of the way, while explaining every decision and concept. It’s pretty amazing stuff but I digress.
At the end of the GUI talk, Casey mentions Sean Barrett’s upcoming Game Developer Magazine article on Immediate Mode GUIs. You can read it online.
Sean Barrett’s article includes a link to some code and a demonstration.
On that page are some decrepit links to forum threads which are preserved here.
You can also find the remnants of the Molly Rocket forums below. There are a great many topics. They are little difficult to read due to incomplete formatting but at least they weren’t deleted like so much of our ever-fading internet.
Also of note are Sean Barrett’s other articles. The Game Developer Magazine Archives are now free to read and Sean’s Inner Product column is always worthwhile.
Today I also stumbled across something Christopher Rast was kind to point out. Although Tim Oren’s Professional GEM was written in 1986, it has some really valuable chapters on user interfaces that will never be out of date.
And on that topic, Apple’s Human Interface Guidelines is a classic.
Let me know your experiences with Immediate Mode GUIs. I think I’m going to give them a try with SQG.