#region Using directives using System; using System.Collections.Generic; using System.Collections.Specialized; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using Microsoft.Xna.Framework.Content.Pipeline; using Microsoft.Xna.Framework.Content.Pipeline.Processors; using Microsoft.Xna.Framework.Content.Pipeline.Graphics; using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler; using XnaGraphicEngineContentProcessors.Helpers; #endregion namespace XnaGraphicEngineContentProcessorsContentProcessors { /// /// XnaGraphicEngine model processor for x files. Loads models the same way as /// the ModelProcessor class, but generates tangents and some additional /// data too. /// [ContentProcessor(DisplayName = "XnaGraphicEngine Model (Tangent support)")] public class XnaGraphicEngineModelProcessor : ModelProcessor { #region Process /// /// 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); } // Process #endregion #region Generate tangents /// /// 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); } // if // Go through all childs foreach (NodeContent child in input.Children) { GenerateTangents(child, context); } // foreach } // GenerateTangents(input, context) #endregion #region UseParentBoneNameIfMeshNameIsNotSet /// /// 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); } // UseParentBoneNameIfMeshNameIsNotSet(input) #endregion #region StoreEffectMaterialsAndTechniques /// /// 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) input.Name = input.Name + effectMaterial.OpaqueData["technique"]; } // if } // if } // foreach } // if // Go through all childs foreach (NodeContent child in input.Children) { StoreEffectTechniqueInMeshName(child, context); } // foreach } // StoreEffectTechniqueInMeshName() #endregion } // class XnaGraphicEngineContentProcessorsModelProcessor } // namespace XnaGraphicEngineContentProcessorsContentProcessors