refactor(M03): extract M2 animated scene finalizer
This commit is contained in:
@@ -75,6 +75,9 @@ const M2_MESH_LOAD_PIPELINE_STATE_SCRIPT := preload(
|
||||
const M2_ANIMATION_LOAD_PIPELINE_STATE_SCRIPT := preload(
|
||||
"res://src/render/m2/m2_animation_load_pipeline_state.gd"
|
||||
)
|
||||
const M2_ANIMATED_SCENE_FINALIZER_SCRIPT := preload(
|
||||
"res://src/render/m2/m2_animated_scene_finalizer.gd"
|
||||
)
|
||||
const M2_MESH_RESOURCE_CACHE_STATE_SCRIPT := preload(
|
||||
"res://src/render/m2/m2_mesh_resource_cache_state.gd"
|
||||
)
|
||||
@@ -274,6 +277,7 @@ var _m2_mesh_resource_cache_state := M2_MESH_RESOURCE_CACHE_STATE_SCRIPT.new()
|
||||
var _m2_mesh_resource_extractor := M2_MESH_RESOURCE_EXTRACTOR_SCRIPT.new()
|
||||
var _m2_mesh_load_pipeline_state := M2_MESH_LOAD_PIPELINE_STATE_SCRIPT.new()
|
||||
var _m2_animation_load_pipeline_state := M2_ANIMATION_LOAD_PIPELINE_STATE_SCRIPT.new()
|
||||
var _m2_animated_scene_finalizer := M2_ANIMATED_SCENE_FINALIZER_SCRIPT.new()
|
||||
var _wmo_build_jobs: Dictionary = {}
|
||||
var _wmo_build_queue: Array = []
|
||||
var _tile_loading_tasks: Dictionary = {}
|
||||
@@ -4238,20 +4242,21 @@ func _drain_m2_animation_loads() -> void:
|
||||
|
||||
var path := String(pending.get("path", ""))
|
||||
var resource: Resource = ResourceLoader.load_threaded_get(path)
|
||||
if resource is PackedScene:
|
||||
var node = (resource as PackedScene).instantiate()
|
||||
if node is Node3D:
|
||||
_repair_m2_animated_materials(normalized_rel, node as Node3D)
|
||||
var players := _find_animation_players_recursive(node)
|
||||
if not players.is_empty():
|
||||
_m2_prototype_cache_state.adopt_animated_prototype(
|
||||
var candidate := _m2_animated_scene_finalizer.instantiate_candidate(resource)
|
||||
if candidate != null:
|
||||
var material_source := _get_or_load_m2_material_prototype(normalized_rel)
|
||||
_m2_animated_scene_finalizer.repair_materials(candidate, material_source)
|
||||
var finalization := _m2_animated_scene_finalizer.finalize_candidate(candidate)
|
||||
var prototype: Node3D = finalization.get("prototype", null)
|
||||
if prototype != null:
|
||||
_m2_prototype_cache_state.adopt_animated_prototype(normalized_rel, prototype)
|
||||
if debug_streaming:
|
||||
print("M2_ANIM_CACHE path=%s cache=%s players=%d" % [
|
||||
normalized_rel,
|
||||
node as Node3D
|
||||
)
|
||||
if debug_streaming:
|
||||
print("M2_ANIM_CACHE path=%s cache=%s players=%d" % [normalized_rel, path, players.size()])
|
||||
continue
|
||||
node.free()
|
||||
path,
|
||||
int(finalization.get("animation_player_count", 0)),
|
||||
])
|
||||
continue
|
||||
_m2_prototype_cache_state.mark_animation_static(normalized_rel)
|
||||
|
||||
|
||||
@@ -4464,7 +4469,7 @@ func _start_m2_animations(root: Node, rel_path: String, instance_index: int) ->
|
||||
float(state.get("length", 0.0)),
|
||||
])
|
||||
|
||||
var players := _find_animation_players_recursive(root)
|
||||
var players := _m2_animated_scene_finalizer.animation_players_in_subtree(root)
|
||||
for player in players:
|
||||
var animation_name := _choose_default_m2_animation(player, rel_path)
|
||||
if animation_name.is_empty():
|
||||
@@ -4523,19 +4528,6 @@ func _choose_default_m2_animation(player: AnimationPlayer, rel_path: String = ""
|
||||
return String(names[0]) if not names.is_empty() else ""
|
||||
|
||||
|
||||
func _find_animation_players_recursive(root: Node) -> Array[AnimationPlayer]:
|
||||
var result: Array[AnimationPlayer] = []
|
||||
_collect_animation_players(root, result)
|
||||
return result
|
||||
|
||||
|
||||
func _collect_animation_players(node: Node, result: Array[AnimationPlayer]) -> void:
|
||||
if node is AnimationPlayer:
|
||||
result.append(node as AnimationPlayer)
|
||||
for child in node.get_children():
|
||||
_collect_animation_players(child, result)
|
||||
|
||||
|
||||
func _finish_m2_build_job(key: String) -> void:
|
||||
if not _m2_build_jobs.has(key):
|
||||
return
|
||||
@@ -4673,7 +4665,7 @@ func _prepare_m2_mesh_for_runtime(normalized_rel: String, mesh: Mesh) -> Mesh:
|
||||
func _prepare_m2_node_for_runtime(normalized_rel: String, root: Node3D) -> void:
|
||||
if root == null:
|
||||
return
|
||||
for mesh_instance in _find_mesh_instances_recursive(root):
|
||||
for mesh_instance in _m2_animated_scene_finalizer.mesh_instances_in_subtree(root):
|
||||
if mesh_instance == null or mesh_instance.mesh == null:
|
||||
continue
|
||||
var prepared := _prepare_m2_mesh_for_runtime(normalized_rel, mesh_instance.mesh)
|
||||
@@ -5000,32 +4992,6 @@ func _is_m2_animation_denied(normalized_rel: String) -> bool:
|
||||
return false
|
||||
|
||||
|
||||
func _repair_m2_animated_materials(normalized_rel: String, animated_root: Node3D) -> void:
|
||||
if animated_root == null:
|
||||
return
|
||||
var material_root := _get_or_load_m2_material_prototype(normalized_rel)
|
||||
if material_root == null:
|
||||
return
|
||||
|
||||
var source_meshes := _find_mesh_instances_recursive(material_root)
|
||||
var target_meshes := _find_mesh_instances_recursive(animated_root)
|
||||
if source_meshes.is_empty() or target_meshes.is_empty():
|
||||
return
|
||||
|
||||
var fallback_material := _first_mesh_material(source_meshes)
|
||||
for i in target_meshes.size():
|
||||
var target := target_meshes[i]
|
||||
if target == null or target.mesh == null:
|
||||
continue
|
||||
var source := source_meshes[mini(i, source_meshes.size() - 1)]
|
||||
for surface_idx in target.mesh.get_surface_count():
|
||||
var material := _mesh_instance_surface_material(source, surface_idx)
|
||||
if material == null:
|
||||
material = fallback_material
|
||||
if material != null:
|
||||
target.set_surface_override_material(surface_idx, material)
|
||||
|
||||
|
||||
func _get_or_load_m2_material_prototype(normalized_rel: String) -> Node3D:
|
||||
if normalized_rel.is_empty():
|
||||
return null
|
||||
@@ -5049,42 +5015,6 @@ func _get_or_load_m2_material_prototype(normalized_rel: String) -> Node3D:
|
||||
return null
|
||||
|
||||
|
||||
func _find_mesh_instances_recursive(root: Node) -> Array[MeshInstance3D]:
|
||||
var result: Array[MeshInstance3D] = []
|
||||
_collect_mesh_instances(root, result)
|
||||
return result
|
||||
|
||||
|
||||
func _collect_mesh_instances(node: Node, result: Array[MeshInstance3D]) -> void:
|
||||
if node is MeshInstance3D:
|
||||
result.append(node as MeshInstance3D)
|
||||
for child in node.get_children():
|
||||
_collect_mesh_instances(child, result)
|
||||
|
||||
|
||||
func _first_mesh_material(meshes: Array[MeshInstance3D]) -> Material:
|
||||
for mesh_instance in meshes:
|
||||
if mesh_instance == null or mesh_instance.mesh == null:
|
||||
continue
|
||||
for surface_idx in mesh_instance.mesh.get_surface_count():
|
||||
var material := _mesh_instance_surface_material(mesh_instance, surface_idx)
|
||||
if material != null:
|
||||
return material
|
||||
return null
|
||||
|
||||
|
||||
func _mesh_instance_surface_material(mesh_instance: MeshInstance3D, surface_idx: int) -> Material:
|
||||
if mesh_instance == null or mesh_instance.mesh == null:
|
||||
return null
|
||||
if surface_idx < mesh_instance.get_surface_override_material_count():
|
||||
var override_material := mesh_instance.get_surface_override_material(surface_idx)
|
||||
if override_material != null:
|
||||
return override_material
|
||||
if surface_idx < mesh_instance.mesh.get_surface_count():
|
||||
return mesh_instance.mesh.surface_get_material(surface_idx)
|
||||
return null
|
||||
|
||||
|
||||
func _glb_cache_is_safe_for_runtime_animation(cache_res_path: String) -> bool:
|
||||
var abs_path := ProjectSettings.globalize_path(cache_res_path)
|
||||
if not FileAccess.file_exists(abs_path):
|
||||
|
||||
Reference in New Issue
Block a user