From 81d0b42930426bddb6793411ae9dce234fbd9c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 21 Nov 2020 19:51:27 +0100 Subject: [PATCH 1/3] Add failing test case --- .../Skinning/LegacySkinAnimationTest.cs | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs new file mode 100644 index 0000000000..509e2fe8ca --- /dev/null +++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs @@ -0,0 +1,79 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Animations; +using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Textures; +using osu.Framework.Testing; +using osu.Framework.Timing; +using osu.Game.Audio; +using osu.Game.Skinning; +using osu.Game.Tests.Visual; + +namespace osu.Game.Tests.NonVisual.Skinning +{ + [HeadlessTest] + public class LegacySkinAnimationTest : OsuTestScene + { + private const string animation_name = "animation"; + private const int frame_count = 6; + + [Cached(typeof(IAnimationTimeReference))] + private TestAnimationTimeReference animationTimeReference = new TestAnimationTimeReference(); + + private TextureAnimation animation; + + [Test] + public void TestAnimationTimeReferenceChange() + { + ISkin skin = new TestSkin(); + + AddStep("get animation", () => Add(animation = (TextureAnimation)skin.GetAnimation(animation_name, true, false))); + AddAssert("frame count correct", () => animation.FrameCount == frame_count); + assertPlaybackPosition(0); + + AddStep("set start time to 1000", () => animationTimeReference.AnimationStartTime = 1000); + assertPlaybackPosition(-1000); + + AddStep("set current time to 500", () => animationTimeReference.ManualClock.CurrentTime = 500); + assertPlaybackPosition(-500); + } + + private void assertPlaybackPosition(double expectedPosition) + => AddAssert($"playback position is {expectedPosition}", () => animation.PlaybackPosition == expectedPosition); + + private class TestSkin : ISkin + { + private static readonly string[] lookup_names = Enumerable.Range(0, frame_count).Select(frame => $"{animation_name}-{frame}").ToArray(); + + public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) + { + return lookup_names.Contains(componentName) ? Texture.WhitePixel : null; + } + + public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException(); + public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException(); + public IBindable GetConfig(TLookup lookup) => throw new NotSupportedException(); + } + + private class TestAnimationTimeReference : IAnimationTimeReference + { + public ManualClock ManualClock { get; } + public IFrameBasedClock Clock { get; } + public double AnimationStartTime { get; set; } + + public TestAnimationTimeReference() + { + ManualClock = new ManualClock(); + Clock = new FramedClock(ManualClock); + } + } + } +} From 240c1b0aef9b24162acb488bece8b5bc988c2fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 21 Nov 2020 20:06:30 +0100 Subject: [PATCH 2/3] Add support for changing animation start time after load --- .../Objects/Drawables/Connections/FollowPoint.cs | 4 +++- .../Connections/FollowPointConnection.cs | 2 +- .../NonVisual/Skinning/LegacySkinAnimationTest.cs | 5 +++-- osu.Game/Skinning/IAnimationTimeReference.cs | 3 ++- osu.Game/Skinning/LegacySkinExtensions.cs | 15 ++++++++++++++- 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs index 3e2ab65bb2..be274131c0 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Bindables; using osuTK; using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions; @@ -47,6 +48,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections }); } - public double AnimationStartTime { get; set; } + public Bindable AnimationStartTime { get; } = new BindableDouble(); + IBindable IAnimationTimeReference.AnimationStartTime => AnimationStartTime; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs index 700d96eff3..6e7b1050cb 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs @@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections fp.Alpha = 0; fp.Scale = new Vector2(1.5f * end.Scale); - fp.AnimationStartTime = fadeInTime; + fp.AnimationStartTime.Value = fadeInTime; using (fp.BeginAbsoluteSequence(fadeInTime)) { diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs index 509e2fe8ca..f05938cb39 100644 --- a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs +++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tests.NonVisual.Skinning AddAssert("frame count correct", () => animation.FrameCount == frame_count); assertPlaybackPosition(0); - AddStep("set start time to 1000", () => animationTimeReference.AnimationStartTime = 1000); + AddStep("set start time to 1000", () => animationTimeReference.AnimationStartTime.Value = 1000); assertPlaybackPosition(-1000); AddStep("set current time to 500", () => animationTimeReference.ManualClock.CurrentTime = 500); @@ -67,7 +67,8 @@ namespace osu.Game.Tests.NonVisual.Skinning { public ManualClock ManualClock { get; } public IFrameBasedClock Clock { get; } - public double AnimationStartTime { get; set; } + public Bindable AnimationStartTime { get; } = new BindableDouble(); + IBindable IAnimationTimeReference.AnimationStartTime => AnimationStartTime; public TestAnimationTimeReference() { diff --git a/osu.Game/Skinning/IAnimationTimeReference.cs b/osu.Game/Skinning/IAnimationTimeReference.cs index 7e52bb8176..c987372f4b 100644 --- a/osu.Game/Skinning/IAnimationTimeReference.cs +++ b/osu.Game/Skinning/IAnimationTimeReference.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Timing; @@ -25,6 +26,6 @@ namespace osu.Game.Skinning /// /// The time which animations should be started from, relative to . /// - double AnimationStartTime { get; } + IBindable AnimationStartTime { get; } } } diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs index 0ee02a2442..b57852847c 100644 --- a/osu.Game/Skinning/LegacySkinExtensions.cs +++ b/osu.Game/Skinning/LegacySkinExtensions.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.OpenGL.Textures; @@ -70,6 +71,8 @@ namespace osu.Game.Skinning [Resolved(canBeNull: true)] private IAnimationTimeReference timeReference { get; set; } + private readonly Bindable animationStartTime = new BindableDouble(); + public SkinnableTextureAnimation(bool startAtCurrentTime = true) : base(startAtCurrentTime) { @@ -82,8 +85,18 @@ namespace osu.Game.Skinning if (timeReference != null) { Clock = timeReference.Clock; - PlaybackPosition = timeReference.Clock.CurrentTime - timeReference.AnimationStartTime; + ((IBindable)animationStartTime).BindTo(timeReference.AnimationStartTime); } + + animationStartTime.BindValueChanged(_ => updatePlaybackPosition(), true); + } + + private void updatePlaybackPosition() + { + if (timeReference == null) + return; + + PlaybackPosition = timeReference.Clock.CurrentTime - timeReference.AnimationStartTime.Value; } } From 1c31a4a6b6513a97ad91ae47a094be35aea41f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Nov 2020 13:11:22 +0100 Subject: [PATCH 3/3] Expose animation start time as mutable in interface --- .../Objects/Drawables/Connections/FollowPoint.cs | 1 - osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs | 1 - osu.Game/Skinning/IAnimationTimeReference.cs | 2 +- osu.Game/Skinning/LegacySkinExtensions.cs | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs index be274131c0..b989500066 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs @@ -49,6 +49,5 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections } public Bindable AnimationStartTime { get; } = new BindableDouble(); - IBindable IAnimationTimeReference.AnimationStartTime => AnimationStartTime; } } diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs index f05938cb39..a5c937119e 100644 --- a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs +++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs @@ -68,7 +68,6 @@ namespace osu.Game.Tests.NonVisual.Skinning public ManualClock ManualClock { get; } public IFrameBasedClock Clock { get; } public Bindable AnimationStartTime { get; } = new BindableDouble(); - IBindable IAnimationTimeReference.AnimationStartTime => AnimationStartTime; public TestAnimationTimeReference() { diff --git a/osu.Game/Skinning/IAnimationTimeReference.cs b/osu.Game/Skinning/IAnimationTimeReference.cs index c987372f4b..f627379a57 100644 --- a/osu.Game/Skinning/IAnimationTimeReference.cs +++ b/osu.Game/Skinning/IAnimationTimeReference.cs @@ -26,6 +26,6 @@ namespace osu.Game.Skinning /// /// The time which animations should be started from, relative to . /// - IBindable AnimationStartTime { get; } + Bindable AnimationStartTime { get; } } } diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs index b57852847c..a7c084998d 100644 --- a/osu.Game/Skinning/LegacySkinExtensions.cs +++ b/osu.Game/Skinning/LegacySkinExtensions.cs @@ -85,7 +85,7 @@ namespace osu.Game.Skinning if (timeReference != null) { Clock = timeReference.Clock; - ((IBindable)animationStartTime).BindTo(timeReference.AnimationStartTime); + animationStartTime.BindTo(timeReference.AnimationStartTime); } animationStartTime.BindValueChanged(_ => updatePlaybackPosition(), true);