/// <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(); } }
/// <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 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 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(); }