Browse Source

Make MeshLibrary export do recursive depth-search for MeshInstance3D nodes

Makes MeshLibrary export do recursive depth-search for MeshInstance3D nodes.
smix8 1 year ago
parent
commit
4d0c21c131

+ 5 - 2
editor/editor_node.cpp

@@ -2026,8 +2026,11 @@ void EditorNode::_dialog_action(String p_file) {
 		} break;
 
 		case FILE_EXPORT_MESH_LIBRARY: {
+			bool merge_with_existing_library = file_export_lib_merge->is_pressed();
+			bool apply_mesh_instance_transforms = file_export_lib_apply_xforms->is_pressed();
+
 			Ref<MeshLibrary> ml;
-			if (file_export_lib_merge->is_pressed() && FileAccess::exists(p_file)) {
+			if (merge_with_existing_library && FileAccess::exists(p_file)) {
 				ml = ResourceLoader::load(p_file, "MeshLibrary");
 
 				if (ml.is_null()) {
@@ -2040,7 +2043,7 @@ void EditorNode::_dialog_action(String p_file) {
 				ml = Ref<MeshLibrary>(memnew(MeshLibrary));
 			}
 
-			MeshLibraryEditor::update_library_file(editor_data.get_edited_scene_root(), ml, true, file_export_lib_apply_xforms->is_pressed());
+			MeshLibraryEditor::update_library_file(editor_data.get_edited_scene_root(), ml, merge_with_existing_library, apply_mesh_instance_transforms);
 
 			Error err = ResourceSaver::save(ml, p_file);
 			if (err) {

+ 88 - 102
editor/plugins/mesh_library_editor_plugin.cpp

@@ -78,108 +78,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
 	HashMap<int, MeshInstance3D *> mesh_instances;
 
 	for (int i = 0; i < p_scene->get_child_count(); i++) {
-		Node *child = p_scene->get_child(i);
-
-		if (!Object::cast_to<MeshInstance3D>(child)) {
-			if (child->get_child_count() > 0) {
-				child = child->get_child(0);
-				if (!Object::cast_to<MeshInstance3D>(child)) {
-					continue;
-				}
-
-			} else {
-				continue;
-			}
-		}
-
-		MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(child);
-		Ref<Mesh> mesh = mi->get_mesh();
-		if (mesh.is_null()) {
-			continue;
-		}
-
-		mesh = mesh->duplicate();
-		for (int j = 0; j < mesh->get_surface_count(); ++j) {
-			Ref<Material> mat = mi->get_surface_override_material(j);
-
-			if (mat.is_valid()) {
-				mesh->surface_set_material(j, mat);
-			}
-		}
-
-		int id = p_library->find_item_by_name(mi->get_name());
-		if (id < 0) {
-			id = p_library->get_last_unused_item_id();
-			p_library->create_item(id);
-			p_library->set_item_name(id, mi->get_name());
-		}
-
-		p_library->set_item_mesh(id, mesh);
-
-		if (p_apply_xforms) {
-			p_library->set_item_mesh_transform(id, mi->get_transform());
-		} else {
-			p_library->set_item_mesh_transform(id, Transform3D());
-		}
-
-		mesh_instances[id] = mi;
-
-		Vector<MeshLibrary::ShapeData> collisions;
-
-		for (int j = 0; j < mi->get_child_count(); j++) {
-			Node *child2 = mi->get_child(j);
-			if (!Object::cast_to<StaticBody3D>(child2)) {
-				continue;
-			}
-
-			StaticBody3D *sb = Object::cast_to<StaticBody3D>(child2);
-			List<uint32_t> shapes;
-			sb->get_shape_owners(&shapes);
-
-			for (uint32_t &E : shapes) {
-				if (sb->is_shape_owner_disabled(E)) {
-					continue;
-				}
-
-				Transform3D shape_transform;
-				if (p_apply_xforms) {
-					shape_transform = mi->get_transform();
-				}
-				shape_transform *= sb->get_transform() * sb->shape_owner_get_transform(E);
-
-				for (int k = 0; k < sb->shape_owner_get_shape_count(E); k++) {
-					Ref<Shape3D> collision = sb->shape_owner_get_shape(E, k);
-					if (!collision.is_valid()) {
-						continue;
-					}
-					MeshLibrary::ShapeData shape_data;
-					shape_data.shape = collision;
-					shape_data.local_transform = shape_transform;
-					collisions.push_back(shape_data);
-				}
-			}
-		}
-
-		p_library->set_item_shapes(id, collisions);
-
-		Ref<NavigationMesh> navigation_mesh;
-		Transform3D navigation_mesh_transform;
-		for (int j = 0; j < mi->get_child_count(); j++) {
-			Node *child2 = mi->get_child(j);
-			if (!Object::cast_to<NavigationRegion3D>(child2)) {
-				continue;
-			}
-			NavigationRegion3D *sb = Object::cast_to<NavigationRegion3D>(child2);
-			navigation_mesh = sb->get_navigation_mesh();
-			navigation_mesh_transform = sb->get_transform();
-			if (!navigation_mesh.is_null()) {
-				break;
-			}
-		}
-		if (!navigation_mesh.is_null()) {
-			p_library->set_item_navigation_mesh(id, navigation_mesh);
-			p_library->set_item_navigation_mesh_transform(id, navigation_mesh_transform);
-		}
+		_import_scene_parse_node(p_library, mesh_instances, p_scene->get_child(i), p_merge, p_apply_xforms);
 	}
 
 	//generate previews!
@@ -221,6 +120,93 @@ void MeshLibraryEditor::_import_scene_cbk(const String &p_str) {
 	menu->get_popup()->set_item_disabled(menu->get_popup()->get_item_index(MENU_OPTION_UPDATE_FROM_SCENE), false);
 }
 
+void MeshLibraryEditor::_import_scene_parse_node(Ref<MeshLibrary> p_library, HashMap<int, MeshInstance3D *> &p_mesh_instances, Node *p_node, bool p_merge, bool p_apply_xforms) {
+	MeshInstance3D *mesh_instance_node = Object::cast_to<MeshInstance3D>(p_node);
+
+	if (!mesh_instance_node) {
+		// No MeshInstance so search deeper ...
+		for (int i = 0; i < p_node->get_child_count(); i++) {
+			_import_scene_parse_node(p_library, p_mesh_instances, p_node->get_child(i), p_merge, p_apply_xforms);
+		}
+		return;
+	}
+
+	Ref<Mesh> source_mesh = mesh_instance_node->get_mesh();
+	if (source_mesh.is_null()) {
+		return;
+	}
+
+	int item_id = p_library->find_item_by_name(mesh_instance_node->get_name());
+	if (item_id < 0) {
+		item_id = p_library->get_last_unused_item_id();
+		p_library->create_item(item_id);
+		p_library->set_item_name(item_id, mesh_instance_node->get_name());
+	} else if (!p_merge) {
+		WARN_PRINT(vformat("MeshLibrary export found a MeshInstance3D with a duplicated name '%s' in the exported scene that overrides a previously parsed MeshInstance3D item with the same name.", mesh_instance_node->get_name()));
+	}
+	p_mesh_instances[item_id] = mesh_instance_node;
+
+	Ref<Mesh> item_mesh = source_mesh->duplicate();
+	for (int i = 0; i < item_mesh->get_surface_count(); i++) {
+		Ref<Material> surface_override_material = mesh_instance_node->get_surface_override_material(i);
+		if (surface_override_material.is_valid()) {
+			item_mesh->surface_set_material(i, surface_override_material);
+		}
+	}
+	p_library->set_item_mesh(item_id, item_mesh);
+
+	Transform3D item_mesh_transform;
+	if (p_apply_xforms) {
+		item_mesh_transform = mesh_instance_node->get_transform();
+	}
+	p_library->set_item_mesh_transform(item_id, item_mesh_transform);
+
+	Vector<MeshLibrary::ShapeData> collisions;
+	for (int i = 0; i < mesh_instance_node->get_child_count(); i++) {
+		StaticBody3D *static_body_node = Object::cast_to<StaticBody3D>(mesh_instance_node->get_child(i));
+		if (!static_body_node) {
+			continue;
+		}
+		List<uint32_t> shapes;
+		static_body_node->get_shape_owners(&shapes);
+		for (uint32_t &E : shapes) {
+			if (static_body_node->is_shape_owner_disabled(E)) {
+				continue;
+			}
+			Transform3D shape_transform;
+			if (p_apply_xforms) {
+				shape_transform = mesh_instance_node->get_transform();
+			}
+			shape_transform *= static_body_node->get_transform() * static_body_node->shape_owner_get_transform(E);
+			for (int k = 0; k < static_body_node->shape_owner_get_shape_count(E); k++) {
+				Ref<Shape3D> collision_shape = static_body_node->shape_owner_get_shape(E, k);
+				if (!collision_shape.is_valid()) {
+					continue;
+				}
+				MeshLibrary::ShapeData shape_data;
+				shape_data.shape = collision_shape;
+				shape_data.local_transform = shape_transform;
+				collisions.push_back(shape_data);
+			}
+		}
+	}
+	p_library->set_item_shapes(item_id, collisions);
+
+	for (int i = 0; i < mesh_instance_node->get_child_count(); i++) {
+		NavigationRegion3D *navigation_region_node = Object::cast_to<NavigationRegion3D>(mesh_instance_node->get_child(i));
+		if (!navigation_region_node) {
+			continue;
+		}
+		Ref<NavigationMesh> navigation_mesh = navigation_region_node->get_navigation_mesh();
+		if (!navigation_mesh.is_null()) {
+			Transform3D navigation_mesh_transform = navigation_region_node->get_transform();
+			p_library->set_item_navigation_mesh(item_id, navigation_mesh);
+			p_library->set_item_navigation_mesh_transform(item_id, navigation_mesh_transform);
+			break;
+		}
+	}
+}
+
 Error MeshLibraryEditor::update_library_file(Node *p_base_scene, Ref<MeshLibrary> ml, bool p_merge, bool p_apply_xforms) {
 	_import_scene(p_base_scene, ml, p_merge, p_apply_xforms);
 	return OK;

+ 2 - 0
editor/plugins/mesh_library_editor_plugin.h

@@ -37,6 +37,7 @@
 class EditorFileDialog;
 class ConfirmationDialog;
 class MenuButton;
+class MeshInstance3D;
 
 class MeshLibraryEditor : public Control {
 	GDCLASS(MeshLibraryEditor, Control);
@@ -65,6 +66,7 @@ class MeshLibraryEditor : public Control {
 	void _menu_update_confirm(bool p_apply_xforms);
 
 	static void _import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge, bool p_apply_xforms);
+	static void _import_scene_parse_node(Ref<MeshLibrary> p_library, HashMap<int, MeshInstance3D *> &p_mesh_instances, Node *p_node, bool p_merge, bool p_apply_xforms);
 
 protected:
 	static void _bind_methods();