Răsfoiți Sursa

implement individual mesh transform for meshlibrary items

(cherry picked from commit 70108fd8509a09230933872c3042a7c7ef2545b8)
Vincent 4 ani în urmă
părinte
comite
ea13ff860d

+ 15 - 0
doc/classes/MeshLibrary.xml

@@ -45,6 +45,13 @@
 				Returns the item's mesh.
 			</description>
 		</method>
+		<method name="get_item_mesh_transform" qualifiers="const">
+			<return type="Transform" />
+			<argument index="0" name="id" type="int" />
+			<description>
+				Returns the transform applied to the item's mesh.
+			</description>
+		</method>
 		<method name="get_item_name" qualifiers="const">
 			<return type="String" />
 			<argument index="0" name="id" type="int" />
@@ -102,6 +109,14 @@
 				Sets the item's mesh.
 			</description>
 		</method>
+		<method name="set_item_mesh_transform">
+			<return type="void" />
+			<argument index="0" name="id" type="int" />
+			<argument index="1" name="mesh_transform" type="Transform" />
+			<description>
+				Sets the transform to apply to the item's mesh.
+			</description>
+		</method>
 		<method name="set_item_name">
 			<return type="void" />
 			<argument index="0" name="id" type="int" />

+ 5 - 1
editor/editor_node.cpp

@@ -1727,7 +1727,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);
+			MeshLibraryEditor::update_library_file(editor_data.get_edited_scene_root(), ml, true, file_export_lib_apply_xforms->is_pressed());
 
 			Error err = ResourceSaver::save(p_file, ml);
 			if (err) {
@@ -6751,6 +6751,10 @@ EditorNode::EditorNode() {
 	file_export_lib_merge->set_text(TTR("Merge With Existing"));
 	file_export_lib_merge->set_pressed(true);
 	file_export_lib->get_vbox()->add_child(file_export_lib_merge);
+	file_export_lib_apply_xforms = memnew(CheckBox);
+	file_export_lib_apply_xforms->set_text(TTR("Apply MeshInstance Transforms"));
+	file_export_lib_apply_xforms->set_pressed(false);
+	file_export_lib->get_vbox()->add_child(file_export_lib_apply_xforms);
 	gui_base->add_child(file_export_lib);
 
 	file_script = memnew(EditorFileDialog);

+ 1 - 0
editor/editor_node.h

@@ -335,6 +335,7 @@ private:
 	EditorFileDialog *file_script;
 	EditorFileDialog *file_android_build_source;
 	CheckBox *file_export_lib_merge;
+	CheckBox *file_export_lib_apply_xforms;
 	String current_path;
 	MenuButton *update_spinner;
 

+ 42 - 20
editor/plugins/mesh_library_editor_plugin.cpp

@@ -47,23 +47,25 @@ void MeshLibraryEditor::edit(const Ref<MeshLibrary> &p_mesh_library) {
 	}
 }
 
-void MeshLibraryEditor::_menu_confirm() {
+void MeshLibraryEditor::_menu_remove_confirm() {
 	switch (option) {
 		case MENU_OPTION_REMOVE_ITEM: {
 			mesh_library->remove_item(to_erase);
 		} break;
-		case MENU_OPTION_UPDATE_FROM_SCENE: {
-			String existing = mesh_library->get_meta("_editor_source_scene");
-			ERR_FAIL_COND(existing == "");
-			_import_scene_cbk(existing);
-
-		} break;
 		default: {
 		};
 	}
 }
 
-void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge) {
+void MeshLibraryEditor::_menu_update_confirm(bool p_apply_xforms) {
+	cd_update->hide();
+	apply_xforms = p_apply_xforms;
+	String existing = mesh_library->get_meta("_editor_source_scene");
+	ERR_FAIL_COND(existing == "");
+	_import_scene_cbk(existing);
+}
+
+void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge, bool p_apply_xforms) {
 	if (!p_merge) {
 		p_library->clear();
 	}
@@ -108,6 +110,13 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
 		}
 
 		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, Transform());
+		}
+
 		mesh_instances[id] = mi;
 
 		Vector<MeshLibrary::ShapeData> collisions;
@@ -197,15 +206,16 @@ void MeshLibraryEditor::_import_scene_cbk(const String &p_str) {
 
 	ERR_FAIL_COND_MSG(!scene, "Cannot create an instance from PackedScene '" + p_str + "'.");
 
-	_import_scene(scene, mesh_library, option == MENU_OPTION_UPDATE_FROM_SCENE);
+	_import_scene(scene, mesh_library, option == MENU_OPTION_UPDATE_FROM_SCENE, apply_xforms);
 
 	memdelete(scene);
 	mesh_library->set_meta("_editor_source_scene", p_str);
+
 	menu->get_popup()->set_item_disabled(menu->get_popup()->get_item_index(MENU_OPTION_UPDATE_FROM_SCENE), false);
 }
 
-Error MeshLibraryEditor::update_library_file(Node *p_base_scene, Ref<MeshLibrary> ml, bool p_merge) {
-	_import_scene(p_base_scene, ml, p_merge);
+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;
 }
 
@@ -219,23 +229,29 @@ void MeshLibraryEditor::_menu_cbk(int p_option) {
 			String p = editor->get_inspector()->get_selected_path();
 			if (p.begins_with("/MeshLibrary/item") && p.get_slice_count("/") >= 3) {
 				to_erase = p.get_slice("/", 3).to_int();
-				cd->set_text(vformat(TTR("Remove item %d?"), to_erase));
-				cd->popup_centered(Size2(300, 60));
+				cd_remove->set_text(vformat(TTR("Remove item %d?"), to_erase));
+				cd_remove->popup_centered(Size2(300, 60));
 			}
 		} break;
 		case MENU_OPTION_IMPORT_FROM_SCENE: {
+			apply_xforms = false;
+			file->popup_centered_ratio();
+		} break;
+		case MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS: {
+			apply_xforms = true;
 			file->popup_centered_ratio();
 		} break;
 		case MENU_OPTION_UPDATE_FROM_SCENE: {
-			cd->set_text(vformat(TTR("Update from existing scene?:\n%s"), String(mesh_library->get_meta("_editor_source_scene"))));
-			cd->popup_centered(Size2(500, 60));
+			cd_update->set_text(vformat(TTR("Update from existing scene?:\n%s"), String(mesh_library->get_meta("_editor_source_scene"))));
+			cd_update->popup_centered(Size2(500, 60));
 		} break;
 	}
 }
 
 void MeshLibraryEditor::_bind_methods() {
 	ClassDB::bind_method("_menu_cbk", &MeshLibraryEditor::_menu_cbk);
-	ClassDB::bind_method("_menu_confirm", &MeshLibraryEditor::_menu_confirm);
+	ClassDB::bind_method("_menu_remove_confirm", &MeshLibraryEditor::_menu_remove_confirm);
+	ClassDB::bind_method("_menu_update_confirm", &MeshLibraryEditor::_menu_update_confirm);
 	ClassDB::bind_method("_import_scene_cbk", &MeshLibraryEditor::_import_scene_cbk);
 }
 
@@ -261,16 +277,22 @@ MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) {
 	menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM);
 	menu->get_popup()->add_item(TTR("Remove Selected Item"), MENU_OPTION_REMOVE_ITEM);
 	menu->get_popup()->add_separator();
-	menu->get_popup()->add_item(TTR("Import from Scene"), MENU_OPTION_IMPORT_FROM_SCENE);
+	menu->get_popup()->add_item(TTR("Import from Scene (Ignore Transforms)"), MENU_OPTION_IMPORT_FROM_SCENE);
+	menu->get_popup()->add_item(TTR("Import from Scene (Apply Transforms)"), MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS);
 	menu->get_popup()->add_item(TTR("Update from Scene"), MENU_OPTION_UPDATE_FROM_SCENE);
 	menu->get_popup()->set_item_disabled(menu->get_popup()->get_item_index(MENU_OPTION_UPDATE_FROM_SCENE), true);
 	menu->get_popup()->connect("id_pressed", this, "_menu_cbk");
 	menu->hide();
 
 	editor = p_editor;
-	cd = memnew(ConfirmationDialog);
-	add_child(cd);
-	cd->get_ok()->connect("pressed", this, "_menu_confirm");
+	cd_remove = memnew(ConfirmationDialog);
+	add_child(cd_remove);
+	cd_remove->get_ok()->connect("pressed", this, "_menu_remove_confirm");
+	cd_update = memnew(ConfirmationDialog);
+	add_child(cd_update);
+	cd_update->get_ok()->set_text("Apply without Transforms");
+	cd_update->get_ok()->connect("pressed", this, "_menu_update_confirm", varray(false));
+	cd_update->add_button("Apply with Transforms")->connect("pressed", this, "_menu_update_confirm", varray(true));
 }
 
 void MeshLibraryEditorPlugin::edit(Object *p_node) {

+ 9 - 5
editor/plugins/mesh_library_editor_plugin.h

@@ -41,8 +41,10 @@ class MeshLibraryEditor : public Control {
 
 	EditorNode *editor;
 	MenuButton *menu;
-	ConfirmationDialog *cd;
+	ConfirmationDialog *cd_remove;
+	ConfirmationDialog *cd_update;
 	EditorFileDialog *file;
+	bool apply_xforms;
 	int to_erase;
 
 	enum {
@@ -50,15 +52,17 @@ class MeshLibraryEditor : public Control {
 		MENU_OPTION_ADD_ITEM,
 		MENU_OPTION_REMOVE_ITEM,
 		MENU_OPTION_UPDATE_FROM_SCENE,
-		MENU_OPTION_IMPORT_FROM_SCENE
+		MENU_OPTION_IMPORT_FROM_SCENE,
+		MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS
 	};
 
 	int option;
 	void _import_scene_cbk(const String &p_str);
 	void _menu_cbk(int p_option);
-	void _menu_confirm();
+	void _menu_remove_confirm();
+	void _menu_update_confirm(bool p_apply_xforms);
 
-	static void _import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge);
+	static void _import_scene(Node *p_scene, Ref<MeshLibrary> p_library, bool p_merge, bool p_apply_xforms);
 
 protected:
 	static void _bind_methods();
@@ -67,7 +71,7 @@ public:
 	MenuButton *get_menu_button() const { return menu; }
 
 	void edit(const Ref<MeshLibrary> &p_mesh_library);
-	static Error update_library_file(Node *p_base_scene, Ref<MeshLibrary> ml, bool p_merge = true);
+	static Error update_library_file(Node *p_base_scene, Ref<MeshLibrary> ml, bool p_merge = true, bool p_apply_xforms = false);
 
 	MeshLibraryEditor(EditorNode *p_editor);
 };

+ 1 - 1
modules/gridmap/grid_map.cpp

@@ -460,7 +460,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
 				}
 
 				Pair<Transform, IndexKey> p;
-				p.first = xform;
+				p.first = xform * mesh_library->get_item_mesh_transform(c.item);
 				p.second = E->get();
 				multimesh_items[c.item].push_back(p);
 			}

+ 6 - 0
modules/gridmap/grid_map_editor_plugin.cpp

@@ -261,6 +261,12 @@ void GridMapEditor::_update_cursor_transform() {
 	cursor_transform.basis *= node->get_cell_scale();
 	cursor_transform = node->get_global_transform() * cursor_transform;
 
+	if (selected_palette >= 0) {
+		if (node && !node->get_mesh_library().is_null()) {
+			cursor_transform *= node->get_mesh_library()->get_item_mesh_transform(selected_palette);
+		}
+	}
+
 	if (cursor_instance.is_valid()) {
 		VisualServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform);
 		VisualServer::get_singleton()->instance_set_visible(cursor_instance, cursor_visible);

+ 19 - 0
scene/resources/mesh_library.cpp

@@ -43,6 +43,8 @@ bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) {
 			set_item_name(idx, p_value);
 		} else if (what == "mesh") {
 			set_item_mesh(idx, p_value);
+		} else if (what == "mesh_transform") {
+			set_item_mesh_transform(idx, p_value);
 		} else if (what == "shape") {
 			Vector<ShapeData> shapes;
 			ShapeData sd;
@@ -77,6 +79,8 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const {
 		r_ret = get_item_name(idx);
 	} else if (what == "mesh") {
 		r_ret = get_item_mesh(idx);
+	} else if (what == "mesh_transform") {
+		r_ret = get_item_mesh_transform(idx);
 	} else if (what == "shapes") {
 		r_ret = _get_item_shapes(idx);
 	} else if (what == "navmesh") {
@@ -127,6 +131,14 @@ void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) {
 	_change_notify();
 }
 
+void MeshLibrary::set_item_mesh_transform(int p_item, const Transform &p_transform) {
+	ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
+	item_map[p_item].mesh_transform = p_transform;
+	notify_change_to_owners();
+	emit_changed();
+	_change_notify();
+}
+
 void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) {
 	ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
 	item_map[p_item].shapes = p_shapes;
@@ -170,6 +182,11 @@ Ref<Mesh> MeshLibrary::get_item_mesh(int p_item) const {
 	return item_map[p_item].mesh;
 }
 
+Transform MeshLibrary::get_item_mesh_transform(int p_item) const {
+	ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
+	return item_map[p_item].mesh_transform;
+}
+
 Vector<MeshLibrary::ShapeData> MeshLibrary::get_item_shapes(int p_item) const {
 	ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Vector<ShapeData>(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
 	return item_map[p_item].shapes;
@@ -267,12 +284,14 @@ void MeshLibrary::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("create_item", "id"), &MeshLibrary::create_item);
 	ClassDB::bind_method(D_METHOD("set_item_name", "id", "name"), &MeshLibrary::set_item_name);
 	ClassDB::bind_method(D_METHOD("set_item_mesh", "id", "mesh"), &MeshLibrary::set_item_mesh);
+	ClassDB::bind_method(D_METHOD("set_item_mesh_transform", "id", "mesh_transform"), &MeshLibrary::set_item_mesh_transform);
 	ClassDB::bind_method(D_METHOD("set_item_navmesh", "id", "navmesh"), &MeshLibrary::set_item_navmesh);
 	ClassDB::bind_method(D_METHOD("set_item_navmesh_transform", "id", "navmesh"), &MeshLibrary::set_item_navmesh_transform);
 	ClassDB::bind_method(D_METHOD("set_item_shapes", "id", "shapes"), &MeshLibrary::_set_item_shapes);
 	ClassDB::bind_method(D_METHOD("set_item_preview", "id", "texture"), &MeshLibrary::set_item_preview);
 	ClassDB::bind_method(D_METHOD("get_item_name", "id"), &MeshLibrary::get_item_name);
 	ClassDB::bind_method(D_METHOD("get_item_mesh", "id"), &MeshLibrary::get_item_mesh);
+	ClassDB::bind_method(D_METHOD("get_item_mesh_transform", "id"), &MeshLibrary::get_item_mesh_transform);
 	ClassDB::bind_method(D_METHOD("get_item_navmesh", "id"), &MeshLibrary::get_item_navmesh);
 	ClassDB::bind_method(D_METHOD("get_item_navmesh_transform", "id"), &MeshLibrary::get_item_navmesh_transform);
 	ClassDB::bind_method(D_METHOD("get_item_shapes", "id"), &MeshLibrary::_get_item_shapes);

+ 3 - 0
scene/resources/mesh_library.h

@@ -52,6 +52,7 @@ public:
 		Vector<ShapeData> shapes;
 		Ref<Texture> preview;
 		Transform navmesh_transform;
+		Transform mesh_transform;
 		Ref<NavigationMesh> navmesh;
 	};
 
@@ -71,12 +72,14 @@ public:
 	void create_item(int p_item);
 	void set_item_name(int p_item, const String &p_name);
 	void set_item_mesh(int p_item, const Ref<Mesh> &p_mesh);
+	void set_item_mesh_transform(int p_item, const Transform &p_transform);
 	void set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh);
 	void set_item_navmesh_transform(int p_item, const Transform &p_transform);
 	void set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes);
 	void set_item_preview(int p_item, const Ref<Texture> &p_preview);
 	String get_item_name(int p_item) const;
 	Ref<Mesh> get_item_mesh(int p_item) const;
+	Transform get_item_mesh_transform(int p_item) const;
 	Ref<NavigationMesh> get_item_navmesh(int p_item) const;
 	Transform get_item_navmesh_transform(int p_item) const;
 	Vector<ShapeData> get_item_shapes(int p_item) const;