Extending an XNA Framework Standard Processor 

This topic describes the process of extending or modifying the behavior of a Microsoft XNA Framework standard processor. Note that the topic assumes you are familiar with standard processor usage and have read Standard Importers and Processors.

Because of the large number of unique data assets and digital content creation tools, there is often a need for extending or modifying the behavior of a standard XNA Framework processor. Some common examples are discussed and demonstrated in the following sections.

  • Changing the Standard Behavior
  • Processing Additional Data
  • Modifying the Processors Called During Execution

Changing the Standard Behavior

Developers often need to modify the existing functionality of a standard processor. For example, a custom model processor could automatically scale the model at build time. This is useful if your source assets and your game are in different scales. You can implement automatic scaling by overriding the Process method of the ModelProcessor class (Model - XNA Framework). In this override, you would then scale the entire scene and use the base functionality to proceed as normal. The following code demonstrates this override.

[ContentProcessor]
class ScalingModelProcessor : ModelProcessor
{
    public override ModelContent Process(
        NodeContent input, ContentProcessorContext context )
    {
        MeshHelper.TransformScene( input, Matrix.CreateScale( 10.0f ) );
        return base.Process( input, context );
    }
}
    

Processing Additional Data

In some cases, you need to process a larger amount of a game asset's data than a standard processor would. For example, if a custom effect is applied to a game asset that requires tangent or binormal data, you can extend the standard model processor to generate this new data. The new custom processor overrides the Process method of the ModelProcessor class and navigates the NodeContent hierarchy of the game asset. For each MeshContent object found, CalculateTangentFrames is called. The following code demonstrates this override.

    
[ContentProcessor]
class ModelProcessorWithTangents : ModelProcessor
{
    public override ModelContent Process( NodeContent input, ContentProcessorContext context )
    {
        GenerateTangentFramesRecursive( input );
        return base.Process( input, context );
    }

    private void GenerateTangentFramesRecursive( NodeContent node )
    {
        MeshContent mesh = node as MeshContent;
        if (mesh != null)
        {
            MeshHelper.CalculateTangentFrames( mesh, VertexChannelNames.TextureCoordinate( 0 ), 
                VertexChannelNames.Tangent( 0 ), VertexChannelNames.Binormal( 0 ) );
        }

        foreach (NodeContent child in node.Children)
        {
            GenerateTangentFramesRecursive( child );
        }
    }
}

Modifying the Processors Called During Execution

Another common scenario is extending one standard processor to change which processors are called from the initial processor. For example, the standard model processor takes a NodeContent object (representing the root of a scene) as input. The processor then calls the standard MaterialProcessor (Material - XNA Framework) for every MaterialContent object used in the scene. Therefore, if there are two MeshContent objects in the scene, each split into two GeometryContent objects and each using a different material, the material processor is called four times.

The standard material processor uses the ModelTextureProcessor (Texture (Model, DXT, mipmapped) - XNA Framework) to process all textures found on the Textures property of the MaterialContent object that was passed in as input to the processor. The model texture processor applies DXT1 compression to all textures. Therefore, it might be better to not use this processor for game assets with compressed textures. Instead, the standard texture processor, which does no compression, could be used. To implement this, you would need to develop two custom processors. The first, called NoCompressionMaterialProcessor, extends the standard material processor and modifies the BuildTexture function to use TextureProcessor instead of the model texture processor. The following code demonstrates this approach.

[ContentProcessor]
class NoCompressionMaterialProcessor : MaterialProcessor
{
    protected override ExternalReference<TextureContent> BuildTexture( string textureName,  
        ExternalReference<TextureContent> texture, ContentProcessorContext context )
    {
        return context.BuildAsset<TextureContent, TextureContent>( texture, "TextureProcessor" );
    }
}
    

In this code, ExternalReference objects signify assets that are shared between multiple classes. For example, multiple materials can all use the same diffuse texture. If an external reference is used, the content manager loads only one copy of the texture at run time. Therefore, the texture is built only once, no matter how many references are made to it.

Continuing with the discussion of the previous code example, the ContentProcessorContext class is the main path of communication with the content pipeline. Calling BuildAsset causes the content (referred to by the texture parameter) to be built sometime during the build process of the game.

Note

The textureName parameter, passed to the BuildTexture call, is not used in this example, but could be if the user wanted to process each texture differently depending on its usage (normal maps, and so on).

The second processor of this example is derived from ModelProcessor and extends the ConvertMaterial method to convert all MaterialContent objects passed as input to the ModelProcessor.Process call. The following code demonstrates this approach.

[ContentProcessor]
class NoCompressionModelProcessor : ModelProcessor
{
    protected override MaterialContent ConvertMaterial(
        MaterialContent material, ContentProcessorContext context )
    {
        return context.Convert<MaterialContent, MaterialContent>(
            material, "NoCompressionMaterialProcessor" );
    }
}
    

This processor differs from the previous processor NoCompressionMaterialProcessor, because it does not use ExternalReference classes. The MaterialContent objects used in this processor are not external references. They are actual objects of type MaterialContent, loaded into memory. Therefore, the Convert function is used instead of BuildAsset. In addition, because they are not external references they are not shared between multiple models, as a texture might be.

See Also

XNA Game Studio Express