/* * meow_ui_anim.c — 动画基座 + UI 节拍器(§12.2)。 * * 时间驱动 tween:start 记录起始时刻(meow_ui_time_ms,单调),tick 按经过时间求 t, * 代入 ease 得 v = from + (to-from)*ease(t),回调 update;t 到 1 → 回调 done(canceled=0) 并回收。 * 取消 → 回调 done(canceled=1) 并回收。静态池(≤MEOW_ANIM_MAX),热路径零 malloc。 * 无动画时 meow_anim_tick() 仅查活动计数即返回(零开销)。 * * 节拍挂接:由 meow_ui_run 主循环(on_tick 之后)与 meow_ui_feed_tick(阻塞 IME 循环)调用, * 不引入常驻高频轮询。modal/dialog 阻塞循环不喂 tick(动画暂停,符合「模态期不做动画」惯例)。 */ #include "meow_ui.h" #include "include/meow_ui_anim.h" #include struct meow_anim { int active; float from, to; uint32_t duration_ms; meow_ease ease; uint64_t start_ms; float value; int region_set; int rx, ry, rw, rh; meow_anim_update_fn update; meow_anim_done_fn done; void *ctx; }; static struct meow_anim g_pool[MEOW_ANIM_MAX]; static unsigned g_active = 0; /* 活动动画计数(0 = 空闲,tick 直退) */ /* ---- 缓动 ---- */ float meow_ease_apply(meow_ease e, float t) { if (e == MEOW_EASE_OUT) { /* ease-out quad */ float u = 1.0f - t; return 1.0f - u * u; } if (e == MEOW_EASE_IN_OUT) { /* ease-in-out quad */ if (t < 0.5f) return 2.0f * t * t; float u = -2.0f * t + 2.0f; return 1.0f - u * u * 0.5f; } if (e == MEOW_EASE_OVERSHOOT) { /* ease-out-back(越过目标再回稳);t=1 → 恰为 1 */ const float c1 = 1.70158f; const float c3 = c1 + 1.0f; float u = t - 1.0f; return 1.0f + c3 * u * u * u + c1 * u * u; } /* MEOW_EASE_LINEAR */ return t; } /* ---- 生命周期 ---- */ meow_anim *meow_anim_start(const meow_anim_desc *d) { if (!d) return NULL; for (int i = 0; i < MEOW_ANIM_MAX; i++) { struct meow_anim *a = &g_pool[i]; if (a->active) continue; a->active = 1; a->from = d->from; a->to = d->to; a->duration_ms = d->duration_ms ? d->duration_ms : 1; /* 0 → 瞬发(下一 tick 完成) */ a->ease = d->ease; a->start_ms = meow_ui_time_ms(); a->update = d->update; a->done = d->done; a->ctx = d->ctx; a->region_set = 0; a->value = d->from; g_active++; if (a->update) a->update(a, a->value, a->ctx); /* 起始帧回调(t=0) */ return a; } return NULL; /* 池满 */ } void meow_anim_cancel(meow_anim *a) { if (!a || !a->active) return; a->active = 0; if (g_active > 0) g_active--; if (a->done) a->done(a, 1, a->ctx); } int meow_anim_active(meow_anim *a) { return (a && a->active) ? 1 : 0; } float meow_anim_value(meow_anim *a) { return a ? a->value : 0.0f; } void meow_anim_set_region(meow_anim *a, int x, int y, int w, int h) { if (!a) return; if (x < 0) { a->region_set = 0; return; } a->region_set = 1; a->rx = x; a->ry = y; a->rw = w > 0 ? w : 0; a->rh = h > 0 ? h : 0; } /* ---- 节拍器 ---- */ unsigned meow_anim_count(void) { return (unsigned)g_active; } void meow_anim_tick(void) { if (g_active == 0) return; /* 无动画:零开销直接返回 */ uint64_t now = meow_ui_time_ms(); for (int i = 0; i < MEOW_ANIM_MAX; i++) { struct meow_anim *a = &g_pool[i]; if (!a->active) continue; uint64_t elapsed = now - a->start_ms; float t = (float)(elapsed) / (float)a->duration_ms; int finished = (t >= 1.0f); if (t > 1.0f) t = 1.0f; if (t < 0.0f) t = 0.0f; float v = a->from + (a->to - a->from) * meow_ease_apply(a->ease, t); a->value = v; if (a->update) a->update(a, v, a->ctx); if (a->region_set && a->rw > 0 && a->rh > 0) meow_ui_flush_region(a->rx, a->ry, a->rw, a->rh); /* 只刷动画影响区 */ if (finished) { a->active = 0; if (g_active > 0) g_active--; if (a->done) a->done(a, 0, a->ctx); } } }