qstbak/Auspex/Auspex/AxAnimation.cs
2026-08-17 20:25:32 +10:00

182 lines
5.4 KiB
C#

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;
}
}