Content Pipeline assemblies

Originally posted to Shawn Hargreaves Blog on MSDN, Monday, November 24, 2008

One of the more confusing things for newcomers to the XNA Framework Content Pipeline is figuring out how (and why) to split your code across multiple assemblies.

First off, let's examine the flow of data through the pipeline:

Untitled

My choice of colors is not random. In fact, knowing why I colored some boxes blue but others red is probably the most important part of understanding the Content Pipeline!

This core difference implies other important distinctions:

You don't always have to implement all the boxes. For instance it is common to write a custom content processor, but use one of the built-in importers. It is also common for all three objects A, B, and C to be of the same type. Let's look at some examples...

 

Processing Existing Data Types

The simplest scenario is writing a custom content processor to modify an existing data type. A good example is the NormalMapProcessor from the Sprite Effects sample:

Note how the sample includes two projects: SpriteEffectsWindows contains the main game code, while SpriteEffectsPipeline contains the custom processor code.

If you open the Xbox version of the solution, you will see that even though the SpriteEffectsXbox game project targets the Xbox 360 platform, SpriteEffectsPipeline still targets Windows (x86).

 

Creating New Data Types

A more interesting scenario occurs if we want to add a new data type. The Custom Model Class sample is a good example of this:

Again the solution contains two projects, and again the pipeline extension project is always built for Windows, even when the game is targeting Xbox. The important thing is which types are defined in which projects:

 

Sharing Data Types Between Build And Runtime

It often turns out that Object B and Object C from my diagram are actually the same type.

Where should we define such a shared type?

We can't put it in the pipeline extension project, because we don't ship that project along with the final game. We also can't put it in the game project, because that would create a circular dependency: we need to use Object B to build content for the game, but if Object B is defined as part of that game, it wouldn't exist before the game was built. We can't use the game to build itself!

Types that are used both during the content build and inside the game itself are no longer purely blue or red. They introduce a third category: let's call it purple. We need a new assembly to contain such things.

You can find an example of this in the Skinned Model sample:

The interesting thing here is which assemblies define each type:

Note how both SkinningModelPipeline and SkinningSampleWindows have references to the shared SkinnedModelWindows project. This allows them both to access the same SkinningData type, so it can be used for both Object B and Object C as data flows through the pipeline.

But what about Xbox? If our game is for Xbox, we can no longer share a single project between the pipeline extension project (which runs on Windows) and the game (which runs on Xbox).

The answer can be found in SkinningSampleXbox.sln. This contains not three, but four separate projects. But two of these are actually the same thing, building the same source code for different platforms. Thus we have both SkinnedModelWindows, which defines the shared type for the Windows platform so it can be referenced by the SkinnedModelPipeline, and also SkinnedModelXbox, which includes the same .cs files and defines the same shared type, but this time for the Xbox platform so it can be referenced by the SkinningSampleXbox game project.

In other words:

Blog index   -   Back to my homepage