5 min read

How the Content Pipeline Works

Introduction

This tutorial discusses how the Content Pipeline works in detail. Before going through this tutorial, it might be a good idea to go through the tutorial on managing content in an XNA game if you haven’t already. While our main goal here is simply to discuss how the Content Pipeline works, in a future tutorial, we will discuss how you can add on to the Content Pipeline.

The Content Pipeline

The Content Pipeline is a very useful and powerful feature of XNA. It allows you to minimize the amount of time you spend reading in resource files. It provides a uniform method for accessing content in your game. It also allows you to redistribute your game without having to redistribute all of your game art, which can be very nice if you want to prevent people from having direct access to your models, textures, and other content. Maybe more important is the fact that the content pipeline allows the duties of the programmer to be separated from the duties of the artist. The Content Pipeline is actually fairly simple. In this tutorial, we will discuss how the pipeline works.

The Content Pipeline takes an asset (sometimes called a Digital-Content Creation or DCC) and loads it into your game in a way that is easy to access. In previous tutorials we have seen commands like the following:

Model model = Content.Load<Model>("aModel");

When we compile our program, all of our game assets, like textures, 3D models, sprite fonts, and so on, are all processed through the Content Pipeline and stored in a temporary file. When we run the command above, we say to the Content Pipeline “give me that model that you’ve processed.” The model is then retrieved from the content pipeline and given to the game as a Model object.

There are four major steps that are performed from the time that the asset is first touched by the Content Pipeline to get it into your game. The diagram below illustrates these steps.

Content Pipeline diagram

The first step is that the asset is read in by an importer . An importer’s primary purpose is to read the data from the file so that it can be handled by the rest of the content pipeline. The importer outputs an object that the next element in the pipeline can process.

The second component in the process is the Content Processor . The content processor takes the data from the importer in a raw form and converts it into something more meaningful. The end result is usually some type of data structure that is referred to as processed data.

Finally, at the end of the content pipeline, the resulting data must be put into a temporary file by a content compiler . This takes the processed data that came from the content processor and puts it into a compiled asset file. These files are binary files and generally have the extension .xnb. Once you have built your project, you can go look through your project directory and find the .xnb files that were generated by the Content Pipeline. This intermediate file remains around until it is ready to be loaded by the game.

The last step of the content pipeline occurs in the game by a content loader . The content loader reads in the compiled asset from the file and turns it into an object that your XNA game can use.

Standard Importers and Processors

Up until this point, we have been using the Content Pipeline without doing very much work. This is because XNA comes with a lot of built-in importers and processors. For example, let’s say you have an image called picture.png. There is a built-in texture importer called TextureImporter that will be used to import this image by default, and a TextureProcessor that is used to process the image. A ContentTypeWriter writes the image data out to a .xnb file where it waits until your game attempts to use it. When you access it, a ContentTypeReader reads in the .xnb file, and the image data is turned into a Texture2D object.

There are several built-in importers, including:

There are also several different built-in content processors, including:

Extending the Content Pipeline

For many smaller games, these built-in types are good enough. In a fancier game, additional importers and processors can be created and added to the Content Pipeline. The uses for Content Pipeline extensions are virtually limitless. I have used them in the past for loading level data that was created in a separate level editor, as well as bounding box information for collision detection in a different game. The Content Pipeline was thought through pretty well. It is a lot of fun to be able to say something like the code below in your game:

Level level = Content.Load<Level>("level4");