Book Review: Software Engineering for Game Developers

This article was originally published on February 18, 2008 at Pulsar Engine.

Software Engineering for Game Developers

Software Engineering for Game Developers

John P Flynt, Ph.D.

Thoughts Overall

SEGD is a detailed post-mortem of a small team’s game project: Ankh. It focuses in on the process of developing a game from start to finish… with a heavy emphasis on the process. The book spans 800+ pages, many of which are tabular explanations of forms and documents. In other words — this book has “academic” written all over it. Okay, granted the Ph.D. at the end of the author’s name also indicates this fact, but I was willing to give the book a chance (as I am with a lot of books!).

Overall, I felt let down about a hundred pages into the book and it never recovered. Initially, I had high hopes because I like reading post-mortems from game projects (even if it may have been from a game that no one’s ever heard of) and I like process. However, SEGD takes its readers down a road that veers strongly towards the managerial side of game development, sans a couple of chapter sections sprinkled with the code of a few classes in an attempt to catch the attention of software engineers. Don’t get me wrong, I don’t mind reading about practices and methodologies — I grew up on SCRUM and Test-Driven Development, but there’s something wrong when a book is detailing forms from the ISO standard.

Yes, I read all of it. The best parts were when they explained the expectations they had, the methods they used, the overall outline of their setup, the roles that team members had, and the problems they ran into and how they resolved them. These were great discussions. In fact, I think the “Stripe” (iteration) methodology used is a pretty viable structure. But all this could have been wrapped up well before hitting the 500 page mark.

Do I Recommend this Book?

For this particular book, I need to you to answer my question first: Do you like digging for your information?

This book is dense and is, in fact, rewarding on varying levels for both managers and members of a game development team, but you’ll have to dig through layers of mechanics for those nuggets.

Pros

I really appreciated the effort that went into tracking the info during the Ankh project. In fact, this is exactly why I bought the book: to read about a team project that goes from design doc to a fully functional game. It was very interesting to read about how a bunch of ideas were turned into something tangible and fun.

This book has a lot to offer in terms of how a team formulates a game and gets their ideas implemented from the initial scribblings they wrote weeks/months before. It examines an iterative development methodology (each iteration they call a “Stripe”). Each stripe is actually a complete demo that fulfills a certain set of specified requirements, along the way to the final stripe with completes the game. The book takes the reader through each stripe (not in detail for all 17, but that’s okay — it started to become monotonous after a while), and explains many important issues that arose and addresses the team dynamics.

Furthermore, each stripe is outlined (with requirements and use cases), implemented, and tested. All of these steps are elaborated upon with good context, though there is a heavy emphasis on the outlining and documentation and less so on the actual implementation.

As you might have expected, the topic of design patterns surfaces throughout the discussion. Although I had feared for the worst when I reached this chapter (due to the overall view being so lofty it made me feel uncomfortably distant from the software), it actually turned out to be one of the best chapters of the book. For SEGD, patterns wasn’t the be-all end-all I have been reading about in other sources. The chapter takes a very practical point of view and after you have finished reading it, you don’t feel like the world can be solved by patterns, rather that they are proven, structured designs to solve a distinct class of problems. This tone and treatment was very refreshing.

Cons

After finishing this book I felt like I needed to have a formal review before moving on to the next book in my queue. My biggest complaint is the book was too focused on formalities of the game development process. I kept asking myself, “How did these guys make any progress with all these documents and meetings?”

Can I think of anything more boring to read about than metrics? I know: tables of ISO standard forms! Why the author could not have merely suggested the reader to take a look at a few forms to use as templates when setting up their design document or other related documents, rather than include pages upon pages of tables with explanations of each section (some of which boil down to “you probably don’t need to include this section”) I cannot fathom.

Don’t expect code. Classes, their objects, and the messages/events passed between them are all examined at a high architectural level. I was thinking this book might have explained more about library modules to form a game engine, but the game project itself was quite tiny in comparison to what I had already been exposed to at work, and did not discuss engine architecture to any detail. Instead, the focus was on using UML and SmartDraw to design every class in your game. Personally, I believe if you have enough foresight and patience to draw out the UML and maintain it throughout the life of a game project, you should take a step back and consider how much time you’re spending not implementing your game. Tools and documentation are there to help you convey ideas and save time — not become a ball-and-chain!

Final Word

This was an interesting read — though I had higher hopes. The cursory content of the vast number of subjects could have been thinned and left to the reader to investigate by reading authoritative, dedicated books on the subjects. The core of the book was really the Ankh project and the Stripes methodology, but it was often times buried under too many layers of formalization. Don’t pick up this book unless you’re willing to spend a lot of time sifting through those layers.

Reading PNG Images from Memory

This article was originally published on January 14, 2009 at Pulsar Engine.

It has been updated to employ the conventions we use in Sauce instead of the ones I had previously used in Pulsar — aside from that, the content remains unchanged. This article still reflects my views and code.

As far as I can tell most everyone is interested in reading PNG image data from file (internally done in libpng via fread()). I thought: “Wow, that’s quite unfortunate.” and figured I’d write about it after I figured it out. The article below is the result.

NOTE: the intent of this article is to help you get something up and running quickly. By design, it does not provide detailed explanations about the functions or interface of libpng — that’s what the documentation is for.

Motivation

There are several reasons why one might want to have data read from memory rather than directly from a file.

Testing – This was the first reason that came to my mind. In the Sauce engine codebase, I want to test my format data loaders, which includes anything from textures and models to config files and scripts. More on this later.

Archives – If you pack a “file” into a custom archive, do you expect you want to hand a third-party library your file pointer? …

IO Performance – File IO has never been instant, and it can be worse depending upon the platform. As a result, you’re usually better off if you read in a file in its entirety as opposed to only reading a small chunk at a time, since the device may have seeked to somewhere else in between your reads.

Scenario in Sauce

I have abstracted the operation of reading into an InputStream interface so that the source of the data (file, buffer in memory, network, or whatever) can be swapped out without affecting the behavior of the loader classes.

The function signature looks like this:

size_t InputStream::Read(byte* dest, const size_t byteCount);

You will see this used as the main data pipe in the next section.

Implementation

I will assume you have already set the include and library dependencies for libpng. The libpng documentation is pretty clear about this topic, so I won’t delve into it here.

I should also note that the code provided below is practical and is taken from a module in my codebase. It includes a basic amount of error checking, but I stripped the rest of it out for clarity sake. As such, I recommend that you use this as a starting point.

You will undoubtedly have to switch out the calls to sauce::InputStream::Read() and replace with them your own data source’s read interface.

Lastly, I have typedefed a few basic data types in my engine. For example: byte is typedefed as an unsigned char.

Setup

First, we check if the data has the PNG signature, which is held in the first 8 bytes of the image data. If libpng determines that the signature is invalid, we bail.

constexpr size_t kPngSignatureLength = 8;
byte pngSignature[kPngSignatureLength];

// call to sauce::InputStream::Read()
// -> replace with your own data source's read interface
inputStream.Read(pngSignature, kPngSignatureLength);

if(!png_check_sig(pngSignature, kPngSignatureLength))
{
   return false;
}

Next, we need to create a pair of file info structures. For future compatibility reasons, libpng must allocate and free the memory for these structures. If either one of these calls fail, we perform the necessary cleanup and bail.

// get PNG file info struct (memory is allocated by libpng)
png_structp png_ptr = NULL;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

if(png_ptr == NULL)
{
   return false;
}

// get PNG image data info struct (memory is allocated by libpng)
png_infop info_ptr = NULL;
info_ptr = png_create_info_struct(png_ptr);

if(info_ptr == NULL)
{
   // libpng must free file info struct memory before we bail
   png_destroy_read_struct(&png_ptr, NULL, NULL);
   return false;
}

This is where the magic happens. Now we must tell libpng to use a our own custom routine for retrieving the image data. To do this, we use the png_set_read_fn() routine:

png_set_read_fn(png_ptr, &inputStream, ReadDataFromInputStream);

The first parameter is the pointer to the first struct we asked libpng to create for us: png_ptr.

The second parameter is a void pointer to the data source object. In this case, the data source my InputStream object.

The final parameter is a pointer to a function that will handle copying the data from the data source object into a given byte buffer. Here, my reader function is called ReadDataFromInputStream(). This routine must have the following function signature:

void ReadDataFromInputStream(png_structp png_ptr, png_bytep outBytes,
   png_size_t byteCountToRead);

Now that we have told libpng where to go when it needs to read bytes, we need to implement that routine. Mine looks like this:

void ReadDataFromInputStream(png_structp png_ptr, png_bytep outBytes,
   png_size_t byteCountToRead)
{
   png_voidp io_ptr = png_get_io_ptr(png_ptr);
   if(io_ptr == NULL)
   {
      return;   // add custom error handling here
   }

   // using pulsar::InputStream
   // -> replace with your own data source interface
   InputStream& inputStream = *(InputStream*)io_ptr;
   const size_t bytesRead = inputStream.Read(
      (byte*)outBytes,
      (size_t)byteCountToRead);

   if((png_size_t)bytesRead != byteCount)
   {
      return;   // add custom error handling here
   }
}

The last piece of setup we need to do is tell libpng that we have already read the first 8 bytes when we checked the signature at the beginning.

// tell libpng we already read the signature
png_set_sig_bytes(png_ptr, kPngSignatureLength);

PNG Header

Now we are ready to read the PNG header info from the data stream. There is a lot of data one could extract from this, but here I’m only going to grab a few important values. Refer to the libpng documentation for more details on this function.

png_read_info(png_ptr, info_ptr);

png_uint_32 width = 0;
png_uint_32 height = 0;
int bitDepth = 0;
int colorType = -1;
png_uint_32 retval = png_get_IHDR(png_ptr, info_ptr,
   &width,
   &height,
   &bitDepth,
   &colorType,
   NULL, NULL, NULL);

if(retval != 1)
{
   return false;	// add error handling and cleanup
}

The width and height parameters are the image dimensions in pixels.

The bitDepth is the number of bits per channel. It is important to note that this is not per pixel (which is what is normally the value stored in a TGA or BMP).

The final parameter we care about is colorType which is an integer that maps to one of the predefined values in libpng that describe the image data (RGB, RGBA, etc). You will need this to determine how many channels you need to read from the bytes into your pixel color.

PNG Image Data

We have reached the point where we can now read in the image data into our internal image pixels.

outImage.Init(width, height);

switch(colorType)
{
   case PNG_COLOR_TYPE_RGB:
      ParseRGB(outImage, png_ptr, info_ptr);
      break;

   case PNG_COLOR_TYPE_RGB_ALPHA:
      ParseRGBA(outImage, png_ptr, info_ptr);
      break;

   default:
      SE_ASSERT_MSG(false, "Invalid PNG ColorType enum value given.\n");
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
      return false;
}

First, I initialize my internal image format, which allocates the appropriate memory for the pixels — each of which is a Color32 (red, green, blue, alpha).

The switch is to differentiate my parsing routines (one of which is listed below) based on the colorType value we retrieved from the header.

To parse the data into pixel colors all we have to do is grab each row from the image and proceed to read each tuple of bytes that represents a pixel. The number of bytes we read is dependent upon the data stored, which is why we differentiate between parsing a 24-bit (RGB) color value and a 32-bit (RGBA) color value via colorType.

I have provided the ParseRGBA() routine below. The ParseRGB() is very similar except no bytes are read for the alpha channel.

void ParseRGBA(Image& outImage, const png_structp& png_ptr,
   const png_infop& info_ptr)
{
   const u32 width = outImage.GetWidth();
   const u32 height = outImage.GetHeight();

   const png_uint_32 bytesPerRow = png_get_rowbytes(png_ptr, info_ptr);
   byte* rowData = new byte[bytesPerRow];

   // read single row at a time
   for(u32 rowIdx = 0; rowIdx < height; ++rowIdx)
   {
      png_read_row(png_ptr, (png_bytep)rowData, NULL);

      const u32 rowOffset = rowIdx * width;

      u32 byteIndex = 0;
      for(u32 colIdx = 0; colIdx < width; ++colIdx)
      {
         const u8 red   = rowData[byteIndex++];
         const u8 green = rowData[byteIndex++];
         const u8 blue  = rowData[byteIndex++];
         const u8 alpha = rowData[byteIndex++];

         const u32 targetPixelIndex = rowOffset + colIdx;
         outImage.SetPixel(targetPixelIndex, Color32(red, green, blue, alpha));
      }
      SE_ASSERT(byteIndex == bytesPerRow);
   }

   delete [] rowData;
}

Cleanup

Finally, now that the image data has been read we should clean up the libpng structures, then we can be on our merry way!

png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

That’s it! Now we can go do whatever we need to with the image data we just read in!

Conclusion

Here I’ve only touched on the basics. This seemingly simple task was practically nowhere to be found when I searched for it, resulting in me having to piece it together. Hopefully this will same someone else some time.

Resources

Image Library Resources

This article was originally published on January 5, 2009 at Pulsar Engine.

It has been updated to employ the conventions we use in Sauce instead of the ones I had previously used in Pulsar — aside from that, the content remains unchanged. This article still reflects my views and code.

I have compiled a listing of resources I used while implementing my Image library. This will be updated as things progress.

TARGA File Format

Extension tga
Endian Little Endian

Resources:

Bitmap File Format

Extension bmp
Endian Little Endian

Resources:

PNG File Format

Extension png

Resources:

DXT File Formats

Extension dds
Endian Little Endian
Data Compression Lossy

Resources:

Tools:

Book Review: Data Structures and Algorithms for Game Developers

This article was originally published on December 5, 2008 at Pulsar Engine.

Data Structures and Algorithms for Game Programmers

Data Structures and Algorithms for Game Developers

Allen Sherrod

Thoughts Overall

Overall, I thought DSAGD was a worthwhile book. I can honestly say that I had fun reading through the basics again and coding up the data structure(s) with each chapter. It has been a good 7+ years since I have written any of the data structures covered in this book, and (as some people know) sorting has never been one of my strengths.

That said, there were also some technicalities about this book (mostly mechanical) that stick out like a sore thumb, which makes me disappointed because I think that they could have all been avoided had someone (not the author in particular) actually taken the time to sit down, read, and give the content a proper editing pass.

Do I Recommend this Book?

I’m usually pretty decisive on this issue, but in this case I’m actually a little bit ambivalent on whether I would recommend this book or not. I will say that DSAGD is not a book I would recommend everyone to read — it certainly depends on the programming level of the person in question.

If they are weak in the areas of (or have just started learning) data structures and sorting, then I think this book is perfect for them. In other words, I would have loved to have this book when I was in CSE 12 back in Spring of 2001 because it makes a point to explain things clearly. It also doesn’t hold your hand in terms of C++ like some other books I have on my book shelf; it just jumps straight into the details about what you need to know about the data structures themselves. I appreciated these aspects of the book a lot throughout the read.

However, I would not recommend this book to a seasoned programmer who is simply looking for a refresher in these topics. I recommend that they should turn to a more solid source (maybe Algorithms in C++ by Robert Sedgewick), as this book will leave them wanting.

Pros

As I mentioned earlier, DSAGD does a good job of staying on track when it comes to what you need to know about fundamental data structures and sorting algorithms.

Here is a list of the data structures covered:

  • Array
    • Unordered Array
    • Ordered Array
    • Bit Array
  • Linked List
    • Singly-Linked List
    • Double-Ended Link List
    • Doubly-Linked List
  • Stack
  • Queue
  • Deque
  • Hash Table
    • Open-Addressing
      • Linear Probing
      • Quadric Probing
      • Double Hashing
    • Separate Chaining
  • Binary Tree
  • kd Tree
  • Heap
  • Priority Queue
  • Graph

Here is a list of the algorithms covered:

  • Sorting
    • Bubble Sort
    • Insertion Sort
    • Selection Sort
    • Merge Sort
    • Shell Sort
    • QuickSort
    • Radix Sort
  • Compression
    • Run-Length Encoding (RLE)
    • Huffman Coding
  • Misc
    • Partitioning

Everything listed above is explained well and has a corresponding implementation. Most of these implementations are fully fleshed out… my main complaint is that the kd-tree is lacking in a couple of important features (such as a Remove() routine).

DSAGD also has a decent amount of examples of when to use certain data structures and sorting algorithms over others. Seeing how this is just as (if not more) important than knowing how to implement them on your own, I could put this point in either the Pros or Cons section, but I’m feeling generous here because I did in fact feel more confident about my stance on data structure usage after finishing DSAGD.

Also, I was pleasantly surprised to see that DXT compressions were covered in the final chapter. I’ve never spent much time in graphics-land, so while I had a basic idea of the differences across the formats nothing was particularly solid — this part of the book was certainly helpful.

Another unexpected surprise that I was happy to see was the provision of a fully functional, platform-independent implementation of a DDS (DirectDraw Surface) file loader (pg 502-509).

Cons

No book is perfect. It is excusable to see a typo or two. But in this book there were enough spelling and grammar errors that it became noticeable… and that’s when it started to distract from the reading.

I also think that this book could have either been 100 pages shorter, or have 100 more pages worth of examples, data structures, and algorithm implementations (like a SkipList or a Remove() routine for the kd-tree!). I make this claim based on the fact that there were places where the code was simply reprinted — for no good reason. I can understand when an author wants to explain things in-line with the code; so they print the implementation and then write a few paragraphs of explanation. I can also understand the benefit of having the entire class printed in completion after the routines and member variables and any miscellaneous assumptions have been explained. But it does not make sense to do both — please pick one or the other! Again, like the textual errors mentioned above, if it had happened only once or twice, I could see it being because there was reasoning behind it; but after the third time I seriously started to get the feeling the author was simply trying to fill space.

I’m tired of books printing listings of the signatures of STL routines… and on top of that, getting them wrong. Yes, DSAGD talks about the STL in addition to the custom implementations listed earlier. At this point in the article, it should be apparent which I am more interested in… it’s why I bought the book in the first place! If you’re looking for a games-oriented view on the STL, check out chapters 8 and 9 in C++ for Game Programmers for a solid, well-written discussion. I own a couple books that focus exclusively on the STL, including: The C++ Standard Library: A Tutorial and Reference and Meyer’s Effective STL, and there are many more books dedicated to explaining the STL in detail out there, so I highly recommend going to one of those before thinking of using DSAGD as an STL reference.

My final complaint was the glossing over of scene-management topics at the end of the book. Granted, this was not what this book was about, and I still have yet to read a really good book on the subject of scene-management, but I felt like I had been taunted after I had finished reading that chapter. Sherrod prints a full implementation of a Vector3d class when he could have at least spent some more time talking about the QuadTree and Octree… or better yet: explaining a concrete implementation! Surely these spatial data structures aren’t difficult to implement on my own but I’m still wondering why he took a step backwards to print the Vector3d code… this is a data structures book, not a math primer.

Final Word

Despite the aforementioned shortcomings, I think DSAGD handles the subject of the fundamental data structures and sorting algorithms very well. The book has a lot of potential and deserves a second edition to clean up the mechanical errors. In the meantime, just be prepared to skip multiple pages at a time when he reprints code, and don’t get your expectations up too high about the content of the final four chapters.

Assert

This article was originally published on November 15, 2008 at Pulsar Engine.

It has been updated to employ the conventions we use in Sauce instead of the ones I had previously used in Pulsar — aside from that, the content remains unchanged. This article still reflects my views and code.

Assert is one of the most important, indispensable, underused devices in a programmer’s toolkit.

One thing that I’ve found is that I can’t live without is the assert mechanism. In fact, it’s the first thing I wrote in the Sauce codebase. This is something that has “plagued” me ever since I was first introduced to it in Steve Maguire’s Writing Solid Code. Furthermore, throughout my reading adventures I’ve found a number of good passages about the assert mechanism. Unfortunately, this cardinal knowledge is spread across several books, so I’ve decided to compile a more compact, centralized synopsis to help give readers a detailed overview.

assert()

Whenever I research something, I always find it best to approach it from multiple angles in hopes to gain a more complete understanding. There are many different ways to “define” assert() — in fact, I have no less than 10 books in my own personal library that devote some portion of their text to this very device![1]

So let’s start where I started: Writing Solid Code by Steve Maguire. Maguire devotes an entire chapter to the assert() mechanism, in which he outlines its potential to improve both the development and quality of a codebase. And if that wasn’t enough, he also exposes a few common pitfalls that have been known to gobble up the unsuspecting unseasoned programmer.

assert is a debug-only macro that aborts execution if its argument is false.

— Steve Maguire, Writing Solid Code

I love Maguire’s straightforward description — it’s simple and precise. However, while this is a nicely formulated answer for something like an interview question, I don’t recommend using this as your explanation for someone who’s never heard of assert() before. In fact, as we will see throughout this article there are many implications that need to be dug out of this pithy answer and brought to light.

Also, I want to emphasize the fact that assert() is a macro (or if you’re Stephen Dewhurst: a “pseudofunction”), not a function. This is an important point because we want to minimize the impact these checks make on our code as much as possible, so that the difference between the execution code for the debug and release builds is negligible. Calling a function proper is likely to cause a state change in our code which means both more overhead, the unloading / loading of registers, a change in the callstack, etc.

The C Programming Language (also often referred to as K&R) defines assert() as follows:

The assert macro is used to add diagnostics to programs:

void assert(int expression)

If expression is zero when assert(expression) is executed, the assert macro will print on stderr a message, such as

Assertion failed: expression, file filename, line nnn

It then calls abort to terminate execution. The source filename and line number come from the preprocessor macros __FILE__ and __LINE__. If NDEBUG is defined at the time <assert.h> is included, the assert macro is ignored.

To be clear, the K&R reference listing is specific to the assert() macro provided in the C Standard Library via the <assert.h> header (or the C++ equivalent <cassert>). It outlines not only the exact signature, but also provides details to its execution behavior. In comparison, Maguire’s definition is more about the concept of assert — the basics a programmer should bare in mind when they encounter or author an assert — allowing it to apply to any implementation: standard or custom.

Also, the fact that assert() is detailed in K&R states that it is an established device in C and C++ (as well as other languages). This means that you can use the assert() macro and be confident that it is both a portable and communal means of enforcing a necessary condition.

Assert statements are like active comments — they not only make assumptions clear and precise, but if these assumptions are violated, they actually do something about it.

— John Lakos, Large-Scale C++ Software Design

[Asserts] occupy a useful niche situated somewhere between comments and exceptions for documenting and detecting illegal behavior.

— Stephen Dewhurst, C++ Gotchas

Although these aren’t quite definitions, I chose to examine this pair of related excerpts because I think that together they conjure up an interesting idea that serves as an excellent supplement to the already said definitions. In particular, the notion that an assert is an “active comment” should make any programmer’s ears perk up.

How many times have you written the assumptions that your function makes in a comment at the top of your code? How many times have you traced bugs down deep into the bowels of a codebase only to find that somebody (maybe you!) disregarded the assumptions outlined in the comment? If you follow Lakos’ advice and employ the use of assert statements to enforce the assumptions made in your code, you can rest assured that you’ll be notified if any of those assumptions are ever ignored again.

Finally, I want to finish this section with an important point made by Noel Llopis:

Asserts are messages by programmers for programmers.

— Noel Llopis, C++ for Game Programmers

This detail about the assert mechanism is probably the most forgotten over any other. Asserts are added to the code for a number of reasons (which we will soon get to), but none of them include the end-user.

Common Usage

After reading the above, you must be itching to see how to actually use an assert() in practice, so let’s take a look at a few common, simple, and admittedly contrived examples.

Example 1: Prohibiting the Impossible

Whenever you find yourself thinking “but of course that could never happen,” add code to check it.

— Andrew Hunt and David Thomas, The Pragmatic Programmer

Let’s say you have an enumeration of error codes which includes both fatal and non-fatal errors. In an effort to help make the distinction easier, the fatal error codes are negative while non-fatal error codes are positive. All errors are reported through the ErrorHandler, but create different objects depending upon whether they are fatal or non-fatal. Thus, you could add a “sanity check” to verify this assumption in the following manner:

enum ErrorCode
{
   ...  /* Fatal Errors < 0 */
   ...  /* Non-Fatal Errors > 0 */
}


class Error
{
public:
   virtual ~Error() = 0;
 
protected:
   ErrorCode mErrorCode;
}


class FatalError : public Error
{
public:
   explicit FatalError(const ErrorCode errorCode)
      : mErrorCode(errorCode)
   {
      assert( mErrorCode < 0 );
   }
 
   virtual ~FatalError() {}
}


class NonFatalError : public Error
{
public:
   explicit NonFatalError(const ErrorCode errorCode)
      : mErrorCode(errorCode)
   {
      assert( mErrorCode > 0 );
   }
 
   virtual ~NonFatalError() {}
}


void ErrorHandler::HandleError(const ErrorCode errorCode)
{
   Error* error = NULL;
   if(errorCode < 0)
   {
      error = new FatalError(errorCode);
   }
   else if(errorCode > 0)
   {
      error = new NonFatalError(errorCode);
   }
   ...
}

The assert() statements are being used here to guard against the impossible. And it’s important to note that if the “impossible” does happen (and believe me, it can), you should terminate the program immediately with extreme prejudice[2].

Example 2: Enforcing Preconditions

Preconditions are the properties that the client code of a routine or class promise will be true before it calls the routine or instantiates the object. Preconditions are the client code’s obligations to the code it calls.

— Steve McConnell, Code Complete

Now let’s say you wrote a function that computes the square root for a given value: SquareRoot(). Since you’re not dealing with complex numbers in your code, you don’t want this function operating on a negative value. In fact, you’d like to be notified if this function does happen to receive a negative value because that would mean that whatever calculations are using this routine aren’t handling all the possibilities before calling your SquareRoot(). This sounds like a perfect place to use an assert()!

float SquareRoot(const float value)
{
   assert( value >= 0 );
   ...
}

In this case, we are using an assert() to enforce the precondition that value parameter must be non-negative. Again, this is something that will help a programmer during an application’s development cycle, not an end-user.

Example 3: Enforcing Postconditions

Postconditions are the properties that the routine or class promises will be true when it concludes executing. Postconditions are the routine’s or class’s obligations to the code that uses it.

— Steve McConnell, Code Complete

Using the same SquareRoot() function from Example 2, let’s add a check to ensure that our final output value sqrtValue is non-negative.

float SquareRoot(const float value)
{
   ...
   assert( sqrtValue >= 0 );
   return sqrtValue;
}

We could also add a check to ensure that our computation is correct:

float SquareRoot(const float value)
{
   ...
   assert( sqrtValue >= 0 );
   assert( FloatEquals(sqrtValue*sqrtValue, value, EPSILON) );
   return sqrtValue;
}

Example 4: Switch Cases

This is one of my favorite places to use the assert() because it helps guard against mistakes while allowing for code extension.

Let’s say you have a set of different platforms your code can output asset files for: Win32, Xenon, and PS3. However, it’s important to write your code in a way that allows for extension for additional platforms (say the Nintendo Wii). Here’s how we can enforce this in our AssetFileWriter:

bool AssetFileWriter::Write(const byte* data,
   const char* filename, const Platform platform)
{
   switch(platform)
   {
      case Platform::WIN32:
         /* write data to file for Win32 */
         break;
      case Platform::XENON:
         /* write data to file for Xenon */
         break;
      case Platform::PS3:
         /* write data to file for PS3 */
         break;
      default:
         assert(false);  /* invalid platform specified */
   }
   ...
}

Now when we get the green light to add the Wii to our list of supported platforms, we will be notified if we happen to forget to add the case in the AssetFileWriter.

Caveats

As Noel pointed out to us earlier, asserts are employed for the benefit of programmers, not end-users. They are active only for _DEBUG builds and are compiled out for all others. The consequences of forgetting this principle can be particularly dangerous. The details to this are two fold:

  1. The assert() expression argument should not contain any required code. This is because all instances of assert() in your code are omitted when compiling a non-debug build of your application.

    The canonical example of this is using a required function call inside assert() expression:

    bool WriteDataToFile(const char* filename, const byte* data);  /* prototype */
     
    assert( WriteDataToFile(filename, data) );  /* uh-oh... */
    

    Guess what happens when you compile a release build (or any build that defines NDEBUG for that matter)… no file for you! The solution to this should be clear, save the data you want to check to local variables and use those in the assert().

    const bool bFileWriteSuccessful = WriteDataToFile(filename, data);
    assert( bFileWriteSuccessful == true );  /* much better */
    

    To be perfectly clear, not all function calls must be avoided inside the assert(). For example, usage of strlen() or another const function guaranteed to have no side effects is perfectly fine to use inside the assert() expression. However, in C++ Gotchas, Dewhurst touts:

    Proper use of assert avoids even a potential side effect in its condition.

    — Stephen Dewhurst, C++ Gotchas

    alluding to functions that appear to be const from the outside, but actually perform some operations in order to return a value.

    Another good, yet more subtle example is the following:

    assert( ++itemCount < maxItemCount );   /* doh! */
    arrayOfItems[itemCount] = itemToAdd;    /* add item to list */
    

    In this case you’ll find that the value of your itemCount never changes in the release builds because your increment was compiled out (which means you’ll just keep overwriting the current item!) Here, we need to push the required increment operation out of the assert:

    assert( (itemCount+1) < maxItemCount );   /* safe check */
    arrayOfItems[++itemCount] = itemToAdd;    /* add item to list */
    
  2. assert() should not be treated as a means of or substitution for proper error-checking.

    The following code snippet resembles a case I have seen more often than I’d like to admit.

    char filename[MAX_PATH];
    OpenFileDialog(&filename, MAX_PATH);  /* fills in filename buffer*/
    assert( strlen(filename) > 0 );
    ...  /* do something with filename */
    

    Here the assert() is being used in a place where proper error-checking should be employed. This is dangerous because while the programmer is rightfully protecting the rest of their code from using an invalid filename, they are going about it in a way that assumes that a user will always proceed to choose a file in the OpenFile dialog. This is a bad assumption because the end-user most certainly has the right to (and will) change their mind about opening a file.

Asserts vs. Exceptions

An assert is different from an exception. A failed assertion represents an unrecoverable, yet programmer-controlled crash. A thrown exception represents an anomaly or deviation from the normal execution path — both of which have the possibly of being recoverable.

To be clear, you should use an assert() if the code after the assertion absolutely positively cannot execute properly without the expression in question evaluating to TRUE. One example of this is the pointer returned from malloc():

void* memBlock = malloc(sizeInBytes);
assert( memBlock != NULL );
...  /* use the allocated memory block */

If malloc() happens to return NULL (which can and does happen!), the rest of the code that follows which uses memBlock has no hope of working properly. As such, we have used an assert() so that we can control the termination of the application rather than allow the continued execution to do something worse.

Another good place for an assert statement is right before accessing an array at a given index. For example, say we have an ItemContainer class that holds an array of Items internally which has a const accessor routine GetItem(). Then we could use an assert() to check the requested Item index in the following manner:

const Item& ItemContainer::GetItem(const int itemIndex) const
{
   assert( (itemIndex >= 0) && (itemIndex < mItemCount) );
   return mItemList[itemIndex];
}

Because we unarguably don’t want to be accessing memory outside the bounds of the array, we have employed an assertion to notify us if the calling code tries to do just that. The importance of this example is two-fold: not only are we protecting ourselves from silently accessing “foreign” memory, but we are also enabling an additional internal layer of debugging for the calling code (which may have a bug in the way it computes the itemIndex parameter).

While I’m not going to go into all the details of exceptions and when and when not to use them, I will offer an example of usage for comparison.

Let’s say you have a routine that reads data from an external source (USB drive, network, etc.). What do you do if the data source is unplugged in the middle of a read? Do you terminate the program? NO WAY! The proper way to handle such a case is to throw an exception and let the exception propagate up to a safer point in the code where the exception can be handled by notifying the user with a nice little dialog box that says “I wasn’t done. Plug it back in!”, all without terminating the program. If it is the user’s intention to exit after they unplug the data source, force them to do so via the conventional means your application has made available to them — it’s just good manners.

Asserts vs. Unit Tests

There’s something else I want to be clear about: asserts are not a means of or substitution for unit testing. Just because we have included an assertion check to make sure the value of our SquareRoot() function is non-negative doesn’t mean we should forgo any appropriate unit testing.

Unit testing can only take you so far. If you write good tests, you can get good coverage for your code; but you don’t run unit tests for every value that ever enters your routine. That’s why if you forget a case in your unit tests, all your tests will pass but you’ll still have bugs. So both unit tests and asserts should be employed together. They are on the same team.

What if we want to test our assertions? Well, the best example I give you for this is outlined in a post about Assert from the guys at Power of Two Games: Stupid C++ Tricks: Adventures in Assert [link no longer exists]). Briefly, in order to test that an assertion is thrown you will need to add some additional hooks into the way you manage your assert() to ensure that your unit tests handle assertion failures gracefully.

Implementing a Custom Assert Macro

In this section I’m going to examine some custom implementations of assert(). For the most part they all implement the same functionality, but I found it very interesting how many different ways I had come across in the books on my shelf. We’ll also look at various implementation flaws (whether intentional or not) and finally wrap up with the implementation I use in Sauce.

The assert example from C++ Gotchas:

#ifndef NDEBUG
   #define assert(e) ((e) \
      ? ((void)0) \
      :__assert_failed(#e, __FILE__, __LINE__) )
 
#else
   #define assert(e) ((void)0)
 
#endif

I consider this the classic C skeleton of assert(). To customize, you would replace __assert_failed() with something that handles the assertion in a way tailored to your own needs.

Unfortunately, I have a problem with this method — unless __assert_failed() is a macro that includes the code to invoke a breakpoint (__asm int 3; and the like), it assumes you will break inside the function and not at the line that broke your code. A little annoying — but, seriously, even the little things are important. Following a recommendation to put the breakpoint code inside the assert() macro (not the handler function), you will be able to get the debugger to stop right at the failed assertion line rather than three callstacks up.

The custom assert example from Writing Solid Code:

#ifdef DEBUG
   void __Assert(char* filename, unsigned int lineNumber);   /* prototype */
 
   #define ASSERT(f) \
      if(f)          \
         {}          \
      else           \
         __Assert(__FILE__, __LINE__)
 
#else
   #define ASSERT(f)
 
#endif

This was the first custom assert() implementation I was introduced to. Looking back on it, one thing I don’t like about it is that Maguire doesn’t include a text version of the expression in the parameters provided to the assert handler.

Also notice that instead of ((void)0), absolutely nothing is evaluated for the Release build. This is a bit troublesome because, if you noticed, Maguire purposefully left off the semicolon after the __Assert(__FILE__, __LINE__) to give the compiler a reason to enforce the client to add one. But he’s left room for error in the Release build.

The custom assert example from Code Complete:

#define ASSERT(condition, message) {    \
   if( !(condition) ) {                 \
      LogError( "Assertion failed: ",   \
         #condition, message );         \
      exit( EXIT_FAILURE );             \
   }                                    \
}

At first you might say… Aha! What about a dangling else?! But if you look closely at McConnell’s code, he uses an additional pair of braces to enforce scoping on his version of assert(). The problem here is that you no longer are forced to append that semicolon.

Also, notice that McConnell doesn’t break either — he just exits. During development, I find it extremely handy to have a failed assert break into the debugger, not just print me an error message and bail.

Finally, where are the build configuration #ifdef‘s ? As is, this code’s going to run in all builds!

These might all sound like me knit-picking, but hey! this is assert()! This is something I use EVERYWHERE! so it better be solid, pristine, and easy to use.

The custom assert example from C++ for Game Programmers:

#ifdef _DEBUG
   #define DO_ASSERT
#endif
 
#ifdef DO_ASSERT
   #define Assert(exp, text) \
      if(!(exp) && MyAssert(exp, text, __FILE__, __LINE__)) \
         _asm int 3;
 
#else
   #define Assert(exp, text)
 
#endif

Noel’s got an interesting addition in his version of assert(): the DO_ASSERT symbol. I think this is actually a nice way to allow developers to turn assertions on and off for multiple builds, especially if you have more than just a Debug and Release configuration (i.e. a additional Debug build with optimizations turned on, or a “Final” build).

However, Noel’s suffers from a very important problem: a dangling else. Let’s say you happen to put this assert inside an if / else block. Guess what, that else is going to attach itself to the if inside the assert() when the macro expands, which is not the logic you had in mind. This can be combated with the scoping we’ve seen earlier, or my preference of a do / while(0) loop.

The authors of The Pragmatic Programmer argue that there’s no need to follow suit when it comes to printing an error message and terminating the application outright with abort() in your assertion. In fact, they claim that as long as your assertion handler is not dependent upon the data that triggered the assert you are free to perform any necessary clean up and exit as gracefully as possible. In other words, when an assertion fails it puts control of the “crash” into the hands of the programmer.

A good example of this is exhibited by Steven Goodwin in Cross-Platform Game Programming:

#define sgxAssert(expr)
   do { \
      if( !(expr) ) { \
         sgxTrace(SGX_ERR_ERROR, __FILE__, __LINE__, #expr); \
         sgxBreak(); \
      } \
   } while(0)

Again, this seems to be missing the #ifdef — maybe these authors are just trying to save trees?

Finally, taking all that I have learned — my implementation of assert() looks something like the following:

#ifdef SE_ASSERTS_ENABLED
   namespace Sauce { namespace AssertHandler {
      bool Report(const char* condition, const char* filename, int lineNumber);
   }}
 
   #define SE_ASSERT(cond) \
      do { \
         if( !(cond) && Sauce::AssertHandler::Report(#cond, __FILE__, __LINE__) ) \
            SE_DEBUG_BREAK(); \
      } while(0)
 
#else   // asserts not enabled
   #define SE_ASSERT(cond) \
      do { \
         SE_UNUSED(cond); \
      } while(0)
 
#endif  // end SE_ASSERTS_ENABLED

I’m utilizing the same trick Noel offers in his version to separate out the enabling of asserts via a single defined symbol SE_ASSERTS_ENABLED.

The SE_DEBUG_BREAK() macro calls __debugbreak() rather than straight __asm int 3; for the sake of x64 compatibility.

The SE_UNUSED() macro utilizes the sizeof() trick detailed in Charles’ article.

I’m also utilizing the do / while(0) loop convention to wrap my macros (including the SE_DEBUG_BREAK() and SE_UNUSED()) for scoping and to enforce the requirement of a semicolon.

My AssertHandler has been implemented in the same spirit as exhibited by the guys at Power of Two. This was mainly because I like the idea of being able to test with my asserts, and even test that the asserts are being thrown in the first place! If you haven’t taken a look at their article yet, I highly recommend you do.

Conclusion

This has been a fun (and two week long) ride to put this article together. I tried to take a comprehensive approach, and, as we can see, there’s a lot that can go into such a tiny little mechanism…

As I said in the beginning, assert() is one of the most important tools I have for code development and after reading this I hope it’s crystal clear why.

Footnotes

  1. I use a lot of them, but not all, as references throughout this article.
  2. In case you were wondering, why would we ever want to crash (as gracefully as possible) the program? Won’t users lose their unsaved work? Won’t they be mad? The answer is simple and resounding: YES. It is far better to abort the application than possibly allow for a user to continue using it in its invalid state while believing that everything is perfectly fine, or even worse corrupt their data. A user will most certainly be upset that they lost any unsaved work, but not anywhere near as angry as they would be if we corrupted their entire dataset!

References

  • Dewhurst, Stephen C. C++ Gotchas. 2003. pp 72-74.
  • Goodwin, Steven. Cross-Platform Game Programming. 2005. pp 262-265.
  • Hunt, Andrew and David Thomas. The Pragmatic Programmer. 2000. pp 113.
  • Lakos, John. Large-Scale C++ Software Design. 1996. pp 32-33.
  • Llopis, Noel. Asserting Oneself. Games From Within. 2005.
  • Llopis, Noel. C++ for Game Programmers. 2003. pp 386-402.
  • Kernighan, Brian and Dennis Ritchie. The C Programming Language. 2nd Ed. 1988. pp 253-254.
  • Maguire, Steve. Writing Solid Code. 1993. pp 13-44.
  • McConnell, Steve. Code Complete. 2nd Ed. 2004. pp 189-194.
  • Nicholson, Charles. Stupid C++ Tricks: Adventures in Assert. Originally posted on Power of Two Games. 2007.

Book Review: C++ for Game Programmers

This article was originally published on March 28, 2005 on a website that no longer exists.

C++ for Game Programmers

C++ for Game Programmers

Noel Llopis

Forward

The following is a book review I wrote when I finished my first reading of C++ for Game Programmers back in early 2005. I’ve left it intact so it differs from the formatting of the other reviews I’ve posted.

I remember why I bought this book in the first place. It was December of 2004 and I was having some trouble while working through Zerbst’s 3D Game Engine Programming. I had never officially had a course on C++ and my knowledge of C was rudimentary. I kept reading about const and “pure virtual” member functions (among other things), and finally came to the conclusion that I needed to take a step back and learn about those before moving forward in Zerbst. I found C++ for Game Programmers at a not quite local Barnes & Noble and picked it up. I especially remember the fact that this book really met me where I was as a programmer: not bothering with the basics of programming, but rather concentrating on the aspects of C++ with which I was unfamiliar. As a result, I’ve had a special fondness for the book, as well as a great appreciation for its author.

Looking back, with maybe the exception of McGuire’s Writing Solid Code, I think this is one of the programming books I’ve reread the most. In addition to his clear presentation of the fundamentals, Noel touches several important and useful topics (a number of which I have incorporated into my own code base) in the later chapters.

It should be noted that a second edition has since been released by a different author. I don’t know how different it is from Noel’s edition.

The Review

Noel Llopis’ C++ for Game Programmers is an excellent reference for any game programmer at any level. The text focuses on both essentials of the C++ programming language like inheritance and constness as well as low-level systems within a game’s code base such as memory management and object serialization. The advice offered in Noel’s book has affected and improved every piece C++ I have written since I picked it up and started reading.

C++ for Game Programmers starts off by covering concepts that every C++ programmer should internalize: Inheritance (single and multiple), the const keyword, passing by reference, the C++ style casting, templates, and exception handling. Each topic discussion includes outlining their advantages and disadvantages, when and when not to use them, and is accompanied by simple, yet real-world code examples and scenarios relevant to game development.

After bootstrapping up these aforementioned fundamentals, Noel address principles every programmer is concerned about: performance, memory. The importance of these topics in game programming cannot be understated; both of these chapters are loaded with detailed explanations, practical examples, and useful recommendations. I think that one of the most important components of this book was the straightforward walkthrough of the need for and the implementation of a versatile memory management system (full source code provided on the CD) that can be easily integrated into any C++ project.

The next two chapters of this book are spent evaluating both the advantages and pitfalls found in the C++ Standard Template Library (STL). The overview includes direction on which data structures are good candidates for particular data sets found in games, as well as why they are poor candidates for others. Overall, these two chapters compose a very solid argument for using the STL in game development.

Part Three is where this text really shines. Starting with an in-depth discussion on Abstract Interfaces, the foundation is set for some extremely useful subsystems for game development, including for plug-ins, Runtime Type Information (RTTI), and object serialization. Even though most of the source code provided with these chapters is not designed to be thrown straight into a large code base, all of the important concepts needed for designing a game engine subsystem based on any one of the components mentioned above are clearly provided in the text.

One last, important feature is the point of view taken throughout the book. It’s one thing to be working on a project, but it’s a completely different ball game to be working on a large-scale project. Noel brings industry-grade advice to the table for each and every topic covered in the book. This was something I appreciated again and again throughout my reading and I suspect others will too.

So, if you are looking for a book that doesn’t cover the just the basics of C++ programming in the light of game development: this book is for you!

Book Review: 3D Game Engine Programming

This article was originally published on November 17, 2004 on a website that no longer exists.

3D Game Engine Programming

3D Game Engine Programming

Stefan Zerbst

Forward

The following is a book review I wrote for Amazon.com a while back. I’ve left it intact so it differs from the formatting of the other reviews I’ve posted.

3D Game Engine Programming was the first game programming book I ever bought. I’ve often said that this is the book that started me off on the right foot; however, as an introductory text to the vast subject, it was both a poor and a great choice.

To be completely honest, I was not ready for this large of a programming project. At the time I was still very new to programming, and had very little C++ experience. This became an impasse later on, which forced me to seek out and purchase another excellent book: C++ for Game Programmers. However, at the same time, Zerbst inspired me to continue on and piece together the components needed for the engine. As a result, after completing my first read through the text and implementing my very first iteration of a game engine, I knew that I had learned and accomplished a lot and I would be utilizing 3DGEP as one of my primary sources for future endeavors.

Undoubtedly, 3DGEP is one of the most comprehensive sources I have found on the subject and very well organized. If you really want to understand what goes into writing a game engine, I recommend steering away from the “Game Programming All in One” books and investing in 3D Game Engine Programming. Even six years later, I still find myself snatching it off my bookshelf for help on assorted topics with my current projects.

Simply put, Zerbst’s 3D Game Engine Programming is one of my favorite resources on the subject of game engine development. I highly recommend it.

The Review

Stefan Zerbst’s 3D Game Engine Programming is a 850-paged guide to constructing a modular, functional video game engine. This reference was one of the biggest reasons I became confident that I could complete a project of my own and has helped me tremendously in the design and building of an engine based upon the fundamentals of the ZFX Engine.

Even though the book does not go into detail and provide the code to all the bells and whistles of a commercial engine, it certainly outlines the basics and even provides code for testing. (I personally liked not having everything provided so that I could add my own features with a more personalized touch). Have no fear: all the basics are there to build off of!

In particular, the text guides the reader through the concepts and code needed to construct an engine that has the ability to support both DirectX and OpenGL (though DirectX is the main focus in the text), Vertex and Pixel Shaders (which is a big plus in upcoming game graphics!), and networkable players. In addition, the book brought extra possibilities such as Non-Player Characters, AI, and other various effects to the table for the reader to take note of where they could be added on to the engine. More importantly, he did do an excellent job of keeping these options (and more!) open without forcing his more ambitious readers to reprogram half the engine.

A very important thing I felt was the key to why I liked it so much was the fact that I understood how the components of the engine worked individually and as a whole to construct a functional game when I had finished the book. So many times have I read a programming book cover to cover and then still be lost on how everything fits together outside of the demos provided in the text– but this book was NOT like that at all. The concepts were presented clearly as well as explicitly outlined within the code.

However, I will note: this book is not for the faint of heart or for the inexperienced programmer. (Hopefully the size scares the aforementioned away in a direction to seek some more practice before coming back to this fantastic reference.) There is a LOT of code and while the text does take care of the graphics, DLL loading, and algorithmic aspects to a FPS game, the book does treat the reader as a programmer and not a novice.

One last, important feature is the Level Editor that is developed along side the engine (that’s right! you build a level editor too!). This chapter (14) is certainly one of the most useful parts of the text and is where a lot of key concepts come together.

So, if you are looking for a book that hits the ground running, providing a complete archive of source code and demos in an effort to construct a comprehensive game engine: this book is for you!