Archive for August, 2007

Unit Test Framework

Thursday, August 30th, 2007

In my previous post about why I’m excited for our rewrite, I forgot to mention our unit test framework. It is really quick and dirty, and we don’t do anything fancy to get around the fact that certain things are just hard to deal with (e.g. “did that sound right?” or “did that draw correctly on screen?”). However, the unit test framework has really allowed us to be sure what we are building on is solid and behaves as we expect it. It has also great been really great for testing a change quickly. For example, the other day I gutted our LoadOgg helper function, but since we had tests written for it it was really easy to be sure I had not broken it. Before our rewrite, we would have to run the whole game, get to the place in-game where our change came into play, and then see if it was right. Now we can just write a test or two for the new change and if we want to we can disable all the other tests. That really speeds up debugging.

Also, because we are making heavy use of the event system, we can test the event sender and the receiver separately. For example, the SoundBuffer and SoundStream classes basically just send events to the sound system telling it to play/pause/stop a sound. In the test, I set my own listener for those events and verified that they are being sent correctly. Another place where the event system was useful was in the initialization of the input system. The input system needs some kind of window handle to give to OIS. Collin set it up so that the input system sends an event with a Variant window handle field. If it is initialized, the render subsystem receives that event and sets the window handle value. However, if you do not have the render system running for whatever reason (like in the input test), you can just register your own handler for that event. So in the input test, Collin creates a simple little window just to get input with raw X11 or Win32 code, and his test receives the event and returns the proper handle. The input system doesn’t care whether the render system created the window, or you did yourself. All it cares about is that something provided it with a window handle. That is pretty slick.

As I mentioned earlier, we aren’t doing anything fancy for user input/output tests for things like sound, graphics, or input. We basically do what we want and then ask the user “did that seem right?” That can get annoying if you are working on something like the sound system. Testing it is a lot of “did the music start?”, “did it stop?”, “did it start again?” kind of questions. It’s not perfect, but it is a simple way to verify that the code works. Compared to what we had it is a huge step forward.

Why I’m Excited About the Rewrite

Thursday, August 23rd, 2007

I have mentioned that I am really excited about our rewrite several times, but I haven’t ever gone into much detail about why that is. I hope that we have learned from what worked and what didn’t work in the old Crown and Cutlass code, and applied those lessons to the new Protocce code. I’m sure there are still things that we will realize are not well done, but this is a much more stable base for future work. Here are several specific things I’m excited about:

Exception – We implemented the pcce::Exception class which we now use consistently for error reporting. Coupled with our greater focus on RAII (see below), I think we have made some serious progress. We used to use error codes sometimes and throw other times. Unfortunately, sometimes we threw strings, sometimes we threw char *’s, sometimes we threw ints, etc. This is much better. It does not descend from std::exception at the moment, but we are thinking about doing that.

Greater focus on RAIIRAII is really a great idiom for resource management in C++, especially when coupled with smart pointers like boost::shared_ptr. We have design for RAII from the start, so that should make things much more manageable. Again, I’m sure we have more to do in this area, but we have a good start.

Variant – At work, I have gotten used to using the Win32 Variant class in Delphi. While it certainly has its drawbacks, it sure can be helpful for doing things like reading text from a config file. Our variant class is cross platform, and based on boost::variant. I think it will change a little as we use it, but I’m pretty happy with it now. You wouldn’t want to use it when a statically typed variable will do, but for example the config system was really easy to do using Variant.

PropertyBag – Again, at work I got used to using “property bags” which are basically just a map from a string to a variant value. You wouldn’t want to replace all of your normal classes with a property bag (static typing can be nice!), but it can be really useful. For example, our configuration system is an INI file. That gets loaded into a property bag. When you initialize a subsystem, you pass its settings as a property bag. That way, you can change the config options around without changing the config object or the method signature. We have also used property bags to create “game objects” which are just property bags with a couple of predetermined fields for model name, texture, etc. The game programmer can put whatever else he wants in there.

Consistent use of shared_ptr – I really don’t mind managing my own memory, but once you start talking about exceptions and RAII, using some kind of smart pointers really makes sense. We are making pretty serious use of boost::shared_ptr, which has made a lot of things easy. No need to worry about who owns an object, as long as you have a shared_ptr to it, it will stay valid. Of course, we have to think about circular references, but overall I think using smart pointers is a big win.

OGRE – I think it’s pretty clear why I am excited about OGRE. Originally, the project was just an excuse to do OpenGL programming. I enjoyed that, but now I am more interested in other things. I’m a little sad not to get to try that from the ground up, but eventually we can revamp Protocce to use a custom engine if we want. Until then, using OGRE will simplify our code, standardize our models (our old model loading code was really picky), and open up the doors to easily implementing graphical improvements. It will also allow us to focus on the game itself, rather than the details of the graphics.

EventSystem – Our old code used to be very tightly coupled (see the SailingState for an example), so minor changes could not only cause a large number of units to need to be rebuilt, but also end up causing a large number of code changes. The event system is based on what is mentioned in Game Coding Complete and allows us to significantly decouple our code. Once an event is defined, you can register a boost::function to receive that event. Events can be dispatched immediately, or queued to be dispatched once per frame. I expect the way that will work is that game events will be queued, while internal “plumbing” type stuff will be sent immediately. As an example, the input subsystem needs a window handle to receive input. Rather than connecting it directly to the render subsystem (which would force you to initialize the entire render subsystem if you wanted to use the input subsystem), the input subsystem just sends an event that the render system receives. If you don’t want to use the render subsystem for some reason, you could just register a different handler for that event. Collin actually does that in the input test. As I mentioned in my previous post, the sound system is also event driven. It is running in its own thread, and all the main thread does is send an event that says “play sound X” or “stop sound Y”. That data is easily sent out to the other thread, where the actual sound code handles it. We can totally revamp the sound implementation and not touch client code at all. I think the event system is a much more flexible system and I think it will open up a lot of doors for us.

Improved resource management – I mentioned this a little in my last post too. Between the release of Alpha 1.4 and the decision to start the rewrite, I wrote a resource management system. It was pretty good. It would make sure that only one copy of a texture, sound file, or model was loaded at a time and used reference counting to automatically unload the model when it was finished. I have further refined it (partially based on the OGRE resource system) and posted a reply on gamedev explaining the Protocce resource system.

Anyway, there are other things but that is a decent explanation of the things that I am excited about.

Sound System Progress

Wednesday, August 22nd, 2007

I have been working on the sound system lately, which has been pretty enjoyable. I based the design on the old sound system. I’m not sure if many people saw that, because I implemented it (along with resource management) between the release of Alpha 1.4 and our decision to rework the code from the ground up. It was pretty slick from the end user’s perspective. The user could create a new SoundEffect object and that would acquire a pointer to the shared AL buffer automatically. That buffer was shared, so there was never more than 1 copy of “cannon.ogg” or whatever in memory at one time. It would also automatically unload the buffer when the last SoundEffect using it was deleted. The sound system also managed your OpenAL sources so that only a given number of sources would be created. If you tried to play more sounds than that, it would revoke the source from the oldest sound to play the most recent. That was pretty nice, but it was a little ugly behind the scenes because when I originally wrote it I was not yet aware of boost’s smart pointers. I had a feature where you could “lock” a source so it would not be revoked, but I never used that because I never updated the code to stream ogg files from the disk to use the sound system. As a result, the source management was much more complicated than it needed to be and it was still possible to run out OpenAL sources if you played too many sounds at one time.

I have gotten a good chunk of the way through moving the sound system into our new codebase. I think in general the sound system is much better now. It is a little ugly because it is running on its own thread, but I think that will be worth it. I have renamed the SoundEffect class to SoundBuffer (since it is a sound that is played from a single buffer in memory as opposed to one that is streamed from disk, which is done with the SoundStream class). It has basically the same interface as it used to, but now all the SoundBuffer does is fire off events to the SoundSubSystem (as you can see in the SoundBuffer implementation). Sources are still revoked just like they were, but now I am positioned to combine the source allocation for the SoundStream class too. I wrote a really simple class for reading ogg/vorbis files in a more C++ friendly manner. It allows us to use RAII and hide some of the oddities of the vorbis lib. I reworked our LoadOgg function that loads the entire contents of an ogg/vorbis file into a single OpenAL buffer so that it used the new OggFile wrapper, and it resulted in this diff. That is way more readable, so I’m pretty pleased with that. Now, I’m working on using that ogg/vorbis wrapper to implement streaming music off the disk. It’s nice to have all of my ogg/vorbis code in a single place instead of duplicating it like we used to. Maybe I should do something similar for WAV files. I also probably should rename all of our *Ogg* classes, functions and methods to *Vorbis*…

Anyway, it has been fun to rework the sound stuff using our improved resource management code and just the general better code base we have now.

New Computer

Wednesday, August 15th, 2007

*Warning* Gloating post ahead!

Over the past 4 years or so, I’ve had some computer drama. I bought a Dell laptop 4 years ago. It was about as good as you could get at the time. Pentium 4, GeForce 4200, 15.4 inch wide screen. It was pretty slick. Unfortunately, almost immediately I started experiencing problems with it. It would be running along happily and suddenly shut down for no apparent reason. No error message, no nothing. I shipped the computer back to Dell and a few weeks later I got it back.

It worked happily for 2 more years, when the video card went bad. It was still under warranty (and I thought it was a waste of money to get the extended warranty) so Dell replaced the video card. Apparently they didn’t have a 4200 any more so it was replaced with a GeForce 5600. Pretty sweet! Except that it ran too hot and my computer would again just shut down when it got too hot. After sending my computer back to Dell 4 or 5 times over 6 months (sometimes they wouldn’t actually change anything), they agreed to replace the laptop with a refurbished machine. Sweet! So again I had a really nice laptop, Core Duo, 17″ screen, GeForce 6800, life was good.

Then, 3 months ago, while playing Winning 11, the video card went bad (weird that its been the video card more than once). At this point it wasn’t under warranty any longer so I was stuck. A new video card from Dell was $300 (not including installation) and if I installed it myself, there would be no returns for a defective product. It wasn’t worth the risk or price.

Which leads us to the new machine. I decided I didn’t want to totally break the bank, but I wanted something I could upgrade later. So I got a pretty sweet processor, a Core 2 Quad. I decided most of the other pieces of a computer are easy to upgrade, but I wanted my processor to last. I don’t think I realized what a difference it made until I compiled Ogre. On David’s machine (which is the exact same laptop I had originally) Ogre takes 25-30 minutes. On my core 2 laptop, it took in the 15 minute range. On my new machine, Ogre compiled in 3 minutes!

All that to say I’m really excited about my new machine.