Exemple #1
0
        /// <summary>
        /// Builds the content for the source audio.
        /// </summary>
        /// <param name="input">The audio content to build.</param>
        /// <param name="context">Context for the specified processor.</param>
        /// <returns>The built audio.</returns>
        public override SongContent Process(AudioContent input, ContentProcessorContext context)
        {
            // Most platforms will use AAC ("mp4") by default
            var targetFormat = ConversionFormat.Aac;

            switch (context.TargetPlatform)
            {
            case TargetPlatform.Windows:
            case TargetPlatform.WindowsPhone8:
            case TargetPlatform.WindowsStoreApp:
                targetFormat = ConversionFormat.WindowsMedia;
                break;

            case TargetPlatform.Linux:
                targetFormat = ConversionFormat.Vorbis;
                break;
            }

            // Get the song output path with the target format extension.
            var songFileName = Path.ChangeExtension(context.OutputFilename, AudioHelper.GetExtension(targetFormat));

            // Make sure the output folder for the song exists.
            Directory.CreateDirectory(Path.GetDirectoryName(songFileName));

            // Convert and write out the song media file.
            input.ConvertFormat(targetFormat, quality, songFileName);

            // Let the pipeline know about the song file so it can clean things up.
            context.AddOutputFile(songFileName);

            // Return the XNB song content.
            return(new SongContent(PathHelper.GetRelativePath(Path.GetDirectoryName(context.OutputFilename) + Path.DirectorySeparatorChar, songFileName), input.Duration));
        }
Exemple #2
0
        /// <summary>
        /// Writes an asset in compiled binary format.
        /// </summary>
        /// <typeparam name="T">The type of asset to write.</typeparam>
        /// <param name="asset">The asset object to write.</param>
        /// <param name="assetName">Name of the final compiled content.</param>
        /// <returns>Reference to the final compiled content.</returns>
        /// <remarks>Adapted from http://forums.xna.com/forums/p/23919/129260.aspx#129260</remarks>
        public static ExternalReference <T> WriteAsset <T>(this ContentProcessorContext context, T asset, string assetName)
        {
            var constructors  = typeof(ContentCompiler).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance);
            var compileMethod = typeof(ContentCompiler).GetMethod("Compile", BindingFlags.NonPublic | BindingFlags.Instance);

            var compiler = constructors[0].Invoke(null) as ContentCompiler;

            string outputFile = context.OutputDirectory + assetName + ".xnb";

            context.AddOutputFile(outputFile);

            using (FileStream stream = new FileStream(outputFile, FileMode.Create))
            {
                object[] parameters = new object[]
                {
                    stream,
                    asset,
                    context.TargetPlatform,
                    true,
                    context.OutputDirectory,
                    context.OutputDirectory
                };
                compileMethod.Invoke(compiler, parameters);
            }

            return(new ExternalReference <T>(outputFile));
        }
Exemple #3
0
        public override AtlasContent Process(AtlasDeclaration input, ContentProcessorContext context)
        {
            Dictionary <int, Bitmap> images     = new Dictionary <int, Bitmap>();
            Dictionary <int, string> imageNames = new Dictionary <int, string>();


            ImagePacker imagePacker = new ImagePacker();
            var         imgFiles    = input.Images.Select(i => Path.Combine(input.AtlasRootDir, i.Replace('/', '\\')));

            if (imgFiles.Count() == 0)
            {
                throw new ArgumentException("No Image found");
            }
            Bitmap output;
            Dictionary <string, Sprite> map;

            imagePacker.PackImage(imgFiles, true, true, 4096, 4096, 0, true, out output, out map);


            var finalSprites = map.Select(s => { s.Value.Name = s.Key.Substring(0, s.Key.LastIndexOf('.')).Substring(input.AtlasRootDir.Length + 1).Replace('\\', '/').Trim('.', '/'); return(s.Value); }).ToArray();
            var atlasPngPath = Path.Combine(input.AtlasRootDir, input.Name + ".png");

            using (FileStream outputSpriteFile = new FileStream(atlasPngPath, FileMode.Create))
            {
                output.Save(outputSpriteFile, ImageFormat.Png);
            }
            context.AddOutputFile(atlasPngPath);
            ExternalReference <TextureContent> texture = new ExternalReference <TextureContent>(atlasPngPath);

            texture = BuildTexture($"{input.Name}Texture", texture, context);

            return(new AtlasContent {
                Texture = texture, Sprites = finalSprites
            });
        }
Exemple #4
0
        internal static void WriteTexture(object spriteFontContent, bool alphaOnly, ContentProcessorContext context, string filename)
        {
            dynamic sfc = ExposedObject.From(spriteFontContent);

            // Get a copy of the texture in Color format
            Texture2DContent           originalTexture = sfc.Texture;
            BitmapContent              originalBitmap  = originalTexture.Mipmaps[0];
            PixelBitmapContent <Color> colorBitmap     = new PixelBitmapContent <Color>(
                originalBitmap.Width, originalBitmap.Height);

            BitmapContent.Copy(originalBitmap, colorBitmap);


            Bitmap bitmap = new Bitmap(colorBitmap.Width, colorBitmap.Height, PixelFormat.Format32bppArgb);

            for (int x = 0; x < colorBitmap.Width; x++)
            {
                for (int y = 0; y < colorBitmap.Height; y++)
                {
                    Color c = colorBitmap.GetPixel(x, y);
                    if (alphaOnly)
                    {
                        c.R = 255; c.G = 255; c.B = 255;                 // Undo premultiplication
                    }
                    bitmap.SetPixel(x, y, System.Drawing.Color.FromArgb(c.A, c.R, c.G, c.B));
                }
            }
            bitmap.Save(filename, ImageFormat.Png);
            bitmap.Dispose();

            context.AddOutputFile(filename);
        }
        /// <summary>
        /// Builds the content for the source audio.
        /// </summary>
        /// <param name="input">The audio content to build.</param>
        /// <param name="context">Context for the specified processor.</param>
        /// <returns>The built audio.</returns>
        public override SongContent Process(AudioContent input, ContentProcessorContext context)
        {
            // The xnb name is the basis for the final song filename.
            string songInputFile = context.OutputFilename;

            // Convert and write out the song media file.
            var profile      = AudioProfile.ForPlatform(context.TargetPlatform);
            var finalQuality = profile.ConvertStreamingAudio(
                context.TargetPlatform,
                Quality,
                input,
                songInputFile,
                out string songOutFile);

            // Let the pipeline know about the song file so it can clean things up.
            context.AddOutputFile(songOutFile);

            if (Quality != finalQuality)
            {
                context.Logger.LogMessage(
                    "Failed to convert using \"{0}\" quality, used \"{1}\" quality",
                    Quality, finalQuality);
            }

            // Return the XNB song content.
            string dirPath  = Path.GetDirectoryName(context.OutputFilename) + Path.DirectorySeparatorChar;
            string filePath = PathHelper.GetRelativePath(dirPath, songOutFile);

            return(new SongContent(filePath, input.Duration));
        }
        public override SongContent Process(AudioContent input, ContentProcessorContext context)
        {
            // Fallback if we aren't buiding for iOS.
            var platform = ContentHelper.GetMonoGamePlatform();
            if (platform != MonoGamePlatform.iOS && platform != MonoGamePlatform.Linux)
                return base.Process(input, context);

            //TODO: If quality isn't best and it's a .wma, don't compress to MP3. Leave it as a .wav instead
            string outputType = (platform == MonoGamePlatform.iOS) ? "mp3" : "wav";
            string outputFilename = Path.ChangeExtension(context.OutputFilename, outputType);
            string directoryName = Path.GetDirectoryName(outputFilename);
            if (!Directory.Exists(directoryName))
                Directory.CreateDirectory(directoryName);

            var inputFilename = Path.GetFullPath(input.FileName);

            // XNA's songprocessor converts the bitrate on the input file based 
            // on it's conversion quality. 
            //http://blogs.msdn.com/b/etayrien/archive/2008/09/22/audio-input-and-output-formats.aspx
            int desiredOutputBitRate = 0;
            switch (this.Quality)
            {
                case ConversionQuality.Low:
                    desiredOutputBitRate = 96000;
                    break;

                case ConversionQuality.Medium:
                    desiredOutputBitRate = 128000;
                    break;

                case ConversionQuality.Best:
                    desiredOutputBitRate = 192000;
                    break;
            }

            AudioFileType target = (platform == MonoGamePlatform.iOS) ? AudioFileType.Mp3 : AudioFileType.Wav;
            // Create a new file if we need to.
            FileStream outputStream = input.FileType != target ? new FileStream(outputFilename, FileMode.Create) : null;
            
            if (input.FileType != target)
                AudioConverter.ConvertFile(inputFilename, outputStream, target, desiredOutputBitRate,
                            input.Format.BitsPerSample, input.Format.ChannelCount);
            else
                File.Copy(inputFilename, outputFilename, true);

            if (outputStream != null)
                outputStream.Close();

            context.AddOutputFile(outputFilename);

            // SoundEffectContent is a sealed class, construct it using reflection
            var type = typeof(SongContent);
            ConstructorInfo c = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,
                    null, new Type[] { typeof(string), typeof(int) }, null);

            var outputSongContent = (SongContent)c.Invoke(new Object[] { Path.GetFileName(outputFilename), (int)input.Duration.TotalMilliseconds });

            return outputSongContent;
        }
Exemple #7
0
        public override VideoContent Process(VideoContent input, ContentProcessorContext context)
        {
            var relative     = Path.GetDirectoryName(PathHelper.GetRelativePath(context.OutputDirectory, context.OutputFilename));
            var relVideoPath = PathHelper.Normalize(Path.Combine(relative, Path.GetFileName(input.Filename)));
            var absVideoPath = PathHelper.Normalize(Path.Combine(context.OutputDirectory, relVideoPath));

            // Make sure the output folder for the video exists.
            Directory.CreateDirectory(Path.GetDirectoryName(absVideoPath));

            // Copy the already encoded video file over
            File.Copy(input.Filename, absVideoPath, true);
            context.AddOutputFile(absVideoPath);

            // Fixup relative path
            input.Filename = PathHelper.GetRelativePath(context.OutputFilename, absVideoPath);

            return(input);
        }
Exemple #8
0
        /// <summary>
        /// Processes the string representation of the specified effect into a platform-specific binary format using the specified context.
        /// </summary>
        /// <param name="input">The effect string to be processed.</param>
        /// <param name="context">Context for the specified processor.</param>
        /// <returns>A platform-specific compiled binary effect.</returns>
        /// <remarks>If you get an error during processing, compilation stops immediately. The effect processor displays an error message. Once you fix the current error, it is possible you may get more errors on subsequent compilation attempts.</remarks>
        public override CompiledEffectContent Process(EffectContent input, ContentProcessorContext context)
        {
#if WINDOWS
            var options = new Options();
            options.SourceFile = input.Identity.SourceFilename;

            options.Profile = ShaderProfile.ForPlatform(context.TargetPlatform.ToString());
            if (options.Profile == null)
            {
                throw new InvalidContentException(string.Format("{0} effects are not supported.", context.TargetPlatform), input.Identity);
            }

            options.Debug      = DebugMode == EffectProcessorDebugMode.Debug;
            options.Defines    = Defines;
            options.OutputFile = context.OutputFilename;

            // Parse the MGFX file expanding includes, macros, and returning the techniques.
            ShaderResult shaderResult;
            try
            {
                shaderResult = ShaderResult.FromFile(options.SourceFile, options,
                                                     new ContentPipelineEffectCompilerOutput(context));

                // Add the include dependencies so that if they change
                // it will trigger a rebuild of this effect.
                foreach (var dep in shaderResult.Dependencies)
                {
                    context.AddDependency(dep);
                }
            }
            catch (InvalidContentException)
            {
                throw;
            }
            catch (Exception ex)
            {
                // TODO: Extract good line numbers from mgfx parser!
                throw new InvalidContentException(ex.Message, input.Identity, ex);
            }

            // Create the effect object.
            EffectObject effect = null;
            var          shaderErrorsAndWarnings = string.Empty;
            try
            {
                effect = EffectObject.CompileEffect(shaderResult, out shaderErrorsAndWarnings);

                // If there were any additional output files we register
                // them so that the cleanup process can manage them.
                foreach (var outfile in shaderResult.AdditionalOutputFiles)
                {
                    context.AddOutputFile(outfile);
                }
            }
            catch (ShaderCompilerException)
            {
                // This will log any warnings and errors and throw.
                ProcessErrorsAndWarnings(true, shaderErrorsAndWarnings, input, context);
            }

            // Process any warning messages that the shader compiler might have produced.
            ProcessErrorsAndWarnings(false, shaderErrorsAndWarnings, input, context);

            // Write out the effect to a runtime format.
            CompiledEffectContent result;
            try
            {
                using (var stream = new MemoryStream())
                {
                    using (var writer = new BinaryWriter(stream))
                        effect.Write(writer, options);

                    result = new CompiledEffectContent(stream.GetBuffer());
                }
            }
            catch (Exception ex)
            {
                throw new InvalidContentException("Failed to serialize the effect!", input.Identity, ex);
            }

            return(result);
#else
            throw new NotImplementedException();
#endif
        }
Exemple #9
0
        public override SongContent Process(AudioContent input, ContentProcessorContext context)
        {
            var outputFilename      = Path.ChangeExtension(context.OutputFilename, "ogg");
            var songContentFilename =
                PathHelper.GetRelativePath(Path.GetDirectoryName(context.OutputFilename) + Path.DirectorySeparatorChar,
                                           outputFilename);

            context.AddOutputFile(outputFilename);

            // Use the ogg-file as-is
            if (Path.GetExtension(input.FileName) == "ogg")
            {
                File.Copy(input.FileName, outputFilename);

                return((SongContent)_songContentConstructor.Invoke(new object[]
                {
                    songContentFilename,
                    input.Duration
                }));
            }

            // Prepare some useful paths and checks
            var hashFile      = Path.ChangeExtension(input.FileName, "hash");
            var oggFile       = Path.ChangeExtension(input.FileName, "ogg");
            var oggFileExists = File.Exists(oggFile);

            // Compare a previous hash, if there is one.
            var    currentHash  = CalculateSHA1(input.FileName);
            string previousHash = null;

            if (File.Exists(hashFile) && oggFileExists)
            {
                previousHash = File.ReadAllText(hashFile);
            }
            else
            {
                File.WriteAllText(hashFile, currentHash);
            }

            // Determine if we can re-use a previously generated ogg-file
            if (oggFileExists && previousHash == currentHash)
            {
                File.Copy(oggFile, outputFilename);
            }
            else
            {
                var conversionQuality = AudioProfile.ForPlatform(TargetPlatform.DesktopGL)
                                        .ConvertStreamingAudio(TargetPlatform.DesktopGL, Quality, input, ref outputFilename);
                if (Quality != conversionQuality)
                {
                    context.Logger.LogMessage("Failed to convert using \"{0}\" quality, used \"{1}\" quality", Quality,
                                              conversionQuality);
                }

                if (oggFileExists)
                {
                    File.Delete(oggFile);
                }

                File.Copy(outputFilename, oggFile);
            }

            return((SongContent)_songContentConstructor.Invoke(new object[]
            {
                songContentFilename,
                input.Duration
            }));
        }
    private void ProcessCursors(ThemeContent theme, ContentProcessorContext context)
    {
      theme.Cursors = new NamedObjectCollection<ThemeCursorContent>();

      // Hardware cursors are only supported on Windows.
      if (context.TargetPlatform != TargetPlatform.Windows)
        return;

      var document = theme.Description;
      if (document.Root == null)
      {
        string message = string.Format("Root element \"<Theme>\" is missing in XML.");
        throw new InvalidContentException(message, theme.Identity);
      }

      var cursorsElement = document.Root.Element("Cursors");
      if (cursorsElement == null)
        return;

      foreach (var cursorElement in cursorsElement.Elements("Cursor"))
      {
        string name = GetMandatoryAttribute(cursorElement, "Name", theme.Identity);
        bool isDefault = (bool?)cursorElement.Attribute("IsDefault") ?? false;
        string filename = GetMandatoryAttribute(cursorElement, "File", theme.Identity);

        // Find cursor file.
        string cursorSourcePath = FindFile(theme, filename);
        string cursorSourceDirectory = Path.GetDirectoryName(cursorSourcePath) + Path.DirectorySeparatorChar;
        context.AddDependency(cursorSourcePath);

        // Get output path.
        // If cursor is in or under the content directory, then we keep the relative directory
        // structure. If cursor is in a parent directory, then we copy the cursor
        // directly into the theme directory.
        string cursorOutputPath;
        if (cursorSourceDirectory.StartsWith(_sourceRootDirectory))
        {
          // Cursor file is in/under the content root directory.
          string relativeCursorSourcePath =
            _themeSourceDirectoryUri.MakeRelativeUri(new Uri(cursorSourcePath)).ToString();
          relativeCursorSourcePath = Uri.UnescapeDataString(relativeCursorSourcePath);
          cursorOutputPath = Path.GetFullPath(Path.Combine(_themeOutputDirectory, relativeCursorSourcePath));
        }
        else
        {
          // Cursor file is not in/under the content root directory.
          string cursorFilename = Path.GetFileName(cursorSourcePath) ?? string.Empty;
          cursorOutputPath = Path.GetFullPath(Path.Combine(_themeOutputDirectory, cursorFilename));
        }
        string cursorOutputDirectory = Path.GetDirectoryName(cursorOutputPath) + Path.DirectorySeparatorChar;

        // Create output directory if it does not exist.
        if (!Directory.Exists(cursorOutputDirectory))
          Directory.CreateDirectory(cursorOutputDirectory);

        // Copy cursor file to output directory.
        File.Copy(cursorSourcePath, cursorOutputPath, true);
        context.AddOutputFile(cursorOutputPath);

        // Get filename relative to the theme directory.
        filename =
          _themeOutputDirectoryUri.MakeRelativeUri(new Uri(cursorOutputPath)).OriginalString;
        filename = Uri.UnescapeDataString(filename);

        var cursor = new ThemeCursorContent
        {
          Name = name,
          IsDefault = isDefault,
          FileName = filename,
        };

        theme.Cursors.Add(cursor);
      }
    }
Exemple #11
0
        /// <summary>
        /// Processes the string representation of the specified effect into a platform-specific binary format using the specified context.
        /// </summary>
        /// <param name="input">The effect string to be processed.</param>
        /// <param name="context">Context for the specified processor.</param>
        /// <returns>A platform-specific compiled binary effect.</returns>
        /// <remarks>If you get an error during processing, compilation stops immediately. The effect processor displays an error message. Once you fix the current error, it is possible you may get more errors on subsequent compilation attempts.</remarks>
        public override CompiledEffectContent Process(EffectContent input, ContentProcessorContext context)
        {
#if WINDOWS
            var options = new Options();
            options.SourceFile = input.Identity.SourceFilename;

            switch (context.TargetPlatform)
            {
            case TargetPlatform.Windows:
            case TargetPlatform.WindowsPhone8:
            case TargetPlatform.WindowsStoreApp:
                options.Profile = ShaderProfile.DirectX_11;
                break;

            case TargetPlatform.iOS:
            case TargetPlatform.Android:
            case TargetPlatform.Linux:
            case TargetPlatform.MacOSX:
            case TargetPlatform.Ouya:
            case TargetPlatform.RaspberryPi:
                options.Profile = ShaderProfile.OpenGL;
                break;

            default:
                throw new InvalidContentException(string.Format("{0} effects are not supported.", context.TargetPlatform), input.Identity);
            }

            options.Debug      = DebugMode == EffectProcessorDebugMode.Debug;
            options.OutputFile = context.OutputFilename;

            // Parse the MGFX file expanding includes, macros, and returning the techniques.
            ShaderInfo shaderInfo;
            try
            {
                shaderInfo = ShaderInfo.FromFile(options.SourceFile, options);

                // Add the include dependencies so that if they change
                // it will trigger a rebuild of this effect.
                foreach (var dep in shaderInfo.Dependencies)
                {
                    context.AddDependency(dep);
                }
            }
            catch (Exception ex)
            {
                // TODO: Extract good line numbers from mgfx parser!
                throw new InvalidContentException(ex.Message, input.Identity, ex);
            }

            // Create the effect object.
            EffectObject effect = null;
            try
            {
                effect = EffectObject.FromShaderInfo(shaderInfo);

                // If there were any additional output files we register
                // them so that the cleanup process can manage them.
                foreach (var outfile in shaderInfo.AdditionalOutputFiles)
                {
                    context.AddOutputFile(outfile);
                }
            }
            catch (Exception ex)
            {
                throw ProcessErrorsAndWarnings(ex.Message, input, context);
            }

            // Write out the effect to a runtime format.
            CompiledEffectContent result;
            try
            {
                using (var stream = new MemoryStream())
                {
                    using (var writer = new BinaryWriter(stream))
                        effect.Write(writer, options);

                    result = new CompiledEffectContent(stream.GetBuffer());
                }
            }
            catch (Exception ex)
            {
                throw new InvalidContentException("Failed to serialize the effect!", input.Identity, ex);
            }

            return(result);
#else
            throw new NotImplementedException();
#endif
        }
        /// <summary>
        /// Loads source sprites referenced in declaration input and packs sprites into a sprite sheet.
        /// </summary>
        /// <param name="declaration">Sprite sheet delcaration input.</param>
        /// <param name="context">Context of the process routine.</param>
        /// <returns>Sprite sheet content.</returns>
        public override SpriteSheetContent Process(SpriteSheetDeclaration declaration, ContentProcessorContext context)
        {
            if (declaration == null)
            {
                throw new ArgumentNullException(nameof(declaration));
            }

            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            // Collect all texture file paths.
            //
            var texturePaths = new HashSet <string>();

            foreach (string pathPattern in declaration.PathPatterns)
            {
                foreach (string filePath in Glob.Files(Directory.GetCurrentDirectory(), pathPattern))
                {
                    texturePaths.Add(filePath);
                }
            }

            // Limit the packed texture based on the target graphics profile.
            //
            int maximumDimension = context.TargetProfile == GraphicsProfile.HiDef ? 4096 : 2048;

            PackedTexture packedTexture =
                SpritePacker.Pack(
                    configuration: new PackConfiguration(maximumDimension, maximumDimension, this.IsPowerOfTwo, this.IsSquare, this.Padding),
                    spritePaths: texturePaths.ToArray());

            // Ensure our output directory exists.
            //
            if (!Directory.Exists(context.OutputDirectory))
            {
                Directory.CreateDirectory(context.OutputDirectory);
            }

            // Write the packed texture to the output location.
            //
            string outputPath = Path.Combine(context.OutputDirectory, $"{declaration.Name}.png");

            using (var stream = new FileStream(outputPath, FileMode.Create))
            {
                packedTexture.Texture.Save(stream, ImageFormat.Png);
            }

            context.AddOutputFile(outputPath);

            // Finalize the content to serialize from this processor.
            //
            return(new SpriteSheetContent
            {
                Name = declaration.Name,
                SpriteNamesToIndexMapping = packedTexture.SpriteNamesToIndexMapping,
                SpriteRectangles = packedTexture.SpriteRectangles,
                Texture = this.BuildTexture($"{declaration.Name}Texture", outputPath, context),
            });
        }
Exemple #13
0
        public override SongContent Process(AudioContent input, ContentProcessorContext context)
        {
            // Fallback if we aren't buiding for iOS.
            var platform = ContentHelper.GetMonoGamePlatform();

            if (platform != MonoGamePlatform.iOS && platform != MonoGamePlatform.Linux)
            {
                return(base.Process(input, context));
            }

            //TODO: If quality isn't best and it's a .wma, don't compress to MP3. Leave it as a .wav instead
            string outputType     = (platform == MonoGamePlatform.iOS) ? "mp3" : "wav";
            string outputFilename = Path.ChangeExtension(context.OutputFilename, outputType);
            string directoryName  = Path.GetDirectoryName(outputFilename);

            if (!Directory.Exists(directoryName))
            {
                Directory.CreateDirectory(directoryName);
            }

            var inputFilename = Path.GetFullPath(input.FileName);

            // XNA's songprocessor converts the bitrate on the input file based
            // on it's conversion quality.
            //http://blogs.msdn.com/b/etayrien/archive/2008/09/22/audio-input-and-output-formats.aspx
            int desiredOutputBitRate = 0;

            switch (this.Quality)
            {
            case ConversionQuality.Low:
                desiredOutputBitRate = 96000;
                break;

            case ConversionQuality.Medium:
                desiredOutputBitRate = 128000;
                break;

            case ConversionQuality.Best:
                desiredOutputBitRate = 192000;
                break;
            }

            AudioFileType target = (platform == MonoGamePlatform.iOS) ? AudioFileType.Mp3 : AudioFileType.Wav;
            // Create a new file if we need to.
            FileStream outputStream = input.FileType != target ? new FileStream(outputFilename, FileMode.Create) : null;

            if (input.FileType != target)
            {
                AudioConverter.ConvertFile(inputFilename, outputStream, target, desiredOutputBitRate,
                                           input.Format.BitsPerSample, input.Format.ChannelCount);
            }
            else
            {
                File.Copy(inputFilename, outputFilename, true);
            }

            if (outputStream != null)
            {
                outputStream.Close();
            }

            context.AddOutputFile(outputFilename);

            // SoundEffectContent is a sealed class, construct it using reflection
            var             type = typeof(SongContent);
            ConstructorInfo c    = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance,
                                                       null, new Type[] { typeof(string), typeof(int) }, null);

            var outputSongContent = (SongContent)c.Invoke(new Object[] { Path.GetFileName(outputFilename), (int)input.Duration.TotalMilliseconds });

            return(outputSongContent);
        }
        public override object Process(XapProjectFile input, ContentProcessorContext context)
        {
            var location = Path.GetFullPath(GetType().Assembly.Location);

            if (string.IsNullOrEmpty(WineInstall))
            {
                WineInstall = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), ".wine");
            }
            // execute the XActBld3.exe.
            var isWindows    = Environment.OSVersion.Platform != PlatformID.Unix;
            var programFiles = isWindows ? Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) :
                               Path.Combine(WineInstall, "drive_c", "Program Files (x86)");
            var xnaPath      = Path.Combine(programFiles, "Microsoft XNA", "XNA Game Studio", "v4.0");
            var XactBld3Tool = Path.Combine("Tools", "XactBld3.exe");
            var toolPath     = Path.Combine(xnaPath, XactBld3Tool);

            if (!isWindows)
            {
                // extract wine and install XNA
                if (!File.Exists(toolPath))
                {
                    throw new InvalidProgramException($"Could not locate {XactBld3Tool}. You need to install Wine and XNA Tooling. See https://github.com/infinitespace-studios/InfinitespaceStudios.Pipeline/wiki for more details.");
                }
            }

            if (isWindows && !File.Exists(toolPath))
            {
                toolPath = Path.Combine(Environment.GetEnvironmentVariable("XNAGSv4"), XactBld3Tool);
                if (!File.Exists(toolPath))
                {
                    toolPath = Path.Combine(location, XactBld3Tool);
                    if (!File.Exists(toolPath))
                    {
                        throw new InvalidProgramException($"Could not locate {XactBld3Tool}");
                    }
                }
            }

            var outputPath = Path.GetDirectoryName(context.OutputFilename);

            Directory.CreateDirectory(outputPath);
            var inputPath = input.FileName;

            if (!isWindows)
            {
                outputPath = "Z:" + outputPath.Replace("/", "\\");
                if (outputPath.EndsWith("\\"))
                {
                    outputPath = outputPath.Substring(0, outputPath.Length - 1);
                }
                inputPath = "Z:" + inputPath.Replace("/", "\\");
            }

            var stdout_completed = new ManualResetEvent(false);
            var stderr_completed = new ManualResetEvent(false);
            var psi = new System.Diagnostics.ProcessStartInfo()
            {
                FileName               = isWindows ? toolPath : WineExe,
                Arguments              = (!isWindows ? $"\"{toolPath}\" " : String.Empty) + $"/WINDOWS \"{inputPath}\" \"{outputPath}\"",
                UseShellExecute        = false,
                RedirectStandardOutput = true,
                RedirectStandardError  = true,
                CreateNoWindow         = true,
                WindowStyle            = System.Diagnostics.ProcessWindowStyle.Hidden,
            };

            context.Logger.LogImportantMessage($"Running: {psi.FileName} {psi.Arguments}");

            using (var proc = new System.Diagnostics.Process())
            {
                proc.OutputDataReceived += (o, e) =>
                {
                    if (e.Data == null)
                    {
                        stdout_completed.Set();
                        return;
                    }
                    //context.Logger.LogImportantMessage($"{e.Data}");
                };
                proc.ErrorDataReceived += (o, e) =>
                {
                    if (e.Data == null)
                    {
                        stderr_completed.Set();
                        return;
                    }
                    //context.Logger.LogImportantMessage($"{e.Data}");
                };
                proc.StartInfo = psi;
                proc.Start();
                proc.BeginOutputReadLine();
                proc.BeginErrorReadLine();
                proc.WaitForExit();
                if (psi.RedirectStandardError)
                {
                    stderr_completed.WaitOne(TimeSpan.FromSeconds(30));
                }
                if (psi.RedirectStandardOutput)
                {
                    stdout_completed.WaitOne(TimeSpan.FromSeconds(30));
                }
                if (proc.ExitCode != 0)
                {
                    throw new InvalidContentException();
                }
                foreach (var file in Directory.GetFiles(Path.GetDirectoryName(context.OutputFilename), "*.xgs", SearchOption.TopDirectoryOnly))
                {
                    context.AddOutputFile(file);
                }
                foreach (var file in Directory.GetFiles(Path.GetDirectoryName(context.OutputFilename), "*.xsb", SearchOption.TopDirectoryOnly))
                {
                    context.AddOutputFile(file);
                }
                foreach (var file in Directory.GetFiles(Path.GetDirectoryName(context.OutputFilename), "*.xwb", SearchOption.TopDirectoryOnly))
                {
                    context.AddOutputFile(file);
                }
            }
            return(null);
        }
Exemple #15
0
        internal static void WriteTexture(object spriteFontContent, bool alphaOnly, ContentProcessorContext context, string filename)
        {
            dynamic sfc = ExposedObject.From(spriteFontContent);

            // Get a copy of the texture in Color format
            Texture2DContent originalTexture = sfc.Texture;
            BitmapContent originalBitmap = originalTexture.Mipmaps[0];
            PixelBitmapContent<Color> colorBitmap = new PixelBitmapContent<Color>(
                    originalBitmap.Width, originalBitmap.Height);
            BitmapContent.Copy(originalBitmap, colorBitmap);

            Bitmap bitmap = new Bitmap(colorBitmap.Width, colorBitmap.Height, PixelFormat.Format32bppArgb);
            for(int x = 0; x < colorBitmap.Width; x++) for(int y = 0; y < colorBitmap.Height; y++)
            {
                Color c = colorBitmap.GetPixel(x, y);
                if(alphaOnly)
                {
                    c.R = 255; c.G = 255; c.B = 255; // Undo premultiplication
                }
                bitmap.SetPixel(x, y, System.Drawing.Color.FromArgb(c.A, c.R, c.G, c.B));
            }
            bitmap.Save(filename, ImageFormat.Png);
            bitmap.Dispose();

            context.AddOutputFile(filename);
        }