2V0-g: port the .fnt font pipeline over a FreeType GDI emulation

CGraphicText, CGraphicFontTexture and CGraphicDib are the 40250 bodies
verbatim; CGraphicTextInstance is verbatim except that its D3D draws become
UI render commands (one image quad per glyph, Bar for cursor/underline).

- platform/Win32Gdi.cpp: the GDI subset those files call, over vendored
  FreeType 2.13.3, following GDI's LOGFONT cell height, win metrics and gasp
  rules; system font lookup with substitute and CJK fallback faces
- Win32Crt: MultiByteToWideChar / WideCharToMultiByte (UTF-8 and 1252 by
  hand, other code pages through iconv)
- CGraphicImageTexture memory textures: glyph pages reach Godot as
  "mem:<id>@<revision>"; Metin2PythonHost.memory_texture + Canvas cache
- Util.cpp code page / font face table, SetDefaultCodePage at boot,
  DefaultFont_* block, fnt resource type, GetMaxTextureWidth/Height
- TextTag, StringCodec, Arabic, Vietnamese copied from 40250
- tests: port.text (Tahoma 12 metrics, alignment, CP949), port.app_loop
  and python_host_test.gd now check glyph quads instead of text commands

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-23 14:17:25 +09:00
co-authored by Claude Opus 5.5
parent 141206cb69
commit afe63bfa61
272 changed files with 137097 additions and 316 deletions
+2 -1
View File
@@ -400,7 +400,8 @@ extension/third_party/cpython-2.7.18/ # 静态库(2P 批次
| 2V0-c | `wndMgr` / `grp` / `grpImage` / `grpText` / `grpThing` 模块 | 绑定已移植并通过导入/窗口句柄测试;图形绘制仍属 2V0-f |
| 2V0-d | 42 个 `UserInterface` 头(都在 `PythonApplication.h` 后面)+ `PythonApplicationModule.cpp`(`app`) | 头与绑定已编译、链接并导入;应用生命周期 adapter 仍属 2V0-f |
| 2V0-e | `dbg` 等桩模块补齐,`system.py` 跑到 `prototype.RunApp()` | 完成:27 个玩法 native 模块导出名桩记录每次调用;真实 `system.py` 已进入 `RunApp()`,目前由待实现的 `app.Create()` 报 `CREATE_DEVICE` |
| 2V0-f | Godot 渲染器上的 platform UI adapter;Logo/Popup 可显示可操作 | 完成:真实 `system.py` 在 app 进程内的脚本纤程上跑 `app.Loop()`(每个 `UIUpdate` = 一次 `CPythonApplication::Process()`),Logo→Login 切换、Popup ESC/点击、`app.Exit` 收尾(按 40250 Main 先 `pyLauncher.Clear()`);图像统一为基贴图 + UV 的四边形命令(`.sub` 共用父贴图名),ExpandedImage 缩放/旋转/RenderingRect 原样移植;`grp.GenerateColor` 已移植(ThinBoard 半透明底)。`port.app_loop` + `python_host_test.gd` 覆盖输入/焦点/裁剪/文字/图像;`MT_TEST_MODE=python_ui` 可视运行。TODO:`.fnt`/`CGraphicText` 字体管线(现用 Godot 回退字体、无对齐)、ExpandedImage 混合模式(SCREEN/COLOR_DODGE/MODULATE)未应用。 |
| 2V0-f | Godot 渲染器上的 platform UI adapter;Logo/Popup 可显示可操作 | 完成:真实 `system.py` 在 app 进程内的脚本纤程上跑 `app.Loop()`(每个 `UIUpdate` = 一次 `CPythonApplication::Process()`),Logo→Login 切换、Popup ESC/点击、`app.Exit` 收尾(按 40250 Main 先 `pyLauncher.Clear()`);图像统一为基贴图 + UV 的四边形命令(`.sub` 共用父贴图名),ExpandedImage 缩放/旋转/RenderingRect 原样移植;`grp.GenerateColor` 已移植(ThinBoard 半透明底)。`port.app_loop` + `python_host_test.gd` 覆盖输入/焦点/裁剪/文字/图像;`MT_TEST_MODE=python_ui` 可视运行。TODO:ExpandedImage 混合模式(SCREEN/COLOR_DODGE/MODULATE)未应用(字体管线见 2V0-g)。 |
| 2V0-g | `.fnt` 字体管线:`CGraphicText` / `CGraphicFontTexture` / `CGraphicDib` / `CGraphicTextInstance` | 完成:四个文件原样移植(`GrpTextInstance` 只把 D3D 绘制换成 UI 命令:每个字形一个四边形,光标/IME 下划线为 Bar);GDI 子集(`CreateFontIndirect`/`CreateDIBSection`/`TextOutW`/`GetTextExtentPoint32W`/`GetCharABCWidthsFloatW`)在 `platform/Win32Gdi.cpp` 用 FreeType 按 GDI 规则模拟(LOGFONT 负高度=字符格高、win ascent/descent、gasp 决定单色/灰度、v35 解释器、斜体 oblique),字体按文件名在系统字体目录找,缺字体按 Arial/Roboto 等替换、缺字按 CJK 字体回退;字形页作为内存纹理(`mem:<id>@<rev>`)交给 Godot,Canvas 按 id 缓存、rev 变了才重取;`MultiByteToWideChar`/`WideCharToMultiByte`(UTF-8/1252 手写,其余代码页走 iconv);`Util.cpp` 代码页→字体表、`SetDefaultCodePage` 在启动时按 40250 Main 调用;`DefaultFont_*` 原样;`fnt` 资源类型注册。`port.text`(Tahoma 12 行高 12、宽度/字符定位/居中、CP949 往返)+ `port.app_loop` + `python_host_test.gd` 验证。TODO:Android 的 `/system/fonts` 没有 Tahoma/Gulim,需要随包带字体(现走 Roboto/Noto 替换,度量与原版不同);字形与 Windows GDI 的逐像素对比未做。 |
2. **2V1 — 登录/选角**:加入 `PythonNetworkStream{,PhaseHandShake,PhaseLogin,PhaseSelect,PhaseLoading}.cpp`、
`PythonNetworkStreamModule.cpp`、AccountConnector 及登录/选角脚本真实调用到的模块。验收为 FakeServer 离线完成 phase 顺序,
再以真服 smoke 证明登录、角色列表和选择进入 Loading;未验证的服务器分支记 `NEEDS_LIVE`。