字体系统
NeoFlux 用 FreeType 做字形光栅化,并用一张灰度纹理图集高效渲染文字。 Widget 按名字引用字体,FontManager 把名字解析为文件路径。
支持格式
扫描器(FontManager::ScanDirectory)识别三种字体格式:
.ttf—— TrueType.otf—— OpenType(CFF).ttc—— TrueType Collection
每个被发现的文件按其文件名主干(去掉扩展名)登记。例如 NotoSansSC-Regular.ttf 注册为字体名 NotoSansSC-regular(查找时忽略大小写)。 最先扫描到的字体成为默认字体,widget 未调用 SetFont() 时使用它。
assets/fonts/ 约定
推荐的工程布局把用户字体放在可执行文件旁边,不纳入源码仓库:
my_app/
├── assets/
│ └── fonts/
│ ├── NotoSansSC-Regular.ttf
│ └── Roboto-Bold.ttf
└── ...在 CMake 里加一个 POST_BUILD 步骤,把整个 assets/fonts/ 目录拷贝到产物二进制旁, 这样运行时按工作目录查找就能命中:
add_custom_command(TARGET my_app POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/assets/fonts
$<TARGET_FILE_DIR:my_app>/assets/fonts)构建后,二进制旁的布局为:
build/bin/
├── my_app.exe
└── assets/
└── fonts/
├── NotoSansSC-Regular.ttf
└── Roboto-Bold.ttf从 bin 目录运行可执行文件,默认查找路径 ./assets/fonts/ 即可命中:
.\build\bin\my_app.exe当前内置扫描路径
本版本中,渲染器(TgfxRenderer::InitFonts)扫描的是 thirdparty/fonts/, 并附带 ../thirdparty/fonts/、../../thirdparty/fonts/ 相对回退,而非 ./assets/fonts/。 自带示例把字体放进 thirdparty/fonts/;你自己的目标则可采用上面的 assets/fonts/ + POST_BUILD 约定,并显式调用 FontManager::ScanDirectory("assets/fonts")。两种方式支持的格式与按主干命名的规则完全一致。
使用字体
默认字体
Text/Button 未指定字体时,使用第一个发现的字体。
auto text = std::make_shared<Text>("Hello"); // 使用默认字体指定字体
按文件名主干选择(忽略大小写):
auto text = std::make_shared<Text>("Hello");
text->SetFont("NotoSansSC-Regular"); // 加载 NotoSansSC-Regular.ttf字号、颜色、对齐
text->SetFontSize(24.0F);
text->SetTextColor({.r = 255, .g = 0, .b = 0, .a = 255}); // 红色
text->SetAlignment(HAlign::kCenter); // 在 bounds 内居中渲染流程
- 初始化 FreeType —— 启动时建立一个
FT_Library。 - 扫描 ——
FontManager::ScanDirectory(dir)遍历目录,把小写主干映射为绝对路径。 - 按需加载 face —— 首次需要某字形时才加载并缓存对应的
FT_Face。 - 光栅化 + 图集 —— 字形位图上传到一张灰度纹理图集,每个字形画成纹理四边形。
- 着色 —— 片元着色器采样图集 alpha 通道,再乘以 widget 的文字颜色。
没有字体就没有文字
若扫描目录不存在或没有字体文件,渲染器会记录 No fonts found ... Text rendering will be disabled,并不绘制任何文字。 务必至少附带一个字体。
CJK 与 Unicode
Text 接受 UTF-8 std::string。中文内容请使用覆盖相应字形的字体(如 Noto Sans SC):
auto text = std::make_shared<Text>(u8"你好世界");
text->SetFont("NotoSansSC-Regular");最佳实践
- 只附带所需字重/子集,控制内存与下载体积。
- 用稳定的主干名引用字体;重命名文件即等于重命名字体。
- 把
assets/fonts/排除在 git 之外(大体积二进制),构建时再拷贝。
讨论