implement individual mesh transform for meshlibrary items

(cherry picked from commit 70108fd850)
This commit is contained in:
Vincent 2021-09-01 01:17:33 +02:00 committed by Rémi Verschelde
parent 73345e1514
commit ea13ff860d
No known key found for this signature in database
GPG key ID: C3336907360768E1
9 changed files with 101 additions and 27 deletions

View file

@ -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" />

View file

@ -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);

View file

@ -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;

View file

@ -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) {

View file

@ -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);
};

View file

@ -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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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;