Exemple #1
0
        /// <summary>
        /// Function to load the text into the file system.
        /// </summary>
        private void LoadText()
        {
            DirectoryInfo physicalPath = GorgonExample.GetResourcePath(@"FolderSystem\");

            // Unload the mounted files.
            _writer.Unmount();
            _fileSystem.Unmount(physicalPath.FullName);

            _fileSystem.Mount(physicalPath.FullName);

            // Load the original before we mount the write directory.
            IGorgonVirtualFile file = _fileSystem.GetFile("/SomeText.txt");

            using (Stream stream = file.OpenStream())
            {
                byte[] textData = new byte[stream.Length];

                stream.Read(textData, 0, textData.Length);
                _originalText = Encoding.UTF8.GetString(textData);
            }

            // Set the write location to the users app data folder.
            _writer.Mount();

            // Load the modified version (if it exists, if it doesn't, the original will be loaded instead).
            file = _fileSystem.GetFile("/SomeText.txt");

            using (Stream stream = file.OpenStream())
            {
                byte[] textData = new byte[stream.Length];

                stream.Read(textData, 0, textData.Length);
                _changedText = Encoding.UTF8.GetString(textData);

                textDisplay.Text = string.Equals(_changedText, _originalText, StringComparison.CurrentCulture) ? _originalText : _changedText;
            }
        }
Exemple #2
0
        /// <summary>
        /// Function to load a sprite from the file system.
        /// </summary>
        /// <param name="path">Path to the file to load.</param>
        /// <returns>A byte array containing the data for a file from the file system.</returns>
        private byte[] LoadFile(string path)
        {
            IGorgonVirtualFile file = _fileSystem.GetFile(path);

            if (file == null)
            {
                throw new FileNotFoundException($"The file '{path}' was not found in the file system.");
            }

            using (Stream stream = file.OpenStream())
            {
                byte[] result = new byte[stream.Length];

                stream.Read(result, 0, result.Length);

                return(result);
            }
        }
        /// <summary>
        /// Function to load a <see cref="IGorgonAnimation"/> from a <see cref="GorgonFileSystem"/>.
        /// </summary>
        /// <param name="fileSystem">The file system to load the animation from.</param>
        /// <param name="renderer">The renderer for the animation.</param>
        /// <param name="path">The path to the animation file in the file system.</param>
        /// <param name="textureOptions">[Optional] Options for the texture loaded associated the sprite.</param>
        /// <param name="animationCodecs">The list of animation codecs to try and load the animation with.</param>
        /// <param name="imageCodecs">The list of image codecs to try and load the animation texture(s) with.</param>
        /// <returns>The animation data in the file as a <see cref="IGorgonAnimation"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="fileSystem"/>, <paramref name="renderer"/>, or <paramref name="path"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="path"/> parameter is empty.</exception>
        /// <exception cref="FileNotFoundException">Thrown if the file in the <paramref name="path"/> was not found.</exception>
        /// <exception cref="GorgonException">Thrown if the animation data in the file system could not be loaded because a suitable codec was not found.</exception>
        /// <remarks>
        /// <para>
        /// This method extends a <see cref="GorgonFileSystem"/> so that animations can be loaded by calling a method on the file system object itself. This negates the need for users to create complex code
        /// for loading an animation.
        /// </para>
        /// <para>
        /// When loading an animation, the method will attempt to locate any <see cref="GorgonTexture2DView"/> objects associated with the animation (if they exist). When loading, it will check:
        /// <list type="number">
        ///     <item>
        ///         <description>For a texture resource with the same name that is already loaded into memory.</description>
        ///     </item>
        ///     <item>
        ///         <description>Use the local <see cref="IGorgonVirtualDirectory"/> for the sprite file and search for the texture in that directory.</description>
        ///     </item>
        ///     <item>
        ///         <description>Check the entire <paramref name="fileSystem"/> for a file if the texture name contains path information (this is done by the GorgonEditor from v2).</description>
        ///     </item>
        /// </list>
        /// If the file is found, and can be loaded by one of the <paramref name="imageCodecs"/>, then it is loaded and assigned to the sprite.
        /// </para>
        /// <para>
        /// The <paramref name="animationCodecs"/> is a list of codecs for loading sprite data. If the user specifies this parameter, the only the codecs provided will be used for determining if an
        /// animation can be read. If it is not supplied, then all built-in (i.e. not plug in based) sprite codecs will be used.
        /// </para>
        /// <para>
        /// The <paramref name="imageCodecs"/> is a list of codecs for loading image data. If the user specifies this parameter, the only the codecs provided will be used for determining if an image can be
        /// read. If it is not supplied, then all built-in (i.e. not plug in based) image codecs will be used.
        /// </para>
        /// </remarks>
        /// <seealso cref="GorgonFileSystem"/>
        /// <seealso cref="GorgonTexture2DView"/>
        /// <seealso cref="IGorgonAnimation"/>
        public static IGorgonAnimation LoadAnimationFromFileSystem(this GorgonFileSystem fileSystem,
                                                                   Gorgon2D renderer,
                                                                   string path,
                                                                   GorgonTexture2DLoadOptions textureOptions           = null,
                                                                   IEnumerable <IGorgonAnimationCodec> animationCodecs = null,
                                                                   IEnumerable <IGorgonImageCodec> imageCodecs         = null)
        {
            if (fileSystem == null)
            {
                throw new ArgumentNullException(nameof(fileSystem));
            }

            IGorgonVirtualFile file = fileSystem.GetFile(path);

            if (file == null)
            {
                throw new FileNotFoundException(string.Format(Resources.GOR2DIO_ERR_FILE_NOT_FOUND, path));
            }

            if ((imageCodecs == null) || (!imageCodecs.Any()))
            {
                // If we don't specify any codecs, then use the built in ones.
                imageCodecs = new IGorgonImageCodec[]
                {
                    new GorgonCodecPng(),
                    new GorgonCodecBmp(),
                    new GorgonCodecDds(),
                    new GorgonCodecGif(),
                    new GorgonCodecJpeg(),
                    new GorgonCodecTga(),
                };
            }
            else
            {
                // Only use codecs that can decode image data.
                imageCodecs = imageCodecs.Where(item => item.CanDecode);
            }

            if ((animationCodecs == null) || (!animationCodecs.Any()))
            {
                // Use all built-in codecs if we haven't asked for any.
                animationCodecs = new IGorgonAnimationCodec[]
                {
                    new GorgonV3AnimationBinaryCodec(renderer),
                    new GorgonV3AnimationJsonCodec(renderer),
                    new GorgonV1AnimationCodec(renderer)
                };
            }
            else
            {
                // Only use codecs that can decode sprite data.
                animationCodecs = animationCodecs.Where(item => item.CanDecode);
            }

            Stream animStream = file.OpenStream();

            try
            {
                if (!animStream.CanSeek)
                {
                    Stream newStream = new DataStream((int)animStream.Length, true, true);
                    animStream.CopyTo(newStream);
                    newStream.Position = 0;

                    animStream.Dispose();
                    animStream = newStream;
                }

                IGorgonAnimationCodec animationCodec = GetAnimationCodec(animStream, animationCodecs);

                if (animationCodec == null)
                {
                    throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GOR2DIO_ERR_NO_SUITABLE_ANIM_CODEC_FOUND, path));
                }

                // Load the animation.
                IGorgonAnimation animation = animationCodec.FromStream(animStream, (int)file.Size);

                // We have no textures to update, leave.
                if (animation.Texture2DTrack.KeyFrames.Count == 0)
                {
                    return(animation);
                }

                // Try to locate the textures.

                // V1 sprite animations need texture coordinate correction.
                bool needsCoordinateFix = animationCodec is GorgonV1AnimationCodec;

                foreach (GorgonKeyTexture2D textureKey in animation.Texture2DTrack.KeyFrames)
                {
                    // Let's try and load the texture into memory.
                    // This does this by:
                    // 1. Checking to see if a texture resource with the name specified is already available in memory.
                    // 2. Checking the local directory of the file to see if the texture is there.
                    // 3. A file system wide search.

                    // ReSharper disable once InvertIf
                    (IGorgonImageCodec codec, IGorgonVirtualFile textureFile, bool loaded) =
                        LocateTextureCodecAndFile(fileSystem, file.Directory, renderer, textureKey.TextureName, imageCodecs);

                    // We have not loaded the texture yet.  Do so now.
                    // ReSharper disable once InvertIf
                    if ((!loaded) && (textureFile != null) && (codec != null))
                    {
                        using (Stream textureStream = textureFile.OpenStream())
                        {
                            textureKey.Value = GorgonTexture2DView.FromStream(renderer.Graphics,
                                                                              textureStream,
                                                                              codec,
                                                                              textureFile.Size, GetTextureOptions(textureFile.FullPath, textureOptions));
                        }
                    }

                    if ((needsCoordinateFix) && (textureKey.Value != null))
                    {
                        textureKey.TextureCoordinates = new RectangleF(textureKey.TextureCoordinates.X / textureKey.Value.Width,
                                                                       textureKey.TextureCoordinates.Y / textureKey.Value.Height,
                                                                       textureKey.TextureCoordinates.Width / textureKey.Value.Width,
                                                                       textureKey.TextureCoordinates.Height / textureKey.Value.Height);
                    }
                }

                return(animation);
            }
            finally
            {
                animStream?.Dispose();
            }
        }
        /// <summary>
        /// Function to load a <see cref="GorgonPolySprite"/> from a <see cref="GorgonFileSystem"/>.
        /// </summary>
        /// <param name="fileSystem">The file system to load the sprite from.</param>
        /// <param name="renderer">The renderer for the sprite.</param>
        /// <param name="path">The path to the sprite file in the file system.</param>
        /// <param name="textureOptions">[Optional] Options for the texture loaded associated the sprite.</param>
        /// <param name="spriteCodecs">The list of polygonal sprite codecs to try and load the sprite with.</param>
        /// <param name="imageCodecs">The list of image codecs to try and load the sprite texture with.</param>
        /// <returns>The sprite data in the file as a <see cref="GorgonSprite"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="fileSystem"/>, <paramref name="renderer"/>, or <paramref name="path"/> parameter is <b>null</b>.</exception>
        /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="path"/> parameter is empty.</exception>
        /// <exception cref="FileNotFoundException">Thrown if the file in the <paramref name="path"/> was not found.</exception>
        /// <exception cref="GorgonException">Thrown if the sprite data in the file system could not be loaded because a suitable codec was not found.</exception>
        /// <remarks>
        /// <para>
        /// This method extends a <see cref="GorgonFileSystem"/> so that sprites can be loaded by calling a method on the file system object itself. This negates the need for users to create complex code
        /// for loading a sprite.
        /// </para>
        /// <para>
        /// When loading a sprite, the method will attempt to locate the <see cref="GorgonTexture2DView"/> associated with the sprite (if it exists). When loading, it will check:
        /// <list type="number">
        ///     <item>
        ///         <description>For a texture resource with the same name that is already loaded into memory.</description>
        ///     </item>
        ///     <item>
        ///         <description>Use the local <see cref="IGorgonVirtualDirectory"/> for the sprite file and search for the texture in that directory.</description>
        ///     </item>
        ///     <item>
        ///         <description>Check the entire <paramref name="fileSystem"/> for a file if the texture name contains path information (this is done by the GorgonEditor from v2).</description>
        ///     </item>
        /// </list>
        /// If the file is found, and can be loaded by one of the <paramref name="imageCodecs"/>, then it is loaded and assigned to the sprite.
        /// </para>
        /// <para>
        /// The <paramref name="spriteCodecs"/> is a list of codecs for loading polygonal sprite data. If the user specifies this parameter, the only the codecs provided will be used for determining if a
        /// sprite can be read. If it is not supplied, then all built-in (i.e. not plug in based) sprite codecs will be used.
        /// </para>
        /// <para>
        /// The <paramref name="imageCodecs"/> is a list of codecs for loading image data. If the user specifies this parameter, the only the codecs provided will be used for determining if an image can be
        /// read. If it is not supplied, then all built-in (i.e. not plug in based) image codecs will be used.
        /// </para>
        /// </remarks>
        /// <seealso cref="GorgonFileSystem"/>
        /// <seealso cref="GorgonTexture2DView"/>
        /// <seealso cref="GorgonPolySprite"/>
        public static GorgonPolySprite LoadPolySpriteFromFileSystem(this GorgonFileSystem fileSystem,
                                                                    Gorgon2D renderer,
                                                                    string path,
                                                                    GorgonTexture2DLoadOptions textureOptions         = null,
                                                                    IEnumerable <IGorgonPolySpriteCodec> spriteCodecs = null,
                                                                    IEnumerable <IGorgonImageCodec> imageCodecs       = null)
        {
            if (fileSystem == null)
            {
                throw new ArgumentNullException(nameof(fileSystem));
            }

            IGorgonVirtualFile file = fileSystem.GetFile(path);

            if (file == null)
            {
                throw new FileNotFoundException(string.Format(Resources.GOR2DIO_ERR_FILE_NOT_FOUND, path));
            }

            if ((imageCodecs == null) || (!imageCodecs.Any()))
            {
                // If we don't specify any codecs, then use the built in ones.
                imageCodecs = new IGorgonImageCodec[]
                {
                    new GorgonCodecPng(),
                    new GorgonCodecBmp(),
                    new GorgonCodecDds(),
                    new GorgonCodecGif(),
                    new GorgonCodecJpeg(),
                    new GorgonCodecTga(),
                };
            }
            else
            {
                // Only use codecs that can decode image data.
                imageCodecs = imageCodecs.Where(item => item.CanDecode);
            }

            if ((spriteCodecs == null) || (!spriteCodecs.Any()))
            {
                // Use all built-in codecs if we haven't asked for any.
                spriteCodecs = new IGorgonPolySpriteCodec[]
                {
                    new GorgonV3PolySpriteBinaryCodec(renderer),
                    new GorgonV3PolySpriteJsonCodec(renderer)
                };
            }
            else
            {
                // Only use codecs that can decode sprite data.
                spriteCodecs = spriteCodecs.Where(item => item.CanDecode);
            }

            Stream spriteStream = file.OpenStream();

            try
            {
                if (!spriteStream.CanSeek)
                {
                    Stream newStream = new DataStream((int)spriteStream.Length, true, true);
                    spriteStream.CopyTo(newStream);
                    newStream.Position = 0;
                    spriteStream.Dispose();
                    spriteStream = newStream;
                }

                IGorgonPolySpriteCodec spriteCodec = GetPolySpriteCodec(spriteStream, spriteCodecs);

                if (spriteCodec == null)
                {
                    throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GOR2DIO_ERR_NO_SUITABLE_SPRITE_CODEC_FOUND, path));
                }

                // Try to locate the texture.
                string textureName = spriteCodec.GetAssociatedTextureName(spriteStream);

                GorgonTexture2DView textureForSprite = null;

                // Let's try and load the texture into memory.
                // This does this by:
                // 1. Checking to see if a texture resource with the name specified is already available in memory.
                // 2. Checking the local directory of the file to see if the texture is there.
                // 3. A file system wide search.

                // ReSharper disable once InvertIf
                if (!string.IsNullOrWhiteSpace(textureName))
                {
                    (IGorgonImageCodec codec, IGorgonVirtualFile textureFile, bool loaded) =
                        LocateTextureCodecAndFile(fileSystem, file.Directory, renderer, textureName, imageCodecs);

                    // We have not loaded the texture yet.  Do so now.
                    // ReSharper disable once InvertIf
                    if ((!loaded) && (textureFile != null) && (codec != null))
                    {
                        using (Stream textureStream = textureFile.OpenStream())
                        {
                            textureForSprite = GorgonTexture2DView.FromStream(renderer.Graphics,
                                                                              textureStream,
                                                                              codec,
                                                                              textureFile.Size,
                                                                              GetTextureOptions(textureFile.FullPath, textureOptions));
                        }
                    }
                }

                return(spriteCodec.FromStream(spriteStream, textureForSprite, (int)file.Size));
            }
            finally
            {
                spriteStream?.Dispose();
            }
        }
        /// <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);
        }