implement individual mesh transform for meshlibrary items

This commit is contained in:
Vincent 2021-09-01 01:17:33 +02:00
parent 3174e2782c
commit 70108fd850
9 changed files with 99 additions and 26 deletions

View File

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

View File

@ -1856,7 +1856,7 @@ void EditorNode::_dialog_action(String p_file) {
ml = Ref<MeshLibrary>(memnew(MeshLibrary)); 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); Error err = ResourceSaver::save(p_file, ml);
if (err) { if (err) {
@ -6811,6 +6811,10 @@ EditorNode::EditorNode() {
file_export_lib_merge->set_text(TTR("Merge With Existing")); file_export_lib_merge->set_text(TTR("Merge With Existing"));
file_export_lib_merge->set_pressed(true); file_export_lib_merge->set_pressed(true);
file_export_lib->get_vbox()->add_child(file_export_lib_merge); 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); gui_base->add_child(file_export_lib);
file_script = memnew(EditorFileDialog); file_script = memnew(EditorFileDialog);

View File

@ -335,6 +335,7 @@ private:
EditorFileDialog *file_script; EditorFileDialog *file_script;
EditorFileDialog *file_android_build_source; EditorFileDialog *file_android_build_source;
CheckBox *file_export_lib_merge; CheckBox *file_export_lib_merge;
CheckBox *file_export_lib_apply_xforms;
String current_path; String current_path;
MenuButton *update_spinner; 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) { switch (option) {
case MENU_OPTION_REMOVE_ITEM: { case MENU_OPTION_REMOVE_ITEM: {
mesh_library->remove_item(to_erase); mesh_library->remove_item(to_erase);
} break; } 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: { 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) { if (!p_merge) {
p_library->clear(); 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); 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; mesh_instances[id] = mi;
Vector<MeshLibrary::ShapeData> collisions; 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 + "'."); 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); memdelete(scene);
mesh_library->set_meta("_editor_source_scene", p_str); 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); 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) { 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); _import_scene(p_base_scene, ml, p_merge, p_apply_xforms);
return OK; return OK;
} }
@ -219,16 +229,21 @@ void MeshLibraryEditor::_menu_cbk(int p_option) {
String p = editor->get_inspector()->get_selected_path(); String p = editor->get_inspector()->get_selected_path();
if (p.begins_with("/MeshLibrary/item") && p.get_slice_count("/") >= 3) { if (p.begins_with("/MeshLibrary/item") && p.get_slice_count("/") >= 3) {
to_erase = p.get_slice("/", 3).to_int(); to_erase = p.get_slice("/", 3).to_int();
cd->set_text(vformat(TTR("Remove item %d?"), to_erase)); cd_remove->set_text(vformat(TTR("Remove item %d?"), to_erase));
cd->popup_centered(Size2(300, 60)); cd_remove->popup_centered(Size2(300, 60));
} }
} break; } break;
case MENU_OPTION_IMPORT_FROM_SCENE: { case MENU_OPTION_IMPORT_FROM_SCENE: {
apply_xforms = false;
file->popup_file_dialog();
} break;
case MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS: {
apply_xforms = true;
file->popup_file_dialog(); file->popup_file_dialog();
} break; } break;
case MENU_OPTION_UPDATE_FROM_SCENE: { 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_update->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->popup_centered(Size2(500, 60));
} break; } break;
} }
} }
@ -258,16 +273,22 @@ MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) {
menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM); 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_item(TTR("Remove Selected Item"), MENU_OPTION_REMOVE_ITEM);
menu->get_popup()->add_separator(); 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()->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()->set_item_disabled(menu->get_popup()->get_item_index(MENU_OPTION_UPDATE_FROM_SCENE), true);
menu->get_popup()->connect("id_pressed", callable_mp(this, &MeshLibraryEditor::_menu_cbk)); menu->get_popup()->connect("id_pressed", callable_mp(this, &MeshLibraryEditor::_menu_cbk));
menu->hide(); menu->hide();
editor = p_editor; editor = p_editor;
cd = memnew(ConfirmationDialog); cd_remove = memnew(ConfirmationDialog);
add_child(cd); add_child(cd_remove);
cd->get_ok_button()->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_confirm)); cd_remove->get_ok_button()->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_remove_confirm));
cd_update = memnew(ConfirmationDialog);
add_child(cd_update);
cd_update->get_ok_button()->set_text("Apply without Transforms");
cd_update->get_ok_button()->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_update_confirm), varray(false));
cd_update->add_button("Apply with Transforms")->connect("pressed", callable_mp(this, &MeshLibraryEditor::_menu_update_confirm), varray(true));
} }
void MeshLibraryEditorPlugin::edit(Object *p_node) { void MeshLibraryEditorPlugin::edit(Object *p_node) {

View File

@ -41,23 +41,27 @@ class MeshLibraryEditor : public Control {
EditorNode *editor; EditorNode *editor;
MenuButton *menu; MenuButton *menu;
ConfirmationDialog *cd; ConfirmationDialog *cd_remove;
ConfirmationDialog *cd_update;
EditorFileDialog *file; EditorFileDialog *file;
bool apply_xforms;
int to_erase; int to_erase;
enum { enum {
MENU_OPTION_ADD_ITEM, MENU_OPTION_ADD_ITEM,
MENU_OPTION_REMOVE_ITEM, MENU_OPTION_REMOVE_ITEM,
MENU_OPTION_UPDATE_FROM_SCENE, MENU_OPTION_UPDATE_FROM_SCENE,
MENU_OPTION_IMPORT_FROM_SCENE MENU_OPTION_IMPORT_FROM_SCENE,
MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS
}; };
int option; int option;
void _import_scene_cbk(const String &p_str); void _import_scene_cbk(const String &p_str);
void _menu_cbk(int p_option); 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: protected:
static void _bind_methods(); static void _bind_methods();
@ -66,7 +70,7 @@ public:
MenuButton *get_menu_button() const { return menu; } MenuButton *get_menu_button() const { return menu; }
void edit(const Ref<MeshLibrary> &p_mesh_library); 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); MeshLibraryEditor(EditorNode *p_editor);
}; };

View File

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

View File

@ -255,6 +255,12 @@ void GridMapEditor::_update_cursor_transform() {
cursor_transform.basis *= node->get_cell_scale(); cursor_transform.basis *= node->get_cell_scale();
cursor_transform = node->get_global_transform() * cursor_transform; 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()) { if (cursor_instance.is_valid()) {
RenderingServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform); RenderingServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform);
RenderingServer::get_singleton()->instance_set_visible(cursor_instance, cursor_visible); RenderingServer::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); set_item_name(idx, p_value);
} else if (what == "mesh") { } else if (what == "mesh") {
set_item_mesh(idx, p_value); set_item_mesh(idx, p_value);
} else if (what == "mesh_transform") {
set_item_mesh_transform(idx, p_value);
} else if (what == "shape") { } else if (what == "shape") {
Vector<ShapeData> shapes; Vector<ShapeData> shapes;
ShapeData sd; ShapeData sd;
@ -77,6 +79,8 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = get_item_name(idx); r_ret = get_item_name(idx);
} else if (what == "mesh") { } else if (what == "mesh") {
r_ret = get_item_mesh(idx); r_ret = get_item_mesh(idx);
} else if (what == "mesh_transform") {
r_ret = get_item_mesh_transform(idx);
} else if (what == "shapes") { } else if (what == "shapes") {
r_ret = _get_item_shapes(idx); r_ret = _get_item_shapes(idx);
} else if (what == "navmesh") { } else if (what == "navmesh") {
@ -127,6 +131,14 @@ void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) {
notify_property_list_changed(); notify_property_list_changed();
} }
void MeshLibrary::set_item_mesh_transform(int p_item, const Transform3D &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();
notify_property_list_changed();
}
void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) { 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) + "'."); ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'.");
item_map[p_item].shapes = p_shapes; 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; return item_map[p_item].mesh;
} }
Transform3D MeshLibrary::get_item_mesh_transform(int p_item) const {
ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform3D(), "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 { 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) + "'."); 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; return item_map[p_item].shapes;
@ -271,12 +288,14 @@ void MeshLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_item", "id"), &MeshLibrary::create_item); 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_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", "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", "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_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_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("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_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", "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", "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_navmesh_transform", "id"), &MeshLibrary::get_item_navmesh_transform);
ClassDB::bind_method(D_METHOD("get_item_shapes", "id"), &MeshLibrary::_get_item_shapes); ClassDB::bind_method(D_METHOD("get_item_shapes", "id"), &MeshLibrary::_get_item_shapes);

View File

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