// ReSharper disable once InconsistentNaming /// <summary> /// Function to build our animation... like an 80's music video... this is going to be ugly. /// </summary> private static void MakeAn80sMusicVideo() { var animBuilder = new GorgonAnimationBuilder(); animBuilder.PositionInterpolationMode(TrackInterpolationMode.Spline) .ScaleInterpolationMode(TrackInterpolationMode.Spline) .RotationInterpolationMode(TrackInterpolationMode.Spline) .ColorInterpolationMode(TrackInterpolationMode.Spline) // Set up some scaling... .EditScale() .SetKey(new GorgonKeyVector3(0, new DX.Vector2(1, 1))) .SetKey(new GorgonKeyVector3(2, new DX.Vector2(0.5f, 0.5f))) .SetKey(new GorgonKeyVector3(4, new DX.Vector2(4.0f, 4.0f))) .SetKey(new GorgonKeyVector3(6, new DX.Vector2(1, 1))) .EndEdit() // Set up some positions... .EditPositions() .SetKey(new GorgonKeyVector3(0, new DX.Vector2(_screen.Width / 2.0f, _screen.Height / 2.0f))) .SetKey(new GorgonKeyVector3(2, new DX.Vector2(200, 220))) .SetKey(new GorgonKeyVector3(3, new DX.Vector2(_screen.Width - 2, 130))) .SetKey(new GorgonKeyVector3(4, new DX.Vector2(255, _screen.Height - _metal.Height))) .SetKey(new GorgonKeyVector3(5, new DX.Vector2(200, 180))) .SetKey(new GorgonKeyVector3(6, new DX.Vector2(180, 160))) .SetKey(new GorgonKeyVector3(7, new DX.Vector2(150, 180))) .SetKey(new GorgonKeyVector3(8, new DX.Vector2(150, 160))) .SetKey(new GorgonKeyVector3(9, new DX.Vector2(_screen.Width / 2, _screen.Height / 2))) .EndEdit() // Set up some colors...By changing the alpha, we can simulate a motion blur effect. .EditColors() .SetKey(new GorgonKeyGorgonColor(0, GorgonColor.Black)) .SetKey(new GorgonKeyGorgonColor(2, new GorgonColor(GorgonColor.RedPure, 0.25f))) .SetKey(new GorgonKeyGorgonColor(4, new GorgonColor(GorgonColor.GreenPure, 0.5f))) .SetKey(new GorgonKeyGorgonColor(6, new GorgonColor(GorgonColor.BluePure, 0.25f))) .SetKey(new GorgonKeyGorgonColor(8, new GorgonColor(GorgonColor.LightCyan, 0.25f))) .SetKey(new GorgonKeyGorgonColor(10, new GorgonColor(GorgonColor.Black, 1.0f))) .EndEdit() // And finally, some MuchMusic/MTV style rotation... because. .EditRotation() .SetKey(new GorgonKeyVector3(0, new DX.Vector3(0, 0, 0))) .SetKey(new GorgonKeyVector3(2, new DX.Vector3(0, 0, 180))) .SetKey(new GorgonKeyVector3(4, new DX.Vector3(0, 0, 270.0f))) .SetKey(new GorgonKeyVector3(6, new DX.Vector3(0, 0, 0))) .EndEdit(); IGorgonTrackKeyBuilder <GorgonKeyTexture2D> trackBuilder = animBuilder.Edit2DTexture(); float time = 0; // Now, add the animation frames from our GIF. for (int i = 0; i < _metal.ArrayCount; ++i) { trackBuilder.SetKey(new GorgonKeyTexture2D(time, _metal, new DX.RectangleF(0, 0, 1, 1), i)); time += _frameDelays[i]; } float delay = (10.0f - time).Max(0) / 15.0f; // Now add in a texture switch with coordinate update... because. trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.25f, 0.25f, 0.5f, 0.5f), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0, 0, 1, 1), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.25f, 0.25f, 0.5f, 0.5f), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0, 0, 1, 1), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.25f, 0.25f, 0.5f, 0.5f), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0, 0, 1, 1), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.25f, 0.25f, 0.5f, 0.5f), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0.125f, 0.125f, 0.75f, 0.75f), 0)); time += delay; trackBuilder.SetKey(new GorgonKeyTexture2D(time, _trooper, new DX.RectangleF(0, 0, 1, 1), 0)); trackBuilder.EndEdit(); _animation = animBuilder.Build(@"\m/"); _animation.IsLooped = true; _animController = new GorgonSpriteAnimationController(); }
/// <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); }