📖 ENGLISH VERSION AVAILABLE AT docs_en/README_en.md
一个 377KB 单文件、零第三方动态库的 C GUI 框架——ldd 里只有系统库,没有 SDL2.dll、没有
libwinpthread。同一份 fxtk.h 与同一套控件 API,PC 走 sokol(OpenGL)、ESP32 走纯 CPU 路径。
核心纯 C、480×272 响应式设计、属性宏建界面。
可当场验证:
cd demo-main && make && ldd ./fxtk_sim—— 或见下方「为什么可能值得一用」。
注:本框架带脏区矩形合并的实现,但当前被
s_full=1旁路、不生效,每次请求都是整帧重绘 (因此不残影,但也没有脏区优化)——详见「性能」一节与fxtk.c中fx_repaint_rect()的注释。
画布与抗锯齿(v2.2 无头渲染示意图):
抗锯齿 fx_set_aa(1) |
渐变 fx_fill_rect_gradient |
自定义控件(仪表盘) | 棋盘格(缩放安全) |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
注:以上 v2.2 示意图由
demo-main/test/render_canvas.c无头渲染(不加载字体),只展示图形/渐变/边缘平滑; 按钮文字、数值等标签在真实运行时有(渲染工具为保持无头把文字函数桩掉了)。完整含文字界面见下方 demo 截图。
一段真实录制(非渲染动画):切页 → 图形页的伪 3D 模式 → 图片页拖动四角做真透视形变。
一句话:一套 fxtk.h + 属性宏,写出的界面在 PC 上是单文件、零第三方动态库(Linux 377KB / Windows 439KB),
在 ESP32 上是同一份 API 的纯 CPU 路径。1080P 下压测页 2820 个控件约 102–130 fps(无头软件渲染实测,见 make bench)。
为什么可能值得一用
- 不想再打包几十 MB 的运行库:Windows 版是一个 exe 出门(
objdump里只有系统 DLL,没有SDL2.dll、没有libwinpthread)。 - 拷过去就能跑:图片解码(PNG/JPEG/BMP/GIF/TGA/PNM)、PNG 截图、剪贴板、文件对话框、随机数、时间、偏好持久化全在框架内,无外部依赖。
- 两端一套 API:PC 默认接 sokol(OpenGL),ESP32 走纯 CPU;两端只保证"语法一致 + 渲染效果一致",PC 端不迁就嵌入式资源约束。
- 自带验证体系:
make test(同一套断言在真实 OS 服务与 stub 确定性后端各跑一遍)、make golden(金图逐像素回归)、make esp32-smoke(假 IDF 头做语法级检查)、make bench。 如实说明覆盖边界:make test用的是无头假驱动,它不渲染帧缓冲(push_pixels只累计像素数), 但 v2.4.4 起已补上颜色/几何契约断言(验证"框架让驱动画了什么")与离屏画布推送计数; 逐像素正确性仍靠make golden的金图。金图本地默认容差 0(逐像素), CI 里会跑,但用GOLDEN_TOL=1并跳过依赖 SDL/字体版本差异的演示页——即 CI 上不是逐像素口径。 - 能改得动:所有控件的颜色/圆角/留白集中在
fxtk_tokens.h,换风格只改一个文件。
- 默认后端换成 sokol(OpenGL), SDL2 降为遗留对照。因此 Windows 版是单 exe、无第三方 DLL; SDL 代码保留只为"无头假驱动"给基准与金图回归用(CI 没有显示器)。
- GPU 真透视四边形形变
fx_draw_image_quad():每角透视权重进gl_Position.w, 单次 draw 即透视正确 —— 没有"两个三角形各做仿射"的对角缝。图片页可直接玩:导入 → 缩放 → 拖四角手柄 → 复位。 - 伪 3D 演示(图形页第 4 模式):地板/天花板、走廊砖墙、旋转纹理立方体、公告板精灵全部由四边形形变拼出, HUD 显示四边形数 / fps / 走的哪条路径。
- GPU 实时光线步进
fx_raymarch_available()/fx_draw_raymarch():片元着色器直接算, 不占 CPU 像素、不回读。 - 设计令牌
components/fxtk/fxtk_tokens.h:控件颜色/圆角/留白集中一处, 改一处即可统一换肤。 - 后端服务层
fxtk_backends.h:随机(PCG32 可复现)/时间/路径/文件/图片解码(PNG·JPEG·BMP·GIF·TGA·PNM)/ PNG 编码/剪贴板/文件对话框/偏好/能力协商;-DFXTK_BACKEND_STUB提供确定性变体。 - canvas 变换栈
fx_canvas_push_affine/pop_affine+fx_fill_quad:push 后矩形填充变实心四边形、图片走透视。 - 验证体系:
make test(真实/stub 两种 OS 服务后端, 无头假驱动、不含像素断言)/make golden(金图, 本地容差 0; CI 上GOLDEN_TOL=1并跳过演示页)/make esp32-smoke(语法级)/make bench; 截图fx_screenshot()走驱动的read_pixels, 零外部依赖。 - 注意:控件层 SDF 抗锯齿默认开启(
s_widget_aa = 1);要对比或排查观感用fx_set_widget_aa(0/1/2)—— 它在"画布 + 文字 + quadwarp 混排"场景下有一个已知缺陷正在修(详见 CHANGELOG v2.4.1)。
中文输入(输入法)在 sokol 版不可用—— v2.4.1 已解决:给 vendored sokol_app 的 X11 后端补了 XIM 支持(惰性XOpenIM/XCreateIC+setlocale+XSetLocaleModifiers+ 事件循环里的XFilterEvent+Xutf8LookupString),现在 fcitx5/ibus 等输入法在 sokol 版可正常组字。实测(本机 fcitx5 + rime): 输入框里打nihao→ 上屏"你好" ✓。- 控件层 SDF 抗锯齿是默认开启的(
s_widget_aa = 1):v2.4.1 曾因"画布 + 文字 + quadwarp 混排"下 实心填充退化成边界环而临时默认关闭, v2.4.2 修好混排后已恢复默认开启,逻辑见fxtk_draw.c。 需要对比性能或排查观感时可用fx_set_widget_aa(0/1/2);注意FXTK_AA=0|1|2这个环境变量 只由演示程序demo-main/app.c读取,你自己的应用里设它不生效(请直接调fx_set_widget_aa)。
fxtk 起于 ESP32 端(esp32(测试) → fxtk-pc(v1.0) → esp32-fxtk(自 PC v1.0 搬运)),
但两端现在已高度分化,因此方针是:
- PC 端不必迁就 ESP 的资源约束。PC 有几百 MB 内存和 GPU,硬把"零动态分配/极小静态池"搬到 PC, 换来的是"列表开多了就滚不动"这类人为 bug,不是优点。
- 只保证两条:① API 与语法一致(同一份
fxtk.h,同一套控件宏与回调约定); ② 渲染效果一致(同样的控件、同样的坐标,两端画出来是一个东西)。 - 具体体现:并发资源在 PC 上给足并可按需调大(
FX_MAX_SCROLL_STATES/FX_MAX_EXTRA_WIDGETS在 PC 上默认 64,在 ESP32 上仍是 8);热路径允许 PC 侧按需分配 (如粒子缓冲pt_reserve()就地扩容);ESP 端保留纯 CPU 绘制路径,PC 端默认走 GPU。 - 不是"把单片机的紧箍咒套在 PC 上",而是"一套 API 两端跑":PC 端负责快与好用,ESP 端负责小与稳。
- 控件:按钮 / 标签 / 滑条 / 进度条 / 复选框 / 网格键盘 / 画布 / 标签页 / 图片 / 输入框 / 列表 / 下拉 / 滚动容器 / 卡片
- 布局:
pixel()(480×272 设计坐标,窗口响应式等比缩放)/percent()/grid() - 开箱默认配色:不写
color()也能直接看;想统一换风格改fxtk_tokens.h一个文件 - 画布(立即模式):线/圆/椭圆/三角/多边形/圆弧/圆角矩形/文字/渐变,支持离屏缓冲与抗锯齿
(
fx_set_aa(1);开启后该画布自动走离屏) - 输入:文本编辑(换行、跨行框选、
Ctrl+A/C/V/X系统剪贴板、字数上限)、滚轮路由、 带动画的滚动(目标值逐帧逼近,静止时零重绘)、滚动条拖拽(含自绘画布)、焦点管理 - 渲染:
fx_image_*24bit 表面、旋转贴图、图像后处理(翻转/灰度/染色/亮度)、 多线程软件 Raymarching(SDF 软阴影/AO/雾)+ 可选 GPU(GLSL) 通道 - 性能:GPU 顶点批、行级持久线程池光追;1080P 压测页 2820 控件约 102–130 fps(实测区间)
- 说明:当前每次请求都是整帧重绘(脏区合并未启用,见本文档开头「注」)—— 该帧率是整帧重建口径下的读数
- 工程化:统一 Makefile(单一源清单)、无头单测、金图回归、GitHub CI(Linux + Windows 交叉 + ESP32 冒烟)
- 体积裁剪:
-DFXTK_WIDGET_XXX=0编译期裁掉用不到的控件(受限平台用);tools/autotrim.sh自动扫描并生成开关 - 跨平台文件 API:
fx_fs_pick_dir()/fx_fs_list(),演示里是完整的文件浏览器
components/fxtk/ 框架本体 (fxtk.c/draw/widgets/effects/extra/backends + 头文件;读代码先看这里)
drivers/ 后端驱动 (sokol 驱动 + stb 文本层 + 应用外壳 + 各自的 main;SDL2 驱动为遗留对照)
your_app/ 从这里开始写你自己的应用 (最小示例 + build.sh/build_win.sh;不参与主构建)
demo-main/ PC 演示与工具链 (12 页演示 app / GPU 光追 / examples / 统一 Makefile)
demo-main/test/ 无头单元测试与基准 (无需窗口)
examples/ 独立示例 ex01~ex18
examples/canvas/ 画布学习教程 (canvas_01 ~ canvas_10)
third_party/ vendored 依赖 (sokol 头文件 1.9MB,含本项目为 X11 输入法所做的本地修改;stb 在 components/fxtk/vendor)
docs/ 中文文档 (quickstart / guide / api / desktop / effects / examples / internals / backends)
docs_en/ 英文文档 (结构与 docs/ 对应)
test/golden/ 金图回归参考图 (逐像素比对,容差 0)
tools/ 开发工具 (autotrim / esp32_smoke / golden / package_release)
.github/ CI (Linux 构建 + 测试 + Windows 交叉)
screenshot_*.png 画布/抗锯齿/渐变示意图
CHANGELOG.md 按版本记录变更 (含根因与实测数字)
LICENSE MIT 许可 (第三方许可见各 vendored 文件头部)
# 必要依赖: X11/Xcursor + GL —— 默认后端是 sokol, 不依赖 SDL2
sudo apt install libx11-dev libxcursor-dev libxi-dev libgl1-mesa-dev
cd demo-main
./build.sh # 编译并运行完整演示 (12 个标签页, 默认 sokol)
./build.sh --sdl # 遗留 SDL 版(需要 SDL2 全家桶), 仅作对照
./build_ex.sh ex01_hello # 运行独立示例
make package # 打发布包(源码 + Linux/Win 产物) → dist/pkg/也可以用统一入口 Makefile(单一源清单):
cd demo-main
make # 构建完整演示 fxtk_sim (sokol, 单文件)
make fxtk_sim_en # 英文版
make test # 无头单元测试: 真实后端 + stub 后端各一遍
make golden # 金图回归(画布示例; 本地容差 0, CI 用 GOLDEN_TOL=1)
make esp32-smoke # ESP32 接口级编译冒烟(不需要 ESP-IDF 工具链)
make bench # 渲染吞吐基准(无头, 无 vsync)
make shared # 打包成动态库(exe 只留 app 层, 体积更小)
make ex01_hello # 构建指定示例
make clean- 无头单元测试
demo-main/test/headless_test.c用一个假fx_driver_t直接驱动核心库, 验证 pixel/percent/grid 布局、press/release 命中回调、value 读写、 控件计数 与 fx_find/fx_delete,不初始化 SDL/窗口/字体。 - 回归与冒烟:
tools/golden.sh(金图逐像素)、tools/esp32_smoke.sh(ESP32 接口级)、tools/package_release.sh(发布打包)、tools/gallery.sh(截图画廊)。 - CI (
.github/workflows/ci.yml) 三个 job:Linux(构建 + 单测 + 示例 + 画布金图)、windows-cross(交叉编译单 exe)、esp32-smoke(接口级冒烟)。
波形(动画画布) / 图形(矢量动效 + 第 4 模式: 伪 3D 场景) / 控件(网格键盘 + 卡片容器) / 图片(导入图片 + 缩放 + 四角手柄做真透视形变) / 3D(GPU 片元着色器光追, HUD 显示走 GPU 还是 CPU) / 输入(文本框全家套) / 画板(鼠标作画) / 键鼠(事件监视) / 压测(动态控件生长) / 滚动(长列表+滚动条) / 组件(文件浏览器/名字编辑器/可拖动组件/颜色选择器) / 粒子(万级图元)
cd demo-main && make package # 或 ../tools/package_release.sh
# → dist/pkg/fxtk-<版本>-src.tar.gz 纯源码(git archive, 无产物) → 传 GitHub
# dist/pkg/fxtk-<版本>-linux-x86_64.tar.gz 中英双语单文件 + 文档 + 展示图
# dist/pkg/fxtk-<版本>-win-x86_64.zip 中英双语单 exe(无第三方 DLL)
# dist/pkg/fxtk-<版本>-linux-shared.tar.gz exe + libfxtk.so + libfxtk_sokol.so- docs/quickstart.md — 5 分钟跑通
- docs/guide.md — 从零到精通完整教程
- docs/api.md — API 速查表
- docs/desktop.md — 桌面演示验收点
- docs/effects.md — 图片/特效说明
- docs/examples.md — 示例导读
- docs/internals.md — 内部机制(面向源码修改)
- docs/windows.md — Windows 编译
MIT(示例与文档同许可)。全文见 LICENSE。
sokol 是默认且唯一在演进的 PC 后端,SDL2 降为遗留:
| 目标 | 后端 | 用途 |
|---|---|---|
make / make fxtk_sim |
sokol(OpenGL) | 默认演示程序;新功能只往这里加 |
make fxtk_sim_en |
sokol | 英文版 |
make sokol |
sokol | fxtk_sim 的别名(旧脚本兼容) |
make fxtk_sim_sdl / _sdl_en |
SDL2(遗留) | 仅用于对照与过渡,不再加新功能 |
为什么 SDL 代码还留着:test/bench(性能基准)与 tools/golden.sh(金图回归)需要
无显示器的确定性渲染,SDL 的 SDL_VIDEODRIVER=dummy 正好提供这个能力;而 sokol 需要真实
GL 上下文,CI 里起不来。所以 SDL 驱动现在只当"无头假驱动"用,发布产物一律走 sokol
(也正因如此,Windows 版才能做到单 exe 无第三方 DLL)。








