Files
lucky-cat/docs/抽签分层动画开发说明.zh-CN.md

152 lines
9.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 抽签分层动画开发说明
## 当前实现
2026-10-10 将五种结果接入同一动作:卜运签(保留原素材中的“补运签”字形)、
和平签、上上签、小吉签、中上签。领域结果目录及云端结果索引未改变,不在平台
重新随机,不改抽签请求、语音或联网流程。
领域继续下发原六步:前三步 `chouqian_qianzhi` 的 0/1/2,后三步所选结果
的 0/1/2,间隔 500/500/500/500/500/1500 ms。平台只有在完整匹配六步、
无附加图标、原间隔及 320×240、GFX 就绪时使用新动画。修改步骤/间隔会回到
普通 PNG,不静默覆盖通用步骤序列。
| 时间 | 动作 |
| --- | --- |
| 0~600 ms | 背面爪签从下方爪堆中抽出;爪堆遮挡签底,保留钓线/鱼 |
| 600~1200 ms | 轻透视翻面;背面缩窄,近 90° 用侧面厚度关键层,正面展开 |
| 1200~1600 ms | 正面问号保持;问号在翻面后半段已经随正面透视展开 |
| 1600~1900 ms | 所选原签文自上往下展开,不使用完整图片交叉淡化 |
| 1900~2500 ms | 爪签连续放大,爪堆淡出,程序金色星光出现 |
| 运动末帧后 1500 ms | 保持结果,变化的时间/电池可刷新,最后正常完成并守卫回待机 |
名义总长约 4 秒;若运动因负载迟到,仍保留完整 1500 ms 末帧阅读时间。
共同起点固定时间轴,目标运动步间隔 34 ms,75 张绘制(含起始与末端),不
画完再等 34 ms、不跳动作、不忙等。实际调度可迟到;目标不是实测 FPS。
取消以 20 ms 等待片轮询加当前绘制/传输时间为边界,不视为成功完成。
保留统一待机 guard,旧动画完成不能覆盖新 pending 请求。
## 图层和渲染
六个共享层:下方爪堆、背面、侧面、空白正面、问号、钓线/鱼;另有五个原签文。
保留源图,背景抖动杂点归零,清除背面裁剪内的钓线,将正面原签文区恢复签底,
保留肉垫与外轮廓;程序星光代替分散的原星光。属于小幅性能适配,并非原 PNG
逐像素不变。签文轮廓/颜色来自旧素材,不使用另加中文字体。
`lcd_emote_fortune.c` 在 PSRAM 的 `(56,20,208,220)` 局部不透明 RGB565 窗口
完成光栅:16 条纹理带近似透视、前后近远缩放、微小姿态变化;仅近侧面时使用
厚度层,避免半翻面时浮出一条不属于轮廓的金线。正面 UV 补偿反向,文字不镜像。
双线性采样在预乘 Alpha 空间进行,边缘不会把透明黑混出暗边。
每步完整恢复同一局部窗口并画新轮廓,防止旧轮廓残影。图片位置/尺寸固定,
无需以错误的“只更新新轮廓”留下旧像素。钓线在窗口外部分借用现有背景对象,
翻面开始只隐藏一次;不逐帧让不变的钓线失效。窗口顶部覆盖放大爪尖但避开
左上时间和右上电池;源图/几何变化需同步边界及预览。
GFX 负责普通图片图层、共享 HUD、区域合成及既有安全传输,不是使用 GFX
三维引擎,也没有 LVGL GUI。复用 153,600 B GFX 合成缓冲、10,240 B DMA
暂存区、ISR 完成等待和故障锁存;新增 91,520 B 是局部光栅缓冲,不是第二个
整屏换帧缓冲。屏幕无 TE,不能承诺完全无撕裂。
## 制作与测试
```text
components/platform/assets/lcd_source/chouqian_*.png 原十八张 PNG,保留
components/platform/assets/lcd_optimized/chouqian_*.png 旧 PNG 后备,仍入包
components/platform/assets/lcd_layers/chouqian/ 六共享图层、五签文、layout
components/platform/src/generated/emote_gfx/fortune_assets.c 实际编译压缩资产
components/platform/internal/lcd_emote_fortune.h 平台私有描述
components/platform/src/lcd_emote_fortune.c 解码与几何
components/platform/src/lcd_direct.c 匹配、准备、播放、解绑、测量
```
生成文件不要手改。以下需要 Pillow 和 Clang,生成会覆盖本次拆分图层及 C,
先保存手工美术修改;旧十八张源/优化 PNG 不改,不把拆分 PNG 重复入资源包。
```bash
python3 tools/prepare_fortune_expression.py
python3 tools/prepare_fortune_expression.py --check
python3 tools/test_lcd_fortune_gfx.py
python3 tools/preview_fortune_expression.py --output /tmp/lucky-fortune-preview --result 2
```
新压缩编码为 LZ4 block:字面量加 16-bit 回指,用有界、自包含解码器直接恢复
RGB565 高字节在前+独立 A8,不引入新解码任务/库,不在每帧解压。解码拒绝
越界回指、截断和输出长度错误。与旧四字节像素 RLE 不能互换。往返相对转换后
的 RGB565+A8 无损;转换/拆分并非 RGB888 原画无损。Alpha 全平面校验保留。
主机测试实际 C 解码和几何,五种结果共 1180 个采样时刻、空间不足/损坏输入、
九次分配失败、75 个取消点、4 秒时间轴、解绑/传输失败;日志开/关均覆盖。
预览也调用实际 C,另比较 C 解压与图层 PNG 转换后的像素及 Alpha。
仍需执行原四个显示回归和 IDF 5.5.4,并对 LCD 源文件验证日志/GFX 关闭条件编译。
替换资源不是只改 PNG:当前拆分坐标、尺寸、问号、原签文区域、锚点、放大
比例和窗口耦合。要调整生成器与几何,并用实际 C 预览检查翻面镜像、爪尖/签底
裁剪、字形缺笔、Alpha 暗边、HUD 遮挡及返回待机。
## 资源与生命周期
新载荷 43,547 B,十一张优化图层 PNG 37,046 B,原十八 PNG 372,012 B、
旧优化十八 PNG 136,226 B。不是相同图层数量的无损压缩比例对比;新方案
只保留少量关键素材而实时计算过渡。新 LZ4 比其十一 PNG 大 6,501 B,选择
它是为有界直接解压与减少 PNG 解码暂存,不是保证最小 Flash。
| 新增项 | 数值 |
| --- | ---: |
| 十一图层原始 RGB565+A8 | 246,633 B(含五签文,不全解压到运行内存) |
| 编译资产对象只读段(含描述/目录名) | 43,831 B;data/BSS 0 |
| 应用镜像 | 3,157,728 B,较上一提交 3,105,872 B 净增 51,856 B |
| 单 OTA 槽余量 | 1,560,864 B |
| 六共享图层解压像素 | 171,753 B |
| 本次所选一份签文 | 14,976 B |
| 局部光栅缓冲 | 91,520 B |
| 播放期像素 PSRAM 峰值 | 278,249 B |
| 场景状态/描述 | 148 B PSRAM;峰值明确请求合计 278,397 B |
| 临时 GFX 图片对象/状态/链节点 | 80+8+8=96 B 普通堆,不含管理开销 |
| 静态可写数据 | LCD 文件增加 4 B 指针 |
| 新内部/DMA 暂存区、任务 | 0 |
| 正常完成/取消后新增 PSRAM/对象常驻 | 0,解绑释放 |
数据来自目标编译器及本次构建,不包含分配器管理、局部栈和绘制临时开销。
旧 PNG 后备保留,包仍是 820,125 B、75 PNG/32 Opus,所以完整固件不会按
新旧素材差额减少。成本在本次提出的额外 Flash 80 KiB、像素 PSRAM 300 KiB
预算内;不要将此预算自动授权给后续更大缓存或新内部/DMA 缓冲。
播放准备失败释放部分成果;创建/绑定失败且安全解绑后才回退 PNG;开始绘制
后取消/失败不从头重播。每次动作只解压六共享层与一签文、申请一局部缓冲和
一个图片对象,正常退出持同任务 GFX 锁,背景重新绑定待机,再删除临时对象,
释放像素/场景。若锁/解绑异常,保留已绑定资源到重启,禁止再次创建该场景,
不能宣称此异常下已完成释放;既有强制删任务异常路径也不作为正常释放保证。
## 设备测试与日志
工厂 UART0 增加仅显示的测试命令,不调用云端,不写 NVS:
```text
lcd_fortune_test 0
lcd_fortune_test 1
lcd_fortune_test 2
lcd_fortune_test 3
lcd_fortune_test 4
```
每条结束后等至少 4 秒再发下一条;新命令会中断当前画面,不能当排队命令。
0~4 映射与上面顺序一致;仅接受单字符索引,缺失/越界/多参数拒绝。
`OK` 仅代表请求入队,完成/显示仍以日志及屏幕为准。当前 USB Serial/JTAG
是次级日志输出,CLI 读取 UART0,不能假设向 USB 日志口发送命令就会被执行。
正常抽签仍可通过既有 SW2/云端流程触发,不需要该测试命令。
开启 `CONFIG_TQ_LCD_EMOTE_FPS_LOG` 时每次运动段输出 `fortune_fps`:
`frames` 仅计成功绘制/传输;`motion_us` 为实际运动墙钟,排除最后保持;
`update_fps` 使用相同时间分母;`draw_avg_us/max_us` 含锁、光栅、GFX、DMA
复制及传输等待,平均分母是绘制尝试数(包括失败尝试);`late_frames` 是绘制
达到 34 ms 的次数,不是面板丢帧。
这些是任务墙钟,不能当纯 CPU,也不等于面板扫描率。开始日志另有解压/准备
时间、像素 PSRAM 及场景描述字节。
本次五签主机/条件编译/IDF 5.5.4 构建通过;当前设备 ota_0 有效,经读取 OTA
选择区确认后只用 app-flash 写 ota_0 应用,镜像校验成功,NVS/模型/选择区未改。
启动采样 25 秒:最终应用 SHA 前缀 06e65e4a0、待机/listening 缓存成功,采样内
无显示锁/传输/崩溃错误。未捕获抽签运动日志,未完成五签 LCD 观感及并行负载
验收,不写成实测稳定 30 FPS。启动期间的内存最低值不能代表抽签运行期最低值。