Forward vs Deferred Rendering (a simple summary)

December 29th, 2008

I’m posting this to discuss the merits and potential of deferred rendering systems as I believe there is a lot of confusion over the matter as well as a lot of “Well how can I accomplish this like I did using traditional forward rendering?” questions.

Deferred Rendering

What is it?

Deferred rendering is where we draw or render the geometry of a scene and then save that geometry data in memory so that lighting calculations can be applied after ALL of the geometry has been generated (we ‘defer’ or ‘hold off’ on the lighting calculations). Variations do exist where this may be accomplished in a different number of steps, where geometry data is stored differently or where different methods of using this data to light the scene are used.

How is it different?

Forward Rendering (used in around 95% of all games) is where we generate our geometry, immediately convert that geometry into pixels and then apply lighting calculations to each pixel. Forward Rendering provides no control over the order in which each pixel is lit and so your shader code can never be aware of adjacent pixels or geometry; amongst other limitations, this makes efficiently filtering out if a pixel should be shaded or not very difficult. As Deferred Rendering provides what is essentially an image of the front most geometry (geometry that isn’t hidden by closer objects) we have quickly narrowed down all visible polygons and as we have the geometrical data of these polygons stored in a ‘geometry buffer’, we can simply check their 3d locations against the volume coverage of a light source (which can be hardware accelerated using the stencil buffer). Compared to Single-Pass Forward Rendering, Deferred Rendering allows us to shade only the pixels that require shading and not pixels that will later be discarded using efficient shader code. In the case of Multi-Pass Forward Rendering, Deferred Rendering allows us to shade only pixels that will not later be hidden by other geometry or appear outside the user’s viewport (field of vision), it also prevents us from having to recalculate our geometry for each individual light source.

Why has it not been adopted on a mass scale?

  1. Deferred Rendering is difficult to implement. Some companies will have determined that it may be more effective to stick with known approaches to programming their games to reduce cost and/or development time.
  2. Traditional Anti-Aliasing (the removal of jagged edges) was not compatible with this method.
  3. You could not use the same quick filtering method to calculate shadows, as objects that can cast shadows may have been outside of the geometry buffer.
  4. Requires more graphical memory to store the extra information as well as high memory bandwidth to access this information.
  5. Partly due to reason 4 and also due to the hardware configuration of graphics cards, deferred rendering struggled to provide the performance that was expected of it.

Why is NOW the time to consider its use? (how have the hurdles from the above limitations been overcome)

  1. Deferred rendering is still difficult to implement, however, improved documentation and examples are now available on the internet. New OpenGL extensions and new shader capabilities have made it possible to more directly implement the technology with far less program workarounds being required.
  2. New methods of performing Anti-Aliasing on deferred rendering framebuffers have been documented. The ability to now store geometry data in textures has allowed for hardware acceleration of many filtering effects that can be used to improve the overall image.
  3. Shadows can be calculated by redrawing the geometry from the point of view of each light source onto a texture and then mapping (transforming) that texture to the angle seen by the user. You may think that this would defeat the objective of deferred rendering, however, using hardware acceleration called early z-culling (which has improved greatly in the latest generation of graphics cards), you can calculate visible geometry very quickly with the limitation of being unable to shade it, which we don’t require for shadowing.
  4. Graphics cards now have much more memory with much more bandwidth to that memory available. The use of more advanced compression can also be used in certain situations.
  5. The hardware of graphics cards is now much more flexible and can be maximised for use with deferred rendering. Shader Model 4.0 has provided us with unified shaders. Previous graphics cards were designed purely for forward rendering; as such they had an allocation of a shader units that could only perform vertex (simple geometry) calculations and units that could only perform pixel (lighting) calculations. This was fine when geometry data was always passed immediately through from the vertex shaders to be rendered by the pixel shaders, however, as deferred rendering has stages where only vertex calculations are being used and stages where only lighting calculations were ran, a large amount of graphical power was wasted. Unified shaders allow the graphics card to use all of its shading units for just vertices and then reassign them just for pixel shading, allowing deferred rendering to make full use of a graphics card’s processing power.

On another note. Shader Model 4.0 graphics cards from nVidia and ATI offer the ability to break away from the shader unit model and perform much more flexible calculations. Provided with the geometry data generated by the deferred rendering system, this can allow for the possibility of several advanced lighting techniques to be considered.

I hope the information I’ve provided here can help shine a light on the merits of deferred rendering. Good look in your implementation.

Bringing up the HUD (Part 3)

December 28th, 2008

OpenGL provides us with many methods of using textures, most of which we wont need but I still recommend reading up on the subject outside of this tutorial, you never know what useful things you may be able to make them do. For now I will example and explain basic 2d texture usage:

// Setup the first texture to hold vertex positions and currently the specular
// lighting value of the vertex and ensure no fancy mapping is used
glBindTexture( GL_TEXTURE_2D, offScreenBuffer[0] );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, width, height, 0,
	GL_RGBA, GL_FLOAT, NULL );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

You may be wondering what I’m blabbing on about when I say that the texture will be holding vertex positions and specular lighting values. Truthfully, I’m not even sure if that’s what I will ultimately use the texture for, however, at the moment I’ve decided that I will create what’s called a geometry buffer as part of my deferred rendering system. In a traditional multi-pass forward rendering system, the geometry is drawn from the point of view of each light source to work out what parts of a scene should be lit by each light and how (or in the case of single-pass forward rendering systems, geometry was only drawn from the user’s point of view but required boat loads of complex shading code). Now imagine your scene contains 20,000 polygons (this means many sided shape, but on a graphics card they always end up being triangles) and that your scene also contains 50 light sources. For each of those 50 lights you’re having to recreate the entire scene again from a different angle. In the worst situation every object might be lit by every light, meaning that your graphics card is likely having to draw 20,000*50 polygons (that’s 1,000,000!) every single frame. 20,000 is the same number of polygons in just one monster in Gears of War, so you can imagine just how extreme this situation can become in a full game.

Traditionally, game designers avoided the drawbacks of forward rendering by ‘baking’ in some of the lighting. Baking is the term used when you pre-calculate the lighting of your scene and then place the values into your game so that when your user comes to play it, their graphics card doesn’t have to work out the lighting for the baked geometry; it only needs to concern itself with moving objects (as the way they are lit changes as they move around). Even today we can still get away with baking some of our geometry, however, in a realistic next generation MMO environment you may wish to simulate weather, sunrise and sunset, landscape changes, or have magic spells light up the room and you will definitely want lots of crazy players running around on the screen all at once. All of these things make baking extremely difficult or in some cases entirely impossible. Now is where deferred rendering could save the day! By drawing the scene geometry only once and storing it in memory (the off screen framebuffer), we can remove a large bulk of the processing power required to generate our scene. I will discuss more about the differences between forward and deferred rendering in a none-tutorial post for anyone that is intrigued or uneasy about the potential merits of deferred rendering.

We use glBindTexture to inform OpenGL of which texture we wish to use and pass the parameter GL_TEXTURE_2D so that our texture is treated as 2d rather than some crazy 8th dimensional entity.

glTexImage2D is what we use to do the initial setup of our 2d texture. After this has been completed a texture will be ready for use, however, usually you’ll want to change some more of the texture’s options using glTexParameteriglTexImage2D requires the following parameters to function:

  • Target GL_TEXTURE_2D reminds OpenGL that we are working on the currently bound 2d texture. You can actually have a GL_TEXTURE_3D (etc) texture bound at the same time, however, you can only bind one 2d texture and one 3d texture and so on at any one time and you can only work on one bind target (GL_TEXTURE_2DGL_TEXTURE_3D…).
  • Level of Detail - Level’s of detail allow you to attach smaller copies of your texture to be used either when the texture is being viewed from far away (the smaller images usually look better on the screen and we can gain speed by using a smaller copy) or if your user has asked for lower graphical quality settings, as smaller textures display faster. The standard level of detail with no ‘mip-maps‘ (this is the name given to the smaller copies) is level 0, so we shall use this.
  • Internal Format - This is how the colour data will be stored in your graphics card’s memory; I have used GL_RGBA16F_ARB which stands for Red Green Blue Alpha 16-bit floating point, _ARB isn’t normally required, however this setting was provided by one of my requested extensions when we first set up OpenGL and indicates that the format GL_RGBA16F isn’t part of the core of OpenGL 2.1. This setting means that we store the value for Red first, then Green, Blue and finally the Alpha, as it’s 16-bit, each of these 4 values will use 16-bits of space each, so the whole combined colour and its transparency value will take 64-bits of memory. The F at the end tells us that the number will be represented as a floating point decimal. Floating point numbers are useful for storing vector information as calculations involving vectors almost always end up as decimal numbers; we can imagine R, G and B as X, Y and Z (3d coordinates) instead. A traditional texture format would be GL_RGBA; when there is no number to indicate how many bits each colour uses, you should assume that it’s 8-bits, as there is no F either, the numbers will be represented as integers (whole numbers). This format is still perfectly fine for storing the colour values of an object, however, vector information requires a little more accuracy which is why for our framebuffer we are using a larger format. These larger formats are also what make HDR lighting possible (I will of course explain the reason behind this much later on).
  • Width - Of the texture in pixels.
  • Height - Of the texture in pixels.
  • Border - Specifies whether the texture will have a border around it; you will almost always want to use 0, if you want to know more about borders I recommend reading up on textures outside this tutorial.
  • Format - This is like the internal format but OpenGL now needs to know how you’ve stored the colour data (which for example you may have loaded into your program’s memory from a picture file) that we’ll be loading into the texture, as I will not be placing any colour information into my framebuffer textures straight away and because when I do that information will be from within OpenGL, I can put any valid value, so I’ll use GL_RGBA.
  • Type - Continuing on from Format, you need to tell OpenGL what data type you have used to stored the colour data that is going to be fed into the texture; as I’m not placing any data inside yet the value I set here doesn’t matter as long as it’s valid. However, if you were creating a texture with the intent of filling it with colour information, you would set this to match the data type you’ve already used to store the data in your program (as an example, for an array of bytes you would use GL_BYTE).
  • Pixels - Provides the option of telling OpenGL where the data you wish to fill your new texture with is located. As I’m not filling the texture with any data I use the value NULL (you can also use 0). You would normally pass a pointer (the location) to the image data you have loaded into memory; OpenGL will then copy and store this data itself, so you can safely delete the image data that you had stored after this function is complete.

Well done if you’ve made it this far! It’s been quite a mouth full so I’ll explain glTexParameteri in the next post and use the extra space to clearly recap what it is that we’ve accomplished here. For now I suggest looking up the OpenGL documentation (perhaps using the search box on the main page of this blog site) and making sure that you correctly understand the workings of glBindTexture and glTexImage2DOpenGL will use the same terms and methodologies in all similar functions and so it’s important to build yourself a solid foundation of how OpenGL does things.

Source: main.cpp

Bringing up the HUD (Part 2)

December 24th, 2008

We’re about to reach the first challenging aspect of creating our game engine. We will now learn how to use the GLEW API and we’ll start by discovering how to initialise the API and check a PC  for the required extensions we plan to use. Firstly don’t forget to add the library and header files to the top of your code like so:

#pragma comment(lib, "glew32.lib") // Ask the compiler to include the glew32.lib library file
#pragma comment(lib, "opengl32.lib") // Ask the compiler to include the opengl32.lib library file
 
#include <GL/glew.h> // Show the compiler where to find the header file containing the GLEW API commands

If you’ve taken a look you may notice that the GLEW lib folder contains more than one library file, however, unlike with SDL I’m only using one of them. The reason for this is that glews32s.lib is what we call a static library. It does the same job as glew32.lib except that it does not use a .dll file and instead places all of its code in with your program. I have chosen to use the .dll version of the library as it will allow me to quickly provide GLEW updates to my users in case a bug, security flaw or performance enhancement is discovered. You may also come across library files ending *d.lib. These files are to be used for extra support when debugging your program, however should be removed from the finished product. If you can’t tell by the file-name, often static libraries and debug libraries are larger in file-size than a .dll or production library. I have also had to include opengl32.lib which is provided by Windows to give basic OpenGL support which is then extended into the latest version by GLEW.

Now we need to run the initialisation function and check for the extensions that we require:

// Using the GLEW API, load OGL v2.1 & various extentions
GLenum glewErrorCode = glewInit();
 
if( glewErrorCode != GLEW_OK )
{
	printf("OpenGL initialization failed: %s\n",
		glewGetErrorString(glewErrorCode));
 
        exit(1);
}
 
if (!glewIsSupported(
     "GL_VERSION_2_1 "
     "GL_ARB_fragment_program "
     "GL_ARB_vertex_program "
     "GL_ARB_texture_float "
     "GL_ARB_color_buffer_float "
     "GL_EXT_framebuffer_object "
     ))
{
	printf("Not all GLEW functions are supported on this system.");
 
	exit(1);
}

As you can see, GLEW is making use of an OpenGL data type called GLenum, as the storage method for its error codes. In fact, GLEW uses many of the same conventions (programming styles or ways of doing things) that OpenGL itself uses. GLEW also has its own function for converting its error codes into a readable string, glewGetErrorString(). Don’t forget that if you wish to pass this error message to other areas of your program, you can make use of the SDL function SDL_SetError() that was mentioned in an earlier post.

Using glewIsSupported(), we can ask GLEW if our requested extensions are supported by the current PC. I’ve asked for all the core OpenGL v2.1 features along with some extra extensions that didn’t make it into the core (this is either because they are not considered important enough or that they’re still being evaluated and approved for core use). I will explain why we require these exertions later, I may even change my mind and add or remove some as I go along and discover new methods for my game engine.

Well done! We now have a working window with an OpenGL rendering context and a full set of the latest OpenGL commands and features ready to use.

What I’m now going to do is create an OpenGL framebuffer object. Framebuffers provide us with rendering contexts that don’t link into Windows and so are not rendered by Windows immediately onto the screen (in fact, as they do not change the rendering context of the screen, they are often not even considered to be separate contexts). In last generation games, it was usually possible to render (draw) your scene onto the screen by generating, drawing and shading the geometry all in one pass (known as forward rendering), in the case of multi-pass forward rendering this process was simplified but repeated for each light source. In next generation games, many of the advanced lighting or post-processing effects we will want to use can not be done in a single pass and will need to be done in stages where we separate the geometry and the shading (this is known as deferred rendering). During this time we don’t want the user to see our unfinished scenes. We also don’t want Windows constantly peeking at our work and slowing us down. Framebuffers are the fastest and easiest method of accomplishing this. There are also two more benefits that Framebuffers provide. The first is support for HDR lighting, which I will discuss much further down the line. The second is the ability to render directly to textures; textures are the images that you place on top of your 3d objects to make them look realistic, giving them colour, detail and sometimes shading information (data to be used in lighting calculations). This means that you can quickly ‘take pictures’ of your scene before you show it to the user and place those pictures into the finished scene.

// Obtain an off-screen framebuffer for use with
// a deferred rendering system
GLuint offScreenFrameBuffer;
 
glGenFramebuffersEXT( 1, &offScreenFrameBuffer );
 
// Set our offscreen buffer as the current frame buffer
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, offScreenFrameBuffer );
 
// Generate 3 textures to hold our offscreen framebuffer information
GLuint offScreenBuffer[3];
 
glGenTextures( 3, offScreenBuffer );

You will notice two similar commands, glGenFramebuffersEXT and glGenTextures. This is a good example of how OpenGL sticks to standards wherever possible. glGen commands are used to ask OpenGL for a unique number that can be used to inform OpenGL which framebuffer or which texture (etc) you are talking about when you issue a command. You can see that I’ve stored the number I’ve been given for my new framebuffer in the variable offScreenFrameBuffer and that I’m using this to tell OpenGL which framebuffer I’m referring to in glBindFramebufferEXT on the next line. You can also request a batch of unique numbers in one go as I’ve done for glGenTextures by requesting ‘3′ unique numbers and providing the array offScreenBuffer that is large enough to hold the three new numbers.

glBind commands are used to tell OpenGL which framebuffer, texture and so on you’d like to work with. This saves you having to tell OpenGL every time you do something, what you’re going to do it to; this is why OpenGL is often referred to as a State Machine. The first time you bind an object is also the point at which OpenGL generates the data for that object AND the point at which you must remember to clean up the data when you’re finished with it. For a framebuffer the function to use is glDeleteFramebuffersEXT (there is an example in the source code at the bottom of this post, we will also discuss this further in the next post). The parameter GL_FRAMEBUFFER_EXT is used to inform OpenGL how I wish to treat my framebuffer once it has been bound. It just so happens that GL_FRAMEBUFFER_EXT is the only option you can use with glBindFramebufferEXT. A good example of its use is when binding a texture, you can use it to specify if the texture is 1d, 2d or 3d and so on. I will cover textures in the next post as we will need to set up our three offScreenBuffer textures for our framebuffer to use. The method that we use will be exactly the same as when setting up textures for use on 3d models.

Source: main.cpp

Bringing up the HUD (Part 1)

December 23rd, 2008

The screen and its rendering context are probably THE most important aspect of a modern 3d game. It provides you with a visible playground for all your 2d images and 3d models. A rendering context is a location where OpenGL can place its output data. Windows will then handle the task of converting the data that’s inside your rendering context on to the screen; as such it’s important to make sure you create the correct rendering context so that windows does this job correctly and provides you with the results you’re expecting to see.

We will now discuss the use of SDL’s SDL_GL_SetAttribute and SDL_SetVideoMode functions and how we can use them to create an OpenGL 2.1 compatible rendering context. I’ll start by showing you an example of the code:

// Request an OpenGL 2.1 rendering context from the window
// manager with the following preffered values
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 ); // Set red to use 1 byte of memory
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 ); // Set green to use 1 byte of memory
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 ); // Set Blue to use 1 byte of memory
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 ); // Request a 24-bit screen depth
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // Request a double buffer
 
Sint32 width = 1024, height = 768, bitsPerPixel = 32;
 
SDL_Surface* surface = SDL_SetVideoMode ( width, height,
	bitsPerPixel, SDL_OPENGL | SDL_GL_ACCELERATED_VISUAL );

To quickly note, I have used Sint32 to represent an integer or int. This is one of many custom data types SDL provides for you to use. The S stands for ’signed’ meaning one of the 32-bits of the integer is used to represent if the number is negative. There is also a Uint32 which stands for ‘Unsigned (positive only) 32-bit integer’. By using these custom types, you’re ensuring that no matter what hardware or operating system you run your program on, SDL will make sure that you will always be using, for example, a ‘Signed 32-bit integer’ where all the bits are in the same order. An example where this can cause a problem when using just int is on a 64-bit Big Endian machine. Not only could the int be 64-bit instead of 32-bit but the bits of the number could be placed in the reverse order, causing issues when trying to mix Big Endian and Little Endian numbers together. As such I believe it is good practise to use SDL’s custom data types wherever possible.

SDL_GL_SetAttribute is used to request our desired context attributes. I say request because should Windows not like your request, it will provide you with the closest matching values that can meet your needs. For example Windows may only allow 16-bit and 32-bit screens depths, when you request a 24-bit depth it will provide you with a 32-bit depth instead. SDL_GL_RED_SIZE, SDL_GL_GREEN_SIZE and SDL_GL_BLUE_SIZE are the attributes for how many bits of my screen’s bitsPerPixel to assign to each of the three primary colours that are used by computer monitors to display a final, overall colour. As you can see I’ve assigned 32-bits for my screen’s bitsPerPixel value (most people have their Window’s desktops run in 32-bit colour mode  as well). As you may know, 8-bits of data can hold upto 256 different values. This means that we can have 256*256*256 different combinations of Red, Green and Blue for each pixel on our screen (that’s over 16million different combinations!). Now, if you’re extra intuitive you may have noticed that 3 multiplied by 8 is only 24, so where have the remaining 8-bits gone? They have gone to a special attribute called SDL_GL_ALPHA_SIZE. Alpha values are generally used to represent the transparency of a colour (that is, how much of each of the Red, Green and Blue colour values should be used on the screen). On a black screen this simply controls the intensity of the colour you have chosen, however, when you’re placing one colour on-top of another, a process called ‘Alpha Blending‘ can be used to determine (based on the Alpha value) how much of each colour should be shown in the final product. We don’t need to set SDL_GL_ALPHA_SIZE as SDL is smart enough to have it fill the remaining 8-bits on its own.

The SDL_GL_DEPTH_SIZE attribute represents how much accuracy we wish to store the depth of a pixel with (that is, how far away from the screen the pixel would be if the screen were really 3d). It’s the depth value that allows 3d graphical programs to decide if one 3d object is actually in front of another. This is used in a technique called Z-Culling that only allows the pixel data from the closest object to reach the screen when two objects occupy the same pixel space (unless it’s transparent of course - then we’d need to know what was behind it!). I have used 24-bits as the value as even up until recently, many graphics cards only had support for 24-bit depths. Even now, using a 32-bit depth can often lead to lower performance on a graphics card and as such 32-bit depth values should only be considered if 3d objects far away from the screen are not displaying correctly (usually they appear and disappear over each other rapidly, this is called Z-Fighting).

The SDL_GL_DOUBLEBUFFER attribute is used to activate double buffering. A double buffer is essentially two separate memory locations for the final screen output of your rendering context. Double buffering is also know as v-synch (verticle synchronisation). It allows you to prepare your next frame in one location (like how at the cinema the movie you’re watching is made up of 24 still pictures or ‘frames’ displayed rapidly each second) whilst displaying your current frame from another. This prevents a common problem from occurring where for a short amount of time, the screen displays a bit of both your current and your previous frames simultaneously, causing a flickering effect. This is a particular issue in fast changing scenes.

  • A downside to this solution is that the screen will not display your new frame until you swap it with the previous frame, by which time you may have to wait for the next monitor refresh for the new frame to be displayed. This can appear to users as jitter or slowdown. To understand the situation, imagine a normal LCD monitor. The LCD monitor updates its image from your graphics card 60 times per second, providing a visible maximum of 60 frames per second (this works out as a new frame every 15milliseconds). However, if your PC is is taking longer than 15milliseconds, lets say 16, then you will have to wait until the next 15milliseconds to see your new frame. This means it is now taking 30milliseconds just to display one new frame on your monitor which is half as fast before, so now you only see 30 frames per second. It is because of this limitation that you should always consider if you really need double buffering or if for your particular game will it not be noticeable? Many developers offer an option to allow users to chose whether to have v-synch on or off.

SDL_SetVideoMode is used to request a rendering context from Windows with the resolution (width and height in pixels) and bits per pixel that we have asked for. It is also used to tell windows that we would like to use an OpenGL context (using the SDL_OPENGL flag) that uses the values we set previously with SDL_GL_SetAttribute. This is also why you must always set your attributes with SDL_GL_SetAttribute BEFORE using SDL_SetVideoMode. I have also used the SDL_GL_ACCELERATED_VISUAL flag to inform windows that I do not want a context that is not hardware accelerated. This ensures that Windows will provide only a full speed rendering context or else SDL_SetVideoMode will return with a null value and surface will be empty.

Source: main.cpp

Igniting our engine!

December 21st, 2008

You didn’t expect to have your new engine driving down the M1 at 200mph just yet did you? However I have high expectations so I’d like to work under the assumption that we’ll be allowed to break the world record on a big open runway; as such I will not be taking any large detours to make this engine backwards compatible with some of the older B roads (computers), besides, by the time we’re done those roads will likely have been replaced by lovely new A roads and Motorways.

Anyhow, on to the coding!

Setting up SDL :-

Firstly, Visual C++ will have generated organisational filters for Header files, Source files and Resource files in your solution explorer on the left hand side of your screen. Personally I like to group my header files and source files together into categories of their functions. As we are not making a typical windows application it is unlikely that we’ll need organisation for resource files either. So I’m going to delete these three filters and create a new filter called Main by right clicking on my project (the item that the filters dropped down from) and selecting Add -> New Filter . I’m now going to add a new file called main.cpp to the Main filter again by right clicking on Main this time and selecting Add -> New Item and choosing the C++ File (.cpp) template. The main.cpp file is of course required by all C++ programs as a place for the compiler to look for the start of your program as is the function I’m now going to create inside main.cpp.

int main( int argc, char *argv[] )
{
	return 0;
}

This is the basic function of all C++ programs. If you want you can use int arg and char *argv[] as a way of passing data to the program when it starts via command line or shortcut options.

We now need to add code that tells the compiler that we wish to use SDL in main.cpp. Our code should now look like the following:

#pragma comment(lib, "SDL.lib") // Ask the compiler to include the SDL.lib library file
#pragma comment(lib, "SDLmain.lib") // Ask the compiler to include the SDLmain.lib library file
 
#include <SDL.h> // Show the compiler where to find the header file containing the SDL API commands
 
int main( int argc, char *argv[] )
{
	return 0;
}

What I have done Is tell the compiler which library files I wish to use with the #pragma command and how to access them with the #include command. SDL just so happens to require a link to both SDL.lib and SDLmain.lib.
We will now initialise the SDL interface. Whilst I will always explain exactly what I’m doing and why, don’t forget that you can usually look-up the documentation of each API online, SDL also comes with a folder called docs which contains a mostly complete list of its features.

int main( int argc, char *argv[] )
{
    // Initialise the timer and video components of SDL
    // and check for an error (-1)
    if( SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO) == -1 )
    {
	// A fatal error has occured so output the error
	// to the user then exit the program
	printf("SDL_Init failed: %s\n", SDL_GetError());
 
        exit(1);
    }
 
	// As SDL was successfully initialised, ask the program
	// to remember to run the clean-up code when it exits
	atexit( SDL_Quit );
 
	return 0;
}

Notice that I’m no longer showing the code outside of main() I will begin doing this to save space from now on so watch out, it’s still there. I will post a link to the source file at the end of each tutorial, though I wont post the entire project as you’ll never learn like that!

If you do not understand some of the code I’ve used then I suggest improving your basic C++ a little more before continuing, there’s a link to programming books and resources on the main page of this blog. I will however mention atexit() as it’s not always common. It places a pointer to the function you pass it onto a stack, which is then executed in reverse order when the program exits. This makes it easier to ensure that you don’t forget to add clean-up code later on.

SDL provides basic built-in error handling with the following functions:

It’s very important to use error handling from the very start. You don’t want to find yourself going back and adding error handling code, it’s boring, trust me! It will help you debug any problems that may arise as well as provide useful messages to your customers so that you know how to fix their program when it’s not working, as being told “It crashed.”, isn’t very helpful.

When initialising SDL, I’ve only activated the Video and Timing components. Event handling is activated by default and I’m not sure if I want to limit myself to SDL’s simple 2 channel audio or that I need access to the CD-ROM drive, so by leaving those out, I’m saving myself a little bit of memory and it’s a few less things that can go wrong.

The next tutorial post will cover setting up the screen with an OpenGL context and an introduction into using the GLEW API.

Source: main.cpp

Setting up a Visual C++ 2008 Express Project with APIs

December 21st, 2008

The proccess of setting up a Project and applying APIs  in Visual C++ is a fairly simple one and may seem quite mundane to many users, however, it’s important to make sure that we’re all on the same page before I start making assumptions during the upcoming tutorials.

First we need to obtain the APIs that we’ll be using.

  • SDL API - An interface that provides screen setup, event handling, multithreading and so on (In my example I will use the win32 development library version 1.2.13-VC8)
  • GLEW API - A collection of OpenGL extentions that effectively provides us with the latest version of OpenGL (In my example I will use the windows binary version 1.5.1)

These links already contain the APIs in their compiled forms, ready to use. On other platforms or future versions of windows, you may need to compile your own versions by downloading from the source code links and customising them for your targeted operating system. Usually this is a fairly simple process however that’s not what we’re here to discuss today.

Inside the zip/install folders of compiled APIs you usually find two key folders and sometimes a .dll file. The two folders are usually called inc and lib (short for ‘include’ and ‘library’). The inc folder contains C/C++ header files, these are used to inform your project of what commands, or interface, the API has for you to use. The lib folder contains library files, these contain the compiled program code of the API, this code will be mixed in with your own code when you compile your project. Should a .dll file be present, this needs to be placed either in your C:\Windows\System32 folder or in the same folder as your program. These files contain compiled code just like library files, however this code remains separate from your own program and is simply accessed from the .dll file as your program executes. This allows for APIs to be updated without recompiling your program, provided that the interface you use to access them with remains the same.

O.K. - How Setup Visual C++ and add new APIs

Make sure that you’ve downloaded and installed Microsoft Visual C++ Express Edition (I won’t insult your intelligence by guiding you through this)

  1. I would recommend registering (for free of course) your product before you forget, otherwise somewhere down the line it’s going to stop working. I’ll note that the registration process doesn’t seem to like the Google Chrome web-browser so make sure you use Internet Explorer when entering your details.
  2. Open up Visual C++ and create a new project, either via File -> New -> Project… or under Recent Projects on the start page.
  3. Under Project Types then Visual C++ select General and chose the Empty Project template. Chose a project name of your choice and click OK to create the project.
  4. From inside your new project, select Tools -> Options. Expand the Projects and Solutions option in the left hand list and select VC++ Directories.
  5. Under the Show Directories For drop-down list, first select Include files and add a link to where the inc folder of your API is located.
  6. Repeat Step 5 but select Library files and add a link to where the lib folder of your API is located.
  7. Repeat Step 4 and 5 for each API that you wish to add to your project.

A final Step, as we created an empty project, we need to remind the compiler’s linker (that’s the thing that joins all our files together) that our program will be using a window (SDL requires that we set this). Select Project from the top menu bar followed by Properties. Expend Configuration Properties and then expand Linker. Select System, go to the SubSystem drop-down box on the right hand side and select Windows. Click on OK to save your changes. 

Congratulations! You have now obtained APIs for yourself and integrated them into your Visual C++ Project.

Well it’s about time! Now that we’re all on the same page the next tutorial post will finally contain some code and we’ll start getting down to the nitty gritty of designing a game engine.

Tools of the trade

December 21st, 2008

Without good tools, modern 3d game development wouldn’t be possible. In the past programmers were able to make simple 2d games (3d if they were really skilled) using a text editor, some pixel art and a compiler. These days games require much more skill, manpower, time and effort to develop. Gamers are demanding better story lines, which is giving writers a headache to the point that their own brains become warped with surprise plot twists. You always hear about the graphics of a game being important these days, if they look pretty they’ll sell like hot cakes even if they get shelved 10 minutes later, this challenges programmers, having to write more and more complex shaders and graphical artists having to create even more detailed models and textures.

Even some of the best companies can run out of steam trying to meet modern gaming expectations. By the time they’re delivered in one area, other areas such as story and gameplay often suffer. The key to a good life is a healthy balance in all things, the same goes for gaming. No one area alone will produce a good game that people will remember for years to come; even more so with MMO style games. MMOs are the most taxing of all. They require a game engine capable of coping with many users under many scenarios. This requires a lot of CPU power and memory and as such, producing graphically impressive online games is almost like asking for a miracle.

Getting to the point! (Tools) :-

Tools can help reduce your workload, thus allowing you to concentrate your efforts into other areas, by allowing quicker and easier creation of content. Also, when working with a large number of people, tools can help reduce overheads by allowing co-workers to consolidate and synchronise their work (version control), as well at make the content they product more portable for use in other areas of development (by which I mean standardised file formats and file format converters).

Tools you can use for programming :-

  • IDE - Integrated Development Environment. For example in my tutorials I use Microsoft Visual C++ Express EditionIDEs aid programmers by providing syntax highlighting, code completion or hinting, organisation and debugging features.
  • APIs - Application Programming Interfaces. In my tutorials I use OpenGL and SDL. These interfaces are collections of programming code written by others to make your life easier. They are often used to provide simple unified methods (an interface) for accessing complex hardware devices. They may also be used simply to automate a task that you would have otherwise had to program yourself. For example SDL is used to handle event data from your mouse and keyboard whilst OpenGL allows you to convert basic geometry in to on-screen images.
  • Version Control - Tools that allow you to work with other programmers on the same project without constantly changing each others work or having to patch it all together at the end. I often use SVN. This ‘commits’ changes in my work to a central storage location, other users can then ‘checkout’ my latest work. Should two users try to edit the same work, it checks that the second user was aware of the first user’s updates before committing the new changes. It also keeps a record of what was changed for all to see; a lack of communication can cause all sorts of problems.
  • WIKI - You may have noticed I have been linking many of my technical terms to a website called Wikipedia. It runs on a piece of web based WIKI software called MediaWikiWIKIs allow you to document your code or design methods in a single consolidated location. This means that all programmers can contribute ideas or documentation for people to view whilst having the ability to reference and link to the work of others. It allows quick editing, making updates and changes easy, encouraging better communication and documentation of one’s work. It’s also a great place to have your latest game plan or design methodology. In my eyes this replaces the need for presentation software to display your ideas and could help in reducing the number of scheduled meetings required to confirm that everyone is aware of current progress and work schedules.

Other Tools :-

There are endless numbers of tools for all aspects of game design, be it 3d modelling, sound mastering, story plotting, database design, publishing and so on. There are too many for me to list in a tutorial designed for programmers, however, try googling for some of these tools to give yourself an idea of the scope in which they can help you to create your game. One 3d design tool I will mention is ZBrush. It’s so easy to use that programmers can generate fairly complex 3d art with varying levels of detail to test out their engines in a very short time, so give it a lookup (don’t worry there’s a free trial - although it’s worth obtaining a full copy for your 3d artists anyway).

 

In the next post I’ll be discussing why I’ve chosen to use the APIs that I have and how to integrate them into Microsoft Visual C++ Express Edition.

Game Design Intro (The boring part… Sorry!)

December 20th, 2008

Welcome! This is the beginning of what shall be TheNewHorizon’s tutorial (sorta) on game engine design.

Why ’sorta’? Well I’m no veteran of game design myself, so at points this tutorial may need some tutorials of its own to get going again! The reason for this blog is to help learn from mistakes and discover the processes and features involved in game design and to help YOU, our reader, avoid these potential pitfalls and to allow you to concentrate on what you enjoy most (academically speaking), which is of course designing game’s that both you and your potential consumer base can take pride and joy in playing.

What to expect :-

  • A lot of C++ programming (I am a programmer and this is what I do well, however, I will touch on other bases as well so that we can see the bigger picture).
  • Portions of tutorial you may have no interest in using. As this blog is intended to help readers learn game engine design, we will use as few APIs as possible. Being the practical ‘time is money’ coder that you are, you may chose to use some of the many pre-existing APIs to handle some of your game engine’s functionality.
  • An MMORPG style engine. MMOs are one of the largest up and coming markets in gaming and one of the hardest challenges for games developers. This tutorial shall attempt to conquer this fearsome beast and draw our readers one step closer to gaining a foothold in this new and exciting field of gaming. As a side benefit, MMO design covers elements from most other gaming genres, making most of the skills you learn highly portable to other areas of gaming and general program design.
  • Good old fashioned, Hard Work.

Primary tools and APIs (free ones of course) we shall be using :-

There will of course be many more tools and APIs we may wish to use as we progress in our tutorial and discover the different elements and functions of a game engine.

I have provided a resources page containing links to books, documentation and help forums which you can find HERE or on the right hand menu.  There’s also a custom google search on the menu that will aid you in searching through various helpful websites along with content on this blog site.

Thank you very much for holding yourself back and not tabbing over to facebook during this introduction. I look forward to showing you what you wish to see (again, academically speaking) and to help you reach your goals of game design. Expect many more posts in the future.