/// <summary> /// Function to remove an item from the collection by index. /// </summary> /// <param name="provider">The provider to remove.</param> protected override void RemoveItem(GorgonFileSystemProvider provider) { // Perform any special clean up. provider.OnUnload(); // Remove any files attached to this provider. var files = _fileSystem.FindFiles("*", true).Where(file => file.Provider == provider); foreach (GorgonFileSystemFileEntry file in files) { file.Directory.Files.Remove(file); } base.RemoveItem(provider); }
/// <summary> /// Function to open the editor file. /// </summary> /// <param name="path">Path to the editor file.</param> public static void Open(string path) { var packFileSystem = new GorgonFileSystem(); FileChanged = false; // Add the new file system as a mount point. var plugIns = from plugIn in Gorgon.PlugIns where plugIn is GorgonFileSystemProviderPlugIn && !PlugIns.IsDisabled(plugIn) select plugIn; foreach (var plugIn in plugIns) { packFileSystem.Providers.LoadProvider(plugIn.Name); } if (!packFileSystem.Providers.Any(item => item.CanReadFile(path))) { throw new FileLoadException(string.Format(APIResources.GOREDIT_ERR_NO_READ_PROVIDERS, Path.GetFileName(path))); } packFileSystem.Mount(path); try { // Remove our previous scratch data. ResetFile(); // At this point we should have a clean scratch area, so all files will exist in the packed file. // Unpack the file structure so we can work with it. var directories = packFileSystem.FindDirectories("*", true); var files = packFileSystem.FindFiles("*", true); // Create our directories. foreach (var directory in directories) { ScratchArea.ScratchFiles.CreateDirectory(directory.FullPath); } // Copy our files. foreach (var file in files) { using (var inputStream = packFileSystem.OpenStream(file, false)) { using (var outputStream = ScratchArea.ScratchFiles.OpenStream(file.FullPath, true)) { inputStream.CopyTo(outputStream); } } } FilePath = string.Empty; Filename = Path.GetFileName(path); // Load the meta data if it exists. EditorMetaDataFile.Load(); // If we can't write the file, then leave the editor file path as blank. // If the file path is blank, then the Save As function will be triggered if we attempt to save so we // can save it in a format that we DO understand. This is of course assuming we have any plug-ins loaded // that will allow us to save. if (GetWriterPlugIn(path) != null) { FilePath = path; } } catch { // We have a problem, reset whatever changes we've made. ResetFile(); throw; } finally { // At this point we don't need this file system any more. We'll // be using our scratch system instead. packFileSystem.Clear(); } }
/// <summary> /// Function to copy the file system data from a file system file. /// </summary> /// <param name="fileSystemFile">The file system file to copy.</param> /// <param name="provider">The provider to use.</param> /// <param name="fileSystemDir">The workspace directory to copy the files into.</param> /// <returns>The path to the metadata file.</returns> private async Task <FileInfo> CopyFileSystemAsync(FileInfo fileSystemFile, IGorgonFileSystemProvider provider, DirectoryInfo fileSystemDir) { IGorgonFileSystem fileSystem = new GorgonFileSystem(provider, Program.Log); fileSystem.Mount(fileSystemFile.FullName); IGorgonVirtualFile metaData = fileSystem.GetFile(Path.Combine("/", CommonEditorConstants.EditorMetadataFileName)); // Get all directories and replicate them. IEnumerable <IGorgonVirtualDirectory> directories = fileSystem.FindDirectories("/", "*") .OrderBy(item => item.FullPath.Length); foreach (IGorgonVirtualDirectory directory in directories) { var dirInfo = new DirectoryInfo(Path.Combine(fileSystemDir.FullName, directory.FullPath.FormatDirectory(Path.DirectorySeparatorChar).Substring(1))); if (dirInfo.Exists) { continue; } dirInfo.Create(); } // Copy all files into the directories we just created. var files = fileSystem.FindFiles("/", "*") .Where(item => item != metaData) .OrderByDescending(item => item.Size) .ToList(); int maxJobCount = (Environment.ProcessorCount * 2).Min(32).Max(1); int filesPerJob = (int)((float)files.Count / maxJobCount).FastCeiling(); var jobs = new List <Task>(); if ((files.Count <= 100) || (maxJobCount < 2)) { filesPerJob = files.Count; } Program.Log.Print($"Copying file system. {filesPerJob} files will be copied in a single job.", LoggingLevel.Verbose); void CopyFile(FileCopyJob job) { foreach (IGorgonVirtualFile file in job.Files) { var fileInfo = new FileInfo(Path.Combine(fileSystemDir.FullName, file.Directory.FullPath.FormatDirectory(Path.DirectorySeparatorChar).Substring(1), file.Name)); using (Stream readStream = file.OpenStream()) using (Stream writeStream = fileInfo.OpenWrite()) { readStream.CopyToStream(writeStream, (int)readStream.Length, job.ReadBuffer); } } } // Build up the tasks for our jobs. while (files.Count > 0) { var jobData = new FileCopyJob(); // Copy the file information to the file copy job data. int length = filesPerJob.Min(files.Count); for (int i = 0; i < length; ++i) { jobData.Files.Add(files[i]); } files.RemoveRange(0, length); jobs.Add(Task.Run(() => CopyFile(jobData))); } Program.Log.Print($"{jobs.Count} jobs running for file copy from '{fileSystemFile.FullName}'.", LoggingLevel.Verbose); // Wait for the file copy to finish. await Task.WhenAll(jobs); var metaDataOutput = new FileInfo(Path.Combine(fileSystemDir.FullName, CommonEditorConstants.EditorMetadataFileName)); if (metaData == null) { Program.Log.Print($"'{fileSystemFile.FullName}' has no metadata. A new metadata index will be generated.", LoggingLevel.Verbose); return(metaDataOutput); } Program.Log.Print($"'{fileSystemFile.FullName}' has metadata. Copying to the .", LoggingLevel.Verbose); byte[] writeBuffer = new byte[81920]; using (Stream readStream = metaData.OpenStream()) using (Stream writeStream = metaDataOutput.OpenWrite()) { readStream.CopyToStream(writeStream, (int)readStream.Length, writeBuffer); } metaDataOutput.Attributes = FileAttributes.Archive | FileAttributes.Normal; metaDataOutput.Refresh(); return(metaDataOutput); }
/// <summary> /// Function to initialize the application. /// </summary> /// <returns>The main window for the application.</returns> private static FormMain Initialize() { GorgonExample.ResourceBaseDirectory = new DirectoryInfo(Settings.Default.ResourceLocation); GorgonExample.PlugInLocationDirectory = new DirectoryInfo(Settings.Default.PlugInLocation); FormMain window = GorgonExample.Initialize(new DX.Size2(Settings.Default.Resolution.Width, Settings.Default.Resolution.Height), "Depth"); try { IReadOnlyList <IGorgonVideoAdapterInfo> videoDevices = GorgonGraphics.EnumerateAdapters(log: GorgonApplication.Log); if (videoDevices.Count == 0) { throw new GorgonException(GorgonResult.CannotCreate, "Gorgon requires at least a Direct3D 11.4 capable video device.\nThere is no suitable device installed on the system."); } // Find the best video device. _graphics = new GorgonGraphics(videoDevices.OrderByDescending(item => item.FeatureSet).First()); _screen = new GorgonSwapChain(_graphics, window, new GorgonSwapChainInfo("Gorgon2D Depth Buffer Example") { Width = Settings.Default.Resolution.Width, Height = Settings.Default.Resolution.Height, Format = BufferFormat.R8G8B8A8_UNorm }); _depthBuffer = GorgonDepthStencil2DView.CreateDepthStencil(_graphics, new GorgonTexture2DInfo(_screen.RenderTargetView) { Binding = TextureBinding.DepthStencil, Format = BufferFormat.D24_UNorm_S8_UInt }); // Tell the graphics API that we want to render to the "screen" swap chain. _graphics.SetRenderTarget(_screen.RenderTargetView, _depthBuffer); // Initialize the renderer so that we are able to draw stuff. _renderer = new Gorgon2D(_graphics); GorgonExample.LoadResources(_graphics); // Load our packed file system plug in. _assemblyCache = new GorgonMefPlugInCache(GorgonApplication.Log); _assemblyCache.LoadPlugInAssemblies(GorgonExample.GetPlugInPath().FullName, "Gorgon.FileSystem.GorPack.dll"); IGorgonPlugInService plugIns = new GorgonMefPlugInService(_assemblyCache); // Load the file system containing our application data (sprites, images, etc...) IGorgonFileSystemProviderFactory providerFactory = new GorgonFileSystemProviderFactory(plugIns, GorgonApplication.Log); IGorgonFileSystemProvider provider = providerFactory.CreateProvider("Gorgon.IO.GorPack.GorPackProvider"); IGorgonFileSystem fileSystem = new GorgonFileSystem(provider, GorgonApplication.Log); // We can load the editor file system directly. // This is handy for switching a production environment where your data may be stored // as a compressed file, and a development environment where your data consists of loose // files. // fileSystem.Mount(@"D:\unpak\scratch\DeepAsAPuddle.gorPack\fs\"); // For now though, we'll load the packed file. fileSystem.Mount(Path.Combine(GorgonExample.GetResourcePath(@"FileSystems").FullName, "Depth.gorPack")); // Get our sprites. These make up the frames of animation for our Guy. // If and when there's an animation editor, we'll only need to create a single sprite and load the animation. IGorgonVirtualFile[] spriteFiles = fileSystem.FindFiles("/Sprites/", "*", true).ToArray(); // Load our sprite data (any associated textures will be loaded as well). Dictionary <string, GorgonSprite> sprites = new Dictionary <string, GorgonSprite>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < spriteFiles.Length; i++) { IGorgonVirtualFile file = spriteFiles[i]; (GorgonSprite sprite, GorgonTexture2D texture) = fileSystem.LoadSprite(_renderer, file.FullPath); // The LoadSprite extension method will automatically find and load your associated texture if you're using // a Gorgon editor file system. So it's important that you leep track of your textures, disposing of just // the associated GorgonTexture2DView won't cut it here, so you'll need to dispose the actual texture resource // when you're done with it. if (!_textures.Contains(texture)) { _textures.Add(texture); } // At super duper resolution, the example graphics would be really hard to see, so we'll scale them up. sprite.Scale = new DX.Vector2((_screen.Width / (_screen.Height / 2)) * 2.0f); sprites[file.Name] = sprite; } _snowTile = sprites["Snow"]; _snowTile.Depth = 0.5f; _icicle = sprites["Icicle"]; _icicle.Depth = 0.2f; _guySprite = sprites["Guy_Up_0"]; _guySprite.Depth = 0.1f; _guyPosition = new DX.Vector2(_screen.Width / 2 + _guySprite.ScaledSize.Width * 1.25f, _screen.Height / 2 + _guySprite.ScaledSize.Height); BuildAnimations(sprites); } finally { GorgonExample.EndInit(); } return(window); }