private ExternalReference <TextureContent> BuildTexture(string textureName, ExternalReference <TextureContent> texture, ContentProcessorContext context, ContentIdentity identity) { // Finding resources is not as robust in MonoGame: Fix path. texture.Filename = ContentHelper.FindFile(texture.Filename, identity); return(OnBuildTexture(textureName, texture, context)); }
private string GetTextureFileName(ExternalReference <TextureContent> texture) { try { return(ContentHelper.FindFile(texture.Filename, _input.Identity)); } catch (InvalidContentException) { // Referenced texture file not found. // No problem - use file name, but strip path. return(Path.GetFileName(texture.Filename)); } }
private static void MergeAnimation(string animationFile, AnimationContentDictionary animationDictionary, ContentIdentity contentIdentity, ContentProcessorContext context) { if (string.IsNullOrEmpty(animationFile)) { return; } if (animationDictionary == null) { throw new ArgumentNullException("animationDictionary"); } if (context == null) { throw new ArgumentNullException("context"); } // Use content pipeline to build the asset. animationFile = ContentHelper.FindFile(animationFile, contentIdentity); NodeContent mergeModel = context.BuildAndLoadAsset <NodeContent, NodeContent>(new ExternalReference <NodeContent>(animationFile), null); // Find the skeleton. BoneContent mergeRoot = MeshHelper.FindSkeleton(mergeModel); if (mergeRoot == null) { context.Logger.LogWarning(null, contentIdentity, "Animation model file '{0}' has no root bone. Cannot merge animations.", animationFile); return; } // Merge all animations of the skeleton root node. foreach (string animationName in mergeRoot.Animations.Keys) { if (animationDictionary.ContainsKey(animationName)) { context.Logger.LogWarning(null, contentIdentity, "Replacing animation '{0}' with merged animation from '{1}'.", animationName, animationFile); animationDictionary[animationName] = mergeRoot.Animations[animationName]; } else { context.Logger.LogImportantMessage("Merging animation '{0}' from '{1}'.", animationName, animationFile); animationDictionary.Add(animationName, mergeRoot.Animations[animationName]); } } }
/// <summary> /// Imports the asset. /// </summary> /// <param name="context">Contains any required custom process parameters.</param> public void Import(ContentProcessorContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (string.IsNullOrWhiteSpace(ModelDescription.FileName)) { throw new InvalidContentException("The attribute 'File' is not set in the model description (.drmdl file).", Identity); } var fileName = ContentHelper.FindFile(ModelDescription.FileName, Identity); var asset = new ExternalReference <NodeContent>(fileName); var node = context.BuildAndLoadAsset <NodeContent, NodeContent>(asset, null, null, ModelDescription.Importer); // BuildAndLoadAsset does not return root node in MonoGame. while (node.Parent != null) { node = node.Parent; } if (node.GetType() == typeof(NodeContent)) { // Root node is of type NodeContent. // --> Copy root node content and children. Name = node.Name; Transform = node.Transform; Animations.AddRange(node.Animations); OpaqueData.AddRange(node.OpaqueData); var children = node.Children.ToArray(); node.Children.Clear(); // Clear parents. Children.AddRange(children); } else { // Root node is a derived type. // --> Add node as child. Children.Add(node); } }
/// <summary> /// Builds the material. /// </summary> /// <param name="material"> /// The external material (<see cref="string"/>) or the local material /// (<see cref="MaterialContent"/>). /// </param> /// <returns> /// The processed material. /// </returns> private object BuildMaterial(object material) { object convertedMaterial; if (!_materials.TryGetValue(material, out convertedMaterial)) { string name = material as string; if (name != null) { // Build external material (XML file). string fileName = ContentHelper.FindFile(name, _input.Identity); var reference = new ExternalReference <DRMaterialContent>(fileName); convertedMaterial = OnBuildMaterial(reference, _context); } else { // Build local material. convertedMaterial = OnConvertMaterial((MaterialContent)material, _context); } } return(convertedMaterial); }
private DRMaterialContent ProcessInternal(MaterialContent input, ContentProcessorContext context) { // Create effect binding for default render pass. var binding = new DREffectBindingContent { Name = DefaultPass, Identity = input.Identity }; // Copy opaque data from material content. ValidateOpaqueData(input); foreach (var entry in input.OpaqueData) { binding.OpaqueData.Add(entry.Key, entry.Value); } foreach (var entry in input.Textures) { binding.Textures.Add(entry.Key, entry.Value); } // ----- Effect if (input is AlphaTestMaterialContent) { binding.EffectType = DREffectType.AlphaTestEffect; } else if (input is DualTextureMaterialContent) { binding.EffectType = DREffectType.DualTextureEffect; } else if (input is EnvironmentMapMaterialContent) { binding.EffectType = DREffectType.EnvironmentMapEffect; } else if (input is SkinnedMaterialContent) { binding.EffectType = DREffectType.SkinnedEffect; } else { var effectMaterial = input as EffectMaterialContent; if (effectMaterial == null || effectMaterial.Effect == null || string.IsNullOrEmpty(effectMaterial.Effect.Filename)) { // The material is either // - a BasicMaterialContent (default) // - or an EffectMaterialContent without an effect. // --> Use the DefaultEffect. binding.EffectType = DefaultEffectType; if (DefaultEffectType == DREffectType.CustomEffect) { if (String.IsNullOrEmpty(DefaultEffectFile)) { throw new InvalidContentException("DefaultEffectType is set to CustomEffect, but DefaultEffectFile is null or empty.", input.Identity); } string fileName = ContentHelper.FindFile(DefaultEffectFile, input.Identity); binding.Effect = new ExternalReference <EffectContent>(fileName); } } } ProcessEffect(binding, context); // ----- Textures foreach (var texture in binding.Textures.Values) { // Store texture parameters in opaque data. texture.OpaqueData.Clear(); texture.OpaqueData.Add("ColorKeyColor", ColorKeyColor); texture.OpaqueData.Add("ColorKeyEnabled", ColorKeyEnabled); texture.OpaqueData.Add("GenerateMipmaps", GenerateMipmaps); texture.OpaqueData.Add("InputGamma", InputTextureGamma); texture.OpaqueData.Add("OutputGamma", OutputTextureGamma); texture.OpaqueData.Add("PremultiplyAlpha", PremultiplyTextureAlpha); texture.OpaqueData.Add("ResizeToPowerOfTwo", ResizeTexturesToPowerOfTwo); texture.OpaqueData.Add("Format", TextureFormat); texture.OpaqueData.Add("ReferenceAlpha", ReferenceAlpha); texture.OpaqueData.Add("ScaleAlphaToCoverage", ScaleTextureAlphaToCoverage); } ProcessTextures(binding, context, input.Identity); // Create DigitalRune material with default render pass. return(new DRMaterialContent { Name = input.Name, Identity = input.Identity, Passes = new Dictionary <string, DREffectBindingContent> { { DefaultPass, binding } } }); }
private DRMaterialContent ProcessInternal(DRMaterialContent material, ContentProcessorContext context) { material.Passes = new Dictionary <string, DREffectBindingContent>(); // Parse XML file. var document = material.Definition; var identity = material.Identity; var materialElement = document.Root; if (materialElement == null || materialElement.Name != "Material") { string message = string.Format(CultureInfo.InvariantCulture, "Root element \"<Material>\" is missing in XML."); throw new InvalidContentException(message, identity); } // Override material name, if attribute is set. material.Name = (string)materialElement.Attribute("Name") ?? material.Name; // Create effect bindings for all render passes. foreach (var passElement in materialElement.Elements("Pass")) { string pass = passElement.GetMandatoryAttribute("Name", identity); if (material.Passes.ContainsKey(pass)) { string message = XmlHelper.GetExceptionMessage(passElement, "Duplicate entry. The pass \"{0}\" was already defined.", pass); throw new InvalidContentException(message, identity); } var binding = new DREffectBindingContent { Name = pass, Identity = identity }; // Skip this pass if the graphics profile does not match the actual target profile. string profile = (string)passElement.Attribute("Profile") ?? "ANY"; string profileLower = profile.ToUpperInvariant(); if (profileLower == "REACH") { if (context.TargetProfile != GraphicsProfile.Reach) { continue; } } else if (profileLower == "HIDEF") { if (context.TargetProfile != GraphicsProfile.HiDef) { continue; } } else if (profileLower != "ANY") { string message = XmlHelper.GetExceptionMessage(passElement, "Unknown profile: \"{0}\". Allowed values are \"Reach\", \"HiDef\" or \"Any\"", profile); throw new InvalidContentException(message, identity); } // ----- Effect string effectName = passElement.GetMandatoryAttribute("Effect", identity); switch (effectName) { case "AlphaTestEffect": binding.EffectType = DREffectType.AlphaTestEffect; break; case "BasicEffect": binding.EffectType = DREffectType.BasicEffect; break; case "DualTextureEffect": binding.EffectType = DREffectType.DualTextureEffect; break; case "EnvironmentMapEffect": binding.EffectType = DREffectType.EnvironmentMapEffect; break; case "SkinnedEffect": binding.EffectType = DREffectType.SkinnedEffect; break; default: binding.EffectType = DREffectType.CustomEffect; if (string.IsNullOrEmpty(Path.GetExtension(effectName))) { // The effect is a prebuilt asset. effectName is the name of the asset, // for example: effectName = "DigitalRune\GBuffer". binding.EffectAsset = effectName; } else { // The effect is a local .fx file. effectName = ContentHelper.FindFile(effectName, identity); binding.Effect = new ExternalReference <EffectContent>(effectName); } break; } ProcessEffect(binding, context); // ----- Parameters foreach (var parameterElement in passElement.Elements("Parameter")) { string name = parameterElement.GetMandatoryAttribute("Name", identity); if (binding.OpaqueData.ContainsKey(name)) { string message = XmlHelper.GetExceptionMessage(parameterElement, "Duplicate entry. The parameter \"{0}\" was already defined.", name); throw new InvalidContentException(message, identity); } object value = parameterElement.Attribute("Value").ToParameterValue(null, identity); if (value != null) { binding.OpaqueData.Add(name, value); } } // ----- Textures foreach (var textureElement in passElement.Elements("Texture")) { string name = textureElement.GetMandatoryAttribute("Name", identity); if (binding.Textures.ContainsKey(name)) { string message = XmlHelper.GetExceptionMessage(textureElement, "Duplicate entry. The texture \"{0}\" was already defined.", name); throw new InvalidContentException(message, identity); } string fileName = textureElement.GetMandatoryAttribute("File", identity); fileName = ContentHelper.FindFile(fileName, identity); // Texture processor parameters. var colorKeyAttribute = textureElement.Attribute("ColorKey"); bool colorKeyEnabled = colorKeyAttribute != null; Color colorKeyColor = colorKeyAttribute.ToColor(Color.Magenta, identity); bool generateMipmaps = (bool?)textureElement.Attribute("GenerateMipmaps") ?? true; float inputGamma = (float?)textureElement.Attribute("InputGamma") ?? 2.2f; float outputGamma = (float?)textureElement.Attribute("OutputGamma") ?? 2.2f; bool premultiplyAlpha = (bool?)textureElement.Attribute("PremultiplyAlpha") ?? true; bool resizeToPowerOfTwo = (bool?)textureElement.Attribute("ResizeToPowerOfTwo") ?? false; DRTextureFormat textureFormat = textureElement.Attribute("Format").ToTextureFormat(DRTextureFormat.Dxt, identity); float referenceAlpha = (float?)textureElement.Attribute("ReferenceAlpha") ?? 0.9f; bool scaleAlphaToCoverage = (bool?)textureElement.Attribute("ScaleAlphaToCoverage") ?? false; // Store texture parameters in opaque data. var texture = new ExternalReference <TextureContent>(fileName); var defaultTextureProcessor = new DRTextureProcessor(); if (colorKeyColor != defaultTextureProcessor.ColorKeyColor) { texture.OpaqueData.Add("ColorKeyColor", colorKeyColor); } if (colorKeyEnabled != defaultTextureProcessor.ColorKeyEnabled) { texture.OpaqueData.Add("ColorKeyEnabled", colorKeyEnabled); } if (generateMipmaps != defaultTextureProcessor.GenerateMipmaps) { texture.OpaqueData.Add("GenerateMipmaps", generateMipmaps); } if (inputGamma != defaultTextureProcessor.InputGamma) { texture.OpaqueData.Add("InputGamma", inputGamma); } if (outputGamma != defaultTextureProcessor.OutputGamma) { texture.OpaqueData.Add("OutputGamma", outputGamma); } if (premultiplyAlpha != defaultTextureProcessor.PremultiplyAlpha) { texture.OpaqueData.Add("PremultiplyAlpha", premultiplyAlpha); } if (resizeToPowerOfTwo != defaultTextureProcessor.ResizeToPowerOfTwo) { texture.OpaqueData.Add("ResizeToPowerOfTwo", resizeToPowerOfTwo); } if (textureFormat != defaultTextureProcessor.Format) { texture.OpaqueData.Add("Format", textureFormat); } if (referenceAlpha != defaultTextureProcessor.ReferenceAlpha) { texture.OpaqueData.Add("ReferenceAlpha", referenceAlpha); } if (scaleAlphaToCoverage != defaultTextureProcessor.ScaleAlphaToCoverage) { texture.OpaqueData.Add("ScaleAlphaToCoverage", scaleAlphaToCoverage); } binding.Textures.Add(name, texture); } ProcessTextures(binding, context, identity); material.Passes.Add(pass, binding); } return(material); }
public static void Split(AnimationContentDictionary animationDictionary, string splitFile, ContentIdentity contentIdentity, ContentProcessorContext context) { if (animationDictionary == null) { return; } if (string.IsNullOrEmpty(splitFile)) { return; } if (contentIdentity == null) { throw new ArgumentNullException("contentIdentity"); } if (context == null) { throw new ArgumentNullException("context"); } if (animationDictionary.Count == 0) { context.Logger.LogWarning(null, contentIdentity, "The model does not have an animation. Animation splitting is skipped."); return; } if (animationDictionary.Count > 1) { context.Logger.LogWarning(null, contentIdentity, "The model contains more than 1 animation. The animation splitting is performed on the first animation. Other animations are deleted!"); } // Load XML file. splitFile = ContentHelper.FindFile(splitFile, contentIdentity); XDocument document = XDocument.Load(splitFile, LoadOptions.SetLineInfo); // Let the content pipeline know that we depend on this file and we need to // rebuild the content if the file is modified. context.AddDependency(splitFile); // Parse XML. var animationsElement = document.Element("Animations"); if (animationsElement == null) { context.Logger.LogWarning(null, contentIdentity, "The animation split file \"{0}\" does not contain an <Animations> root node.", splitFile); return; } var wrappedContext = new ContentPipelineContext(context); var splits = ParseAnimationSplitDefinitions(animationsElement, contentIdentity, wrappedContext); if (splits == null || splits.Count == 0) { context.Logger.LogWarning(null, contentIdentity, "The XML file with the animation split definitions is invalid or empty. Animation is not split."); return; } // Split animations. Split(animationDictionary, splits, contentIdentity, context); }