Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
99 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

  Contents

 Introduction
 Saving Windows
 Loading Windows
 Resource Editors
 Subclassing
 Speeding Up
 GUI Rendering

 Conclusion

 Printable version

 


  The Series

 Part I
 Part II
 Part III
 Part IV

 

Subclassing

Those of you who are familiar with the way Win32 does its windowing probably already know what the term "subclass" means. For those of you who don't – when you "subclass" a window, you effectively "derive" a new window type, and then wedge your new window type into places where the old window used to be.

Let me explain that a little better. Say we need a Super Listbox. We've got a normal listbox class, but it just doesn't cut it for some reason; our game demands the Super Listbox. So we derive a new "super listbox" class from our regular listbox class. So far so good.

But how do we place the Super Listbox in our game's dialog? Since the Super Listbox is specific to our application, it wouldn't make sense for us to add functionality to our resource editor to support it. But, at the same time, how do we tell our GUI system that for this one particular instance (our game), we'd like all listboxes to really be Super Listboxes? That's what subclassing is all about – it's not an exact, technical definition, but it will suffice for now.

The approach I'm about to illustrate is what I call "subclassing at load time." To understand it, let's start with the basic loading code I described in the last section. We've got a load function, which recursively news, loads, and then adds windows. Specifically, we've got something that looks like this, in PDL:

// read total number of children for this window // for each child... // read window ID from disk // new a gui_window derivative based on that ID // ... // next child

To implement subclassing, I've told my window loading routine to "give the application a chance to create a window of this type," like so:

// read total number of children for this window // for each child... // read window ID from disk // give application a chance to create a window of this type // if the application didn't create a window, // then new a gui_window derivative based on the ID // else, use the application's created window // ... // next child

Specifically, I give the application this chance by way of a function pointer. If the application needs to subclass a window, it fills in the function pointer with the address of its own function. When the windows are loading, they call this application function, passing in the ID of the window they want to create. If the application wants to subclass a window from this ID, it news up the appropriate object and returns the new pointer back to the window. If the app doesn't want to do anything special for this ID, it returns NULL, and the window function senses this and news up the appropriate default object. This method allows the app to "pre-filter" the incoming window ID bytes, and to override the default behavior for certain window types. Perfect!

Using a method like this gave me a huge amount of freedom when it came to creating custom controls. I went back and added code to my resource editor that would let me change the IDs that were saved for each window. Then, when I needed a custom control in the app, I just used my resource editor to change the ID byte that was saved for that window. Saved on disk would be the ID, along with the dimensions and all the other base-class properties for the custom control!

Real quickly – there's another way to do this same thing, and that is to mirror the approach the STL has used when it needs to create things. The STL uses special "allocator" classes, which are sort of like "factories," in the sense that clients tell them what they want created, and they create it. You could use this same approach for creating windows.

It'd work something like this. Create a class and call it gui_window_allocator. Implement one virtual function, say CreateWindowOfType(…), which would take in a given window ID and spit back out a brand new pointer to that window. Now you've got a very simple allocator class, which your window loading code will use by default to new up windows as they are needed.

Now, when your application wants to override the "new" behavior for the windows, you simply derive a new, application-specific gui_window_allocator class, and tell your window loading code to use this allocator instead of the default one. This method is similar to providing a function pointer, only with a bit more C++ thrown into the mix.


Next : Speeding Up GUI Rendering