Example #1
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();
        }
Example #2
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();
        }
Example #3
0
        public MonoGameContent LoadXnb(string rootDirectoryName, string fileName, bool cacheResult)
        {
            Debug.Assert(rootDirectoryName != null);
            Debug.Assert(rootDirectoryName.Length > 0);
            Debug.Assert(fileName != null);
            Debug.Assert(fileName.Length > 0);

            // Check whether content has already been loaded and is still cached.
            if (_cachedContent != null &&
                !_cachedContent.IsDisposed &&
                _cachedContent.RootDirectoryName == rootDirectoryName &&
                _cachedContent.FileName == fileName)
            {
                var result = _cachedContent;
                if (!cacheResult)
                {
                    _cachedContent = null;
                }

                return(result);
            }

            // Clear cache.
            _cachedContent?.Dispose();
            _cachedContent = null;

            // External references in MonoGame are relative to the content root directory, not the
            // model. Loading the model fails, if a external reference cannot be resolved.
            // --> Try different content root directories.
            var rootDirectory = new DirectoryInfo(rootDirectoryName);

            while (rootDirectory != null)
            {
                VfsStorage            storage = null;
                StorageContentManager content = null;
                try
                {
                    // Create a virtual file system which contains the DigitalRune effects and the content folder.
                    storage = new VfsStorage();
                    storage.MountInfos.Add(new VfsMountInfo(new ZipStorage(new TitleStorage("Content"), "DigitalRune.zip"), null));
                    storage.MountInfos.Add(new VfsMountInfo(new FileSystemStorage(rootDirectory.FullName), null));
                    content = new StorageContentManager(_services, storage);

                    string assetName = DRPath.GetRelativePath(rootDirectory.FullName, fileName);
                    var    asset     = content.Load <object>(assetName);

                    var result = new MonoGameContent(rootDirectoryName, fileName, storage, content, asset);

                    if (cacheResult)
                    {
                        _cachedContent = result;
                    }

                    return(result);
                }
                catch (Exception exception)
                {
                    storage?.Dispose();
                    content?.Dispose();

                    if (exception is ContentLoadException &&
                        exception.InnerException is ContentLoadException &&
                        rootDirectory.Parent != null)
                    {
                        // ExternalReference could probably not be resolved.
                        // --> Retry with parent folder as content root.
                    }
                    else
                    {
                        // Asset could not be loaded.
                        throw;
                    }
                }

                rootDirectory = rootDirectory.Parent;
            }

            // Execution should never reach this point.
            throw new EditorException("Unexpected error.");
        }
Example #4
0
        public MonoGameContent LoadXnb(string rootDirectoryName, string fileName, bool cacheResult)
        {
            Debug.Assert(rootDirectoryName != null);
            Debug.Assert(rootDirectoryName.Length > 0);
            Debug.Assert(fileName != null);
            Debug.Assert(fileName.Length > 0);

            // Check whether content has already been loaded and is still cached.
            if (_cachedContent != null
                && !_cachedContent.IsDisposed
                && _cachedContent.RootDirectoryName == rootDirectoryName
                && _cachedContent.FileName == fileName)
            {
                var result = _cachedContent;
                if (!cacheResult)
                    _cachedContent = null;

                return result;
            }

            // Clear cache.
            _cachedContent?.Dispose();
            _cachedContent = null;

            // External references in MonoGame are relative to the content root directory, not the
            // model. Loading the model fails, if a external reference cannot be resolved.
            // --> Try different content root directories.
            var rootDirectory = new DirectoryInfo(rootDirectoryName);
            while (rootDirectory != null)
            {
                VfsStorage storage = null;
                StorageContentManager content = null;
                try
                {
                    // Create a virtual file system which contains the DigitalRune effects and the content folder.
                    storage = new VfsStorage();
                    storage.MountInfos.Add(new VfsMountInfo(new ZipStorage(new TitleStorage("Content"), "DigitalRune.zip"), null));
                    storage.MountInfos.Add(new VfsMountInfo(new FileSystemStorage(rootDirectory.FullName), null));
                    content = new StorageContentManager(_services, storage);

                    string assetName = DRPath.GetRelativePath(rootDirectory.FullName, fileName);
                    var asset = content.Load<object>(assetName);

                    var result = new MonoGameContent(rootDirectoryName, fileName, storage, content, asset);

                    if (cacheResult)
                        _cachedContent = result;

                    return result;
                }
                catch (Exception exception)
                {
                    storage?.Dispose();
                    content?.Dispose();

                    if (exception is ContentLoadException
                        && exception.InnerException is ContentLoadException
                        && rootDirectory.Parent != null)
                    {
                        // ExternalReference could probably not be resolved.
                        // --> Retry with parent folder as content root.
                    }
                    else
                    {
                        // Asset could not be loaded.
                        throw;
                    }
                }

                rootDirectory = rootDirectory.Parent;
            }

            // Execution should never reach this point.
            throw new EditorException("Unexpected error.");
        }
Example #5
0
        /// <inheritdoc/>
        protected override void OnLoad()
        {
            Texture2D?.Dispose();
            Texture2D = null;
            _monoGameContent?.Dispose();
            _monoGameContent = null;

            // TODO: Asynchronously load textures.
            string fileName = Uri.LocalPath;
            string extension = Path.GetExtension(fileName);
            bool isXnb = string.Compare(extension, ".XNB", StringComparison.OrdinalIgnoreCase) == 0;
            if (isXnb)
            {
                try
                {
                    string directoryName = Path.GetDirectoryName(fileName);
                    _monoGameContent = _monoGameService.LoadXnb(directoryName, fileName, cacheResult: false);
                    Texture2D = (Texture2D)_monoGameContent.Asset;
                }
                catch
                {
                    Texture2D?.Dispose();
                    Texture2D = null;
                    _monoGameContent?.Dispose();
                    _monoGameContent = null;

                    throw;
                }
            }
            else
            {
                Texture2D = TextureHelper.LoadTexture(_graphicsService, Uri.LocalPath);
            }

            UpdateProperties();
        }