A game framework written with osu! in mind.

Add generic easing to transforms

+111 -32
+7 -5
osu.Framework/Graphics/MarginPadding.cs
··· 3 3 4 4 using osuTK; 5 5 using System; 6 + using osu.Framework.Graphics.Transforms; 6 7 using osu.Framework.Utils; 7 8 8 9 namespace osu.Framework.Graphics ··· 94 95 Bottom = -mp.Bottom, 95 96 }; 96 97 97 - public MarginPadding ValueAt(double time, MarginPadding startValue, MarginPadding endValue, double startTime, double endTime, Easing easingType) 98 + public MarginPadding ValueAt<TEasing>(double time, MarginPadding startValue, MarginPadding endValue, double startTime, double endTime, in TEasing easing) 99 + where TEasing : IEasingFunction 98 100 => new MarginPadding 99 101 { 100 - Left = Interpolation.ValueAt(time, startValue.Left, endValue.Left, startTime, endTime, easingType), 101 - Top = Interpolation.ValueAt(time, startValue.Top, endValue.Top, startTime, endTime, easingType), 102 - Right = Interpolation.ValueAt(time, startValue.Right, endValue.Right, startTime, endTime, easingType), 103 - Bottom = Interpolation.ValueAt(time, startValue.Bottom, endValue.Bottom, startTime, endTime, easingType), 102 + Left = Interpolation.ValueAt(time, startValue.Left, endValue.Left, startTime, endTime, easing), 103 + Top = Interpolation.ValueAt(time, startValue.Top, endValue.Top, startTime, endTime, easing), 104 + Right = Interpolation.ValueAt(time, startValue.Right, endValue.Right, startTime, endTime, easing), 105 + Bottom = Interpolation.ValueAt(time, startValue.Bottom, endValue.Bottom, startTime, endTime, easing), 104 106 }; 105 107 } 106 108 }
+66 -9
osu.Framework/Graphics/TransformableExtensions.cs
··· 29 29 /// <param name="easing">The transform easing to be used for tweening.</param> 30 30 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 31 31 public static TransformSequence<TThis> TransformTo<TThis, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration = 0, Easing easing = Easing.None) 32 - where TThis : class, ITransformable => 33 - t.TransformTo(t.MakeTransform(propertyOrFieldName, newValue, duration, easing)); 32 + where TThis : class, ITransformable 33 + => t.TransformTo(t.MakeTransform(propertyOrFieldName, newValue, duration, new DefaultEasingFunction(easing))); 34 + 35 + /// <summary> 36 + /// Transforms a given property or field member of a given <see cref="ITransformable"/> <typeparamref name="TThis"/> to <paramref name="newValue"/>. 37 + /// The value of the given member is smoothly changed over time using the given <paramref name="easing"/> for tweening. 38 + /// </summary> 39 + /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> to apply the <see cref="Transform{TValue, T}"/> to.</typeparam> 40 + /// <typeparam name="TValue">The value type which is being transformed.</typeparam> 41 + /// <typeparam name="TEasing">The type of easing.</typeparam> 42 + /// <param name="t">The <see cref="ITransformable"/> to apply the <see cref="Transform{TValue, T}"/> to.</param> 43 + /// <param name="propertyOrFieldName">The property or field name of the member ot <typeparamref name="TThis"/> to transform.</param> 44 + /// <param name="newValue">The value to transform to.</param> 45 + /// <param name="duration">The transform duration.</param> 46 + /// <param name="easing">The transform easing to be used for tweening.</param> 47 + /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 48 + public static TransformSequence<TThis> TransformTo<TThis, TValue, TEasing>(this TThis t, string propertyOrFieldName, TValue newValue, double duration, TEasing easing) 49 + where TThis : class, ITransformable 50 + where TEasing : IEasingFunction 51 + => t.TransformTo(t.MakeTransform(propertyOrFieldName, newValue, duration, easing)); 34 52 35 53 /// <summary> 36 54 /// Applies a <see cref="Transform"/> to a given <see cref="ITransformable"/>. ··· 50 68 /// <summary> 51 69 /// Creates a <see cref="Transform{TValue, T}"/> for smoothly changing <paramref name="propertyOrFieldName"/> 52 70 /// over time using the given <paramref name="easing"/> for tweening. 53 - /// <see cref="PopulateTransform{TValue, TThis}(TThis, Transform{TValue, TThis}, TValue, double, Easing)"/> 54 - /// is invoked as part of this method. 71 + /// <see cref="PopulateTransform{TValue, DefaultEasingFunction, TThis}"/> is invoked as part of this method. 72 + /// </summary> 73 + /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 74 + /// <typeparam name="TValue">The value type which is being transformed.</typeparam> 75 + /// <param name="t">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 76 + /// <param name="propertyOrFieldName">The property or field name of the member ot <typeparamref name="TThis"/> to transform.</param> 77 + /// <param name="newValue">The value to transform to.</param> 78 + /// <param name="duration">The transform duration.</param> 79 + /// <param name="easing">The transform easing to be used for tweening.</param> 80 + /// <returns>The resulting <see cref="Transform{TValue, T}"/>.</returns> 81 + public static Transform<TValue, DefaultEasingFunction, TThis> MakeTransform<TThis, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration = 0, 82 + Easing easing = Easing.None) 83 + where TThis : class, ITransformable 84 + => t.MakeTransform(propertyOrFieldName, newValue, duration, new DefaultEasingFunction(easing)); 85 + 86 + /// <summary> 87 + /// Creates a <see cref="Transform{TValue, T}"/> for smoothly changing <paramref name="propertyOrFieldName"/> 88 + /// over time using the given <paramref name="easing"/> for tweening. 89 + /// <see cref="PopulateTransform{TValue, TEasing, TThis}"/> is invoked as part of this method. 55 90 /// </summary> 56 91 /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 57 92 /// <typeparam name="TValue">The value type which is being transformed.</typeparam> 93 + /// <typeparam name="TEasing">The type of easing.</typeparam> 58 94 /// <param name="t">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 59 95 /// <param name="propertyOrFieldName">The property or field name of the member ot <typeparamref name="TThis"/> to transform.</param> 60 96 /// <param name="newValue">The value to transform to.</param> 61 97 /// <param name="duration">The transform duration.</param> 62 98 /// <param name="easing">The transform easing to be used for tweening.</param> 63 99 /// <returns>The resulting <see cref="Transform{TValue, T}"/>.</returns> 64 - public static Transform<TValue, TThis> MakeTransform<TThis, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration = 0, Easing easing = Easing.None) 65 - where TThis : class, ITransformable => 66 - t.PopulateTransform(new TransformCustom<TValue, TThis>(propertyOrFieldName), newValue, duration, easing); 100 + public static Transform<TValue, TEasing, TThis> MakeTransform<TThis, TEasing, TValue>(this TThis t, string propertyOrFieldName, TValue newValue, double duration, TEasing easing) 101 + where TThis : class, ITransformable 102 + where TEasing : IEasingFunction 103 + => t.PopulateTransform(new TransformCustom<TValue, TEasing, TThis>(propertyOrFieldName), newValue, duration, easing); 67 104 68 105 /// <summary> 69 106 /// Populates a newly created <see cref="Transform{TValue, T}"/> with necessary values. ··· 77 114 /// <param name="duration">The transform duration.</param> 78 115 /// <param name="easing">The transform easing to be used for tweening.</param> 79 116 /// <returns>The populated <paramref name="transform"/>.</returns> 80 - public static Transform<TValue, TThis> PopulateTransform<TValue, TThis>(this TThis t, Transform<TValue, TThis> transform, TValue newValue, double duration = 0, Easing easing = Easing.None) 117 + public static Transform<TValue, DefaultEasingFunction, TThis> PopulateTransform<TValue, TThis>(this TThis t, Transform<TValue, DefaultEasingFunction, TThis> transform, TValue newValue, 118 + double duration = 0, Easing easing = Easing.None) 81 119 where TThis : class, ITransformable 120 + => t.PopulateTransform(transform, newValue, duration, new DefaultEasingFunction(easing)); 121 + 122 + /// <summary> 123 + /// Populates a newly created <see cref="Transform{TValue, T}"/> with necessary values. 124 + /// All <see cref="Transform{TValue, T}"/>s must be populated by this method prior to being used. 125 + /// </summary> 126 + /// <typeparam name="TThis">The type of the <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> can be applied to.</typeparam> 127 + /// <typeparam name="TValue">The value type which is being transformed.</typeparam> 128 + /// <typeparam name="TEasing">The type of easing.</typeparam> 129 + /// <param name="t">The <see cref="ITransformable"/> the <see cref="Transform{TValue, T}"/> will be applied to.</param> 130 + /// <param name="transform">The transform to populate.</param> 131 + /// <param name="newValue">The value to transform to.</param> 132 + /// <param name="duration">The transform duration.</param> 133 + /// <param name="easing">The transform easing to be used for tweening.</param> 134 + /// <returns>The populated <paramref name="transform"/>.</returns> 135 + public static Transform<TValue, TEasing, TThis> PopulateTransform<TValue, TEasing, TThis>(this TThis t, Transform<TValue, TEasing, TThis> transform, TValue newValue, double duration, 136 + TEasing easing) 137 + where TThis : class, ITransformable 138 + where TEasing : IEasingFunction 82 139 { 83 140 if (duration < 0) 84 141 throw new ArgumentOutOfRangeException(nameof(duration), $"{nameof(duration)} must be positive."); ··· 415 472 /// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns> 416 473 public static TransformSequence<T> TransformBindableTo<T, TValue>(this T drawable, [NotNull] Bindable<TValue> bindable, TValue newValue, double duration = 0, Easing easing = Easing.None) 417 474 where T : class, ITransformable => 418 - drawable.TransformTo(drawable.PopulateTransform(new TransformBindable<TValue, T>(bindable), newValue, duration, easing)); 475 + drawable.TransformTo(drawable.PopulateTransform(new TransformBindable<TValue, DefaultEasingFunction, T>(bindable), newValue, duration, new DefaultEasingFunction(easing))); 419 476 } 420 477 }
+9 -3
osu.Framework/Graphics/Transforms/Transform.cs
··· 26 26 /// </summary> 27 27 public bool Rewindable = true; 28 28 29 - public Easing Easing; 30 - 31 29 public abstract ITransformable TargetTransformable { get; } 32 30 33 31 public double StartTime { get; internal set; } ··· 75 73 public TValue EndValue { get; protected internal set; } 76 74 } 77 75 78 - public abstract class Transform<TValue, T> : Transform<TValue> 76 + public abstract class Transform<TValue, TEasing, T> : Transform<TValue> 77 + where TEasing : IEasingFunction 79 78 where T : class, ITransformable 80 79 { 81 80 public override ITransformable TargetTransformable => Target; 82 81 83 82 public T Target { get; internal set; } 83 + 84 + public TEasing Easing { get; internal set; } 84 85 85 86 public sealed override void Apply(double time) 86 87 { ··· 95 96 protected abstract void ReadIntoStartValue(T d); 96 97 97 98 public override string ToString() => $"{Target.GetType().Name}.{TargetMember} {StartTime}-{EndTime}ms {StartValue} -> {EndValue}"; 99 + } 100 + 101 + public abstract class Transform<TValue, T> : Transform<TValue, DefaultEasingFunction, T> 102 + where T : class, ITransformable 103 + { 98 104 } 99 105 }
+3 -2
osu.Framework/Graphics/Transforms/TransformBindable.cs
··· 6 6 7 7 namespace osu.Framework.Graphics.Transforms 8 8 { 9 - internal class TransformBindable<TValue, T> : Transform<TValue, T> 9 + internal class TransformBindable<TValue, TEasing, T> : Transform<TValue, TEasing, T> 10 10 where T : class, ITransformable 11 + where TEasing : IEasingFunction 11 12 { 12 13 public override string TargetMember { get; } 13 14 14 15 private readonly Bindable<TValue> targetBindable; 15 - private readonly InterpolationFunc<TValue> interpolationFunc; 16 + private readonly InterpolationFunc<TValue, TEasing> interpolationFunc; 16 17 17 18 public TransformBindable(Bindable<TValue> targetBindable) 18 19 {
+14 -2
osu.Framework/Graphics/Transforms/TransformCustom.cs
··· 15 15 /// A transform which operates on arbitrary fields or properties of a given target. 16 16 /// </summary> 17 17 /// <typeparam name="TValue">The type of the field or property to operate upon.</typeparam> 18 + /// <typeparam name="TEasing">The type of easing.</typeparam> 18 19 /// <typeparam name="T">The type of the target to operate upon.</typeparam> 19 - internal class TransformCustom<TValue, T> : Transform<TValue, T> where T : class, ITransformable 20 + internal class TransformCustom<TValue, TEasing, T> : Transform<TValue, TEasing, T> 21 + where T : class, ITransformable 22 + where TEasing : IEasingFunction 20 23 { 21 24 private delegate TValue ReadFunc(T transformable); 22 25 ··· 141 144 private static Accessor getAccessor(string propertyOrFieldName) => accessors.GetOrAdd(propertyOrFieldName, key => findAccessor(typeof(T), key)); 142 145 143 146 private readonly Accessor accessor; 144 - private readonly InterpolationFunc<TValue> interpolationFunc; 147 + private readonly InterpolationFunc<TValue, TEasing> interpolationFunc; 145 148 146 149 /// <summary> 147 150 /// Creates a new instance operating on a property or field of <typeparamref name="T"/>. The property or field is ··· 175 178 protected override void Apply(T d, double time) => accessor.Write(d, valueAt(time)); 176 179 177 180 protected override void ReadIntoStartValue(T d) => StartValue = accessor.Read(d); 181 + } 182 + 183 + internal class TransformCustom<TValue, T> : TransformCustom<TValue, DefaultEasingFunction, T> 184 + where T : class, ITransformable 185 + { 186 + public TransformCustom(string propertyOrFieldName) 187 + : base(propertyOrFieldName) 188 + { 189 + } 178 190 } 179 191 }
+1 -1
osu.Framework/Graphics/Transforms/Transformable.cs
··· 412 412 413 413 /// <summary> 414 414 /// Adds to this object a <see cref="Transform"/> which was previously populated using this object via 415 - /// <see cref="TransformableExtensions.PopulateTransform{TValue, TThis}(TThis, Transform{TValue, TThis}, TValue, double, Easing)"/>. 415 + /// <see cref="TransformableExtensions.PopulateTransform{TValue, TEasing, TThis}"/>. 416 416 /// Added <see cref="Transform"/>s are immediately applied, and therefore have an immediate effect on this object if the current time of this 417 417 /// object falls within <see cref="Transform.StartTime"/> and <see cref="Transform.EndTime"/>. 418 418 /// If <see cref="Clock"/> is null, e.g. because this object has just been constructed, then the given transform will be finished instantaneously.
+3 -3
osu.Framework/Utils/IInterpolable.cs
··· 1 1 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2 2 // See the LICENCE file in the repository root for full licence text. 3 3 4 - using osu.Framework.Graphics; 4 + using osu.Framework.Graphics.Transforms; 5 5 6 6 namespace osu.Framework.Utils 7 7 { ··· 22 22 /// <param name="endValue">The <typeparamref name="TValue"/> at <paramref name="time"/> = <paramref name="endTime"/>.</param> 23 23 /// <param name="startTime">The start time.</param> 24 24 /// <param name="endTime">The end time.</param> 25 - /// <param name="easingType">The easing to use.</param> 25 + /// <param name="easing">The easing function to use.</param> 26 26 /// <returns>The interpolated value.</returns> 27 - TValue ValueAt(double time, TValue startValue, TValue endValue, double startTime, double endTime, Easing easingType = Easing.None); 27 + TValue ValueAt<TEasing>(double time, TValue startValue, TValue endValue, double startTime, double endTime, in TEasing easing) where TEasing : IEasingFunction; 28 28 } 29 29 }
+8 -7
osu.Framework/Utils/Interpolation.cs
··· 330 330 331 331 public static TValue ValueAt<TValue, TEasing>(double time, TValue startValue, TValue endValue, double startTime, double endTime, in TEasing easing) 332 332 where TEasing : IEasingFunction 333 - => GenericInterpolation<TValue>.FUNCTION(time, startValue, endValue, startTime, endTime, easing); 333 + => GenericInterpolation<TValue, TEasing>.FUNCTION(time, startValue, endValue, startTime, endTime, easing); 334 334 335 335 #endregion 336 336 ··· 341 341 where TEasing : IEasingFunction 342 342 => easing.ApplyEasing(time); 343 343 344 - private static class GenericInterpolation<TValue> 344 + private static class GenericInterpolation<TValue, TEasing> 345 + where TEasing : IEasingFunction 345 346 { 346 - public static readonly InterpolationFunc<TValue> FUNCTION; 347 + public static readonly InterpolationFunc<TValue, TEasing> FUNCTION; 347 348 348 349 static GenericInterpolation() 349 350 { 350 351 const string interpolation_method = nameof(Interpolation.ValueAt); 351 352 352 - var parameters = typeof(InterpolationFunc<TValue>) 353 - .GetMethod(nameof(InterpolationFunc<TValue>.Invoke)) 353 + var parameters = typeof(InterpolationFunc<TValue, TEasing>) 354 + .GetMethod(nameof(InterpolationFunc<TValue, TEasing>.Invoke)) 354 355 ?.GetParameters().Select(p => p.ParameterType).ToArray(); 355 356 356 357 MethodInfo valueAtMethod = typeof(Interpolation).GetMethod(interpolation_method, parameters); 357 358 358 359 if (valueAtMethod != null) 359 - FUNCTION = (InterpolationFunc<TValue>)valueAtMethod.CreateDelegate(typeof(InterpolationFunc<TValue>)); 360 + FUNCTION = (InterpolationFunc<TValue, TEasing>)valueAtMethod.CreateDelegate(typeof(InterpolationFunc<TValue, TEasing>)); 360 361 else 361 362 { 362 363 var typeRef = FormatterServices.GetSafeUninitializedObject(typeof(TValue)) as IInterpolable<TValue>; ··· 370 371 } 371 372 } 372 373 373 - public delegate TValue InterpolationFunc<TValue>(double time, TValue startValue, TValue endValue, double startTime, double endTime, Easing easingType); 374 + public delegate TValue InterpolationFunc<TValue, TEasing>(double time, TValue startValue, TValue endValue, double startTime, double endTime, in TEasing easingType) where TEasing : IEasingFunction; 374 375 }