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(); }
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(); }
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."); }
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."); }
/// <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(); }