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