private void ProcessEffect(DREffectBindingContent binding, ContentProcessorContext context) { if (binding.EffectType == DREffectType.CustomEffect) { if (!string.IsNullOrEmpty(binding.EffectAsset)) { // The effect is a prebuilt asset. return; } // Build effect. if (binding.Effect == null) { string message = string.Format(CultureInfo.InvariantCulture, "Material \"{0}\" does not have an effect.", binding.Name); throw new InvalidContentException(message, binding.Identity); } if (String.IsNullOrEmpty(binding.Effect.Filename)) { string message = string.Format(CultureInfo.InvariantCulture, "Material \"{0}\" does not have a valid effect file. File name is null or empty.", binding.Name); throw new InvalidContentException(message, binding.Identity); } binding.CompiledEffect = OnBuildEffect(binding.Effect, context); } }
private void ProcessTextures(DREffectBindingContent material, ContentProcessorContext context, ContentIdentity identity) { // We have to call OnBuildTexture (which calls BuildAsset) to replace the // current texture references (.jpg, .bmp, etc.) with references to the built // textures (.xnb). // For stock effects we remove all unnecessary textures. if (material.EffectType == DREffectType.AlphaTestEffect || material.EffectType == DREffectType.BasicEffect || material.EffectType == DREffectType.SkinnedEffect) { var texture = material.Texture; material.Textures.Clear(); if (texture != null) material.Texture = BuildTexture("Texture", texture, context, identity); return; } if (material.EffectType == DREffectType.DualTextureEffect) { var texture = material.Texture; var texture2 = material.Texture2; material.Textures.Clear(); if (texture != null) material.Texture = BuildTexture(DualTextureMaterialContent.TextureKey, texture, context, identity); if (texture2 != null) material.Texture2 = BuildTexture(DualTextureMaterialContent.Texture2Key, texture2, context, identity); return; } if (material.EffectType == DREffectType.EnvironmentMapEffect) { var texture = material.Texture; var environmentMap = material.EnvironmentMap; material.Textures.Clear(); if (texture != null) material.Texture = BuildTexture(EnvironmentMapMaterialContent.TextureKey, texture, context, identity); if (environmentMap != null) material.EnvironmentMap = BuildTexture(EnvironmentMapMaterialContent.EnvironmentMapKey, environmentMap, context, identity); return; } // Custom effect: Build all textures stored in the MaterialContent. foreach (var entry in material.Textures.ToArray()) material.Textures[entry.Key] = BuildTexture(entry.Key, entry.Value, context, identity); }
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; }