//--------------------------------------------------------------
        #region Methods
        //--------------------------------------------------------------

        /// <summary>
        /// Builds the specified source file.
        /// </summary>
        /// <param name="sourceFile">
        /// The absolute path of the source file. The file format must be a supported 3D model file
        /// format.
        /// </param>
        /// <param name="importerName">The name of the content importer.</param>
        /// <param name="processorName">The name of the content processor.</param>
        /// <param name="processorParameters">The processor parameters.</param>
        /// <param name="errorMessage">The error message in case of failure.</param>
        /// <returns>
        /// <see langword="true"/> if the asset was successfully processed. <see langword="false"/>
        /// if an error has occurred, in which case the output window should contain useful
        /// information.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="sourceFile"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="sourceFile"/> is empty or is not an absolute (rooted) path.
        /// </exception>
        public bool Build(string sourceFile, string importerName, string processorName, OpaqueDataDictionary processorParameters, out string errorMessage)
        {
            if (sourceFile == null)
            {
                throw new ArgumentNullException(nameof(sourceFile));
            }
            if (sourceFile.Length == 0)
            {
                throw new ArgumentException("Source file path must not be empty.", nameof(sourceFile));
            }
            if (!Path.IsPathRooted(sourceFile))
            {
                throw new ArgumentException("Source file path must be an absolute (rooted) path.", nameof(sourceFile));
            }

            string executableFolder = ExecutableFolder;

            string outputFolder = OutputFolder;

            if (!Path.IsPathRooted(outputFolder))
            {
                outputFolder = Path.GetFullPath(Path.Combine(executableFolder, outputFolder));
            }

            string intermediateFolder = IntermediateFolder;

            if (!Path.IsPathRooted(intermediateFolder))
            {
                intermediateFolder = PathHelper.Normalize(Path.GetFullPath(Path.Combine(executableFolder, intermediateFolder)));
            }

            // No assets should lie outside the working folder because then some XNB are built
            // into parent folders.
            string workingFolder = Path.GetPathRoot(sourceFile);

            Directory.SetCurrentDirectory(workingFolder);

            var manager = new PipelineManager(workingFolder, outputFolder, intermediateFolder)
            {
                Logger            = _logger,
                RethrowExceptions = false,
                CompressContent   = false,
                Profile           = GraphicsProfile.HiDef,
                Platform          = TargetPlatform.Windows
            };

            // Add references to content pipeline assemblies.
            // All assemblies are expected to lie in the executable folder. Therefore, this project
            // references the content pipeline DLLs, so that they are automatically copied to the
            // executable folder.
            // TODO: Make a public property to allow user to set references.
            manager.AddAssembly(Path.GetFullPath(Path.Combine(ExecutableFolder, "DigitalRune.Animation.Content.Pipeline.dll")));
            manager.AddAssembly(Path.GetFullPath(Path.Combine(ExecutableFolder, "DigitalRune.Game.UI.Content.Pipeline.dll")));
            manager.AddAssembly(Path.GetFullPath(Path.Combine(ExecutableFolder, "DigitalRune.Geometry.Content.Pipeline.dll")));
            manager.AddAssembly(Path.GetFullPath(Path.Combine(ExecutableFolder, "DigitalRune.Graphics.Content.Pipeline.dll")));
            manager.AddAssembly(Path.GetFullPath(Path.Combine(ExecutableFolder, "DigitalRune.Mathematics.Content.Pipeline.dll")));

            // Add this assembly because it also contains model processors.
            manager.AddAssembly(Path.GetFullPath(Path.Combine(ExecutableFolder, "DigitalRune.Editor.Game.dll")));

            _logger.LogMessage("----- Begin MonoGame content pipeline -----");

            // Remove any previous build content to force a full rebuild.
            manager.CleanContent(sourceFile);

            try
            {
                manager.BuildContent(sourceFile, null, importerName, processorName, processorParameters);
                errorMessage = null;
                return(true);
            }
            catch (Exception exception)
            {
                _logger.LogMessage("Exception in MonoGame content pipeline:");
                _logger.LogWarning(null, null, exception.Message);
                _logger.LogMessage(exception.StackTrace);
                if (exception.Message.StartsWith("Value cannot be null.", StringComparison.OrdinalIgnoreCase))
                {
                    _logger.LogWarning(null, null, "This can happen if the FBX references a texture but the filename is null. Check the referenced texture file paths in a 3D modeling tool.");
                }

                errorMessage = exception.Message;
                return(false);
            }
            finally
            {
                _logger.LogMessage("----- End MonoGame content pipeline -----");
            }
        }