Saturday, February 26, 2011

I shall introduce you to The Swiss Army Knife of our hero's journey… The Math Library!

What's up dudes? I am almost finished explaining the Four Core Systems, so here is the third one: The Math Library a.k.a. The Swiss Army Knife. This one has been by far the easiest one to code, just two (2) full afternoons of coding and testing, and this baby was ready to Rock n' Roll!

Even though this one has been the fastest to get completed, it doesn't make it less important than the rest. Actually, it is probably the one that is going to be use the most for the rest of the class, basically because the Graphics Engine (which is the next assignment after the core systems) relies on this library for all the dirty work.

Well, here goes the explanation. I think I mentioned this previously, the Math Library consists of a Vector class and Matrix class. The former is a four (4) float object (X, Y, Z and W) and the latter is a sixteen (16) float one (4x4 matrix). You might be asking why does the vector has four (4) components and not just three (3)? Well, as you shall see if you continue reading my blog over the next months, in the following class after this one (Game Engine Programming II) I will deal with a very famous problem called 'Gimbal Lock', and one solution to that issue is through the use of Quaternions (4-D vectors). I will expand on this topic further down the road (so continue following my story =D).

I will assume (as the professor did with us) that you readers have a basic understanding of vectors, matrices and all operations involving them (either independently or combined together). Therefore, I will present you with a list of all the functionalities that the library has:
  • Vector: dot and cross product, magnitude, normalization, angle between vectors and epsilon-based comparisons. 
  • Matrix: determinant, transpose, inverse, epsilon-based comparisons and type-based matrix definitions (identity and rotation/scaling/translation matrices).
Apart from this, the library has all the relevant Math Operators overloaded: addition(+, +=), subtraction(-, -=), multiplication (*, *=) by scalar and between types (vector*vector, matrix*matrix and vector*matrix). Both data types also have the Bracket Operators defined, e.g. you can access the vector's X component by doing "vector[X]" directly.

Finally, is important to clarify that the vector is defined as a union of four (4) floats or a _m128 object type. The same applies for the matrix, it is defined as a union of sixteen (16) floats o four (4) vectors. This is done in order to use SIMD (Single Instruction, Multiple Data) instructions from the processor, but this is a topic for another day and other class (Game Code Optimization).

Well my loyal readers, I shall abandon you for now, I will probably be back tomorrow to explain my File System implementation. So, for the time being have a nice Saturday!

Adios!

Friday, February 25, 2011

They seemed small and inoffensive, but they were bad as hell! Hence their name… Evil Minions!

What's up dudes? As promised, this time around I will talk about the rest of the implementation details for my Memory System. I already mentioned most of the internal elements of the system: the heaps types, their differences and how they are all connected together. But there are a couple details I left out on purpose in order to explain them today. So, here you have them:

The first one involves the way the user interacts with the system. The idea behind this system is to have control over memory allocations in order to improve performance and detect/correct leaks if they exist, but at the same time I want the user to feel as comfortable as possible using it. Therefore, in order to make the system feel natural to the user I overloaded the New/Delete Operators for a general general class called Object. This way, the user can still call the global new/delete operators for objects that do not inherit from this class and they will be stored in memory that is not managed by the Memory System.

On the other hand, if the user decides to create classes that inherit from this general class (Object), he will get the following benefits: data locality (he can place all similar objects inside the same heap), leak detection (in debug mode, every allocation made by the user has its file and line number stored, so they can be tracked down) and also memory control & tracking (the user can track and limit the total amount of space being used at all times).

The second (and final) important design decision taken was to make the Memory System a Singleton, and by doing this, limiting the total number of memory systems a running program can have to just ONE (1), which makes since I only want one central entity managing all heaps ever created without confusing the hell out of the user.

The Singleton Pattern, as it is called in software engineering, is done in C++ by following the next two (2) steps: (1) making the class constructors privates (thus the user cannot create different copies of this class), and (2) creating an static instance of the class which will be our one and only object ever created of this class. In my particular case the Memory System class is called "MemSys", so at the beginning and end of the program the user must call the methods "MemSys::initialize()" and "MemSys::destroy()" in order to create the system, and finally destroy it before terminating the program.

So my buddies, there you have them, all the implementation details of my programming pride, my newly born child… MemSys a.k.a. Diego Jr. There is nothing left to say regarding this one, aside from admitting that it gave me a hard fight, one that I will remember for a long time, but one from which I emerged victorious! =D

I will say goodbye for now, but I shall leave you with the following quote from this video:

 

"Welcome to the world of Gentlemen, Gentlemen". Adios!

P.S.: Stay tune for details on the file system and math library.

Wednesday, February 23, 2011

And along came this dudes, the Memory System a.k.a. The Evil Heap Twins!

Hey guys, long time without hearing from me, I know, I owe every one of you a big apology. The last weeks were tough, but I came on top, victorious nonetheless. Going back and forward between the four systems, trying to finish them up first, and then doing some tuning and re-coding. As Prof. Keenan says "For every line of code you write, you will be re-writing it at least seven times" (I guess he was right about that last one). So, I will try to write a series of posts this week to summarize my design and implementation of the systems.

Today is all about the Memory System, the Evil Heap Twins. Why twins you may ask? The answer goes like this: this system is a memory manager, and one way to handle this (the Windows' way at least) is trough the use of memory heaps, and in this particular case I will be using two types of heaps: Variable-size Block heaps and Fixed-size Block heaps, hence the name "twin".

Lets talk about the Variable-size type first. For this one I am completely relying on the Win32 Library (Windows.h) for the management and placement of the blocks inside the actual heap, therefore I have no control over how the free space is handled and fragmentation is being solved. I am doing it this way for time reasons, because building this kind of heap from scratch takes much more time than I probably have for this whole project. So, it's all about me finding time in the near future to upgrade this part of the system and manage the whole thing myself. I am writing it down now: it's officially part of my bucket list to port this part of the system to be 100% my creation.

Back to the heap topic. I am using the functions HeapCreate and HeapDestroy for the allocation/destruction of huge blocks of memory to use as my heaps. Everytime one of this heaps is created I place a small block inside called "Heap Header", which stores some basic information about the heap itself (stats): total size, number of blocks allocated, maximum number of blocks allocated, used space, a pointer to the first allocated block in the heap and a pointer to the next heap in the system. All heaps in the system (no matter its type) are connected together by their headers, forming a Linked List which only the Memory System have access to.

Then, as the user requests/free blocks of memory for his pleasure, I allocate/destroy blocks of memory inside the heap. In order to do this, I rely on functions HeapAlloc and HeapFree, which as their name implies just allocate and free space in a previous created heap. These blocks of memory have small headers inside, all of them connected together via pointers (forming a double linked list), and also storing the size of the block and a pointer to the heap header (used later to free the block in constant time). You can have a better idea or understanding of this heap type by looking at the following diagram:


On the right side of the diagram you can have a look at the Fixed-size block heap type (the other evil twin, the less powerful one). This one is a little easier to understand and handle, and the best part is that it is a 100% my creation, no Win32 Library involved (Sweet!). As you might guess, what we have here is a heap that contains an specified (n) number of blocks of the same size. When the heap is created (a simple call to the malloc function), we first store the header at the top of it, then we proceed to divide the rest of the space between the n blocks, all linked together by one pointer in each block header (single linked list), and having the heap header point to the first one.

Once the user requests a block from this heap, the first free block is returned by the Memory System, but behind the scenes two other things happen: the second free block in the list becomes the first (the heap header now points to this one) and the pointer inside the new used block header now points to the heap header instead of the next used block. This pointer is used to return to the heap header from the block, which is done when the user requests to free the block.

For the free operation the user only gives the system the pointer to the block itself (not the block header, which the user actually doesn't know of its existence). So, no matter what type of heap it is, the system must be able to go back from the block to the actual heap, so in order to do this as fast as possible (constant time in my case), we store a pointer to the heap header inside each block header, giving us an speed advantage in exchange for a small storage penalty. Not a bad deal in my opinion.

Well guys (if there is actually anybody reading this apart from me), there you have my memory system, a large post that summarizes a few thousands lines of code in low-level C++. This one is my pride as a programmer, and one that made me realize how little I knew about C++.

See you guys around… Adios!

P.S.: Don't you dare think this is over! I still have to talk about the evil minions of the system! Come back tomorrow for the rest of the story.

Tuesday, February 1, 2011

And they thought they would live happily ever after…


The Object System is about 95% ready, it just needs some code review here and there (there are a couple nuts that need to be tightened). I also need to setup the demos before submitting the final code in a couple of weeks, but I will get back to coding this system later.

The Object System is the first piece in a four-part Project which also includes the following three assignments: Memory System, File System and Math System. Allow me to explain the other three parts briefly.

The Memory System is a memory manager build on top the Win32 Library that allocates/frees memory based on user requests. This system creates/destroys Heaps using the Win32 Library, and allocates/frees blocks of memory from those heaps. The idea behind this system is to have control over the memory being used by the Game Engine, therefore be able to detect & fix possible memory leaks and improve performance by allocating objects in specific heaps, i.e. having different heaps for models, maps, sounds, etc., and as a result achieving data locality (much better than having your data spread all over the main memory).

The third one, the File System, is meant to manage data transfers from files to memory and vice versa. Since reaching out for data in your hard drive or optical medium is way much slower than accessing main memory (milliseconds vs. nanoseconds), you want to minimize those access as much as you can. Thus, the idea is to store the game data (models, maps, animations, etc.) in binary-format files, and have the File System manage the file loading efficiently (that’s what those loading screens are for).

The final one (for now) is the Math System, which basically translates into a Vector and Matrix Library. This system has to be able to handle all kind of operations for vectors, matrices and in-between: dot product, cross-product, matrix multiplication, determinant, transpose, inverse, etc. More than difficult, this one implies thousands lines of code and plenty of testing.

In my next posts I will go into more detail about each one of these last three systems. At least the first one is working right (at least I think so), but also made me realize that I am quite rusty in this thing called CODING. Hopefully, by the end of the quarter I will be a little bit more relaxed and skilled working with C++.

Off I go! Memory System you shall be mine!

Adios!