animato-gpu 1.4.0

GPU and CPU-fallback batch tween evaluation for Animato.
Documentation
struct TweenInput {
    start: f32,
    end: f32,
    duration: f32,
    elapsed: f32,
    easing_id: u32,
    _pad0: u32,
    _pad1: u32,
    _pad2: u32,
};

@group(0) @binding(0)
var<storage, read> tweens: array<TweenInput>;

@group(0) @binding(1)
var<storage, read_write> values: array<f32>;

fn ease_out_bounce(t0: f32) -> f32 {
    let n1 = 7.5625;
    let d1 = 2.75;
    var t = t0;
    if (t < 1.0 / d1) {
        return n1 * t * t;
    }
    if (t < 2.0 / d1) {
        t = t - 1.5 / d1;
        return n1 * t * t + 0.75;
    }
    if (t < 2.5 / d1) {
        t = t - 2.25 / d1;
        return n1 * t * t + 0.9375;
    }
    t = t - 2.625 / d1;
    return n1 * t * t + 0.984375;
}

fn easing_apply(id: u32, t: f32) -> f32 {
    let pi = 3.141592653589793;
    switch id {
        case 1u: { return t * t; }
        case 2u: { return 1.0 - pow(1.0 - t, 2.0); }
        case 3u: {
            if (t < 0.5) { return 2.0 * t * t; }
            return 1.0 - pow(-2.0 * t + 2.0, 2.0) / 2.0;
        }
        case 4u: { return t * t * t; }
        case 5u: { return 1.0 - pow(1.0 - t, 3.0); }
        case 6u: {
            if (t < 0.5) { return 4.0 * t * t * t; }
            return 1.0 - pow(-2.0 * t + 2.0, 3.0) / 2.0;
        }
        case 7u: { return t * t * t * t; }
        case 8u: { return 1.0 - pow(1.0 - t, 4.0); }
        case 9u: {
            if (t < 0.5) { return 8.0 * t * t * t * t; }
            return 1.0 - pow(-2.0 * t + 2.0, 4.0) / 2.0;
        }
        case 10u: { return t * t * t * t * t; }
        case 11u: { return 1.0 - pow(1.0 - t, 5.0); }
        case 12u: {
            if (t < 0.5) { return 16.0 * t * t * t * t * t; }
            return 1.0 - pow(-2.0 * t + 2.0, 5.0) / 2.0;
        }
        case 13u: { return 1.0 - cos(t * pi / 2.0); }
        case 14u: { return sin(t * pi / 2.0); }
        case 15u: { return -(cos(t * pi) - 1.0) / 2.0; }
        case 16u: {
            if (t == 0.0) { return 0.0; }
            return pow(2.0, 10.0 * t - 10.0);
        }
        case 17u: {
            if (t == 1.0) { return 1.0; }
            return 1.0 - pow(2.0, -10.0 * t);
        }
        case 18u: {
            if (t == 0.0) { return 0.0; }
            if (t == 1.0) { return 1.0; }
            if (t < 0.5) { return pow(2.0, 20.0 * t - 10.0) / 2.0; }
            return (2.0 - pow(2.0, -20.0 * t + 10.0)) / 2.0;
        }
        case 19u: { return 1.0 - sqrt(1.0 - t * t); }
        case 20u: { return sqrt(1.0 - (t - 1.0) * (t - 1.0)); }
        case 21u: {
            if (t < 0.5) { return (1.0 - sqrt(1.0 - pow(2.0 * t, 2.0))) / 2.0; }
            return (sqrt(1.0 - pow(-2.0 * t + 2.0, 2.0)) + 1.0) / 2.0;
        }
        case 22u: {
            let c1 = 1.70158;
            let c3 = c1 + 1.0;
            return c3 * t * t * t - c1 * t * t;
        }
        case 23u: {
            let c1 = 1.70158;
            let c3 = c1 + 1.0;
            let u = t - 1.0;
            return 1.0 + c3 * u * u * u + c1 * u * u;
        }
        case 24u: {
            let c1 = 1.70158;
            let c2 = c1 * 1.525;
            if (t < 0.5) {
                return (pow(2.0 * t, 2.0) * ((c2 + 1.0) * 2.0 * t - c2)) / 2.0;
            }
            return (pow(2.0 * t - 2.0, 2.0) * ((c2 + 1.0) * (2.0 * t - 2.0) + c2) + 2.0) / 2.0;
        }
        case 25u: {
            if (t == 0.0) { return 0.0; }
            if (t == 1.0) { return 1.0; }
            let c4 = (2.0 * pi) / 3.0;
            return -pow(2.0, 10.0 * t - 10.0) * sin((10.0 * t - 10.75) * c4);
        }
        case 26u: {
            if (t == 0.0) { return 0.0; }
            if (t == 1.0) { return 1.0; }
            let c4 = (2.0 * pi) / 3.0;
            return pow(2.0, -10.0 * t) * sin((10.0 * t - 0.75) * c4) + 1.0;
        }
        case 27u: {
            if (t == 0.0) { return 0.0; }
            if (t == 1.0) { return 1.0; }
            let c5 = (2.0 * pi) / 4.5;
            if (t < 0.5) {
                return -(pow(2.0, 20.0 * t - 10.0) * sin((20.0 * t - 11.125) * c5)) / 2.0;
            }
            return (pow(2.0, -20.0 * t + 10.0) * sin((20.0 * t - 11.125) * c5)) / 2.0 + 1.0;
        }
        case 28u: { return 1.0 - ease_out_bounce(1.0 - t); }
        case 29u: { return ease_out_bounce(t); }
        case 30u: {
            if (t < 0.5) { return (1.0 - ease_out_bounce(1.0 - 2.0 * t)) / 2.0; }
            return (1.0 + ease_out_bounce(2.0 * t - 1.0)) / 2.0;
        }
        default: { return t; }
    }
}

@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
    let i = id.x;
    if (i >= arrayLength(&values)) {
        return;
    }

    let tween = tweens[i];
    let raw = select(1.0, clamp(tween.elapsed / tween.duration, 0.0, 1.0), tween.duration > 0.0);
    let curved = easing_apply(tween.easing_id, raw);
    values[i] = tween.start + (tween.end - tween.start) * curved;
}