1 #include "mesh_instance_editor_plugin.h"
2
3 #include "scene/3d/body_shape.h"
4 #include "scene/3d/navigation_mesh.h"
5 #include "scene/3d/physics_body.h"
6 #include "scene/gui/box_container.h"
7 #include "spatial_editor_plugin.h"
8
_node_removed(Node * p_node)9 void MeshInstanceEditor::_node_removed(Node *p_node) {
10
11 if (p_node == node) {
12 node = NULL;
13 options->hide();
14 }
15 }
16
edit(MeshInstance * p_mesh)17 void MeshInstanceEditor::edit(MeshInstance *p_mesh) {
18
19 node = p_mesh;
20 }
21
_menu_option(int p_option)22 void MeshInstanceEditor::_menu_option(int p_option) {
23
24 Ref<Mesh> mesh = node->get_mesh();
25 if (mesh.is_null()) {
26 err_dialog->set_text(TTR("Mesh is empty!"));
27 err_dialog->popup_centered_minsize();
28 return;
29 }
30
31 switch (p_option) {
32 case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY:
33 case MENU_OPTION_CREATE_STATIC_CONVEX_BODY: {
34
35 bool trimesh_shape = (p_option == MENU_OPTION_CREATE_STATIC_TRIMESH_BODY);
36
37 EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
38 UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
39
40 List<Node *> selection = editor_selection->get_selected_node_list();
41
42 if (selection.empty()) {
43 Ref<Shape> shape = trimesh_shape ? mesh->create_trimesh_shape() : mesh->create_convex_shape();
44 if (shape.is_null())
45 return;
46
47 CollisionShape *cshape = memnew(CollisionShape);
48 cshape->set_shape(shape);
49 StaticBody *body = memnew(StaticBody);
50 body->add_child(cshape);
51
52 Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner();
53
54 if (trimesh_shape)
55 ur->create_action(TTR("Create Static Trimesh Body"));
56 else
57 ur->create_action(TTR("Create Static Convex Body"));
58
59 ur->add_do_method(node, "add_child", body);
60 ur->add_do_method(body, "set_owner", owner);
61 ur->add_do_method(cshape, "set_owner", owner);
62 ur->add_do_reference(body);
63 ur->add_undo_method(node, "remove_child", body);
64 ur->commit_action();
65 return;
66 }
67
68 if (trimesh_shape)
69 ur->create_action(TTR("Create Static Trimesh Body"));
70 else
71 ur->create_action(TTR("Create Static Convex Body"));
72
73 for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
74
75 MeshInstance *instance = E->get()->cast_to<MeshInstance>();
76 if (!instance)
77 continue;
78
79 Ref<Mesh> m = instance->get_mesh();
80 if (m.is_null())
81 continue;
82
83 Ref<Shape> shape = trimesh_shape ? m->create_trimesh_shape() : m->create_convex_shape();
84 if (shape.is_null())
85 continue;
86
87 CollisionShape *cshape = memnew(CollisionShape);
88 cshape->set_shape(shape);
89 StaticBody *body = memnew(StaticBody);
90 body->add_child(cshape);
91
92 Node *owner = instance == get_tree()->get_edited_scene_root() ? instance : instance->get_owner();
93
94 ur->add_do_method(instance, "add_child", body);
95 ur->add_do_method(body, "set_owner", owner);
96 ur->add_do_method(cshape, "set_owner", owner);
97 ur->add_do_reference(body);
98 ur->add_undo_method(instance, "remove_child", body);
99 }
100
101 ur->commit_action();
102
103 } break;
104
105 case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE:
106 case MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE: {
107
108 if (node == get_tree()->get_edited_scene_root()) {
109 err_dialog->set_text(TTR("This doesn't work on scene root!"));
110 err_dialog->popup_centered_minsize();
111 return;
112 }
113
114 bool trimesh_shape = (p_option == MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE);
115
116 Ref<Shape> shape = trimesh_shape ? mesh->create_trimesh_shape() : mesh->create_convex_shape();
117 if (shape.is_null())
118 return;
119
120 CollisionShape *cshape = memnew(CollisionShape);
121 cshape->set_shape(shape);
122
123 Node *owner = node->get_owner();
124
125 UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
126
127 if (trimesh_shape)
128 ur->create_action(TTR("Create Trimesh Shape"));
129 else
130 ur->create_action(TTR("Create Convex Shape"));
131
132 ur->add_do_method(node->get_parent(), "add_child", cshape);
133 ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
134 ur->add_do_method(cshape, "set_owner", owner);
135 ur->add_do_reference(cshape);
136 ur->add_undo_method(node->get_parent(), "remove_child", cshape);
137 ur->commit_action();
138
139 } break;
140
141 case MENU_OPTION_CREATE_NAVMESH: {
142
143 Ref<NavigationMesh> nmesh = memnew(NavigationMesh);
144
145 if (nmesh.is_null())
146 return;
147
148 nmesh->create_from_mesh(mesh);
149 NavigationMeshInstance *nmi = memnew(NavigationMeshInstance);
150 nmi->set_navigation_mesh(nmesh);
151
152 Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner();
153
154 UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
155 ur->create_action(TTR("Create Navigation Mesh"));
156
157 ur->add_do_method(node, "add_child", nmi);
158 ur->add_do_method(nmi, "set_owner", owner);
159
160 ur->add_do_reference(nmi);
161 ur->add_undo_method(node, "remove_child", nmi);
162 ur->commit_action();
163 } break;
164
165 case MENU_OPTION_CREATE_OUTLINE_MESH: {
166
167 outline_dialog->popup_centered(Vector2(200, 90));
168 } break;
169 }
170 }
171
_create_outline_mesh()172 void MeshInstanceEditor::_create_outline_mesh() {
173
174 Ref<Mesh> mesh = node->get_mesh();
175 if (mesh.is_null()) {
176 err_dialog->set_text(TTR("MeshInstance lacks a Mesh!"));
177 err_dialog->popup_centered_minsize();
178 return;
179 }
180
181 if (mesh->get_surface_count() == 0) {
182 err_dialog->set_text(TTR("Mesh has not surface to create outlines from!"));
183 err_dialog->popup_centered_minsize();
184 return;
185 }
186
187 Ref<Mesh> mesho = mesh->create_outline(outline_size->get_val());
188
189 if (mesho.is_null()) {
190 err_dialog->set_text(TTR("Could not create outline!"));
191 err_dialog->popup_centered_minsize();
192 return;
193 }
194
195 MeshInstance *mi = memnew(MeshInstance);
196 mi->set_mesh(mesho);
197 Node *owner = node->get_owner();
198 if (get_tree()->get_edited_scene_root() == node) {
199 owner = node;
200 }
201
202 UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
203
204 ur->create_action(TTR("Create Outline"));
205
206 ur->add_do_method(node, "add_child", mi);
207 ur->add_do_method(mi, "set_owner", owner);
208
209 ur->add_do_reference(mi);
210 ur->add_undo_method(node, "remove_child", mi);
211 ur->commit_action();
212 }
213
_bind_methods()214 void MeshInstanceEditor::_bind_methods() {
215
216 ObjectTypeDB::bind_method("_menu_option", &MeshInstanceEditor::_menu_option);
217 ObjectTypeDB::bind_method("_create_outline_mesh", &MeshInstanceEditor::_create_outline_mesh);
218 }
219
MeshInstanceEditor()220 MeshInstanceEditor::MeshInstanceEditor() {
221
222 options = memnew(MenuButton);
223 SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
224
225 options->set_text(TTR("Mesh"));
226 options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshInstance", "EditorIcons"));
227
228 options->get_popup()->add_item(TTR("Create Trimesh Static Body"), MENU_OPTION_CREATE_STATIC_TRIMESH_BODY);
229 options->get_popup()->add_item(TTR("Create Convex Static Body"), MENU_OPTION_CREATE_STATIC_CONVEX_BODY);
230 options->get_popup()->add_separator();
231 options->get_popup()->add_item(TTR("Create Trimesh Collision Sibling"), MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE);
232 options->get_popup()->add_item(TTR("Create Convex Collision Sibling"), MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE);
233 options->get_popup()->add_separator();
234 options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH);
235 options->get_popup()->add_separator();
236 options->get_popup()->add_item(TTR("Create Outline Mesh.."), MENU_OPTION_CREATE_OUTLINE_MESH);
237
238 options->get_popup()->connect("item_pressed", this, "_menu_option");
239
240 outline_dialog = memnew(ConfirmationDialog);
241 outline_dialog->set_title(TTR("Create Outline Mesh"));
242 outline_dialog->get_ok()->set_text(TTR("Create"));
243
244 VBoxContainer *outline_dialog_vbc = memnew(VBoxContainer);
245 outline_dialog->add_child(outline_dialog_vbc);
246 outline_dialog->set_child_rect(outline_dialog_vbc);
247
248 outline_size = memnew(SpinBox);
249 outline_size->set_min(0.001);
250 outline_size->set_max(1024);
251 outline_size->set_step(0.001);
252 outline_size->set_val(0.05);
253 outline_dialog_vbc->add_margin_child(TTR("Outline Size:"), outline_size);
254
255 add_child(outline_dialog);
256 outline_dialog->connect("confirmed", this, "_create_outline_mesh");
257
258 err_dialog = memnew(AcceptDialog);
259 add_child(err_dialog);
260 }
261
edit(Object * p_object)262 void MeshInstanceEditorPlugin::edit(Object *p_object) {
263
264 mesh_editor->edit(p_object->cast_to<MeshInstance>());
265 }
266
handles(Object * p_object) const267 bool MeshInstanceEditorPlugin::handles(Object *p_object) const {
268
269 return p_object->is_type("MeshInstance");
270 }
271
make_visible(bool p_visible)272 void MeshInstanceEditorPlugin::make_visible(bool p_visible) {
273
274 if (p_visible) {
275 mesh_editor->options->show();
276 } else {
277
278 mesh_editor->options->hide();
279 mesh_editor->edit(NULL);
280 }
281 }
282
MeshInstanceEditorPlugin(EditorNode * p_node)283 MeshInstanceEditorPlugin::MeshInstanceEditorPlugin(EditorNode *p_node) {
284
285 editor = p_node;
286 mesh_editor = memnew(MeshInstanceEditor);
287 editor->get_viewport()->add_child(mesh_editor);
288
289 mesh_editor->options->hide();
290 }
291
~MeshInstanceEditorPlugin()292 MeshInstanceEditorPlugin::~MeshInstanceEditorPlugin() {
293 }
294