The Content Pipeline

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.

ContentPipeline.png

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:

  • Autodesk FBX Importer - imports .fbx 3D model files
  • X File Importer - imports .x 3D model files
  • Effect Importer - imports .fx files
  • SpriteFont Description Importer - imports fonts (.spritefont files)
  • XML Content Importer - imports various .xml files
  • MP3 Audio File Importer - imports MP3 files
  • Texture Importer - imports a wide variety of images
  • WAV Audio File Importer - imports audio in the .wav file format
  • WMA Audio File Importer - imports audio in the .wma file format
  • WMV Video File Importer - imports video in the .wmv file format
  • XACT Project Importer - imports XACT audio projects

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

  • Effect Processor - processes effect files (.fx)
  • SpriteFont Description Processor - processes spritefont descriptions (from .spritefont files)
  • SpriteFont Texture Processor - processes spritefonts that are coming in as images/textures
  • Model Processor - processes .fbx and .x files (and potentially, other formats, if you create a custom importer for them)
  • Song Processor - processes audio files as Songs.
  • Sound Effect Processor - processes audio files as SoundEffects
  • Texture Processor - processes images as textures
  • Video Processor - processes videos
  • XACT Project Processor - processes XACT audio projects

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");

What's Next?

One of the next things to do might be to go through the tutorial on making a simple Content Pipeline extension. It will show you how to make your own extension to the content pipeline.


Troubleshooting.png Having problems with this tutorial? Try the troubleshooting page!