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
@@ -20,6 +20,10 @@ const KEY_TO_DIK := {
|
||||
KEY_RIGHT: 0xcd, KEY_DOWN: 0xd0,
|
||||
}
|
||||
|
||||
# "mem:<id>" → [revision, ImageTexture]: the CGraphicFontTexture glyph pages, refetched when the
|
||||
# "@<revision>" of a command's name moves on (a glyph was added to the page).
|
||||
var _memory_textures := {}
|
||||
|
||||
# True when this surface started system.py itself (run_app) and so owns the interpreter's lifetime.
|
||||
var _owns_app := false
|
||||
|
||||
@@ -106,20 +110,34 @@ func _draw() -> void:
|
||||
var segment := _clip_line(p1, p2, clip)
|
||||
if segment.size() == 2:
|
||||
draw_line(segment[0], segment[1], color)
|
||||
elif command["kind"] == "text":
|
||||
var font: Font = ThemeDB.fallback_font
|
||||
if font != null:
|
||||
var baseline := p1 + Vector2(0, font.get_ascent(14))
|
||||
if clip.has_point(p1):
|
||||
draw_string(font, baseline, command["text"], HORIZONTAL_ALIGNMENT_LEFT,
|
||||
clip.end.x - p1.x, 14, color)
|
||||
elif command["kind"] == "image":
|
||||
var texture: Texture2D = UiAssets.load_tex(AssetRoot.path(), command["text"])
|
||||
var texture: Texture2D = _texture(command["text"])
|
||||
if texture != null:
|
||||
var clipped := _clip_quad(command["quad"], command["uv"], clip)
|
||||
if clipped[0].size() >= 3:
|
||||
draw_polygon(clipped[0], PackedColorArray([color]), clipped[1], texture)
|
||||
|
||||
func _texture(name: String) -> Texture2D:
|
||||
if not name.begins_with("mem:"):
|
||||
return UiAssets.load_tex(AssetRoot.path(), name)
|
||||
var at := name.find("@")
|
||||
var key := name.substr(0, at) if at >= 0 else name
|
||||
var revision := int(name.substr(at + 1)) if at >= 0 else 0
|
||||
var entry: Array = _memory_textures.get(key, [])
|
||||
if not entry.is_empty() and entry[0] == revision:
|
||||
return entry[1]
|
||||
var image: Image = Metin2PythonHost.memory_texture(name, -1)
|
||||
if image == null:
|
||||
_memory_textures.erase(key)
|
||||
return null
|
||||
var texture: ImageTexture = entry[1] if not entry.is_empty() else null
|
||||
if texture != null and texture.get_size() == Vector2(image.get_size()):
|
||||
texture.update(image)
|
||||
else:
|
||||
texture = ImageTexture.create_from_image(image)
|
||||
_memory_textures[key] = [revision, texture]
|
||||
return texture
|
||||
|
||||
# 40250's image quad (TL, TR, BL, BR) clipped to the viewport. The quad is a
|
||||
# parallelogram, so texture coordinates are an affine function of position and are recomputed for
|
||||
# the clipped outline. Returns [points, uvs]; empty points when nothing is visible.
|
||||
|
||||
Reference in New Issue
Block a user