Add blood decals, gore, mobile HUD, web start gate + touch/perf tests
Remove tools/fstest.html scratch page used to probe browser fullscreen/orientation APIs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EznnY8rH2dXhtono1kwsXg
This commit is contained in:
+40
-17
@@ -43,9 +43,11 @@ static func _convert(skel: Skeleton3D, mi: MeshInstance3D) -> bool:
|
||||
bind_bone.append(bone)
|
||||
bind_pose.append(skin.get_bind_pose(b))
|
||||
|
||||
# Accumulate SurfaceTool geometry per destination bone.
|
||||
var st_by_bone: Dictionary = {} # bone index -> SurfaceTool
|
||||
var mat_by_bone: Dictionary = {} # bone index -> Material (first seen)
|
||||
# Accumulate SurfaceTool geometry per (destination bone, source surface). Keying on the
|
||||
# surface too — not just the bone — is what preserves materials: a head bone that carries
|
||||
# both the skin and hair surfaces must stay two pieces with two materials, otherwise every
|
||||
# surface funnelled to a bone collapses onto one material (bald matadors, wrong uniforms).
|
||||
var groups: Dictionary = {} # "bone:surface" -> {"st": SurfaceTool, "mat": Material, "bone": int}
|
||||
|
||||
for s: int in mesh.get_surface_count():
|
||||
var arr := mesh.surface_get_arrays(s)
|
||||
@@ -56,7 +58,13 @@ static func _convert(skel: Skeleton3D, mi: MeshInstance3D) -> bool:
|
||||
var bones: PackedInt32Array = arr[Mesh.ARRAY_BONES]
|
||||
var weights: PackedFloat32Array = arr[Mesh.ARRAY_WEIGHTS]
|
||||
var idx: PackedInt32Array = arr[Mesh.ARRAY_INDEX]
|
||||
var mat := mesh.surface_get_material(s)
|
||||
# Honour a per-instance override (whole mesh) or per-surface override the scene set,
|
||||
# falling back to the material baked into the mesh surface.
|
||||
var mat: Material = mi.material_override
|
||||
if mat == null:
|
||||
mat = mi.get_surface_override_material(s)
|
||||
if mat == null:
|
||||
mat = mesh.surface_get_material(s)
|
||||
var infl := 8 if (mesh.surface_get_format(s) & Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS) else 4
|
||||
|
||||
var tri := PackedInt32Array()
|
||||
@@ -74,12 +82,14 @@ static func _convert(skel: Skeleton3D, mi: MeshInstance3D) -> bool:
|
||||
var bind := _dominant_bind([a, b, c], bones, weights, infl)
|
||||
var bone := bind_bone[bind]
|
||||
var pose := bind_pose[bind]
|
||||
var st: SurfaceTool = st_by_bone.get(bone)
|
||||
if st == null:
|
||||
st = SurfaceTool.new()
|
||||
st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||
st_by_bone[bone] = st
|
||||
mat_by_bone[bone] = mat
|
||||
var key := "%d:%d" % [bone, s]
|
||||
var group: Dictionary = groups.get(key, {})
|
||||
if group.is_empty():
|
||||
var new_st := SurfaceTool.new()
|
||||
new_st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||
group = {"st": new_st, "mat": mat, "bone": bone}
|
||||
groups[key] = group
|
||||
var st: SurfaceTool = group["st"]
|
||||
for v: int in [a, b, c]:
|
||||
if cols.size() > v:
|
||||
st.set_color(cols[v])
|
||||
@@ -89,19 +99,32 @@ static func _convert(skel: Skeleton3D, mi: MeshInstance3D) -> bool:
|
||||
st.set_normal((pose.basis * norms[v]).normalized())
|
||||
st.add_vertex(pose * verts[v])
|
||||
|
||||
if st_by_bone.is_empty():
|
||||
if groups.is_empty():
|
||||
return false
|
||||
|
||||
for bone: int in st_by_bone:
|
||||
# Combine all of a bone's surface-groups into ONE mesh under ONE BoneAttachment (each group
|
||||
# stays its own surface + material). Same draw calls as before, but roughly half the nodes to
|
||||
# transform/cull every frame — which is what a phone feels while ragdolls drive the skeleton.
|
||||
var by_bone: Dictionary = {} # bone:int -> Array[Dictionary]
|
||||
for key: String in groups:
|
||||
var group: Dictionary = groups[key]
|
||||
var bone: int = group["bone"]
|
||||
if not by_bone.has(bone):
|
||||
by_bone[bone] = []
|
||||
(by_bone[bone] as Array).append(group)
|
||||
|
||||
for bone: int in by_bone:
|
||||
var att := BoneAttachment3D.new()
|
||||
att.bone_name = skel.get_bone_name(bone)
|
||||
skel.add_child(att)
|
||||
var piece := MeshInstance3D.new()
|
||||
var st: SurfaceTool = st_by_bone[bone]
|
||||
var m := st.commit()
|
||||
if mat_by_bone[bone] != null:
|
||||
m.surface_set_material(0, mat_by_bone[bone])
|
||||
piece.mesh = m
|
||||
var combined := ArrayMesh.new()
|
||||
for group: Dictionary in by_bone[bone]:
|
||||
var st: SurfaceTool = group["st"]
|
||||
st.commit(combined)
|
||||
if group["mat"] != null:
|
||||
combined.surface_set_material(combined.get_surface_count() - 1, group["mat"])
|
||||
piece.mesh = combined
|
||||
att.add_child(piece)
|
||||
|
||||
# Hide (don't free) the original: keeps the node for any gameplay code that references
|
||||
|
||||
Reference in New Issue
Block a user