using System; using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; namespace Auspex; public readonly struct AxAnimation { private readonly long _startTimestamp; private readonly float _duration; private readonly AxEasing _easing; private readonly AxRepeatMode _repeatMode; private readonly float _delay; public float Progress { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (_duration <= 0f) { return 1f; } float num = (float)Stopwatch.GetElapsedTime(_startTimestamp).TotalSeconds - _delay; if (num < 0f) { return 0f; } float num2 = num / _duration; switch (_repeatMode) { case AxRepeatMode.Repeat: num2 -= MathF.Floor(num2); break; case AxRepeatMode.PingPong: { int num3 = (int)MathF.Floor(num2); num2 -= MathF.Floor(num2); if (num3 % 2 == 1) { num2 = 1f - num2; } break; } default: num2 = Math.Clamp(num2, 0f, 1f); break; } return ApplyEasing(num2, _easing); } } public bool IsComplete { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { if (_repeatMode != AxRepeatMode.None) { return false; } if (_duration <= 0f) { return true; } return (float)Stopwatch.GetElapsedTime(_startTimestamp).TotalSeconds >= _delay + _duration; } } private AxAnimation(float duration, AxEasing easing, AxRepeatMode repeatMode, float delay) { _startTimestamp = Stopwatch.GetTimestamp(); _duration = duration; _easing = easing; _repeatMode = repeatMode; _delay = delay; } public static AxAnimation Start(float duration, AxEasing easing = AxEasing.Linear, AxRepeatMode repeatMode = AxRepeatMode.None, float delay = 0f) { return new AxAnimation(duration, easing, repeatMode, delay); } public static AxAnimation Start(float duration, AxEasing easing, bool repeat) { return new AxAnimation(duration, easing, repeat ? AxRepeatMode.Repeat : AxRepeatMode.None, 0f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public uint FadeIn(uint color) { return AxColor.WithAlpha(color, Progress); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public uint FadeOut(uint color) { return AxColor.WithAlpha(color, 1f - Progress); } public uint Pulse(uint color, float minAlpha = 0f) { float num = (float)((color >> 24) & 0xFF) / 255f; float num2 = 0.5f + 0.5f * MathF.Cos(Progress * 2f * (float)Math.PI); uint num3 = (uint)(Math.Clamp(minAlpha + (num - minAlpha) * num2, 0f, 1f) * 255f); return (color & 0xFFFFFF) | (num3 << 24); } public uint ColorLerp(uint from, uint to) { return AxColor.Lerp(from, to, Progress); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public float Lerp(float from, float to) { return from + (to - from) * Progress; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector2 Lerp(Vector2 from, Vector2 to) { return from + (to - from) * Progress; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3 Lerp(Vector3 from, Vector3 to) { return from + (to - from) * Progress; } internal static float ApplyEasing(float t, AxEasing easing) { return easing switch { AxEasing.EaseIn => t * t, AxEasing.EaseOut => 1f - (1f - t) * (1f - t), AxEasing.EaseInOut => t * t * (3f - 2f * t), AxEasing.CubicIn => t * t * t, AxEasing.CubicOut => 1f - (1f - t) * (1f - t) * (1f - t), AxEasing.CubicInOut => (t < 0.5f) ? (4f * t * t * t) : (1f - MathF.Pow(-2f * t + 2f, 3f) / 2f), AxEasing.SineIn => 1f - MathF.Cos(t * (float)Math.PI / 2f), AxEasing.SineOut => MathF.Sin(t * (float)Math.PI / 2f), AxEasing.SineInOut => (0f - (MathF.Cos((float)Math.PI * t) - 1f)) / 2f, AxEasing.ExponentialIn => (t == 0f) ? 0f : MathF.Pow(2f, 10f * t - 10f), AxEasing.ExponentialOut => (t == 1f) ? 1f : (1f - MathF.Pow(2f, -10f * t)), AxEasing.ExponentialInOut => (t == 0f) ? 0f : ((t == 1f) ? 1f : ((t < 0.5f) ? (MathF.Pow(2f, 20f * t - 10f) / 2f) : ((2f - MathF.Pow(2f, -20f * t + 10f)) / 2f))), AxEasing.BackIn => 2.70158f * t * t * t - 1.70158f * t * t, AxEasing.BackOut => 1f + 2.70158f * (t - 1f) * (t - 1f) * (t - 1f) + 1.70158f * (t - 1f) * (t - 1f), AxEasing.BackInOut => (t < 0.5f) ? (2f * t * (2f * t) * (7.189819f * t - 2.5949094f) / 2f) : (((2f * t - 2f) * (2f * t - 2f) * (3.5949094f * (2f * t - 2f) + 2.5949094f) + 2f) / 2f), AxEasing.ElasticIn => (t == 0f) ? 0f : ((t == 1f) ? 1f : ((0f - MathF.Pow(2f, 10f * t - 10f)) * MathF.Sin((10f * t - 10.75f) * ((float)Math.PI * 2f / 3f)))), AxEasing.ElasticOut => (t == 0f) ? 0f : ((t == 1f) ? 1f : (MathF.Pow(2f, -10f * t) * MathF.Sin((10f * t - 0.75f) * ((float)Math.PI * 2f / 3f)) + 1f)), AxEasing.ElasticInOut => (t == 0f) ? 0f : ((t == 1f) ? 1f : ((t < 0.5f) ? ((0f - MathF.Pow(2f, 20f * t - 10f) * MathF.Sin((20f * t - 11.125f) * ((float)Math.PI * 4f / 9f))) / 2f) : (MathF.Pow(2f, -20f * t + 10f) * MathF.Sin((20f * t - 11.125f) * ((float)Math.PI * 4f / 9f)) / 2f + 1f))), AxEasing.BounceIn => 1f - BounceOut(1f - t), AxEasing.BounceOut => BounceOut(t), AxEasing.BounceInOut => (t < 0.5f) ? ((1f - BounceOut(1f - 2f * t)) / 2f) : ((1f + BounceOut(2f * t - 1f)) / 2f), _ => t, }; } private static float BounceOut(float t) { if (t < 0.36363637f) { return 7.5625f * t * t; } if (t < 0.72727275f) { return 7.5625f * (t -= 0.54545456f) * t + 0.75f; } if (t < 0.90909094f) { return 7.5625f * (t -= 0.8181818f) * t + 0.9375f; } return 7.5625f * (t -= 21f / 22f) * t + 63f / 64f; } }