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-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 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 #include "spatial_editor_plugin.h"
31 #include "print_string.h"
32 
33 #include "camera_matrix.h"
34 #include "core/os/input.h"
35 #include "editor/animation_editor.h"
36 #include "editor/editor_node.h"
37 #include "editor/editor_settings.h"
38 #include "editor/plugins/animation_player_editor_plugin.h"
39 #include "editor/spatial_editor_gizmos.h"
40 #include "globals.h"
41 #include "os/keyboard.h"
42 #include "scene/3d/camera.h"
43 #include "scene/3d/visual_instance.h"
44 #include "scene/resources/surface_tool.h"
45 #include "sort.h"
46 
47 #define DISTANCE_DEFAULT 4
48 
49 #define GIZMO_ARROW_SIZE 0.3
50 #define GIZMO_RING_HALF_WIDTH 0.1
51 //#define GIZMO_SCALE_DEFAULT 0.28
52 #define GIZMO_SCALE_DEFAULT 0.15
53 
_update_camera()54 void SpatialEditorViewport::_update_camera() {
55 	if (orthogonal) {
56 		//camera->set_orthogonal(size.width*cursor.distance,get_znear(),get_zfar());
57 		camera->set_orthogonal(2 * cursor.distance, 0.1, 8192);
58 	} else
59 		camera->set_perspective(get_fov(), get_znear(), get_zfar());
60 
61 	Transform camera_transform;
62 	camera_transform.translate(cursor.pos);
63 	camera_transform.basis.rotate(Vector3(0, 1, 0), cursor.y_rot);
64 	camera_transform.basis.rotate(Vector3(1, 0, 0), cursor.x_rot);
65 
66 	if (orthogonal)
67 		camera_transform.translate(0, 0, 4096);
68 	else
69 		camera_transform.translate(0, 0, cursor.distance);
70 
71 	if (camera->get_global_transform() != camera_transform) {
72 		camera->set_global_transform(camera_transform);
73 		update_transform_gizmo_view();
74 	}
75 }
76 
get_handle_name(int p_idx) const77 String SpatialEditorGizmo::get_handle_name(int p_idx) const {
78 
79 	if (get_script_instance() && get_script_instance()->has_method("get_handle_name"))
80 		return get_script_instance()->call("get_handle_name", p_idx);
81 
82 	return "";
83 }
84 
get_handle_value(int p_idx) const85 Variant SpatialEditorGizmo::get_handle_value(int p_idx) const {
86 
87 	if (get_script_instance() && get_script_instance()->has_method("get_handle_value"))
88 		return get_script_instance()->call("get_handle_value", p_idx);
89 
90 	return Variant();
91 }
92 
set_handle(int p_idx,Camera * p_camera,const Point2 & p_point)93 void SpatialEditorGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
94 
95 	if (get_script_instance() && get_script_instance()->has_method("set_handle"))
96 		get_script_instance()->call("set_handle", p_idx, p_camera, p_point);
97 }
98 
commit_handle(int p_idx,const Variant & p_restore,bool p_cancel)99 void SpatialEditorGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
100 
101 	if (get_script_instance() && get_script_instance()->has_method("commit_handle"))
102 		get_script_instance()->call("commit_handle", p_idx, p_restore, p_cancel);
103 }
104 
intersect_frustum(const Camera * p_camera,const Vector<Plane> & p_frustum)105 bool SpatialEditorGizmo::intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum) {
106 
107 	return false;
108 }
109 
intersect_ray(const Camera * p_camera,const Point2 & p_point,Vector3 & r_pos,Vector3 & r_normal,int * r_gizmo_handle,bool p_sec_first)110 bool SpatialEditorGizmo::intersect_ray(const Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) {
111 
112 	return false;
113 }
114 
SpatialEditorGizmo()115 SpatialEditorGizmo::SpatialEditorGizmo() {
116 
117 	selected = false;
118 }
119 
get_selected_count() const120 int SpatialEditorViewport::get_selected_count() const {
121 
122 	Map<Node *, Object *> &selection = editor_selection->get_selection();
123 
124 	int count = 0;
125 
126 	for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
127 
128 		Spatial *sp = E->key()->cast_to<Spatial>();
129 		if (!sp)
130 			continue;
131 
132 		SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
133 		if (!se)
134 			continue;
135 
136 		count++;
137 	}
138 
139 	return count;
140 }
141 
get_znear() const142 float SpatialEditorViewport::get_znear() const {
143 
144 	float val = spatial_editor->get_znear();
145 	if (val < 0.001)
146 		val = 0.001;
147 	return val;
148 }
get_zfar() const149 float SpatialEditorViewport::get_zfar() const {
150 
151 	float val = spatial_editor->get_zfar();
152 	if (val < 0.001)
153 		val = 0.001;
154 	return val;
155 }
get_fov() const156 float SpatialEditorViewport::get_fov() const {
157 
158 	float val = spatial_editor->get_fov();
159 	if (val < 0.001)
160 		val = 0.001;
161 	if (val > 89)
162 		val = 89;
163 	return val;
164 }
165 
_get_camera_transform() const166 Transform SpatialEditorViewport::_get_camera_transform() const {
167 
168 	return camera->get_global_transform();
169 }
170 
_get_camera_pos() const171 Vector3 SpatialEditorViewport::_get_camera_pos() const {
172 
173 	return _get_camera_transform().origin;
174 }
175 
_point_to_screen(const Vector3 & p_point)176 Point2 SpatialEditorViewport::_point_to_screen(const Vector3 &p_point) {
177 
178 	return camera->unproject_position(p_point);
179 }
180 
_get_ray_pos(const Vector2 & p_pos) const181 Vector3 SpatialEditorViewport::_get_ray_pos(const Vector2 &p_pos) const {
182 
183 	return camera->project_ray_origin(p_pos);
184 }
185 
_get_camera_normal() const186 Vector3 SpatialEditorViewport::_get_camera_normal() const {
187 
188 	return -_get_camera_transform().basis.get_axis(2);
189 }
190 
_get_ray(const Vector2 & p_pos)191 Vector3 SpatialEditorViewport::_get_ray(const Vector2 &p_pos) {
192 
193 	return camera->project_ray_normal(p_pos);
194 }
195 /*
196 void SpatialEditorViewport::_clear_id(Spatial *p_node) {
197 
198 
199 	editor_selection->remove_node(p_node);
200 
201 
202 }
203 */
_clear_selected()204 void SpatialEditorViewport::_clear_selected() {
205 
206 	editor_selection->clear();
207 }
208 
_select_clicked(bool p_append,bool p_single)209 void SpatialEditorViewport::_select_clicked(bool p_append, bool p_single) {
210 
211 	if (!clicked)
212 		return;
213 
214 	Object *obj = ObjectDB::get_instance(clicked);
215 	if (!obj)
216 		return;
217 
218 	Spatial *sp = obj->cast_to<Spatial>();
219 	if (!sp)
220 		return;
221 
222 	_select(sp, clicked_wants_append, true);
223 }
224 
_select(Spatial * p_node,bool p_append,bool p_single)225 void SpatialEditorViewport::_select(Spatial *p_node, bool p_append, bool p_single) {
226 
227 	if (!p_append) {
228 
229 		// should not modify the selection..
230 
231 		editor_selection->clear();
232 		editor_selection->add_node(p_node);
233 
234 	} else {
235 
236 		if (editor_selection->is_selected(p_node) && p_single) {
237 			//erase
238 			editor_selection->remove_node(p_node);
239 		} else {
240 
241 			editor_selection->add_node(p_node);
242 		}
243 	}
244 }
245 
_select_ray(const Point2 & p_pos,bool p_append,bool & r_includes_current,int * r_gizmo_handle,bool p_alt_select)246 ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle, bool p_alt_select) {
247 
248 	if (r_gizmo_handle)
249 		*r_gizmo_handle = -1;
250 
251 	Vector3 ray = _get_ray(p_pos);
252 	Vector3 pos = _get_ray_pos(p_pos);
253 
254 	Vector<RID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
255 	Set<Ref<SpatialEditorGizmo> > found_gizmos;
256 
257 	//uint32_t closest=0;
258 	//	float closest_dist=0;
259 
260 	r_includes_current = false;
261 
262 	List<_RayResult> results;
263 	Vector<Spatial *> subscenes = Vector<Spatial *>();
264 	Vector<Vector3> subscenes_positions = Vector<Vector3>();
265 
266 	for (int i = 0; i < instances.size(); i++) {
267 
268 		uint32_t id = VisualServer::get_singleton()->instance_get_object_instance_ID(instances[i]);
269 		Object *obj = ObjectDB::get_instance(id);
270 		if (!obj)
271 			continue;
272 
273 		Spatial *spat = obj->cast_to<Spatial>();
274 
275 		if (!spat)
276 			continue;
277 
278 		Ref<SpatialEditorGizmo> seg = spat->get_gizmo();
279 
280 		if (!seg.is_valid() || found_gizmos.has(seg)) {
281 			Node *subscene_candidate = spat;
282 			Vector3 source_click_spatial_pos = spat->get_global_transform().origin;
283 
284 			while ((subscene_candidate->get_owner() != NULL) && (subscene_candidate->get_owner() != editor->get_edited_scene()))
285 				subscene_candidate = subscene_candidate->get_owner();
286 
287 			spat = subscene_candidate->cast_to<Spatial>();
288 			if (spat && (spat->get_filename() != "") && (subscene_candidate->get_owner() != NULL)) {
289 				subscenes.push_back(spat);
290 				subscenes_positions.push_back(source_click_spatial_pos);
291 			}
292 
293 			continue;
294 		}
295 
296 		found_gizmos.insert(seg);
297 		Vector3 point;
298 		Vector3 normal;
299 
300 		int handle = -1;
301 		bool inters = seg->intersect_ray(camera, p_pos, point, normal, NULL, p_alt_select);
302 
303 		if (!inters)
304 			continue;
305 
306 		float dist = pos.distance_to(point);
307 
308 		if (dist < 0)
309 			continue;
310 
311 		if (editor_selection->is_selected(spat))
312 			r_includes_current = true;
313 
314 		_RayResult res;
315 		res.item = spat;
316 		res.depth = dist;
317 		res.handle = handle;
318 		results.push_back(res);
319 	}
320 	for (int idx_subscene = 0; idx_subscene < subscenes.size(); idx_subscene++) {
321 
322 		Spatial *subscene = subscenes.get(idx_subscene);
323 		float dist = ray.cross(subscenes_positions.get(idx_subscene) - pos).length();
324 
325 		if ((dist < 0) || (dist > 1.2))
326 			continue;
327 
328 		if (editor_selection->is_selected(subscene))
329 			r_includes_current = true;
330 
331 		_RayResult res;
332 		res.item = subscene;
333 		res.depth = dist;
334 		res.handle = -1;
335 		results.push_back(res);
336 	}
337 
338 	if (results.empty())
339 		return 0;
340 
341 	results.sort();
342 	Spatial *s = NULL;
343 
344 	if (!r_includes_current || results.size() == 1 || (r_gizmo_handle && results.front()->get().handle >= 0)) {
345 
346 		//return the nearest one
347 		s = results.front()->get().item;
348 		if (r_gizmo_handle)
349 			*r_gizmo_handle = results.front()->get().handle;
350 
351 	} else {
352 
353 		//returns the next one from a curent selection
354 		List<_RayResult>::Element *E = results.front();
355 		List<_RayResult>::Element *S = NULL;
356 
357 		while (true) {
358 
359 			//very strange loop algorithm that complies with object selection standards (tm).
360 
361 			if (S == E) {
362 				//went all around and anothing was found
363 				//since can't rotate the selection
364 				//just return the first one
365 
366 				s = results.front()->get().item;
367 				break;
368 			}
369 
370 			if (!S && editor_selection->is_selected(E->get().item)) {
371 				//found an item currently in the selection,
372 				//so start from this one
373 				S = E;
374 			}
375 
376 			if (S && !editor_selection->is_selected(E->get().item)) {
377 				// free item after a selected item, this one is desired.
378 				s = E->get().item;
379 				break;
380 			}
381 
382 			E = E->next();
383 			if (!E) {
384 
385 				if (!S) {
386 					//did a loop but nothing was selected, select first
387 					s = results.front()->get().item;
388 					break;
389 				}
390 				E = results.front();
391 			}
392 		}
393 	}
394 
395 	if (!s)
396 		return 0;
397 
398 	return s->get_instance_ID();
399 }
400 
_find_items_at_pos(const Point2 & p_pos,bool & r_includes_current,Vector<_RayResult> & results,bool p_alt_select)401 void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_includes_current, Vector<_RayResult> &results, bool p_alt_select) {
402 
403 	Vector3 ray = _get_ray(p_pos);
404 	Vector3 pos = _get_ray_pos(p_pos);
405 
406 	Vector<RID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
407 	Set<Ref<SpatialEditorGizmo> > found_gizmos;
408 
409 	r_includes_current = false;
410 
411 	for (int i = 0; i < instances.size(); i++) {
412 
413 		uint32_t id = VisualServer::get_singleton()->instance_get_object_instance_ID(instances[i]);
414 		Object *obj = ObjectDB::get_instance(id);
415 		if (!obj)
416 			continue;
417 
418 		Spatial *spat = obj->cast_to<Spatial>();
419 
420 		if (!spat)
421 			continue;
422 
423 		Ref<SpatialEditorGizmo> seg = spat->get_gizmo();
424 
425 		if (!seg.is_valid())
426 			continue;
427 
428 		if (found_gizmos.has(seg))
429 			continue;
430 
431 		found_gizmos.insert(seg);
432 		Vector3 point;
433 		Vector3 normal;
434 
435 		int handle = -1;
436 		bool inters = seg->intersect_ray(camera, p_pos, point, normal, NULL, p_alt_select);
437 
438 		if (!inters)
439 			continue;
440 
441 		float dist = pos.distance_to(point);
442 
443 		if (dist < 0)
444 			continue;
445 
446 		if (editor_selection->is_selected(spat))
447 			r_includes_current = true;
448 
449 		_RayResult res;
450 		res.item = spat;
451 		res.depth = dist;
452 		res.handle = handle;
453 		results.push_back(res);
454 	}
455 
456 	if (results.empty())
457 		return;
458 
459 	results.sort();
460 }
461 
_get_screen_to_space(const Vector3 & p_pos)462 Vector3 SpatialEditorViewport::_get_screen_to_space(const Vector3 &p_pos) {
463 
464 	CameraMatrix cm;
465 	cm.set_perspective(get_fov(), get_size().get_aspect(), get_znear(), get_zfar());
466 	float screen_w, screen_h;
467 	cm.get_viewport_size(screen_w, screen_h);
468 
469 	Transform camera_transform;
470 	camera_transform.translate(cursor.pos);
471 	camera_transform.basis.rotate(Vector3(0, 1, 0), cursor.y_rot);
472 	camera_transform.basis.rotate(Vector3(1, 0, 0), cursor.x_rot);
473 	camera_transform.translate(0, 0, cursor.distance);
474 
475 	return camera_transform.xform(Vector3(((p_pos.x / get_size().width) * 2.0 - 1.0) * screen_w, ((1.0 - (p_pos.y / get_size().height)) * 2.0 - 1.0) * screen_h, -get_znear()));
476 }
477 
_select_region()478 void SpatialEditorViewport::_select_region() {
479 
480 	if (cursor.region_begin == cursor.region_end)
481 		return; //nothing really
482 
483 	Vector3 box[4] = {
484 		Vector3(
485 				MIN(cursor.region_begin.x, cursor.region_end.x),
486 				MIN(cursor.region_begin.y, cursor.region_end.y),
487 				0),
488 		Vector3(
489 				MAX(cursor.region_begin.x, cursor.region_end.x),
490 				MIN(cursor.region_begin.y, cursor.region_end.y),
491 				0),
492 		Vector3(
493 				MAX(cursor.region_begin.x, cursor.region_end.x),
494 				MAX(cursor.region_begin.y, cursor.region_end.y),
495 				0),
496 		Vector3(
497 				MIN(cursor.region_begin.x, cursor.region_end.x),
498 				MAX(cursor.region_begin.y, cursor.region_end.y),
499 				0)
500 	};
501 
502 	Vector<Plane> frustum;
503 
504 	Vector3 cam_pos = _get_camera_pos();
505 	Set<Ref<SpatialEditorGizmo> > found_gizmos;
506 
507 	for (int i = 0; i < 4; i++) {
508 
509 		Vector3 a = _get_screen_to_space(box[i]);
510 		Vector3 b = _get_screen_to_space(box[(i + 1) % 4]);
511 		frustum.push_back(Plane(a, b, cam_pos));
512 	}
513 
514 	Plane near(cam_pos, -_get_camera_normal());
515 	near.d -= get_znear();
516 
517 	frustum.push_back(near);
518 
519 	Plane far = -near;
520 	far.d += 500.0;
521 
522 	frustum.push_back(far);
523 
524 	Vector<RID> instances = VisualServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world()->get_scenario());
525 
526 	for (int i = 0; i < instances.size(); i++) {
527 
528 		uint32_t id = VisualServer::get_singleton()->instance_get_object_instance_ID(instances[i]);
529 
530 		Object *obj = ObjectDB::get_instance(id);
531 		if (!obj)
532 			continue;
533 		Spatial *sp = obj->cast_to<Spatial>();
534 		if (!sp)
535 			continue;
536 
537 		Ref<SpatialEditorGizmo> seg = sp->get_gizmo();
538 
539 		if (!seg.is_valid())
540 			continue;
541 
542 		if (found_gizmos.has(seg))
543 			continue;
544 
545 		if (seg->intersect_frustum(camera, frustum))
546 			_select(sp, true, false);
547 	}
548 }
549 
_update_name()550 void SpatialEditorViewport::_update_name() {
551 
552 	String ortho = orthogonal ? TTR("Orthogonal") : TTR("Perspective");
553 
554 	if (name != "")
555 		view_menu->set_text("[ " + name + " " + ortho + " ]");
556 	else
557 		view_menu->set_text("[ " + ortho + " ]");
558 }
559 
_compute_edit(const Point2 & p_point)560 void SpatialEditorViewport::_compute_edit(const Point2 &p_point) {
561 
562 	_edit.click_ray = _get_ray(Vector2(p_point.x, p_point.y));
563 	_edit.click_ray_pos = _get_ray_pos(Vector2(p_point.x, p_point.y));
564 	_edit.plane = TRANSFORM_VIEW;
565 	spatial_editor->update_transform_gizmo();
566 	_edit.center = spatial_editor->get_gizmo_transform().origin;
567 
568 	List<Node *> &selection = editor_selection->get_selected_node_list();
569 
570 	//	Vector3 center;
571 	//	int nc=0;
572 	for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
573 
574 		Spatial *sp = E->get()->cast_to<Spatial>();
575 		if (!sp)
576 			continue;
577 
578 		SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
579 		if (!se)
580 			continue;
581 
582 		se->original = se->sp->get_global_transform();
583 		//		center+=se->original.origin;
584 		//		nc++;
585 	}
586 
587 	//	if (nc)
588 	//		_edit.center=center/float(nc);
589 }
590 
_get_key_modifier(const String & p_property)591 static int _get_key_modifier(const String &p_property) {
592 
593 	switch (EditorSettings::get_singleton()->get(p_property).operator int()) {
594 
595 		case 0: return 0;
596 		case 1: return KEY_SHIFT;
597 		case 2: return KEY_ALT;
598 		case 3: return KEY_META;
599 		case 4: return KEY_CONTROL;
600 	}
601 	return 0;
602 }
603 
_get_navigation_schema(const String & p_property)604 SpatialEditorViewport::NavigationScheme SpatialEditorViewport::_get_navigation_schema(const String &p_property) {
605 	switch (EditorSettings::get_singleton()->get(p_property).operator int()) {
606 		case 0: return NAVIGATION_GODOT;
607 		case 1: return NAVIGATION_MAYA;
608 		case 2: return NAVIGATION_MODO;
609 	}
610 	return NAVIGATION_GODOT;
611 }
612 
_get_navigation_zoom_style(const String & p_property)613 SpatialEditorViewport::NavigationZoomStyle SpatialEditorViewport::_get_navigation_zoom_style(const String &p_property) {
614 	switch (EditorSettings::get_singleton()->get(p_property).operator int()) {
615 		case 0: return NAVIGATION_ZOOM_VERTICAL;
616 		case 1: return NAVIGATION_ZOOM_HORIZONTAL;
617 	}
618 	return NAVIGATION_ZOOM_VERTICAL;
619 }
620 
_gizmo_select(const Vector2 & p_screenpos,bool p_hilite_only)621 bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hilite_only) {
622 
623 	if (!spatial_editor->is_gizmo_visible())
624 		return false;
625 	if (get_selected_count() == 0) {
626 		if (p_hilite_only)
627 			spatial_editor->select_gizmo_highlight_axis(-1);
628 		return false;
629 	}
630 
631 	Vector3 ray_pos = _get_ray_pos(Vector2(p_screenpos.x, p_screenpos.y));
632 	Vector3 ray = _get_ray(Vector2(p_screenpos.x, p_screenpos.y));
633 
634 	Transform gt = spatial_editor->get_gizmo_transform();
635 	float gs = gizmo_scale;
636 
637 	if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE) {
638 
639 		int col_axis = -1;
640 		float col_d = 1e20;
641 
642 		for (int i = 0; i < 3; i++) {
643 
644 			Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs;
645 			float grabber_radius = gs * GIZMO_ARROW_SIZE;
646 
647 			Vector3 r;
648 			if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * 10000.0, grabber_pos, grabber_radius, &r)) {
649 				float d = r.distance_to(ray_pos);
650 				if (d < col_d) {
651 					col_d = d;
652 					col_axis = i;
653 				}
654 			}
655 		}
656 
657 		if (col_axis != -1) {
658 
659 			if (p_hilite_only) {
660 
661 				spatial_editor->select_gizmo_highlight_axis(col_axis);
662 
663 			} else {
664 				//handle rotate
665 				_edit.mode = TRANSFORM_TRANSLATE;
666 				_compute_edit(Point2(p_screenpos.x, p_screenpos.y));
667 				_edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis);
668 			}
669 			return true;
670 		}
671 	}
672 
673 	if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE) {
674 
675 		int col_axis = -1;
676 		float col_d = 1e20;
677 
678 		for (int i = 0; i < 3; i++) {
679 
680 			Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
681 			Vector3 r;
682 			if (!plane.intersects_ray(ray_pos, ray, &r))
683 				continue;
684 
685 			float dist = r.distance_to(gt.origin);
686 
687 			if (dist > gs * (1 - GIZMO_RING_HALF_WIDTH) && dist < gs * (1 + GIZMO_RING_HALF_WIDTH)) {
688 
689 				float d = ray_pos.distance_to(r);
690 				if (d < col_d) {
691 					col_d = d;
692 					col_axis = i;
693 				}
694 			}
695 		}
696 
697 		if (col_axis != -1) {
698 
699 			if (p_hilite_only) {
700 
701 				spatial_editor->select_gizmo_highlight_axis(col_axis + 3);
702 			} else {
703 				//handle rotate
704 				_edit.mode = TRANSFORM_ROTATE;
705 				_compute_edit(Point2(p_screenpos.x, p_screenpos.y));
706 				_edit.plane = TransformPlane(TRANSFORM_X_AXIS + col_axis);
707 			}
708 			return true;
709 		}
710 	}
711 
712 	if (p_hilite_only)
713 		spatial_editor->select_gizmo_highlight_axis(-1);
714 
715 	return false;
716 }
717 
_smouseenter()718 void SpatialEditorViewport::_smouseenter() {
719 
720 	if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
721 		surface->grab_focus();
722 }
723 
_list_select(InputEventMouseButton b)724 void SpatialEditorViewport::_list_select(InputEventMouseButton b) {
725 
726 	_find_items_at_pos(Vector2(b.x, b.y), clicked_includes_current, selection_results, b.mod.shift);
727 
728 	Node *scene = editor->get_edited_scene();
729 
730 	for (int i = 0; i < selection_results.size(); i++) {
731 		Spatial *item = selection_results[i].item;
732 		if (item != scene && item->get_owner() != scene && !scene->is_editable_instance(item->get_owner())) {
733 			//invalid result
734 			selection_results.remove(i);
735 			i--;
736 		}
737 	}
738 
739 	clicked_wants_append = b.mod.shift;
740 
741 	if (selection_results.size() == 1) {
742 
743 		clicked = selection_results[0].item->get_instance_ID();
744 		selection_results.clear();
745 
746 		if (clicked) {
747 			_select_clicked(clicked_wants_append, true);
748 			clicked = 0;
749 		}
750 
751 	} else if (!selection_results.empty()) {
752 
753 		NodePath root_path = get_tree()->get_edited_scene_root()->get_path();
754 		StringName root_name = root_path.get_name(root_path.get_name_count() - 1);
755 
756 		for (int i = 0; i < selection_results.size(); i++) {
757 
758 			Spatial *spat = selection_results[i].item;
759 
760 			Ref<Texture> icon;
761 			if (spat->has_meta("_editor_icon"))
762 				icon = spat->get_meta("_editor_icon");
763 			else
764 				icon = get_icon(has_icon(spat->get_type(), "EditorIcons") ? spat->get_type() : String("Object"), "EditorIcons");
765 
766 			String node_path = "/" + root_name + "/" + root_path.rel_path_to(spat->get_path());
767 
768 			selection_menu->add_item(spat->get_name());
769 			selection_menu->set_item_icon(i, icon);
770 			selection_menu->set_item_metadata(i, node_path);
771 			selection_menu->set_item_tooltip(i, String(spat->get_name()) + "\nType: " + spat->get_type() + "\nPath: " + node_path);
772 		}
773 
774 		selection_menu->set_global_pos(Vector2(b.global_x, b.global_y));
775 		selection_menu->popup();
776 		selection_menu->call_deferred("grab_click_focus");
777 		selection_menu->set_invalidate_click_until_motion();
778 	}
779 }
_sinput(const InputEvent & p_event)780 void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
781 
782 	if (previewing)
783 		return; //do NONE
784 
785 	{
786 
787 		EditorNode *en = editor;
788 		EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
789 
790 		if (!over_plugin_list->empty()) {
791 			bool discard = over_plugin_list->forward_spatial_input_event(camera, p_event);
792 			if (discard)
793 				return;
794 		}
795 	}
796 
797 	switch (p_event.type) {
798 		case InputEvent::MOUSE_BUTTON: {
799 
800 			const InputEventMouseButton &b = p_event.mouse_button;
801 
802 			switch (b.button_index) {
803 
804 				case BUTTON_WHEEL_UP: {
805 
806 					cursor.distance /= 1.08;
807 					if (cursor.distance < 0.001)
808 						cursor.distance = 0.001;
809 
810 				} break;
811 				case BUTTON_WHEEL_DOWN: {
812 
813 					if (cursor.distance < 0.001)
814 						cursor.distance = 0.001;
815 					cursor.distance *= 1.08;
816 
817 				} break;
818 				case BUTTON_RIGHT: {
819 
820 					NavigationScheme nav_scheme = _get_navigation_schema("3d_editor/navigation_scheme");
821 
822 					if (b.pressed && _edit.gizmo.is_valid()) {
823 						//restore
824 						_edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, true);
825 						_edit.gizmo = Ref<SpatialEditorGizmo>();
826 					}
827 
828 					if (_edit.mode == TRANSFORM_NONE && b.pressed) {
829 
830 						Plane cursor_plane(cursor.cursor_pos, _get_camera_normal());
831 
832 						Vector3 ray_origin = _get_ray_pos(Vector2(b.x, b.y));
833 						Vector3 ray_dir = _get_ray(Vector2(b.x, b.y));
834 
835 						//gizmo modify
836 
837 						if (b.mod.control) {
838 
839 							Vector<RID> instances = VisualServer::get_singleton()->instances_cull_ray(ray_origin, ray_dir, get_tree()->get_root()->get_world()->get_scenario());
840 
841 							Plane p(ray_origin, _get_camera_normal());
842 
843 							float min_d = 1e10;
844 							bool found = false;
845 
846 							for (int i = 0; i < instances.size(); i++) {
847 
848 								uint32_t id = VisualServer::get_singleton()->instance_get_object_instance_ID(instances[i]);
849 								Object *obj = ObjectDB::get_instance(id);
850 								if (!obj)
851 									continue;
852 
853 								VisualInstance *vi = obj->cast_to<VisualInstance>();
854 								if (!vi)
855 									continue;
856 
857 								//optimize by checking AABB (although should pre sort by distance)
858 								AABB aabb = vi->get_global_transform().xform(vi->get_aabb());
859 								if (p.distance_to(aabb.get_support(-ray_dir)) > min_d)
860 									continue;
861 
862 								DVector<Face3> faces = vi->get_faces(VisualInstance::FACES_SOLID);
863 								int c = faces.size();
864 								if (c > 0) {
865 									DVector<Face3>::Read r = faces.read();
866 
867 									for (int j = 0; j < c; j++) {
868 
869 										Vector3 inters;
870 										if (r[j].intersects_ray(ray_origin, ray_dir, &inters)) {
871 
872 											float d = p.distance_to(inters);
873 											if (d < 0)
874 												continue;
875 
876 											if (d < min_d) {
877 												min_d = d;
878 												found = true;
879 											}
880 										}
881 									}
882 								}
883 							}
884 
885 							if (found) {
886 
887 								//cursor.cursor_pos=ray_origin+ray_dir*min_d;
888 								//VisualServer::get_singleton()->instance_set_transform(cursor_instance,Transform(Matrix3(),cursor.cursor_pos));
889 							}
890 
891 						} else {
892 							Vector3 new_pos;
893 							if (cursor_plane.intersects_ray(ray_origin, ray_dir, &new_pos)) {
894 
895 								//cursor.cursor_pos=new_pos;
896 								//VisualServer::get_singleton()->instance_set_transform(cursor_instance,Transform(Matrix3(),cursor.cursor_pos));
897 							}
898 						}
899 
900 						if (b.mod.alt) {
901 
902 							if (nav_scheme == NAVIGATION_MAYA)
903 								break;
904 
905 							_list_select(b);
906 							return;
907 						}
908 					}
909 
910 					if (_edit.mode != TRANSFORM_NONE && b.pressed) {
911 						//cancel motion
912 						_edit.mode = TRANSFORM_NONE;
913 						//_validate_selection();
914 
915 						List<Node *> &selection = editor_selection->get_selected_node_list();
916 
917 						for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
918 
919 							Spatial *sp = E->get()->cast_to<Spatial>();
920 							if (!sp)
921 								continue;
922 
923 							SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
924 							if (!se)
925 								continue;
926 
927 							sp->set_global_transform(se->original);
928 						}
929 						surface->update();
930 						//VisualServer::get_singleton()->poly_clear(indicators);
931 						set_message(TTR("Transform Aborted."), 3);
932 					}
933 				} break;
934 				case BUTTON_MIDDLE: {
935 
936 					if (b.pressed && _edit.mode != TRANSFORM_NONE) {
937 
938 						switch (_edit.plane) {
939 
940 							case TRANSFORM_VIEW: {
941 
942 								_edit.plane = TRANSFORM_X_AXIS;
943 								set_message(TTR("X-Axis Transform."), 2);
944 								name = "";
945 								_update_name();
946 							} break;
947 							case TRANSFORM_X_AXIS: {
948 
949 								_edit.plane = TRANSFORM_Y_AXIS;
950 								set_message(TTR("Y-Axis Transform."), 2);
951 
952 							} break;
953 							case TRANSFORM_Y_AXIS: {
954 
955 								_edit.plane = TRANSFORM_Z_AXIS;
956 								set_message(TTR("Z-Axis Transform."), 2);
957 
958 							} break;
959 							case TRANSFORM_Z_AXIS: {
960 
961 								_edit.plane = TRANSFORM_VIEW;
962 								set_message(TTR("View Plane Transform."), 2);
963 
964 							} break;
965 						}
966 					}
967 				} break;
968 				case BUTTON_LEFT: {
969 
970 					if (b.pressed) {
971 
972 						NavigationScheme nav_scheme = _get_navigation_schema("3d_editor/navigation_scheme");
973 						if ((nav_scheme == NAVIGATION_MAYA || nav_scheme == NAVIGATION_MODO) && b.mod.alt) {
974 							break;
975 						}
976 
977 						if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_LIST_SELECT) {
978 							_list_select(b);
979 							break;
980 						}
981 
982 						_edit.mouse_pos = Point2(b.x, b.y);
983 						_edit.snap = false;
984 						_edit.mode = TRANSFORM_NONE;
985 
986 						//gizmo has priority over everything
987 
988 						bool can_select_gizmos = true;
989 
990 						{
991 							int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
992 							can_select_gizmos = view_menu->get_popup()->is_item_checked(idx);
993 						}
994 
995 						if (can_select_gizmos && spatial_editor->get_selected()) {
996 
997 							Ref<SpatialEditorGizmo> seg = spatial_editor->get_selected()->get_gizmo();
998 							if (seg.is_valid()) {
999 								int handle = -1;
1000 								Vector3 point;
1001 								Vector3 normal;
1002 								bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, b.mod.shift);
1003 								if (inters && handle != -1) {
1004 
1005 									_edit.gizmo = seg;
1006 									_edit.gizmo_handle = handle;
1007 									//_edit.gizmo_initial_pos=seg->get_handle_pos(gizmo_handle);
1008 									_edit.gizmo_initial_value = seg->get_handle_value(handle);
1009 									break;
1010 								}
1011 							}
1012 						}
1013 
1014 						if (_gizmo_select(_edit.mouse_pos))
1015 							break;
1016 
1017 						clicked = 0;
1018 						clicked_includes_current = false;
1019 
1020 						if ((spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT && b.mod.control) || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE) {
1021 
1022 							/* HANDLE ROTATION */
1023 							if (get_selected_count() == 0)
1024 								break; //bye
1025 							//handle rotate
1026 							_edit.mode = TRANSFORM_ROTATE;
1027 							_compute_edit(Point2(b.x, b.y));
1028 							break;
1029 						}
1030 
1031 						if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE) {
1032 
1033 							if (get_selected_count() == 0)
1034 								break; //bye
1035 							//handle rotate
1036 							_edit.mode = TRANSFORM_TRANSLATE;
1037 							_compute_edit(Point2(b.x, b.y));
1038 							break;
1039 						}
1040 
1041 						if (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE) {
1042 
1043 							if (get_selected_count() == 0)
1044 								break; //bye
1045 							//handle rotate
1046 							_edit.mode = TRANSFORM_SCALE;
1047 							_compute_edit(Point2(b.x, b.y));
1048 							break;
1049 						}
1050 
1051 						// todo scale
1052 
1053 						int gizmo_handle = -1;
1054 
1055 						clicked = _select_ray(Vector2(b.x, b.y), b.mod.shift, clicked_includes_current, &gizmo_handle, b.mod.shift);
1056 
1057 						//clicking is always deferred to either move or release
1058 
1059 						clicked_wants_append = b.mod.shift;
1060 
1061 						if (!clicked) {
1062 
1063 							if (!clicked_wants_append)
1064 								_clear_selected();
1065 
1066 							//default to regionselect
1067 							cursor.region_select = true;
1068 							cursor.region_begin = Point2(b.x, b.y);
1069 							cursor.region_end = Point2(b.x, b.y);
1070 						}
1071 
1072 						if (clicked && gizmo_handle >= 0) {
1073 
1074 							Object *obj = ObjectDB::get_instance(clicked);
1075 							if (obj) {
1076 
1077 								Spatial *spa = obj->cast_to<Spatial>();
1078 								if (spa) {
1079 
1080 									Ref<SpatialEditorGizmo> seg = spa->get_gizmo();
1081 									if (seg.is_valid()) {
1082 
1083 										_edit.gizmo = seg;
1084 										_edit.gizmo_handle = gizmo_handle;
1085 										//_edit.gizmo_initial_pos=seg->get_handle_pos(gizmo_handle);
1086 										_edit.gizmo_initial_value = seg->get_handle_value(gizmo_handle);
1087 										//print_line("GIZMO: "+itos(gizmo_handle)+" FROMPOS: "+_edit.orig_gizmo_pos);
1088 										break;
1089 									}
1090 								}
1091 							}
1092 							//_compute_edit(Point2(b.x,b.y)); //in case a motion happens..
1093 						}
1094 
1095 						surface->update();
1096 					} else {
1097 
1098 						if (_edit.gizmo.is_valid()) {
1099 
1100 							_edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, false);
1101 							_edit.gizmo = Ref<SpatialEditorGizmo>();
1102 							break;
1103 						}
1104 						if (clicked) {
1105 							_select_clicked(clicked_wants_append, true);
1106 							//clickd processing was deferred
1107 							clicked = 0;
1108 						}
1109 
1110 						if (cursor.region_select) {
1111 							_select_region();
1112 							cursor.region_select = false;
1113 							surface->update();
1114 						}
1115 
1116 						if (_edit.mode != TRANSFORM_NONE) {
1117 
1118 							static const char *_transform_name[4] = { "None", "Rotate", "Translate", "Scale" };
1119 							undo_redo->create_action(_transform_name[_edit.mode]);
1120 
1121 							List<Node *> &selection = editor_selection->get_selected_node_list();
1122 
1123 							for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1124 
1125 								Spatial *sp = E->get()->cast_to<Spatial>();
1126 								if (!sp)
1127 									continue;
1128 
1129 								SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1130 								if (!se)
1131 									continue;
1132 
1133 								undo_redo->add_do_method(sp, "set_global_transform", sp->get_global_transform());
1134 								undo_redo->add_undo_method(sp, "set_global_transform", se->original);
1135 							}
1136 							undo_redo->commit_action();
1137 							_edit.mode = TRANSFORM_NONE;
1138 							//VisualServer::get_singleton()->poly_clear(indicators);
1139 							set_message("");
1140 						}
1141 
1142 						surface->update();
1143 					}
1144 				} break;
1145 			}
1146 		} break;
1147 		case InputEvent::MOUSE_MOTION: {
1148 			const InputEventMouseMotion &m = p_event.mouse_motion;
1149 			_edit.mouse_pos = Point2(p_event.mouse_motion.x, p_event.mouse_motion.y);
1150 
1151 			if (spatial_editor->get_selected()) {
1152 
1153 				Ref<SpatialEditorGizmo> seg = spatial_editor->get_selected()->get_gizmo();
1154 				if (seg.is_valid()) {
1155 
1156 					int selected_handle = -1;
1157 
1158 					int handle = -1;
1159 					Vector3 point;
1160 					Vector3 normal;
1161 					bool inters = seg->intersect_ray(camera, _edit.mouse_pos, point, normal, &handle, false);
1162 					if (inters && handle != -1) {
1163 
1164 						selected_handle = handle;
1165 					}
1166 
1167 					if (selected_handle != spatial_editor->get_over_gizmo_handle()) {
1168 						spatial_editor->set_over_gizmo_handle(selected_handle);
1169 						spatial_editor->get_selected()->update_gizmo();
1170 						if (selected_handle != -1)
1171 							spatial_editor->select_gizmo_highlight_axis(-1);
1172 					}
1173 				}
1174 			}
1175 
1176 			if (spatial_editor->get_over_gizmo_handle() == -1 && !(m.button_mask & 1) && !_edit.gizmo.is_valid()) {
1177 
1178 				_gizmo_select(_edit.mouse_pos, true);
1179 			}
1180 
1181 			NavigationScheme nav_scheme = _get_navigation_schema("3d_editor/navigation_scheme");
1182 			NavigationMode nav_mode = NAVIGATION_NONE;
1183 
1184 			if (_edit.gizmo.is_valid()) {
1185 
1186 				_edit.gizmo->set_handle(_edit.gizmo_handle, camera, Vector2(m.x, m.y));
1187 				Variant v = _edit.gizmo->get_handle_value(_edit.gizmo_handle);
1188 				String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle);
1189 				set_message(n + ": " + String(v));
1190 
1191 			} else if (m.button_mask & 1) {
1192 
1193 				if (nav_scheme == NAVIGATION_MAYA && m.mod.alt) {
1194 					nav_mode = NAVIGATION_ORBIT;
1195 				} else if (nav_scheme == NAVIGATION_MODO && m.mod.alt && m.mod.shift) {
1196 					nav_mode = NAVIGATION_PAN;
1197 				} else if (nav_scheme == NAVIGATION_MODO && m.mod.alt && m.mod.control) {
1198 					nav_mode = NAVIGATION_ZOOM;
1199 				} else if (nav_scheme == NAVIGATION_MODO && m.mod.alt) {
1200 					nav_mode = NAVIGATION_ORBIT;
1201 				} else {
1202 					if (clicked) {
1203 
1204 						if (!clicked_includes_current) {
1205 
1206 							_select_clicked(clicked_wants_append, true);
1207 							//clickd processing was deferred
1208 						}
1209 
1210 						_compute_edit(_edit.mouse_pos);
1211 						clicked = 0;
1212 
1213 						_edit.mode = TRANSFORM_TRANSLATE;
1214 					}
1215 
1216 					if (cursor.region_select && nav_mode == NAVIGATION_NONE) {
1217 
1218 						cursor.region_end = Point2(m.x, m.y);
1219 						surface->update();
1220 						return;
1221 					}
1222 
1223 					if (_edit.mode == TRANSFORM_NONE && nav_mode == NAVIGATION_NONE)
1224 						break;
1225 
1226 					Vector3 ray_pos = _get_ray_pos(Vector2(m.x, m.y));
1227 					Vector3 ray = _get_ray(Vector2(m.x, m.y));
1228 
1229 					switch (_edit.mode) {
1230 
1231 						case TRANSFORM_SCALE: {
1232 
1233 							Plane plane = Plane(_edit.center, _get_camera_normal());
1234 
1235 							Vector3 intersection;
1236 							if (!plane.intersects_ray(ray_pos, ray, &intersection))
1237 								break;
1238 
1239 							Vector3 click;
1240 							if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
1241 								break;
1242 
1243 							float center_click_dist = click.distance_to(_edit.center);
1244 							float center_inters_dist = intersection.distance_to(_edit.center);
1245 							if (center_click_dist == 0)
1246 								break;
1247 
1248 							float scale = (center_inters_dist / center_click_dist) * 100.0;
1249 
1250 							if (_edit.snap || spatial_editor->is_snap_enabled()) {
1251 
1252 								scale = Math::stepify(scale, spatial_editor->get_scale_snap());
1253 							}
1254 
1255 							set_message(vformat(TTR("Scaling to %s%%."), String::num(scale, 1)));
1256 							scale /= 100.0;
1257 
1258 							Transform r;
1259 							r.basis.scale(Vector3(scale, scale, scale));
1260 
1261 							List<Node *> &selection = editor_selection->get_selected_node_list();
1262 
1263 							for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1264 
1265 								Spatial *sp = E->get()->cast_to<Spatial>();
1266 								if (!sp)
1267 									continue;
1268 
1269 								SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1270 								if (!se)
1271 									continue;
1272 
1273 								Transform original = se->original;
1274 
1275 								Transform base = Transform(Matrix3(), _edit.center);
1276 								Transform t = base * (r * (base.inverse() * original));
1277 
1278 								sp->set_global_transform(t);
1279 							}
1280 
1281 							surface->update();
1282 
1283 						} break;
1284 
1285 						case TRANSFORM_TRANSLATE: {
1286 
1287 							Vector3 motion_mask;
1288 							Plane plane;
1289 
1290 							switch (_edit.plane) {
1291 								case TRANSFORM_VIEW:
1292 									motion_mask = Vector3(0, 0, 0);
1293 									plane = Plane(_edit.center, _get_camera_normal());
1294 									break;
1295 								case TRANSFORM_X_AXIS:
1296 									motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
1297 									plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
1298 									break;
1299 								case TRANSFORM_Y_AXIS:
1300 									motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
1301 									plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
1302 									break;
1303 								case TRANSFORM_Z_AXIS:
1304 									motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
1305 									plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
1306 									break;
1307 							}
1308 
1309 							Vector3 intersection;
1310 							if (!plane.intersects_ray(ray_pos, ray, &intersection))
1311 								break;
1312 
1313 							Vector3 click;
1314 							if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
1315 								break;
1316 
1317 							//_validate_selection();
1318 							Vector3 motion = intersection - click;
1319 							if (motion_mask != Vector3()) {
1320 								motion = motion_mask.dot(motion) * motion_mask;
1321 							}
1322 
1323 							float snap = 0;
1324 
1325 							if (_edit.snap || spatial_editor->is_snap_enabled()) {
1326 
1327 								snap = spatial_editor->get_translate_snap();
1328 								motion.snap(snap);
1329 							}
1330 
1331 							//set_message("Translating: "+motion);
1332 
1333 							List<Node *> &selection = editor_selection->get_selected_node_list();
1334 
1335 							for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1336 
1337 								Spatial *sp = E->get()->cast_to<Spatial>();
1338 								if (!sp) {
1339 									continue;
1340 								}
1341 
1342 								SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1343 								if (!se) {
1344 									continue;
1345 								}
1346 
1347 								Transform t = se->original;
1348 								t.origin += motion;
1349 								sp->set_global_transform(t);
1350 							}
1351 						} break;
1352 
1353 						case TRANSFORM_ROTATE: {
1354 
1355 							Plane plane;
1356 
1357 							switch (_edit.plane) {
1358 								case TRANSFORM_VIEW:
1359 									plane = Plane(_edit.center, _get_camera_normal());
1360 									break;
1361 								case TRANSFORM_X_AXIS:
1362 									plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
1363 									break;
1364 								case TRANSFORM_Y_AXIS:
1365 									plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(1));
1366 									break;
1367 								case TRANSFORM_Z_AXIS:
1368 									plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(2));
1369 									break;
1370 							}
1371 
1372 							Vector3 intersection;
1373 							if (!plane.intersects_ray(ray_pos, ray, &intersection))
1374 								break;
1375 
1376 							Vector3 click;
1377 							if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
1378 								break;
1379 
1380 							Vector3 y_axis = (click - _edit.center).normalized();
1381 							Vector3 x_axis = plane.normal.cross(y_axis).normalized();
1382 
1383 							float angle = Math::atan2(x_axis.dot(intersection - _edit.center), y_axis.dot(intersection - _edit.center));
1384 							if (_edit.snap || spatial_editor->is_snap_enabled()) {
1385 
1386 								float snap = spatial_editor->get_rotate_snap();
1387 
1388 								if (snap) {
1389 									angle = Math::rad2deg(angle) + snap * 0.5; //else it wont reach +180
1390 									angle -= Math::fmod(angle, snap);
1391 									set_message(vformat(TTR("Rotating %s degrees."), rtos(angle)));
1392 									angle = Math::deg2rad(angle);
1393 								} else
1394 									set_message(vformat(TTR("Rotating %s degrees."), rtos(Math::rad2deg(angle))));
1395 
1396 							} else {
1397 								set_message(vformat(TTR("Rotating %s degrees."), rtos(Math::rad2deg(angle))));
1398 							}
1399 
1400 							Transform r;
1401 							r.basis.rotate(plane.normal, -angle);
1402 
1403 							List<Node *> &selection = editor_selection->get_selected_node_list();
1404 
1405 							for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1406 
1407 								Spatial *sp = E->get()->cast_to<Spatial>();
1408 								if (!sp)
1409 									continue;
1410 
1411 								SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1412 								if (!se)
1413 									continue;
1414 
1415 								Transform original = se->original;
1416 
1417 								Transform base = Transform(Matrix3(), _edit.center);
1418 								Transform t = base * (r * (base.inverse() * original));
1419 
1420 								sp->set_global_transform(t);
1421 							}
1422 
1423 							surface->update();
1424 							/*
1425 							VisualServer::get_singleton()->poly_clear(indicators);
1426 
1427 							Vector<Vector3> points;
1428 							Vector<Vector3> empty;
1429 							Vector<Color> colors;
1430 							points.push_back(intersection);
1431 							points.push_back(_edit.original.origin);
1432 							colors.push_back( Color(255,155,100) );
1433 							colors.push_back( Color(255,155,100) );
1434 							VisualServer::get_singleton()->poly_add_primitive(indicators,points,empty,colors,empty);
1435 							*/
1436 						} break;
1437 						default: {}
1438 					}
1439 				}
1440 
1441 			} else if (m.button_mask & 2) {
1442 
1443 				if (nav_scheme == NAVIGATION_MAYA && m.mod.alt) {
1444 					nav_mode = NAVIGATION_ZOOM;
1445 				}
1446 
1447 			} else if (m.button_mask & 4) {
1448 
1449 				if (nav_scheme == NAVIGATION_GODOT) {
1450 
1451 					int mod = 0;
1452 					if (m.mod.shift)
1453 						mod = KEY_SHIFT;
1454 					if (m.mod.alt)
1455 						mod = KEY_ALT;
1456 					if (m.mod.control)
1457 						mod = KEY_CONTROL;
1458 					if (m.mod.meta)
1459 						mod = KEY_META;
1460 
1461 					if (mod == _get_key_modifier("3d_editor/pan_modifier"))
1462 						nav_mode = NAVIGATION_PAN;
1463 					else if (mod == _get_key_modifier("3d_editor/zoom_modifier"))
1464 						nav_mode = NAVIGATION_ZOOM;
1465 					else if (mod == _get_key_modifier("3d_editor/orbit_modifier"))
1466 						nav_mode = NAVIGATION_ORBIT;
1467 
1468 				} else if (nav_scheme == NAVIGATION_MAYA) {
1469 					if (m.mod.alt)
1470 						nav_mode = NAVIGATION_PAN;
1471 				}
1472 
1473 			} else if (EditorSettings::get_singleton()->get("3d_editor/emulate_3_button_mouse")) {
1474 				// Handle trackpad (no external mouse) use case
1475 				int mod = 0;
1476 				if (m.mod.shift)
1477 					mod = KEY_SHIFT;
1478 				if (m.mod.alt)
1479 					mod = KEY_ALT;
1480 				if (m.mod.control)
1481 					mod = KEY_CONTROL;
1482 				if (m.mod.meta)
1483 					mod = KEY_META;
1484 
1485 				if (mod) {
1486 					if (mod == _get_key_modifier("3d_editor/pan_modifier"))
1487 						nav_mode = NAVIGATION_PAN;
1488 					else if (mod == _get_key_modifier("3d_editor/zoom_modifier"))
1489 						nav_mode = NAVIGATION_ZOOM;
1490 					else if (mod == _get_key_modifier("3d_editor/orbit_modifier"))
1491 						nav_mode = NAVIGATION_ORBIT;
1492 				}
1493 			}
1494 
1495 			switch (nav_mode) {
1496 				case NAVIGATION_PAN: {
1497 
1498 					real_t pan_speed = 1 / 150.0;
1499 					int pan_speed_modifier = 10;
1500 					if (nav_scheme == NAVIGATION_MAYA && m.mod.shift)
1501 						pan_speed *= pan_speed_modifier;
1502 
1503 					Point2i relative;
1504 					if (bool(EditorSettings::get_singleton()->get("3d_editor/warped_mouse_panning"))) {
1505 						relative = Input::get_singleton()->warp_mouse_motion(m, surface->get_global_rect());
1506 					} else {
1507 						relative = Point2i(m.relative_x, m.relative_y);
1508 					}
1509 
1510 					Transform camera_transform;
1511 
1512 					camera_transform.translate(cursor.pos);
1513 					camera_transform.basis.rotate(Vector3(0, 1, 0), cursor.y_rot);
1514 					camera_transform.basis.rotate(Vector3(1, 0, 0), cursor.x_rot);
1515 					Vector3 translation(-relative.x * pan_speed, relative.y * pan_speed, 0);
1516 					translation *= cursor.distance / DISTANCE_DEFAULT;
1517 					camera_transform.translate(translation);
1518 					cursor.pos = camera_transform.origin;
1519 
1520 				} break;
1521 
1522 				case NAVIGATION_ZOOM: {
1523 					real_t zoom_speed = 1 / 80.0;
1524 					int zoom_speed_modifier = 10;
1525 					if (nav_scheme == NAVIGATION_MAYA && m.mod.shift)
1526 						zoom_speed *= zoom_speed_modifier;
1527 
1528 					NavigationZoomStyle zoom_style = _get_navigation_zoom_style("3d_editor/zoom_style");
1529 					if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) {
1530 						if (m.relative_x > 0)
1531 							cursor.distance *= 1 - m.relative_x * zoom_speed;
1532 						else if (m.relative_x < 0)
1533 							cursor.distance /= 1 + m.relative_x * zoom_speed;
1534 					} else {
1535 						if (m.relative_y > 0)
1536 							cursor.distance *= 1 + m.relative_y * zoom_speed;
1537 						else if (m.relative_y < 0)
1538 							cursor.distance /= 1 - m.relative_y * zoom_speed;
1539 					}
1540 
1541 				} break;
1542 
1543 				case NAVIGATION_ORBIT: {
1544 					cursor.x_rot += m.relative_y / 80.0;
1545 					cursor.y_rot += m.relative_x / 80.0;
1546 					if (cursor.x_rot > Math_PI / 2.0)
1547 						cursor.x_rot = Math_PI / 2.0;
1548 					if (cursor.x_rot < -Math_PI / 2.0)
1549 						cursor.x_rot = -Math_PI / 2.0;
1550 					name = "";
1551 					_update_name();
1552 				} break;
1553 
1554 				default: {}
1555 			}
1556 		} break;
1557 		case InputEvent::KEY: {
1558 			const InputEventKey &k = p_event.key;
1559 			if (!k.pressed)
1560 				break;
1561 
1562 			if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) {
1563 				if (_edit.mode != TRANSFORM_NONE) {
1564 					_edit.snap = true;
1565 				}
1566 			}
1567 			if (ED_IS_SHORTCUT("spatial_editor/bottom_view", p_event)) {
1568 				cursor.y_rot = 0;
1569 				cursor.x_rot = -Math_PI / 2.0;
1570 				set_message(TTR("Bottom View."), 2);
1571 				name = TTR("Bottom");
1572 				_update_name();
1573 			}
1574 			if (ED_IS_SHORTCUT("spatial_editor/top_view", p_event)) {
1575 				cursor.y_rot = 0;
1576 				cursor.x_rot = Math_PI / 2.0;
1577 				set_message(TTR("Top View."), 2);
1578 				name = TTR("Top");
1579 				_update_name();
1580 			}
1581 			if (ED_IS_SHORTCUT("spatial_editor/rear_view", p_event)) {
1582 				cursor.x_rot = 0;
1583 				cursor.y_rot = Math_PI;
1584 				set_message(TTR("Rear View."), 2);
1585 				name = TTR("Rear");
1586 				_update_name();
1587 			}
1588 			if (ED_IS_SHORTCUT("spatial_editor/front_view", p_event)) {
1589 				cursor.x_rot = 0;
1590 				cursor.y_rot = 0;
1591 				set_message(TTR("Front View."), 2);
1592 				name = TTR("Front");
1593 				_update_name();
1594 			}
1595 			if (ED_IS_SHORTCUT("spatial_editor/left_view", p_event)) {
1596 				cursor.x_rot = 0;
1597 				cursor.y_rot = Math_PI / 2.0;
1598 				set_message(TTR("Left View."), 2);
1599 				name = TTR("Left");
1600 				_update_name();
1601 			}
1602 			if (ED_IS_SHORTCUT("spatial_editor/right_view", p_event)) {
1603 				cursor.x_rot = 0;
1604 				cursor.y_rot = -Math_PI / 2.0;
1605 				set_message(TTR("Right View."), 2);
1606 				name = TTR("Right");
1607 				_update_name();
1608 			}
1609 			if (ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) {
1610 				_menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_ORTHOGONAL);
1611 				_update_name();
1612 			}
1613 			if (ED_IS_SHORTCUT("spatial_editor/insert_anim_key", p_event)) {
1614 				if (!get_selected_count() || _edit.mode != TRANSFORM_NONE)
1615 					break;
1616 
1617 				if (!AnimationPlayerEditor::singleton->get_key_editor()->has_keying()) {
1618 					set_message(TTR("Keying is disabled (no key inserted)."));
1619 					break;
1620 				}
1621 
1622 				List<Node *> &selection = editor_selection->get_selected_node_list();
1623 
1624 				for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1625 
1626 					Spatial *sp = E->get()->cast_to<Spatial>();
1627 					if (!sp)
1628 						continue;
1629 
1630 					emit_signal("transform_key_request", sp, "", sp->get_transform());
1631 				}
1632 
1633 				set_message(TTR("Animation Key Inserted."));
1634 			}
1635 
1636 			if (k.scancode == KEY_SPACE) {
1637 				if (!k.pressed) emit_signal("toggle_maximize_view", this);
1638 			}
1639 
1640 		} break;
1641 	}
1642 }
1643 
set_message(String p_message,float p_time)1644 void SpatialEditorViewport::set_message(String p_message, float p_time) {
1645 
1646 	message = p_message;
1647 	message_time = p_time;
1648 }
1649 
_notification(int p_what)1650 void SpatialEditorViewport::_notification(int p_what) {
1651 
1652 	if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
1653 
1654 		bool visible = is_visible();
1655 
1656 		set_process(visible);
1657 
1658 		if (visible)
1659 			_update_camera();
1660 
1661 		call_deferred("update_transform_gizmo_view");
1662 	}
1663 
1664 	if (p_what == NOTIFICATION_RESIZED) {
1665 
1666 		call_deferred("update_transform_gizmo_view");
1667 	}
1668 
1669 	if (p_what == NOTIFICATION_PROCESS) {
1670 
1671 		//force editr camera
1672 		/*
1673 		current_camera=get_root_node()->get_current_camera();
1674 		if (current_camera!=camera) {
1675 
1676 
1677 		}
1678 		*/
1679 
1680 		_update_camera();
1681 
1682 		Map<Node *, Object *> &selection = editor_selection->get_selection();
1683 
1684 		bool changed = false;
1685 		bool exist = false;
1686 
1687 		for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) {
1688 
1689 			Spatial *sp = E->key()->cast_to<Spatial>();
1690 			if (!sp)
1691 				continue;
1692 
1693 			SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1694 			if (!se)
1695 				continue;
1696 
1697 			VisualInstance *vi = sp->cast_to<VisualInstance>();
1698 
1699 			if (se->aabb.has_no_surface()) {
1700 
1701 				se->aabb = vi ? vi->get_aabb() : AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
1702 			}
1703 
1704 			Transform t = sp->get_global_transform();
1705 			t.translate(se->aabb.pos);
1706 			t.basis.scale(se->aabb.size);
1707 
1708 			exist = true;
1709 			if (se->last_xform == t)
1710 				continue;
1711 			changed = true;
1712 			se->last_xform = t;
1713 			VisualServer::get_singleton()->instance_set_transform(se->sbox_instance, t);
1714 		}
1715 
1716 		if (changed || (spatial_editor->is_gizmo_visible() && !exist)) {
1717 			spatial_editor->update_transform_gizmo();
1718 		}
1719 
1720 		if (message_time > 0) {
1721 
1722 			if (message != last_message) {
1723 				surface->update();
1724 				last_message = message;
1725 			}
1726 
1727 			message_time -= get_fixed_process_delta_time();
1728 			if (message_time < 0)
1729 				surface->update();
1730 		}
1731 
1732 		// FPS Counter.
1733 		bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS)) && !previewing;
1734 		if (show_fps != fps->is_visible()) {
1735 			if (show_fps)
1736 				fps->show();
1737 			else
1738 				fps->hide();
1739 		}
1740 
1741 		if (show_fps) {
1742 			const float os_fps = OS::get_singleton()->get_frames_per_second();
1743 			String text = TTR("FPS") + ": " + itos(os_fps) + " (" + String::num(1000.0f / os_fps, 2) + " ms)";
1744 
1745 			if (fps_label->get_text() != text || surface->get_size() != prev_size) {
1746 				fps_label->set_text(text);
1747 				Vector2 container_position = Vector2(surface->get_size().x - fps->get_size().x - 20, 20);
1748 				if (preview)
1749 					container_position.y += 20;
1750 
1751 				container_position *= EDSCALE;
1752 				fps->set_pos(container_position);
1753 			}
1754 		}
1755 	}
1756 
1757 	if (p_what == NOTIFICATION_ENTER_TREE) {
1758 
1759 		surface->connect("draw", this, "_draw");
1760 		surface->connect("input_event", this, "_sinput");
1761 		surface->connect("mouse_enter", this, "_smouseenter");
1762 		fps->add_style_override("panel", get_stylebox("panel", "Panel"));
1763 		preview_camera->set_icon(get_icon("Camera", "EditorIcons"));
1764 		_init_gizmo_instance(index);
1765 	}
1766 	if (p_what == NOTIFICATION_EXIT_TREE) {
1767 
1768 		_finish_gizmo_instances();
1769 	}
1770 
1771 	if (p_what == NOTIFICATION_MOUSE_ENTER) {
1772 	}
1773 
1774 	if (p_what == NOTIFICATION_DRAW) {
1775 	}
1776 }
1777 
_draw()1778 void SpatialEditorViewport::_draw() {
1779 
1780 	if (surface->has_focus()) {
1781 		Size2 size = surface->get_size();
1782 		Rect2 r = Rect2(Point2(), size);
1783 		get_stylebox("EditorFocus", "EditorStyles")->draw(surface->get_canvas_item(), r);
1784 	}
1785 
1786 	RID ci = surface->get_canvas_item();
1787 
1788 	if (cursor.region_select) {
1789 
1790 		VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin), Color(0.7, 0.7, 1.0, 0.3));
1791 	}
1792 
1793 	if (message_time > 0) {
1794 		Ref<Font> font = get_font("font", "Label");
1795 		Point2 msgpos = Point2(5, get_size().y - 20);
1796 		font->draw(ci, msgpos + Point2(1, 1), message, Color(0, 0, 0, 0.8));
1797 		font->draw(ci, msgpos + Point2(-1, -1), message, Color(0, 0, 0, 0.8));
1798 		font->draw(ci, msgpos, message, Color(1, 1, 1, 1));
1799 	}
1800 
1801 	if (_edit.mode == TRANSFORM_ROTATE) {
1802 
1803 		Point2 center = _point_to_screen(_edit.center);
1804 		VisualServer::get_singleton()->canvas_item_add_line(ci, _edit.mouse_pos, center, Color(0.4, 0.7, 1.0, 0.8));
1805 	}
1806 
1807 	if (previewing) {
1808 
1809 		Size2 ss = Size2(Globals::get_singleton()->get("display/width"), Globals::get_singleton()->get("display/height"));
1810 		float aspect = ss.get_aspect();
1811 		Size2 s = get_size();
1812 
1813 		Rect2 draw_rect;
1814 
1815 		switch (previewing->get_keep_aspect_mode()) {
1816 			case Camera::KEEP_WIDTH: {
1817 
1818 				draw_rect.size = Size2(s.width, s.width / aspect);
1819 				draw_rect.pos.x = 0;
1820 				draw_rect.pos.y = (s.height - draw_rect.size.y) * 0.5;
1821 
1822 			} break;
1823 			case Camera::KEEP_HEIGHT: {
1824 
1825 				draw_rect.size = Size2(s.height * aspect, s.height);
1826 				draw_rect.pos.y = 0;
1827 				draw_rect.pos.x = (s.width - draw_rect.size.x) * 0.5;
1828 
1829 			} break;
1830 		}
1831 
1832 		draw_rect = Rect2(Vector2(), s).clip(draw_rect);
1833 
1834 		surface->draw_line(draw_rect.pos, draw_rect.pos + Vector2(draw_rect.size.x, 0), Color(0.6, 0.6, 0.1, 0.5), 2.0);
1835 		surface->draw_line(draw_rect.pos + Vector2(draw_rect.size.x, 0), draw_rect.pos + draw_rect.size, Color(0.6, 0.6, 0.1, 0.5), 2.0);
1836 		surface->draw_line(draw_rect.pos + draw_rect.size, draw_rect.pos + Vector2(0, draw_rect.size.y), Color(0.6, 0.6, 0.1, 0.5), 2.0);
1837 		surface->draw_line(draw_rect.pos, draw_rect.pos + Vector2(0, draw_rect.size.y), Color(0.6, 0.6, 0.1, 0.5), 2.0);
1838 	}
1839 }
1840 
_menu_option(int p_option)1841 void SpatialEditorViewport::_menu_option(int p_option) {
1842 
1843 	switch (p_option) {
1844 
1845 		case VIEW_TOP: {
1846 
1847 			cursor.x_rot = Math_PI / 2.0;
1848 			cursor.y_rot = 0;
1849 			name = TTR("Top");
1850 			_update_name();
1851 		} break;
1852 		case VIEW_BOTTOM: {
1853 
1854 			cursor.x_rot = -Math_PI / 2.0;
1855 			cursor.y_rot = 0;
1856 			name = TTR("Bottom");
1857 			_update_name();
1858 
1859 		} break;
1860 		case VIEW_LEFT: {
1861 
1862 			cursor.y_rot = Math_PI / 2.0;
1863 			cursor.x_rot = 0;
1864 			name = TTR("Left");
1865 			_update_name();
1866 
1867 		} break;
1868 		case VIEW_RIGHT: {
1869 
1870 			cursor.y_rot = -Math_PI / 2.0;
1871 			cursor.x_rot = 0;
1872 			name = TTR("Right");
1873 			_update_name();
1874 
1875 		} break;
1876 		case VIEW_FRONT: {
1877 
1878 			cursor.y_rot = 0;
1879 			cursor.x_rot = 0;
1880 			name = TTR("Front");
1881 			_update_name();
1882 
1883 		} break;
1884 		case VIEW_REAR: {
1885 
1886 			cursor.y_rot = Math_PI;
1887 			cursor.x_rot = 0;
1888 			name = TTR("Rear");
1889 			_update_name();
1890 
1891 		} break;
1892 		case VIEW_CENTER_TO_ORIGIN: {
1893 
1894 			cursor.pos = Vector3(0, 0, 0);
1895 
1896 		} break;
1897 		case VIEW_CENTER_TO_SELECTION: {
1898 
1899 			if (!get_selected_count())
1900 				break;
1901 
1902 			Vector3 center;
1903 			int count = 0;
1904 
1905 			List<Node *> &selection = editor_selection->get_selected_node_list();
1906 
1907 			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1908 
1909 				Spatial *sp = E->get()->cast_to<Spatial>();
1910 				if (!sp)
1911 					continue;
1912 
1913 				SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1914 				if (!se)
1915 					continue;
1916 
1917 				center += sp->get_global_transform().origin;
1918 				count++;
1919 			}
1920 
1921 			if (count != 0) {
1922 				center /= float(count);
1923 			}
1924 
1925 			cursor.pos = center;
1926 		} break;
1927 		case VIEW_ALIGN_SELECTION_WITH_VIEW: {
1928 
1929 			if (!get_selected_count())
1930 				break;
1931 
1932 			Transform camera_transform = camera->get_global_transform();
1933 
1934 			List<Node *> &selection = editor_selection->get_selected_node_list();
1935 
1936 			undo_redo->create_action(TTR("Align with view"));
1937 			for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
1938 
1939 				Spatial *sp = E->get()->cast_to<Spatial>();
1940 				if (!sp)
1941 					continue;
1942 
1943 				SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
1944 				if (!se)
1945 					continue;
1946 
1947 				Transform xform = camera_transform;
1948 				xform.scale_basis(sp->get_scale());
1949 
1950 				undo_redo->add_do_method(sp, "set_global_transform", xform);
1951 				undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform());
1952 			}
1953 			undo_redo->commit_action();
1954 		} break;
1955 		case VIEW_ENVIRONMENT: {
1956 
1957 			int idx = view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT);
1958 			bool current = view_menu->get_popup()->is_item_checked(idx);
1959 			current = !current;
1960 			if (current) {
1961 
1962 				camera->set_environment(RES());
1963 			} else {
1964 
1965 				camera->set_environment(SpatialEditor::get_singleton()->get_viewport_environment());
1966 			}
1967 
1968 			view_menu->get_popup()->set_item_checked(idx, current);
1969 
1970 		} break;
1971 		case VIEW_PERSPECTIVE: {
1972 
1973 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true);
1974 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), false);
1975 			orthogonal = false;
1976 			call_deferred("update_transform_gizmo_view");
1977 			_update_name();
1978 
1979 		} break;
1980 		case VIEW_ORTHOGONAL: {
1981 
1982 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), false);
1983 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL), true);
1984 			orthogonal = true;
1985 			call_deferred("update_transform_gizmo_view");
1986 			_update_name();
1987 
1988 		} break;
1989 		case VIEW_AUDIO_LISTENER: {
1990 
1991 			int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
1992 			bool current = view_menu->get_popup()->is_item_checked(idx);
1993 			current = !current;
1994 			viewport->set_as_audio_listener(current);
1995 			view_menu->get_popup()->set_item_checked(idx, current);
1996 
1997 		} break;
1998 		case VIEW_GIZMOS: {
1999 
2000 			int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS);
2001 			bool current = view_menu->get_popup()->is_item_checked(idx);
2002 			current = !current;
2003 			if (current)
2004 				camera->set_visible_layers(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER));
2005 			else
2006 				camera->set_visible_layers(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + index)) | (1 << GIZMO_GRID_LAYER));
2007 			view_menu->get_popup()->set_item_checked(idx, current);
2008 
2009 		} break;
2010 		case VIEW_FPS: {
2011 			int idx = view_menu->get_popup()->get_item_index(VIEW_FPS);
2012 			bool current = view_menu->get_popup()->is_item_checked(idx);
2013 			view_menu->get_popup()->set_item_checked(idx, !current);
2014 
2015 		} break;
2016 	}
2017 }
2018 
_preview_exited_scene()2019 void SpatialEditorViewport::_preview_exited_scene() {
2020 
2021 	preview_camera->set_pressed(false);
2022 	_toggle_camera_preview(false);
2023 	view_menu->show();
2024 }
2025 
_init_gizmo_instance(int p_idx)2026 void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
2027 
2028 	uint32_t layer = 1 << (GIZMO_BASE_LAYER + p_idx); //|(1<<GIZMO_GRID_LAYER);
2029 
2030 	for (int i = 0; i < 3; i++) {
2031 		move_gizmo_instance[i] = VS::get_singleton()->instance_create();
2032 		VS::get_singleton()->instance_set_base(move_gizmo_instance[i], spatial_editor->get_move_gizmo(i)->get_rid());
2033 		VS::get_singleton()->instance_set_scenario(move_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
2034 		VS::get_singleton()->instance_geometry_set_flag(move_gizmo_instance[i], VS::INSTANCE_FLAG_VISIBLE, false);
2035 		//VS::get_singleton()->instance_geometry_set_flag(move_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
2036 		VS::get_singleton()->instance_geometry_set_cast_shadows_setting(move_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
2037 		VS::get_singleton()->instance_set_layer_mask(move_gizmo_instance[i], layer);
2038 
2039 		rotate_gizmo_instance[i] = VS::get_singleton()->instance_create();
2040 		VS::get_singleton()->instance_set_base(rotate_gizmo_instance[i], spatial_editor->get_rotate_gizmo(i)->get_rid());
2041 		VS::get_singleton()->instance_set_scenario(rotate_gizmo_instance[i], get_tree()->get_root()->get_world()->get_scenario());
2042 		VS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i], VS::INSTANCE_FLAG_VISIBLE, false);
2043 		//VS::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i],VS::INSTANCE_FLAG_DEPH_SCALE,true);
2044 		VS::get_singleton()->instance_geometry_set_cast_shadows_setting(rotate_gizmo_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
2045 		VS::get_singleton()->instance_set_layer_mask(rotate_gizmo_instance[i], layer);
2046 	}
2047 }
2048 
_finish_gizmo_instances()2049 void SpatialEditorViewport::_finish_gizmo_instances() {
2050 
2051 	for (int i = 0; i < 3; i++) {
2052 		VS::get_singleton()->free(move_gizmo_instance[i]);
2053 		VS::get_singleton()->free(rotate_gizmo_instance[i]);
2054 	}
2055 }
_toggle_camera_preview(bool p_activate)2056 void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
2057 
2058 	ERR_FAIL_COND(p_activate && !preview);
2059 	ERR_FAIL_COND(!p_activate && !previewing);
2060 
2061 	if (!p_activate) {
2062 
2063 		previewing->disconnect("exit_tree", this, "_preview_exited_scene");
2064 		previewing = NULL;
2065 		VS::get_singleton()->viewport_attach_camera(viewport->get_viewport(), camera->get_camera()); //restore
2066 		if (!preview)
2067 			preview_camera->hide();
2068 		view_menu->show();
2069 		surface->update();
2070 
2071 	} else {
2072 
2073 		previewing = preview;
2074 		previewing->connect("exit_tree", this, "_preview_exited_scene");
2075 		VS::get_singleton()->viewport_attach_camera(viewport->get_viewport(), preview->get_camera()); //replace
2076 		view_menu->hide();
2077 		surface->update();
2078 	}
2079 }
2080 
_selection_result_pressed(int p_result)2081 void SpatialEditorViewport::_selection_result_pressed(int p_result) {
2082 
2083 	if (selection_results.size() <= p_result)
2084 		return;
2085 
2086 	clicked = selection_results[p_result].item->get_instance_ID();
2087 
2088 	if (clicked) {
2089 		_select_clicked(clicked_wants_append, true);
2090 		clicked = 0;
2091 	}
2092 }
2093 
_selection_menu_hide()2094 void SpatialEditorViewport::_selection_menu_hide() {
2095 
2096 	selection_results.clear();
2097 	selection_menu->clear();
2098 	selection_menu->set_size(Vector2(0, 0));
2099 }
2100 
set_can_preview(Camera * p_preview)2101 void SpatialEditorViewport::set_can_preview(Camera *p_preview) {
2102 
2103 	preview = p_preview;
2104 
2105 	if (!preview_camera->is_pressed()) {
2106 
2107 		if (p_preview) {
2108 			preview_camera->show();
2109 		} else {
2110 			preview_camera->hide();
2111 		}
2112 	}
2113 }
2114 
update_transform_gizmo_view()2115 void SpatialEditorViewport::update_transform_gizmo_view() {
2116 
2117 	if (!is_visible())
2118 		return;
2119 
2120 	Transform xform = spatial_editor->get_gizmo_transform();
2121 
2122 	Transform camera_xform = camera->get_transform();
2123 	Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
2124 	Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
2125 	Plane p(camera_xform.origin, camz);
2126 	float gizmo_d = Math::abs(p.distance_to(xform.origin));
2127 	float d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y;
2128 	float d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y;
2129 	float dd = Math::abs(d0 - d1);
2130 	if (dd == 0)
2131 		dd = 0.0001;
2132 
2133 	float gsize = EditorSettings::get_singleton()->get("3d_editor/manipulator_gizmo_size");
2134 	gizmo_scale = (gsize / Math::abs(dd));
2135 	Vector3 scale = Vector3(1, 1, 1) * gizmo_scale;
2136 
2137 	xform.basis.scale(scale);
2138 
2139 	//xform.basis.scale(GIZMO_SCALE_DEFAULT*Vector3(1,1,1));
2140 
2141 	for (int i = 0; i < 3; i++) {
2142 		VisualServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform);
2143 		VisualServer::get_singleton()->instance_geometry_set_flag(move_gizmo_instance[i], VS::INSTANCE_FLAG_VISIBLE, spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE));
2144 		VisualServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform);
2145 		VisualServer::get_singleton()->instance_geometry_set_flag(rotate_gizmo_instance[i], VS::INSTANCE_FLAG_VISIBLE, spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE));
2146 	}
2147 }
2148 
set_state(const Dictionary & p_state)2149 void SpatialEditorViewport::set_state(const Dictionary &p_state) {
2150 
2151 	cursor.pos = p_state["pos"];
2152 	cursor.x_rot = p_state["x_rot"];
2153 	cursor.y_rot = p_state["y_rot"];
2154 	cursor.distance = p_state["distance"];
2155 	bool env = p_state["use_environment"];
2156 	bool orth = p_state["use_orthogonal"];
2157 	if (orth)
2158 		_menu_option(VIEW_ORTHOGONAL);
2159 	else
2160 		_menu_option(VIEW_PERSPECTIVE);
2161 	if (env != camera->get_environment().is_valid())
2162 		_menu_option(VIEW_ENVIRONMENT);
2163 	if (p_state.has("listener")) {
2164 		bool listener = p_state["listener"];
2165 
2166 		int idx = view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER);
2167 		viewport->set_as_audio_listener(listener);
2168 		view_menu->get_popup()->set_item_checked(idx, listener);
2169 	}
2170 
2171 	if (p_state.has("previewing")) {
2172 		Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]);
2173 		if (pv && pv->cast_to<Camera>()) {
2174 			previewing = pv->cast_to<Camera>();
2175 			previewing->connect("exit_tree", this, "_preview_exited_scene");
2176 			VS::get_singleton()->viewport_attach_camera(viewport->get_viewport(), previewing->get_camera()); //replace
2177 			view_menu->hide();
2178 			surface->update();
2179 			preview_camera->set_pressed(true);
2180 			preview_camera->show();
2181 		}
2182 	}
2183 }
2184 
get_state() const2185 Dictionary SpatialEditorViewport::get_state() const {
2186 
2187 	Dictionary d;
2188 	d["pos"] = cursor.pos;
2189 	d["x_rot"] = cursor.x_rot;
2190 	d["y_rot"] = cursor.y_rot;
2191 	d["distance"] = cursor.distance;
2192 	d["use_environment"] = camera->get_environment().is_valid();
2193 	d["use_orthogonal"] = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL;
2194 	d["listener"] = viewport->is_audio_listener();
2195 	if (previewing) {
2196 		d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing);
2197 	}
2198 
2199 	return d;
2200 }
2201 
_bind_methods()2202 void SpatialEditorViewport::_bind_methods() {
2203 
2204 	ObjectTypeDB::bind_method(_MD("_draw"), &SpatialEditorViewport::_draw);
2205 	ObjectTypeDB::bind_method(_MD("_smouseenter"), &SpatialEditorViewport::_smouseenter);
2206 	ObjectTypeDB::bind_method(_MD("_sinput"), &SpatialEditorViewport::_sinput);
2207 	ObjectTypeDB::bind_method(_MD("_menu_option"), &SpatialEditorViewport::_menu_option);
2208 	ObjectTypeDB::bind_method(_MD("_toggle_camera_preview"), &SpatialEditorViewport::_toggle_camera_preview);
2209 	ObjectTypeDB::bind_method(_MD("_preview_exited_scene"), &SpatialEditorViewport::_preview_exited_scene);
2210 	ObjectTypeDB::bind_method(_MD("update_transform_gizmo_view"), &SpatialEditorViewport::update_transform_gizmo_view);
2211 	ObjectTypeDB::bind_method(_MD("_selection_result_pressed"), &SpatialEditorViewport::_selection_result_pressed);
2212 	ObjectTypeDB::bind_method(_MD("_selection_menu_hide"), &SpatialEditorViewport::_selection_menu_hide);
2213 
2214 	ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
2215 }
2216 
reset()2217 void SpatialEditorViewport::reset() {
2218 
2219 	orthogonal = false;
2220 	message_time = 0;
2221 	message = "";
2222 	last_message = "";
2223 	name = "";
2224 
2225 	cursor.x_rot = 0.5;
2226 	cursor.y_rot = 0.5;
2227 	cursor.distance = 4;
2228 	cursor.region_select = false;
2229 	_update_name();
2230 }
2231 
SpatialEditorViewport(SpatialEditor * p_spatial_editor,EditorNode * p_editor,int p_index)2232 SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, EditorNode *p_editor, int p_index) {
2233 
2234 	_edit.mode = TRANSFORM_NONE;
2235 	_edit.plane = TRANSFORM_VIEW;
2236 	_edit.edited_gizmo = 0;
2237 	_edit.snap = 1;
2238 	_edit.gizmo_handle = 0;
2239 
2240 	index = p_index;
2241 	editor = p_editor;
2242 	editor_selection = editor->get_editor_selection();
2243 	undo_redo = editor->get_undo_redo();
2244 	clicked = 0;
2245 	clicked_includes_current = false;
2246 	orthogonal = false;
2247 	message_time = 0;
2248 
2249 	spatial_editor = p_spatial_editor;
2250 	Control *c = memnew(Control);
2251 	add_child(c);
2252 	c->set_area_as_parent_rect();
2253 	viewport = memnew(Viewport);
2254 	viewport->set_disable_input(true);
2255 	c->add_child(viewport);
2256 	surface = memnew(Control);
2257 	add_child(surface);
2258 	surface->set_area_as_parent_rect();
2259 	camera = memnew(Camera);
2260 	camera->set_disable_gizmo(true);
2261 	camera->set_visible_layers(((1 << 20) - 1) | (1 << (GIZMO_BASE_LAYER + p_index)) | (1 << GIZMO_EDIT_LAYER) | (1 << GIZMO_GRID_LAYER));
2262 	//camera->set_environment(SpatialEditor::get_singleton()->get_viewport_environment());
2263 	viewport->add_child(camera);
2264 	camera->make_current();
2265 	surface->set_focus_mode(FOCUS_ALL);
2266 
2267 	view_menu = memnew(MenuButton);
2268 	surface->add_child(view_menu);
2269 	view_menu->set_pos(Point2(4, 4));
2270 	view_menu->set_self_opacity(0.5);
2271 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/top_view"), VIEW_TOP);
2272 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/bottom_view"), VIEW_BOTTOM);
2273 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/left_view"), VIEW_LEFT);
2274 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/right_view"), VIEW_RIGHT);
2275 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/front_view"), VIEW_FRONT);
2276 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/rear_view"), VIEW_REAR);
2277 	view_menu->get_popup()->add_separator();
2278 	view_menu->get_popup()->add_check_item(TTR("Perspective") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_PERSPECTIVE);
2279 	view_menu->get_popup()->add_check_item(TTR("Orthogonal") + " (" + ED_GET_SHORTCUT("spatial_editor/switch_perspective_orthogonal")->get_as_text() + ")", VIEW_ORTHOGONAL);
2280 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_PERSPECTIVE), true);
2281 	view_menu->get_popup()->add_separator();
2282 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_environment", TTR("Environment")), VIEW_ENVIRONMENT);
2283 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_ENVIRONMENT), true);
2284 	view_menu->get_popup()->add_separator();
2285 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_listener", TTR("Audio Listener")), VIEW_AUDIO_LISTENER);
2286 	view_menu->get_popup()->add_separator();
2287 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("Gizmos")), VIEW_GIZMOS);
2288 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS), true);
2289 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View FPS")), VIEW_FPS);
2290 
2291 	view_menu->get_popup()->add_separator();
2292 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_origin"), VIEW_CENTER_TO_ORIGIN);
2293 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/focus_selection"), VIEW_CENTER_TO_SELECTION);
2294 	view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/align_selection_with_view"), VIEW_ALIGN_SELECTION_WITH_VIEW);
2295 	view_menu->get_popup()->connect("item_pressed", this, "_menu_option");
2296 
2297 	preview_camera = memnew(Button);
2298 	preview_camera->set_toggle_mode(true);
2299 	preview_camera->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, 90);
2300 	preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10);
2301 	preview_camera->set_text("preview");
2302 	surface->add_child(preview_camera);
2303 	preview_camera->hide();
2304 	preview_camera->connect("toggled", this, "_toggle_camera_preview");
2305 	previewing = NULL;
2306 	preview = NULL;
2307 	gizmo_scale = 1.0;
2308 
2309 	// FPS Counter.
2310 	fps = memnew(PanelContainer);
2311 	fps->set_self_opacity(0.4f);
2312 	surface->add_child(fps);
2313 	fps_label = memnew(Label);
2314 	fps->add_child(fps_label);
2315 	fps->hide();
2316 
2317 	selection_menu = memnew(PopupMenu);
2318 	add_child(selection_menu);
2319 	selection_menu->set_custom_minimum_size(Vector2(100, 0));
2320 	selection_menu->connect("item_pressed", this, "_selection_result_pressed");
2321 	selection_menu->connect("popup_hide", this, "_selection_menu_hide");
2322 
2323 	if (p_index == 0) {
2324 		view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER), true);
2325 		viewport->set_as_audio_listener(true);
2326 	}
2327 
2328 	name = TTR("Top");
2329 	_update_name();
2330 
2331 	EditorSettings::get_singleton()->connect("settings_changed", this, "update_transform_gizmo_view");
2332 }
2333 
2334 SpatialEditor *SpatialEditor::singleton = NULL;
2335 
~SpatialEditorSelectedItem()2336 SpatialEditorSelectedItem::~SpatialEditorSelectedItem() {
2337 
2338 	if (sbox_instance.is_valid())
2339 		VisualServer::get_singleton()->free(sbox_instance);
2340 }
2341 
select_gizmo_highlight_axis(int p_axis)2342 void SpatialEditor::select_gizmo_highlight_axis(int p_axis) {
2343 
2344 	for (int i = 0; i < 3; i++) {
2345 
2346 		move_gizmo[i]->surface_set_material(0, i == p_axis ? gizmo_hl : gizmo_color[i]);
2347 		rotate_gizmo[i]->surface_set_material(0, (i + 3) == p_axis ? gizmo_hl : gizmo_color[i]);
2348 	}
2349 }
2350 
update_transform_gizmo()2351 void SpatialEditor::update_transform_gizmo() {
2352 
2353 	List<Node *> &selection = editor_selection->get_selected_node_list();
2354 	AABB center;
2355 	bool first = true;
2356 
2357 	Matrix3 gizmo_basis;
2358 	bool local_gizmo_coords = transform_menu->get_popup()->is_item_checked(transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_LOCAL_COORDS));
2359 
2360 	for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
2361 
2362 		Spatial *sp = E->get()->cast_to<Spatial>();
2363 		if (!sp)
2364 			continue;
2365 
2366 		SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
2367 		if (!se)
2368 			continue;
2369 
2370 		Transform xf = se->sp->get_global_transform();
2371 		if (first) {
2372 			center.pos = xf.origin;
2373 			first = false;
2374 			if (local_gizmo_coords) {
2375 				gizmo_basis = xf.basis;
2376 				gizmo_basis.orthonormalize();
2377 			}
2378 		} else {
2379 			center.expand_to(xf.origin);
2380 			gizmo_basis = Matrix3();
2381 		}
2382 		//		count++;
2383 	}
2384 
2385 	Vector3 pcenter = center.pos + center.size * 0.5;
2386 	gizmo.visible = !first;
2387 	gizmo.transform.origin = pcenter;
2388 	gizmo.transform.basis = gizmo_basis;
2389 
2390 	for (int i = 0; i < 4; i++) {
2391 		viewports[i]->update_transform_gizmo_view();
2392 	}
2393 }
2394 
_get_editor_data(Object * p_what)2395 Object *SpatialEditor::_get_editor_data(Object *p_what) {
2396 
2397 	Spatial *sp = p_what->cast_to<Spatial>();
2398 	if (!sp)
2399 		return NULL;
2400 
2401 	SpatialEditorSelectedItem *si = memnew(SpatialEditorSelectedItem);
2402 
2403 	si->sp = sp;
2404 	si->sbox_instance = VisualServer::get_singleton()->instance_create2(selection_box->get_rid(), sp->get_world()->get_scenario());
2405 	VS::get_singleton()->instance_geometry_set_cast_shadows_setting(si->sbox_instance, VS::SHADOW_CASTING_SETTING_OFF);
2406 
2407 	if (get_tree()->is_editor_hint())
2408 		editor->call("edit_node", sp);
2409 
2410 	return si;
2411 }
2412 
_generate_selection_box()2413 void SpatialEditor::_generate_selection_box() {
2414 
2415 	AABB aabb(Vector3(), Vector3(1, 1, 1));
2416 	aabb.grow_by(aabb.get_longest_axis_size() / 20.0);
2417 
2418 	Ref<SurfaceTool> st = memnew(SurfaceTool);
2419 
2420 	st->begin(Mesh::PRIMITIVE_LINES);
2421 	for (int i = 0; i < 12; i++) {
2422 
2423 		Vector3 a, b;
2424 		aabb.get_edge(i, a, b);
2425 
2426 		/*Vector<Vector3> points;
2427 		Vector<Color> colors;
2428 		points.push_back(a);
2429 		points.push_back(b);*/
2430 
2431 		st->add_color(Color(1.0, 1.0, 0.8, 0.8));
2432 		st->add_vertex(a);
2433 		st->add_color(Color(1.0, 1.0, 0.8, 0.4));
2434 		st->add_vertex(a.linear_interpolate(b, 0.2));
2435 
2436 		st->add_color(Color(1.0, 1.0, 0.8, 0.4));
2437 		st->add_vertex(a.linear_interpolate(b, 0.8));
2438 		st->add_color(Color(1.0, 1.0, 0.8, 0.8));
2439 		st->add_vertex(b);
2440 	}
2441 
2442 	Ref<FixedMaterial> mat = memnew(FixedMaterial);
2443 	mat->set_flag(Material::FLAG_UNSHADED, true);
2444 	mat->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(1, 1, 1));
2445 	mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2446 	mat->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
2447 	st->set_material(mat);
2448 	selection_box = st->commit();
2449 }
2450 
get_state() const2451 Dictionary SpatialEditor::get_state() const {
2452 
2453 	Dictionary d;
2454 
2455 	d["snap_enabled"] = snap_enabled;
2456 	d["translate_snap"] = get_translate_snap();
2457 	d["rotate_snap"] = get_rotate_snap();
2458 	d["scale_snap"] = get_scale_snap();
2459 
2460 	int local_coords_index = transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_LOCAL_COORDS);
2461 	d["local_coords"] = transform_menu->get_popup()->is_item_checked(local_coords_index);
2462 
2463 	int vc = 0;
2464 	if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT)))
2465 		vc = 1;
2466 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS)))
2467 		vc = 2;
2468 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS)))
2469 		vc = 3;
2470 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS)))
2471 		vc = 4;
2472 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT)))
2473 		vc = 5;
2474 	else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT)))
2475 		vc = 6;
2476 
2477 	d["viewport_mode"] = vc;
2478 	Array vpdata;
2479 	for (int i = 0; i < 4; i++) {
2480 		vpdata.push_back(viewports[i]->get_state());
2481 	}
2482 
2483 	d["viewports"] = vpdata;
2484 
2485 	d["default_light"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_LIGHT));
2486 	d["ambient_light_color"] = settings_ambient_color->get_color();
2487 
2488 	d["default_srgb"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_SRGB));
2489 	d["show_grid"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID));
2490 	d["show_origin"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN));
2491 	d["fov"] = get_fov();
2492 	d["znear"] = get_znear();
2493 	d["zfar"] = get_zfar();
2494 	d["deflight_rot_x"] = settings_default_light_rot_x;
2495 	d["deflight_rot_y"] = settings_default_light_rot_y;
2496 
2497 	return d;
2498 }
set_state(const Dictionary & p_state)2499 void SpatialEditor::set_state(const Dictionary &p_state) {
2500 
2501 	Dictionary d = p_state;
2502 
2503 	if (d.has("snap_enabled")) {
2504 		snap_enabled = d["snap_enabled"];
2505 		int snap_enabled_idx = transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_USE_SNAP);
2506 		transform_menu->get_popup()->set_item_checked(snap_enabled_idx, snap_enabled);
2507 	}
2508 
2509 	if (d.has("translate_snap"))
2510 		snap_translate->set_text(d["translate_snap"]);
2511 
2512 	if (d.has("rotate_snap"))
2513 		snap_rotate->set_text(d["rotate_snap"]);
2514 
2515 	if (d.has("scale_snap"))
2516 		snap_scale->set_text(d["scale_snap"]);
2517 
2518 	if (d.has("local_coords")) {
2519 		int local_coords_idx = transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_LOCAL_COORDS);
2520 		transform_menu->get_popup()->set_item_checked(local_coords_idx, d["local_coords"]);
2521 		update_transform_gizmo();
2522 	}
2523 
2524 	if (d.has("viewport_mode")) {
2525 		int vc = d["viewport_mode"];
2526 
2527 		if (vc == 1)
2528 			_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
2529 		else if (vc == 2)
2530 			_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
2531 		else if (vc == 3)
2532 			_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
2533 		else if (vc == 4)
2534 			_menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
2535 		else if (vc == 5)
2536 			_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
2537 		else if (vc == 6)
2538 			_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
2539 	}
2540 
2541 	if (d.has("viewports")) {
2542 		Array vp = d["viewports"];
2543 		ERR_FAIL_COND(vp.size() > 4);
2544 
2545 		for (int i = 0; i < 4; i++) {
2546 			viewports[i]->set_state(vp[i]);
2547 		}
2548 	}
2549 
2550 	if (d.has("zfar"))
2551 		settings_zfar->set_val(float(d["zfar"]));
2552 	if (d.has("znear"))
2553 		settings_znear->set_val(float(d["znear"]));
2554 	if (d.has("fov"))
2555 		settings_fov->set_val(float(d["fov"]));
2556 
2557 	if (d.has("default_light")) {
2558 		bool use = d["default_light"];
2559 
2560 		bool existing = light_instance.is_valid();
2561 		if (use != existing) {
2562 			if (existing) {
2563 				VisualServer::get_singleton()->free(light_instance);
2564 				light_instance = RID();
2565 			} else {
2566 				light_instance = VisualServer::get_singleton()->instance_create2(light, get_tree()->get_root()->get_world()->get_scenario());
2567 				VisualServer::get_singleton()->instance_set_transform(light_instance, light_transform);
2568 			}
2569 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_LIGHT), light_instance.is_valid());
2570 		}
2571 	}
2572 	if (d.has("ambient_light_color")) {
2573 		settings_ambient_color->set_color(d["ambient_light_color"]);
2574 		viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR, d["ambient_light_color"]);
2575 	}
2576 
2577 	if (d.has("default_srgb")) {
2578 		bool use = d["default_srgb"];
2579 
2580 		viewport_environment->set_enable_fx(Environment::FX_SRGB, use);
2581 		view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_DEFAULT_SRGB), use);
2582 	}
2583 	if (d.has("show_grid")) {
2584 		bool use = d["show_grid"];
2585 
2586 		if (use != view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID))) {
2587 			_menu_item_pressed(MENU_VIEW_GRID);
2588 		}
2589 	}
2590 
2591 	if (d.has("show_origin")) {
2592 		bool use = d["show_origin"];
2593 
2594 		if (use != view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN))) {
2595 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), use);
2596 			VisualServer::get_singleton()->instance_geometry_set_flag(origin_instance, VS::INSTANCE_FLAG_VISIBLE, use);
2597 		}
2598 	}
2599 
2600 	if (d.has("deflight_rot_x"))
2601 		settings_default_light_rot_x = d["deflight_rot_x"];
2602 	if (d.has("deflight_rot_y"))
2603 		settings_default_light_rot_y = d["deflight_rot_y"];
2604 
2605 	_update_default_light_angle();
2606 }
2607 
edit(Spatial * p_spatial)2608 void SpatialEditor::edit(Spatial *p_spatial) {
2609 
2610 	if (p_spatial != selected) {
2611 		if (selected) {
2612 
2613 			Ref<SpatialEditorGizmo> seg = selected->get_gizmo();
2614 			if (seg.is_valid()) {
2615 				seg->set_selected(false);
2616 				selected->update_gizmo();
2617 			}
2618 		}
2619 
2620 		selected = p_spatial;
2621 		over_gizmo_handle = -1;
2622 
2623 		if (selected) {
2624 
2625 			Ref<SpatialEditorGizmo> seg = selected->get_gizmo();
2626 			if (seg.is_valid()) {
2627 				seg->set_selected(true);
2628 				selected->update_gizmo();
2629 			}
2630 		}
2631 	}
2632 
2633 	if (p_spatial) {
2634 		//_validate_selection();
2635 		//if (selected.has(p_spatial->get_instance_ID()) && selected.size()==1)
2636 		//	return;
2637 		//_select(p_spatial->get_instance_ID(),false,true);
2638 
2639 		// should become the selection
2640 	}
2641 }
2642 
_xform_dialog_action()2643 void SpatialEditor::_xform_dialog_action() {
2644 
2645 	Transform t;
2646 	//translation
2647 	Vector3 scale;
2648 	Vector3 rotate;
2649 	Vector3 translate;
2650 
2651 	for (int i = 0; i < 3; i++) {
2652 		translate[i] = xform_translate[i]->get_text().to_double();
2653 		rotate[i] = Math::deg2rad(xform_rotate[i]->get_text().to_double());
2654 		scale[i] = xform_scale[i]->get_text().to_double();
2655 	}
2656 
2657 	t.origin = translate;
2658 	for (int i = 0; i < 3; i++) {
2659 		if (!rotate[i])
2660 			continue;
2661 		Vector3 axis;
2662 		axis[i] = 1.0;
2663 		t.basis.rotate(axis, rotate[i]);
2664 	}
2665 
2666 	for (int i = 0; i < 3; i++) {
2667 		if (scale[i] == 1)
2668 			continue;
2669 		t.basis.set_axis(i, t.basis.get_axis(i) * scale[i]);
2670 	}
2671 
2672 	undo_redo->create_action(TTR("XForm Dialog"));
2673 
2674 	List<Node *> &selection = editor_selection->get_selected_node_list();
2675 
2676 	for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
2677 
2678 		Spatial *sp = E->get()->cast_to<Spatial>();
2679 		if (!sp)
2680 			continue;
2681 
2682 		SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
2683 		if (!se)
2684 			continue;
2685 
2686 		bool post = xform_type->get_selected() > 0;
2687 
2688 		Transform tr = sp->get_global_transform();
2689 		if (post)
2690 			tr = tr * t;
2691 		else {
2692 
2693 			tr.basis = t.basis * tr.basis;
2694 			tr.origin += t.origin;
2695 		}
2696 
2697 		undo_redo->add_do_method(sp, "set_global_transform", tr);
2698 		undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform());
2699 	}
2700 	undo_redo->commit_action();
2701 }
2702 
_menu_item_pressed(int p_option)2703 void SpatialEditor::_menu_item_pressed(int p_option) {
2704 
2705 	switch (p_option) {
2706 
2707 		case MENU_TOOL_SELECT:
2708 		case MENU_TOOL_MOVE:
2709 		case MENU_TOOL_ROTATE:
2710 		case MENU_TOOL_SCALE:
2711 		case MENU_TOOL_LIST_SELECT: {
2712 
2713 			for (int i = 0; i < TOOL_MAX; i++)
2714 				tool_button[i]->set_pressed(i == p_option);
2715 			tool_mode = (ToolMode)p_option;
2716 
2717 			//		static const char *_mode[]={"Selection Mode.","Translation Mode.","Rotation Mode.","Scale Mode.","List Selection Mode."};
2718 			//			set_message(_mode[p_option],3);
2719 			update_transform_gizmo();
2720 
2721 		} break;
2722 		case MENU_TRANSFORM_USE_SNAP: {
2723 
2724 			bool is_checked = transform_menu->get_popup()->is_item_checked(transform_menu->get_popup()->get_item_index(p_option));
2725 			snap_enabled = !is_checked;
2726 			transform_menu->get_popup()->set_item_checked(transform_menu->get_popup()->get_item_index(p_option), snap_enabled);
2727 		} break;
2728 		case MENU_TRANSFORM_CONFIGURE_SNAP: {
2729 
2730 			snap_dialog->popup_centered(Size2(200, 180));
2731 		} break;
2732 		case MENU_TRANSFORM_LOCAL_COORDS: {
2733 
2734 			bool is_checked = transform_menu->get_popup()->is_item_checked(transform_menu->get_popup()->get_item_index(p_option));
2735 			transform_menu->get_popup()->set_item_checked(transform_menu->get_popup()->get_item_index(p_option), !is_checked);
2736 			update_transform_gizmo();
2737 
2738 		} break;
2739 		case MENU_TRANSFORM_DIALOG: {
2740 
2741 			for (int i = 0; i < 3; i++) {
2742 
2743 				xform_translate[i]->set_text("0");
2744 				xform_rotate[i]->set_text("0");
2745 				xform_scale[i]->set_text("1");
2746 			}
2747 
2748 			xform_dialog->popup_centered(Size2(200, 200));
2749 
2750 		} break;
2751 		case MENU_VIEW_USE_DEFAULT_LIGHT: {
2752 
2753 			bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
2754 
2755 			if (is_checked) {
2756 				VisualServer::get_singleton()->free(light_instance);
2757 				light_instance = RID();
2758 			} else {
2759 				light_instance = VisualServer::get_singleton()->instance_create2(light, get_tree()->get_root()->get_world()->get_scenario());
2760 				VisualServer::get_singleton()->instance_set_transform(light_instance, light_transform);
2761 
2762 				_update_default_light_angle();
2763 			}
2764 
2765 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), light_instance.is_valid());
2766 
2767 		} break;
2768 		case MENU_VIEW_USE_DEFAULT_SRGB: {
2769 
2770 			bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
2771 
2772 			if (is_checked) {
2773 				viewport_environment->set_enable_fx(Environment::FX_SRGB, false);
2774 			} else {
2775 				viewport_environment->set_enable_fx(Environment::FX_SRGB, true);
2776 			}
2777 
2778 			is_checked = !is_checked;
2779 
2780 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), is_checked);
2781 
2782 		} break;
2783 		case MENU_VIEW_USE_1_VIEWPORT: {
2784 
2785 			for (int i = 1; i < 4; i++) {
2786 
2787 				viewports[i]->hide();
2788 			}
2789 
2790 			viewports[0]->set_area_as_parent_rect();
2791 
2792 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), true);
2793 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
2794 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
2795 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
2796 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
2797 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
2798 
2799 		} break;
2800 		case MENU_VIEW_USE_2_VIEWPORTS: {
2801 
2802 			for (int i = 1; i < 4; i++) {
2803 
2804 				if (i == 1 || i == 3)
2805 					viewports[i]->hide();
2806 				else
2807 					viewports[i]->show();
2808 			}
2809 			viewports[0]->set_area_as_parent_rect();
2810 			viewports[0]->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_RATIO, 0.5);
2811 			viewports[2]->set_area_as_parent_rect();
2812 			viewports[2]->set_anchor_and_margin(MARGIN_TOP, ANCHOR_RATIO, 0.5);
2813 
2814 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
2815 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), true);
2816 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
2817 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
2818 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
2819 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
2820 
2821 		} break;
2822 		case MENU_VIEW_USE_2_VIEWPORTS_ALT: {
2823 
2824 			for (int i = 1; i < 4; i++) {
2825 
2826 				if (i == 1 || i == 3)
2827 					viewports[i]->hide();
2828 				else
2829 					viewports[i]->show();
2830 			}
2831 			viewports[0]->set_area_as_parent_rect();
2832 			viewports[0]->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_RATIO, 0.5);
2833 			viewports[2]->set_area_as_parent_rect();
2834 			viewports[2]->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_RATIO, 0.5);
2835 
2836 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
2837 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
2838 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
2839 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
2840 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), true);
2841 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
2842 
2843 		} break;
2844 		case MENU_VIEW_USE_3_VIEWPORTS: {
2845 
2846 			for (int i = 1; i < 4; i++) {
2847 
2848 				if (i == 1)
2849 					viewports[i]->hide();
2850 				else
2851 					viewports[i]->show();
2852 			}
2853 			viewports[0]->set_area_as_parent_rect();
2854 			viewports[0]->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_RATIO, 0.5);
2855 			viewports[2]->set_area_as_parent_rect();
2856 			viewports[2]->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_RATIO, 0.5);
2857 			viewports[2]->set_anchor_and_margin(MARGIN_TOP, ANCHOR_RATIO, 0.5);
2858 			viewports[3]->set_area_as_parent_rect();
2859 			viewports[3]->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_RATIO, 0.5);
2860 			viewports[3]->set_anchor_and_margin(MARGIN_TOP, ANCHOR_RATIO, 0.5);
2861 
2862 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
2863 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
2864 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), true);
2865 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
2866 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
2867 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
2868 
2869 		} break;
2870 		case MENU_VIEW_USE_3_VIEWPORTS_ALT: {
2871 
2872 			for (int i = 1; i < 4; i++) {
2873 
2874 				if (i == 1)
2875 					viewports[i]->hide();
2876 				else
2877 					viewports[i]->show();
2878 			}
2879 			viewports[0]->set_area_as_parent_rect();
2880 			viewports[0]->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_RATIO, 0.5);
2881 			viewports[0]->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_RATIO, 0.5);
2882 			viewports[2]->set_area_as_parent_rect();
2883 			viewports[2]->set_anchor_and_margin(MARGIN_TOP, ANCHOR_RATIO, 0.5);
2884 			viewports[2]->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_RATIO, 0.5);
2885 			viewports[3]->set_area_as_parent_rect();
2886 			viewports[3]->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_RATIO, 0.5);
2887 
2888 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
2889 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
2890 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
2891 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), false);
2892 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
2893 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), true);
2894 
2895 		} break;
2896 		case MENU_VIEW_USE_4_VIEWPORTS: {
2897 
2898 			for (int i = 1; i < 4; i++) {
2899 
2900 				viewports[i]->show();
2901 			}
2902 			viewports[0]->set_area_as_parent_rect();
2903 			viewports[0]->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_RATIO, 0.5);
2904 			viewports[0]->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_RATIO, 0.5);
2905 			viewports[1]->set_area_as_parent_rect();
2906 			viewports[1]->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_RATIO, 0.5);
2907 			viewports[1]->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_RATIO, 0.5);
2908 			viewports[2]->set_area_as_parent_rect();
2909 			viewports[2]->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_RATIO, 0.5);
2910 			viewports[2]->set_anchor_and_margin(MARGIN_TOP, ANCHOR_RATIO, 0.5);
2911 			viewports[3]->set_area_as_parent_rect();
2912 			viewports[3]->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_RATIO, 0.5);
2913 			viewports[3]->set_anchor_and_margin(MARGIN_TOP, ANCHOR_RATIO, 0.5);
2914 
2915 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), false);
2916 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), false);
2917 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), false);
2918 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), true);
2919 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), false);
2920 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), false);
2921 
2922 		} break;
2923 		case MENU_VIEW_DISPLAY_NORMAL: {
2924 
2925 			VisualServer::get_singleton()->scenario_set_debug(get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_DISABLED);
2926 
2927 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), true);
2928 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), false);
2929 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), false);
2930 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), false);
2931 
2932 		} break;
2933 		case MENU_VIEW_DISPLAY_WIREFRAME: {
2934 
2935 			VisualServer::get_singleton()->scenario_set_debug(get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_WIREFRAME);
2936 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), false);
2937 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), true);
2938 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), false);
2939 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), false);
2940 
2941 		} break;
2942 		case MENU_VIEW_DISPLAY_OVERDRAW: {
2943 
2944 			VisualServer::get_singleton()->scenario_set_debug(get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_OVERDRAW);
2945 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), false);
2946 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), false);
2947 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), true);
2948 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), false);
2949 
2950 		} break;
2951 		case MENU_VIEW_DISPLAY_SHADELESS: {
2952 
2953 			VisualServer::get_singleton()->scenario_set_debug(get_tree()->get_root()->get_world()->get_scenario(), VisualServer::SCENARIO_DEBUG_SHADELESS);
2954 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_NORMAL), false);
2955 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME), false);
2956 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_OVERDRAW), false);
2957 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_SHADELESS), true);
2958 
2959 		} break;
2960 		case MENU_VIEW_ORIGIN: {
2961 
2962 			bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
2963 
2964 			is_checked = !is_checked;
2965 			VisualServer::get_singleton()->instance_geometry_set_flag(origin_instance, VS::INSTANCE_FLAG_VISIBLE, is_checked);
2966 
2967 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), is_checked);
2968 		} break;
2969 		case MENU_VIEW_GRID: {
2970 
2971 			bool is_checked = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(p_option));
2972 
2973 			grid_enabled = !is_checked;
2974 
2975 			for (int i = 0; i < 3; ++i) {
2976 				if (grid_enable[i]) {
2977 					VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i], VS::INSTANCE_FLAG_VISIBLE, grid_enabled);
2978 					grid_visible[i] = grid_enabled;
2979 				}
2980 			}
2981 
2982 			view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(p_option), grid_enabled);
2983 
2984 		} break;
2985 		case MENU_VIEW_CAMERA_SETTINGS: {
2986 
2987 			settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50));
2988 		} break;
2989 	}
2990 }
2991 
_init_indicators()2992 void SpatialEditor::_init_indicators() {
2993 
2994 	//make sure that the camera indicator is not selectable
2995 	light = VisualServer::get_singleton()->light_create(VisualServer::LIGHT_DIRECTIONAL);
2996 	//VisualServer::get_singleton()->light_set_shadow( light, true );
2997 	light_instance = VisualServer::get_singleton()->instance_create2(light, get_tree()->get_root()->get_world()->get_scenario());
2998 
2999 	light_transform.rotate(Vector3(1, 0, 0), Math_PI / 5.0);
3000 	VisualServer::get_singleton()->instance_set_transform(light_instance, light_transform);
3001 
3002 	//RID mat = VisualServer::get_singleton()->fixed_material_create();
3003 	///VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA,true);
3004 	//VisualServer::get_singleton()->fixed_material_set_flag(mat, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true);
3005 
3006 	{
3007 
3008 		indicator_mat = VisualServer::get_singleton()->fixed_material_create();
3009 		VisualServer::get_singleton()->material_set_flag(indicator_mat, VisualServer::MATERIAL_FLAG_UNSHADED, true);
3010 		VisualServer::get_singleton()->material_set_flag(indicator_mat, VisualServer::MATERIAL_FLAG_ONTOP, false);
3011 		VisualServer::get_singleton()->fixed_material_set_flag(indicator_mat, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA, true);
3012 		VisualServer::get_singleton()->fixed_material_set_flag(indicator_mat, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY, true);
3013 
3014 		DVector<Color> grid_colors[3];
3015 		DVector<Vector3> grid_points[3];
3016 		Vector<Color> origin_colors;
3017 		Vector<Vector3> origin_points;
3018 
3019 		Color grid_color = EditorSettings::get_singleton()->get("3d_editor/grid_color");
3020 
3021 		for (int i = 0; i < 3; i++) {
3022 			Vector3 axis;
3023 			axis[i] = 1;
3024 			Vector3 axis_n1;
3025 			axis_n1[(i + 1) % 3] = 1;
3026 			Vector3 axis_n2;
3027 			axis_n2[(i + 2) % 3] = 1;
3028 
3029 			origin_colors.push_back(Color(axis.x, axis.y, axis.z));
3030 			origin_colors.push_back(Color(axis.x, axis.y, axis.z));
3031 			origin_points.push_back(axis * 4096);
3032 			origin_points.push_back(axis * -4096);
3033 #define ORIGIN_GRID_SIZE 25
3034 
3035 			for (int j = -ORIGIN_GRID_SIZE; j <= ORIGIN_GRID_SIZE; j++) {
3036 
3037 				grid_colors[i].push_back(grid_color);
3038 				grid_colors[i].push_back(grid_color);
3039 				grid_colors[i].push_back(grid_color);
3040 				grid_colors[i].push_back(grid_color);
3041 				grid_points[i].push_back(axis_n1 * ORIGIN_GRID_SIZE + axis_n2 * j);
3042 				grid_points[i].push_back(-axis_n1 * ORIGIN_GRID_SIZE + axis_n2 * j);
3043 				grid_points[i].push_back(axis_n2 * ORIGIN_GRID_SIZE + axis_n1 * j);
3044 				grid_points[i].push_back(-axis_n2 * ORIGIN_GRID_SIZE + axis_n1 * j);
3045 			}
3046 
3047 			grid[i] = VisualServer::get_singleton()->mesh_create();
3048 			Array d;
3049 			d.resize(VS::ARRAY_MAX);
3050 			d[VisualServer::ARRAY_VERTEX] = grid_points[i];
3051 			d[VisualServer::ARRAY_COLOR] = grid_colors[i];
3052 			VisualServer::get_singleton()->mesh_add_surface(grid[i], VisualServer::PRIMITIVE_LINES, d);
3053 			VisualServer::get_singleton()->mesh_surface_set_material(grid[i], 0, indicator_mat);
3054 			grid_instance[i] = VisualServer::get_singleton()->instance_create2(grid[i], get_tree()->get_root()->get_world()->get_scenario());
3055 
3056 			grid_visible[i] = false;
3057 			grid_enable[i] = false;
3058 			VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i], VS::INSTANCE_FLAG_VISIBLE, false);
3059 			VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(grid_instance[i], VS::SHADOW_CASTING_SETTING_OFF);
3060 			VS::get_singleton()->instance_set_layer_mask(grid_instance[i], 1 << SpatialEditorViewport::GIZMO_GRID_LAYER);
3061 		}
3062 
3063 		origin = VisualServer::get_singleton()->mesh_create();
3064 		Array d;
3065 		d.resize(VS::ARRAY_MAX);
3066 		d[VisualServer::ARRAY_VERTEX] = origin_points;
3067 		d[VisualServer::ARRAY_COLOR] = origin_colors;
3068 
3069 		VisualServer::get_singleton()->mesh_add_surface(origin, VisualServer::PRIMITIVE_LINES, d);
3070 		VisualServer::get_singleton()->mesh_surface_set_material(origin, 0, indicator_mat);
3071 
3072 		//		origin = VisualServer::get_singleton()->poly_create();
3073 		//		VisualServer::get_singleton()->poly_add_primitive(origin,origin_points,Vector<Vector3>(),origin_colors,Vector<Vector3>());
3074 		//		VisualServer::get_singleton()->poly_set_material(origin,indicator_mat,true);
3075 		origin_instance = VisualServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world()->get_scenario());
3076 		VS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << SpatialEditorViewport::GIZMO_GRID_LAYER);
3077 
3078 		VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, VS::SHADOW_CASTING_SETTING_OFF);
3079 
3080 		VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[1], VS::INSTANCE_FLAG_VISIBLE, true);
3081 		grid_enable[1] = true;
3082 		grid_visible[1] = true;
3083 		grid_enabled = true;
3084 		last_grid_snap = 1;
3085 	}
3086 
3087 	{
3088 		cursor_mesh = VisualServer::get_singleton()->mesh_create();
3089 		DVector<Vector3> cursor_points;
3090 		float cs = 0.25;
3091 		cursor_points.push_back(Vector3(+cs, 0, 0));
3092 		cursor_points.push_back(Vector3(-cs, 0, 0));
3093 		cursor_points.push_back(Vector3(0, +cs, 0));
3094 		cursor_points.push_back(Vector3(0, -cs, 0));
3095 		cursor_points.push_back(Vector3(0, 0, +cs));
3096 		cursor_points.push_back(Vector3(0, 0, -cs));
3097 		cursor_material = VisualServer::get_singleton()->fixed_material_create();
3098 		VisualServer::get_singleton()->fixed_material_set_param(cursor_material, VS::FIXED_MATERIAL_PARAM_DIFFUSE, Color(0, 1, 1));
3099 		VisualServer::get_singleton()->material_set_flag(cursor_material, VisualServer::MATERIAL_FLAG_UNSHADED, true);
3100 		VisualServer::get_singleton()->fixed_material_set_flag(cursor_material, VisualServer::FIXED_MATERIAL_FLAG_USE_ALPHA, true);
3101 		VisualServer::get_singleton()->fixed_material_set_flag(cursor_material, VisualServer::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY, true);
3102 
3103 		Array d;
3104 		d.resize(VS::ARRAY_MAX);
3105 		d[VS::ARRAY_VERTEX] = cursor_points;
3106 		VisualServer::get_singleton()->mesh_add_surface(cursor_mesh, VS::PRIMITIVE_LINES, d);
3107 		VisualServer::get_singleton()->mesh_surface_set_material(cursor_mesh, 0, cursor_material);
3108 
3109 		cursor_instance = VisualServer::get_singleton()->instance_create2(cursor_mesh, get_tree()->get_root()->get_world()->get_scenario());
3110 		VS::get_singleton()->instance_set_layer_mask(cursor_instance, 1 << SpatialEditorViewport::GIZMO_GRID_LAYER);
3111 
3112 		VisualServer::get_singleton()->instance_geometry_set_cast_shadows_setting(cursor_instance, VS::SHADOW_CASTING_SETTING_OFF);
3113 	}
3114 
3115 	{
3116 
3117 		//move gizmo
3118 
3119 		float gizmo_alph = EditorSettings::get_singleton()->get("3d_editor/manipulator_gizmo_opacity");
3120 
3121 		gizmo_hl = Ref<FixedMaterial>(memnew(FixedMaterial));
3122 		gizmo_hl->set_flag(Material::FLAG_UNSHADED, true);
3123 		gizmo_hl->set_flag(Material::FLAG_ONTOP, true);
3124 		gizmo_hl->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
3125 		gizmo_hl->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(1, 1, 1, gizmo_alph + 0.2f));
3126 
3127 		for (int i = 0; i < 3; i++) {
3128 
3129 			move_gizmo[i] = Ref<Mesh>(memnew(Mesh));
3130 			rotate_gizmo[i] = Ref<Mesh>(memnew(Mesh));
3131 
3132 			Ref<FixedMaterial> mat = memnew(FixedMaterial);
3133 			mat->set_flag(Material::FLAG_UNSHADED, true);
3134 			mat->set_flag(Material::FLAG_ONTOP, true);
3135 			mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
3136 			Color col;
3137 			col[i] = 1.0;
3138 			col.a = gizmo_alph;
3139 			mat->set_parameter(FixedMaterial::PARAM_DIFFUSE, col);
3140 			gizmo_color[i] = mat;
3141 
3142 			Vector3 ivec;
3143 			ivec[i] = 1;
3144 			Vector3 nivec;
3145 			nivec[(i + 1) % 3] = 1;
3146 			nivec[(i + 2) % 3] = 1;
3147 			Vector3 ivec2;
3148 			ivec2[(i + 1) % 3] = 1;
3149 			Vector3 ivec3;
3150 			ivec3[(i + 2) % 3] = 1;
3151 
3152 			{
3153 
3154 				Ref<SurfaceTool> surftool = memnew(SurfaceTool);
3155 				surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
3156 
3157 				//translate
3158 
3159 				const int arrow_points = 5;
3160 				Vector3 arrow[5] = {
3161 					nivec * 0.0 + ivec * 0.0,
3162 					nivec * 0.01 + ivec * 0.0,
3163 					nivec * 0.01 + ivec * 1.0,
3164 					nivec * 0.1 + ivec * 1.0,
3165 					nivec * 0.0 + ivec * (1 + GIZMO_ARROW_SIZE),
3166 				};
3167 
3168 				int arrow_sides = 6;
3169 
3170 				for (int k = 0; k < 7; k++) {
3171 
3172 					Matrix3 ma(ivec, Math_PI * 2 * float(k) / arrow_sides);
3173 					Matrix3 mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides);
3174 
3175 					for (int j = 0; j < arrow_points - 1; j++) {
3176 
3177 						Vector3 points[4] = {
3178 							ma.xform(arrow[j]),
3179 							mb.xform(arrow[j]),
3180 							mb.xform(arrow[j + 1]),
3181 							ma.xform(arrow[j + 1]),
3182 						};
3183 						surftool->add_vertex(points[0]);
3184 						surftool->add_vertex(points[1]);
3185 						surftool->add_vertex(points[2]);
3186 
3187 						surftool->add_vertex(points[0]);
3188 						surftool->add_vertex(points[2]);
3189 						surftool->add_vertex(points[3]);
3190 					}
3191 				}
3192 
3193 				surftool->set_material(mat);
3194 				surftool->commit(move_gizmo[i]);
3195 			}
3196 
3197 			{
3198 
3199 				Ref<SurfaceTool> surftool = memnew(SurfaceTool);
3200 				surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
3201 
3202 				Vector3 circle[5] = {
3203 					ivec * 0.02 + ivec2 * 0.02 + ivec2 * 1.0,
3204 					ivec * -0.02 + ivec2 * 0.02 + ivec2 * 1.0,
3205 					ivec * -0.02 + ivec2 * -0.02 + ivec2 * 1.0,
3206 					ivec * 0.02 + ivec2 * -0.02 + ivec2 * 1.0,
3207 					ivec * 0.02 + ivec2 * 0.02 + ivec2 * 1.0,
3208 				};
3209 
3210 				for (int k = 0; k < 33; k++) {
3211 
3212 					Matrix3 ma(ivec, Math_PI * 2 * float(k) / 32);
3213 					Matrix3 mb(ivec, Math_PI * 2 * float(k + 1) / 32);
3214 
3215 					for (int j = 0; j < 4; j++) {
3216 
3217 						Vector3 points[4] = {
3218 							ma.xform(circle[j]),
3219 							mb.xform(circle[j]),
3220 							mb.xform(circle[j + 1]),
3221 							ma.xform(circle[j + 1]),
3222 						};
3223 						surftool->add_vertex(points[0]);
3224 						surftool->add_vertex(points[1]);
3225 						surftool->add_vertex(points[2]);
3226 
3227 						surftool->add_vertex(points[0]);
3228 						surftool->add_vertex(points[2]);
3229 						surftool->add_vertex(points[3]);
3230 					}
3231 				}
3232 
3233 				surftool->set_material(mat);
3234 				surftool->commit(rotate_gizmo[i]);
3235 			}
3236 		}
3237 	}
3238 
3239 	/*for(int i=0;i<4;i++) {
3240 
3241 		viewports[i]->init_gizmo_instance(i);
3242 	}*/
3243 
3244 	_generate_selection_box();
3245 
3246 	//get_scene()->get_root_node()->cast_to<EditorNode>()->get_scene_root()->add_child(camera);
3247 
3248 	//current_camera=camera;
3249 }
3250 
_finish_indicators()3251 void SpatialEditor::_finish_indicators() {
3252 
3253 	VisualServer::get_singleton()->free(origin_instance);
3254 	VisualServer::get_singleton()->free(origin);
3255 	for (int i = 0; i < 3; i++) {
3256 		VisualServer::get_singleton()->free(grid_instance[i]);
3257 		VisualServer::get_singleton()->free(grid[i]);
3258 	}
3259 	VisualServer::get_singleton()->free(light_instance);
3260 	VisualServer::get_singleton()->free(light);
3261 	//VisualServer::get_singleton()->free(poly);
3262 	//VisualServer::get_singleton()->free(indicators_instance);
3263 	//VisualServer::get_singleton()->free(indicators);
3264 
3265 	VisualServer::get_singleton()->free(cursor_instance);
3266 	VisualServer::get_singleton()->free(cursor_mesh);
3267 	VisualServer::get_singleton()->free(indicator_mat);
3268 	VisualServer::get_singleton()->free(cursor_material);
3269 }
3270 
_instance_scene()3271 void SpatialEditor::_instance_scene() {
3272 #if 0
3273 	EditorNode *en = get_scene()->get_root_node()->cast_to<EditorNode>();
3274 	ERR_FAIL_COND(!en);
3275 	String path = en->get_filesystem_dock()->get_selected_path();
3276 	if (path=="") {
3277 		set_message(TTR("No scene selected to instance!"));
3278 		return;
3279 	}
3280 
3281 	undo_redo->create_action(TTR("Instance at Cursor"));
3282 
3283 	Node* scene = en->request_instance_scene(path);
3284 
3285 	if (!scene) {
3286 		set_message(TTR("Could not instance scene!"));
3287 		undo_redo->commit_action(); //bleh
3288 		return;
3289 	}
3290 
3291 	Spatial *s = scene->cast_to<Spatial>();
3292 	if (s) {
3293 
3294 		undo_redo->add_do_method(s,"set_global_transform",Transform(Matrix3(),cursor.cursor_pos));
3295 	}
3296 
3297 	undo_redo->commit_action();
3298 #endif
3299 }
3300 
_unhandled_key_input(InputEvent p_event)3301 void SpatialEditor::_unhandled_key_input(InputEvent p_event) {
3302 
3303 	if (!is_visible() || get_viewport()->gui_has_modal_stack())
3304 		return;
3305 
3306 	{
3307 
3308 		EditorNode *en = editor;
3309 		EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
3310 
3311 		if (!over_plugin_list->empty() && over_plugin_list->forward_input_event(p_event)) {
3312 
3313 			return; //ate the over input event
3314 		}
3315 	}
3316 
3317 	switch (p_event.type) {
3318 
3319 		case InputEvent::KEY: {
3320 
3321 			const InputEventKey &k = p_event.key;
3322 
3323 			if (!k.pressed)
3324 				break;
3325 
3326 			switch (k.scancode) {
3327 
3328 				case KEY_Q: _menu_item_pressed(MENU_TOOL_SELECT); break;
3329 				case KEY_W: _menu_item_pressed(MENU_TOOL_MOVE); break;
3330 				case KEY_E: _menu_item_pressed(MENU_TOOL_ROTATE); break;
3331 				case KEY_R: _menu_item_pressed(MENU_TOOL_SCALE); break;
3332 
3333 				case KEY_Z: {
3334 					if (k.mod.shift || k.mod.control || k.mod.command)
3335 						break;
3336 
3337 					if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_DISPLAY_WIREFRAME))) {
3338 						_menu_item_pressed(MENU_VIEW_DISPLAY_NORMAL);
3339 					} else {
3340 						_menu_item_pressed(MENU_VIEW_DISPLAY_WIREFRAME);
3341 					}
3342 				} break;
3343 
3344 #if 0
3345 #endif
3346 			}
3347 
3348 		} break;
3349 	}
3350 }
_notification(int p_what)3351 void SpatialEditor::_notification(int p_what) {
3352 
3353 	if (p_what == NOTIFICATION_READY) {
3354 
3355 		tool_button[SpatialEditor::TOOL_MODE_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons"));
3356 		tool_button[SpatialEditor::TOOL_MODE_MOVE]->set_icon(get_icon("ToolMove", "EditorIcons"));
3357 		tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons"));
3358 		tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons"));
3359 		tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons"));
3360 		instance_button->set_icon(get_icon("SpatialAdd", "EditorIcons"));
3361 		instance_button->hide();
3362 
3363 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons"));
3364 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons"));
3365 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT), get_icon("Panels2Alt", "EditorIcons"));
3366 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_icon("Panels3", "EditorIcons"));
3367 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_icon("Panels3Alt", "EditorIcons"));
3368 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_icon("Panels4", "EditorIcons"));
3369 
3370 		_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
3371 
3372 		get_tree()->connect("node_removed", this, "_node_removed");
3373 		VS::get_singleton()->scenario_set_fallback_environment(get_viewport()->find_world()->get_scenario(), viewport_environment->get_rid());
3374 	}
3375 
3376 	if (p_what == NOTIFICATION_ENTER_TREE) {
3377 
3378 		gizmos = memnew(SpatialEditorGizmos);
3379 		_init_indicators();
3380 		_update_default_light_angle();
3381 	}
3382 
3383 	if (p_what == NOTIFICATION_EXIT_TREE) {
3384 
3385 		_finish_indicators();
3386 		memdelete(gizmos);
3387 	}
3388 }
3389 
add_control_to_menu_panel(Control * p_control)3390 void SpatialEditor::add_control_to_menu_panel(Control *p_control) {
3391 
3392 	hbc_menu->add_child(p_control);
3393 }
3394 
set_can_preview(Camera * p_preview)3395 void SpatialEditor::set_can_preview(Camera *p_preview) {
3396 
3397 	for (int i = 0; i < 4; i++) {
3398 		viewports[i]->set_can_preview(p_preview);
3399 	}
3400 }
3401 
get_shader_split()3402 VSplitContainer *SpatialEditor::get_shader_split() {
3403 
3404 	return shader_split;
3405 }
3406 
get_palette_split()3407 HSplitContainer *SpatialEditor::get_palette_split() {
3408 
3409 	return palette_split;
3410 }
3411 
_request_gizmo(Object * p_obj)3412 void SpatialEditor::_request_gizmo(Object *p_obj) {
3413 
3414 	Spatial *sp = p_obj->cast_to<Spatial>();
3415 	if (!sp)
3416 		return;
3417 	if (editor->get_edited_scene() && (sp == editor->get_edited_scene() || sp->get_owner() == editor->get_edited_scene() || editor->get_edited_scene()->is_editable_instance(sp->get_owner()))) {
3418 
3419 		Ref<SpatialEditorGizmo> seg;
3420 
3421 		for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_editor_plugin_count(); i++) {
3422 
3423 			seg = EditorNode::get_singleton()->get_editor_data().get_editor_plugin(i)->create_spatial_gizmo(sp);
3424 			if (seg.is_valid())
3425 				break;
3426 		}
3427 
3428 		if (!seg.is_valid()) {
3429 			seg = gizmos->get_gizmo(sp);
3430 		}
3431 
3432 		if (seg.is_valid()) {
3433 			sp->set_gizmo(seg);
3434 		}
3435 
3436 		if (seg.is_valid() && sp == selected) {
3437 			seg->set_selected(true);
3438 			selected->update_gizmo();
3439 		}
3440 	}
3441 }
3442 
_toggle_maximize_view(Object * p_viewport)3443 void SpatialEditor::_toggle_maximize_view(Object *p_viewport) {
3444 	if (!p_viewport) return;
3445 	SpatialEditorViewport *current_viewport = p_viewport->cast_to<SpatialEditorViewport>();
3446 	if (!current_viewport) return;
3447 
3448 	int index = -1;
3449 	bool maximized = false;
3450 	for (int i = 0; i < 4; i++) {
3451 		if (viewports[i] == current_viewport) {
3452 			index = i;
3453 			if (current_viewport->get_global_rect() == viewport_base->get_global_rect())
3454 				maximized = true;
3455 			break;
3456 		}
3457 	}
3458 	if (index == -1) return;
3459 
3460 	if (!maximized) {
3461 
3462 		for (int i = 0; i < 4; i++) {
3463 			if (i == index)
3464 				viewports[i]->set_area_as_parent_rect();
3465 			else
3466 				viewports[i]->hide();
3467 		}
3468 	} else {
3469 
3470 		for (int i = 0; i < 4; i++)
3471 			viewports[i]->show();
3472 
3473 		if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT)))
3474 			_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
3475 		else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS)))
3476 			_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
3477 		else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS_ALT)))
3478 			_menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
3479 		else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS)))
3480 			_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
3481 		else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT)))
3482 			_menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
3483 		else if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS)))
3484 			_menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
3485 	}
3486 }
3487 
_node_removed(Node * p_node)3488 void SpatialEditor::_node_removed(Node *p_node) {
3489 
3490 	if (p_node == selected)
3491 		selected = NULL;
3492 }
3493 
_bind_methods()3494 void SpatialEditor::_bind_methods() {
3495 
3496 	//	ObjectTypeDB::bind_method("_input_event",&SpatialEditor::_input_event);
3497 	ObjectTypeDB::bind_method("_unhandled_key_input", &SpatialEditor::_unhandled_key_input);
3498 	ObjectTypeDB::bind_method("_node_removed", &SpatialEditor::_node_removed);
3499 	ObjectTypeDB::bind_method("_menu_item_pressed", &SpatialEditor::_menu_item_pressed);
3500 	ObjectTypeDB::bind_method("_xform_dialog_action", &SpatialEditor::_xform_dialog_action);
3501 	ObjectTypeDB::bind_method("_instance_scene", &SpatialEditor::_instance_scene);
3502 	ObjectTypeDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data);
3503 	ObjectTypeDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo);
3504 	ObjectTypeDB::bind_method("_default_light_angle_input", &SpatialEditor::_default_light_angle_input);
3505 	ObjectTypeDB::bind_method("_update_ambient_light_color", &SpatialEditor::_update_ambient_light_color);
3506 	ObjectTypeDB::bind_method("_toggle_maximize_view", &SpatialEditor::_toggle_maximize_view);
3507 
3508 	ADD_SIGNAL(MethodInfo("transform_key_request"));
3509 }
3510 
clear()3511 void SpatialEditor::clear() {
3512 
3513 	settings_fov->set_val(EDITOR_DEF("3d_editor/default_fov", 55.0));
3514 	settings_znear->set_val(EDITOR_DEF("3d_editor/default_z_near", 0.1));
3515 	settings_zfar->set_val(EDITOR_DEF("3d_editor/default_z_far", 1500.0));
3516 
3517 	for (int i = 0; i < 4; i++) {
3518 		viewports[i]->reset();
3519 	}
3520 
3521 	_menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
3522 	_menu_item_pressed(MENU_VIEW_DISPLAY_NORMAL);
3523 
3524 	VisualServer::get_singleton()->instance_geometry_set_flag(origin_instance, VS::INSTANCE_FLAG_VISIBLE, true);
3525 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), true);
3526 	for (int i = 0; i < 3; ++i) {
3527 		if (grid_enable[i]) {
3528 			VisualServer::get_singleton()->instance_geometry_set_flag(grid_instance[i], VS::INSTANCE_FLAG_VISIBLE, true);
3529 			grid_visible[i] = true;
3530 		}
3531 	}
3532 
3533 	for (int i = 0; i < 4; i++) {
3534 
3535 		viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(SpatialEditorViewport::VIEW_AUDIO_LISTENER), i == 0);
3536 		viewports[i]->viewport->set_as_audio_listener(i == 0);
3537 	}
3538 
3539 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_GRID), true);
3540 
3541 	settings_default_light_rot_x = Math_PI * 0.3;
3542 	settings_default_light_rot_y = Math_PI * 0.2;
3543 
3544 	viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR, Color(0.15, 0.15, 0.15));
3545 	settings_ambient_color->set_color(Color(0.15, 0.15, 0.15));
3546 	if (!light_instance.is_valid())
3547 		_menu_item_pressed(MENU_VIEW_USE_DEFAULT_LIGHT);
3548 
3549 	_update_default_light_angle();
3550 }
3551 
_update_ambient_light_color(const Color & p_color)3552 void SpatialEditor::_update_ambient_light_color(const Color &p_color) {
3553 
3554 	viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR, settings_ambient_color->get_color());
3555 }
3556 
_update_default_light_angle()3557 void SpatialEditor::_update_default_light_angle() {
3558 
3559 	Transform t;
3560 	t.basis.rotate(Vector3(1, 0, 0), settings_default_light_rot_x);
3561 	t.basis.rotate(Vector3(0, 1, 0), settings_default_light_rot_y);
3562 	settings_dlight->set_transform(t);
3563 	if (light_instance.is_valid()) {
3564 		VS::get_singleton()->instance_set_transform(light_instance, t);
3565 	}
3566 }
3567 
_default_light_angle_input(const InputEvent & p_event)3568 void SpatialEditor::_default_light_angle_input(const InputEvent &p_event) {
3569 
3570 	if (p_event.type == InputEvent::MOUSE_MOTION && p_event.mouse_motion.button_mask & (0x1 | 0x2 | 0x4)) {
3571 
3572 		settings_default_light_rot_y = Math::fposmod(settings_default_light_rot_y - p_event.mouse_motion.relative_x * 0.01, Math_PI * 2.0);
3573 		settings_default_light_rot_x = Math::fposmod(settings_default_light_rot_x - p_event.mouse_motion.relative_y * 0.01, Math_PI * 2.0);
3574 		_update_default_light_angle();
3575 	}
3576 }
3577 
SpatialEditor(EditorNode * p_editor)3578 SpatialEditor::SpatialEditor(EditorNode *p_editor) {
3579 
3580 	gizmo.visible = true;
3581 	gizmo.scale = 1.0;
3582 
3583 	viewport_environment = Ref<Environment>(memnew(Environment));
3584 	undo_redo = p_editor->get_undo_redo();
3585 	VBoxContainer *vbc = this;
3586 
3587 	custom_camera = NULL;
3588 	singleton = this;
3589 	editor = p_editor;
3590 	editor_selection = editor->get_editor_selection();
3591 	editor_selection->add_editor_plugin(this);
3592 
3593 	snap_enabled = false;
3594 	tool_mode = TOOL_MODE_SELECT;
3595 
3596 	//set_focus_mode(FOCUS_ALL);
3597 
3598 	hbc_menu = memnew(HBoxContainer);
3599 	vbc->add_child(hbc_menu);
3600 
3601 	Vector<Variant> button_binds;
3602 	button_binds.resize(1);
3603 
3604 	tool_button[TOOL_MODE_SELECT] = memnew(ToolButton);
3605 	hbc_menu->add_child(tool_button[TOOL_MODE_SELECT]);
3606 	tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true);
3607 	tool_button[TOOL_MODE_SELECT]->set_flat(true);
3608 	tool_button[TOOL_MODE_SELECT]->set_pressed(true);
3609 	button_binds[0] = MENU_TOOL_SELECT;
3610 	tool_button[TOOL_MODE_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds);
3611 	tool_button[TOOL_MODE_SELECT]->set_tooltip("Select Mode (Q)\n" + keycode_get_string(KEY_MASK_CMD) + "Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection");
3612 
3613 	tool_button[TOOL_MODE_MOVE] = memnew(ToolButton);
3614 
3615 	hbc_menu->add_child(tool_button[TOOL_MODE_MOVE]);
3616 	tool_button[TOOL_MODE_MOVE]->set_toggle_mode(true);
3617 	tool_button[TOOL_MODE_MOVE]->set_flat(true);
3618 	button_binds[0] = MENU_TOOL_MOVE;
3619 	tool_button[TOOL_MODE_MOVE]->connect("pressed", this, "_menu_item_pressed", button_binds);
3620 	tool_button[TOOL_MODE_MOVE]->set_tooltip(TTR("Move Mode (W)"));
3621 
3622 	tool_button[TOOL_MODE_ROTATE] = memnew(ToolButton);
3623 	hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]);
3624 	tool_button[TOOL_MODE_ROTATE]->set_toggle_mode(true);
3625 	tool_button[TOOL_MODE_ROTATE]->set_flat(true);
3626 	button_binds[0] = MENU_TOOL_ROTATE;
3627 	tool_button[TOOL_MODE_ROTATE]->connect("pressed", this, "_menu_item_pressed", button_binds);
3628 	tool_button[TOOL_MODE_ROTATE]->set_tooltip(TTR("Rotate Mode (E)"));
3629 
3630 	tool_button[TOOL_MODE_SCALE] = memnew(ToolButton);
3631 	hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]);
3632 	tool_button[TOOL_MODE_SCALE]->set_toggle_mode(true);
3633 	tool_button[TOOL_MODE_SCALE]->set_flat(true);
3634 	button_binds[0] = MENU_TOOL_SCALE;
3635 	tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds);
3636 	tool_button[TOOL_MODE_SCALE]->set_tooltip(TTR("Scale Mode (R)"));
3637 
3638 	instance_button = memnew(Button);
3639 	hbc_menu->add_child(instance_button);
3640 	instance_button->set_flat(true);
3641 	instance_button->connect("pressed", this, "_instance_scene");
3642 	instance_button->hide();
3643 
3644 	VSeparator *vs = memnew(VSeparator);
3645 	hbc_menu->add_child(vs);
3646 
3647 	tool_button[TOOL_MODE_LIST_SELECT] = memnew(ToolButton);
3648 	hbc_menu->add_child(tool_button[TOOL_MODE_LIST_SELECT]);
3649 	tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true);
3650 	tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true);
3651 	button_binds[0] = MENU_TOOL_LIST_SELECT;
3652 	tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds);
3653 	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)."));
3654 
3655 	vs = memnew(VSeparator);
3656 	hbc_menu->add_child(vs);
3657 
3658 	ED_SHORTCUT("spatial_editor/bottom_view", TTR("Bottom View"), KEY_MASK_ALT + KEY_KP_7);
3659 	ED_SHORTCUT("spatial_editor/top_view", TTR("Top View"), KEY_KP_7);
3660 	ED_SHORTCUT("spatial_editor/rear_view", TTR("Rear View"), KEY_MASK_ALT + KEY_KP_1);
3661 	ED_SHORTCUT("spatial_editor/front_view", TTR("Front View"), KEY_KP_1);
3662 	ED_SHORTCUT("spatial_editor/left_view", TTR("Left View"), KEY_MASK_ALT + KEY_KP_3);
3663 	ED_SHORTCUT("spatial_editor/right_view", TTR("Right View"), KEY_KP_3);
3664 	ED_SHORTCUT("spatial_editor/switch_perspective_orthogonal", TTR("Switch Perspective/Orthogonal view"), KEY_KP_5);
3665 	ED_SHORTCUT("spatial_editor/snap", TTR("Snap"), KEY_S);
3666 	ED_SHORTCUT("spatial_editor/insert_anim_key", TTR("Insert Animation Key"), KEY_K);
3667 	ED_SHORTCUT("spatial_editor/focus_origin", TTR("Focus Origin"), KEY_O);
3668 	ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), KEY_F);
3669 	ED_SHORTCUT("spatial_editor/align_selection_with_view", TTR("Align Selection With View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_F);
3670 
3671 	PopupMenu *p;
3672 
3673 	transform_menu = memnew(MenuButton);
3674 	transform_menu->set_text(TTR("Transform"));
3675 	hbc_menu->add_child(transform_menu);
3676 
3677 	p = transform_menu->get_popup();
3678 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/use_snap", TTR("Use Snap")), MENU_TRANSFORM_USE_SNAP);
3679 	p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap..")), MENU_TRANSFORM_CONFIGURE_SNAP);
3680 	p->add_separator();
3681 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Local Coords")), MENU_TRANSFORM_LOCAL_COORDS);
3682 	//p->set_item_checked(p->get_item_count()-1,true);
3683 	p->add_separator();
3684 	p->add_shortcut(ED_SHORTCUT("spatial_editor/transform_dialog", TTR("Transform Dialog..")), MENU_TRANSFORM_DIALOG);
3685 
3686 	p->connect("item_pressed", this, "_menu_item_pressed");
3687 
3688 	view_menu = memnew(MenuButton);
3689 	view_menu->set_text(TTR("View"));
3690 	view_menu->set_pos(Point2(212, 0));
3691 	hbc_menu->add_child(view_menu);
3692 
3693 	p = view_menu->get_popup();
3694 
3695 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/use_default_light", TTR("Use Default Light")), MENU_VIEW_USE_DEFAULT_LIGHT);
3696 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/use_default_srgb", TTR("Use Default sRGB")), MENU_VIEW_USE_DEFAULT_SRGB);
3697 	p->add_separator();
3698 
3699 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/1_viewport", TTR("1 Viewport"), KEY_MASK_CMD + KEY_1), MENU_VIEW_USE_1_VIEWPORT);
3700 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/2_viewports", TTR("2 Viewports"), KEY_MASK_CMD + KEY_2), MENU_VIEW_USE_2_VIEWPORTS);
3701 	p->add_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);
3702 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/3_viewports", TTR("3 Viewports"), KEY_MASK_CMD + KEY_3), MENU_VIEW_USE_3_VIEWPORTS);
3703 	p->add_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);
3704 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KEY_MASK_CMD + KEY_4), MENU_VIEW_USE_4_VIEWPORTS);
3705 	p->add_separator();
3706 
3707 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/display_normal", TTR("Display Normal")), MENU_VIEW_DISPLAY_NORMAL);
3708 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/display_wireframe", TTR("Display Wireframe")), MENU_VIEW_DISPLAY_WIREFRAME);
3709 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/display_overdraw", TTR("Display Overdraw")), MENU_VIEW_DISPLAY_OVERDRAW);
3710 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/display_shadeless", TTR("Display Shadeless")), MENU_VIEW_DISPLAY_SHADELESS);
3711 	p->add_separator();
3712 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN);
3713 	p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid")), MENU_VIEW_GRID);
3714 	p->add_separator();
3715 	p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings")), MENU_VIEW_CAMERA_SETTINGS);
3716 
3717 	p->set_item_checked(p->get_item_index(MENU_VIEW_USE_DEFAULT_LIGHT), true);
3718 	p->set_item_checked(p->get_item_index(MENU_VIEW_DISPLAY_NORMAL), true);
3719 	p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true);
3720 	p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true);
3721 
3722 	p->connect("item_pressed", this, "_menu_item_pressed");
3723 
3724 	/* REST OF MENU */
3725 
3726 	palette_split = memnew(HSplitContainer);
3727 	palette_split->set_v_size_flags(SIZE_EXPAND_FILL);
3728 	vbc->add_child(palette_split);
3729 
3730 	shader_split = memnew(VSplitContainer);
3731 	shader_split->set_h_size_flags(SIZE_EXPAND_FILL);
3732 	palette_split->add_child(shader_split);
3733 	viewport_base = memnew(Control);
3734 	shader_split->add_child(viewport_base);
3735 	viewport_base->set_v_size_flags(SIZE_EXPAND_FILL);
3736 	for (int i = 0; i < 4; i++) {
3737 
3738 		viewports[i] = memnew(SpatialEditorViewport(this, editor, i));
3739 		viewports[i]->connect("toggle_maximize_view", this, "_toggle_maximize_view");
3740 		viewport_base->add_child(viewports[i]);
3741 	}
3742 	//vbc->add_child(viewport_base);
3743 
3744 	/* SNAP DIALOG */
3745 
3746 	snap_dialog = memnew(ConfirmationDialog);
3747 	snap_dialog->set_title(TTR("Snap Settings"));
3748 	add_child(snap_dialog);
3749 
3750 	VBoxContainer *snap_dialog_vbc = memnew(VBoxContainer);
3751 	snap_dialog->add_child(snap_dialog_vbc);
3752 	snap_dialog->set_child_rect(snap_dialog_vbc);
3753 
3754 	snap_translate = memnew(LineEdit);
3755 	snap_translate->set_text("1");
3756 	snap_dialog_vbc->add_margin_child(TTR("Translate Snap:"), snap_translate);
3757 
3758 	snap_rotate = memnew(LineEdit);
3759 	snap_rotate->set_text("5");
3760 	snap_dialog_vbc->add_margin_child(TTR("Rotate Snap (deg.):"), snap_rotate);
3761 
3762 	snap_scale = memnew(LineEdit);
3763 	snap_scale->set_text("5");
3764 	snap_dialog_vbc->add_margin_child(TTR("Scale Snap (%):"), snap_scale);
3765 
3766 	/* SETTINGS DIALOG */
3767 
3768 	settings_dialog = memnew(ConfirmationDialog);
3769 	settings_dialog->set_title(TTR("Viewport Settings"));
3770 	add_child(settings_dialog);
3771 	settings_vbc = memnew(VBoxContainer);
3772 	settings_vbc->set_custom_minimum_size(Size2(200, 0));
3773 	settings_dialog->add_child(settings_vbc);
3774 	settings_dialog->set_child_rect(settings_vbc);
3775 
3776 	settings_light_base = memnew(Control);
3777 	settings_light_base->set_custom_minimum_size(Size2(128, 128));
3778 	settings_light_base->connect("input_event", this, "_default_light_angle_input");
3779 	settings_vbc->add_margin_child(TTR("Default Light Normal:"), settings_light_base);
3780 	settings_light_vp = memnew(Viewport);
3781 	settings_light_vp->set_disable_input(true);
3782 	settings_light_vp->set_use_own_world(true);
3783 	settings_light_base->add_child(settings_light_vp);
3784 
3785 	settings_dlight = memnew(DirectionalLight);
3786 	settings_light_vp->add_child(settings_dlight);
3787 	settings_sphere = memnew(ImmediateGeometry);
3788 	settings_sphere->begin(Mesh::PRIMITIVE_TRIANGLES, Ref<Texture>());
3789 	settings_sphere->set_color(Color(1, 1, 1));
3790 	settings_sphere->add_sphere(32, 16, 1);
3791 	settings_sphere->end();
3792 	settings_light_vp->add_child(settings_sphere);
3793 	settings_camera = memnew(Camera);
3794 	settings_light_vp->add_child(settings_camera);
3795 	settings_camera->set_translation(Vector3(0, 0, 2));
3796 	settings_camera->set_orthogonal(2.1, 0.1, 5);
3797 
3798 	settings_default_light_rot_x = Math_PI * 0.3;
3799 	settings_default_light_rot_y = Math_PI * 0.2;
3800 
3801 	settings_ambient_color = memnew(ColorPickerButton);
3802 	settings_vbc->add_margin_child(TTR("Ambient Light Color:"), settings_ambient_color);
3803 	settings_ambient_color->connect("color_changed", this, "_update_ambient_light_color");
3804 
3805 	viewport_environment->set_enable_fx(Environment::FX_AMBIENT_LIGHT, true);
3806 	viewport_environment->fx_set_param(Environment::FX_PARAM_AMBIENT_LIGHT_COLOR, Color(0.15, 0.15, 0.15));
3807 	settings_ambient_color->set_color(Color(0.15, 0.15, 0.15));
3808 
3809 	settings_fov = memnew(SpinBox);
3810 	settings_fov->set_max(179);
3811 	settings_fov->set_min(1);
3812 	settings_fov->set_step(0.01);
3813 	settings_fov->set_val(EDITOR_DEF("3d_editor/default_fov", 55.0));
3814 	settings_vbc->add_margin_child(TTR("Perspective FOV (deg.):"), settings_fov);
3815 
3816 	settings_znear = memnew(SpinBox);
3817 	settings_znear->set_max(10000);
3818 	settings_znear->set_min(0.1);
3819 	settings_znear->set_step(0.01);
3820 	settings_znear->set_val(EDITOR_DEF("3d_editor/default_z_near", 0.1));
3821 	settings_vbc->add_margin_child(TTR("View Z-Near:"), settings_znear);
3822 
3823 	settings_zfar = memnew(SpinBox);
3824 	settings_zfar->set_max(10000);
3825 	settings_zfar->set_min(0.1);
3826 	settings_zfar->set_step(0.01);
3827 	settings_zfar->set_val(EDITOR_DEF("3d_editor/default_z_far", 1500));
3828 	settings_vbc->add_margin_child(TTR("View Z-Far:"), settings_zfar);
3829 
3830 	//settings_dialog->get_cancel()->hide();
3831 	/* XFORM DIALOG */
3832 
3833 	xform_dialog = memnew(ConfirmationDialog);
3834 	xform_dialog->set_title(TTR("Transform Change"));
3835 	add_child(xform_dialog);
3836 	Label *l = memnew(Label);
3837 	l->set_text(TTR("Translate:"));
3838 	l->set_pos(Point2(5, 5));
3839 	xform_dialog->add_child(l);
3840 
3841 	for (int i = 0; i < 3; i++) {
3842 
3843 		xform_translate[i] = memnew(LineEdit);
3844 		xform_translate[i]->set_pos(Point2(15 + i * 60, 22));
3845 		xform_translate[i]->set_size(Size2(50, 12));
3846 		xform_dialog->add_child(xform_translate[i]);
3847 	}
3848 
3849 	l = memnew(Label);
3850 	l->set_text(TTR("Rotate (deg.):"));
3851 	l->set_pos(Point2(5, 45));
3852 	xform_dialog->add_child(l);
3853 
3854 	for (int i = 0; i < 3; i++) {
3855 		xform_rotate[i] = memnew(LineEdit);
3856 		xform_rotate[i]->set_pos(Point2(15 + i * 60, 62));
3857 		xform_rotate[i]->set_size(Size2(50, 22));
3858 		xform_dialog->add_child(xform_rotate[i]);
3859 	}
3860 
3861 	l = memnew(Label);
3862 	l->set_text(TTR("Scale (ratio):"));
3863 	l->set_pos(Point2(5, 85));
3864 	xform_dialog->add_child(l);
3865 
3866 	for (int i = 0; i < 3; i++) {
3867 		xform_scale[i] = memnew(LineEdit);
3868 		xform_scale[i]->set_pos(Point2(15 + i * 60, 102));
3869 		xform_scale[i]->set_size(Size2(50, 22));
3870 		xform_dialog->add_child(xform_scale[i]);
3871 	}
3872 
3873 	l = memnew(Label);
3874 	l->set_text(TTR("Transform Type"));
3875 	l->set_pos(Point2(5, 125));
3876 	xform_dialog->add_child(l);
3877 
3878 	xform_type = memnew(OptionButton);
3879 	xform_type->set_anchor(MARGIN_RIGHT, ANCHOR_END);
3880 	xform_type->set_begin(Point2(15, 142));
3881 	xform_type->set_end(Point2(15, 75));
3882 	xform_type->add_item(TTR("Pre"));
3883 	xform_type->add_item(TTR("Post"));
3884 	xform_dialog->add_child(xform_type);
3885 
3886 	xform_dialog->connect("confirmed", this, "_xform_dialog_action");
3887 
3888 	scenario_debug = VisualServer::SCENARIO_DEBUG_DISABLED;
3889 
3890 	selected = NULL;
3891 
3892 	set_process_unhandled_key_input(true);
3893 	add_to_group("_spatial_editor_group");
3894 
3895 	EDITOR_DEF("3d_editor/manipulator_gizmo_size", 80);
3896 	EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "3d_editor/manipulator_gizmo_size", PROPERTY_HINT_RANGE, "16,1024,1"));
3897 	EDITOR_DEF("3d_editor/manipulator_gizmo_opacity", 0.2);
3898 
3899 	over_gizmo_handle = -1;
3900 }
3901 
~SpatialEditor()3902 SpatialEditor::~SpatialEditor() {
3903 }
3904 
make_visible(bool p_visible)3905 void SpatialEditorPlugin::make_visible(bool p_visible) {
3906 
3907 	if (p_visible) {
3908 
3909 		spatial_editor->show();
3910 		spatial_editor->set_process(true);
3911 		//VisualServer::get_singleton()->viewport_set_hide_scenario(editor->get_scene_root()->get_viewport(),false);
3912 		spatial_editor->grab_focus();
3913 
3914 	} else {
3915 
3916 		spatial_editor->hide();
3917 		spatial_editor->set_process(false);
3918 		//VisualServer::get_singleton()->viewport_set_hide_scenario(editor->get_scene_root()->get_viewport(),true);
3919 	}
3920 }
edit(Object * p_object)3921 void SpatialEditorPlugin::edit(Object *p_object) {
3922 
3923 	spatial_editor->edit(p_object->cast_to<Spatial>());
3924 }
3925 
handles(Object * p_object) const3926 bool SpatialEditorPlugin::handles(Object *p_object) const {
3927 
3928 	return p_object->is_type("Spatial");
3929 }
3930 
get_state() const3931 Dictionary SpatialEditorPlugin::get_state() const {
3932 	return spatial_editor->get_state();
3933 }
3934 
set_state(const Dictionary & p_state)3935 void SpatialEditorPlugin::set_state(const Dictionary &p_state) {
3936 
3937 	spatial_editor->set_state(p_state);
3938 }
3939 
snap_cursor_to_plane(const Plane & p_plane)3940 void SpatialEditor::snap_cursor_to_plane(const Plane &p_plane) {
3941 
3942 	//	cursor.pos=p_plane.project(cursor.pos);
3943 }
3944 
_bind_methods()3945 void SpatialEditorPlugin::_bind_methods() {
3946 
3947 	ObjectTypeDB::bind_method("snap_cursor_to_plane", &SpatialEditorPlugin::snap_cursor_to_plane);
3948 }
3949 
snap_cursor_to_plane(const Plane & p_plane)3950 void SpatialEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) {
3951 
3952 	spatial_editor->snap_cursor_to_plane(p_plane);
3953 }
3954 
SpatialEditorPlugin(EditorNode * p_node)3955 SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) {
3956 
3957 	editor = p_node;
3958 	spatial_editor = memnew(SpatialEditor(p_node));
3959 	spatial_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
3960 	editor->get_viewport()->add_child(spatial_editor);
3961 
3962 	//spatial_editor->set_area_as_parent_rect();
3963 	spatial_editor->hide();
3964 	spatial_editor->connect("transform_key_request", editor, "_transform_keyed");
3965 
3966 	//spatial_editor->set_process(true);
3967 }
3968 
~SpatialEditorPlugin()3969 SpatialEditorPlugin::~SpatialEditorPlugin() {
3970 }
3971