예제 #1
0
        public override ExternalReference <TOutput> BuildAsset <TInput, TOutput>(ExternalReference <TInput> sourceAsset,
                                                                                 string processorName,
                                                                                 OpaqueDataDictionary processorParameters,
                                                                                 string importerName,
                                                                                 string assetName)
        {
            if (string.IsNullOrEmpty(assetName))
            {
                var contentPath = PathHelper.GetRelativePath(_manager.ProjectDirectory, sourceAsset.Filename);
                var filename    = Path.GetFileNameWithoutExtension(contentPath);
                var path        = Path.GetDirectoryName(contentPath);

                // TODO: Is this only does for textures or
                // for all sub-assets like this?
                //
                // TODO: Replace the _0 with a hex 32bit hash of
                // the processor+parameters.  This ensures no collisions
                // when two models process textures with different settings.
                //
                assetName = Path.Combine(path, filename) + "_0";
            }

            // Build the content.
            var buildEvent = _manager.BuildContent(sourceAsset.Filename, assetName, importerName, processorName, processorParameters);

            // Record that we built this dependent asset.
            _pipelineEvent.BuildAsset.AddUnique(buildEvent.DestFile);

            return(new ExternalReference <TOutput>(buildEvent.DestFile));
        }
        public override ExternalReference <TOutput> BuildAsset <TInput, TOutput>(ExternalReference <TInput> sourceAsset,
                                                                                 string processorName,
                                                                                 OpaqueDataDictionary processorParameters,
                                                                                 string importerName,
                                                                                 string assetName)
        {
            if (string.IsNullOrEmpty(assetName))
            {
                assetName = _manager.GetAssetName(sourceAsset.Filename, importerName, processorName, processorParameters);
            }

            // Build the content.
            var buildEvent = _manager.BuildContent(sourceAsset.Filename, assetName, importerName, processorName, processorParameters);

            // Record that we built this dependent asset.
            _pipelineEvent.BuildAsset.AddUnique(buildEvent.DestFile);

            return(new ExternalReference <TOutput>(buildEvent.DestFile));
        }
예제 #3
0
        //--------------------------------------------------------------
        /// <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 -----");
            }
        }
예제 #4
0
        public void Build(out int successCount, out int errorCount)
        {
            var projectDirectory = Directory.GetCurrentDirectory();
            var outputPath = Path.GetFullPath(Path.Combine(projectDirectory, OutputDir));
            var intermediatePath = Path.GetFullPath(Path.Combine(projectDirectory, IntermediateDir));
            _manager = new PipelineManager(projectDirectory, outputPath, intermediatePath);

            // Feed all the assembly references to the pipeline manager
            // so it can resolve importers, processors, writers, and types.
            foreach (var r in References)
                _manager.AddAssembly(r);

            // Load the previously serialized list of built content.
            var contentFile = Path.Combine(intermediatePath, PipelineBuildEvent.Extension);
            var previousContent = SourceFileCollection.Read(contentFile);

            // If the target changed in any way then we need to force
            // a fuull rebuild even under incremental builds.
            var targetChanged = previousContent.Config != Config ||
                                previousContent.Platform != Platform ||
                                previousContent.Profile != Profile;

            // First clean previously built content.
            foreach (var sourceFile in previousContent.SourceFiles)
            {
                var inContent = _content.Any(e => string.Equals(e.SourceFile, sourceFile, StringComparison.InvariantCultureIgnoreCase));
                var cleanOldContent = !inContent && !Incremental;
                var cleanRebuiltContent = inContent && (Rebuild || Clean);
                if (cleanRebuiltContent || cleanOldContent || targetChanged)
                    _manager.CleanContent(sourceFile);                
            }

            var newContent = new SourceFileCollection
            {
                Profile = _manager.Profile = Profile,
                Platform = _manager.Platform = Platform,
                Config = _manager.Config = Config
            };
            errorCount = 0;
            successCount = 0;

            foreach (var c in _content)
            {
                try
                {
                    _manager.BuildContent(c.SourceFile,
                                          null,
                                          c.Importer,
                                          c.Processor,
                                          c.ProcessorParams);

                    newContent.SourceFiles.Add(c.SourceFile);

                    ++successCount;
                }
                catch (PipelineException ex)
                {
                    Console.Error.WriteLine("{0}: error: {1}", c.SourceFile, ex.Message);
                    ++errorCount;
                }
            }

            // If this is an incremental build we merge the list
            // of previous content with the new list.
            if (Incremental && !targetChanged)
                newContent.Merge(previousContent);

            // Delete the old file and write the new content 
            // list if we have any to serialize.
            if (File.Exists(contentFile))
                File.Delete(contentFile);
            if (newContent.SourceFiles.Count > 0)
                newContent.Write(contentFile);
        }
예제 #5
0
        public void Build(out int successCount, out int errorCount)
        {
            var projectDirectory = PathHelper.Normalize(Directory.GetCurrentDirectory());

            var outputPath = ReplaceSymbols (OutputDir);
            if (!Path.IsPathRooted(outputPath))
                outputPath = PathHelper.Normalize(Path.GetFullPath(Path.Combine(projectDirectory, outputPath)));

            var intermediatePath = ReplaceSymbols (IntermediateDir);
            if (!Path.IsPathRooted(intermediatePath))
                intermediatePath = PathHelper.Normalize(Path.GetFullPath(Path.Combine(projectDirectory, intermediatePath)));
            
            _manager = new PipelineManager(projectDirectory, outputPath, intermediatePath);
            _manager.Logger = new ConsoleLogger();
            _manager.CompressContent = CompressContent;

            // If the intent is to debug build, break at the original location
            // of any exception, eg, within the actual importer/processor.
            if (LaunchDebugger)
                _manager.RethrowExceptions = false;

            // Feed all the assembly references to the pipeline manager
            // so it can resolve importers, processors, writers, and types.
            foreach (var r in References)
            {
                var assembly = r;
                if (!Path.IsPathRooted(assembly))
                    assembly = Path.GetFullPath(Path.Combine(projectDirectory, assembly));
                _manager.AddAssembly(assembly);
            }

            // Load the previously serialized list of built content.
            var contentFile = Path.Combine(intermediatePath, PipelineBuildEvent.Extension);
            var previousContent = SourceFileCollection.Read(contentFile);

            // If the target changed in any way then we need to force
            // a fuull rebuild even under incremental builds.
            var targetChanged = previousContent.Config != Config ||
                                previousContent.Platform != Platform ||
                                previousContent.Profile != Profile;

            // First clean previously built content.
            foreach (var sourceFile in previousContent.SourceFiles)
            {
                var inContent = _content.Any(e => string.Equals(e.SourceFile, sourceFile, StringComparison.InvariantCultureIgnoreCase));
                var cleanOldContent = !inContent && !Incremental;
                var cleanRebuiltContent = inContent && (Rebuild || Clean);
                if (cleanRebuiltContent || cleanOldContent || targetChanged)
                    _manager.CleanContent(sourceFile);                
            }

            var newContent = new SourceFileCollection
            {
                Profile = _manager.Profile = Profile,
                Platform = _manager.Platform = Platform,
                Config = _manager.Config = Config
            };
            errorCount = 0;
            successCount = 0;

            // Before building the content, register all files to be built. (Necessary to
            // correctly resolve external references.)
            foreach (var c in _content)
            {
                try
                {
                    _manager.RegisterContent(c.SourceFile, null, c.Importer, c.Processor, c.ProcessorParams);
                }
                catch
                {
                    // Ignore exception. Exception will be handled below.
                }
            }

            foreach (var c in _content)
            {
                try
                {
                    _manager.BuildContent(c.SourceFile,
                                          null,
                                          c.Importer,
                                          c.Processor,
                                          c.ProcessorParams);

                    newContent.SourceFiles.Add(c.SourceFile);

                    ++successCount;
                }
                catch (InvalidContentException ex)
                {
                    var message = string.Empty;
                    if (ex.ContentIdentity != null && !string.IsNullOrEmpty(ex.ContentIdentity.SourceFilename))
                    {
                        message = ex.ContentIdentity.SourceFilename;
                        if (!string.IsNullOrEmpty(ex.ContentIdentity.FragmentIdentifier))
                            message += "(" + ex.ContentIdentity.FragmentIdentifier + ")";
                        message += ": ";
                    }
                    message += ex.Message;
                    Console.WriteLine(message);
                    ++errorCount;
                }
                catch (PipelineException ex)
                {
                    Console.Error.WriteLine("{0}: error: {1}", c.SourceFile, ex.Message);
                    if (ex.InnerException != null)
                        Console.Error.WriteLine(ex.InnerException.ToString());
                    ++errorCount;
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine("{0}: error: {1}", c.SourceFile, ex.Message);
                    if (ex.InnerException != null)
                        Console.Error.WriteLine(ex.InnerException.ToString());
                    ++errorCount;
                }
            }

            // If this is an incremental build we merge the list
            // of previous content with the new list.
            if (Incremental && !targetChanged)
                newContent.Merge(previousContent);

            // Delete the old file and write the new content 
            // list if we have any to serialize.
            FileHelper.DeleteIfExists(contentFile);
            if (newContent.SourceFiles.Count > 0)
                newContent.Write(contentFile);

            // Process copy items (files that bypass the content pipeline)
            foreach (var c in _copyItems)
            {
                try
                {
                    // Figure out an asset name relative to the project directory,
                    // retaining the file extension.
                    // Note that replacing a sub-path like this requires consistent
                    // directory separator characters.
                    var relativeName = c.Replace(projectDirectory, string.Empty)
                                            .TrimStart(Path.DirectorySeparatorChar)
                                            .TrimStart(Path.AltDirectorySeparatorChar);
                    var dest = Path.Combine(outputPath, relativeName);

                    // Only copy if the source file is newer than the destination.
                    // We may want to provide an option for overriding this, but for
                    // nearly all cases this is the desired behavior.
                    if (File.Exists(dest))
                    {
                        var srcTime = File.GetLastWriteTimeUtc(c);
                        var dstTime = File.GetLastWriteTimeUtc(dest);
                        if (srcTime <= dstTime)
                        {
                            Console.WriteLine("Skipping {0}", c);
                            continue;
                        }
                    }

                    // Create the destination directory if it doesn't already exist.
                    var destPath = Path.GetDirectoryName(dest);
                    if (!Directory.Exists(destPath))
                        Directory.CreateDirectory(destPath);

                    File.Copy(c, dest, true);

                    // Destination file should not be read-only even if original was.
                    var fileAttr = File.GetAttributes(dest);
                    fileAttr = fileAttr & (~FileAttributes.ReadOnly);
                    File.SetAttributes(dest, fileAttr);

                    ++successCount;
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine("{0}: error: {1}", c, ex.Message);
                    if (ex.InnerException != null)
                        Console.Error.WriteLine(ex.InnerException.ToString());

                    ++errorCount;
                }
            }
        }
		protected override BuildResult Compile (MonoDevelop.Core.IProgressMonitor monitor, SolutionEntityItem item, BuildData buildData)
		{
#if DEBUG			
			monitor.Log.WriteLine("MonoGame Extension Compile Called");	
#endif			
			try
			{	
				var cfg = buildData.Configuration as MonoGameContentProjectConfiguration;
				var proj = item as MonoGameContentProject;
				if (proj == null || cfg == null)
				{
					monitor.Log.WriteLine("Compiling for Unknown MonoGame Project");
					return base.Compile(monitor, item, buildData);
				}
				monitor.Log.WriteLine("Detected {0} MonoGame Platform", cfg.MonoGamePlatform);
				var result = new BuildResult();
				var manager = new PipelineManager(proj.BaseDirectory.FullPath,
				                                  Path.Combine(buildData.Configuration.OutputDirectory, cfg.MonoGamePlatform),
				                                  buildData.Configuration.IntermediateOutputDirectory);
			
				manager.Logger = new MonitorBuilder(monitor, result);
				manager.Platform =  (TargetPlatform)Enum.Parse(typeof(TargetPlatform), cfg.MonoGamePlatform);
				try {
				foreach(var pr in proj.ParentSolution.GetAllProjects()) {
					if (pr is DotNetAssemblyProject) {
						var dot = pr as DotNetAssemblyProject;
						foreach(var r in dot.References)
						{
							if (r.Package.Name == "monogame-contentpipeline" ) {

								var output = dot.GetOutputFileName(buildData.ConfigurationSelector).FullPath;
								monitor.Log.WriteLine("Adding {0} to Content Pipeline Assembly List", output);
								manager.AddAssembly(output);
								proj.Manager.AddAssembly(output);
								break;
							}
						}
					}
				}
				}
				catch(Exception ex) {
					result.AddWarning(string.Format("Problem processing Content Extensions {0}", ex.Message));
				}

				var dict = new Microsoft.Xna.Framework.Content.Pipeline.OpaqueDataDictionary();
				if (cfg != null) {
					if (cfg.XnaCompressContent.ToLower() == "true") {
						// tell the manager to compress the output
					}
				}
				foreach(var file in proj.Files)
				{
					if (file.BuildAction == "Compile") {
						try 
						{
							dict.Clear();
							foreach(object key in file.ExtendedProperties.Keys) {
								string k = key as string;
								if (k != null && k.StartsWith("ProcessorParameters_")) {
									if (!dict.ContainsKey(k.Replace("ProcessorParameters_", String.Empty))) {
										dict.Add(k.Replace("ProcessorParameters_", String.Empty), file.ExtendedProperties[k]);
									} else {
										dict[k.Replace("ProcessorParameters_", String.Empty)] = file.ExtendedProperties[k];
									}
								}
							}

							// check if the file has changed and rebuild if required.
							manager.BuildContent(file.FilePath.FullPath, 
					                     null, 
							             file.ExtendedProperties.Contains("Importer") ? (string)file.ExtendedProperties["Importer"] : null,
							             file.ExtendedProperties.Contains("Processor") ? (string)file.ExtendedProperties["Processor"] : null, 
							             dict);
						}
						catch(Exception ex)
						{
							monitor.Log.WriteLine(ex.ToString());
							result.AddError(ex.Message);
						}

					}
				}
				return result;
			}
			finally
			{
#if DEBUG				
				monitor.Log.WriteLine("MonoGame Extension Compile Ended");	
#endif				
			}
		}