1 /*************************************************************************/
2 /*  spatial_editor_plugin.cpp                                            */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #include "spatial_editor_plugin.h"
32 
33 #include "core/math/camera_matrix.h"
34 #include "core/os/input.h"
35 #include "core/os/keyboard.h"
36 #include "core/print_string.h"
37 #include "core/project_settings.h"
38 #include "core/sort_array.h"
39 #include "editor/editor_node.h"
40 #include "editor/editor_scale.h"
41 #include "editor/editor_settings.h"
42 #include "editor/plugins/animation_player_editor_plugin.h"
43 #include "editor/plugins/script_editor_plugin.h"
44 #include "editor/script_editor_debugger.h"
45 #include "editor/spatial_editor_gizmos.h"
46 #include "scene/3d/camera.h"
47 #include "scene/3d/collision_shape.h"
48 #include "scene/3d/mesh_instance.h"
49 #include "scene/3d/physics_body.h"
50 #include "scene/3d/visual_instance.h"
51 #include "scene/gui/viewport_container.h"
52 #include "scene/resources/packed_scene.h"
53 #include "scene/resources/surface_tool.h"
54 
55 #define DISTANCE_DEFAULT 4
56 
57 #define GIZMO_ARROW_SIZE 0.35
58 #define GIZMO_RING_HALF_WIDTH 0.1
59 #define GIZMO_SCALE_DEFAULT 0.15
60 #define GIZMO_PLANE_SIZE 0.2
61 #define GIZMO_PLANE_DST 0.3
62 #define GIZMO_CIRCLE_SIZE 1.1
63 #define GIZMO_SCALE_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
64 #define GIZMO_ARROW_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
65 
66 #define ZOOM_MIN_DISTANCE 0.001
67 #define ZOOM_MULTIPLIER 1.08
68 #define ZOOM_INDICATOR_DELAY_S 1.5
69 
70 #define FREELOOK_MIN_SPEED 0.01
71 #define FREELOOK_SPEED_MULTIPLIER 1.08
72 
73 #define MIN_Z 0.01
74 #define MAX_Z 1000000.0
75 
76 #define MIN_FOV 0.01
77 #define MAX_FOV 179
78 
_notification(int p_what)79 void ViewportRotationControl::_notification(int p_what) {
80 
81 	if (p_what == NOTIFICATION_ENTER_TREE) {
82 		axis_menu_options.clear();
83 		axis_menu_options.push_back(SpatialEditorViewport::VIEW_RIGHT);
84 		axis_menu_options.push_back(SpatialEditorViewport::VIEW_TOP);
85 		axis_menu_options.push_back(SpatialEditorViewport::VIEW_FRONT);
86 		axis_menu_options.push_back(SpatialEditorViewport::VIEW_LEFT);
87 		axis_menu_options.push_back(SpatialEditorViewport::VIEW_BOTTOM);
88 		axis_menu_options.push_back(SpatialEditorViewport::VIEW_REAR);
89 
90 		axis_colors.clear();
91 		axis_colors.push_back(get_color("axis_x_color", "Editor"));
92 		axis_colors.push_back(get_color("axis_y_color", "Editor"));
93 		axis_colors.push_back(get_color("axis_z_color", "Editor"));
94 		update();
95 
96 		if (!is_connected("mouse_exited", this, "_on_mouse_exited")) {
97 			connect("mouse_exited", this, "_on_mouse_exited");
98 		}
99 	}
100 
101 	if (p_what == NOTIFICATION_DRAW && viewport != nullptr) {
102 		_draw();
103 	}
104 }
105 
_draw()106 void ViewportRotationControl::_draw() {
107 	Vector2i center = get_size() / 2.0;
108 	float radius = get_size().x / 2.0;
109 
110 	if (focused_axis > -2 || orbiting) {
111 		draw_circle(center, radius, Color(0.5, 0.5, 0.5, 0.25));
112 	}
113 
114 	Vector<Axis2D> axis_to_draw;
115 	_get_sorted_axis(axis_to_draw);
116 	for (int i = 0; i < axis_to_draw.size(); ++i) {
117 		_draw_axis(axis_to_draw[i]);
118 	}
119 }
120 
_draw_axis(const Axis2D & p_axis)121 void ViewportRotationControl::_draw_axis(const Axis2D &p_axis) {
122 	bool focused = focused_axis == p_axis.axis;
123 	bool positive = p_axis.axis < 3;
124 	bool front = (Math::abs(p_axis.z_axis) <= 0.001 && positive) || p_axis.z_axis > 0.001;
125 	int direction = p_axis.axis % 3;
126 
127 	Color axis_color = axis_colors[direction];
128 
129 	if (!front) {
130 		axis_color = axis_color.darkened(0.4);
131 	}
132 	Color c = focused ? Color(0.9, 0.9, 0.9) : axis_color;
133 
134 	if (positive) {
135 		Vector2i center = get_size() / 2.0;
136 		draw_line(center, p_axis.screen_point, c, 1.5 * EDSCALE, true);
137 	}
138 
139 	if (front) {
140 		String axis_name = direction == 0 ? "X" : (direction == 1 ? "Y" : "Z");
141 		draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS, c);
142 		draw_char(get_font("rotation_control", "EditorFonts"), p_axis.screen_point + Vector2(-4.0, 5.0) * EDSCALE, axis_name, "", Color(0.3, 0.3, 0.3));
143 	} else {
144 		draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS * (0.55 + (0.2 * (1.0 + p_axis.z_axis))), c);
145 	}
146 }
147 
_get_sorted_axis(Vector<Axis2D> & r_axis)148 void ViewportRotationControl::_get_sorted_axis(Vector<Axis2D> &r_axis) {
149 	Vector2i center = get_size() / 2.0;
150 	float radius = get_size().x / 2.0;
151 
152 	float axis_radius = radius - AXIS_CIRCLE_RADIUS - 2.0 * EDSCALE;
153 	Basis camera_basis = viewport->to_camera_transform(viewport->cursor).get_basis().inverse();
154 
155 	for (int i = 0; i < 3; ++i) {
156 		Vector3 axis_3d = camera_basis.get_axis(i);
157 		Vector2i axis_vector = Vector2(axis_3d.x, -axis_3d.y) * axis_radius;
158 
159 		if (Math::abs(axis_3d.z) < 1.0) {
160 			Axis2D pos_axis;
161 			pos_axis.axis = i;
162 			pos_axis.screen_point = center + axis_vector;
163 			pos_axis.z_axis = axis_3d.z;
164 			r_axis.push_back(pos_axis);
165 
166 			Axis2D neg_axis;
167 			neg_axis.axis = i + 3;
168 			neg_axis.screen_point = center - axis_vector;
169 			neg_axis.z_axis = -axis_3d.z;
170 			r_axis.push_back(neg_axis);
171 		} else {
172 			// Special case when the camera is aligned with one axis
173 			Axis2D axis;
174 			axis.axis = i + (axis_3d.z < 0 ? 0 : 3);
175 			axis.screen_point = center;
176 			axis.z_axis = 1.0;
177 			r_axis.push_back(axis);
178 		}
179 	}
180 
181 	r_axis.sort_custom<Axis2DCompare>();
182 }
183 
_gui_input(Ref<InputEvent> p_event)184 void ViewportRotationControl::_gui_input(Ref<InputEvent> p_event) {
185 	const Ref<InputEventMouseButton> mb = p_event;
186 	if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
187 		Vector2 pos = mb->get_position();
188 		if (mb->is_pressed()) {
189 			if (pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) {
190 				orbiting = true;
191 			}
192 		} else {
193 			if (focused_axis > -1) {
194 				viewport->_menu_option(axis_menu_options[focused_axis]);
195 				_update_focus();
196 			}
197 			orbiting = false;
198 			if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) {
199 				Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
200 				Input::get_singleton()->warp_mouse_position(orbiting_mouse_start);
201 			}
202 		}
203 	}
204 
205 	const Ref<InputEventMouseMotion> mm = p_event;
206 	if (mm.is_valid()) {
207 		if (orbiting) {
208 			if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_VISIBLE) {
209 				Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
210 				orbiting_mouse_start = mm->get_global_position();
211 			}
212 			viewport->_nav_orbit(mm, viewport->_get_warped_mouse_motion(mm));
213 			focused_axis = -1;
214 		} else {
215 			_update_focus();
216 		}
217 	}
218 }
219 
_update_focus()220 void ViewportRotationControl::_update_focus() {
221 	int original_focus = focused_axis;
222 	focused_axis = -2;
223 	Vector2 mouse_pos = get_local_mouse_position();
224 
225 	if (mouse_pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) {
226 		focused_axis = -1;
227 	}
228 
229 	Vector<Axis2D> axes;
230 	_get_sorted_axis(axes);
231 
232 	for (int i = 0; i < axes.size(); i++) {
233 		const Axis2D &axis = axes[i];
234 		if (mouse_pos.distance_to(axis.screen_point) < AXIS_CIRCLE_RADIUS) {
235 			focused_axis = axis.axis;
236 		}
237 	}
238 
239 	if (focused_axis != original_focus) {
240 		update();
241 	}
242 }
243 
_on_mouse_exited()244 void ViewportRotationControl::_on_mouse_exited() {
245 	focused_axis = -2;
246 	update();
247 }
248 
set_viewport(SpatialEditorViewport * p_viewport)249 void ViewportRotationControl::set_viewport(SpatialEditorViewport *p_viewport) {
250 	viewport = p_viewport;
251 }
252 
_bind_methods()253 void ViewportRotationControl::_bind_methods() {
254 	ClassDB::bind_method(D_METHOD("_gui_input"), &ViewportRotationControl::_gui_input);
255 	ClassDB::bind_method(D_METHOD("_on_mouse_exited"), &ViewportRotationControl::_on_mouse_exited);
256 }
257 
_update_camera(float p_interp_delta)258 void SpatialEditorViewport::_update_camera(float p_interp_delta) {
259 
260 	bool is_orthogonal = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL;
261 
262 	Cursor old_camera_cursor = camera_cursor;
263 	camera_cursor = cursor;
264 
265 	if (p_interp_delta > 0) {
266 
267 		//-------
268 		// Perform smoothing
269 
270 		if (is_freelook_active()) {
271 
272 			// Higher inertia should increase "lag" (lerp with factor between 0 and 1)
273 			// Inertia of zero should produce instant movement (lerp with factor of 1) in this case it returns a really high value and gets clamped to 1.
274 			real_t inertia = EDITOR_GET("editors/3d/freelook/freelook_inertia");
275 			inertia = MAX(0.001, inertia);
276 			real_t factor = (1.0 / inertia) * p_interp_delta;
277 
278 			// We interpolate a different point here, because in freelook mode the focus point (cursor.pos) orbits around eye_pos
279 			camera_cursor.eye_pos = old_camera_cursor.eye_pos.linear_interpolate(cursor.eye_pos, CLAMP(factor, 0, 1));
280 
281 			float orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
282 			orbit_inertia = MAX(0.0001, orbit_inertia);
283 			camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
284 			camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
285 
286 			if (Math::abs(camera_cursor.x_rot - cursor.x_rot) < 0.1) {
287 				camera_cursor.x_rot = cursor.x_rot;
288 			}
289 			if (Math::abs(camera_cursor.y_rot - cursor.y_rot) < 0.1) {
290 				camera_cursor.y_rot = cursor.y_rot;
291 			}
292 
293 			Vector3 forward = to_camera_transform(camera_cursor).basis.xform(Vector3(0, 0, -1));
294 			camera_cursor.pos = camera_cursor.eye_pos + forward * camera_cursor.distance;
295 
296 		} else {
297 
298 			//when not being manipulated, move softly
299 			float free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
300 			float free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia");
301 			//when being manipulated, move more quickly
302 			float manip_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_orbit_inertia");
303 			float manip_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_translation_inertia");
304 
305 			float zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia");
306 
307 			//determine if being manipulated
308 			bool manipulated = Input::get_singleton()->get_mouse_button_mask() & (2 | 4);
309 			manipulated |= Input::get_singleton()->is_key_pressed(KEY_SHIFT);
310 			manipulated |= Input::get_singleton()->is_key_pressed(KEY_ALT);
311 			manipulated |= Input::get_singleton()->is_key_pressed(KEY_CONTROL);
312 
313 			float orbit_inertia = MAX(0.00001, manipulated ? manip_orbit_inertia : free_orbit_inertia);
314 			float translation_inertia = MAX(0.0001, manipulated ? manip_translation_inertia : free_translation_inertia);
315 			zoom_inertia = MAX(0.0001, zoom_inertia);
316 
317 			camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
318 			camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
319 
320 			if (Math::abs(camera_cursor.x_rot - cursor.x_rot) < 0.1) {
321 				camera_cursor.x_rot = cursor.x_rot;
322 			}
323 			if (Math::abs(camera_cursor.y_rot - cursor.y_rot) < 0.1) {
324 				camera_cursor.y_rot = cursor.y_rot;
325 			}
326 
327 			camera_cursor.pos = old_camera_cursor.pos.linear_interpolate(cursor.pos, MIN(1.f, p_interp_delta * (1 / translation_inertia)));
328 			camera_cursor.distance = Math::lerp(old_camera_cursor.distance, cursor.distance, MIN(1.f, p_interp_delta * (1 / zoom_inertia)));
329 		}
330 	}
331 
332 	//-------
333 	// Apply camera transform
334 
335 	float tolerance = 0.001;
336 	bool equal = true;
337 	if (Math::abs(old_camera_cursor.x_rot - camera_cursor.x_rot) > tolerance || Math::abs(old_camera_cursor.y_rot - camera_cursor.y_rot) > tolerance) {
338 		equal = false;
339 	}
340 
341 	if (equal && old_camera_cursor.pos.distance_squared_to(camera_cursor.pos) > tolerance * tolerance) {
342 		equal = false;
343 	}
344 
345 	if (equal && Math::abs(old_camera_cursor.distance - camera_cursor.distance) > tolerance) {
346 		equal = false;
347 	}
348 
349 	if (!equal || p_interp_delta == 0 || is_freelook_active() || is_orthogonal != orthogonal) {
350 
351 		camera->set_global_transform(to_camera_transform(camera_cursor));
352 
353 		if (orthogonal) {
354 			float half_fov = Math::deg2rad(get_fov()) / 2.0;
355 			float height = 2.0 * cursor.distance * Math::tan(half_fov);
356 			camera->set_orthogonal(height, get_znear(), get_zfar());
357 		} else {
358 			camera->set_perspective(get_fov(), get_znear(), get_zfar());
359 		}
360 
361 		update_transform_gizmo_view();
362 		rotation_control->update();
363 	}
364 }
365 
to_camera_transform(const Cursor & p_cursor) const366 Transform SpatialEditorViewport::to_camera_transform(const Cursor &p_cursor) const {
367 	Transform camera_transform;
368 	camera_transform.translate(p_cursor.pos);
369 	camera_transform.basis.rotate(Vector3(1, 0, 0), -p_cursor.x_rot);
370 	camera_transform.basis.rotate(Vector3(0, 1, 0), -p_cursor.y_rot);
371 
372 	if (orthogonal)
373 		camera_transform.translate(0, 0, (get_zfar() - get_znear()) / 2.0);
374 	else
375 		camera_transform.translate(0, 0, p_cursor.distance);
376 
377 	return camera_transform;
378 }
379 
get_selected_count() const380 int SpatialEditorViewport::get_selected_count() const {
381 
382 	Map<Node *, Object *> &selection = editor_selection->get_selection();
383 
384 	int count = 0;
385 
386 	for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
387 
388 		Spatial *sp = Object::cast_to<Spatial>(E->key());
389 		if (!sp)
390 			continue;
391 
392 		SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
393 		if (!se)
394 			continue;
395 
396 		count++;
397 	}
398 
399 	return count;
400 }
401 
get_znear() const402 float SpatialEditorViewport::get_znear() const {
403 
404 	return CLAMP(spatial_editor->get_znear(), MIN_Z, MAX_Z);
405 }
get_zfar() const406 float SpatialEditorViewport::get_zfar() const {
407 
408 	return CLAMP(spatial_editor->get_zfar(), MIN_Z, MAX_Z);
409 }
get_fov() const410 float SpatialEditorViewport::get_fov() const {
411 
412 	return CLAMP(spatial_editor->get_fov(), MIN_FOV, MAX_FOV);
413 }
414 
_get_camera_transform() const415 Transform SpatialEditorViewport::_get_camera_transform() const {
416 
417 	return camera->get_global_transform();
418 }
419 
_get_camera_position() const420 Vector3 SpatialEditorViewport::_get_camera_position() const {
421 
422 	return _get_camera_transform().origin;
423 }
424 
_point_to_screen(const Vector3 & p_point)425 Point2 SpatialEditorViewport::_point_to_screen(const Vector3 &p_point) {
426 
427 	return camera->unproject_position(p_point) * viewport_container->get_stretch_shrink();
428 }
429 
_get_ray_pos(const Vector2 & p_pos) const430 Vector3 SpatialEditorViewport::_get_ray_pos(const Vector2 &p_pos) const {
431 
432 	return camera->project_ray_origin(p_pos / viewport_container->get_stretch_shrink());
433 }
434 
_get_camera_normal() const435 Vector3 SpatialEditorViewport::_get_camera_normal() const {
436 
437 	return -_get_camera_transform().basis.get_axis(2);
438 }
439 
_get_ray(const Vector2 & p_pos) const440 Vector3 SpatialEditorViewport::_get_ray(const Vector2 &p_pos) const {
441 
442 	return camera->project_ray_normal(p_pos / viewport_container->get_stretch_shrink());
443 }
444 
_clear_selected()445 void SpatialEditorViewport::_clear_selected() {
446 
447 	editor_selection->clear();
448 }
449 
_select_clicked(bool p_append,bool p_single)450 void SpatialEditorViewport::_select_clicked(bool p_append, bool p_single) {
451 
452 	if (!clicked)
453 		return;
454 
455 	Node *node = Object::cast_to<Node>(ObjectDB::get_instance(clicked));
456 	Spatial *selected = Object::cast_to<Spatial>(node);
457 	if (!selected)
458 		return;
459 
460 	// Replace the node by the group if grouped
461 	while (node && node != editor->get_edited_scene()->get_parent()) {
462 		Spatial *selected_tmp = Object::cast_to<Spatial>(node);
463 		if (selected_tmp && node->has_meta("_edit_group_")) {
464 			selected = selected_tmp;
465 		}
466 		node = node->get_parent();
467 	}
468 
469 	if (!_is_node_locked(selected))
470 		_select(selected, clicked_wants_append, true);
471 }
472 
_select(Node * p_node,bool p_append,bool p_single)473 void SpatialEditorViewport::_select(Node *p_node, bool p_append, bool p_single) {
474 
475 	if (!p_append) {
476 		editor_selection->clear();
477 	}
478 
479 	if (editor_selection->is_selected(p_node)) {
480 		//erase
481 		editor_selection->remove_node(p_node);
482 	} else {
483 
484 		editor_selection->add_node(p_node);
485 	}
486 
487 	if (p_single) {
488 		if (Engine::get_singleton()->is_editor_hint())
489 			editor->call("edit_node", p_node);
490 	}
491 }
492 
_select_ray(const Point2 & p_pos,bool p_append,bool & r_includes_current,int * r_gizmo_handle,bool p_alt_select)493 ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle, bool p_alt_select) {
494 
495 	if (r_gizmo_handle)
496 		*r_gizmo_handle = -1;
497 
498 	Vector3 ray = _get_ray(p_pos);
499 	Vector3 pos = _get_ray_pos(p_pos);
500 	Vector2 shrinked_pos = p_pos / viewport_container->get_stretch_shrink();
501 
502 	Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
503 	Set<Ref<EditorSpatialGizmo> > found_gizmos;
504 
505 	Node *edited_scene = get_tree()->get_edited_scene_root();
506 	ObjectID closest = 0;
507 	Node *item = NULL;
508 	float closest_dist = 1e20;
509 	int selected_handle = -1;
510 
511 	for (int i = 0; i < instances.size(); i++) {
512 
513 		Spatial *spat = Object::cast_to<Spatial>(ObjectDB::get_instance(instances[i]));
514 
515 		if (!spat)
516 			continue;
517 
518 		Ref<EditorSpatialGizmo> seg = spat->get_gizmo();
519 
520 		if ((!seg.is_valid()) || found_gizmos.has(seg)) {
521 			continue;
522 		}
523 
524 		found_gizmos.insert(seg);
525 		Vector3 point;
526 		Vector3 normal;
527 
528 		int handle = -1;
529 		bool inters = seg->intersect_ray(camera, shrinked_pos, point, normal, &handle, p_alt_select);
530 
531 		if (!inters)
532 			continue;
533 
534 		float dist = pos.distance_to(point);
535 
536 		if (dist < 0)
537 			continue;
538 
539 		if (dist < closest_dist) {
540 
541 			item = Object::cast_to<Node>(spat);
542 			while (item->get_owner() && item->get_owner() != edited_scene && !edited_scene->is_editable_instance(item->get_owner())) {
543 				item = item->get_owner();
544 			}
545 
546 			closest = item->get_instance_id();
547 			closest_dist = dist;
548 			selected_handle = handle;
549 		}
550 	}
551 
552 	if (!item)
553 		return 0;
554 
555 	if (!editor_selection->is_selected(item) || (r_gizmo_handle && selected_handle >= 0)) {
556 
557 		if (r_gizmo_handle)
558 			*r_gizmo_handle = selected_handle;
559 	}
560 
561 	return closest;
562 }
563 
_find_items_at_pos(const Point2 & p_pos,bool & r_includes_current,Vector<_RayResult> & results,bool p_alt_select)564 void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_includes_current, Vector<_RayResult> &results, bool p_alt_select) {
565 
566 	Vector3 ray = _get_ray(p_pos);
567 	Vector3 pos = _get_ray_pos(p_pos);
568 
569 	Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
570 	Set<Ref<EditorSpatialGizmo> > found_gizmos;
571 
572 	r_includes_current = false;
573 
574 	for (int i = 0; i < instances.size(); i++) {
575 
576 		Spatial *spat = Object::cast_to<Spatial>(ObjectDB::get_instance(instances[i]));
577 
578 		if (!spat)
579 			continue;
580 
581 		Ref<EditorSpatialGizmo> seg = spat->get_gizmo();
582 
583 		if (!seg.is_valid())
584 			continue;
585 
586 		if (found_gizmos.has(seg))
587 			continue;
588 
589 		found_gizmos.insert(seg);
590 		Vector3 point;
591 		Vector3 normal;
592 
593 		int handle = -1;
594 		bool inters = seg->intersect_ray(camera, p_pos, point, normal, NULL, p_alt_select);
595 
596 		if (!inters)
597 			continue;
598 
599 		float dist = pos.distance_to(point);
600 
601 		if (dist < 0)
602 			continue;
603 
604 		if (editor_selection->is_selected(spat))
605 			r_includes_current = true;
606 
607 		_RayResult res;
608 		res.item = spat;
609 		res.depth = dist;
610 		res.handle = handle;
611 		results.push_back(res);
612 	}
613 
614 	if (results.empty())
615 		return;
616 
617 	results.sort();
618 }
619 
_get_screen_to_space(const Vector3 & p_vector3)620 Vector3 SpatialEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) {
621 
622 	CameraMatrix cm;
623 	if (orthogonal) {
624 		cm.set_orthogonal(camera->get_size(), get_size().aspect(), get_znear() + p_vector3.z, get_zfar());
625 	} else {
626 		cm.set_perspective(get_fov(), get_size().aspect(), get_znear() + p_vector3.z, get_zfar());
627 	}
628 	Vector2 screen_he = cm.get_viewport_half_extents();
629 
630 	Transform camera_transform;
631 	camera_transform.translate(cursor.pos);
632 	camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
633 	camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
634 	camera_transform.translate(0, 0, cursor.distance);
635 
636 	return camera_transform.xform(Vector3(((p_vector3.x / get_size().width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (p_vector3.y / get_size().height)) * 2.0 - 1.0) * screen_he.y, -(get_znear() + p_vector3.z)));
637 }
638 
_select_region()639 void SpatialEditorViewport::_select_region() {
640 
641 	if (cursor.region_begin == cursor.region_end)
642 		return; //nothing really
643 
644 	float z_offset = MAX(0.0, 5.0 - get_znear());
645 
646 	Vector3 box[4] = {
647 		Vector3(
648 				MIN(cursor.region_begin.x, cursor.region_end.x),
649 				MIN(cursor.region_begin.y, cursor.region_end.y),
650 				z_offset),
651 		Vector3(
652 				MAX(cursor.region_begin.x, cursor.region_end.x),
653 				MIN(cursor.region_begin.y, cursor.region_end.y),
654 				z_offset),
655 		Vector3(
656 				MAX(cursor.region_begin.x, cursor.region_end.x),
657 				MAX(cursor.region_begin.y, cursor.region_end.y),
658 				z_offset),
659 		Vector3(
660 				MIN(cursor.region_begin.x, cursor.region_end.x),
661 				MAX(cursor.region_begin.y, cursor.region_end.y),
662 				z_offset)
663 	};
664 
665 	Vector<Plane> frustum;
666 
667 	Vector3 cam_pos = _get_camera_position();
668 
669 	for (int i = 0; i < 4; i++) {
670 
671 		Vector3 a = _get_screen_to_space(box[i]);
672 		Vector3 b = _get_screen_to_space(box[(i + 1) % 4]);
673 		if (orthogonal) {
674 			frustum.push_back(Plane(a, (a - b).normalized()));
675 		} else {
676 			frustum.push_back(Plane(a, b, cam_pos));
677 		}
678 	}
679 
680 	Plane near(cam_pos, -_get_camera_normal());
681 	near.d -= get_znear();
682 	frustum.push_back(near);
683 
684 	Plane far = -near;
685 	far.d += get_zfar();
686 	frustum.push_back(far);
687 
688 	Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world()->get_scenario());
689 	Vector<Node *> selected;
690 
691 	Node *edited_scene = get_tree()->get_edited_scene_root();
692 
693 	for (int i = 0; i < instances.size(); i++) {
694 
695 		Spatial *sp = Object::cast_to<Spatial>(ObjectDB::get_instance(instances[i]));
696 		if (!sp || _is_node_locked(sp))
697 			continue;
698 
699 		Node *item = Object::cast_to<Node>(sp);
700 		while (item->get_owner() && item->get_owner() != edited_scene && !edited_scene->is_editable_instance(item->get_owner())) {
701 			item = item->get_owner();
702 		}
703 
704 		// Replace the node by the group if grouped
705 		if (item->is_class("Spatial")) {
706 			Spatial *sel = Object::cast_to<Spatial>(item);
707 			while (item && item != editor->get_edited_scene()->get_parent()) {
708 				Spatial *selected_tmp = Object::cast_to<Spatial>(item);
709 				if (selected_tmp && item->has_meta("_edit_group_")) {
710 					sel = selected_tmp;
711 				}
712 				item = item->get_parent();
713 			}
714 			item = sel;
715 		}
716 
717 		if (selected.find(item) != -1) continue;
718 
719 		if (_is_node_locked(item)) continue;
720 
721 		Ref<EditorSpatialGizmo> seg = sp->get_gizmo();
722 
723 		if (!seg.is_valid())
724 			continue;
725 
726 		if (seg->intersect_frustum(camera, frustum)) {
727 			selected.push_back(item);
728 		}
729 	}
730 
731 	bool single = selected.size() == 1;
732 	for (int i = 0; i < selected.size(); i++) {
733 		_select(selected[i], true, single);
734 	}
735 }
736 
_update_name()737 void SpatialEditorViewport::_update_name() {
738 
739 	String view_mode = orthogonal ? TTR("Orthogonal") : TTR("Perspective");
740 
741 	if (auto_orthogonal) {
742 		view_mode += " [auto]";
743 	}
744 
745 	if (name != "")
746 		view_menu->set_text(name + " " + view_mode);
747 	else
748 		view_menu->set_text(view_mode);
749 
750 	view_menu->set_size(Vector2(0, 0)); // resets the button size
751 }
752 
_compute_edit(const Point2 & p_point)753 void SpatialEditorViewport::_compute_edit(const Point2 &p_point) {
754 
755 	_edit.click_ray = _get_ray(Vector2(p_point.x, p_point.y));
756 	_edit.click_ray_pos = _get_ray_pos(Vector2(p_point.x, p_point.y));
757 	_edit.plane = TRANSFORM_VIEW;
758 	spatial_editor->update_transform_gizmo();
759 	_edit.center = spatial_editor->get_gizmo_transform().origin;
760 
761 	List<Node *> &selection = editor_selection->get_selected_node_list();
762 
763 	for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
764 
765 		Spatial *sp = Object::cast_to<Spatial>(E->get());
766 		if (!sp)
767 			continue;
768 
769 		SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
770 		if (!se)
771 			continue;
772 
773 		se->original = se->sp->get_global_gizmo_transform();
774 		se->original_local = se->sp->get_local_gizmo_transform();
775 	}
776 }
777 
_get_key_modifier_setting(const String & p_property)778 static int _get_key_modifier_setting(const String &p_property) {
779 
780 	switch (EditorSettings::get_singleton()->get(p_property).operator int()) {
781 
782 		case 0: return 0;
783 		case 1: return KEY_SHIFT;
784 		case 2: return KEY_ALT;
785 		case 3: return KEY_META;
786 		case 4: return KEY_CONTROL;
787 	}
788 	return 0;
789 }
790 
_get_key_modifier(Ref<InputEventWithModifiers> e)791 static int _get_key_modifier(Ref<InputEventWithModifiers> e) {
792 	if (e->get_shift())
793 		return KEY_SHIFT;
794 	if (e->get_alt())
795 		return KEY_ALT;
796 	if (e->get_control())
797 		return KEY_CONTROL;
798 	if (e->get_metakey())
799 		return KEY_META;
800 	return 0;
801 }
802 
_gizmo_select(const Vector2 & p_screenpos,bool p_highlight_only)803 bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only) {
804 
805 	if (!spatial_editor->is_gizmo_visible())
806 		return false;
807 	if (get_selected_count() == 0) {
808 		if (p_highlight_only)
809 			spatial_editor->select_gizmo_highlight_axis(-1);
810 		return false;
811 	}
812 
813 	Vector3 ray_pos = _get_ray_pos(Vector2(p_screenpos.x, p_screenpos.y));
814 	Vector3 ray = _get_ray(Vector2(p_screenpos.x, p_screenpos.y));
815 
816 	Transform gt = spatial_editor->get_gizmo_transform();
817 	float gs = gizmo_scale;
818 
819 	if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE) {
820 
821 		int col_axis = -1;
822 		float col_d = 1e20;
823 
824 		for (int i = 0; i < 3; i++) {
825 
826 			Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5));
827 			float grabber_radius = gs * GIZMO_ARROW_SIZE;
828 
829 			Vector3 r;
830 
831 			if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
832 				float d = r.distance_to(ray_pos);
833 				if (d < col_d) {
834 					col_d = d;
835 					col_axis = i;
836 				}
837 			}
838 		}
839 
840 		bool is_plane_translate = false;
841 		// plane select
842 		if (col_axis == -1) {
843 			col_d = 1e20;
844 
845 			for (int i = 0; i < 3; i++) {
846 
847 				Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
848 				Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
849 
850 				Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST);
851 
852 				Vector3 r;
853 				Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
854 
855 				if (plane.intersects_ray(ray_pos, ray, &r)) {
856 
857 					float dist = r.distance_to(grabber_pos);
858 					if (dist < (gs * GIZMO_PLANE_SIZE)) {
859 
860 						float d = ray_pos.distance_to(r);
861 						if (d < col_d) {
862 							col_d = d;
863 							col_axis = i;
864 
865 							is_plane_translate = true;
866 						}
867 					}
868 				}
869 			}
870 		}
871 
872 		if (col_axis != -1) {
873 
874 			if (p_highlight_only) {
875 
876 				spatial_editor->select_gizmo_highlight_axis(col_axis + (is_plane_translate ? 6 : 0));
877 
878 			} else {
879 				//handle plane translate
880 				_edit.mode = TRANSFORM_TRANSLATE;
881 				_compute_edit(Point2(p_screenpos.x, p_screenpos.y));
882 				_edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_translate ? 3 : 0));
883 			}
884 			return true;
885 		}
886 	}
887 
888 	if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE) {
889 
890 		int col_axis = -1;
891 		float col_d = 1e20;
892 
893 		for (int i = 0; i < 3; i++) {
894 
895 			Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
896 			Vector3 r;
897 			if (!plane.intersects_ray(ray_pos, ray, &r))
898 				continue;
899 
900 			float dist = r.distance_to(gt.origin);
901 
902 			if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
903 
904 				float d = ray_pos.distance_to(r);
905 				if (d < col_d) {
906 					col_d = d;
907 					col_axis = i;
908 				}
909 			}
910 		}
911 
912 		if (col_axis != -1) {
913 
914 			if (p_highlight_only) {
915 
916 				spatial_editor->select_gizmo_highlight_axis(col_axis + 3);
917 			} else {
918 				//handle rotate
919 				_edit.mode = TRANSFORM_ROTATE;
920 				_compute_edit(Point2(p_screenpos.x, p_screenpos.y));
921 				_edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis);
922 			}
923 			return true;
924 		}
925 	}
926 
927 	if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE) {
928 
929 		int col_axis = -1;
930 		float col_d = 1e20;
931 
932 		for (int i = 0; i < 3; i++) {
933 
934 			Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * GIZMO_SCALE_OFFSET;
935 			float grabber_radius = gs * GIZMO_ARROW_SIZE;
936 
937 			Vector3 r;
938 
939 			if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
940 				float d = r.distance_to(ray_pos);
941 				if (d < col_d) {
942 					col_d = d;
943 					col_axis = i;
944 				}
945 			}
946 		}
947 
948 		bool is_plane_scale = false;
949 		// plane select
950 		if (col_axis == -1) {
951 			col_d = 1e20;
952 
953 			for (int i = 0; i < 3; i++) {
954 
955 				Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
956 				Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
957 
958 				Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST);
959 
960 				Vector3 r;
961 				Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
962 
963 				if (plane.intersects_ray(ray_pos, ray, &r)) {
964 
965 					float dist = r.distance_to(grabber_pos);
966 					if (dist < (gs * GIZMO_PLANE_SIZE)) {
967 
968 						float d = ray_pos.distance_to(r);
969 						if (d < col_d) {
970 							col_d = d;
971 							col_axis = i;
972 
973 							is_plane_scale = true;
974 						}
975 					}
976 				}
977 			}
978 		}
979 
980 		if (col_axis != -1) {
981 
982 			if (p_highlight_only) {
983 
984 				spatial_editor->select_gizmo_highlight_axis(col_axis + (is_plane_scale ? 12 : 9));
985 
986 			} else {
987 				//handle scale
988 				_edit.mode = TRANSFORM_SCALE;
989 				_compute_edit(Point2(p_screenpos.x, p_screenpos.y));
990 				_edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis + (is_plane_scale ? 3 : 0));
991 			}
992 			return true;
993 		}
994 	}
995 
996 	if (p_highlight_only)
997 		spatial_editor->select_gizmo_highlight_axis(-1);
998 
999 	return false;
1000 }
1001 
_surface_mouse_enter()1002 void SpatialEditorViewport::_surface_mouse_enter() {
1003 
1004 	if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
1005 		surface->grab_focus();
1006 }
1007 
_surface_mouse_exit()1008 void SpatialEditorViewport::_surface_mouse_exit() {
1009 
1010 	_remove_preview();
1011 }
1012 
_surface_focus_enter()1013 void SpatialEditorViewport::_surface_focus_enter() {
1014 
1015 	view_menu->set_disable_shortcuts(false);
1016 }
1017 
_surface_focus_exit()1018 void SpatialEditorViewport::_surface_focus_exit() {
1019 
1020 	view_menu->set_disable_shortcuts(true);
1021 }
_is_node_locked(const Node * p_node)1022 bool SpatialEditorViewport ::_is_node_locked(const Node *p_node) {
1023 	return p_node->has_meta("_edit_lock_") && p_node->get_meta("_edit_lock_");
1024 }
_list_select(Ref<InputEventMouseButton> b)1025 void SpatialEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
1026 
1027 	_find_items_at_pos(b->get_position(), clicked_includes_current, selection_results, b->get_shift());
1028 
1029 	Node *scene = editor->get_edited_scene();
1030 
1031 	for (int i = 0; i < selection_results.size(); i++) {
1032 		Spatial *item = selection_results[i].item;
1033 		if (item != scene && item->get_owner() != scene && !scene->is_editable_instance(item->get_owner())) {
1034 			//invalid result
1035 			selection_results.remove(i);
1036 			i--;
1037 		}
1038 	}
1039 
1040 	clicked_wants_append = b->get_shift();
1041 
1042 	if (selection_results.size() == 1) {
1043 
1044 		clicked = selection_results[0].item->get_instance_id();
1045 		selection_results.clear();
1046 
1047 		if (clicked) {
1048 			_select_clicked(clicked_wants_append, true);
1049 			clicked = 0;
1050 		}
1051 
1052 	} else if (!selection_results.empty()) {
1053 
1054 		NodePath root_path = get_tree()->get_edited_scene_root()->get_path();
1055 		StringName root_name = root_path.get_name(root_path.get_name_count() - 1);
1056 
1057 		for (int i = 0; i < selection_results.size(); i++) {
1058 
1059 			Spatial *spat = selection_results[i].item;
1060 
1061 			Ref<Texture> icon = EditorNode::get_singleton()->get_object_icon(spat, "Node");
1062 
1063 			String node_path = "/" + root_name + "/" + root_path.rel_path_to(spat->get_path());
1064 
1065 			selection_menu->add_item(spat->get_name());
1066 			selection_menu->set_item_icon(i, icon);
1067 			selection_menu->set_item_metadata(i, node_path);
1068 			selection_menu->set_item_tooltip(i, String(spat->get_name()) + "\nType: " + spat->get_class() + "\nPath: " + node_path);
1069 		}
1070 
1071 		selection_menu->set_global_position(b->get_global_position());
1072 		selection_menu->popup();
1073 	}
1074 }
1075 
_sinput(const Ref<InputEvent> & p_event)1076 void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
1077 
1078 	if (previewing)
1079 		return; //do NONE
1080 
1081 	{
1082 		EditorNode *en = editor;
1083 		EditorPluginList *force_input_forwarding_list = en->get_editor_plugins_force_input_forwarding();
1084 		if (!force_input_forwarding_list->empty()) {
1085 			bool discard = force_input_forwarding_list->forward_spatial_gui_input(camera, p_event, true);
1086 			if (discard)
1087 				return;
1088 		}
1089 	}
1090 	{
1091 		EditorNode *en = editor;
1092 		EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
1093 		if (!over_plugin_list->empty()) {
1094 			bool discard = over_plugin_list->forward_spatial_gui_input(camera, p_event, false);
1095 			if (discard)
1096 				return;
1097 		}
1098 	}
1099 
1100 	Ref<InputEventMouseButton> b = p_event;
1101 
1102 	if (b.is_valid()) {
1103 		emit_signal("clicked", this);
1104 
1105 		float zoom_factor = 1 + (ZOOM_MULTIPLIER - 1) * b->get_factor();
1106 		switch (b->get_button_index()) {
1107 
1108 			case BUTTON_WHEEL_UP: {
1109 				if (is_freelook_active())
1110 					scale_freelook_speed(zoom_factor);
1111 				else
1112 					scale_cursor_distance(1.0 / zoom_factor);
1113 			} break;
1114 
1115 			case BUTTON_WHEEL_DOWN: {
1116 				if (is_freelook_active())
1117 					scale_freelook_speed(1.0 / zoom_factor);
1118 				else
1119 					scale_cursor_distance(zoom_factor);
1120 			} break;
1121 
1122 			case BUTTON_RIGHT: {
1123 
1124 				NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
1125 
1126 				if (b->is_pressed() && _edit.gizmo.is_valid()) {
1127 					//restore
1128 					_edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, true);
1129 					_edit.gizmo = Ref<EditorSpatialGizmo>();
1130 				}
1131 
1132 				if (_edit.mode == TRANSFORM_NONE && b->is_pressed()) {
1133 
1134 					if (b->get_alt()) {
1135 
1136 						if (nav_scheme == NAVIGATION_MAYA)
1137 							break;
1138 
1139 						_list_select(b);
1140 						return;
1141 					}
1142 				}
1143 
1144 				if (_edit.mode != TRANSFORM_NONE && b->is_pressed()) {
1145 					//cancel motion
1146 					_edit.mode = TRANSFORM_NONE;
1147 
1148 					List<Node *> &selection = editor_selection->get_selected_node_list();
1149 
1150 					for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1151 
1152 						Spatial *sp = Object::cast_to<Spatial>(E->get());
1153 						if (!sp)
1154 							continue;
1155 
1156 						SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1157 						if (!se)
1158 							continue;
1159 
1160 						sp->set_global_transform(se->original);
1161 					}
1162 					surface->update();
1163 					set_message(TTR("Transform Aborted."), 3);
1164 				}
1165 
1166 				if (b->is_pressed()) {
1167 					const int mod = _get_key_modifier(b);
1168 					if (!orthogonal) {
1169 						if (mod == _get_key_modifier_setting("editors/3d/freelook/freelook_activation_modifier")) {
1170 							set_freelook_active(true);
1171 						}
1172 					}
1173 				} else {
1174 					set_freelook_active(false);
1175 				}
1176 
1177 				if (freelook_active && !surface->has_focus()) {
1178 					// Focus usually doesn't trigger on right-click, but in case of freelook it should,
1179 					// otherwise using keyboard navigation would misbehave
1180 					surface->grab_focus();
1181 				}
1182 
1183 			} break;
1184 			case BUTTON_MIDDLE: {
1185 
1186 				if (b->is_pressed() && _edit.mode != TRANSFORM_NONE) {
1187 
1188 					switch (_edit.plane) {
1189 
1190 						case TRANSFORM_VIEW: {
1191 
1192 							_edit.plane = TRANSFORM_X_AXIS;
1193 							set_message(TTR("X-Axis Transform."), 2);
1194 							name = "";
1195 							_update_name();
1196 						} break;
1197 						case TRANSFORM_X_AXIS: {
1198 
1199 							_edit.plane = TRANSFORM_Y_AXIS;
1200 							set_message(TTR("Y-Axis Transform."), 2);
1201 
1202 						} break;
1203 						case TRANSFORM_Y_AXIS: {
1204 
1205 							_edit.plane = TRANSFORM_Z_AXIS;
1206 							set_message(TTR("Z-Axis Transform."), 2);
1207 
1208 						} break;
1209 						case TRANSFORM_Z_AXIS: {
1210 
1211 							_edit.plane = TRANSFORM_VIEW;
1212 							set_message(TTR("View Plane Transform."), 2);
1213 
1214 						} break;
1215 						case TRANSFORM_YZ:
1216 						case TRANSFORM_XZ:
1217 						case TRANSFORM_XY: {
1218 						} break;
1219 					}
1220 				}
1221 			} break;
1222 			case BUTTON_LEFT: {
1223 
1224 				if (b->is_pressed()) {
1225 
1226 					NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
1227 					if ((nav_scheme == NAVIGATION_MAYA || nav_scheme == NAVIGATION_MODO) && b->get_alt()) {
1228 						break;
1229 					}
1230 
1231 					if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_LIST_SELECT) {
1232 						_list_select(b);
1233 						break;
1234 					}
1235 
1236 					_edit.mouse_pos = b->get_position();
1237 					_edit.snap = spatial_editor->is_snap_enabled();
1238 					_edit.mode = TRANSFORM_NONE;
1239 
1240 					//gizmo has priority over everything
1241 
1242 					bool can_select_gizmos = true;
1243 
1244 					{
1245 						int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
1246 						can_select_gizmos = view_menu->get_popup()->is_item_checked(idx);
1247 					}
1248 
1249 					if (can_select_gizmos && spatial_editor->get_selected()) {
1250 
1251 						Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo();
1252 						if (seg.is_valid()) {
1253 							int handle = -1;
1254 							Vector3 point;
1255 							Vector3 normal;
1256 							bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, b->get_shift());
1257 							if (inters && handle != -1) {
1258 
1259 								_edit.gizmo = seg;
1260 								_edit.gizmo_handle = handle;
1261 								_edit.gizmo_initial_value = seg->get_handle_value(handle);
1262 								break;
1263 							}
1264 						}
1265 					}
1266 
1267 					if (_gizmo_select(_edit.mouse_pos))
1268 						break;
1269 
1270 					clicked = 0;
1271 					clicked_includes_current = false;
1272 
1273 					if ((spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT && b->get_control()) || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE) {
1274 
1275 						/* HANDLE ROTATION */
1276 						if (get_selected_count() == 0)
1277 							break; //bye
1278 						//handle rotate
1279 						_edit.mode = TRANSFORM_ROTATE;
1280 						_compute_edit(b->get_position());
1281 						break;
1282 					}
1283 
1284 					if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE) {
1285 
1286 						if (get_selected_count() == 0)
1287 							break; //bye
1288 						//handle translate
1289 						_edit.mode = TRANSFORM_TRANSLATE;
1290 						_compute_edit(b->get_position());
1291 						break;
1292 					}
1293 
1294 					if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE) {
1295 
1296 						if (get_selected_count() == 0)
1297 							break; //bye
1298 						//handle scale
1299 						_edit.mode = TRANSFORM_SCALE;
1300 						_compute_edit(b->get_position());
1301 						break;
1302 					}
1303 
1304 					// todo scale
1305 
1306 					int gizmo_handle = -1;
1307 
1308 					clicked = _select_ray(b->get_position(), b->get_shift(), clicked_includes_current, &gizmo_handle, b->get_shift());
1309 
1310 					//clicking is always deferred to either move or release
1311 
1312 					clicked_wants_append = b->get_shift();
1313 
1314 					if (!clicked) {
1315 
1316 						if (!clicked_wants_append)
1317 							_clear_selected();
1318 
1319 						//default to regionselect
1320 						cursor.region_select = true;
1321 						cursor.region_begin = b->get_position();
1322 						cursor.region_end = b->get_position();
1323 					}
1324 
1325 					if (clicked && gizmo_handle >= 0) {
1326 
1327 						Spatial *spa = Object::cast_to<Spatial>(ObjectDB::get_instance(clicked));
1328 						if (spa) {
1329 
1330 							Ref<EditorSpatialGizmo> seg = spa->get_gizmo();
1331 							if (seg.is_valid()) {
1332 
1333 								_edit.gizmo = seg;
1334 								_edit.gizmo_handle = gizmo_handle;
1335 								_edit.gizmo_initial_value = seg->get_handle_value(gizmo_handle);
1336 								break;
1337 							}
1338 						}
1339 					}
1340 
1341 					surface->update();
1342 				} else {
1343 
1344 					if (_edit.gizmo.is_valid()) {
1345 
1346 						_edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, false);
1347 						_edit.gizmo = Ref<EditorSpatialGizmo>();
1348 						break;
1349 					}
1350 					if (clicked) {
1351 						_select_clicked(clicked_wants_append, true);
1352 						// Processing was deferred.
1353 						clicked = 0;
1354 					}
1355 
1356 					if (cursor.region_select) {
1357 
1358 						if (!clicked_wants_append) _clear_selected();
1359 
1360 						_select_region();
1361 						cursor.region_select = false;
1362 						surface->update();
1363 					}
1364 
1365 					if (_edit.mode != TRANSFORM_NONE) {
1366 
1367 						static const char *_transform_name[4] = { "None", "Rotate", "Translate", "Scale" };
1368 						undo_redo->create_action(_transform_name[_edit.mode]);
1369 
1370 						List<Node *> &selection = editor_selection->get_selected_node_list();
1371 
1372 						for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1373 
1374 							Spatial *sp = Object::cast_to<Spatial>(E->get());
1375 							if (!sp)
1376 								continue;
1377 
1378 							SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1379 							if (!se)
1380 								continue;
1381 
1382 							undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
1383 							undo_redo->add_undo_method(sp, "set_global_transform", se->original);
1384 						}
1385 						undo_redo->commit_action();
1386 						_edit.mode = TRANSFORM_NONE;
1387 						set_message("");
1388 					}
1389 
1390 					surface->update();
1391 				}
1392 
1393 			} break;
1394 		}
1395 	}
1396 
1397 	Ref<InputEventMouseMotion> m = p_event;
1398 
1399 	if (m.is_valid()) {
1400 
1401 		_edit.mouse_pos = m->get_position();
1402 
1403 		if (spatial_editor->get_selected()) {
1404 
1405 			Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo();
1406 			if (seg.is_valid()) {
1407 
1408 				int selected_handle = -1;
1409 
1410 				int handle = -1;
1411 				Vector3 point;
1412 				Vector3 normal;
1413 				bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, false);
1414 				if (inters && handle != -1) {
1415 
1416 					selected_handle = handle;
1417 				}
1418 
1419 				if (selected_handle != spatial_editor->get_over_gizmo_handle()) {
1420 					spatial_editor->set_over_gizmo_handle(selected_handle);
1421 					spatial_editor->get_selected()->update_gizmo();
1422 					if (selected_handle != -1)
1423 						spatial_editor->select_gizmo_highlight_axis(-1);
1424 				}
1425 			}
1426 		}
1427 
1428 		if (spatial_editor->get_over_gizmo_handle() == -1 && !(m->get_button_mask() & 1) && !_edit.gizmo.is_valid()) {
1429 
1430 			_gizmo_select(_edit.mouse_pos, true);
1431 		}
1432 
1433 		NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
1434 		NavigationMode nav_mode = NAVIGATION_NONE;
1435 
1436 		if (_edit.gizmo.is_valid()) {
1437 
1438 			_edit.gizmo->set_handle(_edit.gizmo_handle, camera, m->get_position());
1439 			Variant v = _edit.gizmo->get_handle_value(_edit.gizmo_handle);
1440 			String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle);
1441 			set_message(n + ": " + String(v));
1442 
1443 		} else if (m->get_button_mask() & BUTTON_MASK_LEFT) {
1444 
1445 			if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) {
1446 				nav_mode = NAVIGATION_ORBIT;
1447 			} else if (nav_scheme == NAVIGATION_MODO && m->get_alt() && m->get_shift()) {
1448 				nav_mode = NAVIGATION_PAN;
1449 			} else if (nav_scheme == NAVIGATION_MODO && m->get_alt() && m->get_control()) {
1450 				nav_mode = NAVIGATION_ZOOM;
1451 			} else if (nav_scheme == NAVIGATION_MODO && m->get_alt()) {
1452 				nav_mode = NAVIGATION_ORBIT;
1453 			} else {
1454 				if (clicked) {
1455 
1456 					if (!clicked_includes_current) {
1457 
1458 						_select_clicked(clicked_wants_append, true);
1459 						// Processing was deferred.
1460 					}
1461 
1462 					_compute_edit(_edit.mouse_pos);
1463 					clicked = 0;
1464 
1465 					_edit.mode = TRANSFORM_TRANSLATE;
1466 				}
1467 
1468 				if (cursor.region_select) {
1469 					cursor.region_end = m->get_position();
1470 					surface->update();
1471 					return;
1472 				}
1473 
1474 				if (_edit.mode == TRANSFORM_NONE)
1475 					return;
1476 
1477 				Vector3 ray_pos = _get_ray_pos(m->get_position());
1478 				Vector3 ray = _get_ray(m->get_position());
1479 				float snap = EDITOR_GET("interface/inspector/default_float_step");
1480 				int snap_step_decimals = Math::range_step_decimals(snap);
1481 
1482 				switch (_edit.mode) {
1483 
1484 					case TRANSFORM_SCALE: {
1485 
1486 						Vector3 motion_mask;
1487 						Plane plane;
1488 						bool plane_mv = false;
1489 
1490 						switch (_edit.plane) {
1491 							case TRANSFORM_VIEW:
1492 								motion_mask = Vector3(0, 0, 0);
1493 								plane = Plane(_edit.center, _get_camera_normal());
1494 								break;
1495 							case TRANSFORM_X_AXIS:
1496 								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
1497 								plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
1498 								break;
1499 							case TRANSFORM_Y_AXIS:
1500 								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
1501 								plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
1502 								break;
1503 							case TRANSFORM_Z_AXIS:
1504 								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
1505 								plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
1506 								break;
1507 							case TRANSFORM_YZ:
1508 								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(1);
1509 								plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
1510 								plane_mv = true;
1511 								break;
1512 							case TRANSFORM_XZ:
1513 								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(0);
1514 								plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1));
1515 								plane_mv = true;
1516 								break;
1517 							case TRANSFORM_XY:
1518 								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0) + spatial_editor->get_gizmo_transform().basis.get_axis(1);
1519 								plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2));
1520 								plane_mv = true;
1521 								break;
1522 						}
1523 
1524 						Vector3 intersection;
1525 						if (!plane.intersects_ray(ray_pos, ray, &intersection))
1526 							break;
1527 
1528 						Vector3 click;
1529 						if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
1530 							break;
1531 
1532 						Vector3 motion = intersection - click;
1533 						if (_edit.plane != TRANSFORM_VIEW) {
1534 
1535 							if (!plane_mv) {
1536 
1537 								motion = motion_mask.dot(motion) * motion_mask;
1538 
1539 							} else {
1540 
1541 								// Alternative planar scaling mode
1542 								if (_get_key_modifier(m) != KEY_SHIFT) {
1543 									motion = motion_mask.dot(motion) * motion_mask;
1544 								}
1545 							}
1546 
1547 						} else {
1548 							float center_click_dist = click.distance_to(_edit.center);
1549 							float center_inters_dist = intersection.distance_to(_edit.center);
1550 							if (center_click_dist == 0)
1551 								break;
1552 
1553 							float scale = center_inters_dist - center_click_dist;
1554 							motion = Vector3(scale, scale, scale);
1555 						}
1556 
1557 						List<Node *> &selection = editor_selection->get_selected_node_list();
1558 
1559 						// Disable local transformation for TRANSFORM_VIEW
1560 						bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
1561 
1562 						if (_edit.snap || spatial_editor->is_snap_enabled()) {
1563 							snap = spatial_editor->get_scale_snap() / 100;
1564 						}
1565 						Vector3 motion_snapped = motion;
1566 						motion_snapped.snap(Vector3(snap, snap, snap));
1567 						// This might not be necessary anymore after issue #288 is solved (in 4.0?).
1568 						set_message(TTR("Scaling: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
1569 									String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
1570 
1571 						for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1572 
1573 							Spatial *sp = Object::cast_to<Spatial>(E->get());
1574 							if (!sp) {
1575 								continue;
1576 							}
1577 
1578 							SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1579 							if (!se) {
1580 								continue;
1581 							}
1582 
1583 							if (sp->has_meta("_edit_lock_")) {
1584 								continue;
1585 							}
1586 
1587 							Transform original = se->original;
1588 							Transform original_local = se->original_local;
1589 							Transform base = Transform(Basis(), _edit.center);
1590 							Transform t;
1591 							Vector3 local_scale;
1592 
1593 							if (local_coords) {
1594 
1595 								Basis g = original.basis.orthonormalized();
1596 								Vector3 local_motion = g.inverse().xform(motion);
1597 
1598 								if (_edit.snap || spatial_editor->is_snap_enabled()) {
1599 									local_motion.snap(Vector3(snap, snap, snap));
1600 								}
1601 
1602 								local_scale = original_local.basis.get_scale() * (local_motion + Vector3(1, 1, 1));
1603 
1604 								// Prevent scaling to 0 it would break the gizmo
1605 								Basis check = original_local.basis;
1606 								check.scale(local_scale);
1607 								if (check.determinant() != 0) {
1608 
1609 									// Apply scale
1610 									sp->set_scale(local_scale);
1611 								}
1612 
1613 							} else {
1614 
1615 								if (_edit.snap || spatial_editor->is_snap_enabled()) {
1616 									motion.snap(Vector3(snap, snap, snap));
1617 								}
1618 
1619 								Transform r;
1620 								r.basis.scale(motion + Vector3(1, 1, 1));
1621 								t = base * (r * (base.inverse() * original));
1622 
1623 								// Apply scale
1624 								sp->set_global_transform(t);
1625 							}
1626 						}
1627 
1628 						surface->update();
1629 
1630 					} break;
1631 
1632 					case TRANSFORM_TRANSLATE: {
1633 
1634 						Vector3 motion_mask;
1635 						Plane plane;
1636 						bool plane_mv = false;
1637 
1638 						switch (_edit.plane) {
1639 							case TRANSFORM_VIEW:
1640 								plane = Plane(_edit.center, _get_camera_normal());
1641 								break;
1642 							case TRANSFORM_X_AXIS:
1643 								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
1644 								plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
1645 								break;
1646 							case TRANSFORM_Y_AXIS:
1647 								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
1648 								plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
1649 								break;
1650 							case TRANSFORM_Z_AXIS:
1651 								motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
1652 								plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
1653 								break;
1654 							case TRANSFORM_YZ:
1655 								plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
1656 								plane_mv = true;
1657 								break;
1658 							case TRANSFORM_XZ:
1659 								plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1));
1660 								plane_mv = true;
1661 								break;
1662 							case TRANSFORM_XY:
1663 								plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2));
1664 								plane_mv = true;
1665 								break;
1666 						}
1667 
1668 						Vector3 intersection;
1669 						if (!plane.intersects_ray(ray_pos, ray, &intersection))
1670 							break;
1671 
1672 						Vector3 click;
1673 						if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
1674 							break;
1675 
1676 						Vector3 motion = intersection - click;
1677 						if (_edit.plane != TRANSFORM_VIEW) {
1678 							if (!plane_mv) {
1679 								motion = motion_mask.dot(motion) * motion_mask;
1680 							}
1681 						}
1682 
1683 						List<Node *> &selection = editor_selection->get_selected_node_list();
1684 
1685 						// Disable local transformation for TRANSFORM_VIEW
1686 						bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
1687 
1688 						if (_edit.snap || spatial_editor->is_snap_enabled()) {
1689 							snap = spatial_editor->get_translate_snap();
1690 						}
1691 						Vector3 motion_snapped = motion;
1692 						motion_snapped.snap(Vector3(snap, snap, snap));
1693 						set_message(TTR("Translating: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
1694 									String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
1695 
1696 						for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1697 
1698 							Spatial *sp = Object::cast_to<Spatial>(E->get());
1699 							if (!sp) {
1700 								continue;
1701 							}
1702 
1703 							SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1704 							if (!se) {
1705 								continue;
1706 							}
1707 
1708 							if (sp->has_meta("_edit_lock_")) {
1709 								continue;
1710 							}
1711 
1712 							Transform original = se->original;
1713 							Transform t;
1714 
1715 							if (local_coords) {
1716 
1717 								if (_edit.snap || spatial_editor->is_snap_enabled()) {
1718 									Basis g = original.basis.orthonormalized();
1719 									Vector3 local_motion = g.inverse().xform(motion);
1720 									local_motion.snap(Vector3(snap, snap, snap));
1721 
1722 									motion = g.xform(local_motion);
1723 								}
1724 
1725 							} else {
1726 
1727 								if (_edit.snap || spatial_editor->is_snap_enabled()) {
1728 									motion.snap(Vector3(snap, snap, snap));
1729 								}
1730 							}
1731 
1732 							// Apply translation
1733 							t = original;
1734 							t.origin += motion;
1735 							sp->set_global_transform(t);
1736 						}
1737 
1738 						surface->update();
1739 
1740 					} break;
1741 
1742 					case TRANSFORM_ROTATE: {
1743 
1744 						Plane plane;
1745 						Vector3 axis;
1746 
1747 						switch (_edit.plane) {
1748 							case TRANSFORM_VIEW:
1749 								plane = Plane(_edit.center, _get_camera_normal());
1750 								break;
1751 							case TRANSFORM_X_AXIS:
1752 								plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
1753 								axis = Vector3(1, 0, 0);
1754 								break;
1755 							case TRANSFORM_Y_AXIS:
1756 								plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1));
1757 								axis = Vector3(0, 1, 0);
1758 								break;
1759 							case TRANSFORM_Z_AXIS:
1760 								plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2));
1761 								axis = Vector3(0, 0, 1);
1762 								break;
1763 							case TRANSFORM_YZ:
1764 							case TRANSFORM_XZ:
1765 							case TRANSFORM_XY:
1766 								break;
1767 						}
1768 
1769 						Vector3 intersection;
1770 						if (!plane.intersects_ray(ray_pos, ray, &intersection))
1771 							break;
1772 
1773 						Vector3 click;
1774 						if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
1775 							break;
1776 
1777 						Vector3 y_axis = (click - _edit.center).normalized();
1778 						Vector3 x_axis = plane.normal.cross(y_axis).normalized();
1779 
1780 						float angle = Math::atan2(x_axis.dot(intersection - _edit.center), y_axis.dot(intersection - _edit.center));
1781 
1782 						if (_edit.snap || spatial_editor->is_snap_enabled()) {
1783 							snap = spatial_editor->get_rotate_snap();
1784 						}
1785 						angle = Math::rad2deg(angle) + snap * 0.5; //else it won't reach +180
1786 						angle -= Math::fmod(angle, snap);
1787 						set_message(vformat(TTR("Rotating %s degrees."), String::num(angle, snap_step_decimals)));
1788 						angle = Math::deg2rad(angle);
1789 
1790 						List<Node *> &selection = editor_selection->get_selected_node_list();
1791 
1792 						bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
1793 
1794 						for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1795 
1796 							Spatial *sp = Object::cast_to<Spatial>(E->get());
1797 							if (!sp)
1798 								continue;
1799 
1800 							SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1801 							if (!se)
1802 								continue;
1803 
1804 							if (sp->has_meta("_edit_lock_")) {
1805 								continue;
1806 							}
1807 
1808 							Transform t;
1809 
1810 							if (local_coords) {
1811 
1812 								Transform original_local = se->original_local;
1813 								Basis rot = Basis(axis, angle);
1814 
1815 								t.basis = original_local.get_basis().orthonormalized() * rot;
1816 								t.origin = original_local.origin;
1817 
1818 								// Apply rotation
1819 								sp->set_transform(t);
1820 								sp->set_scale(original_local.basis.get_scale()); // re-apply original scale
1821 
1822 							} else {
1823 
1824 								Transform original = se->original;
1825 								Transform r;
1826 								Transform base = Transform(Basis(), _edit.center);
1827 
1828 								r.basis.rotate(plane.normal, angle);
1829 								t = base * r * base.inverse() * original;
1830 
1831 								// Apply rotation
1832 								sp->set_global_transform(t);
1833 							}
1834 						}
1835 
1836 						surface->update();
1837 
1838 					} break;
1839 					default: {
1840 					}
1841 				}
1842 			}
1843 
1844 		} else if ((m->get_button_mask() & BUTTON_MASK_RIGHT) || freelook_active) {
1845 
1846 			if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) {
1847 				nav_mode = NAVIGATION_ZOOM;
1848 			} else if (freelook_active) {
1849 				nav_mode = NAVIGATION_LOOK;
1850 			} else if (orthogonal) {
1851 				nav_mode = NAVIGATION_PAN;
1852 			}
1853 
1854 		} else if (m->get_button_mask() & BUTTON_MASK_MIDDLE) {
1855 
1856 			if (nav_scheme == NAVIGATION_GODOT) {
1857 
1858 				const int mod = _get_key_modifier(m);
1859 
1860 				if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
1861 					nav_mode = NAVIGATION_PAN;
1862 				} else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) {
1863 					nav_mode = NAVIGATION_ZOOM;
1864 				} else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
1865 					// Always allow Alt as a modifier to better support graphic tablets.
1866 					nav_mode = NAVIGATION_ORBIT;
1867 				}
1868 
1869 			} else if (nav_scheme == NAVIGATION_MAYA) {
1870 				if (m->get_alt())
1871 					nav_mode = NAVIGATION_PAN;
1872 			}
1873 
1874 		} else if (EditorSettings::get_singleton()->get("editors/3d/navigation/emulate_3_button_mouse")) {
1875 			// Handle trackpad (no external mouse) use case
1876 			const int mod = _get_key_modifier(m);
1877 
1878 			if (mod) {
1879 				if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
1880 					nav_mode = NAVIGATION_PAN;
1881 				} else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) {
1882 					nav_mode = NAVIGATION_ZOOM;
1883 				} else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
1884 					// Always allow Alt as a modifier to better support graphic tablets.
1885 					nav_mode = NAVIGATION_ORBIT;
1886 				}
1887 			}
1888 		}
1889 
1890 		switch (nav_mode) {
1891 			case NAVIGATION_PAN: {
1892 				_nav_pan(m, _get_warped_mouse_motion(m));
1893 
1894 			} break;
1895 
1896 			case NAVIGATION_ZOOM: {
1897 				_nav_zoom(m, m->get_relative());
1898 
1899 			} break;
1900 
1901 			case NAVIGATION_ORBIT: {
1902 				_nav_orbit(m, _get_warped_mouse_motion(m));
1903 
1904 			} break;
1905 
1906 			case NAVIGATION_LOOK: {
1907 				_nav_look(m, _get_warped_mouse_motion(m));
1908 
1909 			} break;
1910 
1911 			default: {
1912 			}
1913 		}
1914 	}
1915 
1916 	Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
1917 	if (magnify_gesture.is_valid()) {
1918 
1919 		if (is_freelook_active())
1920 			scale_freelook_speed(magnify_gesture->get_factor());
1921 		else
1922 			scale_cursor_distance(1.0 / magnify_gesture->get_factor());
1923 	}
1924 
1925 	Ref<InputEventPanGesture> pan_gesture = p_event;
1926 	if (pan_gesture.is_valid()) {
1927 
1928 		NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
1929 		NavigationMode nav_mode = NAVIGATION_NONE;
1930 
1931 		if (nav_scheme == NAVIGATION_GODOT) {
1932 
1933 			const int mod = _get_key_modifier(pan_gesture);
1934 
1935 			if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
1936 				nav_mode = NAVIGATION_PAN;
1937 			} else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) {
1938 				nav_mode = NAVIGATION_ZOOM;
1939 			} else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) {
1940 				// Always allow Alt as a modifier to better support graphic tablets.
1941 				nav_mode = NAVIGATION_ORBIT;
1942 			}
1943 
1944 		} else if (nav_scheme == NAVIGATION_MAYA) {
1945 			if (pan_gesture->get_alt())
1946 				nav_mode = NAVIGATION_PAN;
1947 		}
1948 
1949 		switch (nav_mode) {
1950 			case NAVIGATION_PAN: {
1951 				_nav_pan(pan_gesture, pan_gesture->get_delta());
1952 
1953 			} break;
1954 
1955 			case NAVIGATION_ZOOM: {
1956 				_nav_zoom(pan_gesture, pan_gesture->get_delta());
1957 
1958 			} break;
1959 
1960 			case NAVIGATION_ORBIT: {
1961 				_nav_orbit(pan_gesture, pan_gesture->get_delta());
1962 
1963 			} break;
1964 
1965 			case NAVIGATION_LOOK: {
1966 				_nav_look(pan_gesture, pan_gesture->get_delta());
1967 
1968 			} break;
1969 
1970 			default: {
1971 			}
1972 		}
1973 	}
1974 
1975 	Ref<InputEventKey> k = p_event;
1976 
1977 	if (k.is_valid()) {
1978 		if (!k->is_pressed())
1979 			return;
1980 
1981 		if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) {
1982 			if (_edit.mode != TRANSFORM_NONE) {
1983 				_edit.snap = !_edit.snap;
1984 			}
1985 		}
1986 		if (ED_IS_SHORTCUT("spatial_editor/bottom_view", p_event)) {
1987 			_menu_option(VIEW_BOTTOM);
1988 		}
1989 		if (ED_IS_SHORTCUT("spatial_editor/top_view", p_event)) {
1990 			_menu_option(VIEW_TOP);
1991 		}
1992 		if (ED_IS_SHORTCUT("spatial_editor/rear_view", p_event)) {
1993 			_menu_option(VIEW_REAR);
1994 		}
1995 		if (ED_IS_SHORTCUT("spatial_editor/front_view", p_event)) {
1996 			_menu_option(VIEW_FRONT);
1997 		}
1998 		if (ED_IS_SHORTCUT("spatial_editor/left_view", p_event)) {
1999 			_menu_option(VIEW_LEFT);
2000 		}
2001 		if (ED_IS_SHORTCUT("spatial_editor/right_view", p_event)) {
2002 			_menu_option(VIEW_RIGHT);
2003 		}
2004 		if (ED_IS_SHORTCUT("spatial_editor/focus_origin", p_event)) {
2005 			_menu_option(VIEW_CENTER_TO_ORIGIN);
2006 		}
2007 		if (ED_IS_SHORTCUT("spatial_editor/focus_selection", p_event)) {
2008 			_menu_option(VIEW_CENTER_TO_SELECTION);
2009 		}
2010 		// Orthgonal mode doesn't work in freelook.
2011 		if (!freelook_active && ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) {
2012 			_menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_ORTHOGONAL);
2013 		}
2014 		if (ED_IS_SHORTCUT("spatial_editor/align_transform_with_view", p_event)) {
2015 			_menu_option(VIEW_ALIGN_TRANSFORM_WITH_VIEW);
2016 		}
2017 		if (ED_IS_SHORTCUT("spatial_editor/align_rotation_with_view", p_event)) {
2018 			_menu_option(VIEW_ALIGN_ROTATION_WITH_VIEW);
2019 		}
2020 		if (ED_IS_SHORTCUT("spatial_editor/insert_anim_key", p_event)) {
2021 			if (!get_selected_count() || _edit.mode != TRANSFORM_NONE)
2022 				return;
2023 
2024 			if (!AnimationPlayerEditor::singleton->get_track_editor()->has_keying()) {
2025 				set_message(TTR("Keying is disabled (no key inserted)."));
2026 				return;
2027 			}
2028 
2029 			List<Node *> &selection = editor_selection->get_selected_node_list();
2030 
2031 			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
2032 
2033 				Spatial *sp = Object::cast_to<Spatial>(E->get());
2034 				if (!sp)
2035 					continue;
2036 
2037 				spatial_editor->emit_signal("transform_key_request", sp, "", sp->get_transform());
2038 			}
2039 
2040 			set_message(TTR("Animation Key Inserted."));
2041 		}
2042 
2043 		// Freelook doesn't work in orthogonal mode.
2044 		if (!orthogonal && ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) {
2045 			set_freelook_active(!is_freelook_active());
2046 
2047 		} else if (k->get_scancode() == KEY_ESCAPE) {
2048 			set_freelook_active(false);
2049 		}
2050 
2051 		if (k->get_scancode() == KEY_SPACE) {
2052 			if (!k->is_pressed()) emit_signal("toggle_maximize_view", this);
2053 		}
2054 	}
2055 
2056 	// freelook uses most of the useful shortcuts, like save, so its ok
2057 	// to consider freelook active as end of the line for future events.
2058 	if (freelook_active)
2059 		accept_event();
2060 }
2061 
_nav_pan(Ref<InputEventWithModifiers> p_event,const Vector2 & p_relative)2062 void SpatialEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
2063 
2064 	const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
2065 
2066 	real_t pan_speed = 1 / 150.0;
2067 	int pan_speed_modifier = 10;
2068 	if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift())
2069 		pan_speed *= pan_speed_modifier;
2070 
2071 	Transform camera_transform;
2072 
2073 	camera_transform.translate(cursor.pos);
2074 	camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
2075 	camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
2076 	const bool invert_x_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_x_axis");
2077 	const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
2078 	Vector3 translation(
2079 			(invert_x_axis ? -1 : 1) * -p_relative.x * pan_speed,
2080 			(invert_y_axis ? -1 : 1) * p_relative.y * pan_speed,
2081 			0);
2082 	translation *= cursor.distance / DISTANCE_DEFAULT;
2083 	camera_transform.translate(translation);
2084 	cursor.pos = camera_transform.origin;
2085 }
2086 
_nav_zoom(Ref<InputEventWithModifiers> p_event,const Vector2 & p_relative)2087 void SpatialEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
2088 
2089 	const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
2090 
2091 	real_t zoom_speed = 1 / 80.0;
2092 	int zoom_speed_modifier = 10;
2093 	if (nav_scheme == NAVIGATION_MAYA && p_event->get_shift())
2094 		zoom_speed *= zoom_speed_modifier;
2095 
2096 	NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/navigation/zoom_style").operator int();
2097 	if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) {
2098 		if (p_relative.x > 0)
2099 			scale_cursor_distance(1 - p_relative.x * zoom_speed);
2100 		else if (p_relative.x < 0)
2101 			scale_cursor_distance(1.0 / (1 + p_relative.x * zoom_speed));
2102 	} else {
2103 		if (p_relative.y > 0)
2104 			scale_cursor_distance(1 + p_relative.y * zoom_speed);
2105 		else if (p_relative.y < 0)
2106 			scale_cursor_distance(1.0 / (1 - p_relative.y * zoom_speed));
2107 	}
2108 }
2109 
_nav_orbit(Ref<InputEventWithModifiers> p_event,const Vector2 & p_relative)2110 void SpatialEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
2111 
2112 	if (lock_rotation) {
2113 		_nav_pan(p_event, p_relative);
2114 		return;
2115 	}
2116 
2117 	if (orthogonal && auto_orthogonal) {
2118 		_menu_option(VIEW_PERSPECTIVE);
2119 	}
2120 
2121 	const real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
2122 	const real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
2123 	const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
2124 	const bool invert_x_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_x_axis");
2125 
2126 	if (invert_y_axis) {
2127 		cursor.x_rot -= p_relative.y * radians_per_pixel;
2128 	} else {
2129 		cursor.x_rot += p_relative.y * radians_per_pixel;
2130 	}
2131 	// Clamp the Y rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented.
2132 	cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57);
2133 
2134 	if (invert_x_axis) {
2135 		cursor.y_rot -= p_relative.x * radians_per_pixel;
2136 	} else {
2137 		cursor.y_rot += p_relative.x * radians_per_pixel;
2138 	}
2139 	name = "";
2140 	_update_name();
2141 }
2142 
_nav_look(Ref<InputEventWithModifiers> p_event,const Vector2 & p_relative)2143 void SpatialEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
2144 
2145 	if (orthogonal) {
2146 		_nav_pan(p_event, p_relative);
2147 		return;
2148 	}
2149 
2150 	if (orthogonal && auto_orthogonal) {
2151 		_menu_option(VIEW_PERSPECTIVE);
2152 	}
2153 
2154 	const real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
2155 	const real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
2156 	const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
2157 
2158 	// Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
2159 	const Transform prev_camera_transform = to_camera_transform(cursor);
2160 
2161 	if (invert_y_axis) {
2162 		cursor.x_rot -= p_relative.y * radians_per_pixel;
2163 	} else {
2164 		cursor.x_rot += p_relative.y * radians_per_pixel;
2165 	}
2166 	// Clamp the Y rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented.
2167 	cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57);
2168 
2169 	cursor.y_rot += p_relative.x * radians_per_pixel;
2170 
2171 	// Look is like the opposite of Orbit: the focus point rotates around the camera
2172 	Transform camera_transform = to_camera_transform(cursor);
2173 	Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
2174 	Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0));
2175 	Vector3 diff = prev_pos - pos;
2176 	cursor.pos += diff;
2177 
2178 	name = "";
2179 	_update_name();
2180 }
2181 
set_freelook_active(bool active_now)2182 void SpatialEditorViewport::set_freelook_active(bool active_now) {
2183 
2184 	if (!freelook_active && active_now) {
2185 		// Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential
2186 		cursor = camera_cursor;
2187 
2188 		// Make sure eye_pos is synced, because freelook referential is eye pos rather than orbit pos
2189 		Vector3 forward = to_camera_transform(cursor).basis.xform(Vector3(0, 0, -1));
2190 		cursor.eye_pos = cursor.pos - cursor.distance * forward;
2191 		// Also sync the camera cursor, otherwise switching to freelook will be trippy if inertia is active
2192 		camera_cursor.eye_pos = cursor.eye_pos;
2193 
2194 		if (EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_speed_zoom_link")) {
2195 			// Re-adjust freelook speed from the current zoom level
2196 			real_t base_speed = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_base_speed");
2197 			freelook_speed = base_speed * cursor.distance;
2198 		}
2199 
2200 		previous_mouse_position = get_local_mouse_position();
2201 
2202 		// Hide mouse like in an FPS (warping doesn't work)
2203 		Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
2204 
2205 	} else if (freelook_active && !active_now) {
2206 		// Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential
2207 		cursor = camera_cursor;
2208 
2209 		// Restore mouse
2210 		Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
2211 
2212 		// Restore the previous mouse position when leaving freelook mode.
2213 		// This is done because leaving `Input.MOUSE_MODE_CAPTURED` will center the cursor
2214 		// due to OS limitations.
2215 		warp_mouse(previous_mouse_position);
2216 	}
2217 
2218 	freelook_active = active_now;
2219 }
2220 
scale_cursor_distance(real_t scale)2221 void SpatialEditorViewport::scale_cursor_distance(real_t scale) {
2222 
2223 	// Prevents zero distance which would short-circuit any scaling
2224 	if (cursor.distance < ZOOM_MIN_DISTANCE)
2225 		cursor.distance = ZOOM_MIN_DISTANCE;
2226 
2227 	cursor.distance *= scale;
2228 
2229 	if (cursor.distance < ZOOM_MIN_DISTANCE)
2230 		cursor.distance = ZOOM_MIN_DISTANCE;
2231 
2232 	zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S;
2233 	surface->update();
2234 }
2235 
scale_freelook_speed(real_t scale)2236 void SpatialEditorViewport::scale_freelook_speed(real_t scale) {
2237 
2238 	// Prevents zero distance which would short-circuit any scaling
2239 	if (freelook_speed < FREELOOK_MIN_SPEED)
2240 		freelook_speed = FREELOOK_MIN_SPEED;
2241 
2242 	freelook_speed *= scale;
2243 
2244 	if (freelook_speed < FREELOOK_MIN_SPEED)
2245 		freelook_speed = FREELOOK_MIN_SPEED;
2246 
2247 	zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S;
2248 	surface->update();
2249 }
2250 
_get_warped_mouse_motion(const Ref<InputEventMouseMotion> & p_ev_mouse_motion) const2251 Point2i SpatialEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const {
2252 	Point2i relative;
2253 	if (bool(EDITOR_DEF("editors/3d/navigation/warped_mouse_panning", false))) {
2254 		relative = Input::get_singleton()->warp_mouse_motion(p_ev_mouse_motion, surface->get_global_rect());
2255 	} else {
2256 		relative = p_ev_mouse_motion->get_relative();
2257 	}
2258 	return relative;
2259 }
2260 
is_shortcut_pressed(const String & p_path)2261 static bool is_shortcut_pressed(const String &p_path) {
2262 	Ref<ShortCut> shortcut = ED_GET_SHORTCUT(p_path);
2263 	if (shortcut.is_null()) {
2264 		return false;
2265 	}
2266 	InputEventKey *k = Object::cast_to<InputEventKey>(shortcut->get_shortcut().ptr());
2267 	if (k == NULL) {
2268 		return false;
2269 	}
2270 	const Input &input = *Input::get_singleton();
2271 	int scancode = k->get_scancode();
2272 	return input.is_key_pressed(scancode);
2273 }
2274 
_update_freelook(real_t delta)2275 void SpatialEditorViewport::_update_freelook(real_t delta) {
2276 
2277 	if (!is_freelook_active()) {
2278 		return;
2279 	}
2280 
2281 	const FreelookNavigationScheme navigation_scheme = (FreelookNavigationScheme)EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_navigation_scheme").operator int();
2282 
2283 	Vector3 forward;
2284 	if (navigation_scheme == FREELOOK_FULLY_AXIS_LOCKED) {
2285 		// Forward/backward keys will always go straight forward/backward, never moving on the Y axis.
2286 		forward = Vector3(0, 0, -1).rotated(Vector3(0, 1, 0), camera->get_rotation().y);
2287 	} else {
2288 		// Forward/backward keys will be relative to the camera pitch.
2289 		forward = camera->get_transform().basis.xform(Vector3(0, 0, -1));
2290 	}
2291 
2292 	const Vector3 right = camera->get_transform().basis.xform(Vector3(1, 0, 0));
2293 
2294 	Vector3 up;
2295 	if (navigation_scheme == FREELOOK_PARTIALLY_AXIS_LOCKED || navigation_scheme == FREELOOK_FULLY_AXIS_LOCKED) {
2296 		// Up/down keys will always go up/down regardless of camera pitch.
2297 		up = Vector3(0, 1, 0);
2298 	} else {
2299 		// Up/down keys will be relative to the camera pitch.
2300 		up = camera->get_transform().basis.xform(Vector3(0, 1, 0));
2301 	}
2302 
2303 	Vector3 direction;
2304 
2305 	if (is_shortcut_pressed("spatial_editor/freelook_left")) {
2306 		direction -= right;
2307 	}
2308 	if (is_shortcut_pressed("spatial_editor/freelook_right")) {
2309 		direction += right;
2310 	}
2311 	if (is_shortcut_pressed("spatial_editor/freelook_forward")) {
2312 		direction += forward;
2313 	}
2314 	if (is_shortcut_pressed("spatial_editor/freelook_backwards")) {
2315 		direction -= forward;
2316 	}
2317 	if (is_shortcut_pressed("spatial_editor/freelook_up")) {
2318 		direction += up;
2319 	}
2320 	if (is_shortcut_pressed("spatial_editor/freelook_down")) {
2321 		direction -= up;
2322 	}
2323 
2324 	real_t speed = freelook_speed;
2325 
2326 	if (is_shortcut_pressed("spatial_editor/freelook_speed_modifier")) {
2327 		speed *= 3.0;
2328 	}
2329 	if (is_shortcut_pressed("spatial_editor/freelook_slow_modifier")) {
2330 		speed *= 0.333333;
2331 	}
2332 
2333 	const Vector3 motion = direction * speed * delta;
2334 	cursor.pos += motion;
2335 	cursor.eye_pos += motion;
2336 }
2337 
set_message(String p_message,float p_time)2338 void SpatialEditorViewport::set_message(String p_message, float p_time) {
2339 
2340 	message = p_message;
2341 	message_time = p_time;
2342 }
2343 
edited_scene_changed()2344 void SpatialEditorPlugin::edited_scene_changed() {
2345 	for (uint32_t i = 0; i < SpatialEditor::VIEWPORTS_COUNT; i++) {
2346 		SpatialEditorViewport *viewport = SpatialEditor::get_singleton()->get_editor_viewport(i);
2347 		if (viewport->is_visible()) {
2348 			viewport->notification(Control::NOTIFICATION_VISIBILITY_CHANGED);
2349 		}
2350 	}
2351 }
2352 
_notification(int p_what)2353 void SpatialEditorViewport::_notification(int p_what) {
2354 
2355 	if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
2356 
2357 		bool visible = is_visible_in_tree();
2358 
2359 		set_process(visible);
2360 
2361 		if (visible) {
2362 			orthogonal = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL));
2363 			_update_name();
2364 			_update_camera(0);
2365 		} else {
2366 			set_freelook_active(false);
2367 		}
2368 		call_deferred("update_transform_gizmo_view");
2369 		rotation_control->set_visible(EditorSettings::get_singleton()->get("editors/3d/navigation/show_viewport_rotation_gizmo"));
2370 	}
2371 
2372 	if (p_what == NOTIFICATION_RESIZED) {
2373 
2374 		call_deferred("update_transform_gizmo_view");
2375 	}
2376 
2377 	if (p_what == NOTIFICATION_PROCESS) {
2378 
2379 		real_t delta = get_process_delta_time();
2380 
2381 		if (zoom_indicator_delay > 0) {
2382 			zoom_indicator_delay -= delta;
2383 			if (zoom_indicator_delay <= 0) {
2384 				surface->update();
2385 			}
2386 		}
2387 
2388 		_update_freelook(delta);
2389 
2390 		Node *scene_root = editor->get_scene_tree_dock()->get_editor_data()->get_edited_scene_root();
2391 		if (previewing_cinema && scene_root != NULL) {
2392 			Camera *cam = scene_root->get_viewport()->get_camera();
2393 			if (cam != NULL && cam != previewing) {
2394 				//then switch the viewport's camera to the scene's viewport camera
2395 				if (previewing != NULL) {
2396 					previewing->disconnect("tree_exited", this, "_preview_exited_scene");
2397 				}
2398 				previewing = cam;
2399 				previewing->connect("tree_exited", this, "_preview_exited_scene");
2400 				VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), cam->get_camera());
2401 				surface->update();
2402 			}
2403 		}
2404 
2405 		_update_camera(delta);
2406 
2407 		Map<Node *, Object *> &selection = editor_selection->get_selection();
2408 
2409 		bool changed = false;
2410 		bool exist = false;
2411 
2412 		for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
2413 
2414 			Spatial *sp = Object::cast_to<Spatial>(E->key());
2415 			if (!sp)
2416 				continue;
2417 
2418 			SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
2419 			if (!se)
2420 				continue;
2421 
2422 			Transform t = sp->get_global_gizmo_transform();
2423 
2424 			exist = true;
2425 			if (se->last_xform == t && !se->last_xform_dirty)
2426 				continue;
2427 			changed = true;
2428 			se->last_xform_dirty = false;
2429 			se->last_xform = t;
2430 
2431 			VisualInstance *vi = Object::cast_to<VisualInstance>(sp);
2432 
2433 			se->aabb = vi ? vi->get_aabb() : _calculate_spatial_bounds(sp);
2434 
2435 			t.translate(se->aabb.position);
2436 
2437 			// apply AABB scaling before item's global transform
2438 			Basis aabb_s;
2439 			aabb_s.scale(se->aabb.size);
2440 			t.basis = t.basis * aabb_s;
2441 
2442 			VisualServer::get_singleton()->instance_set_transform(se->sbox_instance, t);
2443 		}
2444 
2445 		if (changed || (spatial_editor->is_gizmo_visible() && !exist)) {
2446 			spatial_editor->update_transform_gizmo();
2447 		}
2448 
2449 		if (message_time > 0) {
2450 
2451 			if (message != last_message) {
2452 				surface->update();
2453 				last_message = message;
2454 			}
2455 
2456 			message_time -= get_physics_process_delta_time();
2457 			if (message_time < 0)
2458 				surface->update();
2459 		}
2460 
2461 		//update shadow atlas if changed
2462 
2463 		int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/size");
2464 		int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_0_subdiv");
2465 		int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_1_subdiv");
2466 		int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_2_subdiv");
2467 		int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/quality/shadow_atlas/quadrant_3_subdiv");
2468 
2469 		viewport->set_shadow_atlas_size(shadowmap_size);
2470 		viewport->set_shadow_atlas_quadrant_subdiv(0, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0));
2471 		viewport->set_shadow_atlas_quadrant_subdiv(1, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q1));
2472 		viewport->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2));
2473 		viewport->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3));
2474 
2475 		bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION));
2476 
2477 		if (shrink != (viewport_container->get_stretch_shrink() > 1)) {
2478 			viewport_container->set_stretch_shrink(shrink ? 2 : 1);
2479 		}
2480 
2481 		//update msaa if changed
2482 
2483 		int msaa_mode = ProjectSettings::get_singleton()->get("rendering/quality/filters/msaa");
2484 		viewport->set_msaa(Viewport::MSAA(msaa_mode));
2485 
2486 		bool hdr = ProjectSettings::get_singleton()->get("rendering/quality/depth/hdr");
2487 		viewport->set_hdr(hdr);
2488 
2489 		bool show_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
2490 		info_label->set_visible(show_info);
2491 
2492 		Camera *current_camera;
2493 
2494 		if (previewing) {
2495 			current_camera = previewing;
2496 		} else {
2497 			current_camera = camera;
2498 		}
2499 
2500 		if (show_info) {
2501 			String text;
2502 			text += "X: " + rtos(current_camera->get_translation().x).pad_decimals(1) + "\n";
2503 			text += "Y: " + rtos(current_camera->get_translation().y).pad_decimals(1) + "\n";
2504 			text += "Z: " + rtos(current_camera->get_translation().z).pad_decimals(1) + "\n";
2505 			text += TTR("Pitch") + ": " + itos(Math::round(current_camera->get_rotation_degrees().x)) + "\n";
2506 			text += TTR("Yaw") + ": " + itos(Math::round(current_camera->get_rotation_degrees().y)) + "\n\n";
2507 			text += TTR("Objects Drawn") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_OBJECTS_IN_FRAME)) + "\n";
2508 			text += TTR("Material Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_MATERIAL_CHANGES_IN_FRAME)) + "\n";
2509 			text += TTR("Shader Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SHADER_CHANGES_IN_FRAME)) + "\n";
2510 			text += TTR("Surface Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SURFACE_CHANGES_IN_FRAME)) + "\n";
2511 			text += TTR("Draw Calls") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME)) + "\n";
2512 			text += TTR("Vertices") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_VERTICES_IN_FRAME));
2513 			info_label->set_text(text);
2514 		}
2515 
2516 		// FPS Counter.
2517 		bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS));
2518 		fps_label->set_visible(show_fps);
2519 
2520 		if (show_fps) {
2521 			String text;
2522 			const float temp_fps = Engine::get_singleton()->get_frames_per_second();
2523 			text += TTR(vformat("FPS: %d (%s ms)", temp_fps, String::num(1000.0f / temp_fps, 2)));
2524 			fps_label->set_text(text);
2525 		}
2526 
2527 		bool show_cinema = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
2528 		cinema_label->set_visible(show_cinema);
2529 		if (show_cinema) {
2530 			float cinema_half_width = cinema_label->get_size().width / 2.0f;
2531 			cinema_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -cinema_half_width);
2532 		}
2533 
2534 		if (lock_rotation) {
2535 			float locked_half_width = locked_label->get_size().width / 2.0f;
2536 			locked_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -locked_half_width);
2537 		}
2538 	}
2539 
2540 	if (p_what == NOTIFICATION_ENTER_TREE) {
2541 
2542 		surface->connect("draw", this, "_draw");
2543 		surface->connect("gui_input", this, "_sinput");
2544 		surface->connect("mouse_entered", this, "_surface_mouse_enter");
2545 		surface->connect("mouse_exited", this, "_surface_mouse_exit");
2546 		surface->connect("focus_entered", this, "_surface_focus_enter");
2547 		surface->connect("focus_exited", this, "_surface_focus_exit");
2548 
2549 		_init_gizmo_instance(index);
2550 	}
2551 
2552 	if (p_what == NOTIFICATION_EXIT_TREE) {
2553 
2554 		_finish_gizmo_instances();
2555 	}
2556 
2557 	if (p_what == NOTIFICATION_THEME_CHANGED) {
2558 
2559 		view_menu->set_icon(get_icon("GuiTabMenuHl", "EditorIcons"));
2560 		preview_camera->set_icon(get_icon("Camera", "EditorIcons"));
2561 
2562 		view_menu->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2563 		view_menu->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2564 		view_menu->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2565 		view_menu->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2566 		view_menu->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2567 
2568 		preview_camera->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2569 		preview_camera->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2570 		preview_camera->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2571 		preview_camera->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2572 		preview_camera->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2573 
2574 		info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2575 		fps_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2576 		cinema_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2577 		locked_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
2578 	}
2579 }
2580 
draw_indicator_bar(Control & surface,real_t fill,const Ref<Texture> icon,const Ref<Font> font,const String & text)2581 static void draw_indicator_bar(Control &surface, real_t fill, const Ref<Texture> icon, const Ref<Font> font, const String &text) {
2582 	// Adjust bar size from control height
2583 	const Vector2 surface_size = surface.get_size();
2584 	const real_t h = surface_size.y / 2.0;
2585 	const real_t y = (surface_size.y - h) / 2.0;
2586 
2587 	const Rect2 r(10 * EDSCALE, y, 6 * EDSCALE, h);
2588 	const real_t sy = r.size.y * fill;
2589 
2590 	// Note: because this bar appears over the viewport, it has to stay readable for any background color
2591 	// Draw both neutral dark and bright colors to account this
2592 	surface.draw_rect(r, Color(1, 1, 1, 0.2));
2593 	surface.draw_rect(Rect2(r.position.x, r.position.y + r.size.y - sy, r.size.x, sy), Color(1, 1, 1, 0.6));
2594 	surface.draw_rect(r.grow(1), Color(0, 0, 0, 0.7), false, Math::round(EDSCALE));
2595 
2596 	const Vector2 icon_size = icon->get_size();
2597 	const Vector2 icon_pos = Vector2(r.position.x - (icon_size.x - r.size.x) / 2, r.position.y + r.size.y + 2 * EDSCALE);
2598 	surface.draw_texture(icon, icon_pos);
2599 
2600 	// Draw text below the bar (for speed/zoom information).
2601 	surface.draw_string(font, Vector2(icon_pos.x, icon_pos.y + icon_size.y + 16 * EDSCALE), text);
2602 }
2603 
_draw()2604 void SpatialEditorViewport::_draw() {
2605 
2606 	EditorPluginList *over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_over();
2607 	if (!over_plugin_list->empty()) {
2608 		over_plugin_list->forward_spatial_draw_over_viewport(surface);
2609 	}
2610 
2611 	EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over();
2612 	if (!force_over_plugin_list->empty()) {
2613 		force_over_plugin_list->forward_spatial_force_draw_over_viewport(surface);
2614 	}
2615 
2616 	if (surface->has_focus()) {
2617 		Size2 size = surface->get_size();
2618 		Rect2 r = Rect2(Point2(), size);
2619 		get_stylebox("Focus", "EditorStyles")->draw(surface->get_canvas_item(), r);
2620 	}
2621 
2622 	if (cursor.region_select) {
2623 		const Rect2 selection_rect = Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin);
2624 
2625 		surface->draw_rect(
2626 				selection_rect,
2627 				get_color("box_selection_fill_color", "Editor"));
2628 
2629 		surface->draw_rect(
2630 				selection_rect,
2631 				get_color("box_selection_stroke_color", "Editor"),
2632 				false,
2633 				Math::round(EDSCALE));
2634 	}
2635 
2636 	RID ci = surface->get_canvas_item();
2637 
2638 	if (message_time > 0) {
2639 		Ref<Font> font = get_font("font", "Label");
2640 		Point2 msgpos = Point2(5, get_size().y - 20);
2641 		font->draw(ci, msgpos + Point2(1, 1), message, Color(0, 0, 0, 0.8));
2642 		font->draw(ci, msgpos + Point2(-1, -1), message, Color(0, 0, 0, 0.8));
2643 		font->draw(ci, msgpos, message, Color(1, 1, 1, 1));
2644 	}
2645 
2646 	if (_edit.mode == TRANSFORM_ROTATE) {
2647 
2648 		Point2 center = _point_to_screen(_edit.center);
2649 		VisualServer::get_singleton()->canvas_item_add_line(
2650 				ci,
2651 				_edit.mouse_pos,
2652 				center,
2653 				get_color("accent_color", "Editor") * Color(1, 1, 1, 0.6),
2654 				Math::round(2 * EDSCALE),
2655 				true);
2656 	}
2657 	if (previewing) {
2658 
2659 		Size2 ss = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
2660 		float aspect = ss.aspect();
2661 		Size2 s = get_size();
2662 
2663 		Rect2 draw_rect;
2664 
2665 		switch (previewing->get_keep_aspect_mode()) {
2666 			case Camera::KEEP_WIDTH: {
2667 
2668 				draw_rect.size = Size2(s.width, s.width / aspect);
2669 				draw_rect.position.x = 0;
2670 				draw_rect.position.y = (s.height - draw_rect.size.y) * 0.5;
2671 
2672 			} break;
2673 			case Camera::KEEP_HEIGHT: {
2674 
2675 				draw_rect.size = Size2(s.height * aspect, s.height);
2676 				draw_rect.position.y = 0;
2677 				draw_rect.position.x = (s.width - draw_rect.size.x) * 0.5;
2678 
2679 			} break;
2680 		}
2681 
2682 		draw_rect = Rect2(Vector2(), s).clip(draw_rect);
2683 
2684 		surface->draw_rect(draw_rect, Color(0.6, 0.6, 0.1, 0.5), false, Math::round(2 * EDSCALE));
2685 
2686 	} else {
2687 
2688 		if (zoom_indicator_delay > 0.0) {
2689 
2690 			if (is_freelook_active()) {
2691 				// Show speed
2692 
2693 				real_t min_speed = FREELOOK_MIN_SPEED;
2694 				real_t max_speed = camera->get_zfar();
2695 				real_t scale_length = (max_speed - min_speed);
2696 
2697 				if (!Math::is_zero_approx(scale_length)) {
2698 					real_t logscale_t = 1.0 - Math::log(1 + freelook_speed - min_speed) / Math::log(1 + scale_length);
2699 
2700 					// There is no real maximum speed so that factor can become negative,
2701 					// Let's make it look asymptotic instead (will decrease slower and slower).
2702 					if (logscale_t < 0.25)
2703 						logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0);
2704 
2705 					// Display the freelook speed to help the user get a better sense of scale.
2706 					const int precision = freelook_speed < 1.0 ? 2 : 1;
2707 					draw_indicator_bar(
2708 							*surface,
2709 							1.0 - logscale_t,
2710 							get_icon("ViewportSpeed", "EditorIcons"),
2711 							get_font("font", "Label"),
2712 							vformat("%s u/s", String::num(freelook_speed).pad_decimals(precision)));
2713 				}
2714 
2715 			} else {
2716 				// Show zoom
2717 
2718 				real_t min_distance = ZOOM_MIN_DISTANCE; // TODO Why not pick znear to limit zoom?
2719 				real_t max_distance = camera->get_zfar();
2720 				real_t scale_length = (max_distance - min_distance);
2721 
2722 				if (!Math::is_zero_approx(scale_length)) {
2723 					real_t logscale_t = 1.0 - Math::log(1 + cursor.distance - min_distance) / Math::log(1 + scale_length);
2724 
2725 					// There is no real maximum distance so that factor can become negative,
2726 					// Let's make it look asymptotic instead (will decrease slower and slower).
2727 					if (logscale_t < 0.25)
2728 						logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0);
2729 
2730 					// Display the zoom center distance to help the user get a better sense of scale.
2731 					const int precision = cursor.distance < 1.0 ? 2 : 1;
2732 					draw_indicator_bar(
2733 							*surface,
2734 							logscale_t,
2735 							get_icon("ViewportZoom", "EditorIcons"),
2736 							get_font("font", "Label"),
2737 							vformat("%s u", String::num(cursor.distance).pad_decimals(precision)));
2738 				}
2739 			}
2740 		}
2741 	}
2742 }
2743 
_menu_option(int p_option)2744 void SpatialEditorViewport::_menu_option(int p_option) {
2745 
2746 	switch (p_option) {
2747 
2748 		case VIEW_TOP: {
2749 
2750 			cursor.y_rot = 0;
2751 			cursor.x_rot = Math_PI / 2.0;
2752 			set_message(TTR("Top View."), 2);
2753 			name = TTR("Top");
2754 			_set_auto_orthogonal();
2755 			_update_name();
2756 
2757 		} break;
2758 		case VIEW_BOTTOM: {
2759 
2760 			cursor.y_rot = 0;
2761 			cursor.x_rot = -Math_PI / 2.0;
2762 			set_message(TTR("Bottom View."), 2);
2763 			name = TTR("Bottom");
2764 			_set_auto_orthogonal();
2765 			_update_name();
2766 
2767 		} break;
2768 		case VIEW_LEFT: {
2769 
2770 			cursor.x_rot = 0;
2771 			cursor.y_rot = Math_PI / 2.0;
2772 			set_message(TTR("Left View."), 2);
2773 			name = TTR("Left");
2774 			_set_auto_orthogonal();
2775 			_update_name();
2776 
2777 		} break;
2778 		case VIEW_RIGHT: {
2779 
2780 			cursor.x_rot = 0;
2781 			cursor.y_rot = -Math_PI / 2.0;
2782 			set_message(TTR("Right View."), 2);
2783 			name = TTR("Right");
2784 			_set_auto_orthogonal();
2785 			_update_name();
2786 
2787 		} break;
2788 		case VIEW_FRONT: {
2789 
2790 			cursor.x_rot = 0;
2791 			cursor.y_rot = 0;
2792 			set_message(TTR("Front View."), 2);
2793 			name = TTR("Front");
2794 			_set_auto_orthogonal();
2795 			_update_name();
2796 
2797 		} break;
2798 		case VIEW_REAR: {
2799 
2800 			cursor.x_rot = 0;
2801 			cursor.y_rot = Math_PI;
2802 			set_message(TTR("Rear View."), 2);
2803 			name = TTR("Rear");
2804 			_set_auto_orthogonal();
2805 			_update_name();
2806 
2807 		} break;
2808 		case VIEW_CENTER_TO_ORIGIN: {
2809 
2810 			cursor.pos = Vector3(0, 0, 0);
2811 
2812 		} break;
2813 		case VIEW_CENTER_TO_SELECTION: {
2814 
2815 			focus_selection();
2816 
2817 		} break;
2818 		case VIEW_ALIGN_TRANSFORM_WITH_VIEW: {
2819 
2820 			if (!get_selected_count())
2821 				break;
2822 
2823 			Transform camera_transform = camera->get_global_transform();
2824 
2825 			List<Node *> &selection = editor_selection->get_selected_node_list();
2826 
2827 			undo_redo->create_action(TTR("Align Transform with View"));
2828 
2829 			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
2830 
2831 				Spatial *sp = Object::cast_to<Spatial>(E->get());
2832 				if (!sp)
2833 					continue;
2834 
2835 				SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
2836 				if (!se)
2837 					continue;
2838 
2839 				Transform xform;
2840 				if (orthogonal) {
2841 					xform = sp->get_global_transform();
2842 					xform.basis.set_euler(camera_transform.basis.get_euler());
2843 				} else {
2844 					xform = camera_transform;
2845 					xform.scale_basis(sp->get_scale());
2846 				}
2847 
2848 				undo_redo->add_do_method(sp, "set_global_transform", xform);
2849 				undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
2850 			}
2851 			undo_redo->commit_action();
2852 
2853 		} break;
2854 		case VIEW_ALIGN_ROTATION_WITH_VIEW: {
2855 
2856 			if (!get_selected_count())
2857 				break;
2858 
2859 			Transform camera_transform = camera->get_global_transform();
2860 
2861 			List<Node *> &selection = editor_selection->get_selected_node_list();
2862 
2863 			undo_redo->create_action(TTR("Align Rotation with View"));
2864 			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
2865 
2866 				Spatial *sp = Object::cast_to<Spatial>(E->get());
2867 				if (!sp)
2868 					continue;
2869 
2870 				SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
2871 				if (!se)
2872 					continue;
2873 
2874 				undo_redo->add_do_method(sp, "set_rotation", camera_transform.basis.get_rotation());
2875 				undo_redo->add_undo_method(sp, "set_rotation", sp->get_rotation());
2876 			}
2877 			undo_redo->commit_action();
2878 
2879 		} break;
2880 		case VIEW_ENVIRONMENT: {
2881 
2882 			int idx = view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT);
2883 			bool current = view_menu->get_popup()->is_item_checked(idx);
2884 			current = !current;
2885 			if (current) {
2886 
2887 				camera->set_environment(RES());
2888 			} else {
2889 
2890 				camera->set_environment(SpatialEditor::get_singleton()->get_viewport_environment());
2891 			}
2892 
2893 			view_menu->get_popup()->set_item_checked(idx, current);
2894 
2895 		} break;
2896 		case VIEW_PERSPECTIVE: {
2897 
2898 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true);
2899 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), false);
2900 			orthogonal = false;
2901 			auto_orthogonal = false;
2902 			call_deferred("update_transform_gizmo_view");
2903 			_update_name();
2904 
2905 		} break;
2906 		case VIEW_ORTHOGONAL: {
2907 
2908 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), false);
2909 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), true);
2910 			orthogonal = true;
2911 			auto_orthogonal = false;
2912 			call_deferred("update_transform_gizmo_view");
2913 			_update_name();
2914 
2915 		} break;
2916 		case VIEW_AUTO_ORTHOGONAL: {
2917 
2918 			int idx = view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL);
2919 			bool current = view_menu->get_popup()->is_item_checked(idx);
2920 			current = !current;
2921 			view_menu->get_popup()->set_item_checked(idx, current);
2922 			if (auto_orthogonal) {
2923 				auto_orthogonal = false;
2924 				_update_name();
2925 			}
2926 		} break;
2927 		case VIEW_LOCK_ROTATION: {
2928 
2929 			int idx = view_menu->get_popup()->get_item_index(VIEW_LOCK_ROTATION);
2930 			bool current = view_menu->get_popup()->is_item_checked(idx);
2931 			lock_rotation = !current;
2932 			view_menu->get_popup()->set_item_checked(idx, !current);
2933 			if (lock_rotation) {
2934 				locked_label->show();
2935 			} else {
2936 				locked_label->hide();
2937 			}
2938 
2939 		} break;
2940 		case VIEW_AUDIO_LISTENER: {
2941 
2942 			int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
2943 			bool current = view_menu->get_popup()->is_item_checked(idx);
2944 			current = !current;
2945 			viewport->set_as_audio_listener(current);
2946 			view_menu->get_popup()->set_item_checked(idx, current);
2947 
2948 		} break;
2949 		case VIEW_AUDIO_DOPPLER: {
2950 
2951 			int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER);
2952 			bool current = view_menu->get_popup()->is_item_checked(idx);
2953 			current = !current;
2954 			camera->set_doppler_tracking(current ? Camera::DOPPLER_TRACKING_IDLE_STEP : Camera::DOPPLER_TRACKING_DISABLED);
2955 			view_menu->get_popup()->set_item_checked(idx, current);
2956 
2957 		} break;
2958 		case VIEW_CINEMATIC_PREVIEW: {
2959 
2960 			int idx = view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW);
2961 			bool current = view_menu->get_popup()->is_item_checked(idx);
2962 			current = !current;
2963 			view_menu->get_popup()->set_item_checked(idx, current);
2964 			previewing_cinema = true;
2965 			_toggle_cinema_preview(current);
2966 
2967 			if (current) {
2968 				preview_camera->hide();
2969 			} else {
2970 				if (previewing != NULL)
2971 					preview_camera->show();
2972 			}
2973 		} break;
2974 		case VIEW_GIZMOS: {
2975 
2976 			int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
2977 			bool current = view_menu->get_popup()->is_item_checked(idx);
2978 			current = !current;
2979 			if (current)
2980 				camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER));
2981 			else
2982 				camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + index)) | (1 << GIZMO_GRID_LAYER));
2983 			view_menu->get_popup()->set_item_checked(idx, current);
2984 
2985 		} break;
2986 		case VIEW_HALF_RESOLUTION: {
2987 
2988 			int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION);
2989 			bool current = view_menu->get_popup()->is_item_checked(idx);
2990 			current = !current;
2991 			view_menu->get_popup()->set_item_checked(idx, current);
2992 		} break;
2993 		case VIEW_INFORMATION: {
2994 
2995 			int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION);
2996 			bool current = view_menu->get_popup()->is_item_checked(idx);
2997 			view_menu->get_popup()->set_item_checked(idx, !current);
2998 
2999 		} break;
3000 		case VIEW_FPS: {
3001 
3002 			int idx = view_menu->get_popup()->get_item_index(VIEW_FPS);
3003 			bool current = view_menu->get_popup()->is_item_checked(idx);
3004 			view_menu->get_popup()->set_item_checked(idx, !current);
3005 
3006 		} break;
3007 		case VIEW_DISPLAY_NORMAL: {
3008 
3009 			viewport->set_debug_draw(Viewport::DEBUG_DRAW_DISABLED);
3010 
3011 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), true);
3012 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), false);
3013 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), false);
3014 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), false);
3015 		} break;
3016 		case VIEW_DISPLAY_WIREFRAME: {
3017 
3018 			viewport->set_debug_draw(Viewport::DEBUG_DRAW_WIREFRAME);
3019 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), false);
3020 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), true);
3021 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), false);
3022 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), false);
3023 
3024 		} break;
3025 		case VIEW_DISPLAY_OVERDRAW: {
3026 
3027 			viewport->set_debug_draw(Viewport::DEBUG_DRAW_OVERDRAW);
3028 			VisualServer::get_singleton()->scenario_set_debug(get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_OVERDRAW);
3029 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), false);
3030 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), false);
3031 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), true);
3032 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), false);
3033 
3034 		} break;
3035 		case VIEW_DISPLAY_SHADELESS: {
3036 
3037 			viewport->set_debug_draw(Viewport::DEBUG_DRAW_UNSHADED);
3038 			VisualServer::get_singleton()->scenario_set_debug(get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_SHADELESS);
3039 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), false);
3040 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME), false);
3041 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW), false);
3042 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS), true);
3043 
3044 		} break;
3045 	}
3046 }
3047 
_set_auto_orthogonal()3048 void SpatialEditorViewport::_set_auto_orthogonal() {
3049 	if (!orthogonal && view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL))) {
3050 		_menu_option(VIEW_ORTHOGONAL);
3051 		auto_orthogonal = true;
3052 	}
3053 }
3054 
_preview_exited_scene()3055 void SpatialEditorViewport::_preview_exited_scene() {
3056 
3057 	preview_camera->disconnect("toggled", this, "_toggle_camera_preview");
3058 	preview_camera->set_pressed(false);
3059 	_toggle_camera_preview(false);
3060 	preview_camera->connect("toggled", this, "_toggle_camera_preview");
3061 	view_menu->show();
3062 }
3063 
_init_gizmo_instance(int p_idx)3064 void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
3065 
3066 	uint32_t layer = 1 << (GIZMO_BASE_LAYER + p_idx);
3067 
3068 	for (int i = 0; i < 3; i++) {
3069 		move_gizmo_instance[i] = VS::get_singleton()->instance_create();
3070 		VS::get_singleton()->instance_set_base(move_gizmo_instance[i], spatial_editor->get_move_gizmo(i)->get_rid());
3071 		VS::get_singleton()->instance_set_scenario(move_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
3072 		VS::get_singleton()->instance_set_visible(move_gizmo_instance[i], false);
3073 		VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
3074 		VS::get_singleton()->instance_set_layer_mask(move_gizmo_instance[i], layer);
3075 
3076 		move_plane_gizmo_instance[i] = VS::get_singleton()->instance_create();
3077 		VS::get_singleton()->instance_set_base(move_plane_gizmo_instance[i], spatial_editor->get_move_plane_gizmo(i)->get_rid());
3078 		VS::get_singleton()->instance_set_scenario(move_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
3079 		VS::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false);
3080 		VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
3081 		VS::get_singleton()->instance_set_layer_mask(move_plane_gizmo_instance[i], layer);
3082 
3083 		rotate_gizmo_instance[i] = VS::get_singleton()->instance_create();
3084 		VS::get_singleton()->instance_set_base(rotate_gizmo_instance[i], spatial_editor->get_rotate_gizmo(i)->get_rid());
3085 		VS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
3086 		VS::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
3087 		VS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
3088 		VS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer);
3089 
3090 		scale_gizmo_instance[i] = VS::get_singleton()->instance_create();
3091 		VS::get_singleton()->instance_set_base(scale_gizmo_instance[i], spatial_editor->get_scale_gizmo(i)->get_rid());
3092 		VS::get_singleton()->instance_set_scenario(scale_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
3093 		VS::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
3094 		VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
3095 		VS::get_singleton()->instance_set_layer_mask(scale_gizmo_instance[i], layer);
3096 
3097 		scale_plane_gizmo_instance[i] = VS::get_singleton()->instance_create();
3098 		VS::get_singleton()->instance_set_base(scale_plane_gizmo_instance[i], spatial_editor->get_scale_plane_gizmo(i)->get_rid());
3099 		VS::get_singleton()->instance_set_scenario(scale_plane_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
3100 		VS::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
3101 		VS::get_singleton()->instance_geometry_set_cast_shadows_setting(scale_plane_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
3102 		VS::get_singleton()->instance_set_layer_mask(scale_plane_gizmo_instance[i], layer);
3103 	}
3104 }
3105 
_finish_gizmo_instances()3106 void SpatialEditorViewport::_finish_gizmo_instances() {
3107 
3108 	for (int i = 0; i < 3; i++) {
3109 		VS::get_singleton()->free(move_gizmo_instance[i]);
3110 		VS::get_singleton()->free(move_plane_gizmo_instance[i]);
3111 		VS::get_singleton()->free(rotate_gizmo_instance[i]);
3112 		VS::get_singleton()->free(scale_gizmo_instance[i]);
3113 		VS::get_singleton()->free(scale_plane_gizmo_instance[i]);
3114 	}
3115 }
_toggle_camera_preview(bool p_activate)3116 void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
3117 
3118 	ERR_FAIL_COND(p_activate && !preview);
3119 	ERR_FAIL_COND(!p_activate && !previewing);
3120 
3121 	rotation_control->set_visible(!p_activate);
3122 
3123 	if (!p_activate) {
3124 
3125 		previewing->disconnect("tree_exiting", this, "_preview_exited_scene");
3126 		previewing = NULL;
3127 		VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore
3128 		if (!preview)
3129 			preview_camera->hide();
3130 		view_menu->set_disabled(false);
3131 		surface->update();
3132 
3133 	} else {
3134 
3135 		previewing = preview;
3136 		previewing->connect("tree_exiting", this, "_preview_exited_scene");
3137 		VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace
3138 		view_menu->set_disabled(true);
3139 		surface->update();
3140 	}
3141 }
3142 
_toggle_cinema_preview(bool p_activate)3143 void SpatialEditorViewport::_toggle_cinema_preview(bool p_activate) {
3144 	previewing_cinema = p_activate;
3145 	if (!previewing_cinema) {
3146 		if (previewing != NULL)
3147 			previewing->disconnect("tree_exited", this, "_preview_exited_scene");
3148 
3149 		previewing = NULL;
3150 		VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore
3151 		preview_camera->set_pressed(false);
3152 		if (!preview) {
3153 			preview_camera->hide();
3154 		} else {
3155 			preview_camera->show();
3156 		}
3157 		view_menu->show();
3158 		surface->update();
3159 	}
3160 }
3161 
_selection_result_pressed(int p_result)3162 void SpatialEditorViewport::_selection_result_pressed(int p_result) {
3163 
3164 	if (selection_results.size() <= p_result)
3165 		return;
3166 
3167 	clicked = selection_results[p_result].item->get_instance_id();
3168 
3169 	if (clicked) {
3170 		_select_clicked(clicked_wants_append, true);
3171 		clicked = 0;
3172 	}
3173 }
3174 
_selection_menu_hide()3175 void SpatialEditorViewport::_selection_menu_hide() {
3176 
3177 	selection_results.clear();
3178 	selection_menu->clear();
3179 	selection_menu->set_size(Vector2(0, 0));
3180 }
3181 
set_can_preview(Camera * p_preview)3182 void SpatialEditorViewport::set_can_preview(Camera *p_preview) {
3183 
3184 	preview = p_preview;
3185 
3186 	if (!preview_camera->is_pressed() && !previewing_cinema)
3187 		preview_camera->set_visible(p_preview);
3188 }
3189 
update_transform_gizmo_view()3190 void SpatialEditorViewport::update_transform_gizmo_view() {
3191 
3192 	if (!is_visible_in_tree())
3193 		return;
3194 
3195 	Transform xform = spatial_editor->get_gizmo_transform();
3196 
3197 	Transform camera_xform = camera->get_transform();
3198 
3199 	if (xform.origin.distance_squared_to(camera_xform.origin) < 0.01) {
3200 		for (int i = 0; i < 3; i++) {
3201 			VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], false);
3202 			VisualServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], false);
3203 			VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], false);
3204 			VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], false);
3205 			VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], false);
3206 		}
3207 		return;
3208 	}
3209 
3210 	Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
3211 	Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
3212 	Plane p(camera_xform.origin, camz);
3213 	float gizmo_d = MAX(Math::abs(p.distance_to(xform.origin)), CMP_EPSILON);
3214 	float d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y;
3215 	float d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y;
3216 	float dd = Math::abs(d0 - d1);
3217 	if (dd == 0)
3218 		dd = 0.0001;
3219 
3220 	float gizmo_size = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size");
3221 	// At low viewport heights, multiply the gizmo scale based on the viewport height.
3222 	// This prevents the gizmo from growing very large and going outside the viewport.
3223 	const int viewport_base_height = 400 * MAX(1, EDSCALE);
3224 	gizmo_scale =
3225 			(gizmo_size / Math::abs(dd)) * MAX(1, EDSCALE) *
3226 			MIN(viewport_base_height, viewport_container->get_size().height) / viewport_base_height /
3227 			viewport_container->get_stretch_shrink();
3228 	Vector3 scale = Vector3(1, 1, 1) * gizmo_scale;
3229 
3230 	xform.basis.scale(scale);
3231 
3232 	for (int i = 0; i < 3; i++) {
3233 		VisualServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform);
3234 		VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE));
3235 		VisualServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], xform);
3236 		VisualServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE));
3237 		VisualServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform);
3238 		VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE));
3239 		VisualServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform);
3240 		VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE));
3241 		VisualServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform);
3242 		VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE));
3243 	}
3244 }
3245 
set_state(const Dictionary & p_state)3246 void SpatialEditorViewport::set_state(const Dictionary &p_state) {
3247 
3248 	if (p_state.has("position"))
3249 		cursor.pos = p_state["position"];
3250 	if (p_state.has("x_rotation"))
3251 		cursor.x_rot = p_state["x_rotation"];
3252 	if (p_state.has("y_rotation"))
3253 		cursor.y_rot = p_state["y_rotation"];
3254 	if (p_state.has("distance"))
3255 		cursor.distance = p_state["distance"];
3256 
3257 	if (p_state.has("use_orthogonal")) {
3258 		bool orth = p_state["use_orthogonal"];
3259 
3260 		if (orth)
3261 			_menu_option(VIEW_ORTHOGONAL);
3262 		else
3263 			_menu_option(VIEW_PERSPECTIVE);
3264 	}
3265 	if (p_state.has("view_name")) {
3266 		name = p_state["view_name"];
3267 		_update_name();
3268 	}
3269 	if (p_state.has("auto_orthogonal")) {
3270 		auto_orthogonal = p_state["auto_orthogonal"];
3271 		_update_name();
3272 	}
3273 	if (p_state.has("auto_orthogonal_enabled")) {
3274 		bool enabled = p_state["auto_orthogonal_enabled"];
3275 		view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL), enabled);
3276 	}
3277 	if (p_state.has("display_mode")) {
3278 		int display = p_state["display_mode"];
3279 
3280 		int idx = view_menu->get_popup()->get_item_index(display);
3281 		if (!view_menu->get_popup()->is_item_checked(idx))
3282 			_menu_option(display);
3283 	}
3284 	if (p_state.has("lock_rotation")) {
3285 		lock_rotation = p_state["lock_rotation"];
3286 
3287 		int idx = view_menu->get_popup()->get_item_index(VIEW_LOCK_ROTATION);
3288 		view_menu->get_popup()->set_item_checked(idx, lock_rotation);
3289 	}
3290 	if (p_state.has("use_environment")) {
3291 		bool env = p_state["use_environment"];
3292 
3293 		if (env != camera->get_environment().is_valid())
3294 			_menu_option(VIEW_ENVIRONMENT);
3295 	}
3296 	if (p_state.has("listener")) {
3297 		bool listener = p_state["listener"];
3298 
3299 		int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
3300 		viewport->set_as_audio_listener(listener);
3301 		view_menu->get_popup()->set_item_checked(idx, listener);
3302 	}
3303 	if (p_state.has("doppler")) {
3304 		bool doppler = p_state["doppler"];
3305 
3306 		int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER);
3307 		camera->set_doppler_tracking(doppler ? Camera::DOPPLER_TRACKING_IDLE_STEP : Camera::DOPPLER_TRACKING_DISABLED);
3308 		view_menu->get_popup()->set_item_checked(idx, doppler);
3309 	}
3310 	if (p_state.has("gizmos")) {
3311 		bool gizmos = p_state["gizmos"];
3312 
3313 		int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
3314 		if (view_menu->get_popup()->is_item_checked(idx) != gizmos)
3315 			_menu_option(VIEW_GIZMOS);
3316 	}
3317 	if (p_state.has("information")) {
3318 		bool information = p_state["information"];
3319 
3320 		int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION);
3321 		if (view_menu->get_popup()->is_item_checked(idx) != information)
3322 			_menu_option(VIEW_INFORMATION);
3323 	}
3324 	if (p_state.has("fps")) {
3325 		bool fps = p_state["fps"];
3326 
3327 		int idx = view_menu->get_popup()->get_item_index(VIEW_FPS);
3328 		if (view_menu->get_popup()->is_item_checked(idx) != fps)
3329 			_menu_option(VIEW_FPS);
3330 	}
3331 	if (p_state.has("half_res")) {
3332 		bool half_res = p_state["half_res"];
3333 
3334 		int idx = view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION);
3335 		view_menu->get_popup()->set_item_checked(idx, half_res);
3336 	}
3337 	if (p_state.has("cinematic_preview")) {
3338 		previewing_cinema = p_state["cinematic_preview"];
3339 
3340 		int idx = view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW);
3341 		view_menu->get_popup()->set_item_checked(idx, previewing_cinema);
3342 	}
3343 
3344 	if (preview_camera->is_connected("toggled", this, "_toggle_camera_preview")) {
3345 		preview_camera->disconnect("toggled", this, "_toggle_camera_preview");
3346 	}
3347 	if (p_state.has("previewing")) {
3348 		Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]);
3349 		if (Object::cast_to<Camera>(pv)) {
3350 			previewing = Object::cast_to<Camera>(pv);
3351 			previewing->connect("tree_exiting", this, "_preview_exited_scene");
3352 			VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace
3353 			view_menu->set_disabled(true);
3354 			surface->update();
3355 			preview_camera->set_pressed(true);
3356 			preview_camera->show();
3357 		}
3358 	}
3359 	preview_camera->connect("toggled", this, "_toggle_camera_preview");
3360 }
3361 
get_state() const3362 Dictionary SpatialEditorViewport::get_state() const {
3363 
3364 	Dictionary d;
3365 	d["position"] = cursor.pos;
3366 	d["x_rotation"] = cursor.x_rot;
3367 	d["y_rotation"] = cursor.y_rot;
3368 	d["distance"] = cursor.distance;
3369 	d["use_environment"] = camera->get_environment().is_valid();
3370 	d["use_orthogonal"] = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL;
3371 	d["view_name"] = name;
3372 	d["auto_orthogonal"] = auto_orthogonal;
3373 	d["auto_orthogonal_enabled"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL));
3374 	if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL)))
3375 		d["display_mode"] = VIEW_DISPLAY_NORMAL;
3376 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME)))
3377 		d["display_mode"] = VIEW_DISPLAY_WIREFRAME;
3378 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW)))
3379 		d["display_mode"] = VIEW_DISPLAY_OVERDRAW;
3380 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS)))
3381 		d["display_mode"] = VIEW_DISPLAY_SHADELESS;
3382 	d["listener"] = viewport->is_audio_listener();
3383 	d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER));
3384 	d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS));
3385 	d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
3386 	d["fps"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS));
3387 	d["half_res"] = viewport_container->get_stretch_shrink() > 1;
3388 	d["cinematic_preview"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
3389 	if (previewing)
3390 		d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing);
3391 	if (lock_rotation)
3392 		d["lock_rotation"] = lock_rotation;
3393 
3394 	return d;
3395 }
3396 
_bind_methods()3397 void SpatialEditorViewport::_bind_methods() {
3398 
3399 	ClassDB::bind_method(D_METHOD("_draw"), &SpatialEditorViewport::_draw);
3400 
3401 	ClassDB::bind_method(D_METHOD("_surface_mouse_enter"), &SpatialEditorViewport::_surface_mouse_enter);
3402 	ClassDB::bind_method(D_METHOD("_surface_mouse_exit"), &SpatialEditorViewport::_surface_mouse_exit);
3403 	ClassDB::bind_method(D_METHOD("_surface_focus_enter"), &SpatialEditorViewport::_surface_focus_enter);
3404 	ClassDB::bind_method(D_METHOD("_surface_focus_exit"), &SpatialEditorViewport::_surface_focus_exit);
3405 	ClassDB::bind_method(D_METHOD("_sinput"), &SpatialEditorViewport::_sinput);
3406 	ClassDB::bind_method(D_METHOD("_menu_option"), &SpatialEditorViewport::_menu_option);
3407 	ClassDB::bind_method(D_METHOD("_toggle_camera_preview"), &SpatialEditorViewport::_toggle_camera_preview);
3408 	ClassDB::bind_method(D_METHOD("_preview_exited_scene"), &SpatialEditorViewport::_preview_exited_scene);
3409 	ClassDB::bind_method(D_METHOD("_update_camera"), &SpatialEditorViewport::_update_camera);
3410 	ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &SpatialEditorViewport::update_transform_gizmo_view);
3411 	ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &SpatialEditorViewport::_selection_result_pressed);
3412 	ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &SpatialEditorViewport::_selection_menu_hide);
3413 	ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SpatialEditorViewport::can_drop_data_fw);
3414 	ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpatialEditorViewport::drop_data_fw);
3415 
3416 	ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
3417 	ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport")));
3418 }
3419 
reset()3420 void SpatialEditorViewport::reset() {
3421 
3422 	orthogonal = false;
3423 	auto_orthogonal = false;
3424 	lock_rotation = false;
3425 	message_time = 0;
3426 	message = "";
3427 	last_message = "";
3428 	name = "";
3429 
3430 	cursor = Cursor();
3431 	_update_name();
3432 }
3433 
focus_selection()3434 void SpatialEditorViewport::focus_selection() {
3435 	if (!get_selected_count())
3436 		return;
3437 
3438 	Vector3 center;
3439 	int count = 0;
3440 
3441 	List<Node *> &selection = editor_selection->get_selected_node_list();
3442 
3443 	for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
3444 
3445 		Spatial *sp = Object::cast_to<Spatial>(E->get());
3446 		if (!sp)
3447 			continue;
3448 
3449 		SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
3450 		if (!se)
3451 			continue;
3452 
3453 		center += sp->get_global_gizmo_transform().origin;
3454 		count++;
3455 	}
3456 
3457 	if (count != 0) {
3458 		center /= float(count);
3459 	}
3460 
3461 	cursor.pos = center;
3462 }
3463 
assign_pending_data_pointers(Spatial * p_preview_node,AABB * p_preview_bounds,AcceptDialog * p_accept)3464 void SpatialEditorViewport::assign_pending_data_pointers(Spatial *p_preview_node, AABB *p_preview_bounds, AcceptDialog *p_accept) {
3465 	preview_node = p_preview_node;
3466 	preview_bounds = p_preview_bounds;
3467 	accept = p_accept;
3468 }
3469 
_get_instance_position(const Point2 & p_pos) const3470 Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const {
3471 	const float MAX_DISTANCE = 10;
3472 
3473 	Vector3 world_ray = _get_ray(p_pos);
3474 	Vector3 world_pos = _get_ray_pos(p_pos);
3475 
3476 	Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(world_pos, world_ray, get_tree()->get_root()->get_world()->get_scenario());
3477 	Set<Ref<EditorSpatialGizmo> > found_gizmos;
3478 
3479 	float closest_dist = MAX_DISTANCE;
3480 
3481 	Vector3 point = world_pos + world_ray * MAX_DISTANCE;
3482 	Vector3 normal = Vector3(0.0, 0.0, 0.0);
3483 
3484 	for (int i = 0; i < instances.size(); i++) {
3485 
3486 		MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(ObjectDB::get_instance(instances[i]));
3487 
3488 		if (!mesh_instance)
3489 			continue;
3490 
3491 		Ref<EditorSpatialGizmo> seg = mesh_instance->get_gizmo();
3492 
3493 		if ((!seg.is_valid()) || found_gizmos.has(seg)) {
3494 			continue;
3495 		}
3496 
3497 		found_gizmos.insert(seg);
3498 
3499 		Vector3 hit_point;
3500 		Vector3 hit_normal;
3501 		bool inters = seg->intersect_ray(camera, p_pos, hit_point, hit_normal, NULL, false);
3502 
3503 		if (!inters)
3504 			continue;
3505 
3506 		float dist = world_pos.distance_to(hit_point);
3507 
3508 		if (dist < 0)
3509 			continue;
3510 
3511 		if (dist < closest_dist) {
3512 			closest_dist = dist;
3513 			point = hit_point;
3514 			normal = hit_normal;
3515 		}
3516 	}
3517 	Vector3 offset = Vector3();
3518 	for (int i = 0; i < 3; i++) {
3519 		if (normal[i] > 0.0)
3520 			offset[i] = (preview_bounds->get_size()[i] - (preview_bounds->get_size()[i] + preview_bounds->get_position()[i]));
3521 		else if (normal[i] < 0.0)
3522 			offset[i] = -(preview_bounds->get_size()[i] + preview_bounds->get_position()[i]);
3523 	}
3524 	return point + offset;
3525 }
3526 
_calculate_spatial_bounds(const Spatial * p_parent,bool p_exclude_toplevel_transform)3527 AABB SpatialEditorViewport::_calculate_spatial_bounds(const Spatial *p_parent, bool p_exclude_toplevel_transform) {
3528 	AABB bounds;
3529 
3530 	const MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(p_parent);
3531 	if (mesh_instance) {
3532 		bounds = mesh_instance->get_aabb();
3533 	}
3534 
3535 	for (int i = 0; i < p_parent->get_child_count(); i++) {
3536 		Spatial *child = Object::cast_to<Spatial>(p_parent->get_child(i));
3537 		if (child) {
3538 			AABB child_bounds = _calculate_spatial_bounds(child, false);
3539 
3540 			if (bounds.size == Vector3() && p_parent->get_class_name() == StringName("Spatial")) {
3541 				bounds = child_bounds;
3542 			} else {
3543 				bounds.merge_with(child_bounds);
3544 			}
3545 		}
3546 	}
3547 
3548 	if (bounds.size == Vector3() && p_parent->get_class_name() != StringName("Spatial")) {
3549 		bounds = AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
3550 	}
3551 
3552 	if (!p_exclude_toplevel_transform) {
3553 		bounds = p_parent->get_transform().xform(bounds);
3554 	}
3555 
3556 	return bounds;
3557 }
3558 
_create_preview(const Vector<String> & files) const3559 void SpatialEditorViewport::_create_preview(const Vector<String> &files) const {
3560 	for (int i = 0; i < files.size(); i++) {
3561 		String path = files[i];
3562 		RES res = ResourceLoader::load(path);
3563 		ERR_CONTINUE(res.is_null());
3564 		Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
3565 		Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
3566 		if (mesh != NULL || scene != NULL) {
3567 			if (mesh != NULL) {
3568 				MeshInstance *mesh_instance = memnew(MeshInstance);
3569 				mesh_instance->set_mesh(mesh);
3570 				preview_node->add_child(mesh_instance);
3571 			} else {
3572 				if (scene.is_valid()) {
3573 					Node *instance = scene->instance();
3574 					if (instance) {
3575 						preview_node->add_child(instance);
3576 					}
3577 				}
3578 			}
3579 			editor->get_scene_root()->add_child(preview_node);
3580 		}
3581 	}
3582 	*preview_bounds = _calculate_spatial_bounds(preview_node);
3583 }
3584 
_remove_preview()3585 void SpatialEditorViewport::_remove_preview() {
3586 	if (preview_node->get_parent()) {
3587 		for (int i = preview_node->get_child_count() - 1; i >= 0; i--) {
3588 			Node *node = preview_node->get_child(i);
3589 			node->queue_delete();
3590 			preview_node->remove_child(node);
3591 		}
3592 		editor->get_scene_root()->remove_child(preview_node);
3593 	}
3594 }
3595 
_cyclical_dependency_exists(const String & p_target_scene_path,Node * p_desired_node)3596 bool SpatialEditorViewport::_cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) {
3597 	if (p_desired_node->get_filename() == p_target_scene_path) {
3598 		return true;
3599 	}
3600 
3601 	int childCount = p_desired_node->get_child_count();
3602 	for (int i = 0; i < childCount; i++) {
3603 		Node *child = p_desired_node->get_child(i);
3604 		if (_cyclical_dependency_exists(p_target_scene_path, child)) {
3605 			return true;
3606 		}
3607 	}
3608 	return false;
3609 }
3610 
_create_instance(Node * parent,String & path,const Point2 & p_point)3611 bool SpatialEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) {
3612 	RES res = ResourceLoader::load(path);
3613 	ERR_FAIL_COND_V(res.is_null(), false);
3614 
3615 	Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
3616 	Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
3617 
3618 	Node *instanced_scene = NULL;
3619 
3620 	if (mesh != NULL || scene != NULL) {
3621 		if (mesh != NULL) {
3622 			MeshInstance *mesh_instance = memnew(MeshInstance);
3623 			mesh_instance->set_mesh(mesh);
3624 			mesh_instance->set_name(path.get_file().get_basename());
3625 			instanced_scene = mesh_instance;
3626 		} else {
3627 			if (!scene.is_valid()) { // invalid scene
3628 				return false;
3629 			} else {
3630 				instanced_scene = scene->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
3631 			}
3632 		}
3633 	}
3634 
3635 	if (instanced_scene == NULL) {
3636 		return false;
3637 	}
3638 
3639 	if (editor->get_edited_scene()->get_filename() != "") { // cyclical instancing
3640 		if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instanced_scene)) {
3641 			memdelete(instanced_scene);
3642 			return false;
3643 		}
3644 	}
3645 
3646 	if (scene != NULL) {
3647 		instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path));
3648 	}
3649 
3650 	editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene);
3651 	editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", editor->get_edited_scene());
3652 	editor_data->get_undo_redo().add_do_reference(instanced_scene);
3653 	editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene);
3654 
3655 	String new_name = parent->validate_child_name(instanced_scene);
3656 	ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
3657 	editor_data->get_undo_redo().add_do_method(sed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name);
3658 	editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
3659 
3660 	Spatial *spatial = Object::cast_to<Spatial>(instanced_scene);
3661 	if (spatial) {
3662 		Transform global_transform;
3663 		Spatial *parent_spatial = Object::cast_to<Spatial>(parent);
3664 		if (parent_spatial) {
3665 			global_transform = parent_spatial->get_global_gizmo_transform();
3666 		}
3667 
3668 		global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
3669 		global_transform.basis *= spatial->get_transform().basis;
3670 
3671 		editor_data->get_undo_redo().add_do_method(instanced_scene, "set_global_transform", global_transform);
3672 	}
3673 
3674 	return true;
3675 }
3676 
_perform_drop_data()3677 void SpatialEditorViewport::_perform_drop_data() {
3678 	_remove_preview();
3679 
3680 	Vector<String> error_files;
3681 
3682 	editor_data->get_undo_redo().create_action(TTR("Create Node"));
3683 
3684 	for (int i = 0; i < selected_files.size(); i++) {
3685 		String path = selected_files[i];
3686 		RES res = ResourceLoader::load(path);
3687 		if (res.is_null()) {
3688 			continue;
3689 		}
3690 		Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
3691 		Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
3692 		if (mesh != NULL || scene != NULL) {
3693 			bool success = _create_instance(target_node, path, drop_pos);
3694 			if (!success) {
3695 				error_files.push_back(path);
3696 			}
3697 		}
3698 	}
3699 
3700 	editor_data->get_undo_redo().commit_action();
3701 
3702 	if (error_files.size() > 0) {
3703 		String files_str;
3704 		for (int i = 0; i < error_files.size(); i++) {
3705 			files_str += error_files[i].get_file().get_basename() + ",";
3706 		}
3707 		files_str = files_str.substr(0, files_str.length() - 1);
3708 		accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str()));
3709 		accept->popup_centered_minsize();
3710 	}
3711 }
3712 
can_drop_data_fw(const Point2 & p_point,const Variant & p_data,Control * p_from) const3713 bool SpatialEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
3714 
3715 	bool can_instance = false;
3716 
3717 	if (!preview_node->is_inside_tree()) {
3718 		Dictionary d = p_data;
3719 		if (d.has("type") && (String(d["type"]) == "files")) {
3720 			Vector<String> files = d["files"];
3721 
3722 			List<String> scene_extensions;
3723 			ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
3724 			List<String> mesh_extensions;
3725 			ResourceLoader::get_recognized_extensions_for_type("Mesh", &mesh_extensions);
3726 
3727 			for (int i = 0; i < files.size(); i++) {
3728 				if (mesh_extensions.find(files[i].get_extension()) || scene_extensions.find(files[i].get_extension())) {
3729 					RES res = ResourceLoader::load(files[i]);
3730 					if (res.is_null()) {
3731 						continue;
3732 					}
3733 
3734 					String type = res->get_class();
3735 					if (type == "PackedScene") {
3736 						Ref<PackedScene> sdata = ResourceLoader::load(files[i]);
3737 						Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
3738 						if (!instanced_scene) {
3739 							continue;
3740 						}
3741 						memdelete(instanced_scene);
3742 					} else if (type == "Mesh" || type == "ArrayMesh" || type == "PrimitiveMesh") {
3743 						Ref<Mesh> mesh = ResourceLoader::load(files[i]);
3744 						if (!mesh.is_valid()) {
3745 							continue;
3746 						}
3747 					} else {
3748 						continue;
3749 					}
3750 					can_instance = true;
3751 					break;
3752 				}
3753 			}
3754 			if (can_instance) {
3755 				_create_preview(files);
3756 			}
3757 		}
3758 	} else {
3759 		can_instance = true;
3760 	}
3761 
3762 	if (can_instance) {
3763 		Transform global_transform = Transform(Basis(), _get_instance_position(p_point));
3764 		preview_node->set_global_transform(global_transform);
3765 	}
3766 
3767 	return can_instance;
3768 }
3769 
drop_data_fw(const Point2 & p_point,const Variant & p_data,Control * p_from)3770 void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
3771 	if (!can_drop_data_fw(p_point, p_data, p_from))
3772 		return;
3773 
3774 	bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
3775 
3776 	selected_files.clear();
3777 	Dictionary d = p_data;
3778 	if (d.has("type") && String(d["type"]) == "files") {
3779 		selected_files = d["files"];
3780 	}
3781 
3782 	List<Node *> list = editor->get_editor_selection()->get_selected_node_list();
3783 	if (list.size() == 0) {
3784 		Node *root_node = editor->get_edited_scene();
3785 		if (root_node) {
3786 			list.push_back(root_node);
3787 		} else {
3788 			accept->set_text(TTR("No parent to instance a child at."));
3789 			accept->popup_centered_minsize();
3790 			_remove_preview();
3791 			return;
3792 		}
3793 	}
3794 	if (list.size() != 1) {
3795 		accept->set_text(TTR("This operation requires a single selected node."));
3796 		accept->popup_centered_minsize();
3797 		_remove_preview();
3798 		return;
3799 	}
3800 
3801 	target_node = list[0];
3802 	if (is_shift && target_node != editor->get_edited_scene()) {
3803 		target_node = target_node->get_parent();
3804 	}
3805 	drop_pos = p_point;
3806 
3807 	_perform_drop_data();
3808 }
3809 
SpatialEditorViewport(SpatialEditor * p_spatial_editor,EditorNode * p_editor,int p_index)3810 SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, EditorNode *p_editor, int p_index) {
3811 
3812 	_edit.mode = TRANSFORM_NONE;
3813 	_edit.plane = TRANSFORM_VIEW;
3814 	_edit.edited_gizmo = 0;
3815 	_edit.snap = 1;
3816 	_edit.gizmo_handle = 0;
3817 
3818 	index = p_index;
3819 	editor = p_editor;
3820 	editor_data = editor->get_scene_tree_dock()->get_editor_data();
3821 	editor_selection = editor->get_editor_selection();
3822 	undo_redo = editor->get_undo_redo();
3823 	clicked = 0;
3824 	clicked_includes_current = false;
3825 	orthogonal = false;
3826 	auto_orthogonal = false;
3827 	lock_rotation = false;
3828 	message_time = 0;
3829 	zoom_indicator_delay = 0.0;
3830 
3831 	spatial_editor = p_spatial_editor;
3832 	ViewportContainer *c = memnew(ViewportContainer);
3833 	viewport_container = c;
3834 	c->set_stretch(true);
3835 	add_child(c);
3836 	c->set_anchors_and_margins_preset(Control::PRESET_WIDE);
3837 	viewport = memnew(Viewport);
3838 	viewport->set_disable_input(true);
3839 
3840 	c->add_child(viewport);
3841 	surface = memnew(Control);
3842 	surface->set_drag_forwarding(this);
3843 	add_child(surface);
3844 	surface->set_anchors_and_margins_preset(Control::PRESET_WIDE);
3845 	surface->set_clip_contents(true);
3846 	camera = memnew(Camera);
3847 	camera->set_disable_gizmo(true);
3848 	camera->set_cull_mask(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + p_index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER));
3849 	viewport->add_child(camera);
3850 	camera->make_current();
3851 	surface->set_focus_mode(FOCUS_ALL);
3852 
3853 	VBoxContainer *vbox = memnew(VBoxContainer);
3854 	surface->add_child(vbox);
3855 	vbox->set_position(Point2(10, 10) * EDSCALE);
3856 
3857 	view_menu = memnew(MenuButton);
3858 	view_menu->set_flat(false);
3859 	vbox->add_child(view_menu);
3860 	view_menu->set_h_size_flags(0);
3861 
3862 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/top_view"), VIEW_TOP);
3863 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/bottom_view"), VIEW_BOTTOM);
3864 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/left_view"), VIEW_LEFT);
3865 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/right_view"), VIEW_RIGHT);
3866 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/front_view"), VIEW_FRONT);
3867 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/rear_view"), VIEW_REAR);
3868 	view_menu->get_popup()->add_separator();
3869 	view_menu->get_popup()->add_radio_check_item(TTR("Perspective") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_PERSPECTIVE);
3870 	view_menu->get_popup()->add_radio_check_item(TTR("Orthogonal") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_ORTHOGONAL);
3871 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true);
3872 	view_menu->get_popup()->add_check_item(TTR("Auto Orthogonal Enabled"), VIEW_AUTO_ORTHOGONAL);
3873 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUTO_ORTHOGONAL), true);
3874 	view_menu->get_popup()->add_separator();
3875 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_lock_rotation", TTR("Lock View Rotation")), VIEW_LOCK_ROTATION);
3876 	view_menu->get_popup()->add_separator();
3877 	view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_normal", TTR("Display Normal")), VIEW_DISPLAY_NORMAL);
3878 	view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_wireframe", TTR("Display Wireframe")), VIEW_DISPLAY_WIREFRAME);
3879 	view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_overdraw", TTR("Display Overdraw")), VIEW_DISPLAY_OVERDRAW);
3880 	view_menu->get_popup()->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/view_display_unshaded", TTR("Display Unshaded")), VIEW_DISPLAY_SHADELESS);
3881 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL), true);
3882 	view_menu->get_popup()->add_separator();
3883 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("View Environment")), VIEW_ENVIRONMENT);
3884 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS);
3885 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION);
3886 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View FPS")), VIEW_FPS);
3887 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT), true);
3888 	view_menu->get_popup()->add_separator();
3889 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION);
3890 	view_menu->get_popup()->add_separator();
3891 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_listener", TTR("Audio Listener")), VIEW_AUDIO_LISTENER);
3892 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_doppler", TTR("Enable Doppler")), VIEW_AUDIO_DOPPLER);
3893 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS), true);
3894 
3895 	view_menu->get_popup()->add_separator();
3896 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_cinematic_preview", TTR("Cinematic Preview")), VIEW_CINEMATIC_PREVIEW);
3897 
3898 	view_menu->get_popup()->add_separator();
3899 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_origin"), VIEW_CENTER_TO_ORIGIN);
3900 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_selection"), VIEW_CENTER_TO_SELECTION);
3901 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_transform_with_view"), VIEW_ALIGN_TRANSFORM_WITH_VIEW);
3902 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_rotation_with_view"), VIEW_ALIGN_ROTATION_WITH_VIEW);
3903 	view_menu->get_popup()->connect("id_pressed", this, "_menu_option");
3904 
3905 	view_menu->set_disable_shortcuts(true);
3906 
3907 	if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
3908 		// Alternate display modes only work when using the GLES3 renderer; make this explicit.
3909 		const int normal_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL);
3910 		const int wireframe_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_WIREFRAME);
3911 		const int overdraw_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_OVERDRAW);
3912 		const int shadeless_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_SHADELESS);
3913 		const String unsupported_tooltip = TTR("Not available when using the GLES2 renderer.");
3914 
3915 		view_menu->get_popup()->set_item_disabled(normal_idx, true);
3916 		view_menu->get_popup()->set_item_tooltip(normal_idx, unsupported_tooltip);
3917 		view_menu->get_popup()->set_item_disabled(wireframe_idx, true);
3918 		view_menu->get_popup()->set_item_tooltip(wireframe_idx, unsupported_tooltip);
3919 		view_menu->get_popup()->set_item_disabled(overdraw_idx, true);
3920 		view_menu->get_popup()->set_item_tooltip(overdraw_idx, unsupported_tooltip);
3921 		view_menu->get_popup()->set_item_disabled(shadeless_idx, true);
3922 		view_menu->get_popup()->set_item_tooltip(shadeless_idx, unsupported_tooltip);
3923 	}
3924 
3925 	ED_SHORTCUT("spatial_editor/freelook_left", TTR("Freelook Left"), KEY_A);
3926 	ED_SHORTCUT("spatial_editor/freelook_right", TTR("Freelook Right"), KEY_D);
3927 	ED_SHORTCUT("spatial_editor/freelook_forward", TTR("Freelook Forward"), KEY_W);
3928 	ED_SHORTCUT("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), KEY_S);
3929 	ED_SHORTCUT("spatial_editor/freelook_up", TTR("Freelook Up"), KEY_E);
3930 	ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), KEY_Q);
3931 	ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), KEY_SHIFT);
3932 	ED_SHORTCUT("spatial_editor/freelook_slow_modifier", TTR("Freelook Slow Modifier"), KEY_ALT);
3933 
3934 	preview_camera = memnew(CheckBox);
3935 	preview_camera->set_text(TTR("Preview"));
3936 	vbox->add_child(preview_camera);
3937 	preview_camera->set_h_size_flags(0);
3938 	preview_camera->hide();
3939 	preview_camera->connect("toggled", this, "_toggle_camera_preview");
3940 	previewing = NULL;
3941 	gizmo_scale = 1.0;
3942 
3943 	preview_node = NULL;
3944 
3945 	info_label = memnew(Label);
3946 	info_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
3947 	info_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -90 * EDSCALE);
3948 	info_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
3949 	info_label->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -10 * EDSCALE);
3950 	info_label->set_h_grow_direction(GROW_DIRECTION_BEGIN);
3951 	info_label->set_v_grow_direction(GROW_DIRECTION_BEGIN);
3952 	surface->add_child(info_label);
3953 	info_label->hide();
3954 
3955 	cinema_label = memnew(Label);
3956 	cinema_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
3957 	cinema_label->set_h_grow_direction(GROW_DIRECTION_END);
3958 	cinema_label->set_align(Label::ALIGN_CENTER);
3959 	surface->add_child(cinema_label);
3960 	cinema_label->set_text(TTR("Cinematic Preview"));
3961 	cinema_label->hide();
3962 	previewing_cinema = false;
3963 
3964 	locked_label = memnew(Label);
3965 	locked_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -20 * EDSCALE);
3966 	locked_label->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -10 * EDSCALE);
3967 	locked_label->set_h_grow_direction(GROW_DIRECTION_END);
3968 	locked_label->set_v_grow_direction(GROW_DIRECTION_BEGIN);
3969 	locked_label->set_align(Label::ALIGN_CENTER);
3970 	surface->add_child(locked_label);
3971 	locked_label->set_text(TTR("View Rotation Locked"));
3972 	locked_label->hide();
3973 
3974 	top_right_vbox = memnew(VBoxContainer);
3975 	top_right_vbox->set_anchors_and_margins_preset(PRESET_TOP_RIGHT, PRESET_MODE_MINSIZE, 2.0 * EDSCALE);
3976 	top_right_vbox->set_h_grow_direction(GROW_DIRECTION_BEGIN);
3977 
3978 	rotation_control = memnew(ViewportRotationControl);
3979 	rotation_control->set_custom_minimum_size(Size2(80, 80) * EDSCALE);
3980 	rotation_control->set_h_size_flags(SIZE_SHRINK_END);
3981 	rotation_control->set_viewport(this);
3982 	top_right_vbox->add_child(rotation_control);
3983 
3984 	fps_label = memnew(Label);
3985 	fps_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
3986 	fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
3987 	fps_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
3988 	fps_label->set_h_grow_direction(GROW_DIRECTION_BEGIN);
3989 	fps_label->set_tooltip(TTR("Note: The FPS value displayed is the editor's framerate.\nIt cannot be used as a reliable indication of in-game performance."));
3990 	fps_label->set_mouse_filter(MOUSE_FILTER_PASS); // Otherwise tooltip doesn't show.
3991 	top_right_vbox->add_child(fps_label);
3992 	fps_label->hide();
3993 
3994 	surface->add_child(top_right_vbox);
3995 
3996 	accept = NULL;
3997 
3998 	freelook_active = false;
3999 	freelook_speed = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_base_speed");
4000 
4001 	selection_menu = memnew(PopupMenu);
4002 	add_child(selection_menu);
4003 	selection_menu->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
4004 	selection_menu->connect("id_pressed", this, "_selection_result_pressed");
4005 	selection_menu->connect("popup_hide", this, "_selection_menu_hide");
4006 
4007 	if (p_index == 0) {
4008 		view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER), true);
4009 		viewport->set_as_audio_listener(true);
4010 	}
4011 
4012 	name = "";
4013 	_update_name();
4014 
4015 	EditorSettings::get_singleton()->connect("settings_changed", this, "update_transform_gizmo_view");
4016 }
4017 
4018 //////////////////////////////////////////////////////////////
4019 
_gui_input(const Ref<InputEvent> & p_event)4020 void SpatialEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) {
4021 
4022 	Ref<InputEventMouseButton> mb = p_event;
4023 
4024 	if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
4025 
4026 		if (mb->is_pressed()) {
4027 			Vector2 size = get_size();
4028 
4029 			int h_sep = get_constant("separation", "HSplitContainer");
4030 			int v_sep = get_constant("separation", "VSplitContainer");
4031 
4032 			int mid_w = size.width * ratio_h;
4033 			int mid_h = size.height * ratio_v;
4034 
4035 			dragging_h = mb->get_position().x > (mid_w - h_sep / 2) && mb->get_position().x < (mid_w + h_sep / 2);
4036 			dragging_v = mb->get_position().y > (mid_h - v_sep / 2) && mb->get_position().y < (mid_h + v_sep / 2);
4037 
4038 			drag_begin_pos = mb->get_position();
4039 			drag_begin_ratio.x = ratio_h;
4040 			drag_begin_ratio.y = ratio_v;
4041 
4042 			switch (view) {
4043 				case VIEW_USE_1_VIEWPORT: {
4044 
4045 					dragging_h = false;
4046 					dragging_v = false;
4047 
4048 				} break;
4049 				case VIEW_USE_2_VIEWPORTS: {
4050 
4051 					dragging_h = false;
4052 
4053 				} break;
4054 				case VIEW_USE_2_VIEWPORTS_ALT: {
4055 
4056 					dragging_v = false;
4057 
4058 				} break;
4059 				case VIEW_USE_3_VIEWPORTS:
4060 				case VIEW_USE_3_VIEWPORTS_ALT:
4061 				case VIEW_USE_4_VIEWPORTS: {
4062 
4063 					// Do nothing.
4064 
4065 				} break;
4066 			}
4067 		} else {
4068 			dragging_h = false;
4069 			dragging_v = false;
4070 		}
4071 	}
4072 
4073 	Ref<InputEventMouseMotion> mm = p_event;
4074 
4075 	if (mm.is_valid()) {
4076 
4077 		if (view == VIEW_USE_3_VIEWPORTS || view == VIEW_USE_3_VIEWPORTS_ALT || view == VIEW_USE_4_VIEWPORTS) {
4078 			Vector2 size = get_size();
4079 
4080 			int h_sep = get_constant("separation", "HSplitContainer");
4081 			int v_sep = get_constant("separation", "VSplitContainer");
4082 
4083 			int mid_w = size.width * ratio_h;
4084 			int mid_h = size.height * ratio_v;
4085 
4086 			bool was_hovering_h = hovering_h;
4087 			bool was_hovering_v = hovering_v;
4088 			hovering_h = mm->get_position().x > (mid_w - h_sep / 2) && mm->get_position().x < (mid_w + h_sep / 2);
4089 			hovering_v = mm->get_position().y > (mid_h - v_sep / 2) && mm->get_position().y < (mid_h + v_sep / 2);
4090 
4091 			if (was_hovering_h != hovering_h || was_hovering_v != hovering_v) {
4092 				update();
4093 			}
4094 		}
4095 
4096 		if (dragging_h) {
4097 			float new_ratio = drag_begin_ratio.x + (mm->get_position().x - drag_begin_pos.x) / get_size().width;
4098 			new_ratio = CLAMP(new_ratio, 40 / get_size().width, (get_size().width - 40) / get_size().width);
4099 			ratio_h = new_ratio;
4100 			queue_sort();
4101 			update();
4102 		}
4103 		if (dragging_v) {
4104 			float new_ratio = drag_begin_ratio.y + (mm->get_position().y - drag_begin_pos.y) / get_size().height;
4105 			new_ratio = CLAMP(new_ratio, 40 / get_size().height, (get_size().height - 40) / get_size().height);
4106 			ratio_v = new_ratio;
4107 			queue_sort();
4108 			update();
4109 		}
4110 	}
4111 }
4112 
_notification(int p_what)4113 void SpatialEditorViewportContainer::_notification(int p_what) {
4114 
4115 	if (p_what == NOTIFICATION_MOUSE_ENTER || p_what == NOTIFICATION_MOUSE_EXIT) {
4116 
4117 		mouseover = (p_what == NOTIFICATION_MOUSE_ENTER);
4118 		update();
4119 	}
4120 
4121 	if (p_what == NOTIFICATION_DRAW && mouseover) {
4122 
4123 		Ref<Texture> h_grabber = get_icon("grabber", "HSplitContainer");
4124 		Ref<Texture> v_grabber = get_icon("grabber", "VSplitContainer");
4125 
4126 		Ref<Texture> hdiag_grabber = get_icon("GuiViewportHdiagsplitter", "EditorIcons");
4127 		Ref<Texture> vdiag_grabber = get_icon("GuiViewportVdiagsplitter", "EditorIcons");
4128 		Ref<Texture> vh_grabber = get_icon("GuiViewportVhsplitter", "EditorIcons");
4129 
4130 		Vector2 size = get_size();
4131 
4132 		int h_sep = get_constant("separation", "HSplitContainer");
4133 
4134 		int v_sep = get_constant("separation", "VSplitContainer");
4135 
4136 		int mid_w = size.width * ratio_h;
4137 		int mid_h = size.height * ratio_v;
4138 
4139 		int size_left = mid_w - h_sep / 2;
4140 		int size_bottom = size.height - mid_h - v_sep / 2;
4141 
4142 		switch (view) {
4143 
4144 			case VIEW_USE_1_VIEWPORT: {
4145 
4146 				// Nothing to show.
4147 
4148 			} break;
4149 			case VIEW_USE_2_VIEWPORTS: {
4150 
4151 				draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
4152 				set_default_cursor_shape(CURSOR_VSPLIT);
4153 
4154 			} break;
4155 			case VIEW_USE_2_VIEWPORTS_ALT: {
4156 
4157 				draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
4158 				set_default_cursor_shape(CURSOR_HSPLIT);
4159 
4160 			} break;
4161 			case VIEW_USE_3_VIEWPORTS: {
4162 
4163 				if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
4164 					draw_texture(hdiag_grabber, Vector2(mid_w - hdiag_grabber->get_width() / 2, mid_h - v_grabber->get_height() / 4));
4165 					set_default_cursor_shape(CURSOR_DRAG);
4166 				} else if ((hovering_v && !dragging_h) || dragging_v) {
4167 					draw_texture(v_grabber, Vector2((size.width - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
4168 					set_default_cursor_shape(CURSOR_VSPLIT);
4169 				} else if (hovering_h || dragging_h) {
4170 					draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, mid_h + v_grabber->get_height() / 2 + (size_bottom - h_grabber->get_height()) / 2));
4171 					set_default_cursor_shape(CURSOR_HSPLIT);
4172 				}
4173 
4174 			} break;
4175 			case VIEW_USE_3_VIEWPORTS_ALT: {
4176 
4177 				if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
4178 					draw_texture(vdiag_grabber, Vector2(mid_w - vdiag_grabber->get_width() + v_grabber->get_height() / 4, mid_h - vdiag_grabber->get_height() / 2));
4179 					set_default_cursor_shape(CURSOR_DRAG);
4180 				} else if ((hovering_v && !dragging_h) || dragging_v) {
4181 					draw_texture(v_grabber, Vector2((size_left - v_grabber->get_width()) / 2, mid_h - v_grabber->get_height() / 2));
4182 					set_default_cursor_shape(CURSOR_VSPLIT);
4183 				} else if (hovering_h || dragging_h) {
4184 					draw_texture(h_grabber, Vector2(mid_w - h_grabber->get_width() / 2, (size.height - h_grabber->get_height()) / 2));
4185 					set_default_cursor_shape(CURSOR_HSPLIT);
4186 				}
4187 
4188 			} break;
4189 			case VIEW_USE_4_VIEWPORTS: {
4190 
4191 				Vector2 half(mid_w, mid_h);
4192 				if ((hovering_v && hovering_h && !dragging_v && !dragging_h) || (dragging_v && dragging_h)) {
4193 					draw_texture(vh_grabber, half - vh_grabber->get_size() / 2.0);
4194 					set_default_cursor_shape(CURSOR_DRAG);
4195 				} else if ((hovering_v && !dragging_h) || dragging_v) {
4196 					draw_texture(v_grabber, half - v_grabber->get_size() / 2.0);
4197 					set_default_cursor_shape(CURSOR_VSPLIT);
4198 				} else if (hovering_h || dragging_h) {
4199 					draw_texture(h_grabber, half - h_grabber->get_size() / 2.0);
4200 					set_default_cursor_shape(CURSOR_HSPLIT);
4201 				}
4202 
4203 			} break;
4204 		}
4205 	}
4206 
4207 	if (p_what == NOTIFICATION_SORT_CHILDREN) {
4208 
4209 		SpatialEditorViewport *viewports[4];
4210 		int vc = 0;
4211 		for (int i = 0; i < get_child_count(); i++) {
4212 			viewports[vc] = Object::cast_to<SpatialEditorViewport>(get_child(i));
4213 			if (viewports[vc]) {
4214 				vc++;
4215 			}
4216 		}
4217 
4218 		ERR_FAIL_COND(vc != 4);
4219 
4220 		Size2 size = get_size();
4221 
4222 		if (size.x < 10 || size.y < 10) {
4223 			for (int i = 0; i < 4; i++) {
4224 				viewports[i]->hide();
4225 			}
4226 			return;
4227 		}
4228 		int h_sep = get_constant("separation", "HSplitContainer");
4229 
4230 		int v_sep = get_constant("separation", "VSplitContainer");
4231 
4232 		int mid_w = size.width * ratio_h;
4233 		int mid_h = size.height * ratio_v;
4234 
4235 		int size_left = mid_w - h_sep / 2;
4236 		int size_right = size.width - mid_w - h_sep / 2;
4237 
4238 		int size_top = mid_h - v_sep / 2;
4239 		int size_bottom = size.height - mid_h - v_sep / 2;
4240 
4241 		switch (view) {
4242 
4243 			case VIEW_USE_1_VIEWPORT: {
4244 
4245 				viewports[0]->show();
4246 				for (int i = 1; i < 4; i++) {
4247 
4248 					viewports[i]->hide();
4249 				}
4250 
4251 				fit_child_in_rect(viewports[0], Rect2(Vector2(), size));
4252 
4253 			} break;
4254 			case VIEW_USE_2_VIEWPORTS: {
4255 
4256 				for (int i = 0; i < 4; i++) {
4257 
4258 					if (i == 1 || i == 3)
4259 						viewports[i]->hide();
4260 					else
4261 						viewports[i]->show();
4262 				}
4263 
4264 				fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
4265 				fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size.width, size_bottom)));
4266 
4267 			} break;
4268 			case VIEW_USE_2_VIEWPORTS_ALT: {
4269 
4270 				for (int i = 0; i < 4; i++) {
4271 
4272 					if (i == 1 || i == 3)
4273 						viewports[i]->hide();
4274 					else
4275 						viewports[i]->show();
4276 				}
4277 				fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size.height)));
4278 				fit_child_in_rect(viewports[2], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
4279 
4280 			} break;
4281 			case VIEW_USE_3_VIEWPORTS: {
4282 
4283 				for (int i = 0; i < 4; i++) {
4284 
4285 					if (i == 1)
4286 						viewports[i]->hide();
4287 					else
4288 						viewports[i]->show();
4289 				}
4290 
4291 				fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size.width, size_top)));
4292 				fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
4293 				fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
4294 
4295 			} break;
4296 			case VIEW_USE_3_VIEWPORTS_ALT: {
4297 
4298 				for (int i = 0; i < 4; i++) {
4299 
4300 					if (i == 1)
4301 						viewports[i]->hide();
4302 					else
4303 						viewports[i]->show();
4304 				}
4305 
4306 				fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
4307 				fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
4308 				fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size.height)));
4309 
4310 			} break;
4311 			case VIEW_USE_4_VIEWPORTS: {
4312 
4313 				for (int i = 0; i < 4; i++) {
4314 
4315 					viewports[i]->show();
4316 				}
4317 
4318 				fit_child_in_rect(viewports[0], Rect2(Vector2(), Vector2(size_left, size_top)));
4319 				fit_child_in_rect(viewports[1], Rect2(Vector2(mid_w + h_sep / 2, 0), Vector2(size_right, size_top)));
4320 				fit_child_in_rect(viewports[2], Rect2(Vector2(0, mid_h + v_sep / 2), Vector2(size_left, size_bottom)));
4321 				fit_child_in_rect(viewports[3], Rect2(Vector2(mid_w + h_sep / 2, mid_h + v_sep / 2), Vector2(size_right, size_bottom)));
4322 
4323 			} break;
4324 		}
4325 	}
4326 }
4327 
set_view(View p_view)4328 void SpatialEditorViewportContainer::set_view(View p_view) {
4329 
4330 	view = p_view;
4331 	queue_sort();
4332 }
4333 
get_view()4334 SpatialEditorViewportContainer::View SpatialEditorViewportContainer::get_view() {
4335 
4336 	return view;
4337 }
4338 
_bind_methods()4339 void SpatialEditorViewportContainer::_bind_methods() {
4340 
4341 	ClassDB::bind_method("_gui_input", &SpatialEditorViewportContainer::_gui_input);
4342 }
4343 
SpatialEditorViewportContainer()4344 SpatialEditorViewportContainer::SpatialEditorViewportContainer() {
4345 
4346 	set_clip_contents(true);
4347 	view = VIEW_USE_1_VIEWPORT;
4348 	mouseover = false;
4349 	ratio_h = 0.5;
4350 	ratio_v = 0.5;
4351 	hovering_v = false;
4352 	hovering_h = false;
4353 	dragging_v = false;
4354 	dragging_h = false;
4355 }
4356 
4357 ///////////////////////////////////////////////////////////////////
4358 
4359 SpatialEditor *SpatialEditor::singleton = NULL;
4360 
~SpatialEditorSelectedItem()4361 SpatialEditorSelectedItem::~SpatialEditorSelectedItem() {
4362 
4363 	if (sbox_instance.is_valid())
4364 		VisualServer::get_singleton()->free(sbox_instance);
4365 }
4366 
select_gizmo_highlight_axis(int p_axis)4367 void SpatialEditor::select_gizmo_highlight_axis(int p_axis) {
4368 
4369 	for (int i = 0; i < 3; i++) {
4370 
4371 		move_gizmo[i]->surface_set_material(0, i == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
4372 		move_plane_gizmo[i]->surface_set_material(0, (i + 6) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]);
4373 		rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
4374 		scale_gizmo[i]->surface_set_material(0, (i + 9) == p_axis ? gizmo_color_hl[i] : gizmo_color[i]);
4375 		scale_plane_gizmo[i]->surface_set_material(0, (i + 12) == p_axis ? plane_gizmo_color_hl[i] : plane_gizmo_color[i]);
4376 	}
4377 }
4378 
update_transform_gizmo()4379 void SpatialEditor::update_transform_gizmo() {
4380 
4381 	List<Node *> &selection = editor_selection->get_selected_node_list();
4382 	AABB center;
4383 	bool first = true;
4384 
4385 	Basis gizmo_basis;
4386 	bool local_gizmo_coords = are_local_coords_enabled();
4387 
4388 	for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4389 
4390 		Spatial *sp = Object::cast_to<Spatial>(E->get());
4391 		if (!sp)
4392 			continue;
4393 
4394 		SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
4395 		if (!se)
4396 			continue;
4397 
4398 		Transform xf = se->sp->get_global_gizmo_transform();
4399 
4400 		if (first) {
4401 			center.position = xf.origin;
4402 			first = false;
4403 			if (local_gizmo_coords) {
4404 				gizmo_basis = xf.basis;
4405 				gizmo_basis.orthonormalize();
4406 			}
4407 		} else {
4408 			center.expand_to(xf.origin);
4409 			gizmo_basis = Basis();
4410 		}
4411 	}
4412 
4413 	Vector3 pcenter = center.position + center.size * 0.5;
4414 	gizmo.visible = !first;
4415 	gizmo.transform.origin = pcenter;
4416 	gizmo.transform.basis = gizmo_basis;
4417 
4418 	for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
4419 		viewports[i]->update_transform_gizmo_view();
4420 	}
4421 }
4422 
_update_all_gizmos(Node * p_node)4423 void _update_all_gizmos(Node *p_node) {
4424 	for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
4425 		Spatial *spatial_node = Object::cast_to<Spatial>(p_node->get_child(i));
4426 		if (spatial_node) {
4427 			spatial_node->update_gizmo();
4428 		}
4429 
4430 		_update_all_gizmos(p_node->get_child(i));
4431 	}
4432 }
4433 
update_all_gizmos(Node * p_node)4434 void SpatialEditor::update_all_gizmos(Node *p_node) {
4435 	if (!p_node) {
4436 		p_node = SceneTree::get_singleton()->get_root();
4437 	}
4438 	_update_all_gizmos(p_node);
4439 }
4440 
_get_editor_data(Object * p_what)4441 Object *SpatialEditor::_get_editor_data(Object *p_what) {
4442 
4443 	Spatial *sp = Object::cast_to<Spatial>(p_what);
4444 	if (!sp)
4445 		return NULL;
4446 
4447 	SpatialEditorSelectedItem *si = memnew(SpatialEditorSelectedItem);
4448 
4449 	si->sp = sp;
4450 	si->sbox_instance = VisualServer::get_singleton()->instance_create2(selection_box->get_rid(), sp->get_world()->get_scenario());
4451 	VS::get_singleton()->instance_geometry_set_cast_shadows_setting(si->sbox_instance, VS::SHADOW_CASTING_SETTING_OFF);
4452 
4453 	return si;
4454 }
4455 
_generate_selection_box()4456 void SpatialEditor::_generate_selection_box() {
4457 
4458 	AABB aabb(Vector3(), Vector3(1, 1, 1));
4459 	aabb.grow_by(aabb.get_longest_axis_size() / 20.0);
4460 
4461 	Ref<SurfaceTool> st = memnew(SurfaceTool);
4462 
4463 	st->begin(Mesh::PRIMITIVE_LINES);
4464 	for (int i = 0; i < 12; i++) {
4465 
4466 		Vector3 a, b;
4467 		aabb.get_edge(i, a, b);
4468 
4469 		st->add_color(Color(1.0, 1.0, 0.8, 0.8));
4470 		st->add_vertex(a);
4471 		st->add_color(Color(1.0, 1.0, 0.8, 0.4));
4472 		st->add_vertex(a.linear_interpolate(b, 0.2));
4473 
4474 		st->add_color(Color(1.0, 1.0, 0.8, 0.4));
4475 		st->add_vertex(a.linear_interpolate(b, 0.8));
4476 		st->add_color(Color(1.0, 1.0, 0.8, 0.8));
4477 		st->add_vertex(b);
4478 	}
4479 
4480 	Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
4481 	mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
4482 	mat->set_albedo(Color(1, 1, 1));
4483 	mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
4484 	mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
4485 	mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
4486 	st->set_material(mat);
4487 	selection_box = st->commit();
4488 }
4489 
get_state() const4490 Dictionary SpatialEditor::get_state() const {
4491 
4492 	Dictionary d;
4493 
4494 	d["snap_enabled"] = snap_enabled;
4495 	d["translate_snap"] = get_translate_snap();
4496 	d["rotate_snap"] = get_rotate_snap();
4497 	d["scale_snap"] = get_scale_snap();
4498 
4499 	d["local_coords"] = tool_option_button[TOOL_OPT_LOCAL_COORDS]->is_pressed();
4500 
4501 	int vc = 0;
4502 	if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT)))
4503 		vc = 1;
4504 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS)))
4505 		vc = 2;
4506 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS)))
4507 		vc = 3;
4508 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS)))
4509 		vc = 4;
4510 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT)))
4511 		vc = 5;
4512 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT)))
4513 		vc = 6;
4514 
4515 	d["viewport_mode"] = vc;
4516 	Array vpdata;
4517 	for (int i = 0; i < 4; i++) {
4518 		vpdata.push_back(viewports[i]->get_state());
4519 	}
4520 
4521 	d["viewports"] = vpdata;
4522 
4523 	d["show_grid"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID));
4524 	d["show_origin"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN));
4525 	d["fov"] = get_fov();
4526 	d["znear"] = get_znear();
4527 	d["zfar"] = get_zfar();
4528 
4529 	Dictionary gizmos_status;
4530 	for (int i = 0; i < gizmo_plugins_by_name.size(); i++) {
4531 		if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
4532 		int state = gizmos_menu->get_item_state(gizmos_menu->get_item_index(i));
4533 		String name = gizmo_plugins_by_name[i]->get_name();
4534 		gizmos_status[name] = state;
4535 	}
4536 
4537 	d["gizmos_status"] = gizmos_status;
4538 
4539 	return d;
4540 }
set_state(const Dictionary & p_state)4541 void SpatialEditor::set_state(const Dictionary &p_state) {
4542 
4543 	Dictionary d = p_state;
4544 
4545 	if (d.has("snap_enabled")) {
4546 		snap_enabled = d["snap_enabled"];
4547 		tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(d["snap_enabled"]);
4548 	}
4549 
4550 	if (d.has("translate_snap"))
4551 		snap_translate_value = d["translate_snap"];
4552 
4553 	if (d.has("rotate_snap"))
4554 		snap_rotate_value = d["rotate_snap"];
4555 
4556 	if (d.has("scale_snap"))
4557 		snap_scale_value = d["scale_snap"];
4558 
4559 	_snap_update();
4560 
4561 	if (d.has("local_coords")) {
4562 		tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_pressed(d["local_coords"]);
4563 		update_transform_gizmo();
4564 	}
4565 
4566 	if (d.has("viewport_mode")) {
4567 		int vc = d["viewport_mode"];
4568 
4569 		if (vc == 1)
4570 			_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
4571 		else if (vc == 2)
4572 			_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
4573 		else if (vc == 3)
4574 			_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
4575 		else if (vc == 4)
4576 			_menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
4577 		else if (vc == 5)
4578 			_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
4579 		else if (vc == 6)
4580 			_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
4581 	}
4582 
4583 	if (d.has("viewports")) {
4584 		Array vp = d["viewports"];
4585 		uint32_t vp_size = static_cast<uint32_t>(vp.size());
4586 		if (vp_size > VIEWPORTS_COUNT) {
4587 			WARN_PRINT("Ignoring superfluous viewport settings from spatial editor state.");
4588 			vp_size = VIEWPORTS_COUNT;
4589 		}
4590 
4591 		for (uint32_t i = 0; i < vp_size; i++) {
4592 			viewports[i]->set_state(vp[i]);
4593 		}
4594 	}
4595 
4596 	if (d.has("zfar"))
4597 		settings_zfar->set_value(float(d["zfar"]));
4598 	if (d.has("znear"))
4599 		settings_znear->set_value(float(d["znear"]));
4600 	if (d.has("fov"))
4601 		settings_fov->set_value(float(d["fov"]));
4602 	if (d.has("show_grid")) {
4603 		bool use = d["show_grid"];
4604 
4605 		if (use != view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID))) {
4606 			_menu_item_pressed(MENU_VIEW_GRID);
4607 		}
4608 	}
4609 
4610 	if (d.has("show_origin")) {
4611 		bool use = d["show_origin"];
4612 
4613 		if (use != view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN))) {
4614 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), use);
4615 			VisualServer::get_singleton()->instance_set_visible(origin_instance, use);
4616 		}
4617 	}
4618 
4619 	if (d.has("gizmos_status")) {
4620 		Dictionary gizmos_status = d["gizmos_status"];
4621 		List<Variant> keys;
4622 		gizmos_status.get_key_list(&keys);
4623 
4624 		for (int j = 0; j < gizmo_plugins_by_name.size(); ++j) {
4625 			if (!gizmo_plugins_by_name[j]->can_be_hidden()) continue;
4626 			int state = EditorSpatialGizmoPlugin::VISIBLE;
4627 			for (int i = 0; i < keys.size(); i++) {
4628 				if (gizmo_plugins_by_name.write[j]->get_name() == keys[i]) {
4629 					state = gizmos_status[keys[i]];
4630 					break;
4631 				}
4632 			}
4633 
4634 			gizmo_plugins_by_name.write[j]->set_state(state);
4635 		}
4636 		_update_gizmos_menu();
4637 	}
4638 }
4639 
edit(Spatial * p_spatial)4640 void SpatialEditor::edit(Spatial *p_spatial) {
4641 
4642 	if (p_spatial != selected) {
4643 		if (selected) {
4644 
4645 			Ref<EditorSpatialGizmo> seg = selected->get_gizmo();
4646 			if (seg.is_valid()) {
4647 				seg->set_selected(false);
4648 				selected->update_gizmo();
4649 			}
4650 		}
4651 
4652 		selected = p_spatial;
4653 		over_gizmo_handle = -1;
4654 
4655 		if (selected) {
4656 
4657 			Ref<EditorSpatialGizmo> seg = selected->get_gizmo();
4658 			if (seg.is_valid()) {
4659 				seg->set_selected(true);
4660 				selected->update_gizmo();
4661 			}
4662 		}
4663 	}
4664 }
4665 
_snap_changed()4666 void SpatialEditor::_snap_changed() {
4667 
4668 	snap_translate_value = snap_translate->get_text().to_double();
4669 	snap_rotate_value = snap_rotate->get_text().to_double();
4670 	snap_scale_value = snap_scale->get_text().to_double();
4671 }
4672 
_snap_update()4673 void SpatialEditor::_snap_update() {
4674 
4675 	snap_translate->set_text(String::num(snap_translate_value));
4676 	snap_rotate->set_text(String::num(snap_rotate_value));
4677 	snap_scale->set_text(String::num(snap_scale_value));
4678 }
4679 
_xform_dialog_action()4680 void SpatialEditor::_xform_dialog_action() {
4681 
4682 	Transform t;
4683 	//translation
4684 	Vector3 scale;
4685 	Vector3 rotate;
4686 	Vector3 translate;
4687 
4688 	for (int i = 0; i < 3; i++) {
4689 		translate[i] = xform_translate[i]->get_text().to_double();
4690 		rotate[i] = Math::deg2rad(xform_rotate[i]->get_text().to_double());
4691 		scale[i] = xform_scale[i]->get_text().to_double();
4692 	}
4693 
4694 	t.basis.scale(scale);
4695 	t.basis.rotate(rotate);
4696 	t.origin = translate;
4697 
4698 	undo_redo->create_action(TTR("XForm Dialog"));
4699 
4700 	List<Node *> &selection = editor_selection->get_selected_node_list();
4701 
4702 	for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4703 
4704 		Spatial *sp = Object::cast_to<Spatial>(E->get());
4705 		if (!sp)
4706 			continue;
4707 
4708 		SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
4709 		if (!se)
4710 			continue;
4711 
4712 		bool post = xform_type->get_selected() > 0;
4713 
4714 		Transform tr = sp->get_global_gizmo_transform();
4715 		if (post)
4716 			tr = tr * t;
4717 		else {
4718 
4719 			tr.basis = t.basis * tr.basis;
4720 			tr.origin += t.origin;
4721 		}
4722 
4723 		undo_redo->add_do_method(sp, "set_global_transform", tr);
4724 		undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
4725 	}
4726 	undo_redo->commit_action();
4727 }
4728 
_menu_item_toggled(bool pressed,int p_option)4729 void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) {
4730 
4731 	switch (p_option) {
4732 		case MENU_TOOL_LOCAL_COORDS: {
4733 
4734 			tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_pressed(pressed);
4735 			update_transform_gizmo();
4736 		} break;
4737 
4738 		case MENU_TOOL_USE_SNAP: {
4739 			tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(pressed);
4740 			snap_enabled = pressed;
4741 		} break;
4742 
4743 		case MENU_TOOL_OVERRIDE_CAMERA: {
4744 			ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger();
4745 
4746 			if (pressed) {
4747 				using Override = ScriptEditorDebugger::CameraOverride;
4748 
4749 				debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
4750 			} else {
4751 				debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
4752 			}
4753 
4754 		} break;
4755 	}
4756 }
4757 
_menu_gizmo_toggled(int p_option)4758 void SpatialEditor::_menu_gizmo_toggled(int p_option) {
4759 
4760 	const int idx = gizmos_menu->get_item_index(p_option);
4761 	gizmos_menu->toggle_item_multistate(idx);
4762 
4763 	// Change icon
4764 	const int state = gizmos_menu->get_item_state(idx);
4765 	switch (state) {
4766 		case EditorSpatialGizmoPlugin::VISIBLE:
4767 			gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_visible"));
4768 			break;
4769 		case EditorSpatialGizmoPlugin::ON_TOP:
4770 			gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_xray"));
4771 			break;
4772 		case EditorSpatialGizmoPlugin::HIDDEN:
4773 			gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_hidden"));
4774 			break;
4775 	}
4776 
4777 	gizmo_plugins_by_name.write[p_option]->set_state(state);
4778 
4779 	update_all_gizmos();
4780 }
4781 
_update_camera_override_button(bool p_game_running)4782 void SpatialEditor::_update_camera_override_button(bool p_game_running) {
4783 	Button *const button = tool_option_button[TOOL_OPT_OVERRIDE_CAMERA];
4784 
4785 	if (p_game_running) {
4786 		button->set_disabled(false);
4787 		button->set_tooltip(TTR("Game Camera Override\nNo game instance running."));
4788 	} else {
4789 		button->set_disabled(true);
4790 		button->set_pressed(false);
4791 		button->set_tooltip(TTR("Game Camera Override\nOverrides game camera with editor viewport camera."));
4792 	}
4793 }
4794 
_update_camera_override_viewport(Object * p_viewport)4795 void SpatialEditor::_update_camera_override_viewport(Object *p_viewport) {
4796 	SpatialEditorViewport *current_viewport = Object::cast_to<SpatialEditorViewport>(p_viewport);
4797 
4798 	if (!current_viewport)
4799 		return;
4800 
4801 	ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger();
4802 
4803 	camera_override_viewport_id = current_viewport->index;
4804 	if (debugger->get_camera_override() >= ScriptEditorDebugger::OVERRIDE_3D_1) {
4805 		using Override = ScriptEditorDebugger::CameraOverride;
4806 
4807 		debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
4808 	}
4809 }
4810 
_menu_item_pressed(int p_option)4811 void SpatialEditor::_menu_item_pressed(int p_option) {
4812 
4813 	switch (p_option) {
4814 
4815 		case MENU_TOOL_SELECT:
4816 		case MENU_TOOL_MOVE:
4817 		case MENU_TOOL_ROTATE:
4818 		case MENU_TOOL_SCALE:
4819 		case MENU_TOOL_LIST_SELECT: {
4820 
4821 			for (int i = 0; i < TOOL_MAX; i++)
4822 				tool_button[i]->set_pressed(i == p_option);
4823 			tool_mode = (ToolMode)p_option;
4824 			update_transform_gizmo();
4825 
4826 		} break;
4827 		case MENU_TRANSFORM_CONFIGURE_SNAP: {
4828 
4829 			snap_dialog->popup_centered(Size2(200, 180));
4830 		} break;
4831 		case MENU_TRANSFORM_DIALOG: {
4832 
4833 			for (int i = 0; i < 3; i++) {
4834 
4835 				xform_translate[i]->set_text("0");
4836 				xform_rotate[i]->set_text("0");
4837 				xform_scale[i]->set_text("1");
4838 			}
4839 
4840 			xform_dialog->popup_centered(Size2(320, 240) * EDSCALE);
4841 
4842 		} break;
4843 		case MENU_VIEW_USE_1_VIEWPORT: {
4844 
4845 			viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_1_VIEWPORT);
4846 
4847 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), true);
4848 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
4849 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
4850 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
4851 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
4852 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
4853 
4854 		} break;
4855 		case MENU_VIEW_USE_2_VIEWPORTS: {
4856 
4857 			viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_2_VIEWPORTS);
4858 
4859 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
4860 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), true);
4861 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
4862 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
4863 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
4864 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
4865 
4866 		} break;
4867 		case MENU_VIEW_USE_2_VIEWPORTS_ALT: {
4868 
4869 			viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_2_VIEWPORTS_ALT);
4870 
4871 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
4872 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
4873 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
4874 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
4875 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), true);
4876 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
4877 
4878 		} break;
4879 		case MENU_VIEW_USE_3_VIEWPORTS: {
4880 
4881 			viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_3_VIEWPORTS);
4882 
4883 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
4884 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
4885 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), true);
4886 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
4887 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
4888 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
4889 
4890 		} break;
4891 		case MENU_VIEW_USE_3_VIEWPORTS_ALT: {
4892 
4893 			viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_3_VIEWPORTS_ALT);
4894 
4895 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
4896 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
4897 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
4898 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
4899 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
4900 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), true);
4901 
4902 		} break;
4903 		case MENU_VIEW_USE_4_VIEWPORTS: {
4904 
4905 			viewport_base->set_view(SpatialEditorViewportContainer::VIEW_USE_4_VIEWPORTS);
4906 
4907 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
4908 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
4909 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
4910 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), true);
4911 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
4912 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
4913 
4914 		} break;
4915 		case MENU_VIEW_ORIGIN: {
4916 
4917 			bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
4918 
4919 			origin_enabled = !is_checked;
4920 			VisualServer::get_singleton()->instance_set_visible(origin_instance, origin_enabled);
4921 			// Update the grid since its appearance depends on whether the origin is enabled
4922 			_finish_grid();
4923 			_init_grid();
4924 
4925 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), origin_enabled);
4926 		} break;
4927 		case MENU_VIEW_GRID: {
4928 
4929 			bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
4930 
4931 			grid_enabled = !is_checked;
4932 
4933 			for (int i = 0; i < 3; ++i) {
4934 				if (grid_enable[i]) {
4935 					VisualServer::get_singleton()->instance_set_visible(grid_instance[i], grid_enabled);
4936 					grid_visible[i] = grid_enabled;
4937 				}
4938 			}
4939 
4940 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), grid_enabled);
4941 
4942 		} break;
4943 		case MENU_VIEW_CAMERA_SETTINGS: {
4944 
4945 			settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50));
4946 		} break;
4947 		case MENU_SNAP_TO_FLOOR: {
4948 			snap_selected_nodes_to_floor();
4949 		} break;
4950 		case MENU_LOCK_SELECTED: {
4951 			undo_redo->create_action(TTR("Lock Selected"));
4952 
4953 			List<Node *> &selection = editor_selection->get_selected_node_list();
4954 
4955 			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4956 
4957 				Spatial *spatial = Object::cast_to<Spatial>(E->get());
4958 				if (!spatial || !spatial->is_visible_in_tree())
4959 					continue;
4960 
4961 				if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
4962 					continue;
4963 
4964 				undo_redo->add_do_method(spatial, "set_meta", "_edit_lock_", true);
4965 				undo_redo->add_undo_method(spatial, "remove_meta", "_edit_lock_");
4966 				undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
4967 				undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
4968 			}
4969 
4970 			undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
4971 			undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
4972 			undo_redo->commit_action();
4973 		} break;
4974 		case MENU_UNLOCK_SELECTED: {
4975 			undo_redo->create_action(TTR("Unlock Selected"));
4976 
4977 			List<Node *> &selection = editor_selection->get_selected_node_list();
4978 
4979 			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
4980 
4981 				Spatial *spatial = Object::cast_to<Spatial>(E->get());
4982 				if (!spatial || !spatial->is_visible_in_tree())
4983 					continue;
4984 
4985 				if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
4986 					continue;
4987 
4988 				undo_redo->add_do_method(spatial, "remove_meta", "_edit_lock_");
4989 				undo_redo->add_undo_method(spatial, "set_meta", "_edit_lock_", true);
4990 				undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
4991 				undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
4992 			}
4993 
4994 			undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
4995 			undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
4996 			undo_redo->commit_action();
4997 		} break;
4998 		case MENU_GROUP_SELECTED: {
4999 			undo_redo->create_action(TTR("Group Selected"));
5000 
5001 			List<Node *> &selection = editor_selection->get_selected_node_list();
5002 
5003 			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
5004 
5005 				Spatial *spatial = Object::cast_to<Spatial>(E->get());
5006 				if (!spatial || !spatial->is_visible_in_tree())
5007 					continue;
5008 
5009 				if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
5010 					continue;
5011 
5012 				undo_redo->add_do_method(spatial, "set_meta", "_edit_group_", true);
5013 				undo_redo->add_undo_method(spatial, "remove_meta", "_edit_group_");
5014 				undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
5015 				undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
5016 			}
5017 
5018 			undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
5019 			undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
5020 			undo_redo->commit_action();
5021 		} break;
5022 		case MENU_UNGROUP_SELECTED: {
5023 			undo_redo->create_action(TTR("Ungroup Selected"));
5024 			List<Node *> &selection = editor_selection->get_selected_node_list();
5025 
5026 			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
5027 
5028 				Spatial *spatial = Object::cast_to<Spatial>(E->get());
5029 				if (!spatial || !spatial->is_visible_in_tree())
5030 					continue;
5031 
5032 				if (spatial->get_viewport() != EditorNode::get_singleton()->get_scene_root())
5033 					continue;
5034 
5035 				undo_redo->add_do_method(spatial, "remove_meta", "_edit_group_");
5036 				undo_redo->add_undo_method(spatial, "set_meta", "_edit_group_", true);
5037 				undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
5038 				undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
5039 			}
5040 
5041 			undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
5042 			undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
5043 			undo_redo->commit_action();
5044 		} break;
5045 	}
5046 }
5047 
_init_indicators()5048 void SpatialEditor::_init_indicators() {
5049 
5050 	{
5051 		origin_enabled = true;
5052 		grid_enabled = true;
5053 
5054 		indicator_mat.instance();
5055 		indicator_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
5056 		indicator_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
5057 		indicator_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
5058 
5059 		Vector<Color> origin_colors;
5060 		Vector<Vector3> origin_points;
5061 
5062 		for (int i = 0; i < 3; i++) {
5063 			Vector3 axis;
5064 			axis[i] = 1;
5065 			Color origin_color;
5066 			switch (i) {
5067 				case 0:
5068 					origin_color = get_color("axis_x_color", "Editor");
5069 					break;
5070 				case 1:
5071 					origin_color = get_color("axis_y_color", "Editor");
5072 					break;
5073 				case 2:
5074 					origin_color = get_color("axis_z_color", "Editor");
5075 					break;
5076 				default:
5077 					origin_color = Color();
5078 					break;
5079 			}
5080 
5081 			grid_enable[i] = false;
5082 			grid_visible[i] = false;
5083 
5084 			origin_colors.push_back(origin_color);
5085 			origin_colors.push_back(origin_color);
5086 			origin_points.push_back(axis * 4096);
5087 			origin_points.push_back(axis * -4096);
5088 		}
5089 
5090 		grid_enable[1] = true;
5091 		grid_visible[1] = true;
5092 
5093 		_init_grid();
5094 
5095 		origin = VisualServer::get_singleton()->mesh_create();
5096 		Array d;
5097 		d.resize(VS::ARRAY_MAX);
5098 		d[VisualServer::ARRAY_VERTEX] = origin_points;
5099 		d[VisualServer::ARRAY_COLOR] = origin_colors;
5100 
5101 		VisualServer::get_singleton()->mesh_add_surface_from_arrays(origin, VisualServer::PRIMITIVE_LINES, d);
5102 		VisualServer::get_singleton()->mesh_surface_set_material(origin, 0, indicator_mat->get_rid());
5103 
5104 		origin_instance = VisualServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world()->get_scenario());
5105 		VS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << SpatialEditorViewport::GIZMO_GRID_LAYER);
5106 
5107 		VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, VS::SHADOW_CASTING_SETTING_OFF);
5108 	}
5109 
5110 	{
5111 
5112 		//move gizmo
5113 
5114 		for (int i = 0; i < 3; i++) {
5115 
5116 			Color col;
5117 			switch (i) {
5118 				case 0:
5119 					col = get_color("axis_x_color", "Editor");
5120 					break;
5121 				case 1:
5122 					col = get_color("axis_y_color", "Editor");
5123 					break;
5124 				case 2:
5125 					col = get_color("axis_z_color", "Editor");
5126 					break;
5127 				default:
5128 					col = Color();
5129 					break;
5130 			}
5131 
5132 			col.a = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_opacity");
5133 
5134 			move_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
5135 			move_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
5136 			rotate_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
5137 			scale_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
5138 			scale_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
5139 
5140 			Ref<SpatialMaterial> mat = memnew(SpatialMaterial);
5141 			mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
5142 			mat->set_on_top_of_alpha();
5143 			mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
5144 			mat->set_albedo(col);
5145 			gizmo_color[i] = mat;
5146 
5147 			Ref<SpatialMaterial> mat_hl = mat->duplicate();
5148 			mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
5149 			gizmo_color_hl[i] = mat_hl;
5150 
5151 			Vector3 ivec;
5152 			ivec[i] = 1;
5153 			Vector3 nivec;
5154 			nivec[(i + 1) % 3] = 1;
5155 			nivec[(i + 2) % 3] = 1;
5156 			Vector3 ivec2;
5157 			ivec2[(i + 1) % 3] = 1;
5158 			Vector3 ivec3;
5159 			ivec3[(i + 2) % 3] = 1;
5160 
5161 			//translate
5162 			{
5163 
5164 				Ref<SurfaceTool> surftool = memnew(SurfaceTool);
5165 				surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
5166 
5167 				// Arrow profile
5168 				const int arrow_points = 5;
5169 				Vector3 arrow[5] = {
5170 					nivec * 0.0 + ivec * 0.0,
5171 					nivec * 0.01 + ivec * 0.0,
5172 					nivec * 0.01 + ivec * GIZMO_ARROW_OFFSET,
5173 					nivec * 0.065 + ivec * GIZMO_ARROW_OFFSET,
5174 					nivec * 0.0 + ivec * (GIZMO_ARROW_OFFSET + GIZMO_ARROW_SIZE),
5175 				};
5176 
5177 				int arrow_sides = 16;
5178 
5179 				for (int k = 0; k < arrow_sides; k++) {
5180 
5181 					Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides);
5182 					Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides);
5183 
5184 					for (int j = 0; j < arrow_points - 1; j++) {
5185 
5186 						Vector3 points[4] = {
5187 							ma.xform(arrow[j]),
5188 							mb.xform(arrow[j]),
5189 							mb.xform(arrow[j + 1]),
5190 							ma.xform(arrow[j + 1]),
5191 						};
5192 						surftool->add_vertex(points[0]);
5193 						surftool->add_vertex(points[1]);
5194 						surftool->add_vertex(points[2]);
5195 
5196 						surftool->add_vertex(points[0]);
5197 						surftool->add_vertex(points[2]);
5198 						surftool->add_vertex(points[3]);
5199 					}
5200 				}
5201 
5202 				surftool->set_material(mat);
5203 				surftool->commit(move_gizmo[i]);
5204 			}
5205 
5206 			// Plane Translation
5207 			{
5208 				Ref<SurfaceTool> surftool = memnew(SurfaceTool);
5209 				surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
5210 
5211 				Vector3 vec = ivec2 - ivec3;
5212 				Vector3 plane[4] = {
5213 					vec * GIZMO_PLANE_DST,
5214 					vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE,
5215 					vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE),
5216 					vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE
5217 				};
5218 
5219 				Basis ma(ivec, Math_PI / 2);
5220 
5221 				Vector3 points[4] = {
5222 					ma.xform(plane[0]),
5223 					ma.xform(plane[1]),
5224 					ma.xform(plane[2]),
5225 					ma.xform(plane[3]),
5226 				};
5227 				surftool->add_vertex(points[0]);
5228 				surftool->add_vertex(points[1]);
5229 				surftool->add_vertex(points[2]);
5230 
5231 				surftool->add_vertex(points[0]);
5232 				surftool->add_vertex(points[2]);
5233 				surftool->add_vertex(points[3]);
5234 
5235 				Ref<SpatialMaterial> plane_mat = memnew(SpatialMaterial);
5236 				plane_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
5237 				plane_mat->set_on_top_of_alpha();
5238 				plane_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
5239 				plane_mat->set_cull_mode(SpatialMaterial::CULL_DISABLED);
5240 				plane_mat->set_albedo(col);
5241 				plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides
5242 				surftool->set_material(plane_mat);
5243 				surftool->commit(move_plane_gizmo[i]);
5244 
5245 				Ref<SpatialMaterial> plane_mat_hl = plane_mat->duplicate();
5246 				plane_mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
5247 				plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
5248 			}
5249 
5250 			// Rotate
5251 			{
5252 
5253 				Ref<SurfaceTool> surftool = memnew(SurfaceTool);
5254 				surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
5255 
5256 				Vector3 circle[5] = {
5257 					ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
5258 					ivec * -0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
5259 					ivec * -0.02 + ivec2 * -0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
5260 					ivec * 0.02 + ivec2 * -0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
5261 					ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE,
5262 				};
5263 
5264 				for (int k = 0; k < 64; k++) {
5265 
5266 					Basis ma(ivec, Math_PI * 2 * float(k) / 64);
5267 					Basis mb(ivec, Math_PI * 2 * float(k + 1) / 64);
5268 
5269 					for (int j = 0; j < 4; j++) {
5270 
5271 						Vector3 points[4] = {
5272 							ma.xform(circle[j]),
5273 							mb.xform(circle[j]),
5274 							mb.xform(circle[j + 1]),
5275 							ma.xform(circle[j + 1]),
5276 						};
5277 						surftool->add_vertex(points[0]);
5278 						surftool->add_vertex(points[1]);
5279 						surftool->add_vertex(points[2]);
5280 
5281 						surftool->add_vertex(points[0]);
5282 						surftool->add_vertex(points[2]);
5283 						surftool->add_vertex(points[3]);
5284 					}
5285 				}
5286 
5287 				surftool->set_material(mat);
5288 				surftool->commit(rotate_gizmo[i]);
5289 			}
5290 
5291 			// Scale
5292 			{
5293 				Ref<SurfaceTool> surftool = memnew(SurfaceTool);
5294 				surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
5295 
5296 				// Cube arrow profile
5297 				const int arrow_points = 6;
5298 				Vector3 arrow[6] = {
5299 					nivec * 0.0 + ivec * 0.0,
5300 					nivec * 0.01 + ivec * 0.0,
5301 					nivec * 0.01 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
5302 					nivec * 0.07 + ivec * 1.0 * GIZMO_SCALE_OFFSET,
5303 					nivec * 0.07 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
5304 					nivec * 0.0 + ivec * 1.11 * GIZMO_SCALE_OFFSET,
5305 				};
5306 
5307 				int arrow_sides = 4;
5308 
5309 				for (int k = 0; k < 4; k++) {
5310 
5311 					Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides);
5312 					Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides);
5313 
5314 					for (int j = 0; j < arrow_points - 1; j++) {
5315 
5316 						Vector3 points[4] = {
5317 							ma.xform(arrow[j]),
5318 							mb.xform(arrow[j]),
5319 							mb.xform(arrow[j + 1]),
5320 							ma.xform(arrow[j + 1]),
5321 						};
5322 						surftool->add_vertex(points[0]);
5323 						surftool->add_vertex(points[1]);
5324 						surftool->add_vertex(points[2]);
5325 
5326 						surftool->add_vertex(points[0]);
5327 						surftool->add_vertex(points[2]);
5328 						surftool->add_vertex(points[3]);
5329 					}
5330 				}
5331 
5332 				surftool->set_material(mat);
5333 				surftool->commit(scale_gizmo[i]);
5334 			}
5335 
5336 			// Plane Scale
5337 			{
5338 				Ref<SurfaceTool> surftool = memnew(SurfaceTool);
5339 				surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
5340 
5341 				Vector3 vec = ivec2 - ivec3;
5342 				Vector3 plane[4] = {
5343 					vec * GIZMO_PLANE_DST,
5344 					vec * GIZMO_PLANE_DST + ivec2 * GIZMO_PLANE_SIZE,
5345 					vec * (GIZMO_PLANE_DST + GIZMO_PLANE_SIZE),
5346 					vec * GIZMO_PLANE_DST - ivec3 * GIZMO_PLANE_SIZE
5347 				};
5348 
5349 				Basis ma(ivec, Math_PI / 2);
5350 
5351 				Vector3 points[4] = {
5352 					ma.xform(plane[0]),
5353 					ma.xform(plane[1]),
5354 					ma.xform(plane[2]),
5355 					ma.xform(plane[3]),
5356 				};
5357 				surftool->add_vertex(points[0]);
5358 				surftool->add_vertex(points[1]);
5359 				surftool->add_vertex(points[2]);
5360 
5361 				surftool->add_vertex(points[0]);
5362 				surftool->add_vertex(points[2]);
5363 				surftool->add_vertex(points[3]);
5364 
5365 				Ref<SpatialMaterial> plane_mat = memnew(SpatialMaterial);
5366 				plane_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
5367 				plane_mat->set_on_top_of_alpha();
5368 				plane_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
5369 				plane_mat->set_cull_mode(SpatialMaterial::CULL_DISABLED);
5370 				plane_mat->set_albedo(col);
5371 				plane_gizmo_color[i] = plane_mat; // needed, so we can draw planes from both sides
5372 				surftool->set_material(plane_mat);
5373 				surftool->commit(scale_plane_gizmo[i]);
5374 
5375 				Ref<SpatialMaterial> plane_mat_hl = plane_mat->duplicate();
5376 				plane_mat_hl->set_albedo(Color(col.r, col.g, col.b, 1.0));
5377 				plane_gizmo_color_hl[i] = plane_mat_hl; // needed, so we can draw planes from both sides
5378 			}
5379 		}
5380 	}
5381 
5382 	_generate_selection_box();
5383 }
5384 
_update_gizmos_menu()5385 void SpatialEditor::_update_gizmos_menu() {
5386 
5387 	gizmos_menu->clear();
5388 
5389 	for (int i = 0; i < gizmo_plugins_by_name.size(); ++i) {
5390 		if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
5391 		String plugin_name = gizmo_plugins_by_name[i]->get_name();
5392 		const int plugin_state = gizmo_plugins_by_name[i]->get_state();
5393 		gizmos_menu->add_multistate_item(TTR(plugin_name), 3, plugin_state, i);
5394 		const int idx = gizmos_menu->get_item_index(i);
5395 		gizmos_menu->set_item_tooltip(
5396 				idx,
5397 				TTR("Click to toggle between visibility states.\n\nOpen eye: Gizmo is visible.\nClosed eye: Gizmo is hidden.\nHalf-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."));
5398 		switch (plugin_state) {
5399 			case EditorSpatialGizmoPlugin::VISIBLE:
5400 				gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible"));
5401 				break;
5402 			case EditorSpatialGizmoPlugin::ON_TOP:
5403 				gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray"));
5404 				break;
5405 			case EditorSpatialGizmoPlugin::HIDDEN:
5406 				gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden"));
5407 				break;
5408 		}
5409 	}
5410 }
5411 
_update_gizmos_menu_theme()5412 void SpatialEditor::_update_gizmos_menu_theme() {
5413 	for (int i = 0; i < gizmo_plugins_by_name.size(); ++i) {
5414 		if (!gizmo_plugins_by_name[i]->can_be_hidden()) continue;
5415 		const int plugin_state = gizmo_plugins_by_name[i]->get_state();
5416 		const int idx = gizmos_menu->get_item_index(i);
5417 		switch (plugin_state) {
5418 			case EditorSpatialGizmoPlugin::VISIBLE:
5419 				gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible"));
5420 				break;
5421 			case EditorSpatialGizmoPlugin::ON_TOP:
5422 				gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray"));
5423 				break;
5424 			case EditorSpatialGizmoPlugin::HIDDEN:
5425 				gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden"));
5426 				break;
5427 		}
5428 	}
5429 }
5430 
_init_grid()5431 void SpatialEditor::_init_grid() {
5432 
5433 	PoolVector<Color> grid_colors[3];
5434 	PoolVector<Vector3> grid_points[3];
5435 
5436 	Color primary_grid_color = EditorSettings::get_singleton()->get("editors/3d/primary_grid_color");
5437 	Color secondary_grid_color = EditorSettings::get_singleton()->get("editors/3d/secondary_grid_color");
5438 	int grid_size = EditorSettings::get_singleton()->get("editors/3d/grid_size");
5439 	int primary_grid_steps = EditorSettings::get_singleton()->get("editors/3d/primary_grid_steps");
5440 
5441 	for (int i = 0; i < 3; i++) {
5442 		Vector3 axis;
5443 		axis[i] = 1;
5444 		Vector3 axis_n1;
5445 		axis_n1[(i + 1) % 3] = 1;
5446 		Vector3 axis_n2;
5447 		axis_n2[(i + 2) % 3] = 1;
5448 
5449 		for (int j = -grid_size; j <= grid_size; j++) {
5450 			Vector3 p1 = axis_n1 * j + axis_n2 * -grid_size;
5451 			Vector3 p1_dest = p1 * (-axis_n2 + axis_n1);
5452 			Vector3 p2 = axis_n2 * j + axis_n1 * -grid_size;
5453 			Vector3 p2_dest = p2 * (-axis_n1 + axis_n2);
5454 
5455 			Color line_color = secondary_grid_color;
5456 			if (origin_enabled && j == 0) {
5457 				// Don't draw the center lines of the grid if the origin is enabled
5458 				// The origin would overlap the grid lines in this case, causing flickering
5459 				continue;
5460 			} else if (j % primary_grid_steps == 0) {
5461 				line_color = primary_grid_color;
5462 			}
5463 
5464 			grid_points[i].push_back(p1);
5465 			grid_points[i].push_back(p1_dest);
5466 			grid_colors[i].push_back(line_color);
5467 			grid_colors[i].push_back(line_color);
5468 
5469 			grid_points[i].push_back(p2);
5470 			grid_points[i].push_back(p2_dest);
5471 			grid_colors[i].push_back(line_color);
5472 			grid_colors[i].push_back(line_color);
5473 		}
5474 
5475 		grid[i] = VisualServer::get_singleton()->mesh_create();
5476 		Array d;
5477 		d.resize(VS::ARRAY_MAX);
5478 		d[VisualServer::ARRAY_VERTEX] = grid_points[i];
5479 		d[VisualServer::ARRAY_COLOR] = grid_colors[i];
5480 		VisualServer::get_singleton()->mesh_add_surface_from_arrays(grid[i], VisualServer::PRIMITIVE_LINES, d);
5481 		VisualServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat->get_rid());
5482 		grid_instance[i] = VisualServer::get_singleton()->instance_create2(grid[i], get_tree()->get_root()->get_world()->get_scenario());
5483 
5484 		VisualServer::get_singleton()->instance_set_visible(grid_instance[i], grid_visible[i]);
5485 		VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
5486 		VS::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << SpatialEditorViewport::GIZMO_GRID_LAYER);
5487 	}
5488 }
5489 
_finish_indicators()5490 void SpatialEditor::_finish_indicators() {
5491 
5492 	VisualServer::get_singleton()->free(origin_instance);
5493 	VisualServer::get_singleton()->free(origin);
5494 
5495 	_finish_grid();
5496 }
5497 
_finish_grid()5498 void SpatialEditor::_finish_grid() {
5499 	for (int i = 0; i < 3; i++) {
5500 		VisualServer::get_singleton()->free(grid_instance[i]);
5501 		VisualServer::get_singleton()->free(grid[i]);
5502 	}
5503 }
5504 
is_any_freelook_active() const5505 bool SpatialEditor::is_any_freelook_active() const {
5506 	for (unsigned int i = 0; i < VIEWPORTS_COUNT; ++i) {
5507 		if (viewports[i]->is_freelook_active())
5508 			return true;
5509 	}
5510 	return false;
5511 }
5512 
_refresh_menu_icons()5513 void SpatialEditor::_refresh_menu_icons() {
5514 
5515 	bool all_locked = true;
5516 	bool all_grouped = true;
5517 
5518 	List<Node *> &selection = editor_selection->get_selected_node_list();
5519 
5520 	if (selection.empty()) {
5521 		all_locked = false;
5522 		all_grouped = false;
5523 	} else {
5524 		for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
5525 			if (Object::cast_to<Spatial>(E->get()) && !Object::cast_to<Spatial>(E->get())->has_meta("_edit_lock_")) {
5526 				all_locked = false;
5527 				break;
5528 			}
5529 		}
5530 		for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
5531 			if (Object::cast_to<Spatial>(E->get()) && !Object::cast_to<Spatial>(E->get())->has_meta("_edit_group_")) {
5532 				all_grouped = false;
5533 				break;
5534 			}
5535 		}
5536 	}
5537 
5538 	tool_button[TOOL_LOCK_SELECTED]->set_visible(!all_locked);
5539 	tool_button[TOOL_LOCK_SELECTED]->set_disabled(selection.empty());
5540 	tool_button[TOOL_UNLOCK_SELECTED]->set_visible(all_locked);
5541 
5542 	tool_button[TOOL_GROUP_SELECTED]->set_visible(!all_grouped);
5543 	tool_button[TOOL_GROUP_SELECTED]->set_disabled(selection.empty());
5544 	tool_button[TOOL_UNGROUP_SELECTED]->set_visible(all_grouped);
5545 }
5546 
5547 template <typename T>
_get_child_nodes(Node * parent_node)5548 Set<T *> _get_child_nodes(Node *parent_node) {
5549 	Set<T *> nodes = Set<T *>();
5550 	T *node = Node::cast_to<T>(parent_node);
5551 	if (node) {
5552 		nodes.insert(node);
5553 	}
5554 
5555 	for (int i = 0; i < parent_node->get_child_count(); i++) {
5556 		Node *child_node = parent_node->get_child(i);
5557 		Set<T *> child_nodes = _get_child_nodes<T>(child_node);
5558 		for (typename Set<T *>::Element *I = child_nodes.front(); I; I = I->next()) {
5559 			nodes.insert(I->get());
5560 		}
5561 	}
5562 
5563 	return nodes;
5564 }
5565 
_get_physics_bodies_rid(Node * node)5566 Set<RID> _get_physics_bodies_rid(Node *node) {
5567 	Set<RID> rids = Set<RID>();
5568 	PhysicsBody *pb = Node::cast_to<PhysicsBody>(node);
5569 	if (pb) {
5570 		rids.insert(pb->get_rid());
5571 	}
5572 	Set<PhysicsBody *> child_nodes = _get_child_nodes<PhysicsBody>(node);
5573 	for (Set<PhysicsBody *>::Element *I = child_nodes.front(); I; I = I->next()) {
5574 		rids.insert(I->get()->get_rid());
5575 	}
5576 
5577 	return rids;
5578 }
5579 
snap_selected_nodes_to_floor()5580 void SpatialEditor::snap_selected_nodes_to_floor() {
5581 	List<Node *> &selection = editor_selection->get_selected_node_list();
5582 	Dictionary snap_data;
5583 
5584 	for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
5585 		Spatial *sp = Object::cast_to<Spatial>(E->get());
5586 		if (sp) {
5587 			Vector3 from = Vector3();
5588 			Vector3 position_offset = Vector3();
5589 
5590 			// Priorities for snapping to floor are CollisionShapes, VisualInstances and then origin
5591 			Set<VisualInstance *> vi = _get_child_nodes<VisualInstance>(sp);
5592 			Set<CollisionShape *> cs = _get_child_nodes<CollisionShape>(sp);
5593 
5594 			if (cs.size()) {
5595 				AABB aabb = sp->get_global_transform().xform(cs.front()->get()->get_shape()->get_debug_mesh()->get_aabb());
5596 				for (Set<CollisionShape *>::Element *I = cs.front(); I; I = I->next()) {
5597 					aabb.merge_with(sp->get_global_transform().xform(I->get()->get_shape()->get_debug_mesh()->get_aabb()));
5598 				}
5599 				Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5);
5600 				from = aabb.position + size;
5601 				position_offset.y = from.y - sp->get_global_transform().origin.y;
5602 			} else if (vi.size()) {
5603 				AABB aabb = vi.front()->get()->get_transformed_aabb();
5604 				for (Set<VisualInstance *>::Element *I = vi.front(); I; I = I->next()) {
5605 					aabb.merge_with(I->get()->get_transformed_aabb());
5606 				}
5607 				Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5);
5608 				from = aabb.position + size;
5609 				position_offset.y = from.y - sp->get_global_transform().origin.y;
5610 			} else {
5611 				from = sp->get_global_transform().origin;
5612 			}
5613 
5614 			// We add a bit of margin to the from position to avoid it from snapping
5615 			// when the spatial is already on a floor and there's another floor under
5616 			// it
5617 			from = from + Vector3(0.0, 0.2, 0.0);
5618 
5619 			Dictionary d;
5620 
5621 			d["from"] = from;
5622 			d["position_offset"] = position_offset;
5623 			snap_data[sp] = d;
5624 		}
5625 	}
5626 
5627 	PhysicsDirectSpaceState *ss = get_tree()->get_root()->get_world()->get_direct_space_state();
5628 	PhysicsDirectSpaceState::RayResult result;
5629 
5630 	Array keys = snap_data.keys();
5631 
5632 	// The maximum height an object can travel to be snapped
5633 	const float max_snap_height = 20.0;
5634 
5635 	// Will be set to `true` if at least one node from the selection was successfully snapped
5636 	bool snapped_to_floor = false;
5637 
5638 	if (keys.size()) {
5639 		// For snapping to be performed, there must be solid geometry under at least one of the selected nodes.
5640 		// We need to check this before snapping to register the undo/redo action only if needed.
5641 		for (int i = 0; i < keys.size(); i++) {
5642 			Node *node = keys[i];
5643 			Spatial *sp = Object::cast_to<Spatial>(node);
5644 			Dictionary d = snap_data[node];
5645 			Vector3 from = d["from"];
5646 			Vector3 to = from - Vector3(0.0, max_snap_height, 0.0);
5647 			Set<RID> excluded = _get_physics_bodies_rid(sp);
5648 
5649 			if (ss->intersect_ray(from, to, result, excluded)) {
5650 				snapped_to_floor = true;
5651 			}
5652 		}
5653 
5654 		if (snapped_to_floor) {
5655 			undo_redo->create_action(TTR("Snap Nodes To Floor"));
5656 
5657 			// Perform snapping if at least one node can be snapped
5658 			for (int i = 0; i < keys.size(); i++) {
5659 				Node *node = keys[i];
5660 				Spatial *sp = Object::cast_to<Spatial>(node);
5661 				Dictionary d = snap_data[node];
5662 				Vector3 from = d["from"];
5663 				Vector3 to = from - Vector3(0.0, max_snap_height, 0.0);
5664 				Set<RID> excluded = _get_physics_bodies_rid(sp);
5665 
5666 				if (ss->intersect_ray(from, to, result, excluded)) {
5667 					Vector3 position_offset = d["position_offset"];
5668 					Transform new_transform = sp->get_global_transform();
5669 
5670 					new_transform.origin.y = result.position.y;
5671 					new_transform.origin = new_transform.origin - position_offset;
5672 
5673 					undo_redo->add_do_method(sp, "set_global_transform", new_transform);
5674 					undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform());
5675 				}
5676 			}
5677 
5678 			undo_redo->commit_action();
5679 		} else {
5680 			EditorNode::get_singleton()->show_warning(TTR("Couldn't find a solid floor to snap the selection to."));
5681 		}
5682 	}
5683 }
5684 
_unhandled_key_input(Ref<InputEvent> p_event)5685 void SpatialEditor::_unhandled_key_input(Ref<InputEvent> p_event) {
5686 
5687 	if (!is_visible_in_tree() || get_viewport()->gui_has_modal_stack())
5688 		return;
5689 
5690 	snap_key_enabled = Input::get_singleton()->is_key_pressed(KEY_CONTROL);
5691 }
_notification(int p_what)5692 void SpatialEditor::_notification(int p_what) {
5693 
5694 	if (p_what == NOTIFICATION_READY) {
5695 
5696 		tool_button[SpatialEditor::TOOL_MODE_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons"));
5697 		tool_button[SpatialEditor::TOOL_MODE_MOVE]->set_icon(get_icon("ToolMove", "EditorIcons"));
5698 		tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons"));
5699 		tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons"));
5700 		tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons"));
5701 		tool_button[SpatialEditor::TOOL_LOCK_SELECTED]->set_icon(get_icon("Lock", "EditorIcons"));
5702 		tool_button[SpatialEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_icon("Unlock", "EditorIcons"));
5703 		tool_button[SpatialEditor::TOOL_GROUP_SELECTED]->set_icon(get_icon("Group", "EditorIcons"));
5704 		tool_button[SpatialEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_icon("Ungroup", "EditorIcons"));
5705 
5706 		tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons"));
5707 		tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons"));
5708 		tool_option_button[SpatialEditor::TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_icon("Camera", "EditorIcons"));
5709 
5710 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons"));
5711 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons"));
5712 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_icon("Panels2Alt", "EditorIcons"));
5713 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_icon("Panels3", "EditorIcons"));
5714 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_icon("Panels3Alt", "EditorIcons"));
5715 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_icon("Panels4", "EditorIcons"));
5716 
5717 		_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
5718 
5719 		_refresh_menu_icons();
5720 
5721 		get_tree()->connect("node_removed", this, "_node_removed");
5722 		EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->connect("node_changed", this, "_refresh_menu_icons");
5723 		editor_selection->connect("selection_changed", this, "_refresh_menu_icons");
5724 
5725 		editor->connect("stop_pressed", this, "_update_camera_override_button", make_binds(false));
5726 		editor->connect("play_pressed", this, "_update_camera_override_button", make_binds(true));
5727 	} else if (p_what == NOTIFICATION_ENTER_TREE) {
5728 
5729 		_register_all_gizmos();
5730 		_update_gizmos_menu();
5731 		_init_indicators();
5732 	} else if (p_what == NOTIFICATION_THEME_CHANGED) {
5733 		_update_gizmos_menu_theme();
5734 	} else if (p_what == NOTIFICATION_EXIT_TREE) {
5735 
5736 		_finish_indicators();
5737 	} else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
5738 		tool_button[SpatialEditor::TOOL_MODE_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons"));
5739 		tool_button[SpatialEditor::TOOL_MODE_MOVE]->set_icon(get_icon("ToolMove", "EditorIcons"));
5740 		tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons"));
5741 		tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons"));
5742 		tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons"));
5743 		tool_button[SpatialEditor::TOOL_LOCK_SELECTED]->set_icon(get_icon("Lock", "EditorIcons"));
5744 		tool_button[SpatialEditor::TOOL_UNLOCK_SELECTED]->set_icon(get_icon("Unlock", "EditorIcons"));
5745 		tool_button[SpatialEditor::TOOL_GROUP_SELECTED]->set_icon(get_icon("Group", "EditorIcons"));
5746 		tool_button[SpatialEditor::TOOL_UNGROUP_SELECTED]->set_icon(get_icon("Ungroup", "EditorIcons"));
5747 
5748 		tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons"));
5749 		tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons"));
5750 
5751 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons"));
5752 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons"));
5753 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_icon("Panels2Alt", "EditorIcons"));
5754 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_icon("Panels3", "EditorIcons"));
5755 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_icon("Panels3Alt", "EditorIcons"));
5756 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_icon("Panels4", "EditorIcons"));
5757 
5758 		// Update grid color by rebuilding grid.
5759 		_finish_grid();
5760 		_init_grid();
5761 	} else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
5762 		if (!is_visible() && tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->is_pressed()) {
5763 			ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger();
5764 
5765 			debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
5766 			tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false);
5767 		}
5768 	}
5769 }
5770 
add_control_to_menu_panel(Control * p_control)5771 void SpatialEditor::add_control_to_menu_panel(Control *p_control) {
5772 
5773 	hbc_menu->add_child(p_control);
5774 }
5775 
remove_control_from_menu_panel(Control * p_control)5776 void SpatialEditor::remove_control_from_menu_panel(Control *p_control) {
5777 
5778 	hbc_menu->remove_child(p_control);
5779 }
5780 
set_can_preview(Camera * p_preview)5781 void SpatialEditor::set_can_preview(Camera *p_preview) {
5782 
5783 	for (int i = 0; i < 4; i++) {
5784 		viewports[i]->set_can_preview(p_preview);
5785 	}
5786 }
5787 
get_shader_split()5788 VSplitContainer *SpatialEditor::get_shader_split() {
5789 
5790 	return shader_split;
5791 }
5792 
get_palette_split()5793 HSplitContainer *SpatialEditor::get_palette_split() {
5794 
5795 	return palette_split;
5796 }
5797 
_request_gizmo(Object * p_obj)5798 void SpatialEditor::_request_gizmo(Object *p_obj) {
5799 
5800 	Spatial *sp = Object::cast_to<Spatial>(p_obj);
5801 	if (!sp)
5802 		return;
5803 	if (editor->get_edited_scene() && (sp == editor->get_edited_scene() || (sp->get_owner() && editor->get_edited_scene()->is_a_parent_of(sp)))) {
5804 
5805 		Ref<EditorSpatialGizmo> seg;
5806 
5807 		for (int i = 0; i < gizmo_plugins_by_priority.size(); ++i) {
5808 			seg = gizmo_plugins_by_priority.write[i]->get_gizmo(sp);
5809 
5810 			if (seg.is_valid()) {
5811 				sp->set_gizmo(seg);
5812 
5813 				if (sp == selected) {
5814 					seg->set_selected(true);
5815 					selected->update_gizmo();
5816 				}
5817 
5818 				break;
5819 			}
5820 		}
5821 	}
5822 }
5823 
_toggle_maximize_view(Object * p_viewport)5824 void SpatialEditor::_toggle_maximize_view(Object *p_viewport) {
5825 	if (!p_viewport) return;
5826 	SpatialEditorViewport *current_viewport = Object::cast_to<SpatialEditorViewport>(p_viewport);
5827 	if (!current_viewport) return;
5828 
5829 	int index = -1;
5830 	bool maximized = false;
5831 	for (int i = 0; i < 4; i++) {
5832 		if (viewports[i] == current_viewport) {
5833 			index = i;
5834 			if (current_viewport->get_global_rect() == viewport_base->get_global_rect())
5835 				maximized = true;
5836 			break;
5837 		}
5838 	}
5839 	if (index == -1) return;
5840 
5841 	if (!maximized) {
5842 
5843 		for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
5844 			if (i == (uint32_t)index)
5845 				viewports[i]->set_anchors_and_margins_preset(Control::PRESET_WIDE);
5846 			else
5847 				viewports[i]->hide();
5848 		}
5849 	} else {
5850 
5851 		for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++)
5852 			viewports[i]->show();
5853 
5854 		if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT)))
5855 			_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
5856 		else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS)))
5857 			_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
5858 		else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT)))
5859 			_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
5860 		else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS)))
5861 			_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
5862 		else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT)))
5863 			_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
5864 		else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS)))
5865 			_menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
5866 	}
5867 }
5868 
_node_removed(Node * p_node)5869 void SpatialEditor::_node_removed(Node *p_node) {
5870 
5871 	if (p_node == selected)
5872 		selected = NULL;
5873 }
5874 
_register_all_gizmos()5875 void SpatialEditor::_register_all_gizmos() {
5876 	add_gizmo_plugin(Ref<CameraSpatialGizmoPlugin>(memnew(CameraSpatialGizmoPlugin)));
5877 	add_gizmo_plugin(Ref<LightSpatialGizmoPlugin>(memnew(LightSpatialGizmoPlugin)));
5878 	add_gizmo_plugin(Ref<AudioStreamPlayer3DSpatialGizmoPlugin>(memnew(AudioStreamPlayer3DSpatialGizmoPlugin)));
5879 	add_gizmo_plugin(Ref<MeshInstanceSpatialGizmoPlugin>(memnew(MeshInstanceSpatialGizmoPlugin)));
5880 	add_gizmo_plugin(Ref<SoftBodySpatialGizmoPlugin>(memnew(SoftBodySpatialGizmoPlugin)));
5881 	add_gizmo_plugin(Ref<Sprite3DSpatialGizmoPlugin>(memnew(Sprite3DSpatialGizmoPlugin)));
5882 	add_gizmo_plugin(Ref<SkeletonSpatialGizmoPlugin>(memnew(SkeletonSpatialGizmoPlugin)));
5883 	add_gizmo_plugin(Ref<Position3DSpatialGizmoPlugin>(memnew(Position3DSpatialGizmoPlugin)));
5884 	add_gizmo_plugin(Ref<RayCastSpatialGizmoPlugin>(memnew(RayCastSpatialGizmoPlugin)));
5885 	add_gizmo_plugin(Ref<SpringArmSpatialGizmoPlugin>(memnew(SpringArmSpatialGizmoPlugin)));
5886 	add_gizmo_plugin(Ref<VehicleWheelSpatialGizmoPlugin>(memnew(VehicleWheelSpatialGizmoPlugin)));
5887 	add_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin)));
5888 	add_gizmo_plugin(Ref<ParticlesGizmoPlugin>(memnew(ParticlesGizmoPlugin)));
5889 	add_gizmo_plugin(Ref<CPUParticlesGizmoPlugin>(memnew(CPUParticlesGizmoPlugin)));
5890 	add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin)));
5891 	add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin)));
5892 	add_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin)));
5893 	add_gizmo_plugin(Ref<CollisionShapeSpatialGizmoPlugin>(memnew(CollisionShapeSpatialGizmoPlugin)));
5894 	add_gizmo_plugin(Ref<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin)));
5895 	add_gizmo_plugin(Ref<NavigationMeshSpatialGizmoPlugin>(memnew(NavigationMeshSpatialGizmoPlugin)));
5896 	add_gizmo_plugin(Ref<JointSpatialGizmoPlugin>(memnew(JointSpatialGizmoPlugin)));
5897 	add_gizmo_plugin(Ref<PhysicalBoneSpatialGizmoPlugin>(memnew(PhysicalBoneSpatialGizmoPlugin)));
5898 }
5899 
_bind_methods()5900 void SpatialEditor::_bind_methods() {
5901 
5902 	ClassDB::bind_method("_unhandled_key_input", &SpatialEditor::_unhandled_key_input);
5903 	ClassDB::bind_method("_node_removed", &SpatialEditor::_node_removed);
5904 	ClassDB::bind_method("_menu_item_pressed", &SpatialEditor::_menu_item_pressed);
5905 	ClassDB::bind_method("_menu_gizmo_toggled", &SpatialEditor::_menu_gizmo_toggled);
5906 	ClassDB::bind_method("_menu_item_toggled", &SpatialEditor::_menu_item_toggled);
5907 	ClassDB::bind_method("_xform_dialog_action", &SpatialEditor::_xform_dialog_action);
5908 	ClassDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data);
5909 	ClassDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo);
5910 	ClassDB::bind_method("_toggle_maximize_view", &SpatialEditor::_toggle_maximize_view);
5911 	ClassDB::bind_method("_refresh_menu_icons", &SpatialEditor::_refresh_menu_icons);
5912 	ClassDB::bind_method("_update_camera_override_button", &SpatialEditor::_update_camera_override_button);
5913 	ClassDB::bind_method("_update_camera_override_viewport", &SpatialEditor::_update_camera_override_viewport);
5914 	ClassDB::bind_method("_snap_changed", &SpatialEditor::_snap_changed);
5915 	ClassDB::bind_method("_snap_update", &SpatialEditor::_snap_update);
5916 
5917 	ADD_SIGNAL(MethodInfo("transform_key_request"));
5918 	ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
5919 	ADD_SIGNAL(MethodInfo("item_group_status_changed"));
5920 }
5921 
clear()5922 void SpatialEditor::clear() {
5923 
5924 	settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 70.0));
5925 	settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near", 0.05));
5926 	settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500.0));
5927 
5928 	for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
5929 		viewports[i]->reset();
5930 	}
5931 
5932 	VisualServer::get_singleton()->instance_set_visible(origin_instance, true);
5933 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), true);
5934 	for (int i = 0; i < 3; ++i) {
5935 		if (grid_enable[i]) {
5936 			VisualServer::get_singleton()->instance_set_visible(grid_instance[i], true);
5937 			grid_visible[i] = true;
5938 		}
5939 	}
5940 
5941 	for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
5942 
5943 		viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(SpatialEditorViewport::VIEW_AUDIO_LISTENER), i == 0);
5944 		viewports[i]->viewport->set_as_audio_listener(i == 0);
5945 	}
5946 
5947 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), true);
5948 }
5949 
SpatialEditor(EditorNode * p_editor)5950 SpatialEditor::SpatialEditor(EditorNode *p_editor) {
5951 
5952 	gizmo.visible = true;
5953 	gizmo.scale = 1.0;
5954 
5955 	viewport_environment = Ref<Environment>(memnew(Environment));
5956 	undo_redo = p_editor->get_undo_redo();
5957 	VBoxContainer *vbc = this;
5958 
5959 	custom_camera = NULL;
5960 	singleton = this;
5961 	editor = p_editor;
5962 	editor_selection = editor->get_editor_selection();
5963 	editor_selection->add_editor_plugin(this);
5964 
5965 	snap_enabled = false;
5966 	snap_key_enabled = false;
5967 	tool_mode = TOOL_MODE_SELECT;
5968 
5969 	camera_override_viewport_id = 0;
5970 
5971 	hbc_menu = memnew(HBoxContainer);
5972 	vbc->add_child(hbc_menu);
5973 
5974 	Vector<Variant> button_binds;
5975 	button_binds.resize(1);
5976 	String sct;
5977 
5978 	tool_button[TOOL_MODE_SELECT] = memnew(ToolButton);
5979 	hbc_menu->add_child(tool_button[TOOL_MODE_SELECT]);
5980 	tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true);
5981 	tool_button[TOOL_MODE_SELECT]->set_flat(true);
5982 	tool_button[TOOL_MODE_SELECT]->set_pressed(true);
5983 	button_binds.write[0] = MENU_TOOL_SELECT;
5984 	tool_button[TOOL_MODE_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds);
5985 	tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), KEY_Q));
5986 	tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection"));
5987 
5988 	hbc_menu->add_child(memnew(VSeparator));
5989 
5990 	tool_button[TOOL_MODE_MOVE] = memnew(ToolButton);
5991 	hbc_menu->add_child(tool_button[TOOL_MODE_MOVE]);
5992 	tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true);
5993 	tool_button[TOOL_MODE_MOVE]->set_flat(true);
5994 	button_binds.write[0] = MENU_TOOL_MOVE;
5995 	tool_button[TOOL_MODE_MOVE]->connect("pressed", this, "_menu_item_pressed", button_binds);
5996 	tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), KEY_W));
5997 
5998 	tool_button[TOOL_MODE_ROTATE] = memnew(ToolButton);
5999 	hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]);
6000 	tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true);
6001 	tool_button[TOOL_MODE_ROTATE]->set_flat(true);
6002 	button_binds.write[0] = MENU_TOOL_ROTATE;
6003 	tool_button[TOOL_MODE_ROTATE]->connect("pressed", this, "_menu_item_pressed", button_binds);
6004 	tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), KEY_E));
6005 
6006 	tool_button[TOOL_MODE_SCALE] = memnew(ToolButton);
6007 	hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]);
6008 	tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true);
6009 	tool_button[TOOL_MODE_SCALE]->set_flat(true);
6010 	button_binds.write[0] = MENU_TOOL_SCALE;
6011 	tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds);
6012 	tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), KEY_R));
6013 
6014 	hbc_menu->add_child(memnew(VSeparator));
6015 
6016 	tool_button[TOOL_MODE_LIST_SELECT] = memnew(ToolButton);
6017 	hbc_menu->add_child(tool_button[TOOL_MODE_LIST_SELECT]);
6018 	tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true);
6019 	tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true);
6020 	button_binds.write[0] = MENU_TOOL_LIST_SELECT;
6021 	tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds);
6022 	tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show a list of all objects at the position clicked\n(same as Alt+RMB in select mode)."));
6023 
6024 	tool_button[TOOL_LOCK_SELECTED] = memnew(ToolButton);
6025 	hbc_menu->add_child(tool_button[TOOL_LOCK_SELECTED]);
6026 	button_binds.write[0] = MENU_LOCK_SELECTED;
6027 	tool_button[TOOL_LOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
6028 	tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock the selected object in place (can't be moved)."));
6029 
6030 	tool_button[TOOL_UNLOCK_SELECTED] = memnew(ToolButton);
6031 	hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]);
6032 	button_binds.write[0] = MENU_UNLOCK_SELECTED;
6033 	tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
6034 	tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock the selected object (can be moved)."));
6035 
6036 	tool_button[TOOL_GROUP_SELECTED] = memnew(ToolButton);
6037 	hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]);
6038 	button_binds.write[0] = MENU_GROUP_SELECTED;
6039 	tool_button[TOOL_GROUP_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
6040 	tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable."));
6041 
6042 	tool_button[TOOL_UNGROUP_SELECTED] = memnew(ToolButton);
6043 	hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
6044 	button_binds.write[0] = MENU_UNGROUP_SELECTED;
6045 	tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", this, "_menu_item_pressed", button_binds);
6046 	tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected."));
6047 
6048 	hbc_menu->add_child(memnew(VSeparator));
6049 
6050 	tool_option_button[TOOL_OPT_LOCAL_COORDS] = memnew(ToolButton);
6051 	hbc_menu->add_child(tool_option_button[TOOL_OPT_LOCAL_COORDS]);
6052 	tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_toggle_mode(true);
6053 	tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true);
6054 	button_binds.write[0] = MENU_TOOL_LOCAL_COORDS;
6055 	tool_option_button[TOOL_OPT_LOCAL_COORDS]->connect("toggled", this, "_menu_item_toggled", button_binds);
6056 	tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Use Local Space"), KEY_T));
6057 
6058 	tool_option_button[TOOL_OPT_USE_SNAP] = memnew(ToolButton);
6059 	hbc_menu->add_child(tool_option_button[TOOL_OPT_USE_SNAP]);
6060 	tool_option_button[TOOL_OPT_USE_SNAP]->set_toggle_mode(true);
6061 	tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true);
6062 	button_binds.write[0] = MENU_TOOL_USE_SNAP;
6063 	tool_option_button[TOOL_OPT_USE_SNAP]->connect("toggled", this, "_menu_item_toggled", button_binds);
6064 	tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), KEY_Y));
6065 
6066 	hbc_menu->add_child(memnew(VSeparator));
6067 
6068 	tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(ToolButton);
6069 	hbc_menu->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]);
6070 	tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true);
6071 	tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_flat(true);
6072 	tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true);
6073 	button_binds.write[0] = MENU_TOOL_OVERRIDE_CAMERA;
6074 	tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect("toggled", this, "_menu_item_toggled", button_binds);
6075 	_update_camera_override_button(false);
6076 
6077 	hbc_menu->add_child(memnew(VSeparator));
6078 
6079 	// Drag and drop support;
6080 	preview_node = memnew(Spatial);
6081 	preview_bounds = AABB();
6082 
6083 	ED_SHORTCUT("spatial_editor/bottom_view", TTR("Bottom View"), KEY_MASK_ALT + KEY_KP_7);
6084 	ED_SHORTCUT("spatial_editor/top_view", TTR("Top View"), KEY_KP_7);
6085 	ED_SHORTCUT("spatial_editor/rear_view", TTR("Rear View"), KEY_MASK_ALT + KEY_KP_1);
6086 	ED_SHORTCUT("spatial_editor/front_view", TTR("Front View"), KEY_KP_1);
6087 	ED_SHORTCUT("spatial_editor/left_view", TTR("Left View"), KEY_MASK_ALT + KEY_KP_3);
6088 	ED_SHORTCUT("spatial_editor/right_view", TTR("Right View"), KEY_KP_3);
6089 	ED_SHORTCUT("spatial_editor/switch_perspective_orthogonal", TTR("Switch Perspective/Orthogonal View"), KEY_KP_5);
6090 	ED_SHORTCUT("spatial_editor/insert_anim_key", TTR("Insert Animation Key"), KEY_K);
6091 	ED_SHORTCUT("spatial_editor/focus_origin", TTR("Focus Origin"), KEY_O);
6092 	ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), KEY_F);
6093 	ED_SHORTCUT("spatial_editor/align_transform_with_view", TTR("Align Transform with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_M);
6094 	ED_SHORTCUT("spatial_editor/align_rotation_with_view", TTR("Align Rotation with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_F);
6095 	ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F);
6096 
6097 	PopupMenu *p;
6098 
6099 	transform_menu = memnew(MenuButton);
6100 	transform_menu->set_text(TTR("Transform"));
6101 	transform_menu->set_switch_on_hover(true);
6102 	hbc_menu->add_child(transform_menu);
6103 
6104 	p = transform_menu->get_popup();
6105 	p->add_shortcut(ED_SHORTCUT("spatial_editor/snap_to_floor", TTR("Snap Object to Floor"), KEY_PAGEDOWN), MENU_SNAP_TO_FLOOR);
6106 	p->add_shortcut(ED_SHORTCUT("spatial_editor/transform_dialog", TTR("Transform Dialog...")), MENU_TRANSFORM_DIALOG);
6107 
6108 	p->add_separator();
6109 	p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap...")), MENU_TRANSFORM_CONFIGURE_SNAP);
6110 
6111 	p->connect("id_pressed", this, "_menu_item_pressed");
6112 
6113 	view_menu = memnew(MenuButton);
6114 	view_menu->set_text(TTR("View"));
6115 	view_menu->set_switch_on_hover(true);
6116 	hbc_menu->add_child(view_menu);
6117 
6118 	p = view_menu->get_popup();
6119 
6120 	accept = memnew(AcceptDialog);
6121 	editor->get_gui_base()->add_child(accept);
6122 
6123 	p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/1_viewport", TTR("1 Viewport"), KEY_MASK_CMD + KEY_1), MENU_VIEW_USE_1_VIEWPORT);
6124 	p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports", TTR("2 Viewports"), KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS);
6125 	p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports_alt", TTR("2 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS_ALT);
6126 	p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports", TTR("3 Viewports"), KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS);
6127 	p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports_alt", TTR("3 Viewports (Alt)"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS_ALT);
6128 	p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KEY_MASK_CMD + KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
6129 	p->add_separator();
6130 
6131 	p->add_submenu_item(TTR("Gizmos"), "GizmosMenu");
6132 
6133 	p->add_separator();
6134 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
6135 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid")), MENU_VIEW_GRID);
6136 
6137 	p->add_separator();
6138 	p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS);
6139 
6140 	p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true);
6141 	p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true);
6142 
6143 	p->connect("id_pressed", this, "_menu_item_pressed");
6144 
6145 	gizmos_menu = memnew(PopupMenu);
6146 	p->add_child(gizmos_menu);
6147 	gizmos_menu->set_name("GizmosMenu");
6148 	gizmos_menu->set_hide_on_checkable_item_selection(false);
6149 	gizmos_menu->connect("id_pressed", this, "_menu_gizmo_toggled");
6150 
6151 	/* REST OF MENU */
6152 
6153 	palette_split = memnew(HSplitContainer);
6154 	palette_split->set_v_size_flags(SIZE_EXPAND_FILL);
6155 	vbc->add_child(palette_split);
6156 
6157 	shader_split = memnew(VSplitContainer);
6158 	shader_split->set_h_size_flags(SIZE_EXPAND_FILL);
6159 	palette_split->add_child(shader_split);
6160 	viewport_base = memnew(SpatialEditorViewportContainer);
6161 	shader_split->add_child(viewport_base);
6162 	viewport_base->set_v_size_flags(SIZE_EXPAND_FILL);
6163 	for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
6164 
6165 		viewports[i] = memnew(SpatialEditorViewport(this, editor, i));
6166 		viewports[i]->connect("toggle_maximize_view", this, "_toggle_maximize_view");
6167 		viewports[i]->connect("clicked", this, "_update_camera_override_viewport");
6168 		viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept);
6169 		viewport_base->add_child(viewports[i]);
6170 	}
6171 
6172 	/* SNAP DIALOG */
6173 
6174 	snap_translate_value = 1;
6175 	snap_rotate_value = 15;
6176 	snap_scale_value = 10;
6177 
6178 	snap_dialog = memnew(ConfirmationDialog);
6179 	snap_dialog->set_title(TTR("Snap Settings"));
6180 	add_child(snap_dialog);
6181 	snap_dialog->connect("confirmed", this, "_snap_changed");
6182 	snap_dialog->get_cancel()->connect("pressed", this, "_snap_update");
6183 
6184 	VBoxContainer *snap_dialog_vbc = memnew(VBoxContainer);
6185 	snap_dialog->add_child(snap_dialog_vbc);
6186 
6187 	snap_translate = memnew(LineEdit);
6188 	snap_dialog_vbc->add_margin_child(TTR("Translate Snap:"), snap_translate);
6189 
6190 	snap_rotate = memnew(LineEdit);
6191 	snap_dialog_vbc->add_margin_child(TTR("Rotate Snap (deg.):"), snap_rotate);
6192 
6193 	snap_scale = memnew(LineEdit);
6194 	snap_dialog_vbc->add_margin_child(TTR("Scale Snap (%):"), snap_scale);
6195 
6196 	_snap_update();
6197 
6198 	/* SETTINGS DIALOG */
6199 
6200 	settings_dialog = memnew(ConfirmationDialog);
6201 	settings_dialog->set_title(TTR("Viewport Settings"));
6202 	add_child(settings_dialog);
6203 	settings_vbc = memnew(VBoxContainer);
6204 	settings_vbc->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
6205 	settings_dialog->add_child(settings_vbc);
6206 
6207 	settings_fov = memnew(SpinBox);
6208 	settings_fov->set_max(MAX_FOV);
6209 	settings_fov->set_min(MIN_FOV);
6210 	settings_fov->set_step(0.01);
6211 	settings_fov->set_value(EDITOR_DEF("editors/3d/default_fov", 70.0));
6212 	settings_vbc->add_margin_child(TTR("Perspective FOV (deg.):"), settings_fov);
6213 
6214 	settings_znear = memnew(SpinBox);
6215 	settings_znear->set_max(MAX_Z);
6216 	settings_znear->set_min(MIN_Z);
6217 	settings_znear->set_step(0.01);
6218 	settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near", 0.05));
6219 	settings_vbc->add_margin_child(TTR("View Z-Near:"), settings_znear);
6220 
6221 	settings_zfar = memnew(SpinBox);
6222 	settings_zfar->set_max(MAX_Z);
6223 	settings_zfar->set_min(MIN_Z);
6224 	settings_zfar->set_step(0.01);
6225 	settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500));
6226 	settings_vbc->add_margin_child(TTR("View Z-Far:"), settings_zfar);
6227 
6228 	for (uint32_t i = 0; i < VIEWPORTS_COUNT; ++i) {
6229 		settings_dialog->connect("confirmed", viewports[i], "_update_camera", varray(0.0));
6230 	}
6231 
6232 	/* XFORM DIALOG */
6233 
6234 	xform_dialog = memnew(ConfirmationDialog);
6235 	xform_dialog->set_title(TTR("Transform Change"));
6236 	add_child(xform_dialog);
6237 
6238 	VBoxContainer *xform_vbc = memnew(VBoxContainer);
6239 	xform_dialog->add_child(xform_vbc);
6240 
6241 	Label *l = memnew(Label);
6242 	l->set_text(TTR("Translate:"));
6243 	xform_vbc->add_child(l);
6244 
6245 	HBoxContainer *xform_hbc = memnew(HBoxContainer);
6246 	xform_vbc->add_child(xform_hbc);
6247 
6248 	for (int i = 0; i < 3; i++) {
6249 
6250 		xform_translate[i] = memnew(LineEdit);
6251 		xform_translate[i]->set_h_size_flags(SIZE_EXPAND_FILL);
6252 		xform_hbc->add_child(xform_translate[i]);
6253 	}
6254 
6255 	l = memnew(Label);
6256 	l->set_text(TTR("Rotate (deg.):"));
6257 	xform_vbc->add_child(l);
6258 
6259 	xform_hbc = memnew(HBoxContainer);
6260 	xform_vbc->add_child(xform_hbc);
6261 
6262 	for (int i = 0; i < 3; i++) {
6263 		xform_rotate[i] = memnew(LineEdit);
6264 		xform_rotate[i]->set_h_size_flags(SIZE_EXPAND_FILL);
6265 		xform_hbc->add_child(xform_rotate[i]);
6266 	}
6267 
6268 	l = memnew(Label);
6269 	l->set_text(TTR("Scale (ratio):"));
6270 	xform_vbc->add_child(l);
6271 
6272 	xform_hbc = memnew(HBoxContainer);
6273 	xform_vbc->add_child(xform_hbc);
6274 
6275 	for (int i = 0; i < 3; i++) {
6276 		xform_scale[i] = memnew(LineEdit);
6277 		xform_scale[i]->set_h_size_flags(SIZE_EXPAND_FILL);
6278 		xform_hbc->add_child(xform_scale[i]);
6279 	}
6280 
6281 	l = memnew(Label);
6282 	l->set_text(TTR("Transform Type"));
6283 	xform_vbc->add_child(l);
6284 
6285 	xform_type = memnew(OptionButton);
6286 	xform_type->set_h_size_flags(SIZE_EXPAND_FILL);
6287 	xform_type->add_item(TTR("Pre"));
6288 	xform_type->add_item(TTR("Post"));
6289 	xform_vbc->add_child(xform_type);
6290 
6291 	xform_dialog->connect("confirmed", this, "_xform_dialog_action");
6292 
6293 	scenario_debug = VisualServer::SCENARIO_DEBUG_DISABLED;
6294 
6295 	selected = NULL;
6296 
6297 	set_process_unhandled_key_input(true);
6298 	add_to_group("_spatial_editor_group");
6299 
6300 	EDITOR_DEF("editors/3d/manipulator_gizmo_size", 80);
6301 	EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d/manipulator_gizmo_size", PROPERTY_HINT_RANGE, "16,1024,1"));
6302 	EDITOR_DEF("editors/3d/manipulator_gizmo_opacity", 0.4);
6303 	EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::REAL, "editors/3d/manipulator_gizmo_opacity", PROPERTY_HINT_RANGE, "0,1,0.01"));
6304 	EDITOR_DEF("editors/3d/navigation/show_viewport_rotation_gizmo", true);
6305 
6306 	over_gizmo_handle = -1;
6307 }
6308 
~SpatialEditor()6309 SpatialEditor::~SpatialEditor() {
6310 	memdelete(preview_node);
6311 }
6312 
make_visible(bool p_visible)6313 void SpatialEditorPlugin::make_visible(bool p_visible) {
6314 
6315 	if (p_visible) {
6316 
6317 		spatial_editor->show();
6318 		spatial_editor->set_process(true);
6319 
6320 	} else {
6321 
6322 		spatial_editor->hide();
6323 		spatial_editor->set_process(false);
6324 	}
6325 }
edit(Object * p_object)6326 void SpatialEditorPlugin::edit(Object *p_object) {
6327 
6328 	spatial_editor->edit(Object::cast_to<Spatial>(p_object));
6329 }
6330 
handles(Object * p_object) const6331 bool SpatialEditorPlugin::handles(Object *p_object) const {
6332 
6333 	return p_object->is_class("Spatial");
6334 }
6335 
get_state() const6336 Dictionary SpatialEditorPlugin::get_state() const {
6337 	return spatial_editor->get_state();
6338 }
6339 
set_state(const Dictionary & p_state)6340 void SpatialEditorPlugin::set_state(const Dictionary &p_state) {
6341 
6342 	spatial_editor->set_state(p_state);
6343 }
6344 
snap_cursor_to_plane(const Plane & p_plane)6345 void SpatialEditor::snap_cursor_to_plane(const Plane &p_plane) {
6346 
6347 	//cursor.pos=p_plane.project(cursor.pos);
6348 }
6349 
snap_point(Vector3 p_target,Vector3 p_start) const6350 Vector3 SpatialEditor::snap_point(Vector3 p_target, Vector3 p_start) const {
6351 	if (is_snap_enabled()) {
6352 		p_target.x = Math::snap_scalar(0.0, get_translate_snap(), p_target.x);
6353 		p_target.y = Math::snap_scalar(0.0, get_translate_snap(), p_target.y);
6354 		p_target.z = Math::snap_scalar(0.0, get_translate_snap(), p_target.z);
6355 	}
6356 	return p_target;
6357 }
6358 
get_translate_snap() const6359 float SpatialEditor::get_translate_snap() const {
6360 	float snap_value;
6361 	if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
6362 		snap_value = snap_translate->get_text().to_double() / 10.0;
6363 	} else {
6364 		snap_value = snap_translate->get_text().to_double();
6365 	}
6366 
6367 	return snap_value;
6368 }
6369 
get_rotate_snap() const6370 float SpatialEditor::get_rotate_snap() const {
6371 	float snap_value;
6372 	if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
6373 		snap_value = snap_rotate->get_text().to_double() / 3.0;
6374 	} else {
6375 		snap_value = snap_rotate->get_text().to_double();
6376 	}
6377 
6378 	return snap_value;
6379 }
6380 
get_scale_snap() const6381 float SpatialEditor::get_scale_snap() const {
6382 	float snap_value;
6383 	if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {
6384 		snap_value = snap_scale->get_text().to_double() / 2.0;
6385 	} else {
6386 		snap_value = snap_scale->get_text().to_double();
6387 	}
6388 
6389 	return snap_value;
6390 }
6391 
_bind_methods()6392 void SpatialEditorPlugin::_bind_methods() {
6393 
6394 	ClassDB::bind_method("snap_cursor_to_plane", &SpatialEditorPlugin::snap_cursor_to_plane);
6395 }
6396 
snap_cursor_to_plane(const Plane & p_plane)6397 void SpatialEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) {
6398 
6399 	spatial_editor->snap_cursor_to_plane(p_plane);
6400 }
6401 
6402 struct _GizmoPluginPriorityComparator {
6403 
operator ()_GizmoPluginPriorityComparator6404 	bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const {
6405 		if (p_a->get_priority() == p_b->get_priority()) {
6406 			return p_a->get_name() < p_b->get_name();
6407 		}
6408 		return p_a->get_priority() > p_b->get_priority();
6409 	}
6410 };
6411 
6412 struct _GizmoPluginNameComparator {
6413 
operator ()_GizmoPluginNameComparator6414 	bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const {
6415 		return p_a->get_name() < p_b->get_name();
6416 	}
6417 };
6418 
add_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin)6419 void SpatialEditor::add_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin) {
6420 	ERR_FAIL_NULL(p_plugin.ptr());
6421 
6422 	gizmo_plugins_by_priority.push_back(p_plugin);
6423 	gizmo_plugins_by_priority.sort_custom<_GizmoPluginPriorityComparator>();
6424 
6425 	gizmo_plugins_by_name.push_back(p_plugin);
6426 	gizmo_plugins_by_name.sort_custom<_GizmoPluginNameComparator>();
6427 
6428 	_update_gizmos_menu();
6429 	SpatialEditor::get_singleton()->update_all_gizmos();
6430 }
6431 
remove_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin)6432 void SpatialEditor::remove_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> p_plugin) {
6433 	gizmo_plugins_by_priority.erase(p_plugin);
6434 	gizmo_plugins_by_name.erase(p_plugin);
6435 	_update_gizmos_menu();
6436 }
6437 
SpatialEditorPlugin(EditorNode * p_node)6438 SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) {
6439 
6440 	editor = p_node;
6441 	spatial_editor = memnew(SpatialEditor(p_node));
6442 	spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
6443 	editor->get_viewport()->add_child(spatial_editor);
6444 
6445 	spatial_editor->hide();
6446 	spatial_editor->connect("transform_key_request", editor->get_inspector_dock(), "_transform_keyed");
6447 }
6448 
~SpatialEditorPlugin()6449 SpatialEditorPlugin::~SpatialEditorPlugin() {
6450 }
6451 
create_material(const String & p_name,const Color & p_color,bool p_billboard,bool p_on_top,bool p_use_vertex_color)6452 void EditorSpatialGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) {
6453 
6454 	Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6));
6455 
6456 	Vector<Ref<SpatialMaterial> > mats;
6457 
6458 	for (int i = 0; i < 4; i++) {
6459 		bool selected = i % 2 == 1;
6460 		bool instanced = i < 2;
6461 
6462 		Ref<SpatialMaterial> material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
6463 
6464 		Color color = instanced ? instanced_color : p_color;
6465 
6466 		if (!selected) {
6467 			color.a *= 0.3;
6468 		}
6469 
6470 		material->set_albedo(color);
6471 		material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
6472 		material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
6473 		material->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN + 1);
6474 
6475 		if (p_use_vertex_color) {
6476 			material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
6477 			material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
6478 		}
6479 
6480 		if (p_billboard) {
6481 			material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
6482 		}
6483 
6484 		if (p_on_top && selected) {
6485 			material->set_on_top_of_alpha();
6486 		}
6487 
6488 		mats.push_back(material);
6489 	}
6490 
6491 	materials[p_name] = mats;
6492 }
6493 
create_icon_material(const String & p_name,const Ref<Texture> & p_texture,bool p_on_top,const Color & p_albedo)6494 void EditorSpatialGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top, const Color &p_albedo) {
6495 
6496 	Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6));
6497 
6498 	Vector<Ref<SpatialMaterial> > icons;
6499 
6500 	for (int i = 0; i < 4; i++) {
6501 		bool selected = i % 2 == 1;
6502 		bool instanced = i < 2;
6503 
6504 		Ref<SpatialMaterial> icon = Ref<SpatialMaterial>(memnew(SpatialMaterial));
6505 
6506 		Color color = instanced ? instanced_color : p_albedo;
6507 
6508 		if (!selected) {
6509 			color.a *= 0.85;
6510 		}
6511 
6512 		icon->set_albedo(color);
6513 
6514 		icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
6515 		icon->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
6516 		icon->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
6517 		icon->set_cull_mode(SpatialMaterial::CULL_DISABLED);
6518 		icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED);
6519 		icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
6520 		icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, p_texture);
6521 		icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true);
6522 		icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
6523 		icon->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN);
6524 
6525 		if (p_on_top && selected) {
6526 			icon->set_on_top_of_alpha();
6527 		}
6528 
6529 		icons.push_back(icon);
6530 	}
6531 
6532 	materials[p_name] = icons;
6533 }
6534 
create_handle_material(const String & p_name,bool p_billboard)6535 void EditorSpatialGizmoPlugin::create_handle_material(const String &p_name, bool p_billboard) {
6536 	Ref<SpatialMaterial> handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial));
6537 
6538 	handle_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
6539 	handle_material->set_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true);
6540 	Ref<Texture> handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle", "EditorIcons");
6541 	handle_material->set_point_size(handle_t->get_width());
6542 	handle_material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, handle_t);
6543 	handle_material->set_albedo(Color(1, 1, 1));
6544 	handle_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
6545 	handle_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
6546 	handle_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
6547 	handle_material->set_on_top_of_alpha();
6548 	if (p_billboard) {
6549 		handle_material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED);
6550 		handle_material->set_on_top_of_alpha();
6551 	}
6552 
6553 	materials[p_name] = Vector<Ref<SpatialMaterial> >();
6554 	materials[p_name].push_back(handle_material);
6555 }
6556 
add_material(const String & p_name,Ref<SpatialMaterial> p_material)6557 void EditorSpatialGizmoPlugin::add_material(const String &p_name, Ref<SpatialMaterial> p_material) {
6558 	materials[p_name] = Vector<Ref<SpatialMaterial> >();
6559 	materials[p_name].push_back(p_material);
6560 }
6561 
get_material(const String & p_name,const Ref<EditorSpatialGizmo> & p_gizmo)6562 Ref<SpatialMaterial> EditorSpatialGizmoPlugin::get_material(const String &p_name, const Ref<EditorSpatialGizmo> &p_gizmo) {
6563 	ERR_FAIL_COND_V(!materials.has(p_name), Ref<SpatialMaterial>());
6564 	ERR_FAIL_COND_V(materials[p_name].size() == 0, Ref<SpatialMaterial>());
6565 
6566 	if (p_gizmo.is_null() || materials[p_name].size() == 1) return materials[p_name][0];
6567 
6568 	int index = (p_gizmo->is_selected() ? 1 : 0) + (p_gizmo->is_editable() ? 2 : 0);
6569 
6570 	Ref<SpatialMaterial> mat = materials[p_name][index];
6571 
6572 	if (current_state == ON_TOP && p_gizmo->is_selected()) {
6573 		mat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true);
6574 	} else {
6575 		mat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, false);
6576 	}
6577 
6578 	return mat;
6579 }
6580 
get_name() const6581 String EditorSpatialGizmoPlugin::get_name() const {
6582 	if (get_script_instance() && get_script_instance()->has_method("get_name")) {
6583 		return get_script_instance()->call("get_name");
6584 	}
6585 	return TTR("Nameless gizmo");
6586 }
6587 
get_priority() const6588 int EditorSpatialGizmoPlugin::get_priority() const {
6589 	if (get_script_instance() && get_script_instance()->has_method("get_priority")) {
6590 		return get_script_instance()->call("get_priority");
6591 	}
6592 	return 0;
6593 }
6594 
get_gizmo(Spatial * p_spatial)6595 Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::get_gizmo(Spatial *p_spatial) {
6596 
6597 	if (get_script_instance() && get_script_instance()->has_method("get_gizmo")) {
6598 		return get_script_instance()->call("get_gizmo", p_spatial);
6599 	}
6600 
6601 	Ref<EditorSpatialGizmo> ref = create_gizmo(p_spatial);
6602 
6603 	if (ref.is_null()) return ref;
6604 
6605 	ref->set_plugin(this);
6606 	ref->set_spatial_node(p_spatial);
6607 	ref->set_hidden(current_state == HIDDEN);
6608 
6609 	current_gizmos.push_back(ref.ptr());
6610 	return ref;
6611 }
6612 
_bind_methods()6613 void EditorSpatialGizmoPlugin::_bind_methods() {
6614 #define GIZMO_REF PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "EditorSpatialGizmo")
6615 
6616 	BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Spatial")));
6617 	BIND_VMETHOD(MethodInfo(GIZMO_REF, "create_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Spatial")));
6618 
6619 	ClassDB::bind_method(D_METHOD("create_material", "name", "color", "billboard", "on_top", "use_vertex_color"), &EditorSpatialGizmoPlugin::create_material, DEFVAL(false), DEFVAL(false), DEFVAL(false));
6620 	ClassDB::bind_method(D_METHOD("create_icon_material", "name", "texture", "on_top", "color"), &EditorSpatialGizmoPlugin::create_icon_material, DEFVAL(false), DEFVAL(Color(1, 1, 1, 1)));
6621 	ClassDB::bind_method(D_METHOD("create_handle_material", "name", "billboard"), &EditorSpatialGizmoPlugin::create_handle_material, DEFVAL(false));
6622 	ClassDB::bind_method(D_METHOD("add_material", "name", "material"), &EditorSpatialGizmoPlugin::add_material);
6623 
6624 	ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorSpatialGizmoPlugin::get_material); //, DEFVAL(Ref<EditorSpatialGizmo>()));
6625 
6626 	BIND_VMETHOD(MethodInfo(Variant::STRING, "get_name"));
6627 	BIND_VMETHOD(MethodInfo(Variant::STRING, "get_priority"));
6628 	BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_be_hidden"));
6629 	BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_selectable_when_hidden"));
6630 
6631 	BIND_VMETHOD(MethodInfo("redraw", GIZMO_REF));
6632 	BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", GIZMO_REF, PropertyInfo(Variant::INT, "index")));
6633 
6634 	MethodInfo hvget(Variant::NIL, "get_handle_value", GIZMO_REF, PropertyInfo(Variant::INT, "index"));
6635 	hvget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
6636 	BIND_VMETHOD(hvget);
6637 
6638 	BIND_VMETHOD(MethodInfo("set_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::VECTOR2, "point")));
6639 	MethodInfo cm = MethodInfo("commit_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::NIL, "restore"), PropertyInfo(Variant::BOOL, "cancel"));
6640 	cm.default_arguments.push_back(false);
6641 	BIND_VMETHOD(cm);
6642 
6643 	BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_handle_highlighted", GIZMO_REF, PropertyInfo(Variant::INT, "index")));
6644 
6645 #undef GIZMO_REF
6646 }
6647 
has_gizmo(Spatial * p_spatial)6648 bool EditorSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
6649 	if (get_script_instance() && get_script_instance()->has_method("has_gizmo")) {
6650 		return get_script_instance()->call("has_gizmo", p_spatial);
6651 	}
6652 	return false;
6653 }
6654 
create_gizmo(Spatial * p_spatial)6655 Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::create_gizmo(Spatial *p_spatial) {
6656 
6657 	if (get_script_instance() && get_script_instance()->has_method("create_gizmo")) {
6658 		return get_script_instance()->call("create_gizmo", p_spatial);
6659 	}
6660 
6661 	Ref<EditorSpatialGizmo> ref;
6662 	if (has_gizmo(p_spatial)) ref.instance();
6663 	return ref;
6664 }
6665 
can_be_hidden() const6666 bool EditorSpatialGizmoPlugin::can_be_hidden() const {
6667 	if (get_script_instance() && get_script_instance()->has_method("can_be_hidden")) {
6668 		return get_script_instance()->call("can_be_hidden");
6669 	}
6670 	return true;
6671 }
6672 
is_selectable_when_hidden() const6673 bool EditorSpatialGizmoPlugin::is_selectable_when_hidden() const {
6674 	if (get_script_instance() && get_script_instance()->has_method("is_selectable_when_hidden")) {
6675 		return get_script_instance()->call("is_selectable_when_hidden");
6676 	}
6677 	return false;
6678 }
6679 
redraw(EditorSpatialGizmo * p_gizmo)6680 void EditorSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
6681 	if (get_script_instance() && get_script_instance()->has_method("redraw")) {
6682 		Ref<EditorSpatialGizmo> ref(p_gizmo);
6683 		get_script_instance()->call("redraw", ref);
6684 	}
6685 }
6686 
get_handle_name(const EditorSpatialGizmo * p_gizmo,int p_idx) const6687 String EditorSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
6688 	if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) {
6689 		return get_script_instance()->call("get_handle_name", p_gizmo, p_idx);
6690 	}
6691 	return "";
6692 }
6693 
get_handle_value(EditorSpatialGizmo * p_gizmo,int p_idx) const6694 Variant EditorSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const {
6695 	if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) {
6696 		return get_script_instance()->call("get_handle_value", p_gizmo, p_idx);
6697 	}
6698 	return Variant();
6699 }
6700 
set_handle(EditorSpatialGizmo * p_gizmo,int p_idx,Camera * p_camera,const Point2 & p_point)6701 void EditorSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {
6702 	if (get_script_instance() && get_script_instance()->has_method("set_handle")) {
6703 		get_script_instance()->call("set_handle", p_gizmo, p_idx, p_camera, p_point);
6704 	}
6705 }
6706 
commit_handle(EditorSpatialGizmo * p_gizmo,int p_idx,const Variant & p_restore,bool p_cancel)6707 void EditorSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) {
6708 	if (get_script_instance() && get_script_instance()->has_method("commit_handle")) {
6709 		get_script_instance()->call("commit_handle", p_gizmo, p_idx, p_restore, p_cancel);
6710 	}
6711 }
6712 
is_handle_highlighted(const EditorSpatialGizmo * p_gizmo,int p_idx) const6713 bool EditorSpatialGizmoPlugin::is_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int p_idx) const {
6714 	if (get_script_instance() && get_script_instance()->has_method("is_handle_highlighted")) {
6715 		return get_script_instance()->call("is_handle_highlighted", p_gizmo, p_idx);
6716 	}
6717 	return false;
6718 }
6719 
set_state(int p_state)6720 void EditorSpatialGizmoPlugin::set_state(int p_state) {
6721 	current_state = p_state;
6722 	for (int i = 0; i < current_gizmos.size(); ++i) {
6723 		current_gizmos[i]->set_hidden(current_state == HIDDEN);
6724 	}
6725 }
6726 
get_state() const6727 int EditorSpatialGizmoPlugin::get_state() const {
6728 	return current_state;
6729 }
6730 
unregister_gizmo(EditorSpatialGizmo * p_gizmo)6731 void EditorSpatialGizmoPlugin::unregister_gizmo(EditorSpatialGizmo *p_gizmo) {
6732 	current_gizmos.erase(p_gizmo);
6733 }
6734 
EditorSpatialGizmoPlugin()6735 EditorSpatialGizmoPlugin::EditorSpatialGizmoPlugin() {
6736 	current_state = VISIBLE;
6737 }
6738 
~EditorSpatialGizmoPlugin()6739 EditorSpatialGizmoPlugin::~EditorSpatialGizmoPlugin() {
6740 	for (int i = 0; i < current_gizmos.size(); ++i) {
6741 		current_gizmos[i]->set_plugin(NULL);
6742 		current_gizmos[i]->get_spatial_node()->set_gizmo(NULL);
6743 	}
6744 	if (SpatialEditor::get_singleton()) {
6745 		SpatialEditor::get_singleton()->update_all_gizmos();
6746 	}
6747 }
6748