/// <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 convert a JSON formatted string into a <see cref="IGorgonAnimation"/> object. /// </summary> /// <param name="renderer">The renderer for the animation.</param> /// <param name="json">The JSON string containing the animation data.</param> /// <returns>A new <see cref="IGorgonAnimation"/>.</returns> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="renderer"/>, or the <paramref name="json"/> parameter is <b>null</b>.</exception> /// <exception cref="ArgumentEmptyException">Thrown when the <paramref name="json"/> parameter is empty.</exception> /// <exception cref="GorgonException">Thrown if the JSON string does not contain animation data, or there is a version mismatch.</exception> public IGorgonAnimation FromJson(Gorgon2D renderer, string json) { if (renderer == null) { throw new ArgumentNullException(nameof(renderer)); } if (json == null) { throw new ArgumentNullException(nameof(json)); } if (string.IsNullOrWhiteSpace(json)) { throw new ArgumentEmptyException(nameof(json)); } string animName = string.Empty; float animLength = 0; int loopCount = 0; bool isLooped = false; var colorConvert = new JsonGorgonColorKeyConverter(); var textureConvert = new JsonTextureKeyConverter(renderer.Graphics); var vec3Converter = new JsonVector3KeyConverter(); var rectConverter = new JsonRectKeyConverter(); TrackInterpolationMode posInterp = TrackInterpolationMode.None; TrackInterpolationMode scaleInterp = TrackInterpolationMode.None; TrackInterpolationMode rotInterp = TrackInterpolationMode.None; TrackInterpolationMode sizeInterp = TrackInterpolationMode.None; TrackInterpolationMode colorInterp = TrackInterpolationMode.None; TrackInterpolationMode boundInterp = TrackInterpolationMode.None; List <GorgonKeyVector3> positions = null; List <GorgonKeyVector3> rotations = null; List <GorgonKeyVector3> scales = null; List <GorgonKeyVector3> sizes = null; List <GorgonKeyGorgonColor> colors = null; List <GorgonKeyRectangle> bounds = null; List <GorgonKeyTexture2D> textures = null; using (var baseReader = new StringReader(json)) using (var reader = new JsonTextReader(baseReader)) { if (!IsReadableJObject(reader)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GOR2DIO_ERR_JSON_NOT_ANIM); } while (reader.Read()) { if (reader.TokenType != JsonToken.PropertyName) { continue; } string propName = reader.Value.ToString().ToUpperInvariant(); switch (propName) { case "POSITIONS": positions = ReadVector3(reader, vec3Converter, out posInterp); break; case "SCALES": scales = ReadVector3(reader, vec3Converter, out scaleInterp); break; case "ROTATIONS": rotations = ReadVector3(reader, vec3Converter, out rotInterp); break; case "SIZE": sizes = ReadVector3(reader, vec3Converter, out sizeInterp); break; case "BOUNDS": bounds = ReadRects(reader, rectConverter, out boundInterp); break; case "COLORS": colors = ReadColors(reader, colorConvert, out colorInterp); break; case "TEXTURES": textures = ReadTextures(reader, textureConvert); break; case "NAME": animName = reader.ReadAsString(); break; case "LENGTH": animLength = (float)(reader.ReadAsDecimal() ?? 0); break; case "ISLOOPED": isLooped = (reader.ReadAsBoolean() ?? false); break; case "LOOPCOUNT": loopCount = (reader.ReadAsInt32() ?? 0); break; } } } // There's no name, so it's a broken JSON. if (string.IsNullOrWhiteSpace(animName)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GOR2DIO_ERR_JSON_NOT_ANIM); } var builder = new GorgonAnimationBuilder(); if ((positions != null) && (positions.Count > 0)) { builder.PositionInterpolationMode(posInterp) .EditPositions() .SetKeys(positions) .EndEdit(); } if ((scales != null) && (scales.Count > 0)) { builder.ScaleInterpolationMode(scaleInterp) .EditScale() .SetKeys(scales) .EndEdit(); } if ((rotations != null) && (rotations.Count > 0)) { builder.RotationInterpolationMode(rotInterp) .EditRotation() .SetKeys(rotations) .EndEdit(); } if ((sizes != null) && (sizes.Count > 0)) { builder.SizeInterpolationMode(sizeInterp) .EditSize() .SetKeys(sizes) .EndEdit(); } if ((colors != null) && (colors.Count > 0)) { builder.ColorInterpolationMode(colorInterp) .EditColors() .SetKeys(colors) .EndEdit(); } if ((bounds != null) && (bounds.Count > 0)) { builder.RotationInterpolationMode(boundInterp) .EditRectangularBounds() .SetKeys(bounds) .EndEdit(); } if ((textures != null) && (textures.Count > 0)) { builder.Edit2DTexture() .SetKeys(textures) .EndEdit(); } IGorgonAnimation result = builder.Build(animName, animLength); result.LoopCount = loopCount; result.IsLooped = isLooped; result.Speed = 1.0f; return(result); }