//----------------------------------------------------------------------------- // RacingGameModelProcessor.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using System; using Microsoft.Xna.Framework.Content.Pipeline; using Microsoft.Xna.Framework.Content.Pipeline.Processors; using Microsoft.Xna.Framework.Content.Pipeline.Graphics; namespace RacingGame.PipelineExtension { /// /// RacingGame model processor for x files. Loads models the same way as /// the ModelProcessor class, but generates tangents and some additional /// data too. /// [ContentProcessor(DisplayName = "RacingGame Model (Tangent support)")] public class RacingGameModelProcessor : ModelProcessor { /// /// Process the model /// /// Input data /// Context for logging /// Model content public override ModelContent Process( NodeContent input, ContentProcessorContext context) { // First generate tangent data because x files don't store them GenerateTangents(input, context); // Use the name of the bone for our mesh name if it is not set UseParentBoneNameIfMeshNameIsNotSet(input); // Store the current selected technique and if the texture uses alpha // into the mesh name for each mesh part. StoreEffectTechniqueInMeshName(input, context); // And let the rest be processed by the default model processor return base.Process(input, context); } /// /// Generate tangents helper method, x files do not have tangents /// exported, we have to generate them ourselfs. /// /// Input data /// Context for logging private void GenerateTangents( NodeContent input, ContentProcessorContext context) { MeshContent mesh = input as MeshContent; if (mesh != null) { // Generate trangents for the mesh. We don't want binormals, // so null is passed in for the last parameter. MeshHelper.CalculateTangentFrames(mesh, VertexChannelNames.TextureCoordinate(0), VertexChannelNames.Tangent(0), null); } // Go through all childs foreach (NodeContent child in input.Children) { GenerateTangents(child, context); } } /// /// Use parent bone's name if mesh's name is not set. /// /// private void UseParentBoneNameIfMeshNameIsNotSet(NodeContent input) { if (String.IsNullOrEmpty(input.Name) && input.Parent != null && String.IsNullOrEmpty(input.Parent.Name) == false) input.Name = input.Parent.Name; foreach (NodeContent node in input.Children) UseParentBoneNameIfMeshNameIsNotSet(node); } /// /// Stores the current selected technique and if the texture uses alpha /// into the mesh name for each mesh part. /// private void StoreEffectTechniqueInMeshName( NodeContent input, ContentProcessorContext context) { MeshContent mesh = input as MeshContent; if (mesh != null) { foreach (GeometryContent geom in mesh.Geometry) { EffectMaterialContent effectMaterial = geom.Material as EffectMaterialContent; if (effectMaterial != null) { if (effectMaterial.OpaqueData.ContainsKey("technique")) { // Store technique here! (OpaqueData["technique"] is an // int32) If we have multiple mesh parts in our mesh object, // there will be multiple techniques listed at the end of // our mesh name. input.Name = input.Name + effectMaterial.OpaqueData["technique"]; } } } } // Go through all childs foreach (NodeContent child in input.Children) { StoreEffectTechniqueInMeshName(child, context); } } } }