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:
co-authored by
Claude Opus 5.5
parent
141206cb69
commit
afe63bfa61
@@ -133,14 +133,32 @@ wndMgr.Show(_ui_clip)
|
||||
surface.free()
|
||||
_ck(Metin2PythonHost.run_line("wndMgr.Destroy(_ui_bar)") == "", "Bar 窗口已销毁")
|
||||
_ck(Metin2PythonHost.run_line("grp.RestoreViewport(); wndMgr.Destroy(_ui_clip)") == "", "裁剪窗口已销毁")
|
||||
_ck(Metin2PythonHost.run_line("_ui_text_probe = _UIProbe(); _ui_text = wndMgr.RegisterTextLine(_ui_text_probe, 'UI'); wndMgr.SetWindowPosition(_ui_text, 70, 80); wndMgr.SetText(_ui_text, 'Hello'); wndMgr.SetFontColor(_ui_text, 1.0, 0.5, 0.0); wndMgr.Show(_ui_text)") == "",
|
||||
"40250 TextLine 已创建")
|
||||
_ck(Metin2PythonHost.run_line("_ui_text_probe = _UIProbe(); _ui_text = wndMgr.RegisterTextLine(_ui_text_probe, 'UI'); wndMgr.SetWindowPosition(_ui_text, 70, 80); wndMgr.SetFontName(_ui_text, 'Tahoma:12'); wndMgr.SetText(_ui_text, 'Hello'); wndMgr.SetFontColor(_ui_text, 1.0, 0.5, 0.0); wndMgr.Show(_ui_text)") == "",
|
||||
"40250 TextLine 已创建(和 ui.TextLine.__init__ 一样先 SetFontName)")
|
||||
draws = Metin2PythonHost.ui_render_commands()
|
||||
var has_text := false
|
||||
for draw in draws:
|
||||
if draw["kind"] == "text" and draw["text"] == "Hello" and draw["x1"] == 70.0 and draw["y1"] == 80.0:
|
||||
has_text = true
|
||||
_ck(has_text, "40250 TextLine 文本进入 Godot Canvas 命令队列")
|
||||
var glyphs: Array = draws.filter(func(d): return d["kind"] == "image" and String(d["text"]).begins_with("mem:"))
|
||||
var min_x := INF
|
||||
for draw in glyphs:
|
||||
min_x = minf(min_x, draw["quad"][0].x)
|
||||
_ck(glyphs.size() == 5 and absf(min_x - 70.0) <= 1.5,
|
||||
"40250 TextLine 经 CGraphicFontTexture 字形页画成 5 个字形四边形(%d 个,左边 %.1f)" % [glyphs.size(), min_x])
|
||||
if not glyphs.is_empty():
|
||||
var page: Image = Metin2PythonHost.memory_texture(glyphs[0]["text"], -1)
|
||||
var inked := false
|
||||
if page != null:
|
||||
for y in page.get_height():
|
||||
for x in page.get_width():
|
||||
if page.get_pixel(x, y).a > 0.0:
|
||||
inked = true
|
||||
break
|
||||
if inked:
|
||||
break
|
||||
_ck(inked, "字形页(mem: 内存纹理)有字形像素")
|
||||
var page_surface := preload("res://python_ui_surface.gd").new()
|
||||
var page_texture: Texture2D = page_surface._texture(glyphs[0]["text"])
|
||||
_ck(page_texture != null and page_texture == page_surface._texture(glyphs[0]["text"]),
|
||||
"Canvas 按 mem:<id> 缓存字形页纹理")
|
||||
page_surface.free()
|
||||
_ck(Metin2PythonHost.run_line("wndMgr.Destroy(_ui_text)") == "", "TextLine 已销毁")
|
||||
var image_path := "locale/en/ui/vkey/key_backspace.tga"
|
||||
if Metin2Pack.exists(image_path):
|
||||
@@ -193,16 +211,21 @@ func _run_app_loop() -> void:
|
||||
reached = true
|
||||
break
|
||||
_ck(reached, "帧推进后进入 LoginWindow")
|
||||
var glyphs_before := _glyph_quads()
|
||||
_ck(Metin2PythonHost.run_line("_stream.popupWindow.Open('POPUP_PROBE')\nassert _stream.popupWindow.IsShow()") == "", "PopupDialog 已打开")
|
||||
Metin2PythonHost.ui_update()
|
||||
var has_popup := false
|
||||
for draw in Metin2PythonHost.ui_render_commands():
|
||||
if draw["kind"] == "text" and draw["text"] == "POPUP_PROBE":
|
||||
has_popup = true
|
||||
_ck(has_popup, "弹窗文字进入 Godot Canvas 命令队列")
|
||||
_ck(_glyph_quads() >= glyphs_before + 11, "弹窗文字的字形进入 Godot Canvas 命令队列")
|
||||
Metin2PythonHost.ui_key(1, true) # DIK_ESCAPE
|
||||
Metin2PythonHost.ui_key(1, false)
|
||||
Metin2PythonHost.ui_update()
|
||||
_ck(Metin2PythonHost.run_line("assert not _stream.popupWindow.IsShow()") == "", "ESC 关闭弹窗")
|
||||
Metin2PythonHost.stop()
|
||||
_ck(not Metin2PythonHost.is_running() and not Metin2PythonHost.is_app_looping(), "stop() 结束 app.Loop() 并收尾")
|
||||
|
||||
# CGraphicTextInstance draws one image quad per glyph from a "mem:<id>@<rev>" font page.
|
||||
func _glyph_quads() -> int:
|
||||
var count := 0
|
||||
for draw in Metin2PythonHost.ui_render_commands():
|
||||
if draw["kind"] == "image" and String(draw["text"]).begins_with("mem:"):
|
||||
count += 1
|
||||
return count
|
||||
|
||||
Reference in New Issue
Block a user