Ejemplo n.º 1
0
        /// <summary>
        /// Called by the XNA Framework when importing an texture file to be used as a game asset. This
        /// is the method called by the XNA Framework when an asset is to be imported into an object
        /// that can be recognized by the Content Pipeline.
        /// </summary>
        /// <param name="filename">Name of a game asset file.</param>
        /// <param name="context">
        /// Contains information for importing a game asset, such as a logger interface.
        /// </param>
        /// <returns>Resulting game asset.</returns>
        public override TextureContent Import(string filename, ContentImporterContext context)
        {
            string extension = Path.GetExtension(filename);

            if (extension != null)
            {
                Texture texture = null;
                if (extension.Equals(".DDS", StringComparison.OrdinalIgnoreCase))
                {
                    using (var stream = File.OpenRead(filename))
                        texture = DdsHelper.Load(stream, DdsFlags.ForceRgb | DdsFlags.ExpandLuminance);
                }
                else if (extension.Equals(".TGA", StringComparison.OrdinalIgnoreCase))
                {
                    using (var stream = File.OpenRead(filename))
                        texture = TgaHelper.Load(stream);
                }

                if (texture != null)
                {
                    // When using the XNA content pipeline, check for MonoGame content.
                    if (!string.IsNullOrEmpty(ContentHelper.GetMonoGamePlatform()))

                    {
                        // These formats are not (yet) available in MonoGame.
                        switch (texture.Description.Format)
                        {
                        case DataFormat.B5G5R5A1_UNORM: // (16-bit TGA files.)
                        case DataFormat.R8_UNORM:
                        case DataFormat.A8_UNORM:
                            texture = texture.ConvertTo(DataFormat.R8G8B8A8_UNORM);
                            break;
                        }
                    }

                    // Convert DigitalRune Texture to XNA TextureContent.
                    var identity = new ContentIdentity(filename, "DigitalRune");
                    return(TextureHelper.ToContent(texture, identity));
                }
            }

            return(base.Import(filename, context));
        }
Ejemplo n.º 2
0
        private static void SetSkinnedMaterial(NodeContent node, Dictionary <MaterialContent, SkinnedMaterialContent> swappedMaterials, SkinnedMaterialContent defaultMaterial)
        {
            var mesh = node as MeshContent;

            if (mesh != null)
            {
                foreach (var geometry in mesh.Geometry)
                {
                    if (!ContentHelper.IsSkinned(geometry))
                    {
                        continue;
                    }

                    if (geometry.Material == null)
                    {
                        // Happens if the model is exported without a material. (XNA only!)
                        geometry.Material = defaultMaterial;
                        continue;
                    }

                    SkinnedMaterialContent skinnedMaterial;
                    if (!swappedMaterials.TryGetValue(geometry.Material, out skinnedMaterial))
                    {
                        // Convert BasicMaterialContent to SkinnedMaterialContent.
                        skinnedMaterial = ContentHelper.ConvertToSkinnedMaterial(geometry.Material);
                        if (skinnedMaterial == null)
                        {
                            continue;
                        }

                        swappedMaterials[geometry.Material] = skinnedMaterial;
                    }

                    geometry.Material = skinnedMaterial;
                }
            }

            foreach (var child in node.Children)
            {
                SetSkinnedMaterial(child, swappedMaterials, defaultMaterial);
            }
        }
Ejemplo n.º 3
0
        /// <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);
            }
        }
Ejemplo n.º 4
0
    private static void ValidateOpaqueData(ContentItem input)
    {
      foreach (var data in input.OpaqueData)
      {
        if (data.Key == "Effect" || data.Key == "CompiledEffect")
        {
          // "Effect" and "CompiledEffect" have already been handled.
          continue;
        }

        // All other opaque data only make sense if the can be used as effect parameter 
        // value. Only certain types can be used for effect parameters.
        if (!ContentHelper.IsValidTypeForEffectParameter(data.Value))
        {
          string message = string.Format(
            CultureInfo.InvariantCulture,
            "Material pass \"{0}\" contains invalid type for effect parameter. Name = \"{1}\", Type = \"{2}\".",
            input.Name, data.Key, data.Value.GetType());
          throw new InvalidContentException(message, input.Identity);
        }
      }
    }
Ejemplo n.º 5
0
        /// <summary>
        /// Bakes all node transforms in the specified subtree into the mesh geometry so that each
        /// node's transform is Identity. (Only bones and morph targets keep their transforms.)
        /// </summary>
        /// <param name="node">The node.</param>
        private static void BakeAllTransforms(NodeContent node)
        {
            if (node is BoneContent)
            {
                return;
            }
            if (ContentHelper.IsMorphTarget(node))
            {
                return;
            }

            if (node.Transform != Matrix.Identity)
            {
                MeshHelper.TransformScene(node, node.Transform);
                node.Transform = Matrix.Identity;
            }

            foreach (NodeContent child in node.Children)
            {
                BakeAllTransforms(child);
            }
        }
Ejemplo n.º 6
0
        /// <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);
        }
Ejemplo n.º 7
0
    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]);
        }
      }
    }
Ejemplo n.º 8
0
    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 }
        }
      };
    }
Ejemplo n.º 9
0
    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;
    }
Ejemplo n.º 10
0
    /// <summary>
    /// Processes a texture.
    /// </summary>
    /// <param name="input">The texture content to process.</param>
    /// <param name="context">Context for the specified processor.</param>
    /// <returns>The converted texture content.</returns>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="input"/> or <paramref name="context"/> is <see langword="null"/>.
    /// </exception>
    public override TextureContent Process(TextureContent input, ContentProcessorContext context)
    {
      if (input == null)
        throw new ArgumentNullException("input");
      if (context == null)
        throw new ArgumentNullException("context");

      // Linear vs. sRGB:
      // XNA does not support _SRGB texture formats. Texture processing is designed
      // for non-sRGB formats. (sRGB formats require a different order of operations!
      // See section "Alpha Blending" in DigitalRune KB.)

      try
      {
        var mipmapChain = input.Faces[0]; // Mipmap chain.
        var level0 = mipmapChain[0];      // Most detailed mipmap level.
        int width = level0.Width;
        int height = level0.Height;

        // Early out?
        if (!ColorKeyEnabled
            && (!GenerateMipmaps || (width == 1 && height == 1) // Does not need mipmaps
                || mipmapChain.Count > 1)                       // or already has mipmaps.
            && !PremultiplyAlpha
            && (!ResizeToPowerOfTwo || (MathHelper.IsPowerOf2(width) && MathHelper.IsPowerOf2(height)))
            && !ScaleAlphaToCoverage)
        {
          if (Format == DRTextureFormat.NoChange)
          {
            // No processing required.
            return input;
          }

          SurfaceFormat surfaceFormat;
          if (!level0.TryGetFormat(out surfaceFormat))
            throw new InvalidContentException("Surface format is not supported.", input.Identity);

          if ((Format == DRTextureFormat.Color && surfaceFormat == SurfaceFormat.Color)
              || (Format == DRTextureFormat.Dxt && IsDxt(surfaceFormat)))
          {
            // No processing required.
            return input;
          }
        }

        var texture = TextureHelper.ToTexture(input);
        var sourceFormat = texture.Description.Format;

        // Apply color keying.
        if (ColorKeyEnabled)
        {
          // Apply color keying in RGBA 8:8:8:8.
          texture = texture.ConvertTo(DataFormat.R8G8B8A8_UNORM);
          TextureHelper.ApplyColorKey(texture, ColorKeyColor.R, ColorKeyColor.G, ColorKeyColor.B, ColorKeyColor.A);
        }

        // Normal maps require special treatment (no sRGB, etc.).
        bool isNormalMap = (Format == DRTextureFormat.Normal || Format == DRTextureFormat.NormalInvertY);
        if (isNormalMap)
        {
          InputGamma = 1.0f;
          OutputGamma = 1.0f;
          PremultiplyAlpha = false;
        }

        // Check whether alpha channel is used.
        bool hasAlpha = false;            // true if alpha channel != 1.
        bool hasFractionalAlpha = false;  // true if alpha channel has 0 < alpha < 1.
        if (!isNormalMap)
        {
          if (GenerateMipmaps || ResizeToPowerOfTwo || PremultiplyAlpha || Format == DRTextureFormat.Dxt)
          {
            try
            {
              TextureHelper.HasAlpha(texture, out hasAlpha, out hasFractionalAlpha);
            }
            catch (NotSupportedException)
            {
              // HasAlpha() does not support the current format. Convert and try again.
              texture = texture.ConvertTo(DataFormat.R32G32B32A32_FLOAT);
              TextureHelper.HasAlpha(texture, out hasAlpha, out hasFractionalAlpha);
            }
          }
        }

        // Convert to high-precision, floating-point format for processing.
        texture = texture.ConvertTo(DataFormat.R32G32B32A32_FLOAT);

        if (!isNormalMap)
        {
          // Convert texture from gamma space to linear space.
          TextureHelper.GammaToLinear(texture, InputGamma);
        }
        else
        {
          // Convert normal map from [0, 1] to [-1, 1].
          TextureHelper.UnpackNormals(texture);
        }

        // The resize filter needs to consider alpha if the image is not already
        // premultiplied. PremultiplyAlpha indicates that the source image has
        // alpha, but is not yet premultiplied. (Premultiplication happen at the
        // end.)
        bool alphaTransparency = hasAlpha && PremultiplyAlpha;

        if (ResizeToPowerOfTwo || context.TargetProfile == GraphicsProfile.Reach && Format == DRTextureFormat.Dxt)
        {
          // Resize to power-of-two.
          int expectedWidth = RoundUpToPowerOfTwo(texture.Description.Width);
          int expectedHeight = RoundUpToPowerOfTwo(texture.Description.Height);
          if (expectedWidth != texture.Description.Width || expectedHeight != texture.Description.Height)
            texture = texture.Resize(expectedWidth, expectedHeight, texture.Description.Depth, ResizeFilter.Kaiser, alphaTransparency, TextureAddressMode.Clamp);
        }

        if (Format == DRTextureFormat.Dxt || Format == DRTextureFormat.Normal || Format == DRTextureFormat.NormalInvertY)
        {
          // Resize to multiple of four.
          int expectedWidth = RoundToMultipleOfFour(texture.Description.Width);
          int expectedHeight = RoundToMultipleOfFour(texture.Description.Height);
          if (expectedWidth != texture.Description.Width || expectedHeight != texture.Description.Height)
            texture = texture.Resize(expectedWidth, expectedHeight, texture.Description.Depth, ResizeFilter.Kaiser, alphaTransparency, TextureAddressMode.Clamp);
        }

        if (GenerateMipmaps && texture.Description.MipLevels <= 1)
        {
            // Generate mipmaps.
            texture.GenerateMipmaps(ResizeFilter.Box, alphaTransparency, TextureAddressMode.Repeat);
        }

        // For debugging:
        // ColorizeMipmaps(texture);

        if (!isNormalMap)
        {
          if (ScaleAlphaToCoverage)
            TextureHelper.ScaleAlphaToCoverage(texture, ReferenceAlpha, /* data not yet premultiplied */ false);

          // Convert texture from linear space to gamma space.
          TextureHelper.LinearToGamma(texture, OutputGamma);

          // Premultiply alpha.
          if (hasAlpha && PremultiplyAlpha)
            TextureHelper.PremultiplyAlpha(texture);
        }
        else
        {
          // Renormalize normal map and convert to DXT5nm.
          TextureHelper.ProcessNormals(texture, Format == DRTextureFormat.NormalInvertY);
        }


        // No PVRTC in XNA build.
        string mgPlatform = ContentHelper.GetMonoGamePlatform();
        if (!string.IsNullOrEmpty(mgPlatform) && mgPlatform.ToUpperInvariant() == "IOS")
          Format = DRTextureFormat.Color;


        // Convert to from floating-point format to requested output format.
        switch (Format)
        {
          case DRTextureFormat.NoChange:
            texture = texture.ConvertTo(sourceFormat);
            input = TextureHelper.ToContent(texture, input.Identity);
            break;

          case DRTextureFormat.Color:
            texture = texture.ConvertTo(DataFormat.R8G8B8A8_UNORM);
            input = TextureHelper.ToContent(texture, input.Identity);
            break;

          case DRTextureFormat.Dxt:
            if (texture.Description.Dimension == TextureDimension.Texture3D)
            {
              texture = texture.ConvertTo(DataFormat.R8G8B8A8_UNORM);
              input = TextureHelper.ToContent(texture, input.Identity);
            }
            else
            {

              input = Compress(context, texture, hasAlpha, hasFractionalAlpha, PremultiplyAlpha, input.Identity);
#else
              if (hasFractionalAlpha)
                texture = texture.ConvertTo(DataFormat.BC3_UNORM);
              else
                texture = texture.ConvertTo(DataFormat.BC1_UNORM);

              input = TextureHelper.ToContent(texture, input.Identity);

            }
            break;

          case DRTextureFormat.Normal:
          case DRTextureFormat.NormalInvertY:

            input = Compress(context, texture, true, true, false, input.Identity);
#else
            texture = texture.ConvertTo(DataFormat.BC3_UNORM);
            input = TextureHelper.ToContent(texture, input.Identity);

            break;
          default:
            throw new NotSupportedException("The specified output format is not supported.");
        }
      }
      catch (Exception ex)
      {
        throw new InvalidContentException(ex.Message, input.Identity);
      }

      return input;
    }
Ejemplo n.º 11
0
        /// <summary>
        /// Traverses the scene graph and collapses all LODs into <strong>LodGroupNodes</strong>.
        /// </summary>
        private void CombineLodGroups()
        {
            // The LOD level is encoded in the scene node name. Example: "MeshXyz_LOD2"
            // --> Collect all LOD levels.
            var lodGroupNodes = new Dictionary <string, DRLodGroupNodeContent>();

            foreach (var node in _model.GetSubtree())
            {
                string name;
                int?   lodLevel;
                ContentHelper.ParseSceneNodeName(node.Name, out name, out lodLevel);
                if (lodLevel.HasValue && !string.IsNullOrWhiteSpace(name))
                {
                    // Scene node is part of LOD group.
                    DRLodGroupNodeContent lodGroupNode;
                    if (!lodGroupNodes.TryGetValue(name, out lodGroupNode))
                    {
                        lodGroupNode = new DRLodGroupNodeContent {
                            Name = name
                        };
                        lodGroupNodes.Add(name, lodGroupNode);
                    }

                    lodGroupNode.Levels.Add(node);
                    node.LodLevel = lodLevel.Value;
                }
            }

            // Detach scene nodes that belong to LOD group and replace them with a single LodGroupNode.
            foreach (var lodGroupNode in lodGroupNodes.Values)
            {
                // Find LOD0 (= the scene node that represents the highest level of detail).
                var lod0 = lodGroupNode.Levels.FirstOrDefault(n => n.LodLevel == 0);
                if (lod0 == null)
                {
                    // LOD0 is not in list. The scene node does probably not have "_LOD0" in its name.
                    // --> Search for scene node without extension "_LOD0".
                    lod0 = _model.GetSubtree().FirstOrDefault(n => n.Name == lodGroupNode.Name);
                    if (lod0 != null)
                    {
                        lodGroupNode.Levels.Add(lod0);
                        lod0.LodLevel = 0;
                    }
                }

                // Note: At this point all LODs should be registered in LOD group.
                lodGroupNode.Levels.Sort(LodComparer.Instance);

                // Set MaxDistance by checking all LOD nodes.
                lodGroupNode.MaxDistance = lodGroupNode.Levels
                                           .SelectMany(n => n.GetSubtree())
                                           .Max(n => n.MaxDistance);

                if (lod0 == null)
                {
                    // LOD0 was not found.
                    // --> As a fallback use first LOD.
                    lod0 = lodGroupNode.Levels[0];
                }

                // Replace LOD0 with LodGroupNode.
                lodGroupNode.ScaleLocal = lod0.ScaleLocal;
                lodGroupNode.PoseLocal  = lod0.PoseLocal;
                // We have to set PoseWorld too. PoseWorld/PoseLocal are separate properties in
                // DRSceneNodeContent, unlike SceneNode where they update each other.
                lodGroupNode.PoseWorld = lod0.PoseWorld;
                lod0.Parent.Children.Add(lodGroupNode);

                // Remove all LODs from scene graph.
                foreach (var lodNode in lodGroupNode.Levels)
                {
                    lodNode.Parent.Children.Remove(lodNode);
                }
            }
        }
Ejemplo n.º 12
0
        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);
        }
        private static DRSceneNodeContent BuildSceneGraph(NodeContent node, DRSceneNodeContent parent)
        {
            CheckForCyclicReferences(node);

            DRSceneNodeContent sceneNode;

            if (node is BoneContent)
            {
                // ----- BoneContent
                // Bones do not show up in the scene graph.
                sceneNode = null;
            }
            else if (node is MeshContent)
            {
                // ----- MeshContent
                var    mesh = (MeshContent)node;
                string morphTargetName;
                if (ContentHelper.IsMorphTarget(mesh, out morphTargetName))
                {
                    // ----- Morph Targets
                    // Morph targets are stored in the parent mesh, they do not show up in
                    // the scene graph. Children of morph targets are ignored!
                    mesh.Name = morphTargetName;
                    AddMorphTarget(parent, mesh);
                    sceneNode = null;
                }
                else if (ContentHelper.IsOccluder(mesh))
                {
                    // ----- OccluderNode
                    sceneNode = new DROccluderNodeContent {
                        InputMesh = mesh
                    };
                }
                else
                {
                    // ----- MeshNode
                    sceneNode = new DRMeshNodeContent {
                        InputMesh = mesh
                    };
                }
            }
            else
            {
                // ----- Empty/unsupported node
                sceneNode = new DRSceneNodeContent();
            }

            if (sceneNode != null)
            {
                sceneNode.Name = node.Name;
                Pose    pose;
                Vector3 scale;
                DecomposeTransform(node, out pose, out scale);
                sceneNode.PoseLocal  = pose;
                sceneNode.ScaleLocal = scale;
                if (node.Children.Count > 0)
                {
                    // Process children.
                    sceneNode.Children = new List <DRSceneNodeContent>();

                    // Recursively add children.
                    foreach (var childNode in node.Children)
                    {
                        var childSceneNode = BuildSceneGraph(childNode, sceneNode);
                        if (childSceneNode != null)
                        {
                            childSceneNode.Parent = sceneNode;
                            sceneNode.Children.Add(childSceneNode);
                        }
                    }
                }
            }

            return(sceneNode);
        }