/* * meow_font_demo.c — MeowOS 字体子系统主机/真机验证 demo。 * * 用法: * host(主机侧验证):meow_font_demo --sim demo.raw * 渲染中文串到内存 480x720 RGB565 缓冲并写入 demo.raw,主机再用 raw2png.py 转 PNG。 * 真机:meow_font_demo --to-fb (写 /dev/fb0,默认走非显示后备缓冲并暂存,谨慎用 --sim) * * 通过 meow_font.h 的公开 API 绘制,验证字形/字号/advance/描边;把 width_text 打印到 stdout。 */ #include "meow_font.h" #include #include #include #define FB_W 480 #define FB_H 720 static uint16_t *g_fb; static inline uint16_t rgb565(int r, int g, int b) { return (uint16_t)(((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)); } static void fill_bg(uint16_t c) { for (size_t i = 0; i < (size_t)FB_W * FB_H; i++) g_fb[i] = c; } static void fill_rect(int x, int y, int w, int h, uint16_t c) { for (int yy = y; yy < y + h; yy++) { for (int xx = x; xx < x + w; xx++) { if (xx >= 0 && xx < FB_W && yy >= 0 && yy < FB_H) g_fb[(size_t)yy * FB_W + xx] = c; } } } /* 设备侧写文件 */ static int write_raw(const char *path) { FILE *f = fopen(path, "wb"); if (!f) { fprintf(stderr, "cannot open %s\n", path); return -1; } size_t n = fwrite(g_fb, 2, (size_t)FB_W * FB_H, f); fclose(f); return (n == (size_t)FB_W * FB_H) ? 0 : -1; } int main(int argc, char **argv) { int to_fb = 0; const char *rawpath = "font/demo/meow_demo.raw"; for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "--to-fb")) to_fb = 1; else if (!strcmp(argv[i], "--sim")) rawpath = (i + 1 < argc) ? argv[++i] : rawpath; else { fprintf(stderr, "usage: %s [--sim out.raw | --to-fb]\n", argv[0]); return 2; } } g_fb = (uint16_t *)calloc((size_t)FB_W * FB_H, 2); if (!g_fb) return 3; meow_font_set_fb(FB_W, FB_H, FB_W * 2); const char *png = "font/atlas/font.png"; const char *idx = "font/atlas/font.idx"; int rc = meow_font_load(png, idx); if (rc != 0) { fprintf(stderr, "meow_font_load failed rc=%d\n", rc); return 4; } printf("loaded %s + %s : has_size(28)=%d has_size(20)=%d\n", png, idx, meow_font_has_size(28), meow_font_has_size(20)); /* ---- 度量核对 ---- */ printf("width_text('MeowOS 主屏',28)=%d line_h28=%d asc28=%d\n", meow_font_width_text("MeowOS 主屏", 28), meow_font_line_height(28), meow_font_ascent(28)); printf("width_text('返回播放器需重启',20)=%d line_h20=%d\n", meow_font_width_text("返回播放器需重启", 20), meow_font_line_height(20)); /* ---- 布局 --- */ uint16_t cbg = rgb565(0x0c, 0x0e, 0x12); uint16_t ctit = rgb565(0xff, 0xb0, 0x30); /* 主题橙 */ uint16_t ctext = rgb565(0xf2, 0xf2, 0xf2); /* 近白 */ uint16_t c_dim = rgb565(0x7a, 0x82, 0x8c); /* 灰 */ uint16_t cselbg = rgb565(0x1e, 0x2a, 0x3a); /* 选中背景 */ fill_bg(cbg); /* 顶栏:标题 + 状态(版本) */ meow_font_drawtext(g_fb, 16, 10, "MeowOS 主屏", ctit, 28); meow_font_drawtext(g_fb, 400, 16, "0.6.9", c_dim, 20); /* 分隔线 */ fill_rect(16, 56, FB_W - 32, 1, rgb565(0x2a, 0x30, 0x38)); /* 应用/功能列表(正文 20px) */ struct item { const char *s; int sel; } items[] = { {"本地音乐", 0}, {"在线电台", 0}, {"返回播放器需重启", 1}, {"设置", 0}, {"关闭背光", 0}, {"关机", 0}, }; int y = 78; for (unsigned i = 0; i < sizeof(items) / sizeof(items[0]); i++) { int lh = meow_font_line_height(20); if (items[i].sel) { fill_rect(12, y - 4, FB_W - 24, lh + 6, cselbg); meow_font_drawtext_outline(g_fb, 24, y, items[i].s, ctext, ctit, 1, 20); } else { meow_font_drawtext(g_fb, 24, y, items[i].s, items[i].sel ? ctit : ctext, 20); } y += lh + 16; } /* 底栏提示 */ meow_font_drawtext(g_fb, 16, FB_H - 46, "按住电源键 3 秒返回", c_dim, 20); if (to_fb) { fprintf(stderr, "--to-fb 暂未在本机关联(真机用);先用 --sim 验证\n"); } if (write_raw(rawpath) != 0) { fprintf(stderr, "write_raw failed\n"); return 5; } printf("wrote %s\n", rawpath); meow_font_unload(); free(g_fb); return 0; }