# emit_ease.ludic — the Ease.* namespace: tween curves over a normalized amount # t in 0.0..1.0, returning an eased fixed. All pure Q16.16, deterministic. The # "juice" layer that makes motion feel good (Robert Penner's easings). function is_ease_ns(meth: pointer) -> bool { if (meth == "in") or (meth == "out") or (meth == "in_out") { return true } if (meth == "back") or (meth == "bounce") or (meth == "elastic") { return true } return false } # n1 * u * u (u a fixed code) -> code of a fixed i32 function ease_bounce_seg(u: pointer) -> pointer { let uu = fx_mul_code(u, u) return fx_mul_code(uu, "495616") # 7.5625 * u*u } function emit_ease_ns(meth: pointer, e: Node) -> Val { let t = emit_expr(e.kids[0]) if (meth == "in") { # ease-in quad: t*t return val(fx_mul_code(t.code, t.code), "fixed") } if (meth == "out") { # ease-out quad: t*(2 - t) let inv = emit_bind(`sub i32 131072, {t.code}`) return val(fx_mul_code(t.code, inv), "fixed") } if (meth == "in_out") { # smooth ease-in-out: 3t^2 - 2t^3 let t2 = fx_mul_code(t.code, t.code) let t3 = fx_mul_code(t2, t.code) let three = emit_bind(`mul i32 {t2}, 3`) let two = emit_bind(`mul i32 {t3}, 2`) return val(emit_bind(`sub i32 {three}, {two}`), "fixed") } if (meth == "back") { # ease-in-back (overshoots below 0) let t2 = fx_mul_code(t.code, t.code) let t3 = fx_mul_code(t2, t.code) let a = fx_mul_code(t3, "177051") # 2.70158 * t^3 let b = fx_mul_code(t2, "111515") # 1.70158 * t^2 return val(emit_bind(`sub i32 {a}, {b}`), "fixed") } if (meth == "elastic") { # ease-out elastic: springy overshoot that settles g_uses_mathrt = true # 2^(-10t) * sin((10t - 0.75) * 2pi/3) + 1 let tt = emit_bind(`mul i32 {t.code}, 10`) # 10t let ntt = emit_bind(`sub i32 0, {tt}`) # -10t (exp2 exponent, Q16.16) let decay = emit_bind(`call i32 @fn_fx_exp2(i32 {ntt})`) let ph = emit_bind(`sub i32 {tt}, 49152`) # 10t - 0.75 let ang = fx_mul_code(ph, "137258") # * (2pi/3), 2pi/3 = 137258 fixed let s = emit_bind(`call i32 @fn_fx_sin(i32 {ang})`) let osc = fx_mul_code(decay, s) return val(emit_bind(`add i32 {osc}, 65536`), "fixed") } # ease-out bounce: four parabolic segments, selected by t (all computed, then # picked branch-free). Shifts/offsets are the standard 2.75-denominator set. let sA = ease_bounce_seg(t.code) let uB = emit_bind(`sub i32 {t.code}, 35747`); let sB0 = ease_bounce_seg(uB); let sB = emit_bind(`add i32 {sB0}, 49152`) let uC = emit_bind(`sub i32 {t.code}, 53620`); let sC0 = ease_bounce_seg(uC); let sC = emit_bind(`add i32 {sC0}, 61440`) let uD = emit_bind(`sub i32 {t.code}, 62557`); let sD0 = ease_bounce_seg(uD); let sD = emit_bind(`add i32 {sD0}, 64512`) let cCD = emit_bind(`icmp slt i32 {t.code}, 59578`) let rCD = emit_bind(`select i1 {cCD}, i32 {sC}, i32 {sD}`) let cB = emit_bind(`icmp slt i32 {t.code}, 47663`) let rB = emit_bind(`select i1 {cB}, i32 {sB}, i32 {rCD}`) let cA = emit_bind(`icmp slt i32 {t.code}, 23831`) return val(emit_bind(`select i1 {cA}, i32 {sA}, i32 {rB}`), "fixed") }