/// <summary>
        /// Function to retrieve the name of the associated texture.
        /// </summary>
        /// <param name="stream">The stream containing the texture data.</param>
        /// <returns>The name of the texture associated with the sprite, or <b>null</b> if no texture was found.</returns>
        protected override string OnGetAssociatedTextureName(Stream stream)
        {
            GorgonChunkFileReader reader    = null;
            GorgonBinaryReader    binReader = null;

            try
            {
                reader = new GorgonChunkFileReader(stream, new[] { CurrentFileHeader });
                reader.Open();
                if (!IsReadableChunkFile(reader))
                {
                    return(null);
                }

                // No texture data in this file.
                if (!reader.Chunks.Contains(TextureData))
                {
                    return(null);
                }

                binReader = reader.OpenChunk(TextureData);
                string result = binReader.ReadString();
                reader.CloseChunk();

                return(result);
            }
            finally
            {
                binReader?.Dispose();
                reader?.Close();
            }
        }
Пример #2
0
        /// <summary>
        /// Function to determine if the data in a stream is readable by this codec.
        /// </summary>
        /// <param name="stream">The stream containing the data.</param>
        /// <returns><b>true</b> if the data can be read, or <b>false</b> if not.</returns>
        protected override bool OnIsReadable(Stream stream)
        {
            using (var reader = new GorgonBinaryReader(stream, true))
            {
                // If we don't have at least 10 bytes, then this file is not valid.
                if ((stream.Length - stream.Position) < 16)
                {
                    return(false);
                }

                string headerVersion = reader.ReadString();
                if ((!headerVersion.StartsWith("GORSPR", StringComparison.OrdinalIgnoreCase)) ||
                    (headerVersion.Length < 7) ||
                    (headerVersion.Length > 9))
                {
                    return(false);
                }

                // Get the version information.
                switch (headerVersion.ToUpperInvariant())
                {
                case "GORSPR1":
                case "GORSPR1.1":
                case "GORSPR1.2":
                    return(true);

                default:
                    return(false);
                }
            }
        }
Пример #3
0
 /// <summary>
 /// Function to read the sprite data from a stream.
 /// </summary>
 /// <param name="stream">The stream containing the sprite.</param>
 /// <param name="byteCount">The number of bytes to read from the stream.</param>
 /// <param name="overrideTexture">[Optional] The texture to assign to the sprite instead of the texture associated with the name stored in the file.</param>
 /// <returns>A new <see cref="GorgonSprite"/>.</returns>
 protected override GorgonSprite OnReadFromStream(Stream stream, int byteCount, GorgonTexture2DView overrideTexture)
 {
     using (var reader = new GorgonBinaryReader(stream, true))
     {
         // We don't need the byte count here.
         return(LoadSprite(Graphics, reader, overrideTexture));
     }
 }
        /// <summary>
        /// Function to load the texture information.
        /// </summary>
        /// <param name="reader">The reader containing the texture information.</param>
        /// <param name="overrideTexture">The texture to assign to the sprite instead of the texture associated with the name stored in the file.</param>
        /// <param name="textureOffset">The texture transform offset.</param>
        /// <param name="textureScale">The texture transform scale.</param>
        /// <param name="textureArrayIndex">The texture array index.</param>
        /// <returns>The texture attached to the sprite.</returns>
        private GorgonTexture2DView LoadTexture(GorgonBinaryReader reader, GorgonTexture2DView overrideTexture, out DX.Vector2 textureOffset, out DX.Vector2 textureScale, out int textureArrayIndex)
        {
            // Write out as much info about the texture as we can so we can look it up based on these values when loading.
            string textureName = reader.ReadString();

            textureOffset     = DX.Vector2.Zero;
            textureScale      = DX.Vector2.One;
            textureArrayIndex = 0;

            if (string.IsNullOrWhiteSpace(textureName))
            {
                return(null);
            }

            reader.ReadValue(out textureOffset);
            reader.ReadValue(out textureScale);
            reader.ReadValue(out textureArrayIndex);
            reader.ReadValue(out int textureWidth);
            reader.ReadValue(out int textureHeight);
            reader.ReadValue(out BufferFormat textureFormat);
            reader.ReadValue(out int textureArrayCount);
            reader.ReadValue(out int textureMipCount);

            GorgonTexture2D texture = null;

            // Locate the texture resource.
            if (overrideTexture == null)
            {
                texture = Renderer.Graphics.LocateResourcesByName <GorgonTexture2D>(textureName)
                          .FirstOrDefault(item => item.Width == textureWidth &&
                                          item.Height == textureHeight &&
                                          item.Format == textureFormat &&
                                          item.ArrayCount == textureArrayCount &&
                                          item.MipLevels == textureMipCount);

                if (texture == null)
                {
                    textureOffset     = DX.Vector2.Zero;
                    textureScale      = DX.Vector2.One;
                    textureArrayIndex = 0;
                    return(null);
                }
            }

            reader.ReadValue(out int viewArrayIndex);
            reader.ReadValue(out int viewArrayCount);
            reader.ReadValue(out int viewMipSlice);
            reader.ReadValue(out int viewMipCount);
            reader.ReadValue(out BufferFormat viewFormat);

            return(overrideTexture ?? texture.GetShaderResourceView(viewFormat, viewMipSlice, viewMipCount, viewArrayIndex, viewArrayCount));
        }
        /// <summary>
        /// Function to determine if the chunk file is a readable file.
        /// </summary>
        /// <param name="reader">The chunk file reader to use.</param>
        /// <returns><b>true</b> if the chunk file is readable, or <b>false</b> if not.</returns>
        private bool IsReadableChunkFile(GorgonChunkFileReader reader)
        {
            if ((!reader.Chunks.Contains(VersionData)) ||
                (!reader.Chunks.Contains(AnimationData)))
            {
                return(false);
            }

            using (GorgonBinaryReader binReader = reader.OpenChunk(VersionData))
            {
                var fileVersion = new Version(binReader.ReadByte(), binReader.ReadByte());
                reader.CloseChunk();

                return(Version.Equals(fileVersion));
            }
        }
Пример #6
0
        /// <summary>
        /// Function to determine if the data in a stream is readable by this codec.
        /// </summary>
        /// <param name="stream">The stream containing the data.</param>
        /// <returns><b>true</b> if the data can be read, or <b>false</b> if not.</returns>
        protected override bool OnIsReadable(Stream stream)
        {
            using (var reader = new GorgonBinaryReader(stream, true))
            {
                if ((stream.Length - stream.Position) < sizeof(ulong) * 2)
                {
                    return(false);
                }

                ulong chunkHeader = reader.ReadUInt64();
                // Skip the size, we don't need it.
                reader.ReadUInt32();
                ulong chunkFileData = reader.ReadUInt64();

                return((chunkHeader == FileHeader.ChunkID()) && (chunkFileData == SpriteDataChunk.ChunkID()));
            }
        }
Пример #7
0
        /// <summary>
        /// Function to retrieve the name of the associated texture.
        /// </summary>
        /// <param name="stream">The stream containing the texture data.</param>
        /// <returns>The name of the texture associated with the sprite, or <b>null</b> if no texture was found.</returns>
        protected override string OnGetAssociatedTextureName(Stream stream)
        {
            using (var reader = new GorgonBinaryReader(stream, true))
            {
                string headerVersion = reader.ReadString();
                if ((!headerVersion.StartsWith("GORSPR", StringComparison.OrdinalIgnoreCase)) ||
                    (headerVersion.Length < 7) ||
                    (headerVersion.Length > 9))
                {
                    return(null);
                }

                // Get the version information.
                switch (headerVersion.ToUpperInvariant())
                {
                case "GORSPR1":
                case "GORSPR1.1":
                case "GORSPR1.2":
                    break;

                default:
                    return(null);
                }

                // We don't need the sprite name.
                reader.ReadString();

                // Find out if we have an image.
                if (!reader.ReadBoolean())
                {
                    return(null);
                }

                reader.ReadBoolean();
                return(reader.ReadString());
            }
        }
        /// <summary>
        /// Function to read the animation data from a stream.
        /// </summary>
        /// <param name="stream">The stream containing the animation.</param>
        /// <param name="byteCount">The number of bytes to read from the stream.</param>
        /// <returns>A new <see cref="IGorgonAnimation"/>.</returns>
        protected override IGorgonAnimation OnReadFromStream(Stream stream, int byteCount)
        {
            var builder = new GorgonAnimationBuilder();

            var reader = new GorgonChunkFileReader(stream,
                                                   new[]
            {
                CurrentFileHeader
            });
            GorgonBinaryReader binReader = null;

            try
            {
                reader.Open();
                binReader = reader.OpenChunk(AnimationData);
                string name      = binReader.ReadString();
                float  length    = binReader.ReadSingle();
                bool   isLooped  = binReader.ReadBoolean();
                int    loopCount = binReader.ReadInt32();
                reader.CloseChunk();

                int keyCount;

                if (reader.Chunks.Contains(PositionData))
                {
                    binReader = reader.OpenChunk(PositionData);
                    builder.PositionInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyVector3> track = builder.EditPositions();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyVector3(binReader.ReadSingle(), binReader.ReadValue <DX.Vector3>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                if (reader.Chunks.Contains(ScaleData))
                {
                    binReader = reader.OpenChunk(ScaleData);
                    builder.ScaleInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyVector3> track = builder.EditScale();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyVector3(binReader.ReadSingle(), binReader.ReadValue <DX.Vector3>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                if (reader.Chunks.Contains(RotationData))
                {
                    binReader = reader.OpenChunk(RotationData);
                    builder.RotationInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyVector3> track = builder.EditRotation();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyVector3(binReader.ReadSingle(), binReader.ReadValue <DX.Vector3>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                if (reader.Chunks.Contains(SizeData))
                {
                    binReader = reader.OpenChunk(SizeData);
                    builder.SizeInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyVector3> track = builder.EditSize();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyVector3(binReader.ReadSingle(), binReader.ReadValue <DX.Vector3>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                if (reader.Chunks.Contains(BoundsData))
                {
                    binReader = reader.OpenChunk(BoundsData);
                    builder.RotationInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyRectangle> track = builder.EditRectangularBounds();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyRectangle(binReader.ReadSingle(), binReader.ReadValue <DX.RectangleF>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                if (reader.Chunks.Contains(ColorData))
                {
                    binReader = reader.OpenChunk(ColorData);
                    builder.RotationInterpolationMode(binReader.ReadValue <TrackInterpolationMode>());
                    keyCount = binReader.ReadInt32();

                    IGorgonTrackKeyBuilder <GorgonKeyGorgonColor> track = builder.EditColors();
                    for (int i = 0; i < keyCount; ++i)
                    {
                        track.SetKey(new GorgonKeyGorgonColor(binReader.ReadSingle(), binReader.ReadValue <GorgonColor>()));
                    }
                    track.EndEdit();
                    reader.CloseChunk();
                }

                IGorgonAnimation result;
                if (!reader.Chunks.Contains(TextureData))
                {
                    result           = builder.Build(name, length);
                    result.IsLooped  = isLooped;
                    result.LoopCount = loopCount;
                    return(result);
                }

                binReader = reader.OpenChunk(TextureData);
                keyCount  = binReader.ReadInt32();

                IGorgonTrackKeyBuilder <GorgonKeyTexture2D> textureTrack = builder.Edit2DTexture();
                for (int i = 0; i < keyCount; ++i)
                {
                    float time                  = binReader.ReadSingle();
                    byte  hasTexture            = binReader.ReadByte();
                    GorgonTexture2DView texture = null;
                    string textureName          = string.Empty;

                    if (hasTexture != 0)
                    {
                        texture = LoadTexture(binReader, out textureName);

                        if ((texture == null) && (string.IsNullOrWhiteSpace(textureName)))
                        {
                            Renderer.Log.Print("Attempted to load a texture from the data, but the texture was not in memory and the name is unknown.",
                                               LoggingLevel.Verbose);
                            continue;
                        }
                    }

                    if ((texture == null) && (hasTexture != 0))
                    {
                        textureTrack.SetKey(new GorgonKeyTexture2D(time, textureName, binReader.ReadValue <DX.RectangleF>(), binReader.ReadInt32()));
                    }
                    else
                    {
                        textureTrack.SetKey(new GorgonKeyTexture2D(time, texture, binReader.ReadValue <DX.RectangleF>(), binReader.ReadInt32()));
                    }
                }
                textureTrack.EndEdit();
                reader.CloseChunk();

                result           = builder.Build(name, length);
                result.IsLooped  = isLooped;
                result.LoopCount = loopCount;
                return(result);
            }
            finally
            {
                binReader?.Dispose();
                reader.Close();
            }
        }
Пример #9
0
        /// <summary>
        /// Function to load a version 1.x Gorgon sprite.
        /// </summary>
        /// <param name="graphics">The graphics interface used to create states.</param>
        /// <param name="reader">Binary reader to use to read in the data.</param>
        /// <param name="overrideTexture">The texture to assign to the sprite instead of the texture associated with the name stored in the file.</param>
        /// <returns>The sprite from the stream data.</returns>
        private static GorgonSprite LoadSprite(GorgonGraphics graphics, GorgonBinaryReader reader, GorgonTexture2DView overrideTexture)
        {
            Version version;
            string  imageName = string.Empty;

            string headerVersion = reader.ReadString();

            if ((!headerVersion.StartsWith("GORSPR", StringComparison.OrdinalIgnoreCase)) ||
                (headerVersion.Length < 7) ||
                (headerVersion.Length > 9))
            {
                throw new GorgonException(GorgonResult.CannotRead, Resources.GOR2DIO_ERR_INVALID_HEADER);
            }

            var sprite = new GorgonSprite();

            // Get the version information.
            switch (headerVersion.ToUpperInvariant())
            {
            case "GORSPR1":
                version = new Version(1, 0);
                break;

            case "GORSPR1.1":
                version = new Version(1, 1);
                break;

            case "GORSPR1.2":
                version = new Version(1, 2);
                break;

            default:
                throw new GorgonException(GorgonResult.CannotRead, string.Format(Resources.GOR2DIO_ERR_VERSION_MISMATCH, headerVersion));
            }

            // We don't need the sprite name.
            reader.ReadString();

            // Find out if we have an image.
            if (reader.ReadBoolean())
            {
                bool isRenderTarget = reader.ReadBoolean();

                imageName = reader.ReadString();

                // We won't be supporting reading render targets from sprites in this version.
                if (isRenderTarget)
                {
                    // Skip the target data.
                    reader.ReadInt32();
                    reader.ReadInt32();
                    reader.ReadInt32();
                    reader.ReadBoolean();
                    reader.ReadBoolean();
                }
            }

            // We don't use "inherited" values anymore.  But we need them because
            // the file doesn't include inherited data.
            bool InheritAlphaMaskFunction     = reader.ReadBoolean();
            bool InheritAlphaMaskValue        = reader.ReadBoolean();
            bool InheritBlending              = reader.ReadBoolean();
            bool InheritHorizontalWrapping    = reader.ReadBoolean();
            bool InheritSmoothing             = reader.ReadBoolean();
            bool InheritStencilCompare        = reader.ReadBoolean();
            bool InheritStencilEnabled        = reader.ReadBoolean();
            bool InheritStencilFailOperation  = reader.ReadBoolean();
            bool InheritStencilMask           = reader.ReadBoolean();
            bool InheritStencilPassOperation  = reader.ReadBoolean();
            bool InheritStencilReference      = reader.ReadBoolean();
            bool InheritStencilZFailOperation = reader.ReadBoolean();
            bool InheritVerticalWrapping      = reader.ReadBoolean();
            bool InheritDepthBias             = true;
            bool InheritDepthTestFunction     = true;
            bool InheritDepthWriteEnabled     = true;

            // Get version 1.1 fields.
            if ((version.Major == 1) && (version.Minor >= 1))
            {
                InheritDepthBias         = reader.ReadBoolean();
                InheritDepthTestFunction = reader.ReadBoolean();
                InheritDepthWriteEnabled = reader.ReadBoolean();
            }

            // Get the size of the sprite.
            sprite.Size = new DX.Size2F(reader.ReadSingle(), reader.ReadSingle());

            // Older versions of the sprite object used pixel space for their texture coordinates.  We will have to
            // fix up these coordinates into texture space once we have a texture loaded.  At this point, there's no guarantee
            // that the texture was loaded safely, so we'll have to defer it until later.
            // Also, older versions used the size the determine the area on the texture to cover.  So use the size to
            // get the texture bounds.
            var textureOffset = new DX.Vector2(reader.ReadSingle(), reader.ReadSingle());

            // Read the anchor.
            // Gorgon v3 anchors are relative, so we need to convert them based on our sprite size.
            sprite.Anchor = new DX.Vector2(reader.ReadSingle() / sprite.Size.Width, reader.ReadSingle() / sprite.Size.Height);

            // Get vertex offsets.
            sprite.CornerOffsets.UpperLeft  = new DX.Vector3(reader.ReadSingle(), reader.ReadSingle(), 0);
            sprite.CornerOffsets.UpperRight = new DX.Vector3(reader.ReadSingle(), reader.ReadSingle(), 0);
            sprite.CornerOffsets.LowerRight = new DX.Vector3(reader.ReadSingle(), reader.ReadSingle(), 0);
            sprite.CornerOffsets.LowerLeft  = new DX.Vector3(reader.ReadSingle(), reader.ReadSingle(), 0);

            // Get vertex colors.
            sprite.CornerColors.UpperLeft  = new GorgonColor(reader.ReadInt32());
            sprite.CornerColors.UpperRight = new GorgonColor(reader.ReadInt32());
            sprite.CornerColors.LowerLeft  = new GorgonColor(reader.ReadInt32());
            sprite.CornerColors.LowerRight = new GorgonColor(reader.ReadInt32());

            // Skip shader information.  Version 1.0 had shader information attached to the sprite.
            if ((version.Major == 1) && (version.Minor < 1))
            {
                if (reader.ReadBoolean())
                {
                    reader.ReadString();
                    reader.ReadBoolean();
                    if (reader.ReadBoolean())
                    {
                        reader.ReadString();
                    }
                }
            }

            // We no longer have an alpha mask function.
            if (!InheritAlphaMaskFunction)
            {
                reader.ReadInt32();
            }

            if (!InheritAlphaMaskValue)
            {
                // Direct 3D 9 used a value from 0..255 for alpha masking, we use
                // a scalar value so convert to a scalar.
                sprite.AlphaTest = new GorgonRangeF(0.0f, reader.ReadInt32() / 255.0f);
            }

            // Set the blending mode.
            if (!InheritBlending)
            {
                // Skip the blending mode.  We don't use it per-sprite.
                reader.ReadInt32();
                reader.ReadInt32();
                reader.ReadInt32();
            }

            // Get alpha blending mode.
            if ((version.Major == 1) && (version.Minor >= 2))
            {
                // Skip the blending mode information.  We don't use it per-sprite.
                reader.ReadInt32();
                reader.ReadInt32();
            }

            TextureWrap  hWrap         = TextureWrap.Clamp;
            TextureWrap  vWrap         = TextureWrap.Clamp;
            SampleFilter filter        = SampleFilter.MinMagMipLinear;
            GorgonColor  samplerBorder = GorgonColor.White;

            // Get horizontal wrapping mode.
            if (!InheritHorizontalWrapping)
            {
                hWrap = ConvertImageAddressToTextureAddress(reader.ReadInt32());
            }

            // Get smoothing mode.
            if (!InheritSmoothing)
            {
                filter = ConvertSmoothingToFilter(reader.ReadInt32());
            }

            // Get stencil stuff.
            if (!InheritStencilCompare)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }
            if (!InheritStencilEnabled)
            {
                // We don't enable stencil in the same way anymore, so skip this value.
                reader.ReadBoolean();
            }
            if (!InheritStencilFailOperation)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }
            if (!InheritStencilMask)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }
            if (!InheritStencilPassOperation)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }
            if (!InheritStencilReference)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }
            if (!InheritStencilZFailOperation)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }

            // Get vertical wrapping mode.
            if (!InheritVerticalWrapping)
            {
                vWrap = ConvertImageAddressToTextureAddress(reader.ReadInt32());
            }

            // Get depth info.
            if ((version.Major == 1) && (version.Minor >= 1))
            {
                if (!InheritDepthBias)
                {
                    // Depth bias values are quite different on D3D9 than they are on D3D11, so skip this.
                    reader.ReadSingle();
                }
                if (!InheritDepthTestFunction)
                {
                    // We don't use depth/stencil info per sprite anymore.
                    reader.ReadInt32();
                }
                if (!InheritDepthWriteEnabled)
                {
                    // We don't use depth/stencil info per sprite anymore.
                    reader.ReadBoolean();
                }

                samplerBorder = new GorgonColor(reader.ReadInt32());

                // The border in the older version defaults to black.  To make it more performant, reverse this value to white.
                if (samplerBorder == GorgonColor.Black)
                {
                    samplerBorder = GorgonColor.White;
                }
            }

            // Get flipped flags.
            sprite.HorizontalFlip = reader.ReadBoolean();
            sprite.VerticalFlip   = reader.ReadBoolean();

            GorgonTexture2DView textureView;

            // Bind the texture (if we have one bound to this sprite) if it's already loaded, otherwise defer it.
            if ((!string.IsNullOrEmpty(imageName)) && (overrideTexture == null))
            {
                GorgonTexture2D texture = graphics.LocateResourcesByName <GorgonTexture2D>(imageName).FirstOrDefault();
                textureView = texture?.GetShaderResourceView();
            }
            else
            {
                textureView = overrideTexture;
            }

            // If we cannot load the image, then fall back to the standard coordinates.
            if (textureView == null)
            {
                sprite.TextureRegion = new DX.RectangleF(0, 0, 1, 1);
            }
            else
            {
                sprite.TextureRegion = new DX.RectangleF(textureOffset.X / textureView.Width,
                                                         textureOffset.Y / textureView.Height,
                                                         sprite.Size.Width / textureView.Width,
                                                         sprite.Size.Height / textureView.Height);
                sprite.TextureSampler = CreateSamplerState(graphics, filter, samplerBorder, hWrap, vWrap);
            }

            sprite.Texture = textureView;

            return(sprite);
        }
        /// <summary>
        /// Function to read the sprite data from a stream.
        /// </summary>
        /// <param name="stream">The stream containing the sprite.</param>
        /// <param name="byteCount">The number of bytes to read from the stream.</param>
        /// <param name="overrideTexture">The texture to assign to the sprite instead of the texture associated with the name stored in the file.</param>
        /// <returns>A new <see cref="GorgonPolySprite"/>.</returns>
        protected override GorgonPolySprite OnReadFromStream(Stream stream, int byteCount, GorgonTexture2DView overrideTexture)
        {
            var reader = new GorgonChunkFileReader(stream,
                                                   new[]
            {
                CurrentFileHeader
            });
            GorgonBinaryReader binReader = null;
            var sprite = new GorgonPolySpriteBuilder(Renderer);

            try
            {
                reader.Open();
                binReader = reader.OpenChunk(SpriteData);
                sprite.Anchor(binReader.ReadValue <DX.Vector2>());

                // If we do not have alpha test information, then skip writing its data.
                if (binReader.ReadBoolean())
                {
                    sprite.AlphaTest(binReader.ReadValue <GorgonRangeF>());
                }

                reader.CloseChunk();

                binReader = reader.OpenChunk(VertexData);

                int vertexCount = binReader.ReadInt32();

                for (int i = 0; i < vertexCount; ++i)
                {
                    sprite.AddVertex(new GorgonPolySpriteVertex(binReader.ReadValue <DX.Vector2>(),
                                                                binReader.ReadValue <GorgonColor>(),
                                                                binReader.ReadValue <DX.Vector2>()));
                }

                reader.CloseChunk();

                if (reader.Chunks.Contains(TextureData))
                {
                    binReader = reader.OpenChunk(TextureData);
                    sprite.Texture(LoadTexture(binReader, overrideTexture, out DX.Vector2 textureOffset, out DX.Vector2 textureScale, out int textureArrayIndex));
                    sprite.TextureArrayIndex(textureArrayIndex);
                    sprite.TextureTransform(textureOffset, textureScale);
                    reader.CloseChunk();
                }

                if (!reader.Chunks.Contains(TextureSamplerData))
                {
                    return(sprite.Build());
                }

                var builder = new GorgonSamplerStateBuilder(Renderer.Graphics);
                binReader = reader.OpenChunk(TextureSamplerData);
                binReader.ReadValue(out SampleFilter filter);
                binReader.ReadValue(out GorgonColor borderColor);
                binReader.ReadValue(out Comparison compareFunc);
                binReader.ReadValue(out TextureWrap wrapU);
                binReader.ReadValue(out TextureWrap wrapV);
                binReader.ReadValue(out TextureWrap wrapW);
                binReader.ReadValue(out int maxAnisotropy);
                binReader.ReadValue(out float minLod);
                binReader.ReadValue(out float maxLod);
                binReader.ReadValue(out float mipLodBias);
                reader.CloseChunk();

                sprite.TextureSampler(builder.Wrapping(wrapU, wrapV, wrapW, borderColor)
                                      .Filter(filter)
                                      .ComparisonFunction(compareFunc)
                                      .MaxAnisotropy(maxAnisotropy)
                                      .MipLevelOfDetail(minLod, maxLod, mipLodBias)
                                      .Build());

                return(sprite.Build());
            }
            finally
            {
                binReader?.Dispose();
                reader.Close();
            }
        }
        /// <summary>
        /// Function to read the sprite data from a stream.
        /// </summary>
        /// <param name="stream">The stream containing the sprite.</param>
        /// <param name="byteCount">The number of bytes to read from the stream.</param>
        /// <param name="overrideTexture">The texture to assign to the sprite instead of the texture associated with the name stored in the file.</param>
        /// <returns>A new <see cref="GorgonSprite"/>.</returns>
        protected override GorgonSprite OnReadFromStream(Stream stream, int byteCount, GorgonTexture2DView overrideTexture)
        {
            var reader = new GorgonChunkFileReader(stream,
                                                   new[]
            {
                CurrentFileHeader
            });
            GorgonBinaryReader binReader = null;
            var sprite = new GorgonSprite();

            try
            {
                reader.Open();
                binReader     = reader.OpenChunk(SpriteData);
                sprite.Size   = binReader.ReadValue <DX.Size2F>();
                sprite.Anchor = binReader.ReadValue <DX.Vector2>();

                // If we do not have alpha test information, then skip writing its data.
                if (binReader.ReadBoolean())
                {
                    sprite.AlphaTest = binReader.ReadValue <GorgonRangeF>();
                }

                // Write out corner data.
                sprite.CornerOffsets.UpperLeft  = binReader.ReadValue <DX.Vector3>();
                sprite.CornerOffsets.UpperRight = binReader.ReadValue <DX.Vector3>();
                sprite.CornerOffsets.LowerLeft  = binReader.ReadValue <DX.Vector3>();
                sprite.CornerOffsets.LowerRight = binReader.ReadValue <DX.Vector3>();

                sprite.CornerColors.UpperLeft  = binReader.ReadValue <GorgonColor>();
                sprite.CornerColors.UpperRight = binReader.ReadValue <GorgonColor>();
                sprite.CornerColors.LowerLeft  = binReader.ReadValue <GorgonColor>();
                sprite.CornerColors.LowerRight = binReader.ReadValue <GorgonColor>();

                reader.CloseChunk();

                if (reader.Chunks.Contains(TextureData))
                {
                    binReader                = reader.OpenChunk(TextureData);
                    sprite.Texture           = LoadTexture(binReader, overrideTexture, out DX.RectangleF textureCoordinates, out int textureArrayIndex);
                    sprite.TextureRegion     = textureCoordinates;
                    sprite.TextureArrayIndex = textureArrayIndex;
                    reader.CloseChunk();
                }


                if (!reader.Chunks.Contains(TextureSamplerData))
                {
                    return(sprite);
                }

                var builder = new GorgonSamplerStateBuilder(Renderer.Graphics);
                binReader = reader.OpenChunk(TextureSamplerData);
                binReader.ReadValue(out SampleFilter filter);
                binReader.ReadValue(out GorgonColor borderColor);
                binReader.ReadValue(out Comparison compareFunc);
                binReader.ReadValue(out TextureWrap wrapU);
                binReader.ReadValue(out TextureWrap wrapV);
                binReader.ReadValue(out TextureWrap wrapW);
                binReader.ReadValue(out int maxAnisotropy);
                binReader.ReadValue(out float minLod);
                binReader.ReadValue(out float maxLod);
                binReader.ReadValue(out float mipLodBias);
                reader.CloseChunk();

                sprite.TextureSampler = builder.Wrapping(wrapU, wrapV, wrapW, borderColor)
                                        .Filter(filter)
                                        .ComparisonFunction(compareFunc)
                                        .MaxAnisotropy(maxAnisotropy)
                                        .MipLevelOfDetail(minLod, maxLod, mipLodBias)
                                        .Build();

                return(sprite);
            }
            finally
            {
                binReader?.Dispose();
                reader.Close();
            }
        }
        /// <summary>
        /// Function to skip the unnecessary parts of the file and move to the animation section.
        /// </summary>
        /// <param name="reader">The binary reader for the stream.</param>
        /// <param name="version">The version of the sprite.</param>
        private static void SkipToAnimationSection(GorgonBinaryReader reader, Version version)
        {
            // We don't need the sprite name.
            reader.ReadString();

            // Find out if we have an image.
            if (reader.ReadBoolean())
            {
                bool isRenderTarget = reader.ReadBoolean();
                reader.ReadString();

                // We won't be supporting reading render targets from sprites in this version.
                if (isRenderTarget)
                {
                    // Skip the target data.
                    for (int i = 0; i < 3; ++i)
                    {
                        reader.ReadInt32();
                    }

                    reader.ReadBoolean();
                    reader.ReadBoolean();
                }
            }

            // We don't use "inherited" values anymore.  But we need them because
            // the file doesn't include inherited data.
            bool InheritAlphaMaskFunction     = reader.ReadBoolean();
            bool InheritAlphaMaskValue        = reader.ReadBoolean();
            bool InheritBlending              = reader.ReadBoolean();
            bool InheritHorizontalWrapping    = reader.ReadBoolean();
            bool InheritSmoothing             = reader.ReadBoolean();
            bool InheritStencilCompare        = reader.ReadBoolean();
            bool InheritStencilEnabled        = reader.ReadBoolean();
            bool InheritStencilFailOperation  = reader.ReadBoolean();
            bool InheritStencilMask           = reader.ReadBoolean();
            bool InheritStencilPassOperation  = reader.ReadBoolean();
            bool InheritStencilReference      = reader.ReadBoolean();
            bool InheritStencilZFailOperation = reader.ReadBoolean();
            bool InheritVerticalWrapping      = reader.ReadBoolean();
            bool InheritDepthBias             = true;
            bool InheritDepthTestFunction     = true;
            bool InheritDepthWriteEnabled     = true;

            // Get version 1.1 fields.
            if ((version.Major == 1) && (version.Minor >= 1))
            {
                InheritDepthBias         = reader.ReadBoolean();
                InheritDepthTestFunction = reader.ReadBoolean();
                InheritDepthWriteEnabled = reader.ReadBoolean();
            }

            // Get the size of the sprite.
            for (int i = 0; i < 14; ++i)
            {
                reader.ReadSingle(); // 0
            }

            // Get vertex colors.
            for (int i = 0; i < 4; ++i)
            {
                reader.ReadInt32();
            }

            // Skip shader information.  Version 1.0 had shader information attached to the sprite.
            if ((version.Major == 1) && (version.Minor < 1))
            {
                if (reader.ReadBoolean())
                {
                    reader.ReadString();
                    reader.ReadBoolean();
                    if (reader.ReadBoolean())
                    {
                        reader.ReadString();
                    }
                }
            }

            // We no longer have an alpha mask function.
            if (!InheritAlphaMaskFunction)
            {
                reader.ReadInt32();
            }

            if (!InheritAlphaMaskValue)
            {
                // Direct 3D 9 used a value from 0..255 for alpha masking, we use
                // a scalar value so convert to a scalar.
                reader.ReadInt32();
            }

            // Set the blending mode.
            if (!InheritBlending)
            {
                // Skip the blending mode.  We don't use it per-sprite.
                for (int i = 0; i < 3; ++i)
                {
                    reader.ReadInt32();
                }
            }

            // Get alpha blending mode.
            if ((version.Major == 1) && (version.Minor >= 2))
            {
                // Skip the blending mode information.  We don't use it per-sprite.
                reader.ReadInt32();
                reader.ReadInt32();
            }

            // Get horizontal wrapping mode.
            if (!InheritHorizontalWrapping)
            {
                reader.ReadInt32();
            }

            // Get smoothing mode.
            if (!InheritSmoothing)
            {
                reader.ReadInt32();
            }

            // Get stencil stuff.
            if (!InheritStencilCompare)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }

            if (!InheritStencilEnabled)
            {
                // We don't enable stencil in the same way anymore, so skip this value.
                reader.ReadBoolean();
            }

            if (!InheritStencilFailOperation)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }

            if (!InheritStencilMask)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }

            if (!InheritStencilPassOperation)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }

            if (!InheritStencilReference)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }

            if (!InheritStencilZFailOperation)
            {
                // We don't use depth/stencil info per sprite anymore.
                reader.ReadInt32();
            }

            // Get vertical wrapping mode.
            if (!InheritVerticalWrapping)
            {
                reader.ReadInt32();
            }

            // Get depth info.
            if ((version.Major == 1) && (version.Minor >= 1))
            {
                if (!InheritDepthBias)
                {
                    // Depth bias values are quite different on D3D9 than they are on D3D11, so skip this.
                    reader.ReadSingle();
                }

                if (!InheritDepthTestFunction)
                {
                    // We don't use depth/stencil info per sprite anymore.
                    reader.ReadInt32();
                }

                if (!InheritDepthWriteEnabled)
                {
                    // We don't use depth/stencil info per sprite anymore.
                    reader.ReadBoolean();
                }

                reader.ReadInt32();
            }

            // Get flipped flags.
            reader.ReadBoolean();
            reader.ReadBoolean();
        }
 /// <summary>
 /// Function to read 2D vector data.
 /// </summary>
 /// <param name="reader">The reader containing the track data.</param>
 /// <param name="keyCount">The number of keys to read.</param>
 /// <returns>A list of track times and vector2 values.</returns>
 private static IReadOnlyList <(float time, DX.Vector2 value)> ReadVec2(GorgonBinaryReader reader, int keyCount)
 {
     var keys = new (float, DX.Vector2)[keyCount];