Пример #1
0
        /// <summary>Function to load the sprites used to generate the atlas texture(s).</summary>
        /// <param name="files">The sprite files to load.</param>
        /// <returns>A list of sprites and their associated files.</returns>
        public IReadOnlyDictionary <IContentFile, GorgonSprite> LoadSprites(IEnumerable <IContentFile> files)
        {
            var    result   = new Dictionary <IContentFile, GorgonSprite>();
            Stream stream   = null;
            var    textures = new Dictionary <string, GorgonTexture2DView>(StringComparer.OrdinalIgnoreCase);

            try
            {
                foreach (IContentFile file in files)
                {
                    GorgonTexture2DView texture = null;

                    if (file.Metadata.DependsOn.TryGetValue(CommonEditorContentTypes.ImageType, out string texturePath))
                    {
                        if (!textures.TryGetValue(texturePath, out texture))
                        {
                            texture = LoadSpriteTexture(_fileSystem.GetFile(texturePath));
                            textures[texturePath] = texture;
                        }
                    }

                    stream       = file.OpenRead();
                    result[file] = _defaultSpriteCodec.FromStream(stream, texture);
                    stream.Dispose();
                }
            }
            catch
            {
                // If we loaded in a bunch of textures already, then dump them since we can't do it outside of here.
                foreach (KeyValuePair <IContentFile, GorgonSprite> sprite in result)
                {
                    sprite.Value.Texture?.Dispose();
                }

                throw;
            }
            finally
            {
                stream?.Dispose();
            }

            return(result);
        }
        /// <summary>
        /// Function to load a <see cref="GorgonSprite"/> 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">[Optional] The list of sprite codecs to try and load the sprite with.</param>
        /// <param name="imageCodecs">[Optional] 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 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="GorgonSprite"/>
        public static GorgonSprite LoadSpriteFromFileSystem(this IGorgonFileSystem fileSystem,
                                                            Gorgon2D renderer,
                                                            string path,
                                                            GorgonTexture2DLoadOptions textureOptions     = null,
                                                            IEnumerable <IGorgonSpriteCodec> 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 IGorgonSpriteCodec[]
                {
                    new GorgonV3SpriteBinaryCodec(renderer),
                    new GorgonV3SpriteJsonCodec(renderer),
                    new GorgonV2SpriteCodec(renderer),
                    new GorgonV1SpriteBinaryCodec(renderer),
                };
            }
            else
            {
                // Only use codecs that can decode sprite data.
                spriteCodecs = spriteCodecs.Where(item => item.CanDecode);
            }

            // We need to copy the sprite data into a memory stream since the underlying stream may not be seekable.
            Stream spriteStream = file.OpenStream();

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

                IGorgonSpriteCodec spriteCodec = GetSpriteCodec(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();
            }
        }