feat: complete native client rendering parity updates
This commit is contained in:
+284
-70
@@ -8,16 +8,26 @@ const UiAssets = preload("res://ui/ui_assets.gd")
|
||||
const KEY_TO_DIK := {
|
||||
KEY_ESCAPE: 0x01, KEY_1: 0x02, KEY_2: 0x03, KEY_3: 0x04,
|
||||
KEY_4: 0x05, KEY_5: 0x06, KEY_6: 0x07, KEY_7: 0x08,
|
||||
KEY_8: 0x09, KEY_9: 0x0a, KEY_0: 0x0b, KEY_BACKSPACE: 0x0e,
|
||||
KEY_TAB: 0x0f, KEY_Q: 0x10, KEY_W: 0x11, KEY_E: 0x12,
|
||||
KEY_R: 0x13, KEY_T: 0x14, KEY_Y: 0x15, KEY_U: 0x16,
|
||||
KEY_I: 0x17, KEY_O: 0x18, KEY_P: 0x19, KEY_ENTER: 0x1c,
|
||||
KEY_A: 0x1e, KEY_S: 0x1f, KEY_D: 0x20, KEY_F: 0x21,
|
||||
KEY_G: 0x22, KEY_H: 0x23, KEY_J: 0x24, KEY_K: 0x25,
|
||||
KEY_L: 0x26, KEY_Z: 0x2c, KEY_X: 0x2d, KEY_C: 0x2e,
|
||||
KEY_8: 0x09, KEY_9: 0x0a, KEY_0: 0x0b, KEY_MINUS: 0x0c,
|
||||
KEY_EQUAL: 0x0d, KEY_BACKSPACE: 0x0e, KEY_TAB: 0x0f,
|
||||
KEY_Q: 0x10, KEY_W: 0x11, KEY_E: 0x12, KEY_R: 0x13,
|
||||
KEY_T: 0x14, KEY_Y: 0x15, KEY_U: 0x16, KEY_I: 0x17,
|
||||
KEY_O: 0x18, KEY_P: 0x19, KEY_BRACKETLEFT: 0x1a, KEY_BRACKETRIGHT: 0x1b,
|
||||
KEY_ENTER: 0x1c, KEY_CTRL: 0x1d, KEY_A: 0x1e, KEY_S: 0x1f,
|
||||
KEY_D: 0x20, KEY_F: 0x21, KEY_G: 0x22, KEY_H: 0x23,
|
||||
KEY_J: 0x24, KEY_K: 0x25, KEY_L: 0x26, KEY_SEMICOLON: 0x27,
|
||||
KEY_APOSTROPHE: 0x28, KEY_QUOTELEFT: 0x29, KEY_SHIFT: 0x2a,
|
||||
KEY_BACKSLASH: 0x2b, KEY_Z: 0x2c, KEY_X: 0x2d, KEY_C: 0x2e,
|
||||
KEY_V: 0x2f, KEY_B: 0x30, KEY_N: 0x31, KEY_M: 0x32,
|
||||
KEY_SPACE: 0x39, KEY_UP: 0xc8, KEY_LEFT: 0xcb,
|
||||
KEY_RIGHT: 0xcd, KEY_DOWN: 0xd0,
|
||||
KEY_COMMA: 0x33, KEY_PERIOD: 0x34, KEY_SLASH: 0x35,
|
||||
KEY_ALT: 0x38, KEY_SPACE: 0x39,
|
||||
KEY_F1: 0x3b, KEY_F2: 0x3c, KEY_F3: 0x3d, KEY_F4: 0x3e,
|
||||
KEY_F5: 0x3f, KEY_F6: 0x40, KEY_F7: 0x41, KEY_F8: 0x42,
|
||||
KEY_F9: 0x43, KEY_F10: 0x44, KEY_F11: 0x57, KEY_F12: 0x58,
|
||||
KEY_HOME: 0xc7, KEY_UP: 0xc8, KEY_PAGEUP: 0xc9,
|
||||
KEY_LEFT: 0xcb, KEY_RIGHT: 0xcd, KEY_END: 0xcf,
|
||||
KEY_DOWN: 0xd0, KEY_PAGEDOWN: 0xd1, KEY_INSERT: 0xd2,
|
||||
KEY_DELETE: 0xd3,
|
||||
}
|
||||
|
||||
# Win32 virtual-key codes of the keys EditLine.OnIMEKeyDown handles (WM_KEYDOWN → OnIMEKeyDown);
|
||||
@@ -36,6 +46,11 @@ const KEY_TO_CHAR := {
|
||||
# "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 := {}
|
||||
var _tex_info_cache := {}
|
||||
var _color_cache := {}
|
||||
var _white_color_array := PackedColorArray([Color.WHITE])
|
||||
var _asset_root_path := ""
|
||||
var _segments_used := 0
|
||||
|
||||
# True when this surface started system.py itself (run_app) and so owns the interpreter's lifetime.
|
||||
var _owns_app := false
|
||||
@@ -80,6 +95,8 @@ func _exit_tree() -> void:
|
||||
func _ready() -> void:
|
||||
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
texture_repeat = CanvasItem.TEXTURE_REPEAT_ENABLED
|
||||
_asset_root_path = AssetRoot.path()
|
||||
_sync_size()
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
@@ -100,7 +117,10 @@ func _process(_delta: float) -> void:
|
||||
get_tree().quit(0)
|
||||
return
|
||||
if Metin2PythonHost.is_running():
|
||||
var profile_start := Time.get_ticks_usec() if _profile_frame else 0
|
||||
Metin2PythonHost.ui_update()
|
||||
if profile_start != 0:
|
||||
profile_ui_update_ms = float(Time.get_ticks_usec() - profile_start) / 1000.0
|
||||
queue_redraw()
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
@@ -112,10 +132,30 @@ func _gui_input(event: InputEvent) -> void:
|
||||
if event.button_index >= MOUSE_BUTTON_LEFT and event.button_index <= MOUSE_BUTTON_MIDDLE:
|
||||
Metin2PythonHost.ui_mouse_button(event.button_index, event.pressed,
|
||||
int(event.position.x), int(event.position.y))
|
||||
elif event.pressed:
|
||||
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
||||
var factor: float = event.factor if event.factor > 0.0 else 1.0
|
||||
Metin2PythonHost.ui_mouse_wheel(int(round(120.0 * factor)))
|
||||
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
||||
var factor: float = event.factor if event.factor > 0.0 else 1.0
|
||||
Metin2PythonHost.ui_mouse_wheel(-int(round(120.0 * factor)))
|
||||
elif event is InputEventPanGesture:
|
||||
# macOS trackpad two-finger scroll: scrolling up has negative delta.y, zooming in
|
||||
var delta: int = -int(round(event.delta.y * 30.0))
|
||||
if delta != 0:
|
||||
Metin2PythonHost.ui_mouse_wheel(delta)
|
||||
elif event is InputEventMagnifyGesture:
|
||||
# macOS trackpad pinch to zoom: factor > 1.0 is zoom in
|
||||
var delta: int = int(round((event.factor - 1.0) * 600.0))
|
||||
if delta != 0:
|
||||
Metin2PythonHost.ui_mouse_wheel(delta)
|
||||
|
||||
func _unhandled_key_input(event: InputEvent) -> void:
|
||||
if event is InputEventKey and Metin2PythonHost.is_running():
|
||||
var dik: int = KEY_TO_DIK.get(event.physical_keycode, 0)
|
||||
var code: int = event.physical_keycode
|
||||
var dik: int = KEY_TO_DIK.get(code, 0)
|
||||
if dik == 0 and event.keycode != 0:
|
||||
dik = KEY_TO_DIK.get(event.keycode, 0)
|
||||
if dik != 0:
|
||||
Metin2PythonHost.ui_key(dik, event.pressed)
|
||||
if event.pressed:
|
||||
@@ -159,79 +199,247 @@ var _segments: Array[RID] = []
|
||||
var _materials: Array[RID] = []
|
||||
var _mask_shader := RID()
|
||||
var _white: ImageTexture
|
||||
var _profile_frame := OS.has_environment("MT_PROFILE_FRAME")
|
||||
var profile_ui_update_ms := 0.0
|
||||
var profile_draw_ms := 0.0
|
||||
|
||||
func _get_color_array(argb: int) -> PackedColorArray:
|
||||
if argb == 0xFFFFFFFF or argb == -1:
|
||||
return _white_color_array
|
||||
var arr: PackedColorArray = _color_cache.get(argb, PackedColorArray())
|
||||
if not arr.is_empty():
|
||||
return arr
|
||||
var c := Color8((argb >> 16) & 255, (argb >> 8) & 255, argb & 255, (argb >> 24) & 255)
|
||||
arr = PackedColorArray([c])
|
||||
_color_cache[argb] = arr
|
||||
return arr
|
||||
|
||||
func _get_tex_draw_info(name: String) -> Array:
|
||||
var info: Array = _tex_info_cache.get(name, [])
|
||||
if not info.is_empty():
|
||||
return info
|
||||
var texture: Texture2D = _texture(name)
|
||||
if texture == null:
|
||||
_tex_info_cache[name] = []
|
||||
return []
|
||||
var tex_rid: RID = texture.get_rid()
|
||||
var is_atlas := false
|
||||
var u0 := 0.0
|
||||
var v0 := 0.0
|
||||
var du := 1.0
|
||||
var dv := 1.0
|
||||
var default_uv := PackedVector2Array()
|
||||
if texture is AtlasTexture:
|
||||
var at: AtlasTexture = texture
|
||||
if at.atlas != null:
|
||||
tex_rid = at.atlas.get_rid()
|
||||
var asize: Vector2 = at.atlas.get_size()
|
||||
if asize.x > 0 and asize.y > 0:
|
||||
is_atlas = true
|
||||
var r: Rect2 = at.region
|
||||
u0 = r.position.x / asize.x
|
||||
v0 = r.position.y / asize.y
|
||||
du = r.size.x / asize.x
|
||||
dv = r.size.y / asize.y
|
||||
default_uv = PackedVector2Array([
|
||||
Vector2(u0, v0),
|
||||
Vector2(u0 + du, v0),
|
||||
Vector2(u0 + du, v0 + dv),
|
||||
Vector2(u0, v0 + dv)
|
||||
])
|
||||
if default_uv.is_empty():
|
||||
default_uv = PackedVector2Array([
|
||||
Vector2(0, 0),
|
||||
Vector2(1, 0),
|
||||
Vector2(1, 1),
|
||||
Vector2(0, 1)
|
||||
])
|
||||
info = [tex_rid, is_atlas, u0, v0, du, dv, default_uv, texture]
|
||||
_tex_info_cache[name] = info
|
||||
return info
|
||||
|
||||
func _draw() -> void:
|
||||
var used := 0
|
||||
var profile_start := Time.get_ticks_usec() if _profile_frame else 0
|
||||
var fg_used := 0
|
||||
var fg_plain := false
|
||||
var masked := 0
|
||||
var plain := false
|
||||
for segment in _segments:
|
||||
RenderingServer.canvas_item_clear(segment)
|
||||
|
||||
for i in _segments_used:
|
||||
RenderingServer.canvas_item_clear(_segments[i])
|
||||
_segments_used = 0
|
||||
|
||||
if not Metin2PythonHost.is_running():
|
||||
return
|
||||
for command in Metin2PythonHost.ui_render_commands():
|
||||
var argb: int = command["argb"]
|
||||
var color := Color8((argb >> 16) & 255, (argb >> 8) & 255,
|
||||
argb & 255, (argb >> 24) & 255)
|
||||
var p1 := Vector2(command["x1"], command["y1"])
|
||||
var p2 := Vector2(command["x2"], command["y2"])
|
||||
var clip := Rect2(Vector2(command["clip_x1"], command["clip_y1"]),
|
||||
Vector2(command["clip_x2"] - command["clip_x1"],
|
||||
command["clip_y2"] - command["clip_y1"]))
|
||||
if command["kind"] == "bar":
|
||||
var visible := Rect2(p1, p2 - p1).intersection(clip)
|
||||
if visible.has_area():
|
||||
if not plain:
|
||||
used = _segment(used, RID())
|
||||
plain = true
|
||||
RenderingServer.canvas_item_add_rect(_segments[used - 1], visible, color)
|
||||
elif command["kind"] == "gradient_bar":
|
||||
var visible := Rect2(p1, p2 - p1).intersection(clip)
|
||||
if visible.has_area():
|
||||
if not plain:
|
||||
used = _segment(used, RID())
|
||||
plain = true
|
||||
var bottom_argb: int = command["end_argb"]
|
||||
|
||||
var has_3d: bool = Metin2PythonHost.has_3d_draws()
|
||||
|
||||
for command in Metin2PythonHost.ui_render_commands_batched():
|
||||
# Skip background UI commands when 3D is active, as the 3D surface renders the background Quad
|
||||
if has_3d and bool(command.get(&"behind_3d", false)):
|
||||
continue
|
||||
var kind: Variant = command[&"kind"]
|
||||
if kind == &"glyph_batch":
|
||||
var info := _get_tex_draw_info(command[&"text"])
|
||||
if info.is_empty():
|
||||
continue
|
||||
if not fg_plain:
|
||||
fg_used = _segment(fg_used, RID())
|
||||
fg_plain = true
|
||||
RenderingServer.canvas_item_add_triangle_array(_segments[fg_used - 1],
|
||||
command[&"indices"], command[&"points"], command[&"colors"],
|
||||
command[&"uvs"], PackedInt32Array(), PackedFloat32Array(), info[0])
|
||||
continue
|
||||
|
||||
var x1: float = command[&"x1"]
|
||||
var y1: float = command[&"y1"]
|
||||
var x2: float = command[&"x2"]
|
||||
var y2: float = command[&"y2"]
|
||||
var cx1: float = command[&"clip_x1"]
|
||||
var cy1: float = command[&"clip_y1"]
|
||||
var cx2: float = command[&"clip_x2"]
|
||||
var cy2: float = command[&"clip_y2"]
|
||||
|
||||
# 1) Completely culled by scissor?
|
||||
if x2 <= cx1 or x1 >= cx2 or y2 <= cy1 or y1 >= cy2:
|
||||
continue
|
||||
|
||||
var argb: int = command[&"argb"]
|
||||
var target_segments := _segments
|
||||
|
||||
if kind == &"image":
|
||||
var text_name: String = command.get(&"text", "")
|
||||
var mask_name: String = command.get(&"mask", "")
|
||||
var mask_tex: Texture2D = _texture(mask_name) if not mask_name.is_empty() else null
|
||||
if text_name.is_empty() and mask_tex != null:
|
||||
text_name = "__white__"
|
||||
|
||||
var info := _get_tex_draw_info(text_name)
|
||||
if info.is_empty():
|
||||
continue
|
||||
var tex_rid: RID = info[0]
|
||||
var is_atlas: bool = info[1]
|
||||
var u0: float = info[2]
|
||||
var v0: float = info[3]
|
||||
var du: float = info[4]
|
||||
var dv: float = info[5]
|
||||
|
||||
var quad: PackedVector2Array = command[&"quad"]
|
||||
var quad_uv: PackedVector2Array = command[&"uv"]
|
||||
|
||||
var needs_clip := x1 < cx1 or x2 > cx2 or y1 < cy1 or y2 > cy2
|
||||
var poly_pts: PackedVector2Array
|
||||
var poly_uv: PackedVector2Array
|
||||
|
||||
if not needs_clip:
|
||||
poly_pts = PackedVector2Array([quad[0], quad[1], quad[3], quad[2]])
|
||||
var is_full_uv := quad_uv[0] == Vector2.ZERO and quad_uv[1] == Vector2(1, 0) and quad_uv[2] == Vector2(0, 1) and quad_uv[3] == Vector2.ONE
|
||||
if is_full_uv:
|
||||
poly_uv = info[6]
|
||||
elif is_atlas:
|
||||
poly_uv = PackedVector2Array([
|
||||
Vector2(u0 + quad_uv[0].x * du, v0 + quad_uv[0].y * dv),
|
||||
Vector2(u0 + quad_uv[1].x * du, v0 + quad_uv[1].y * dv),
|
||||
Vector2(u0 + quad_uv[3].x * du, v0 + quad_uv[3].y * dv),
|
||||
Vector2(u0 + quad_uv[2].x * du, v0 + quad_uv[2].y * dv)
|
||||
])
|
||||
else:
|
||||
poly_uv = PackedVector2Array([quad_uv[0], quad_uv[1], quad_uv[3], quad_uv[2]])
|
||||
else:
|
||||
var mapped_uv: PackedVector2Array
|
||||
if is_atlas:
|
||||
mapped_uv = PackedVector2Array([
|
||||
Vector2(u0 + quad_uv[0].x * du, v0 + quad_uv[0].y * dv),
|
||||
Vector2(u0 + quad_uv[1].x * du, v0 + quad_uv[1].y * dv),
|
||||
Vector2(u0 + quad_uv[2].x * du, v0 + quad_uv[2].y * dv),
|
||||
Vector2(u0 + quad_uv[3].x * du, v0 + quad_uv[3].y * dv)
|
||||
])
|
||||
else:
|
||||
mapped_uv = quad_uv
|
||||
var clip_rect := Rect2(cx1, cy1, cx2 - cx1, cy2 - cy1)
|
||||
var clipped := _clip_quad(quad, mapped_uv, clip_rect)
|
||||
if clipped[0].size() < 3:
|
||||
continue
|
||||
poly_pts = clipped[0]
|
||||
poly_uv = clipped[1]
|
||||
|
||||
if mask_tex != null:
|
||||
var mat_rid := _mask_material(masked, mask_tex, quad_uv, command[&"mask_uv"])
|
||||
fg_used = _segment(fg_used, mat_rid)
|
||||
fg_plain = false
|
||||
masked += 1
|
||||
elif not fg_plain:
|
||||
fg_used = _segment(fg_used, RID())
|
||||
fg_plain = true
|
||||
var seg_idx := fg_used - 1
|
||||
RenderingServer.canvas_item_add_polygon(target_segments[seg_idx], poly_pts,
|
||||
_get_color_array(argb), poly_uv, tex_rid)
|
||||
|
||||
elif kind == &"bar":
|
||||
var bx1 := maxf(x1, cx1)
|
||||
var by1 := maxf(y1, cy1)
|
||||
var bx2 := minf(x2, cx2)
|
||||
var by2 := minf(y2, cy2)
|
||||
if bx2 > bx1 and by2 > by1:
|
||||
if not fg_plain:
|
||||
fg_used = _segment(fg_used, RID())
|
||||
fg_plain = true
|
||||
var seg_idx := fg_used - 1
|
||||
var color := Color8((argb >> 16) & 255, (argb >> 8) & 255,
|
||||
argb & 255, (argb >> 24) & 255)
|
||||
RenderingServer.canvas_item_add_rect(target_segments[seg_idx],
|
||||
Rect2(bx1, by1, bx2 - bx1, by2 - by1), color)
|
||||
|
||||
elif kind == &"gradient_bar":
|
||||
var bx1 := maxf(x1, cx1)
|
||||
var by1 := maxf(y1, cy1)
|
||||
var bx2 := minf(x2, cx2)
|
||||
var by2 := minf(y2, cy2)
|
||||
if bx2 > bx1 and by2 > by1:
|
||||
if not fg_plain:
|
||||
fg_used = _segment(fg_used, RID())
|
||||
fg_plain = true
|
||||
var seg_idx := fg_used - 1
|
||||
var color := Color8((argb >> 16) & 255, (argb >> 8) & 255,
|
||||
argb & 255, (argb >> 24) & 255)
|
||||
var bottom_argb: int = command[&"end_argb"]
|
||||
var bottom := Color8((bottom_argb >> 16) & 255, (bottom_argb >> 8) & 255,
|
||||
bottom_argb & 255, (bottom_argb >> 24) & 255)
|
||||
var top_factor := (visible.position.y - p1.y) / (p2.y - p1.y)
|
||||
var bottom_factor := (visible.end.y - p1.y) / (p2.y - p1.y)
|
||||
RenderingServer.canvas_item_add_polygon(_segments[used - 1],
|
||||
PackedVector2Array([visible.position, Vector2(visible.end.x, visible.position.y),
|
||||
visible.end, Vector2(visible.position.x, visible.end.y)]),
|
||||
var top_factor := (by1 - y1) / (y2 - y1) if y2 != y1 else 0.0
|
||||
var bottom_factor := (by2 - y1) / (y2 - y1) if y2 != y1 else 1.0
|
||||
RenderingServer.canvas_item_add_polygon(target_segments[seg_idx],
|
||||
PackedVector2Array([Vector2(bx1, by1), Vector2(bx2, by1),
|
||||
Vector2(bx2, by2), Vector2(bx1, by2)]),
|
||||
PackedColorArray([color.lerp(bottom, top_factor), color.lerp(bottom, top_factor),
|
||||
color.lerp(bottom, bottom_factor), color.lerp(bottom, bottom_factor)]))
|
||||
elif command["kind"] == "line":
|
||||
var segment := _clip_line(p1, p2, clip)
|
||||
|
||||
elif kind == &"line":
|
||||
var clip_rect := Rect2(cx1, cy1, cx2 - cx1, cy2 - cy1)
|
||||
var p1 := Vector2(x1, y1)
|
||||
var p2 := Vector2(x2, y2)
|
||||
var segment := _clip_line(p1, p2, clip_rect)
|
||||
if segment.size() == 2:
|
||||
if not plain:
|
||||
used = _segment(used, RID())
|
||||
plain = true
|
||||
RenderingServer.canvas_item_add_line(_segments[used - 1], segment[0], segment[1], color)
|
||||
elif command["kind"] == "image":
|
||||
var texture: Texture2D = _texture(command["text"])
|
||||
var mask: Texture2D = _texture(command["mask"]) if command.has("mask") else null
|
||||
if mask != null and texture == null:
|
||||
texture = _white_texture()
|
||||
if texture != null:
|
||||
var clipped := _clip_quad(command["quad"], command["uv"], clip)
|
||||
if clipped[0].size() >= 3:
|
||||
if mask != null:
|
||||
used = _segment(used, _mask_material(masked, mask, command["uv"], command["mask_uv"]))
|
||||
masked += 1
|
||||
plain = false
|
||||
elif not plain:
|
||||
used = _segment(used, RID())
|
||||
plain = true
|
||||
RenderingServer.canvas_item_add_polygon(_segments[used - 1], clipped[0],
|
||||
PackedColorArray([color]), clipped[1], texture.get_rid())
|
||||
if not fg_plain:
|
||||
fg_used = _segment(fg_used, RID())
|
||||
fg_plain = true
|
||||
var seg_idx := fg_used - 1
|
||||
var color := Color8((argb >> 16) & 255, (argb >> 8) & 255,
|
||||
argb & 255, (argb >> 24) & 255)
|
||||
RenderingServer.canvas_item_add_line(target_segments[seg_idx], segment[0], segment[1], color)
|
||||
|
||||
_segments_used = fg_used
|
||||
if profile_start != 0:
|
||||
profile_draw_ms = float(Time.get_ticks_usec() - profile_start) / 1000.0
|
||||
|
||||
# Opens the next pooled child item (draw order = index) with the given material; returns the count used.
|
||||
func _segment(used: int, material: RID) -> int:
|
||||
if used == _segments.size():
|
||||
var pool := _segments
|
||||
var parent_item: RID = get_canvas_item()
|
||||
if used == pool.size():
|
||||
var item := RenderingServer.canvas_item_create()
|
||||
RenderingServer.canvas_item_set_parent(item, get_canvas_item())
|
||||
_segments.push_back(item)
|
||||
var item := _segments[used]
|
||||
RenderingServer.canvas_item_set_parent(item, parent_item)
|
||||
RenderingServer.canvas_item_set_default_texture_repeat(item, RenderingServer.CANVAS_ITEM_TEXTURE_REPEAT_ENABLED)
|
||||
pool.push_back(item)
|
||||
var item := pool[used]
|
||||
RenderingServer.canvas_item_set_draw_index(item, used)
|
||||
RenderingServer.canvas_item_set_material(item, material)
|
||||
return used + 1
|
||||
@@ -260,8 +468,11 @@ func _white_texture() -> Texture2D:
|
||||
return _white
|
||||
|
||||
func _texture(name: String) -> Texture2D:
|
||||
if name == "__white__":
|
||||
return _white_texture()
|
||||
if not name.begins_with("mem:"):
|
||||
return UiAssets.load_tex(AssetRoot.path(), name)
|
||||
var root := _asset_root_path if not _asset_root_path.is_empty() else AssetRoot.path()
|
||||
return UiAssets.load_tex(root, 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
|
||||
@@ -292,6 +503,9 @@ func _clip_quad(quad: PackedVector2Array, uv: PackedVector2Array, clip: Rect2) -
|
||||
var det := edge_u.cross(edge_v)
|
||||
if is_zero_approx(det):
|
||||
return [PackedVector2Array(), PackedVector2Array()]
|
||||
if clip.has_point(quad[0]) and clip.has_point(quad[1]) \
|
||||
and clip.has_point(quad[2]) and clip.has_point(quad[3]):
|
||||
return [outline, PackedVector2Array([uv[0], uv[1], uv[3], uv[2]])]
|
||||
var rect := PackedVector2Array([clip.position, Vector2(clip.end.x, clip.position.y),
|
||||
clip.end, Vector2(clip.position.x, clip.end.y)])
|
||||
var pieces := Geometry2D.intersect_polygons(outline, rect)
|
||||
|
||||
Reference in New Issue
Block a user