Skip to content

Commit

Permalink
Rework TransformSequence<> to be stack allocated
Browse files Browse the repository at this point in the history
  • Loading branch information
smoogipoo committed Oct 2, 2024
1 parent e4cbe94 commit ea22f19
Show file tree
Hide file tree
Showing 14 changed files with 440 additions and 512 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@ private void animate()

boxes[4].Delay(1000).Loop(1000, 10, b => b.RotateTo(0).RotateTo(340, 1000));

boxes[5].RotateTo(0).ScaleTo(1).RotateTo(360, 1000)
.Then(1000,
b => b.RotateTo(0, 1000),
b => b.ScaleTo(2, 500)
)
.Then().RotateTo(360, 1000).ScaleTo(0.5f, 1000)
.Then().FadeEdgeEffectTo(Color4.Red, 1000).ScaleTo(2, 500);

boxes[5].RotateTo(0).ScaleTo(1).RotateTo(360, 1000)
.Then(1000,
b => b.RotateTo(0, 1000),
Expand Down
8 changes: 4 additions & 4 deletions osu.Framework/Audio/IAdjustableAudioComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public static TransformSequence<T> TempoTo<T, TEasing>(this T component, double
public static TransformSequence<T> VolumeTo<T, TEasing>(this TransformSequence<T> sequence, double newVolume, double duration, TEasing easing)
where T : class, IAdjustableAudioComponent, IDrawable
where TEasing : IEasingFunction
=> sequence.Append(o => o.TransformBindableTo(o.Volume, newVolume, duration, easing));
=> sequence.Merge().With(sequence.Target.TransformBindableTo(sequence.Target.Volume, newVolume, duration, easing));

/// <summary>
/// Smoothly adjusts <see cref="IAdjustableAudioComponent.Balance"/> over time.
Expand All @@ -187,7 +187,7 @@ public static TransformSequence<T> VolumeTo<T, TEasing>(this TransformSequence<T
public static TransformSequence<T> BalanceTo<T, TEasing>(this TransformSequence<T> sequence, double newBalance, double duration, TEasing easing)
where T : class, IAdjustableAudioComponent, IDrawable
where TEasing : IEasingFunction
=> sequence.Append(o => o.TransformBindableTo(o.Balance, newBalance, duration, easing));
=> sequence.Merge().With(sequence.Target.TransformBindableTo(sequence.Target.Balance, newBalance, duration, easing));

/// <summary>
/// Smoothly adjusts <see cref="IAdjustableAudioComponent.Frequency"/> over time.
Expand All @@ -196,7 +196,7 @@ public static TransformSequence<T> BalanceTo<T, TEasing>(this TransformSequence<
public static TransformSequence<T> FrequencyTo<T, TEasing>(this TransformSequence<T> sequence, double newFrequency, double duration, TEasing easing)
where T : class, IAdjustableAudioComponent, IDrawable
where TEasing : IEasingFunction
=> sequence.Append(o => o.TransformBindableTo(o.Frequency, newFrequency, duration, easing));
=> sequence.Merge().With(sequence.Target.TransformBindableTo(sequence.Target.Frequency, newFrequency, duration, easing));

/// <summary>
/// Smoothly adjusts <see cref="IAdjustableAudioComponent.Tempo"/> over time.
Expand All @@ -205,7 +205,7 @@ public static TransformSequence<T> FrequencyTo<T, TEasing>(this TransformSequenc
public static TransformSequence<T> TempoTo<T, TEasing>(this TransformSequence<T> sequence, double newTempo, double duration, TEasing easing)
where T : class, IAdjustableAudioComponent, IDrawable
where TEasing : IEasingFunction
=> sequence.Append(o => o.TransformBindableTo(o.Tempo, newTempo, duration, easing));
=> sequence.Merge().With(sequence.Target.TransformBindableTo(sequence.Target.Tempo, newTempo, duration, easing));

#endregion
}
Expand Down
2 changes: 1 addition & 1 deletion osu.Framework/Graphics/Containers/ModelBackedDrawable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ private void finishLoad(DelayedLoadWrapper? wrapper)
// otherwise, we can hide the old wrapper instantaneously and leave a blank display
var hideTransforms = wrapper == null
? ApplyHideTransforms(lastWrapper)
: ((Drawable)lastWrapper)?.Delay(TransformDuration)?.Append(ApplyHideTransforms);
: ((Drawable)lastWrapper)?.Delay(TransformDuration).Merge().With(ApplyHideTransforms(lastWrapper));

// Expire the last wrapper after the front-most transform has completed (the last wrapper is assumed to be invisible by that point)
(showTransforms ?? hideTransforms)?.OnComplete(_ => lastWrapper?.Expire());
Expand Down
138 changes: 105 additions & 33 deletions osu.Framework/Graphics/TransformSequenceExtensions.cs

Large diffs are not rendered by default.

142 changes: 58 additions & 84 deletions osu.Framework/Graphics/TransformableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ public static TransformSequence<TThis> TransformTo<TThis, TValue>(this TThis t,
/// <param name="easing">The transform easing to be used for tweening.</param>
/// <param name="grouping">An optional grouping specification to be used when the same property may be touched by multiple transform types.</param>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<TThis> TransformTo<TThis, TValue, TEasing>(this TThis t, string propertyOrFieldName, TValue newValue, double duration, in TEasing easing, string grouping = null)
public static TransformSequence<TThis> TransformTo<TThis, TValue, TEasing>(this TThis t, string propertyOrFieldName, TValue newValue, double duration, in TEasing easing,
string grouping = null)
where TThis : class, ITransformable
where TEasing : IEasingFunction
=> t.TransformTo(t.MakeTransform(propertyOrFieldName, newValue, duration, easing, grouping));
Expand All @@ -61,13 +62,9 @@ public static TransformSequence<TThis> TransformTo<TThis, TValue, TEasing>(this
/// <param name="t">The <see cref="ITransformable"/> to apply the <see cref="Transform{TValue, T}"/> to.</param>
/// <param name="transform">The transform to use.</param>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<TThis> TransformTo<TThis>(this TThis t, Transform transform) where TThis : class, ITransformable
{
var result = new TransformSequence<TThis>(t);
result.Add(transform);
t.AddTransform(transform);
return result;
}
public static TransformSequence<TThis> TransformTo<TThis>(this TThis t, Transform transform)
where TThis : class, ITransformable
=> TransformSequence<TThis>.Create(t).Add(transform);

/// <summary>
/// Creates a <see cref="Transform{TValue, T}"/> for smoothly changing <paramref name="propertyOrFieldName"/>
Expand Down Expand Up @@ -103,7 +100,8 @@ public static Transform<TValue, DefaultEasingFunction, TThis> MakeTransform<TThi
/// <param name="easing">The transform easing to be used for tweening.</param>
/// <param name="grouping">An optional grouping specification to be used when the same property may be touched by multiple transform types.</param>
/// <returns>The resulting <see cref="Transform{TValue, T}"/>.</returns>
public static Transform<TValue, TEasing, TThis> MakeTransform<TThis, TEasing, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration, in TEasing easing, string grouping = null)
public static Transform<TValue, TEasing, TThis> MakeTransform<TThis, TEasing, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration, in TEasing easing,
string grouping = null)
where TThis : class, ITransformable
where TEasing : IEasingFunction
=> t.PopulateTransform(new TransformCustom<TValue, TEasing, TThis>(propertyOrFieldName, grouping), newValue, duration, easing);
Expand Down Expand Up @@ -177,108 +175,43 @@ static bool isFinite(TValue value)
}
}

/// <summary>
/// Applies <paramref name="childGenerators"/> via TransformSequence.Append(IEnumerable{Generator})/>.
/// </summary>
/// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam>
/// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param>
/// <param name="childGenerators">The optional Generators for <see cref="TransformSequence{T}"/>s to be appended.</param>
/// <returns>This <see cref="TransformSequence{T}"/>.</returns>
public static TransformSequence<T> Animate<T>(this T transformable, params TransformSequence<T>.Generator[] childGenerators) where T : class, ITransformable =>
transformable.Delay(0, childGenerators);

/// <summary>
/// Advances the start time of future appended <see cref="TransformSequence{T}"/>s by <paramref name="delay"/> milliseconds.
/// Then, <paramref name="childGenerators"/> are appended via TransformSequence.Append(IEnumerable{Generator})/>.
/// </summary>
/// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam>
/// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param>
/// <param name="delay">The delay to advance the start time by.</param>
/// <param name="childGenerators">The optional Generators for <see cref="TransformSequence{T}"/>s to be appended.</param>
/// <returns>This <see cref="TransformSequence{T}"/>.</returns>
public static TransformSequence<T> Delay<T>(this T transformable, double delay, params TransformSequence<T>.Generator[] childGenerators) where T : class, ITransformable =>
new TransformSequence<T>(transformable).Delay(delay, childGenerators);
public static TransformSequence<T> Delay<T>(this T transformable, double delay) where T : class, ITransformable
=> TransformSequence<T>.Create(transformable).Delay(delay);

/// <summary>
/// Returns a <see cref="TransformSequence{T}"/> which waits for all existing transforms to finish.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> which has a delay waiting for all transforms to be completed.</returns>
public static TransformSequence<T> DelayUntilTransformsFinished<T>(this T transformable)
where T : Transformable =>
transformable.Delay(Math.Max(0, transformable.LatestTransformEndTime - transformable.Time.Current));

/// <summary>
/// Append a looping <see cref="TransformSequence{T}"/> to this <see cref="TransformSequence{T}"/>.
/// All <see cref="Transform"/>s generated by <paramref name="childGenerators"/> are appended to
/// this <see cref="TransformSequence{T}"/> and then repeated <paramref name="numIters"/> times
/// with <paramref name="pause"/> milliseconds between iterations.
/// </summary>
/// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam>
/// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param>
/// <param name="pause">The pause between iterations in milliseconds.</param>
/// <param name="numIters">The number of iterations.</param>
/// <param name="childGenerators">The functions to generate the <see cref="TransformSequence{T}"/>s to be looped.</param>
/// <returns>This <see cref="TransformSequence{T}"/>.</returns>
public static TransformSequence<T> Loop<T>(this T transformable, double pause, int numIters, params TransformSequence<T>.Generator[] childGenerators)
where T : class, ITransformable =>
transformable.Delay(0).Loop(pause, numIters, childGenerators);

/// <summary>
/// Append a looping <see cref="TransformSequence{T}"/> to this <see cref="TransformSequence{T}"/>.
/// All <see cref="Transform"/>s generated by <paramref name="childGenerators"/> are appended to
/// this <see cref="TransformSequence{T}"/> and then repeated indefinitely with <paramref name="pause"/>
/// milliseconds between iterations.
/// </summary>
/// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam>
/// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param>
/// <param name="pause">The pause between iterations in milliseconds.</param>
/// <param name="childGenerators">The functions to generate the <see cref="TransformSequence{T}"/>s to be looped.</param>
/// <returns>This <see cref="TransformSequence{T}"/>.</returns>
public static TransformSequence<T> Loop<T>(this T transformable, double pause, params TransformSequence<T>.Generator[] childGenerators)
where T : class, ITransformable =>
transformable.Delay(0).Loop(pause, childGenerators);

/// <summary>
/// Append a looping <see cref="TransformSequence{T}"/> to this <see cref="TransformSequence{T}"/>.
/// All <see cref="Transform"/>s generated by <paramref name="childGenerators"/> are appended to
/// this <see cref="TransformSequence{T}"/> and then repeated indefinitely.
/// milliseconds between iterations.
/// </summary>
/// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam>
/// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param>
/// <param name="childGenerators">The functions to generate the <see cref="TransformSequence{T}"/>s to be looped.</param>
/// <returns>This <see cref="TransformSequence{T}"/>.</returns>
public static TransformSequence<T> Loop<T>(this T transformable, params TransformSequence<T>.Generator[] childGenerators)
where T : class, ITransformable =>
transformable.Delay(0).Loop(childGenerators);

/// <summary>
/// Append a looping <see cref="TransformSequence{T}"/> to this <see cref="TransformSequence{T}"/> to repeat indefinitely with <paramref name="pause"/>
/// milliseconds between iterations.
/// </summary>
/// <typeparam name="T">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam>
/// <param name="transformable">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param>
/// <param name="pause">The pause between iterations in milliseconds.</param>
/// <returns>This <see cref="TransformSequence{T}"/>.</returns>
public static TransformSequence<T> Loop<T>(this T transformable, double pause = 0)
where T : class, ITransformable =>
transformable.Delay(0).Loop(pause);
where T : Transformable
=> transformable.Delay(Math.Max(0, transformable.LatestTransformEndTime - transformable.Time.Current));

/// <summary>
/// Rotate over one full rotation with provided parameters.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> Spin<T>(this T drawable, double revolutionDuration, RotationDirection direction, float startRotation = 0)
where T : Drawable
=> drawable.Delay(0).Spin(revolutionDuration, direction, startRotation);
=> drawable.RotateTo(startRotation)
.RotateTo(startRotation + (direction == RotationDirection.Clockwise ? 360 : -360), revolutionDuration)
.Loop(0, -1);

/// <summary>
/// Rotate <paramref name="numRevolutions"/> times with provided parameters.
/// </summary>
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
public static TransformSequence<T> Spin<T>(this T drawable, double revolutionDuration, RotationDirection direction, float startRotation, int numRevolutions)
where T : Drawable
=> drawable.Delay(0).Spin(revolutionDuration, direction, startRotation, numRevolutions);
=> drawable.RotateTo(startRotation)
.RotateTo(startRotation + (direction == RotationDirection.Clockwise ? 360 : -360), revolutionDuration)
.Loop(0, numRevolutions);

#region Easing

Expand Down Expand Up @@ -774,6 +707,47 @@ public static TransformSequence<T> TransformBindableTo<T, TValue, TEasing>(this

#endregion

#region Compatibility

[Obsolete("For compatibility use only, replacement: X.Y().Z()")]
public static TransformSequence<T> Animate<T>(this T transformable, params TransformSequence<T>.Generator[] childGenerators)
where T : Drawable
{
// Create the inner sequence.
TransformSequence<T> inner = TransformSequence<T>.Create(transformable);
foreach (var gen in childGenerators)
inner = inner.Merge().With(gen(transformable));

// Return an empty outer sequence - inner sequence is hidden.
return TransformSequence<T>.Create(transformable);
}

[Obsolete("For compatibility use only, replacement: X.Y().Z().Loop(pause, numIters)")]
public static TransformSequence<T> Loop<T>(this T transformable, double pause, int numIters, params TransformSequence<T>.Generator[] childGenerators)
where T : Drawable
{
// Create the inner sequence.
TransformSequence<T> sequence = TransformSequence<T>.Create(transformable);
foreach (var gen in childGenerators)
sequence = sequence.Merge().With(gen(transformable));
sequence.Loop(pause, numIters);

// Return an empty outer sequence - inner sequence is hidden.
return TransformSequence<T>.Create(transformable);
}

[Obsolete("For compatibility use only, replacement: X.Y().Z().Loop(pause)")]
public static TransformSequence<T> Loop<T>(this T transformable, double pause, params TransformSequence<T>.Generator[] childGenerators)
where T : Drawable
=> transformable.Loop(pause, -1, childGenerators);

[Obsolete("For compatibility use only, replacement: X.Y().Z().Loop()")]
public static TransformSequence<T> Loop<T>(this T transformable, params TransformSequence<T>.Generator[] childGenerators)
where T : Drawable
=> transformable.Loop(0, -1, childGenerators);

#endregion

private class PositionOffsetTransform<TEasing> : Transform<Vector2, TEasing, Drawable>
where TEasing : IEasingFunction
{
Expand Down
11 changes: 0 additions & 11 deletions osu.Framework/Graphics/Transforms/ITransformSequence.cs

This file was deleted.

9 changes: 8 additions & 1 deletion osu.Framework/Graphics/Transforms/ITransformable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Timing;

Expand Down Expand Up @@ -33,8 +34,14 @@ public interface ITransformable

double TransformStartTime { get; }

void AddTransform(Transform transform, ulong? customTransformID = null);
void AddTransform(Transform transform);

void RemoveTransform(Transform toRemove);

internal void RemoveTransformNoAbort(Transform toRemove);

IEnumerable<Transform> GetTransforms();

TransformSequenceEventHandler? GetTransformEventHandler(Guid? sequenceId);
}
}
Loading

0 comments on commit ea22f19

Please sign in to comment.