9.2 KiB
抽签分层动画开发说明
当前实现
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,不能承诺完全无撕裂。
制作与测试
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 重复入资源包。
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:
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。启动期间的内存最低值不能代表抽签运行期最低值。