/// <summary> /// Function to locate the texture file associated with the sprite being imported. /// </summary> /// <returns>The texture being imported.</returns> private GorgonTexture2DView GetTexture() { // We need to copy the sprite data into a memory stream since the underlying stream may not be seekable (BZip2 lies and says it is seekable, but it really isn't). using (Stream fileStream = SourceFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) { string textureName = _codec.GetAssociatedTextureName(fileStream); GorgonTexture2DView textureForSprite = null; // Let's try and load the texture into memory. // ReSharper disable once InvertIf if (!string.IsNullOrWhiteSpace(textureName)) { IGorgonVirtualFile textureFile = LocateTextureFile(textureName); // We couldn't load the file, so, let's try again without a file extension since we strip those. int extensionDot = textureName.LastIndexOf('.'); if ((textureFile == null) && (extensionDot > 1)) { textureName = textureName.Substring(0, extensionDot); textureFile = LocateTextureFile(textureName); } // We have not loaded the texture yet. Do so now. // ReSharper disable once InvertIf if (textureFile != null) { using (Stream textureStream = textureFile.OpenStream()) { textureForSprite = GorgonTexture2DView.FromStream(_renderer.Graphics, textureStream, _ddsCodec, textureFile.Size, new GorgonTexture2DLoadOptions { Name = textureFile.FullPath, Usage = ResourceUsage.Default, Binding = TextureBinding.ShaderResource }); } } } return(textureForSprite); } }
/// <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(); } }