Beispiel #1
0
        private void Reset()
        {
            StopAnimation();

            _monoGameContent?.Dispose();
            _monoGameContent = null;

            Debug.Assert(ModelNode == null || ModelNode.IsDisposed, "ModelNode should be disposed together with the ContentManager.");
            ModelNode = null;
            Model     = null;

            _tempDirectoryHelper?.Dispose();
            _tempDirectoryHelper = null;

            _assimpScene = null;

            if (_outlineService != null && _outlineService.Outline == Outline)
            {
                _outlineService.Outline = null;
            }

            if (_propertiesService != null && _propertiesService.PropertySource == _currentPropertySource)
            {
                _propertiesService.PropertySource = null;
            }

            CleanErrors();
        }
        private static async Task <Tuple <bool, List <Error> > > BuildMonoGameAsync(
            ServiceContainer services, string applicationName, TextDocument document, DelegateCommand <Error> goToLocationCommand)
        {
            string errorMessage = await Task.Run(() =>
            {
                using (var tempDirectoryHelper = new TempDirectoryHelper(applicationName, "ShaderDocument"))
                {
                    var contentBuilder = new GameContentBuilder(services)
                    {
                        IntermediateFolder = tempDirectoryHelper.TempDirectoryName + "\\obj",
                        OutputFolder       = tempDirectoryHelper.TempDirectoryName + "\\bin",
                    };

                    string message;
                    contentBuilder.Build(document.Uri.LocalPath, null, "EffectProcessor", null, out message);
                    return(message);
                }
            });

            List <Error> errors = null;

            if (!string.IsNullOrEmpty(errorMessage))
            {
                errorMessage = errorMessage.TrimEnd(' ', '\r', '\n');
                errors       = new List <Error>();

                // Use regular expression to parse the MSBuild output lines.
                // Example: "X:\DigitalRune\Samples\DigitalRune.Graphics.Content\DigitalRune\Billboard.fx(22,3) : Unexpected token 'x' found. Expected CloseBracket"
                var regex = new Regex(@"(?<file>[^\\/]*)\((?<line>\d+),(?<column>\d+)\) : (?<message>.*)");

                var match = regex.Match(errorMessage);
                if (match.Success)
                {
                    string lineText   = match.Groups["line"].Value;
                    string columnText = match.Groups["column"].Value;
                    string message    = match.Groups["message"].Value;
                    bool   isWarning  = match.Groups["warning"].Success;
                    var    error      = new Error(
                        isWarning ? ErrorType.Warning : ErrorType.Error,
                        $"[MonoGame] {message}",
                        match.Groups["file"].Value,
                        int.Parse(lineText),
                        int.Parse(columnText));

                    error.UserData            = document;
                    error.GoToLocationCommand = goToLocationCommand;
                    errors.Add(error);
                }
                else
                {
                    errors.Add(new Error(ErrorType.Error, errorMessage));
                }
            }

            return(Tuple.Create(string.IsNullOrEmpty(errorMessage), errors));
        }
Beispiel #3
0
        //--------------------------------------------------------------
        #region Methods
        //--------------------------------------------------------------

        private static async Task<Tuple<bool, List<Error>>> BuildMonoGameAsync(
            ServiceContainer services, string applicationName, TextDocument document, DelegateCommand<Error> goToLocationCommand)
        {
            string errorMessage = await Task.Run(() =>
            {
                using (var tempDirectoryHelper = new TempDirectoryHelper(applicationName, "ShaderDocument"))
                {
                    var contentBuilder = new GameContentBuilder(services)
                    {
                        IntermediateFolder = tempDirectoryHelper.TempDirectoryName + "\\obj",
                        OutputFolder = tempDirectoryHelper.TempDirectoryName + "\\bin",
                    };

                    string message;
                    contentBuilder.Build(document.Uri.LocalPath, null, "EffectProcessor", null, out message);
                    return message;
                }
            });

            List<Error> errors = null;
            if (!string.IsNullOrEmpty(errorMessage))
            {
                errorMessage = errorMessage.TrimEnd(' ', '\r', '\n');
                errors = new List<Error>();

                // Use regular expression to parse the MSBuild output lines.
                // Example: "X:\DigitalRune\Samples\DigitalRune.Graphics.Content\DigitalRune\Billboard.fx(22,3) : Unexpected token 'x' found. Expected CloseBracket"
                var regex = new Regex(@"(?<file>[^\\/]*)\((?<line>\d+),(?<column>\d+)\) : (?<message>.*)");

                var match = regex.Match(errorMessage);
                if (match.Success)
                {
                    string lineText = match.Groups["line"].Value;
                    string columnText = match.Groups["column"].Value;
                    string message = match.Groups["message"].Value;
                    bool isWarning = match.Groups["warning"].Success;
                    var error = new Error(
                        isWarning ? ErrorType.Warning : ErrorType.Error,
                        $"[MonoGame] {message}",
                        match.Groups["file"].Value,
                        int.Parse(lineText),
                        int.Parse(columnText));

                    error.UserData = document;
                    error.GoToLocationCommand = goToLocationCommand;
                    errors.Add(error);
                }
                else
                {
                    errors.Add(new Error(ErrorType.Error, errorMessage));
                }
            }

            return Tuple.Create(string.IsNullOrEmpty(errorMessage), errors);
        }
Beispiel #4
0
        private static Tuple <string, TempDirectoryHelper> BuildXnb(IServiceLocator services, string applicationName, string fileName, bool createModelNode, bool recreateModelAndMaterialFiles)
        {
            Debug.Assert(services != null);
            Debug.Assert(applicationName != null);
            Debug.Assert(applicationName.Length > 0);
            Debug.Assert(fileName != null);
            Debug.Assert(fileName.Length > 0);

            var tempDirectoryHelper = new TempDirectoryHelper(applicationName, "ModelDocument");

            try
            {
                var contentBuilder = new GameContentBuilder(services)
                {
                    IntermediateFolder = tempDirectoryHelper.TempDirectoryName + "\\obj",
                    OutputFolder       = tempDirectoryHelper.TempDirectoryName + "\\bin",
                };

                string processorName;
                var    processorParams = new OpaqueDataDictionary();
                if (createModelNode)
                {
                    processorName = "GameModelProcessor";
                    processorParams.Add("RecreateModelDescriptionFile", recreateModelAndMaterialFiles);
                    processorParams.Add("RecreateMaterialDefinitionFiles", recreateModelAndMaterialFiles);
                }
                else
                {
                    processorName = "ModelProcessor";
                }

                string errorMessage;
                bool   success = contentBuilder.Build(Path.GetFullPath(fileName), null, processorName, processorParams, out errorMessage);
                if (!success)
                {
                    throw new EditorException(Invariant($"Could not process 3d model: {fileName}.\n See output window for details."));
                }

                // Return output folder into which we built the XNB.
                var outputFolder = contentBuilder.OutputFolder;
                if (!Path.IsPathRooted(outputFolder))
                {
                    outputFolder = Path.GetFullPath(Path.Combine(contentBuilder.ExecutableFolder, contentBuilder.OutputFolder));
                }

                return(Tuple.Create(outputFolder, tempDirectoryHelper));
            }
            catch
            {
                tempDirectoryHelper.Dispose();
                throw;
            }
        }
Beispiel #5
0
        /// <summary>
        /// Creates a new content builder.
        /// </summary>
        /// <param name="editor">The editor.</param>
        public XnaContentBuilder(IEditorService editor)
        {
            if (editor == null)
            {
                throw new ArgumentNullException(nameof(editor));
            }

            _outputService = editor.Services.GetInstance <IOutputService>().ThrowIfMissing();

            //_buildLogger = new BuildLogger(outputService);
            _tempDirectoryHelper = new TempDirectoryHelper(editor.ApplicationName, "XnaContentBuilder");
            CreateBuildProject();
        }
Beispiel #6
0
        private static Tuple<string, TempDirectoryHelper> BuildXnb(IServiceLocator services, string applicationName, string fileName, bool createModelNode, bool recreateModelAndMaterialFiles)
        {
            Debug.Assert(services != null);
            Debug.Assert(applicationName != null);
            Debug.Assert(applicationName.Length > 0);
            Debug.Assert(fileName != null);
            Debug.Assert(fileName.Length > 0);

            var tempDirectoryHelper = new TempDirectoryHelper(applicationName, "ModelDocument");
            try
            {
                var contentBuilder = new GameContentBuilder(services)
                {
                    IntermediateFolder = tempDirectoryHelper.TempDirectoryName + "\\obj",
                    OutputFolder = tempDirectoryHelper.TempDirectoryName + "\\bin",
                };

                string processorName;
                var processorParams = new OpaqueDataDictionary();
                if (createModelNode)
                {
                    processorName = "GameModelProcessor";
                    processorParams.Add("RecreateModelDescriptionFile", recreateModelAndMaterialFiles);
                    processorParams.Add("RecreateMaterialDefinitionFiles", recreateModelAndMaterialFiles);
                }
                else
                {
                    processorName = "ModelProcessor";
                }

                string errorMessage;
                bool success = contentBuilder.Build(Path.GetFullPath(fileName), null, processorName, processorParams, out errorMessage);
                if (!success)
                    throw new EditorException(Invariant($"Could not process 3d model: {fileName}.\n See output window for details."));

                // Return output folder into which we built the XNB.
                var outputFolder = contentBuilder.OutputFolder;
                if (!Path.IsPathRooted(outputFolder))
                    outputFolder = Path.GetFullPath(Path.Combine(contentBuilder.ExecutableFolder, contentBuilder.OutputFolder));

                return Tuple.Create(outputFolder, tempDirectoryHelper);
            }
            catch
            {
                tempDirectoryHelper.Dispose();
                throw;
            }
        }
Beispiel #7
0
        private async Task LoadAsync(string fileName, bool recreateModelAndMaterialFiles)
        {
            Debug.Assert(_tempDirectoryHelper == null);
            Debug.Assert(_monoGameContent == null);
            Debug.Assert(ModelNode == null);
            Debug.Assert(Model == null);
            Debug.Assert(_assimpScene == null);
            Debug.Assert(State == ModelDocumentState.Loading);

            string extension = Path.GetExtension(fileName);
            IsXnb = string.Compare(extension, ".XNB", StringComparison.OrdinalIgnoreCase) == 0;

            // ----- Build XNB
            string directoryName;
            try
            {
                if (IsXnb)
                {
                    // Get the folder that contains the XNB.
                    directoryName = Path.GetDirectoryName(fileName);
                }
                else if (GameContentBuilder.IsSupportedModelFileExtension(extension))
                {
                    // Build the XNB and get the output folder.
                    var buildResult = await Task.Run(() => BuildXnb(Editor.Services, Editor.ApplicationName, fileName, UseDigitalRuneGraphics, recreateModelAndMaterialFiles));
                    directoryName = buildResult.Item1;
                    _tempDirectoryHelper = buildResult.Item2;
                }
                else
                {
                    throw new EditorException(Invariant($"Unsupported 3D model file format (file extension \"{extension}\")."));
                }
            }
            catch (Exception)
            {
                if (IsDisposed)
                {
                    // Document was closed during loading.
                    Reset();
                    return;
                }

                State = ModelDocumentState.Error;
                UpdateProperties();
                UpdateOutline();

                // The GameContentBuilder logs to the output service.
                _outputService.Show();

                throw;
            }

            if (IsDisposed)
            {
                // Document was closed during loading.
                Reset();
                return;
            }

            Debug.Assert(directoryName != null);

            // ----- Load XNB
            try
            {
                // Get asset name for use with ContentManager. XNBs and unprocessed models
                // use different folder hierarchies.
                string assetFileName;
                if (IsXnb)
                {
                    // Use absolute path.
                    assetFileName = fileName;
                }
                else
                {
                    // The asset is built relative to the root folder (e.g. "C:\"). The folder
                    // hierarchy (from root to asset) is rebuilt in the temporary output folder.

                    // Make file name relative to root.
                    assetFileName = DRPath.GetRelativePath(Path.GetPathRoot(fileName), fileName);

                    // Get absolute file name relative to temporary output folder.
                    assetFileName = Path.Combine(directoryName, assetFileName);

                    // Change extension. .fbx --> .xnb
                    assetFileName = Path.ChangeExtension(assetFileName, "xnb");
                }

                _monoGameContent = await Task.Run(() => _monoGameService.LoadXnb(directoryName, assetFileName, cacheResult: false));

                if (_monoGameContent.Asset is ModelNode)
                {
                    ModelNode = (ModelNode)_monoGameContent.Asset;
                    UseDigitalRuneGraphics = true;
                    HasAnimations = ModelNode.GetDescendants()
                                             .OfType<MeshNode>()
                                             .FirstOrDefault()?
                                             .Mesh?
                                             .Animations?
                                             .Count > 0;
                }
                else if (_monoGameContent.Asset is Model)
                {
                    Model = (Model)_monoGameContent.Asset;
                    UseDigitalRuneGraphics = false;
                    HasAnimations = false;

                    // Enable default lighting.
                    var effects = Model.Meshes
                                       .SelectMany(m => m.Effects)
                                       .OfType<IEffectLights>();
                    foreach (var effect in effects)
                        effect.EnableDefaultLighting();
                }
                else
                {
                    throw new EditorException("XNB does not contain ModelNode or Model.");
                }
            }
            catch (Exception exception)
            {
                Reset();

                if (IsDisposed)
                    return;

                State = ModelDocumentState.Error;
                Logger.Error(exception, "XNB could not be loaded.");

                // Let LoadAsync return and fail, then show message box.
                WindowsHelper.BeginInvokeOnUI(() =>
                {
                    var message = Invariant($"XNB could not be loaded:\n\n\"{exception.Message}\"");
                    MessageBox.Show(message, Editor.ApplicationName, MessageBoxButton.OK, MessageBoxImage.Error);
                });

                throw;
            }

            if (IsDisposed)
            {
                // Document was closed during loading.
                Reset();
                return;
            }

            // ----- Load Assimp scene
            try
            {
                if (!IsXnb)
                    _assimpScene = await Task.Run(() => LoadAssimp(fileName));
            }
            catch (Exception exception)
            {
                Logger.Warn(exception, "Assimp could not read model file.");
            }

            if (IsDisposed)
            {
                // Document was closed during loading.
                Reset();
                return;
            }

            State = ModelDocumentState.Loaded;

            // ----- Validate model
            ValidateModelNode();
            // TODO: Validate MonoGame Model.

            // If there are errors or warnings, show Output and Errors window.
            // (Drawback: This steals focus from the document.)
            //if (_errors.Count > 0)
            //{
            //    _outputService?.Show();
            //    _errorService?.Show();
            //}

            // ----- Update outline and properties
            UpdateOutline();
            UpdateProperties();
        }
Beispiel #8
0
        private void Reset()
        {
            StopAnimation();

            _monoGameContent?.Dispose();
            _monoGameContent = null;

            Debug.Assert(ModelNode == null || ModelNode.IsDisposed, "ModelNode should be disposed together with the ContentManager.");
            ModelNode = null;
            Model = null;

            _tempDirectoryHelper?.Dispose();
            _tempDirectoryHelper = null;

            _assimpScene = null;

            if (_outlineService != null && _outlineService.Outline == Outline)
                _outlineService.Outline = null;

            if (_propertiesService != null && _propertiesService.PropertySource == _currentPropertySource)
                _propertiesService.PropertySource = null;

            CleanErrors();
        }
Beispiel #9
0
        private async Task LoadAsync(string fileName, bool recreateModelAndMaterialFiles)
        {
            Debug.Assert(_tempDirectoryHelper == null);
            Debug.Assert(_monoGameContent == null);
            Debug.Assert(ModelNode == null);
            Debug.Assert(Model == null);
            Debug.Assert(_assimpScene == null);
            Debug.Assert(State == ModelDocumentState.Loading);

            string extension = Path.GetExtension(fileName);

            IsXnb = string.Compare(extension, ".XNB", StringComparison.OrdinalIgnoreCase) == 0;

            // ----- Build XNB
            string directoryName;

            try
            {
                if (IsXnb)
                {
                    // Get the folder that contains the XNB.
                    directoryName = Path.GetDirectoryName(fileName);
                }
                else if (GameContentBuilder.IsSupportedModelFileExtension(extension))
                {
                    // Build the XNB and get the output folder.
                    var buildResult = await Task.Run(() => BuildXnb(Editor.Services, Editor.ApplicationName, fileName, UseDigitalRuneGraphics, recreateModelAndMaterialFiles));

                    directoryName        = buildResult.Item1;
                    _tempDirectoryHelper = buildResult.Item2;
                }
                else
                {
                    throw new EditorException(Invariant($"Unsupported 3D model file format (file extension \"{extension}\")."));
                }
            }
            catch (Exception)
            {
                if (IsDisposed)
                {
                    // Document was closed during loading.
                    Reset();
                    return;
                }

                State = ModelDocumentState.Error;
                UpdateProperties();
                UpdateOutline();

                // The GameContentBuilder logs to the output service.
                _outputService.Show();

                throw;
            }

            if (IsDisposed)
            {
                // Document was closed during loading.
                Reset();
                return;
            }

            Debug.Assert(directoryName != null);

            // ----- Load XNB
            try
            {
                // Get asset name for use with ContentManager. XNBs and unprocessed models
                // use different folder hierarchies.
                string assetFileName;
                if (IsXnb)
                {
                    // Use absolute path.
                    assetFileName = fileName;
                }
                else
                {
                    // The asset is built relative to the root folder (e.g. "C:\"). The folder
                    // hierarchy (from root to asset) is rebuilt in the temporary output folder.

                    // Make file name relative to root.
                    assetFileName = DRPath.GetRelativePath(Path.GetPathRoot(fileName), fileName);

                    // Get absolute file name relative to temporary output folder.
                    assetFileName = Path.Combine(directoryName, assetFileName);

                    // Change extension. .fbx --> .xnb
                    assetFileName = Path.ChangeExtension(assetFileName, "xnb");
                }

                _monoGameContent = await Task.Run(() => _monoGameService.LoadXnb(directoryName, assetFileName, cacheResult: false));

                if (_monoGameContent.Asset is ModelNode)
                {
                    ModelNode = (ModelNode)_monoGameContent.Asset;
                    UseDigitalRuneGraphics = true;
                    HasAnimations          = ModelNode.GetDescendants()
                                             .OfType <MeshNode>()
                                             .FirstOrDefault()?
                                             .Mesh?
                                             .Animations?
                                             .Count > 0;
                }
                else if (_monoGameContent.Asset is Model)
                {
                    Model = (Model)_monoGameContent.Asset;
                    UseDigitalRuneGraphics = false;
                    HasAnimations          = false;

                    // Enable default lighting.
                    var effects = Model.Meshes
                                  .SelectMany(m => m.Effects)
                                  .OfType <IEffectLights>();
                    foreach (var effect in effects)
                    {
                        effect.EnableDefaultLighting();
                    }
                }
                else
                {
                    throw new EditorException("XNB does not contain ModelNode or Model.");
                }
            }
            catch (Exception exception)
            {
                Reset();

                if (IsDisposed)
                {
                    return;
                }

                State = ModelDocumentState.Error;
                Logger.Error(exception, "XNB could not be loaded.");

                // Let LoadAsync return and fail, then show message box.
                WindowsHelper.BeginInvokeOnUI(() =>
                {
                    var message = Invariant($"XNB could not be loaded:\n\n\"{exception.Message}\"");
                    MessageBox.Show(message, Editor.ApplicationName, MessageBoxButton.OK, MessageBoxImage.Error);
                });

                throw;
            }

            if (IsDisposed)
            {
                // Document was closed during loading.
                Reset();
                return;
            }

            // ----- Load Assimp scene
            try
            {
                if (!IsXnb)
                {
                    _assimpScene = await Task.Run(() => LoadAssimp(fileName));
                }
            }
            catch (Exception exception)
            {
                Logger.Warn(exception, "Assimp could not read model file.");
            }

            if (IsDisposed)
            {
                // Document was closed during loading.
                Reset();
                return;
            }

            State = ModelDocumentState.Loaded;

            // ----- Validate model
            ValidateModelNode();
            // TODO: Validate MonoGame Model.

            // If there are errors or warnings, show Output and Errors window.
            // (Drawback: This steals focus from the document.)
            //if (_errors.Count > 0)
            //{
            //    _outputService?.Show();
            //    _errorService?.Show();
            //}

            // ----- Update outline and properties
            UpdateOutline();
            UpdateProperties();
        }
Beispiel #10
0
        //--------------------------------------------------------------
        /// <summary>
        /// Creates a new content builder.
        /// </summary>
        /// <param name="editor">The editor.</param>
        public XnaContentBuilder(IEditorService editor)
        {
            if (editor == null)
                throw new ArgumentNullException(nameof(editor));

            _outputService = editor.Services.GetInstance<IOutputService>().ThrowIfMissing();

            //_buildLogger = new BuildLogger(outputService);
            _tempDirectoryHelper = new TempDirectoryHelper(editor.ApplicationName, "XnaContentBuilder");
            CreateBuildProject();
        }