1 /*************************************************************************/
2 /*  spatial_editor_gizmos.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_gizmos.h"
31 #include "geometry.h"
32 #include "quick_hull.h"
33 #include "scene/3d/camera.h"
34 #include "scene/resources/box_shape.h"
35 #include "scene/resources/capsule_shape.h"
36 #include "scene/resources/convex_polygon_shape.h"
37 #include "scene/resources/plane_shape.h"
38 #include "scene/resources/ray_shape.h"
39 #include "scene/resources/sphere_shape.h"
40 #include "scene/resources/surface_tool.h"
41 
42 // Keep small children away from this file.
43 // It's so ugly it will eat them alive
44 
45 #define HANDLE_HALF_SIZE 0.05
46 
clear()47 void EditorSpatialGizmo::clear() {
48 
49 	for (int i = 0; i < instances.size(); i++) {
50 
51 		if (instances[i].instance.is_valid())
52 			VS::get_singleton()->free(instances[i].instance);
53 	}
54 
55 	billboard_handle = false;
56 	collision_segments.clear();
57 	collision_mesh = Ref<TriangleMesh>();
58 	instances.clear();
59 	handles.clear();
60 	secondary_handles.clear();
61 }
62 
redraw()63 void EditorSpatialGizmo::redraw() {
64 
65 	if (get_script_instance() && get_script_instance()->has_method("redraw"))
66 		get_script_instance()->call("redraw");
67 }
68 
create_instance(Spatial * p_base)69 void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base) {
70 
71 	instance = VS::get_singleton()->instance_create2(mesh->get_rid(), p_base->get_world()->get_scenario());
72 	VS::get_singleton()->instance_attach_object_instance_ID(instance, p_base->get_instance_ID());
73 	if (billboard)
74 		VS::get_singleton()->instance_geometry_set_flag(instance, VS::INSTANCE_FLAG_BILLBOARD, true);
75 	if (unscaled)
76 		VS::get_singleton()->instance_geometry_set_flag(instance, VS::INSTANCE_FLAG_DEPH_SCALE, true);
77 	if (skeleton.is_valid())
78 		VS::get_singleton()->instance_attach_skeleton(instance, skeleton);
79 	if (extra_margin)
80 		VS::get_singleton()->instance_set_extra_visibility_margin(instance, 1);
81 	VS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance, VS::SHADOW_CASTING_SETTING_OFF);
82 	VS::get_singleton()->instance_geometry_set_flag(instance, VS::INSTANCE_FLAG_RECEIVE_SHADOWS, false);
83 	VS::get_singleton()->instance_set_layer_mask(instance, 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER); //gizmos are 26
84 }
85 
add_mesh(const Ref<Mesh> & p_mesh,bool p_billboard,const RID & p_skeleton)86 void EditorSpatialGizmo::add_mesh(const Ref<Mesh> &p_mesh, bool p_billboard, const RID &p_skeleton) {
87 
88 	ERR_FAIL_COND(!spatial_node);
89 	Instance ins;
90 
91 	ins.billboard = p_billboard;
92 	ins.mesh = p_mesh;
93 	ins.skeleton = p_skeleton;
94 	if (valid) {
95 		ins.create_instance(spatial_node);
96 		VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
97 	}
98 
99 	instances.push_back(ins);
100 }
101 
add_lines(const Vector<Vector3> & p_lines,const Ref<Material> & p_material,bool p_billboard)102 void EditorSpatialGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard) {
103 
104 	ERR_FAIL_COND(!spatial_node);
105 	Instance ins;
106 
107 	Ref<Mesh> mesh = memnew(Mesh);
108 	Array a;
109 	a.resize(Mesh::ARRAY_MAX);
110 
111 	a[Mesh::ARRAY_VERTEX] = p_lines;
112 
113 	DVector<Color> color;
114 	color.resize(p_lines.size());
115 	{
116 		DVector<Color>::Write w = color.write();
117 		for (int i = 0; i < p_lines.size(); i++) {
118 			if (is_selected())
119 				w[i] = Color(1, 1, 1, 0.6);
120 			else
121 				w[i] = Color(1, 1, 1, 0.25);
122 		}
123 	}
124 
125 	a[Mesh::ARRAY_COLOR] = color;
126 
127 	mesh->add_surface(Mesh::PRIMITIVE_LINES, a);
128 	mesh->surface_set_material(0, p_material);
129 
130 	if (p_billboard) {
131 		float md = 0;
132 		for (int i = 0; i < p_lines.size(); i++) {
133 
134 			md = MAX(0, p_lines[i].length());
135 		}
136 		if (md) {
137 			mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
138 		}
139 	}
140 
141 	ins.billboard = p_billboard;
142 	ins.mesh = mesh;
143 	if (valid) {
144 		ins.create_instance(spatial_node);
145 		VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
146 	}
147 
148 	instances.push_back(ins);
149 }
150 
add_unscaled_billboard(const Ref<Material> & p_material,float p_scale)151 void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material> &p_material, float p_scale) {
152 
153 	ERR_FAIL_COND(!spatial_node);
154 	Instance ins;
155 
156 	Vector<Vector3> vs;
157 	Vector<Vector2> uv;
158 
159 	vs.push_back(Vector3(-p_scale, p_scale, 0));
160 	vs.push_back(Vector3(p_scale, p_scale, 0));
161 	vs.push_back(Vector3(p_scale, -p_scale, 0));
162 	vs.push_back(Vector3(-p_scale, -p_scale, 0));
163 
164 	uv.push_back(Vector2(1, 0));
165 	uv.push_back(Vector2(0, 0));
166 	uv.push_back(Vector2(0, 1));
167 	uv.push_back(Vector2(1, 1));
168 
169 	Ref<Mesh> mesh = memnew(Mesh);
170 	Array a;
171 	a.resize(Mesh::ARRAY_MAX);
172 	a[Mesh::ARRAY_VERTEX] = vs;
173 	a[Mesh::ARRAY_TEX_UV] = uv;
174 	mesh->add_surface(Mesh::PRIMITIVE_TRIANGLE_FAN, a);
175 	mesh->surface_set_material(0, p_material);
176 
177 	if (true) {
178 		float md = 0;
179 		for (int i = 0; i < vs.size(); i++) {
180 
181 			md = MAX(0, vs[i].length());
182 		}
183 		if (md) {
184 			mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
185 		}
186 	}
187 
188 	ins.mesh = mesh;
189 	ins.unscaled = true;
190 	ins.billboard = true;
191 	if (valid) {
192 		ins.create_instance(spatial_node);
193 		VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
194 	}
195 
196 	instances.push_back(ins);
197 }
198 
add_collision_triangles(const Ref<TriangleMesh> & p_tmesh)199 void EditorSpatialGizmo::add_collision_triangles(const Ref<TriangleMesh> &p_tmesh) {
200 
201 	collision_mesh = p_tmesh;
202 }
203 
add_collision_segments(const Vector<Vector3> & p_lines)204 void EditorSpatialGizmo::add_collision_segments(const Vector<Vector3> &p_lines) {
205 
206 	int from = collision_segments.size();
207 	collision_segments.resize(from + p_lines.size());
208 	for (int i = 0; i < p_lines.size(); i++) {
209 
210 		collision_segments[from + i] = p_lines[i];
211 	}
212 }
213 
add_handles(const Vector<Vector3> & p_handles,bool p_billboard,bool p_secondary)214 void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_billboard, bool p_secondary) {
215 
216 	billboard_handle = p_billboard;
217 
218 	if (!is_selected())
219 		return;
220 
221 	ERR_FAIL_COND(!spatial_node);
222 
223 	ERR_FAIL_COND(!spatial_node);
224 	Instance ins;
225 
226 	Ref<Mesh> mesh = memnew(Mesh);
227 #if 1
228 
229 	Array a;
230 	a.resize(VS::ARRAY_MAX);
231 	a[VS::ARRAY_VERTEX] = p_handles;
232 	DVector<Color> colors;
233 	{
234 		colors.resize(p_handles.size());
235 		DVector<Color>::Write w = colors.write();
236 		for (int i = 0; i < p_handles.size(); i++) {
237 
238 			Color col(1, 1, 1, 1);
239 			if (SpatialEditor::get_singleton()->get_over_gizmo_handle() != i)
240 				col = Color(0.9, 0.9, 0.9, 0.9);
241 			w[i] = col;
242 		}
243 	}
244 	a[VS::ARRAY_COLOR] = colors;
245 	mesh->add_surface(Mesh::PRIMITIVE_POINTS, a);
246 	mesh->surface_set_material(0, SpatialEditorGizmos::singleton->handle2_material);
247 
248 	if (p_billboard) {
249 		float md = 0;
250 		for (int i = 0; i < p_handles.size(); i++) {
251 
252 			md = MAX(0, p_handles[i].length());
253 		}
254 		if (md) {
255 			mesh->set_custom_aabb(AABB(Vector3(-md, -md, -md), Vector3(md, md, md) * 2.0));
256 		}
257 	}
258 
259 #else
260 	for (int ih = 0; ih < p_handles.size(); ih++) {
261 
262 		Vector<Vector3> vertices;
263 		Vector<Vector3> normals;
264 
265 		int vtx_idx = 0;
266 
267 #define ADD_VTX(m_idx)                                                           \
268 	vertices.push_back((face_points[m_idx] * HANDLE_HALF_SIZE + p_handles[ih])); \
269 	normals.push_back(normal_points[m_idx]);                                     \
270 	vtx_idx++;
271 
272 		for (int i = 0; i < 6; i++) {
273 
274 			Vector3 face_points[4];
275 			Vector3 normal_points[4];
276 			float uv_points[8] = { 0, 0, 0, 1, 1, 1, 1, 0 };
277 
278 			for (int j = 0; j < 4; j++) {
279 
280 				float v[3];
281 				v[0] = 1.0;
282 				v[1] = 1 - 2 * ((j >> 1) & 1);
283 				v[2] = v[1] * (1 - 2 * (j & 1));
284 
285 				for (int k = 0; k < 3; k++) {
286 
287 					if (i < 3)
288 						face_points[j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1);
289 					else
290 						face_points[3 - j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1);
291 				}
292 				normal_points[j] = Vector3();
293 				normal_points[j][i % 3] = (i >= 3 ? -1 : 1);
294 			}
295 			//tri 1
296 			ADD_VTX(0);
297 			ADD_VTX(1);
298 			ADD_VTX(2);
299 			//tri 2
300 			ADD_VTX(2);
301 			ADD_VTX(3);
302 			ADD_VTX(0);
303 		}
304 
305 		Array d;
306 		d.resize(VS::ARRAY_MAX);
307 		d[VisualServer::ARRAY_NORMAL] = normals;
308 		d[VisualServer::ARRAY_VERTEX] = vertices;
309 
310 		mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, d);
311 		mesh->surface_set_material(ih, SpatialEditorGizmos::singleton->handle_material);
312 	}
313 #endif
314 	ins.mesh = mesh;
315 	ins.billboard = p_billboard;
316 	ins.extra_margin = true;
317 	if (valid) {
318 		ins.create_instance(spatial_node);
319 		VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform());
320 	}
321 	instances.push_back(ins);
322 	if (!p_secondary) {
323 		int chs = handles.size();
324 		handles.resize(chs + p_handles.size());
325 		for (int i = 0; i < p_handles.size(); i++) {
326 			handles[i + chs] = p_handles[i];
327 		}
328 	} else {
329 
330 		int chs = secondary_handles.size();
331 		secondary_handles.resize(chs + p_handles.size());
332 		for (int i = 0; i < p_handles.size(); i++) {
333 			secondary_handles[i + chs] = p_handles[i];
334 		}
335 	}
336 }
337 
set_spatial_node(Spatial * p_node)338 void EditorSpatialGizmo::set_spatial_node(Spatial *p_node) {
339 
340 	ERR_FAIL_NULL(p_node);
341 	spatial_node = p_node;
342 }
343 
intersect_frustum(const Camera * p_camera,const Vector<Plane> & p_frustum)344 bool EditorSpatialGizmo::intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum) {
345 
346 	ERR_FAIL_COND_V(!spatial_node, false);
347 	ERR_FAIL_COND_V(!valid, false);
348 
349 	if (collision_segments.size()) {
350 
351 		const Plane *p = p_frustum.ptr();
352 		int fc = p_frustum.size();
353 
354 		int vc = collision_segments.size();
355 		const Vector3 *vptr = collision_segments.ptr();
356 		Transform t = spatial_node->get_global_transform();
357 
358 		for (int i = 0; i < vc / 2; i++) {
359 
360 			Vector3 a = t.xform(vptr[i * 2 + 0]);
361 			Vector3 b = t.xform(vptr[i * 2 + 1]);
362 
363 			bool any_out = false;
364 			for (int j = 0; j < fc; j++) {
365 
366 				if (p[j].distance_to(a) > 0 && p[j].distance_to(b) > 0) {
367 
368 					any_out = true;
369 					break;
370 				}
371 			}
372 
373 			if (!any_out)
374 				return true;
375 		}
376 
377 		return false;
378 	}
379 
380 	return false;
381 }
382 
intersect_ray(const Camera * p_camera,const Point2 & p_point,Vector3 & r_pos,Vector3 & r_normal,int * r_gizmo_handle,bool p_sec_first)383 bool EditorSpatialGizmo::intersect_ray(const Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) {
384 
385 	ERR_FAIL_COND_V(!spatial_node, false);
386 	ERR_FAIL_COND_V(!valid, false);
387 
388 	if (r_gizmo_handle) {
389 
390 		Transform t = spatial_node->get_global_transform();
391 		t.orthonormalize();
392 		if (billboard_handle) {
393 			t.set_look_at(t.origin, t.origin + p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
394 		}
395 		Transform ti = t.affine_inverse();
396 
397 		float min_d = 1e20;
398 		int idx = -1;
399 
400 		for (int i = 0; i < secondary_handles.size(); i++) {
401 
402 			Vector3 hpos = t.xform(secondary_handles[i]);
403 			Vector2 p = p_camera->unproject_position(hpos);
404 			if (p.distance_to(p_point) < SpatialEditorGizmos::singleton->handle_t->get_width() * 0.6) {
405 
406 				real_t dp = p_camera->get_transform().origin.distance_to(hpos);
407 				if (dp < min_d) {
408 
409 					r_pos = t.xform(hpos);
410 					r_normal = p_camera->get_transform().basis.get_axis(2);
411 					min_d = dp;
412 					idx = i + handles.size();
413 				}
414 			}
415 		}
416 
417 		if (p_sec_first && idx != -1) {
418 
419 			*r_gizmo_handle = idx;
420 			return true;
421 		}
422 
423 		min_d = 1e20;
424 
425 		for (int i = 0; i < handles.size(); i++) {
426 
427 			Vector3 hpos = t.xform(handles[i]);
428 			Vector2 p = p_camera->unproject_position(hpos);
429 			if (p.distance_to(p_point) < SpatialEditorGizmos::singleton->handle_t->get_width() * 0.6) {
430 
431 				real_t dp = p_camera->get_transform().origin.distance_to(hpos);
432 				if (dp < min_d) {
433 
434 					r_pos = t.xform(hpos);
435 					r_normal = p_camera->get_transform().basis.get_axis(2);
436 					min_d = dp;
437 					idx = i;
438 				}
439 			}
440 		}
441 
442 		if (idx >= 0) {
443 			*r_gizmo_handle = idx;
444 			return true;
445 		}
446 	}
447 
448 	if (collision_segments.size()) {
449 
450 		Plane camp(p_camera->get_transform().origin, (-p_camera->get_transform().basis.get_axis(2)).normalized());
451 
452 		int vc = collision_segments.size();
453 		const Vector3 *vptr = collision_segments.ptr();
454 		Transform t = spatial_node->get_global_transform();
455 		if (billboard_handle) {
456 			t.set_look_at(t.origin, t.origin + p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
457 		}
458 
459 		Vector3 cp;
460 		float cpd = 1e20;
461 
462 		for (int i = 0; i < vc / 2; i++) {
463 
464 			Vector3 a = t.xform(vptr[i * 2 + 0]);
465 			Vector3 b = t.xform(vptr[i * 2 + 1]);
466 			Vector2 s[2];
467 			s[0] = p_camera->unproject_position(a);
468 			s[1] = p_camera->unproject_position(b);
469 
470 			Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, s);
471 
472 			float pd = p.distance_to(p_point);
473 
474 			if (pd < cpd) {
475 
476 				float d = s[0].distance_to(s[1]);
477 				Vector3 tcp;
478 				if (d > 0) {
479 
480 					float d2 = s[0].distance_to(p) / d;
481 					tcp = a + (b - a) * d2;
482 
483 				} else {
484 					tcp = a;
485 				}
486 
487 				if (camp.distance_to(tcp) < p_camera->get_znear())
488 					continue;
489 				cp = tcp;
490 				cpd = pd;
491 			}
492 		}
493 
494 		if (cpd < 8) {
495 
496 			r_pos = cp;
497 			r_normal = -p_camera->project_ray_normal(p_point);
498 			return true;
499 		}
500 
501 		return false;
502 	}
503 
504 	if (collision_mesh.is_valid()) {
505 		Transform gt = spatial_node->get_global_transform();
506 
507 		if (billboard_handle) {
508 			gt.set_look_at(gt.origin, gt.origin + p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1));
509 		}
510 
511 		Transform ai = gt.affine_inverse();
512 		Vector3 ray_from = ai.xform(p_camera->project_ray_origin(p_point));
513 		Vector3 ray_dir = ai.basis.xform(p_camera->project_ray_normal(p_point)).normalized();
514 		Vector3 rpos, rnorm;
515 
516 		if (collision_mesh->intersect_ray(ray_from, ray_dir, rpos, rnorm)) {
517 
518 			r_pos = gt.xform(rpos);
519 			r_normal = gt.basis.xform(rnorm).normalized();
520 			return true;
521 		}
522 	}
523 
524 	return false;
525 }
526 
create()527 void EditorSpatialGizmo::create() {
528 
529 	ERR_FAIL_COND(!spatial_node);
530 	ERR_FAIL_COND(valid);
531 	valid = true;
532 
533 	for (int i = 0; i < instances.size(); i++) {
534 
535 		instances[i].create_instance(spatial_node);
536 	}
537 
538 	transform();
539 }
540 
transform()541 void EditorSpatialGizmo::transform() {
542 
543 	ERR_FAIL_COND(!spatial_node);
544 	ERR_FAIL_COND(!valid);
545 	for (int i = 0; i < instances.size(); i++) {
546 		VS::get_singleton()->instance_set_transform(instances[i].instance, spatial_node->get_global_transform());
547 	}
548 }
549 
free()550 void EditorSpatialGizmo::free() {
551 
552 	ERR_FAIL_COND(!spatial_node);
553 	ERR_FAIL_COND(!valid);
554 
555 	for (int i = 0; i < instances.size(); i++) {
556 
557 		if (instances[i].instance.is_valid())
558 			VS::get_singleton()->free(instances[i].instance);
559 		instances[i].instance = RID();
560 	}
561 
562 	valid = false;
563 }
564 
_bind_methods()565 void EditorSpatialGizmo::_bind_methods() {
566 
567 	ObjectTypeDB::bind_method(_MD("add_lines", "lines", "material:Material", "billboard"), &EditorSpatialGizmo::add_lines, DEFVAL(false));
568 	ObjectTypeDB::bind_method(_MD("add_mesh", "mesh:Mesh", "billboard", "skeleton"), &EditorSpatialGizmo::add_mesh, DEFVAL(false), DEFVAL(RID()));
569 	ObjectTypeDB::bind_method(_MD("add_collision_segments", "segments"), &EditorSpatialGizmo::add_collision_segments);
570 	ObjectTypeDB::bind_method(_MD("add_collision_triangles", "triangles:TriangleMesh"), &EditorSpatialGizmo::add_collision_triangles);
571 	ObjectTypeDB::bind_method(_MD("add_unscaled_billboard", "material:Material", "default_scale"), &EditorSpatialGizmo::add_unscaled_billboard, DEFVAL(1));
572 	ObjectTypeDB::bind_method(_MD("add_handles", "handles", "billboard", "secondary"), &EditorSpatialGizmo::add_handles, DEFVAL(false), DEFVAL(false));
573 	ObjectTypeDB::bind_method(_MD("set_spatial_node", "node:Spatial"), &EditorSpatialGizmo::_set_spatial_node);
574 	ObjectTypeDB::bind_method(_MD("clear"), &EditorSpatialGizmo::clear);
575 
576 	BIND_VMETHOD(MethodInfo("redraw"));
577 	BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", PropertyInfo(Variant::INT, "index")));
578 	BIND_VMETHOD(MethodInfo("get_handle_value:Variant", PropertyInfo(Variant::INT, "index")));
579 	BIND_VMETHOD(MethodInfo("set_handle", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera:Camera"), PropertyInfo(Variant::VECTOR2, "point")));
580 	MethodInfo cm = MethodInfo("commit_handle", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::NIL, "restore:Variant"), PropertyInfo(Variant::BOOL, "cancel"));
581 	cm.default_arguments.push_back(false);
582 	BIND_VMETHOD(cm);
583 }
584 
EditorSpatialGizmo()585 EditorSpatialGizmo::EditorSpatialGizmo() {
586 	valid = false;
587 	billboard_handle = false;
588 	base = NULL;
589 	spatial_node = NULL;
590 }
591 
~EditorSpatialGizmo()592 EditorSpatialGizmo::~EditorSpatialGizmo() {
593 
594 	clear();
595 }
596 
get_handle_pos(int p_idx) const597 Vector3 EditorSpatialGizmo::get_handle_pos(int p_idx) const {
598 
599 	ERR_FAIL_INDEX_V(p_idx, handles.size(), Vector3());
600 
601 	return handles[p_idx];
602 }
603 
604 //// light gizmo
605 
get_handle_name(int p_idx) const606 String LightSpatialGizmo::get_handle_name(int p_idx) const {
607 
608 	if (p_idx == 0)
609 		return "Radius";
610 	else
611 		return "Aperture";
612 }
613 
get_handle_value(int p_idx) const614 Variant LightSpatialGizmo::get_handle_value(int p_idx) const {
615 
616 	if (p_idx == 0)
617 		return light->get_parameter(Light::PARAM_RADIUS);
618 	if (p_idx == 1)
619 		return light->get_parameter(Light::PARAM_SPOT_ANGLE);
620 
621 	return Variant();
622 }
623 
_find_closest_angle_to_half_pi_arc(const Vector3 & p_from,const Vector3 & p_to,float p_arc_radius,const Transform & p_arc_xform)624 static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vector3 &p_to, float p_arc_radius, const Transform &p_arc_xform) {
625 
626 	//bleh, discrete is simpler
627 	static const int arc_test_points = 64;
628 	float min_d = 1e20;
629 	Vector3 min_p;
630 
631 	for (int i = 0; i < arc_test_points; i++) {
632 
633 		float a = i * Math_PI * 0.5 / arc_test_points;
634 		float an = (i + 1) * Math_PI * 0.5 / arc_test_points;
635 		Vector3 p = Vector3(Math::cos(a), 0, -Math::sin(a)) * p_arc_radius;
636 		Vector3 n = Vector3(Math::cos(an), 0, -Math::sin(an)) * p_arc_radius;
637 
638 		Vector3 ra, rb;
639 		Geometry::get_closest_points_between_segments(p, n, p_from, p_to, ra, rb);
640 
641 		float d = ra.distance_to(rb);
642 		if (d < min_d) {
643 			min_d = d;
644 			min_p = ra;
645 		}
646 	}
647 
648 	//min_p = p_arc_xform.affine_inverse().xform(min_p);
649 	float a = Vector2(min_p.x, -min_p.z).angle();
650 	return a * 180.0 / Math_PI;
651 }
652 
set_handle(int p_idx,Camera * p_camera,const Point2 & p_point)653 void LightSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
654 
655 	Transform gt = light->get_global_transform();
656 	gt.orthonormalize();
657 	Transform gi = gt.affine_inverse();
658 
659 	Vector3 ray_from = p_camera->project_ray_origin(p_point);
660 	Vector3 ray_dir = p_camera->project_ray_normal(p_point);
661 
662 	Vector3 s[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
663 	if (p_idx == 0) {
664 
665 		if (light->cast_to<SpotLight>()) {
666 			Vector3 ra, rb;
667 			Geometry::get_closest_points_between_segments(Vector3(), Vector3(0, 0, -4096), s[0], s[1], ra, rb);
668 
669 			float d = -ra.z;
670 			if (d < 0)
671 				d = 0;
672 
673 			light->set_parameter(Light::PARAM_RADIUS, d);
674 		} else if (light->cast_to<OmniLight>()) {
675 
676 			Plane cp = Plane(gt.origin, p_camera->get_transform().basis.get_axis(2));
677 
678 			Vector3 inters;
679 			if (cp.intersects_ray(ray_from, ray_dir, &inters)) {
680 
681 				float r = inters.distance_to(gt.origin);
682 				light->set_parameter(Light::PARAM_RADIUS, r);
683 			}
684 		}
685 
686 	} else if (p_idx == 1) {
687 
688 		float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], light->get_parameter(Light::PARAM_RADIUS), gt);
689 		light->set_parameter(Light::PARAM_SPOT_ANGLE, CLAMP(a, 0.01, 89.99));
690 	}
691 }
692 
commit_handle(int p_idx,const Variant & p_restore,bool p_cancel)693 void LightSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
694 
695 	if (p_cancel) {
696 
697 		light->set_parameter(p_idx == 0 ? Light::PARAM_RADIUS : Light::PARAM_SPOT_ANGLE, p_restore);
698 
699 	} else if (p_idx == 0) {
700 
701 		UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
702 		ur->create_action(TTR("Change Light Radius"));
703 		ur->add_do_method(light, "set_parameter", Light::PARAM_RADIUS, light->get_parameter(Light::PARAM_RADIUS));
704 		ur->add_undo_method(light, "set_parameter", Light::PARAM_RADIUS, p_restore);
705 		ur->commit_action();
706 	} else if (p_idx == 1) {
707 
708 		UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
709 		ur->create_action(TTR("Change Light Radius"));
710 		ur->add_do_method(light, "set_parameter", Light::PARAM_SPOT_ANGLE, light->get_parameter(Light::PARAM_SPOT_ANGLE));
711 		ur->add_undo_method(light, "set_parameter", Light::PARAM_SPOT_ANGLE, p_restore);
712 		ur->commit_action();
713 	}
714 }
715 
redraw()716 void LightSpatialGizmo::redraw() {
717 
718 	if (light->cast_to<DirectionalLight>()) {
719 
720 		const int arrow_points = 5;
721 		Vector3 arrow[arrow_points] = {
722 			Vector3(0, 0, 2),
723 			Vector3(1, 1, 2),
724 			Vector3(1, 1, -1),
725 			Vector3(2, 2, -1),
726 			Vector3(0, 0, -3)
727 		};
728 
729 		int arrow_sides = 4;
730 
731 		Vector<Vector3> lines;
732 
733 		for (int i = 0; i < arrow_sides; i++) {
734 
735 			Matrix3 ma(Vector3(0, 0, 1), Math_PI * 2 * float(i) / arrow_sides);
736 			Matrix3 mb(Vector3(0, 0, 1), Math_PI * 2 * float(i + 1) / arrow_sides);
737 
738 			for (int j = 1; j < arrow_points - 1; j++) {
739 
740 				if (j != 2) {
741 					lines.push_back(ma.xform(arrow[j]));
742 					lines.push_back(ma.xform(arrow[j + 1]));
743 				}
744 				if (j < arrow_points - 1) {
745 					lines.push_back(ma.xform(arrow[j]));
746 					lines.push_back(mb.xform(arrow[j]));
747 				}
748 			}
749 		}
750 
751 		add_lines(lines, SpatialEditorGizmos::singleton->light_material);
752 		add_collision_segments(lines);
753 		add_unscaled_billboard(SpatialEditorGizmos::singleton->light_material_directional_icon, 0.05);
754 	}
755 
756 	if (light->cast_to<OmniLight>()) {
757 
758 		clear();
759 
760 		OmniLight *on = light->cast_to<OmniLight>();
761 
762 		float r = on->get_parameter(Light::PARAM_RADIUS);
763 
764 		Vector<Vector3> points;
765 
766 		for (int i = 0; i <= 360; i++) {
767 
768 			float ra = Math::deg2rad(i);
769 			float rb = Math::deg2rad(i + 1);
770 			Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
771 			Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
772 
773 			/*points.push_back(Vector3(a.x,0,a.y));
774 			points.push_back(Vector3(b.x,0,b.y));
775 			points.push_back(Vector3(0,a.x,a.y));
776 			points.push_back(Vector3(0,b.x,b.y));*/
777 			points.push_back(Vector3(a.x, a.y, 0));
778 			points.push_back(Vector3(b.x, b.y, 0));
779 		}
780 
781 		add_lines(points, SpatialEditorGizmos::singleton->light_material, true);
782 		add_collision_segments(points);
783 
784 		add_unscaled_billboard(SpatialEditorGizmos::singleton->light_material_omni_icon, 0.05);
785 
786 		Vector<Vector3> handles;
787 		handles.push_back(Vector3(r, 0, 0));
788 		add_handles(handles, true);
789 	}
790 
791 	if (light->cast_to<SpotLight>()) {
792 
793 		clear();
794 
795 		Vector<Vector3> points;
796 		SpotLight *on = light->cast_to<SpotLight>();
797 
798 		float r = on->get_parameter(Light::PARAM_RADIUS);
799 		float w = r * Math::sin(Math::deg2rad(on->get_parameter(Light::PARAM_SPOT_ANGLE)));
800 		float d = r * Math::cos(Math::deg2rad(on->get_parameter(Light::PARAM_SPOT_ANGLE)));
801 
802 		for (int i = 0; i < 360; i++) {
803 
804 			float ra = Math::deg2rad(i);
805 			float rb = Math::deg2rad(i + 1);
806 			Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
807 			Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
808 
809 			/*points.push_back(Vector3(a.x,0,a.y));
810 			points.push_back(Vector3(b.x,0,b.y));
811 			points.push_back(Vector3(0,a.x,a.y));
812 			points.push_back(Vector3(0,b.x,b.y));*/
813 			points.push_back(Vector3(a.x, a.y, -d));
814 			points.push_back(Vector3(b.x, b.y, -d));
815 
816 			if (i % 90 == 0) {
817 
818 				points.push_back(Vector3(a.x, a.y, -d));
819 				points.push_back(Vector3());
820 			}
821 		}
822 
823 		points.push_back(Vector3(0, 0, -r));
824 		points.push_back(Vector3());
825 
826 		add_lines(points, SpatialEditorGizmos::singleton->light_material);
827 
828 		Vector<Vector3> handles;
829 		handles.push_back(Vector3(0, 0, -r));
830 
831 		Vector<Vector3> collision_segments;
832 
833 		for (int i = 0; i < 64; i++) {
834 
835 			float ra = i * Math_PI * 2.0 / 64.0;
836 			float rb = (i + 1) * Math_PI * 2.0 / 64.0;
837 			Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
838 			Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
839 
840 			collision_segments.push_back(Vector3(a.x, a.y, -d));
841 			collision_segments.push_back(Vector3(b.x, b.y, -d));
842 
843 			if (i % 16 == 0) {
844 
845 				collision_segments.push_back(Vector3(a.x, a.y, -d));
846 				collision_segments.push_back(Vector3());
847 			}
848 
849 			if (i == 16) {
850 
851 				handles.push_back(Vector3(a.x, a.y, -d));
852 			}
853 		}
854 
855 		collision_segments.push_back(Vector3(0, 0, -r));
856 		collision_segments.push_back(Vector3());
857 
858 		add_handles(handles);
859 		add_collision_segments(collision_segments);
860 		add_unscaled_billboard(SpatialEditorGizmos::singleton->light_material_omni_icon, 0.05);
861 	}
862 }
863 
LightSpatialGizmo(Light * p_light)864 LightSpatialGizmo::LightSpatialGizmo(Light *p_light) {
865 
866 	light = p_light;
867 	set_spatial_node(p_light);
868 }
869 //////
870 
redraw()871 void ListenerSpatialGizmo::redraw() {
872 
873 	clear();
874 
875 	add_unscaled_billboard(SpatialEditorGizmos::singleton->listener_icon, 0.05);
876 
877 	add_mesh(SpatialEditorGizmos::singleton->listener_line_mesh);
878 	Vector<Vector3> cursor_points;
879 	cursor_points.push_back(Vector3(0, 0, 0));
880 	cursor_points.push_back(Vector3(0, 0, -1.0));
881 	add_collision_segments(cursor_points);
882 }
883 
ListenerSpatialGizmo(Listener * p_listener)884 ListenerSpatialGizmo::ListenerSpatialGizmo(Listener *p_listener) {
885 
886 	set_spatial_node(p_listener);
887 	listener = p_listener;
888 }
889 
890 //////
891 
get_handle_name(int p_idx) const892 String CameraSpatialGizmo::get_handle_name(int p_idx) const {
893 
894 	if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) {
895 		return "FOV";
896 	} else {
897 		return "Size";
898 	}
899 }
get_handle_value(int p_idx) const900 Variant CameraSpatialGizmo::get_handle_value(int p_idx) const {
901 
902 	if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) {
903 		return camera->get_fov();
904 	} else {
905 
906 		return camera->get_size();
907 	}
908 }
set_handle(int p_idx,Camera * p_camera,const Point2 & p_point)909 void CameraSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
910 
911 	Transform gt = camera->get_global_transform();
912 	gt.orthonormalize();
913 	Transform gi = gt.affine_inverse();
914 
915 	Vector3 ray_from = p_camera->project_ray_origin(p_point);
916 	Vector3 ray_dir = p_camera->project_ray_normal(p_point);
917 
918 	Vector3 s[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
919 
920 	if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) {
921 		Transform gt = camera->get_global_transform();
922 		float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], 1.0, gt);
923 		camera->set("fov", a);
924 	} else {
925 
926 		Vector3 ra, rb;
927 		Geometry::get_closest_points_between_segments(Vector3(0, 0, -1), Vector3(4096, 0, -1), s[0], s[1], ra, rb);
928 		float d = ra.x * 2.0;
929 		if (d < 0)
930 			d = 0;
931 
932 		camera->set("size", d);
933 	}
934 }
commit_handle(int p_idx,const Variant & p_restore,bool p_cancel)935 void CameraSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
936 
937 	if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) {
938 
939 		if (p_cancel) {
940 
941 			camera->set("fov", p_restore);
942 		} else {
943 			UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
944 			ur->create_action(TTR("Change Camera FOV"));
945 			ur->add_do_property(camera, "fov", camera->get_fov());
946 			ur->add_undo_property(camera, "fov", p_restore);
947 			ur->commit_action();
948 		}
949 
950 	} else {
951 
952 		if (p_cancel) {
953 
954 			camera->set("size", p_restore);
955 		} else {
956 			UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
957 			ur->create_action(TTR("Change Camera Size"));
958 			ur->add_do_property(camera, "size", camera->get_size());
959 			ur->add_undo_property(camera, "size", p_restore);
960 			ur->commit_action();
961 		}
962 	}
963 }
964 
redraw()965 void CameraSpatialGizmo::redraw() {
966 
967 	clear();
968 
969 	Vector<Vector3> lines;
970 	Vector<Vector3> handles;
971 
972 	switch (camera->get_projection()) {
973 
974 		case Camera::PROJECTION_PERSPECTIVE: {
975 
976 			float fov = camera->get_fov();
977 
978 			Vector3 side = Vector3(Math::sin(Math::deg2rad(fov)), 0, -Math::cos(Math::deg2rad(fov)));
979 			Vector3 nside = side;
980 			nside.x = -nside.x;
981 			Vector3 up = Vector3(0, side.x, 0);
982 
983 #define ADD_TRIANGLE(m_a, m_b, m_c) \
984 	{                               \
985 		lines.push_back(m_a);       \
986 		lines.push_back(m_b);       \
987 		lines.push_back(m_b);       \
988 		lines.push_back(m_c);       \
989 		lines.push_back(m_c);       \
990 		lines.push_back(m_a);       \
991 	}
992 
993 			ADD_TRIANGLE(Vector3(), side + up, side - up);
994 			ADD_TRIANGLE(Vector3(), nside + up, nside - up);
995 			ADD_TRIANGLE(Vector3(), side + up, nside + up);
996 			ADD_TRIANGLE(Vector3(), side - up, nside - up);
997 
998 			handles.push_back(side);
999 			side.x *= 0.25;
1000 			nside.x *= 0.25;
1001 			Vector3 tup(0, up.y * 3 / 2, side.z);
1002 			ADD_TRIANGLE(tup, side + up, nside + up);
1003 
1004 		} break;
1005 		case Camera::PROJECTION_ORTHOGONAL: {
1006 
1007 #define ADD_QUAD(m_a, m_b, m_c, m_d) \
1008 	{                                \
1009 		lines.push_back(m_a);        \
1010 		lines.push_back(m_b);        \
1011 		lines.push_back(m_b);        \
1012 		lines.push_back(m_c);        \
1013 		lines.push_back(m_c);        \
1014 		lines.push_back(m_d);        \
1015 		lines.push_back(m_d);        \
1016 		lines.push_back(m_a);        \
1017 	}
1018 			float size = camera->get_size();
1019 
1020 			float hsize = size * 0.5;
1021 			Vector3 right(hsize, 0, 0);
1022 			Vector3 up(0, hsize, 0);
1023 			Vector3 back(0, 0, -1.0);
1024 			Vector3 front(0, 0, 0);
1025 
1026 			ADD_QUAD(-up - right, -up + right, up + right, up - right);
1027 			ADD_QUAD(-up - right + back, -up + right + back, up + right + back, up - right + back);
1028 			ADD_QUAD(up + right, up + right + back, up - right + back, up - right);
1029 			ADD_QUAD(-up + right, -up + right + back, -up - right + back, -up - right);
1030 			handles.push_back(right + back);
1031 
1032 			right.x *= 0.25;
1033 			Vector3 tup(0, up.y * 3 / 2, back.z);
1034 			ADD_TRIANGLE(tup, right + up + back, -right + up + back);
1035 
1036 		} break;
1037 	}
1038 
1039 	add_lines(lines, SpatialEditorGizmos::singleton->camera_material);
1040 	add_collision_segments(lines);
1041 	add_handles(handles);
1042 }
1043 
CameraSpatialGizmo(Camera * p_camera)1044 CameraSpatialGizmo::CameraSpatialGizmo(Camera *p_camera) {
1045 
1046 	camera = p_camera;
1047 	set_spatial_node(camera);
1048 }
1049 
1050 //////
1051 
redraw()1052 void MeshInstanceSpatialGizmo::redraw() {
1053 
1054 	Ref<Mesh> m = mesh->get_mesh();
1055 	if (!m.is_valid())
1056 		return; //none
1057 
1058 	Ref<TriangleMesh> tm = m->generate_triangle_mesh();
1059 	if (tm.is_valid())
1060 		add_collision_triangles(tm);
1061 }
1062 
MeshInstanceSpatialGizmo(MeshInstance * p_mesh)1063 MeshInstanceSpatialGizmo::MeshInstanceSpatialGizmo(MeshInstance *p_mesh) {
1064 
1065 	mesh = p_mesh;
1066 	set_spatial_node(p_mesh);
1067 }
1068 
1069 /////
1070 
redraw()1071 void Position3DSpatialGizmo::redraw() {
1072 
1073 	clear();
1074 	add_mesh(SpatialEditorGizmos::singleton->pos3d_mesh);
1075 	Vector<Vector3> cursor_points;
1076 	float cs = 0.25;
1077 	cursor_points.push_back(Vector3(+cs, 0, 0));
1078 	cursor_points.push_back(Vector3(-cs, 0, 0));
1079 	cursor_points.push_back(Vector3(0, +cs, 0));
1080 	cursor_points.push_back(Vector3(0, -cs, 0));
1081 	cursor_points.push_back(Vector3(0, 0, +cs));
1082 	cursor_points.push_back(Vector3(0, 0, -cs));
1083 	add_collision_segments(cursor_points);
1084 }
1085 
Position3DSpatialGizmo(Position3D * p_p3d)1086 Position3DSpatialGizmo::Position3DSpatialGizmo(Position3D *p_p3d) {
1087 
1088 	p3d = p_p3d;
1089 	set_spatial_node(p3d);
1090 }
1091 
1092 /////
1093 
redraw()1094 void SkeletonSpatialGizmo::redraw() {
1095 
1096 	clear();
1097 
1098 	Ref<SurfaceTool> surface_tool(memnew(SurfaceTool));
1099 
1100 	surface_tool->begin(Mesh::PRIMITIVE_LINES);
1101 	surface_tool->set_material(SpatialEditorGizmos::singleton->skeleton_material);
1102 	Vector<Transform> grests;
1103 	grests.resize(skel->get_bone_count());
1104 
1105 	Vector<int> bones;
1106 	Vector<float> weights;
1107 	bones.resize(4);
1108 	weights.resize(4);
1109 
1110 	for (int i = 0; i < 4; i++) {
1111 		bones[i] = 0;
1112 		weights[i] = 0;
1113 	}
1114 
1115 	weights[0] = 1;
1116 
1117 	AABB aabb;
1118 
1119 	Color bonecolor = Color(1.0, 0.4, 0.4, 0.3);
1120 	Color rootcolor = Color(0.4, 1.0, 0.4, 0.1);
1121 
1122 	for (int i = 0; i < skel->get_bone_count(); i++) {
1123 
1124 		int parent = skel->get_bone_parent(i);
1125 
1126 		if (parent >= 0) {
1127 			grests[i] = grests[parent] * skel->get_bone_rest(i);
1128 
1129 			Vector3 v0 = grests[parent].origin;
1130 			Vector3 v1 = grests[i].origin;
1131 			Vector3 d = (v1 - v0).normalized();
1132 			float dist = v0.distance_to(v1);
1133 
1134 			//find closest axis
1135 			int closest = -1;
1136 			float closest_d = 0.0;
1137 
1138 			for (int j = 0; j < 3; j++) {
1139 				float dp = Math::abs(grests[parent].basis[j].normalized().dot(d));
1140 				if (j == 0 || dp > closest_d)
1141 					closest = j;
1142 			}
1143 
1144 			//find closest other
1145 			Vector3 first;
1146 			Vector3 points[4];
1147 			int pointidx = 0;
1148 			for (int j = 0; j < 3; j++) {
1149 
1150 				bones[0] = parent;
1151 				surface_tool->add_bones(bones);
1152 				surface_tool->add_weights(weights);
1153 				surface_tool->add_color(rootcolor);
1154 				surface_tool->add_vertex(v0 - grests[parent].basis[j].normalized() * dist * 0.05);
1155 				surface_tool->add_bones(bones);
1156 				surface_tool->add_weights(weights);
1157 				surface_tool->add_color(rootcolor);
1158 				surface_tool->add_vertex(v0 + grests[parent].basis[j].normalized() * dist * 0.05);
1159 
1160 				if (j == closest)
1161 					continue;
1162 
1163 				Vector3 axis;
1164 				if (first == Vector3()) {
1165 					axis = d.cross(d.cross(grests[parent].basis[j])).normalized();
1166 					first = axis;
1167 				} else {
1168 					axis = d.cross(first).normalized();
1169 				}
1170 
1171 				for (int k = 0; k < 2; k++) {
1172 
1173 					if (k == 1)
1174 						axis = -axis;
1175 					Vector3 point = v0 + d * dist * 0.2;
1176 					point += axis * dist * 0.1;
1177 
1178 					bones[0] = parent;
1179 					surface_tool->add_bones(bones);
1180 					surface_tool->add_weights(weights);
1181 					surface_tool->add_color(bonecolor);
1182 					surface_tool->add_vertex(v0);
1183 					surface_tool->add_bones(bones);
1184 					surface_tool->add_weights(weights);
1185 					surface_tool->add_color(bonecolor);
1186 					surface_tool->add_vertex(point);
1187 
1188 					bones[0] = parent;
1189 					surface_tool->add_bones(bones);
1190 					surface_tool->add_weights(weights);
1191 					surface_tool->add_color(bonecolor);
1192 					surface_tool->add_vertex(point);
1193 					bones[0] = i;
1194 					surface_tool->add_bones(bones);
1195 					surface_tool->add_weights(weights);
1196 					surface_tool->add_color(bonecolor);
1197 					surface_tool->add_vertex(v1);
1198 					points[pointidx++] = point;
1199 				}
1200 			}
1201 
1202 			SWAP(points[1], points[2]);
1203 			for (int j = 0; j < 4; j++) {
1204 
1205 				bones[0] = parent;
1206 				surface_tool->add_bones(bones);
1207 				surface_tool->add_weights(weights);
1208 				surface_tool->add_color(bonecolor);
1209 				surface_tool->add_vertex(points[j]);
1210 				surface_tool->add_bones(bones);
1211 				surface_tool->add_weights(weights);
1212 				surface_tool->add_color(bonecolor);
1213 				surface_tool->add_vertex(points[(j + 1) % 4]);
1214 			}
1215 
1216 			/*
1217 			bones[0]=parent;
1218 			surface_tool->add_bones(bones);
1219 			surface_tool->add_weights(weights);
1220 			surface_tool->add_color(Color(0.4,1,0.4,0.4));
1221 			surface_tool->add_vertex(v0);
1222 			bones[0]=i;
1223 			surface_tool->add_bones(bones);
1224 			surface_tool->add_weights(weights);
1225 			surface_tool->add_color(Color(0.4,1,0.4,0.4));
1226 			surface_tool->add_vertex(v1);
1227 */
1228 		} else {
1229 
1230 			grests[i] = skel->get_bone_rest(i);
1231 			bones[0] = i;
1232 		}
1233 		/*
1234 		Transform  t = grests[i];
1235 		t.orthonormalize();
1236 
1237 		for (int i=0;i<6;i++) {
1238 
1239 
1240 			Vector3 face_points[4];
1241 
1242 			for (int j=0;j<4;j++) {
1243 
1244 				float v[3];
1245 				v[0]=1.0;
1246 				v[1]=1-2*((j>>1)&1);
1247 				v[2]=v[1]*(1-2*(j&1));
1248 
1249 				for (int k=0;k<3;k++) {
1250 
1251 					if (i<3)
1252 						face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
1253 					else
1254 						face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
1255 				}
1256 			}
1257 
1258 			for(int j=0;j<4;j++) {
1259 				surface_tool->add_bones(bones);
1260 				surface_tool->add_weights(weights);
1261 				surface_tool->add_color(Color(1.0,0.4,0.4,0.4));
1262 				surface_tool->add_vertex(t.xform(face_points[j]*0.04));
1263 				surface_tool->add_bones(bones);
1264 				surface_tool->add_weights(weights);
1265 				surface_tool->add_color(Color(1.0,0.4,0.4,0.4));
1266 				surface_tool->add_vertex(t.xform(face_points[(j+1)%4]*0.04));
1267 			}
1268 
1269 		}
1270 		*/
1271 	}
1272 
1273 	Ref<Mesh> m = surface_tool->commit();
1274 	add_mesh(m, false, skel->get_skeleton());
1275 }
1276 
SkeletonSpatialGizmo(Skeleton * p_skel)1277 SkeletonSpatialGizmo::SkeletonSpatialGizmo(Skeleton *p_skel) {
1278 
1279 	skel = p_skel;
1280 	set_spatial_node(p_skel);
1281 }
1282 
1283 /////
1284 
redraw()1285 void SpatialPlayerSpatialGizmo::redraw() {
1286 
1287 	clear();
1288 	if (splayer->cast_to<SpatialStreamPlayer>()) {
1289 
1290 		add_unscaled_billboard(SpatialEditorGizmos::singleton->stream_player_icon, 0.05);
1291 
1292 	} else if (splayer->cast_to<SpatialSamplePlayer>()) {
1293 
1294 		add_unscaled_billboard(SpatialEditorGizmos::singleton->sample_player_icon, 0.05);
1295 	}
1296 }
1297 
SpatialPlayerSpatialGizmo(SpatialPlayer * p_splayer)1298 SpatialPlayerSpatialGizmo::SpatialPlayerSpatialGizmo(SpatialPlayer *p_splayer) {
1299 
1300 	set_spatial_node(p_splayer);
1301 	splayer = p_splayer;
1302 }
1303 
1304 /////
1305 
redraw()1306 void RoomSpatialGizmo::redraw() {
1307 
1308 	clear();
1309 	Ref<RoomBounds> roomie = room->get_room();
1310 	if (roomie.is_null())
1311 		return;
1312 	DVector<Face3> faces = roomie->get_geometry_hint();
1313 
1314 	Vector<Vector3> lines;
1315 	int fc = faces.size();
1316 	DVector<Face3>::Read r = faces.read();
1317 
1318 	Map<_EdgeKey, Vector3> edge_map;
1319 
1320 	for (int i = 0; i < fc; i++) {
1321 
1322 		Vector3 fn = r[i].get_plane().normal;
1323 
1324 		for (int j = 0; j < 3; j++) {
1325 
1326 			_EdgeKey ek;
1327 			ek.from = r[i].vertex[j].snapped(CMP_EPSILON);
1328 			ek.to = r[i].vertex[(j + 1) % 3].snapped(CMP_EPSILON);
1329 			if (ek.from < ek.to)
1330 				SWAP(ek.from, ek.to);
1331 
1332 			Map<_EdgeKey, Vector3>::Element *E = edge_map.find(ek);
1333 
1334 			if (E) {
1335 
1336 				if (E->get().dot(fn) > 0.9) {
1337 
1338 					E->get() = Vector3();
1339 				}
1340 
1341 			} else {
1342 
1343 				edge_map[ek] = fn;
1344 			}
1345 		}
1346 	}
1347 
1348 	for (Map<_EdgeKey, Vector3>::Element *E = edge_map.front(); E; E = E->next()) {
1349 
1350 		if (E->get() != Vector3()) {
1351 			lines.push_back(E->key().from);
1352 			lines.push_back(E->key().to);
1353 		}
1354 	}
1355 
1356 	add_lines(lines, SpatialEditorGizmos::singleton->room_material);
1357 	add_collision_segments(lines);
1358 }
1359 
RoomSpatialGizmo(Room * p_room)1360 RoomSpatialGizmo::RoomSpatialGizmo(Room *p_room) {
1361 
1362 	set_spatial_node(p_room);
1363 	room = p_room;
1364 }
1365 
1366 /////
1367 
redraw()1368 void PortalSpatialGizmo::redraw() {
1369 
1370 	clear();
1371 
1372 	Vector<Point2> points = portal->get_shape();
1373 	if (points.size() == 0) {
1374 		return;
1375 	}
1376 
1377 	Vector<Vector3> lines;
1378 
1379 	Vector3 center;
1380 	for (int i = 0; i < points.size(); i++) {
1381 
1382 		Vector3 f;
1383 		f.x = points[i].x;
1384 		f.y = points[i].y;
1385 		Vector3 fn;
1386 		fn.x = points[(i + 1) % points.size()].x;
1387 		fn.y = points[(i + 1) % points.size()].y;
1388 		center += f;
1389 
1390 		lines.push_back(f);
1391 		lines.push_back(fn);
1392 	}
1393 
1394 	center /= points.size();
1395 	lines.push_back(center);
1396 	lines.push_back(center + Vector3(0, 0, 1));
1397 
1398 	add_lines(lines, SpatialEditorGizmos::singleton->portal_material);
1399 	add_collision_segments(lines);
1400 }
1401 
PortalSpatialGizmo(Portal * p_portal)1402 PortalSpatialGizmo::PortalSpatialGizmo(Portal *p_portal) {
1403 
1404 	set_spatial_node(p_portal);
1405 	portal = p_portal;
1406 }
1407 
1408 /////
1409 
redraw()1410 void RayCastSpatialGizmo::redraw() {
1411 
1412 	clear();
1413 
1414 	Vector<Vector3> lines;
1415 
1416 	lines.push_back(Vector3());
1417 	lines.push_back(raycast->get_cast_to());
1418 
1419 	add_lines(lines, SpatialEditorGizmos::singleton->raycast_material);
1420 	add_collision_segments(lines);
1421 }
1422 
RayCastSpatialGizmo(RayCast * p_raycast)1423 RayCastSpatialGizmo::RayCastSpatialGizmo(RayCast *p_raycast) {
1424 
1425 	set_spatial_node(p_raycast);
1426 	raycast = p_raycast;
1427 }
1428 
1429 /////
1430 
redraw()1431 void VehicleWheelSpatialGizmo::redraw() {
1432 
1433 	clear();
1434 
1435 	Vector<Vector3> points;
1436 
1437 	float r = car_wheel->get_radius();
1438 	const int skip = 10;
1439 	for (int i = 0; i <= 360; i += skip) {
1440 
1441 		float ra = Math::deg2rad(i);
1442 		float rb = Math::deg2rad(i + skip);
1443 		Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
1444 		Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
1445 
1446 		points.push_back(Vector3(0, a.x, a.y));
1447 		points.push_back(Vector3(0, b.x, b.y));
1448 
1449 		const int springsec = 4;
1450 
1451 		for (int j = 0; j < springsec; j++) {
1452 			float t = car_wheel->get_suspension_rest_length() * 5;
1453 			points.push_back(Vector3(a.x, i / 360.0 * t / springsec + j * (t / springsec), a.y) * 0.2);
1454 			points.push_back(Vector3(b.x, (i + skip) / 360.0 * t / springsec + j * (t / springsec), b.y) * 0.2);
1455 		}
1456 	}
1457 
1458 	//travel
1459 	points.push_back(Vector3(0, 0, 0));
1460 	points.push_back(Vector3(0, car_wheel->get_suspension_rest_length(), 0));
1461 
1462 	//axis
1463 	points.push_back(Vector3(r * 0.2, car_wheel->get_suspension_rest_length(), 0));
1464 	points.push_back(Vector3(-r * 0.2, car_wheel->get_suspension_rest_length(), 0));
1465 	//axis
1466 	points.push_back(Vector3(r * 0.2, 0, 0));
1467 	points.push_back(Vector3(-r * 0.2, 0, 0));
1468 
1469 	//forward line
1470 	points.push_back(Vector3(0, -r, 0));
1471 	points.push_back(Vector3(0, -r, r * 2));
1472 	points.push_back(Vector3(0, -r, r * 2));
1473 	points.push_back(Vector3(r * 2 * 0.2, -r, r * 2 * 0.8));
1474 	points.push_back(Vector3(0, -r, r * 2));
1475 	points.push_back(Vector3(-r * 2 * 0.2, -r, r * 2 * 0.8));
1476 
1477 	add_lines(points, SpatialEditorGizmos::singleton->car_wheel_material);
1478 	add_collision_segments(points);
1479 }
1480 
VehicleWheelSpatialGizmo(VehicleWheel * p_car_wheel)1481 VehicleWheelSpatialGizmo::VehicleWheelSpatialGizmo(VehicleWheel *p_car_wheel) {
1482 
1483 	set_spatial_node(p_car_wheel);
1484 	car_wheel = p_car_wheel;
1485 }
1486 
1487 ///
1488 
redraw()1489 void TestCubeSpatialGizmo::redraw() {
1490 
1491 	clear();
1492 	add_collision_triangles(SpatialEditorGizmos::singleton->test_cube_tm);
1493 }
1494 
TestCubeSpatialGizmo(TestCube * p_tc)1495 TestCubeSpatialGizmo::TestCubeSpatialGizmo(TestCube *p_tc) {
1496 
1497 	tc = p_tc;
1498 	set_spatial_node(p_tc);
1499 }
1500 
1501 ///////////
1502 
get_handle_name(int p_idx) const1503 String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const {
1504 
1505 	Ref<Shape> s = cs->get_shape();
1506 	if (s.is_null())
1507 		return "";
1508 
1509 	if (s->cast_to<SphereShape>()) {
1510 
1511 		return "Radius";
1512 	}
1513 
1514 	if (s->cast_to<BoxShape>()) {
1515 
1516 		return "Extents";
1517 	}
1518 
1519 	if (s->cast_to<CapsuleShape>()) {
1520 
1521 		return p_idx == 0 ? "Radius" : "Height";
1522 	}
1523 
1524 	if (s->cast_to<RayShape>()) {
1525 
1526 		return "Length";
1527 	}
1528 
1529 	return "";
1530 }
get_handle_value(int p_idx) const1531 Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const {
1532 
1533 	Ref<Shape> s = cs->get_shape();
1534 	if (s.is_null())
1535 		return Variant();
1536 
1537 	if (s->cast_to<SphereShape>()) {
1538 
1539 		Ref<SphereShape> ss = s;
1540 		return ss->get_radius();
1541 	}
1542 
1543 	if (s->cast_to<BoxShape>()) {
1544 
1545 		Ref<BoxShape> bs = s;
1546 		return bs->get_extents();
1547 	}
1548 
1549 	if (s->cast_to<CapsuleShape>()) {
1550 
1551 		Ref<CapsuleShape> cs = s;
1552 		return p_idx == 0 ? cs->get_radius() : cs->get_height();
1553 	}
1554 
1555 	if (s->cast_to<RayShape>()) {
1556 
1557 		Ref<RayShape> cs = s;
1558 		return cs->get_length();
1559 	}
1560 
1561 	return Variant();
1562 }
set_handle(int p_idx,Camera * p_camera,const Point2 & p_point)1563 void CollisionShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
1564 	Ref<Shape> s = cs->get_shape();
1565 	if (s.is_null())
1566 		return;
1567 
1568 	Transform gt = cs->get_global_transform();
1569 	gt.orthonormalize();
1570 	Transform gi = gt.affine_inverse();
1571 
1572 	Vector3 ray_from = p_camera->project_ray_origin(p_point);
1573 	Vector3 ray_dir = p_camera->project_ray_normal(p_point);
1574 
1575 	Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
1576 
1577 	if (s->cast_to<SphereShape>()) {
1578 
1579 		Ref<SphereShape> ss = s;
1580 		Vector3 ra, rb;
1581 		Geometry::get_closest_points_between_segments(Vector3(), Vector3(4096, 0, 0), sg[0], sg[1], ra, rb);
1582 		float d = ra.x;
1583 		if (d < 0.001)
1584 			d = 0.001;
1585 
1586 		ss->set_radius(d);
1587 	}
1588 
1589 	if (s->cast_to<RayShape>()) {
1590 
1591 		Ref<RayShape> rs = s;
1592 		Vector3 ra, rb;
1593 		Geometry::get_closest_points_between_segments(Vector3(), Vector3(0, 0, 4096), sg[0], sg[1], ra, rb);
1594 		float d = ra.z;
1595 		if (d < 0.001)
1596 			d = 0.001;
1597 
1598 		rs->set_length(d);
1599 	}
1600 
1601 	if (s->cast_to<BoxShape>()) {
1602 
1603 		Vector3 axis;
1604 		axis[p_idx] = 1.0;
1605 		Ref<BoxShape> bs = s;
1606 		Vector3 ra, rb;
1607 		Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
1608 		float d = ra[p_idx];
1609 		if (d < 0.001)
1610 			d = 0.001;
1611 
1612 		Vector3 he = bs->get_extents();
1613 		he[p_idx] = d;
1614 		bs->set_extents(he);
1615 	}
1616 
1617 	if (s->cast_to<CapsuleShape>()) {
1618 
1619 		Vector3 axis;
1620 		axis[p_idx == 0 ? 0 : 2] = 1.0;
1621 		Ref<CapsuleShape> cs = s;
1622 		Vector3 ra, rb;
1623 		Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
1624 		float d = axis.dot(ra);
1625 		if (p_idx == 1)
1626 			d -= cs->get_radius();
1627 		if (d < 0.001)
1628 			d = 0.001;
1629 
1630 		if (p_idx == 0)
1631 			cs->set_radius(d);
1632 		else if (p_idx == 1)
1633 			cs->set_height(d * 2.0);
1634 	}
1635 }
commit_handle(int p_idx,const Variant & p_restore,bool p_cancel)1636 void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
1637 	Ref<Shape> s = cs->get_shape();
1638 	if (s.is_null())
1639 		return;
1640 
1641 	if (s->cast_to<SphereShape>()) {
1642 
1643 		Ref<SphereShape> ss = s;
1644 		if (p_cancel) {
1645 			ss->set_radius(p_restore);
1646 			return;
1647 		}
1648 
1649 		UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
1650 		ur->create_action(TTR("Change Sphere Shape Radius"));
1651 		ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
1652 		ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
1653 		ur->commit_action();
1654 	}
1655 
1656 	if (s->cast_to<BoxShape>()) {
1657 
1658 		Ref<BoxShape> ss = s;
1659 		if (p_cancel) {
1660 			ss->set_extents(p_restore);
1661 			return;
1662 		}
1663 
1664 		UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
1665 		ur->create_action(TTR("Change Box Shape Extents"));
1666 		ur->add_do_method(ss.ptr(), "set_extents", ss->get_extents());
1667 		ur->add_undo_method(ss.ptr(), "set_extents", p_restore);
1668 		ur->commit_action();
1669 	}
1670 
1671 	if (s->cast_to<CapsuleShape>()) {
1672 
1673 		Ref<CapsuleShape> ss = s;
1674 		if (p_cancel) {
1675 			if (p_idx == 0)
1676 				ss->set_radius(p_restore);
1677 			else
1678 				ss->set_height(p_restore);
1679 			return;
1680 		}
1681 
1682 		UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
1683 		if (p_idx == 0) {
1684 			ur->create_action(TTR("Change Capsule Shape Radius"));
1685 			ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
1686 			ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
1687 		} else {
1688 			ur->create_action(TTR("Change Capsule Shape Height"));
1689 			ur->add_do_method(ss.ptr(), "set_height", ss->get_height());
1690 			ur->add_undo_method(ss.ptr(), "set_height", p_restore);
1691 		}
1692 
1693 		ur->commit_action();
1694 	}
1695 
1696 	if (s->cast_to<RayShape>()) {
1697 
1698 		Ref<RayShape> ss = s;
1699 		if (p_cancel) {
1700 			ss->set_length(p_restore);
1701 			return;
1702 		}
1703 
1704 		UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
1705 		ur->create_action(TTR("Change Ray Shape Length"));
1706 		ur->add_do_method(ss.ptr(), "set_length", ss->get_length());
1707 		ur->add_undo_method(ss.ptr(), "set_length", p_restore);
1708 		ur->commit_action();
1709 	}
1710 }
redraw()1711 void CollisionShapeSpatialGizmo::redraw() {
1712 
1713 	clear();
1714 
1715 	Ref<Shape> s = cs->get_shape();
1716 	if (s.is_null())
1717 		return;
1718 
1719 	if (s->cast_to<SphereShape>()) {
1720 
1721 		Ref<SphereShape> sp = s;
1722 		float r = sp->get_radius();
1723 
1724 		Vector<Vector3> points;
1725 
1726 		for (int i = 0; i <= 360; i++) {
1727 
1728 			float ra = Math::deg2rad(i);
1729 			float rb = Math::deg2rad(i + 1);
1730 			Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
1731 			Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
1732 
1733 			points.push_back(Vector3(a.x, 0, a.y));
1734 			points.push_back(Vector3(b.x, 0, b.y));
1735 			points.push_back(Vector3(0, a.x, a.y));
1736 			points.push_back(Vector3(0, b.x, b.y));
1737 			points.push_back(Vector3(a.x, a.y, 0));
1738 			points.push_back(Vector3(b.x, b.y, 0));
1739 		}
1740 
1741 		Vector<Vector3> collision_segments;
1742 
1743 		for (int i = 0; i < 64; i++) {
1744 
1745 			float ra = i * Math_PI * 2.0 / 64.0;
1746 			float rb = (i + 1) * Math_PI * 2.0 / 64.0;
1747 			Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
1748 			Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
1749 
1750 			collision_segments.push_back(Vector3(a.x, 0, a.y));
1751 			collision_segments.push_back(Vector3(b.x, 0, b.y));
1752 			collision_segments.push_back(Vector3(0, a.x, a.y));
1753 			collision_segments.push_back(Vector3(0, b.x, b.y));
1754 			collision_segments.push_back(Vector3(a.x, a.y, 0));
1755 			collision_segments.push_back(Vector3(b.x, b.y, 0));
1756 		}
1757 
1758 		add_lines(points, SpatialEditorGizmos::singleton->shape_material);
1759 		add_collision_segments(collision_segments);
1760 		Vector<Vector3> handles;
1761 		handles.push_back(Vector3(r, 0, 0));
1762 		add_handles(handles);
1763 	}
1764 
1765 	if (s->cast_to<BoxShape>()) {
1766 
1767 		Ref<BoxShape> bs = s;
1768 		Vector<Vector3> lines;
1769 		AABB aabb;
1770 		aabb.pos = -bs->get_extents();
1771 		aabb.size = aabb.pos * -2;
1772 
1773 		for (int i = 0; i < 12; i++) {
1774 			Vector3 a, b;
1775 			aabb.get_edge(i, a, b);
1776 			lines.push_back(a);
1777 			lines.push_back(b);
1778 		}
1779 
1780 		Vector<Vector3> handles;
1781 
1782 		for (int i = 0; i < 3; i++) {
1783 
1784 			Vector3 ax;
1785 			ax[i] = bs->get_extents()[i];
1786 			handles.push_back(ax);
1787 		}
1788 
1789 		add_lines(lines, SpatialEditorGizmos::singleton->shape_material);
1790 		add_collision_segments(lines);
1791 		add_handles(handles);
1792 	}
1793 
1794 	if (s->cast_to<CapsuleShape>()) {
1795 
1796 		Ref<CapsuleShape> cs = s;
1797 		float radius = cs->get_radius();
1798 		float height = cs->get_height();
1799 
1800 		Vector<Vector3> points;
1801 
1802 		Vector3 d(0, 0, height * 0.5);
1803 		for (int i = 0; i < 360; i++) {
1804 
1805 			float ra = Math::deg2rad(i);
1806 			float rb = Math::deg2rad(i + 1);
1807 			Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
1808 			Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
1809 
1810 			points.push_back(Vector3(a.x, a.y, 0) + d);
1811 			points.push_back(Vector3(b.x, b.y, 0) + d);
1812 
1813 			points.push_back(Vector3(a.x, a.y, 0) - d);
1814 			points.push_back(Vector3(b.x, b.y, 0) - d);
1815 
1816 			if (i % 90 == 0) {
1817 
1818 				points.push_back(Vector3(a.x, a.y, 0) + d);
1819 				points.push_back(Vector3(a.x, a.y, 0) - d);
1820 			}
1821 
1822 			Vector3 dud = i < 180 ? d : -d;
1823 
1824 			points.push_back(Vector3(0, a.y, a.x) + dud);
1825 			points.push_back(Vector3(0, b.y, b.x) + dud);
1826 			points.push_back(Vector3(a.y, 0, a.x) + dud);
1827 			points.push_back(Vector3(b.y, 0, b.x) + dud);
1828 		}
1829 
1830 		add_lines(points, SpatialEditorGizmos::singleton->shape_material);
1831 
1832 		Vector<Vector3> collision_segments;
1833 
1834 		for (int i = 0; i < 64; i++) {
1835 
1836 			float ra = i * Math_PI * 2.0 / 64.0;
1837 			float rb = (i + 1) * Math_PI * 2.0 / 64.0;
1838 			Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
1839 			Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
1840 
1841 			collision_segments.push_back(Vector3(a.x, a.y, 0) + d);
1842 			collision_segments.push_back(Vector3(b.x, b.y, 0) + d);
1843 
1844 			collision_segments.push_back(Vector3(a.x, a.y, 0) - d);
1845 			collision_segments.push_back(Vector3(b.x, b.y, 0) - d);
1846 
1847 			if (i % 16 == 0) {
1848 
1849 				collision_segments.push_back(Vector3(a.x, a.y, 0) + d);
1850 				collision_segments.push_back(Vector3(a.x, a.y, 0) - d);
1851 			}
1852 
1853 			Vector3 dud = i < 32 ? d : -d;
1854 
1855 			collision_segments.push_back(Vector3(0, a.y, a.x) + dud);
1856 			collision_segments.push_back(Vector3(0, b.y, b.x) + dud);
1857 			collision_segments.push_back(Vector3(a.y, 0, a.x) + dud);
1858 			collision_segments.push_back(Vector3(b.y, 0, b.x) + dud);
1859 		}
1860 
1861 		add_collision_segments(collision_segments);
1862 
1863 		Vector<Vector3> handles;
1864 		handles.push_back(Vector3(cs->get_radius(), 0, 0));
1865 		handles.push_back(Vector3(0, 0, cs->get_height() * 0.5 + cs->get_radius()));
1866 		add_handles(handles);
1867 	}
1868 
1869 	if (s->cast_to<PlaneShape>()) {
1870 
1871 		Ref<PlaneShape> ps = s;
1872 		Plane p = ps->get_plane();
1873 		Vector<Vector3> points;
1874 
1875 		Vector3 n1 = p.get_any_perpendicular_normal();
1876 		Vector3 n2 = p.normal.cross(n1).normalized();
1877 
1878 		Vector3 pface[4] = {
1879 			p.normal * p.d + n1 * 10.0 + n2 * 10.0,
1880 			p.normal * p.d + n1 * 10.0 + n2 * -10.0,
1881 			p.normal * p.d + n1 * -10.0 + n2 * -10.0,
1882 			p.normal * p.d + n1 * -10.0 + n2 * 10.0,
1883 		};
1884 
1885 		points.push_back(pface[0]);
1886 		points.push_back(pface[1]);
1887 		points.push_back(pface[1]);
1888 		points.push_back(pface[2]);
1889 		points.push_back(pface[2]);
1890 		points.push_back(pface[3]);
1891 		points.push_back(pface[3]);
1892 		points.push_back(pface[0]);
1893 		points.push_back(p.normal * p.d);
1894 		points.push_back(p.normal * p.d + p.normal * 3);
1895 
1896 		add_lines(points, SpatialEditorGizmos::singleton->shape_material);
1897 		add_collision_segments(points);
1898 	}
1899 
1900 	if (s->cast_to<ConvexPolygonShape>()) {
1901 
1902 		DVector<Vector3> points = s->cast_to<ConvexPolygonShape>()->get_points();
1903 
1904 		if (points.size() > 3) {
1905 
1906 			QuickHull qh;
1907 			Vector<Vector3> varr = Variant(points);
1908 			Geometry::MeshData md;
1909 			Error err = qh.build(varr, md);
1910 			if (err == OK) {
1911 				Vector<Vector3> points;
1912 				points.resize(md.edges.size() * 2);
1913 				for (int i = 0; i < md.edges.size(); i++) {
1914 					points[i * 2 + 0] = md.vertices[md.edges[i].a];
1915 					points[i * 2 + 1] = md.vertices[md.edges[i].b];
1916 				}
1917 
1918 				add_lines(points, SpatialEditorGizmos::singleton->shape_material);
1919 				add_collision_segments(points);
1920 			}
1921 		}
1922 	}
1923 
1924 	if (s->cast_to<RayShape>()) {
1925 
1926 		Ref<RayShape> rs = s;
1927 
1928 		Vector<Vector3> points;
1929 		points.push_back(Vector3());
1930 		points.push_back(Vector3(0, 0, rs->get_length()));
1931 		add_lines(points, SpatialEditorGizmos::singleton->shape_material);
1932 		add_collision_segments(points);
1933 		Vector<Vector3> handles;
1934 		handles.push_back(Vector3(0, 0, rs->get_length()));
1935 		add_handles(handles);
1936 	}
1937 }
CollisionShapeSpatialGizmo(CollisionShape * p_cs)1938 CollisionShapeSpatialGizmo::CollisionShapeSpatialGizmo(CollisionShape *p_cs) {
1939 
1940 	cs = p_cs;
1941 	set_spatial_node(p_cs);
1942 }
1943 
1944 /////
1945 
redraw()1946 void CollisionPolygonSpatialGizmo::redraw() {
1947 
1948 	clear();
1949 
1950 	Vector<Vector2> points = polygon->get_polygon();
1951 	float depth = polygon->get_depth() * 0.5;
1952 
1953 	Vector<Vector3> lines;
1954 	for (int i = 0; i < points.size(); i++) {
1955 
1956 		int n = (i + 1) % points.size();
1957 		lines.push_back(Vector3(points[i].x, points[i].y, depth));
1958 		lines.push_back(Vector3(points[n].x, points[n].y, depth));
1959 		lines.push_back(Vector3(points[i].x, points[i].y, -depth));
1960 		lines.push_back(Vector3(points[n].x, points[n].y, -depth));
1961 		lines.push_back(Vector3(points[i].x, points[i].y, depth));
1962 		lines.push_back(Vector3(points[i].x, points[i].y, -depth));
1963 	}
1964 
1965 	add_lines(lines, SpatialEditorGizmos::singleton->shape_material);
1966 	add_collision_segments(lines);
1967 }
1968 
CollisionPolygonSpatialGizmo(CollisionPolygon * p_polygon)1969 CollisionPolygonSpatialGizmo::CollisionPolygonSpatialGizmo(CollisionPolygon *p_polygon) {
1970 
1971 	set_spatial_node(p_polygon);
1972 	polygon = p_polygon;
1973 }
1974 ///
1975 
get_handle_name(int p_idx) const1976 String VisibilityNotifierGizmo::get_handle_name(int p_idx) const {
1977 
1978 	switch (p_idx) {
1979 		case 0: return "X";
1980 		case 1: return "Y";
1981 		case 2: return "Z";
1982 	}
1983 
1984 	return "";
1985 }
get_handle_value(int p_idx) const1986 Variant VisibilityNotifierGizmo::get_handle_value(int p_idx) const {
1987 
1988 	return notifier->get_aabb();
1989 }
set_handle(int p_idx,Camera * p_camera,const Point2 & p_point)1990 void VisibilityNotifierGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
1991 
1992 	Transform gt = notifier->get_global_transform();
1993 	//gt.orthonormalize();
1994 	Transform gi = gt.affine_inverse();
1995 
1996 	AABB aabb = notifier->get_aabb();
1997 	Vector3 ray_from = p_camera->project_ray_origin(p_point);
1998 	Vector3 ray_dir = p_camera->project_ray_normal(p_point);
1999 
2000 	Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
2001 	Vector3 ofs = aabb.pos + aabb.size * 0.5;
2002 
2003 	Vector3 axis;
2004 	axis[p_idx] = 1.0;
2005 
2006 	Vector3 ra, rb;
2007 	Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb);
2008 	float d = ra[p_idx];
2009 	if (d < 0.001)
2010 		d = 0.001;
2011 
2012 	aabb.pos[p_idx] = (aabb.pos[p_idx] + aabb.size[p_idx] * 0.5) - d;
2013 	aabb.size[p_idx] = d * 2;
2014 	notifier->set_aabb(aabb);
2015 }
2016 
commit_handle(int p_idx,const Variant & p_restore,bool p_cancel)2017 void VisibilityNotifierGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
2018 
2019 	if (p_cancel) {
2020 		notifier->set_aabb(p_restore);
2021 		return;
2022 	}
2023 
2024 	UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
2025 	ur->create_action(TTR("Change Notifier Extents"));
2026 	ur->add_do_method(notifier, "set_aabb", notifier->get_aabb());
2027 	ur->add_undo_method(notifier, "set_aabb", p_restore);
2028 	ur->commit_action();
2029 }
2030 
redraw()2031 void VisibilityNotifierGizmo::redraw() {
2032 
2033 	clear();
2034 
2035 	Vector<Vector3> lines;
2036 	AABB aabb = notifier->get_aabb();
2037 
2038 	for (int i = 0; i < 12; i++) {
2039 		Vector3 a, b;
2040 		aabb.get_edge(i, a, b);
2041 		lines.push_back(a);
2042 		lines.push_back(b);
2043 	}
2044 
2045 	Vector<Vector3> handles;
2046 
2047 	for (int i = 0; i < 3; i++) {
2048 
2049 		Vector3 ax;
2050 		ax[i] = aabb.pos[i] + aabb.size[i];
2051 		handles.push_back(ax);
2052 	}
2053 
2054 	add_lines(lines, SpatialEditorGizmos::singleton->visibility_notifier_material);
2055 	//add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05);
2056 	add_collision_segments(lines);
2057 	add_handles(handles);
2058 }
VisibilityNotifierGizmo(VisibilityNotifier * p_notifier)2059 VisibilityNotifierGizmo::VisibilityNotifierGizmo(VisibilityNotifier *p_notifier) {
2060 
2061 	notifier = p_notifier;
2062 	set_spatial_node(p_notifier);
2063 }
2064 
2065 ////////
2066 
redraw()2067 void NavigationMeshSpatialGizmo::redraw() {
2068 
2069 	clear();
2070 	Ref<NavigationMesh> navmeshie = navmesh->get_navigation_mesh();
2071 	if (navmeshie.is_null())
2072 		return;
2073 
2074 	DVector<Vector3> vertices = navmeshie->get_vertices();
2075 	DVector<Vector3>::Read vr = vertices.read();
2076 	List<Face3> faces;
2077 	for (int i = 0; i < navmeshie->get_polygon_count(); i++) {
2078 		Vector<int> p = navmeshie->get_polygon(i);
2079 
2080 		for (int j = 2; j < p.size(); j++) {
2081 			Face3 f;
2082 			f.vertex[0] = vr[p[0]];
2083 			f.vertex[1] = vr[p[j - 1]];
2084 			f.vertex[2] = vr[p[j]];
2085 
2086 			faces.push_back(f);
2087 		}
2088 	}
2089 
2090 	if (faces.empty())
2091 		return;
2092 
2093 	Map<_EdgeKey, bool> edge_map;
2094 	DVector<Vector3> tmeshfaces;
2095 	tmeshfaces.resize(faces.size() * 3);
2096 
2097 	{
2098 		DVector<Vector3>::Write tw = tmeshfaces.write();
2099 		int tidx = 0;
2100 
2101 		for (List<Face3>::Element *E = faces.front(); E; E = E->next()) {
2102 
2103 			const Face3 &f = E->get();
2104 
2105 			for (int j = 0; j < 3; j++) {
2106 
2107 				tw[tidx++] = f.vertex[j];
2108 				_EdgeKey ek;
2109 				ek.from = f.vertex[j].snapped(CMP_EPSILON);
2110 				ek.to = f.vertex[(j + 1) % 3].snapped(CMP_EPSILON);
2111 				if (ek.from < ek.to)
2112 					SWAP(ek.from, ek.to);
2113 
2114 				Map<_EdgeKey, bool>::Element *E = edge_map.find(ek);
2115 
2116 				if (E) {
2117 
2118 					E->get() = false;
2119 
2120 				} else {
2121 
2122 					edge_map[ek] = true;
2123 				}
2124 			}
2125 		}
2126 	}
2127 	Vector<Vector3> lines;
2128 
2129 	for (Map<_EdgeKey, bool>::Element *E = edge_map.front(); E; E = E->next()) {
2130 
2131 		if (E->get()) {
2132 			lines.push_back(E->key().from);
2133 			lines.push_back(E->key().to);
2134 		}
2135 	}
2136 
2137 	Ref<TriangleMesh> tmesh = memnew(TriangleMesh);
2138 	tmesh->create(tmeshfaces);
2139 
2140 	if (lines.size())
2141 		add_lines(lines, navmesh->is_enabled() ? SpatialEditorGizmos::singleton->navmesh_edge_material : SpatialEditorGizmos::singleton->navmesh_edge_material_disabled);
2142 	add_collision_triangles(tmesh);
2143 	Ref<Mesh> m = memnew(Mesh);
2144 	Array a;
2145 	a.resize(Mesh::ARRAY_MAX);
2146 	a[0] = tmeshfaces;
2147 	m->add_surface(Mesh::PRIMITIVE_TRIANGLES, a);
2148 	m->surface_set_material(0, navmesh->is_enabled() ? SpatialEditorGizmos::singleton->navmesh_solid_material : SpatialEditorGizmos::singleton->navmesh_solid_material_disabled);
2149 	add_mesh(m);
2150 	add_collision_segments(lines);
2151 }
2152 
NavigationMeshSpatialGizmo(NavigationMeshInstance * p_navmesh)2153 NavigationMeshSpatialGizmo::NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh) {
2154 
2155 	set_spatial_node(p_navmesh);
2156 	navmesh = p_navmesh;
2157 }
2158 
2159 //////
2160 ///
2161 ///
2162 
redraw()2163 void PinJointSpatialGizmo::redraw() {
2164 
2165 	clear();
2166 	Vector<Vector3> cursor_points;
2167 	float cs = 0.25;
2168 	cursor_points.push_back(Vector3(+cs, 0, 0));
2169 	cursor_points.push_back(Vector3(-cs, 0, 0));
2170 	cursor_points.push_back(Vector3(0, +cs, 0));
2171 	cursor_points.push_back(Vector3(0, -cs, 0));
2172 	cursor_points.push_back(Vector3(0, 0, +cs));
2173 	cursor_points.push_back(Vector3(0, 0, -cs));
2174 	add_collision_segments(cursor_points);
2175 	add_lines(cursor_points, SpatialEditorGizmos::singleton->joint_material);
2176 }
2177 
PinJointSpatialGizmo(PinJoint * p_p3d)2178 PinJointSpatialGizmo::PinJointSpatialGizmo(PinJoint *p_p3d) {
2179 
2180 	p3d = p_p3d;
2181 	set_spatial_node(p3d);
2182 }
2183 
2184 ////
2185 
redraw()2186 void HingeJointSpatialGizmo::redraw() {
2187 
2188 	clear();
2189 	Vector<Vector3> cursor_points;
2190 	float cs = 0.25;
2191 	/*cursor_points.push_back(Vector3(+cs,0,0));
2192 	cursor_points.push_back(Vector3(-cs,0,0));
2193 	cursor_points.push_back(Vector3(0,+cs,0));
2194 	cursor_points.push_back(Vector3(0,-cs,0));*/
2195 	cursor_points.push_back(Vector3(0, 0, +cs * 2));
2196 	cursor_points.push_back(Vector3(0, 0, -cs * 2));
2197 
2198 	float ll = p3d->get_param(HingeJoint::PARAM_LIMIT_LOWER);
2199 	float ul = p3d->get_param(HingeJoint::PARAM_LIMIT_UPPER);
2200 
2201 	if (p3d->get_flag(HingeJoint::FLAG_USE_LIMIT) && ll < ul) {
2202 
2203 		const int points = 32;
2204 
2205 		for (int i = 0; i < points; i++) {
2206 
2207 			float s = ll + i * (ul - ll) / points;
2208 			float n = ll + (i + 1) * (ul - ll) / points;
2209 
2210 			Vector3 from = Vector3(-Math::sin(s), Math::cos(s), 0) * cs;
2211 			Vector3 to = Vector3(-Math::sin(n), Math::cos(n), 0) * cs;
2212 
2213 			if (i == points - 1) {
2214 				cursor_points.push_back(to);
2215 				cursor_points.push_back(Vector3());
2216 			}
2217 			if (i == 0) {
2218 				cursor_points.push_back(from);
2219 				cursor_points.push_back(Vector3());
2220 			}
2221 
2222 			cursor_points.push_back(from);
2223 			cursor_points.push_back(to);
2224 		}
2225 
2226 		cursor_points.push_back(Vector3(0, cs * 1.5, 0));
2227 		cursor_points.push_back(Vector3());
2228 
2229 	} else {
2230 
2231 		const int points = 32;
2232 
2233 		for (int i = 0; i < points; i++) {
2234 
2235 			float s = ll + i * (Math_PI * 2.0) / points;
2236 			float n = ll + (i + 1) * (Math_PI * 2.0) / points;
2237 
2238 			Vector3 from = Vector3(-Math::sin(s), Math::cos(s), 0) * cs;
2239 			Vector3 to = Vector3(-Math::sin(n), Math::cos(n), 0) * cs;
2240 
2241 			cursor_points.push_back(from);
2242 			cursor_points.push_back(to);
2243 		}
2244 	}
2245 	add_collision_segments(cursor_points);
2246 	add_lines(cursor_points, SpatialEditorGizmos::singleton->joint_material);
2247 }
2248 
HingeJointSpatialGizmo(HingeJoint * p_p3d)2249 HingeJointSpatialGizmo::HingeJointSpatialGizmo(HingeJoint *p_p3d) {
2250 
2251 	p3d = p_p3d;
2252 	set_spatial_node(p3d);
2253 }
2254 
2255 ///////
2256 ///
2257 ////
2258 
redraw()2259 void SliderJointSpatialGizmo::redraw() {
2260 
2261 	clear();
2262 	Vector<Vector3> cursor_points;
2263 	float cs = 0.25;
2264 	/*cursor_points.push_back(Vector3(+cs,0,0));
2265 	cursor_points.push_back(Vector3(-cs,0,0));
2266 	cursor_points.push_back(Vector3(0,+cs,0));
2267 	cursor_points.push_back(Vector3(0,-cs,0));*/
2268 	cursor_points.push_back(Vector3(0, 0, +cs * 2));
2269 	cursor_points.push_back(Vector3(0, 0, -cs * 2));
2270 
2271 	float ll = p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER);
2272 	float ul = p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER);
2273 	float lll = -p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER);
2274 	float lul = -p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER);
2275 
2276 	if (lll > lul) {
2277 
2278 		cursor_points.push_back(Vector3(lul, 0, 0));
2279 		cursor_points.push_back(Vector3(lll, 0, 0));
2280 
2281 		cursor_points.push_back(Vector3(lul, -cs, -cs));
2282 		cursor_points.push_back(Vector3(lul, -cs, cs));
2283 		cursor_points.push_back(Vector3(lul, -cs, cs));
2284 		cursor_points.push_back(Vector3(lul, cs, cs));
2285 		cursor_points.push_back(Vector3(lul, cs, cs));
2286 		cursor_points.push_back(Vector3(lul, cs, -cs));
2287 		cursor_points.push_back(Vector3(lul, cs, -cs));
2288 		cursor_points.push_back(Vector3(lul, -cs, -cs));
2289 
2290 		cursor_points.push_back(Vector3(lll, -cs, -cs));
2291 		cursor_points.push_back(Vector3(lll, -cs, cs));
2292 		cursor_points.push_back(Vector3(lll, -cs, cs));
2293 		cursor_points.push_back(Vector3(lll, cs, cs));
2294 		cursor_points.push_back(Vector3(lll, cs, cs));
2295 		cursor_points.push_back(Vector3(lll, cs, -cs));
2296 		cursor_points.push_back(Vector3(lll, cs, -cs));
2297 		cursor_points.push_back(Vector3(lll, -cs, -cs));
2298 
2299 	} else {
2300 
2301 		cursor_points.push_back(Vector3(+cs * 2, 0, 0));
2302 		cursor_points.push_back(Vector3(-cs * 2, 0, 0));
2303 	}
2304 
2305 	if (ll < ul) {
2306 
2307 		const int points = 32;
2308 
2309 		for (int i = 0; i < points; i++) {
2310 
2311 			float s = ll + i * (ul - ll) / points;
2312 			float n = ll + (i + 1) * (ul - ll) / points;
2313 
2314 			Vector3 from = Vector3(0, Math::cos(s), -Math::sin(s)) * cs;
2315 			Vector3 to = Vector3(0, Math::cos(n), -Math::sin(n)) * cs;
2316 
2317 			if (i == points - 1) {
2318 				cursor_points.push_back(to);
2319 				cursor_points.push_back(Vector3());
2320 			}
2321 			if (i == 0) {
2322 				cursor_points.push_back(from);
2323 				cursor_points.push_back(Vector3());
2324 			}
2325 
2326 			cursor_points.push_back(from);
2327 			cursor_points.push_back(to);
2328 		}
2329 
2330 		cursor_points.push_back(Vector3(0, cs * 1.5, 0));
2331 		cursor_points.push_back(Vector3());
2332 
2333 	} else {
2334 
2335 		const int points = 32;
2336 
2337 		for (int i = 0; i < points; i++) {
2338 
2339 			float s = ll + i * (Math_PI * 2.0) / points;
2340 			float n = ll + (i + 1) * (Math_PI * 2.0) / points;
2341 
2342 			Vector3 from = Vector3(0, Math::cos(s), -Math::sin(s)) * cs;
2343 			Vector3 to = Vector3(0, Math::cos(n), -Math::sin(n)) * cs;
2344 
2345 			cursor_points.push_back(from);
2346 			cursor_points.push_back(to);
2347 		}
2348 	}
2349 	add_collision_segments(cursor_points);
2350 	add_lines(cursor_points, SpatialEditorGizmos::singleton->joint_material);
2351 }
2352 
SliderJointSpatialGizmo(SliderJoint * p_p3d)2353 SliderJointSpatialGizmo::SliderJointSpatialGizmo(SliderJoint *p_p3d) {
2354 
2355 	p3d = p_p3d;
2356 	set_spatial_node(p3d);
2357 }
2358 
2359 ///////
2360 ///
2361 ////
2362 
redraw()2363 void ConeTwistJointSpatialGizmo::redraw() {
2364 
2365 	clear();
2366 	Vector<Vector3> points;
2367 
2368 	float r = 1.0;
2369 	float w = r * Math::sin(p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN));
2370 	float d = r * Math::cos(p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN));
2371 
2372 	//swing
2373 	for (int i = 0; i < 360; i += 10) {
2374 
2375 		float ra = Math::deg2rad(i);
2376 		float rb = Math::deg2rad(i + 10);
2377 		Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
2378 		Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
2379 
2380 		/*points.push_back(Vector3(a.x,0,a.y));
2381 		points.push_back(Vector3(b.x,0,b.y));
2382 		points.push_back(Vector3(0,a.x,a.y));
2383 		points.push_back(Vector3(0,b.x,b.y));*/
2384 		points.push_back(Vector3(d, a.x, a.y));
2385 		points.push_back(Vector3(d, b.x, b.y));
2386 
2387 		if (i % 90 == 0) {
2388 
2389 			points.push_back(Vector3(d, a.x, a.y));
2390 			points.push_back(Vector3());
2391 		}
2392 	}
2393 
2394 	points.push_back(Vector3());
2395 	points.push_back(Vector3(1, 0, 0));
2396 
2397 	//twist
2398 	/*
2399 	 */
2400 	float ts = Math::rad2deg(p3d->get_param(ConeTwistJoint::PARAM_TWIST_SPAN));
2401 	ts = MIN(ts, 720);
2402 
2403 	for (int i = 0; i < int(ts); i += 5) {
2404 
2405 		float ra = Math::deg2rad(i);
2406 		float rb = Math::deg2rad(i + 5);
2407 		float c = i / 720.0;
2408 		float cn = (i + 5) / 720.0;
2409 		Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w * c;
2410 		Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w * cn;
2411 
2412 		/*points.push_back(Vector3(a.x,0,a.y));
2413 		points.push_back(Vector3(b.x,0,b.y));
2414 		points.push_back(Vector3(0,a.x,a.y));
2415 		points.push_back(Vector3(0,b.x,b.y));*/
2416 
2417 		points.push_back(Vector3(c, a.x, a.y));
2418 		points.push_back(Vector3(cn, b.x, b.y));
2419 	}
2420 
2421 	add_collision_segments(points);
2422 	add_lines(points, SpatialEditorGizmos::singleton->joint_material);
2423 }
2424 
ConeTwistJointSpatialGizmo(ConeTwistJoint * p_p3d)2425 ConeTwistJointSpatialGizmo::ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d) {
2426 
2427 	p3d = p_p3d;
2428 	set_spatial_node(p3d);
2429 }
2430 
2431 ////////
2432 /// \brief SpatialEditorGizmos::singleton
2433 ///
2434 ///////
2435 ///
2436 ////
2437 
redraw()2438 void Generic6DOFJointSpatialGizmo::redraw() {
2439 
2440 	clear();
2441 	Vector<Vector3> cursor_points;
2442 	float cs = 0.25;
2443 
2444 	for (int ax = 0; ax < 3; ax++) {
2445 		/*cursor_points.push_back(Vector3(+cs,0,0));
2446 		cursor_points.push_back(Vector3(-cs,0,0));
2447 		cursor_points.push_back(Vector3(0,+cs,0));
2448 		cursor_points.push_back(Vector3(0,-cs,0));
2449 		cursor_points.push_back(Vector3(0,0,+cs*2));
2450 		cursor_points.push_back(Vector3(0,0,-cs*2)); */
2451 
2452 		float ll;
2453 		float ul;
2454 		float lll;
2455 		float lul;
2456 
2457 		int a1, a2, a3;
2458 		bool enable_ang;
2459 		bool enable_lin;
2460 
2461 		switch (ax) {
2462 			case 0:
2463 				ll = p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
2464 				ul = p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
2465 				lll = -p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
2466 				lul = -p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
2467 				enable_ang = p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
2468 				enable_lin = p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
2469 				a1 = 0;
2470 				a2 = 1;
2471 				a3 = 2;
2472 				break;
2473 			case 1:
2474 				ll = p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
2475 				ul = p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
2476 				lll = -p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
2477 				lul = -p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
2478 				enable_ang = p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
2479 				enable_lin = p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
2480 				a1 = 2;
2481 				a2 = 0;
2482 				a3 = 1;
2483 				break;
2484 			case 2:
2485 				ll = p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
2486 				ul = p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
2487 				lll = -p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
2488 				lul = -p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
2489 				enable_ang = p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
2490 				enable_lin = p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
2491 
2492 				a1 = 1;
2493 				a2 = 2;
2494 				a3 = 0;
2495 				break;
2496 		}
2497 
2498 #define ADD_VTX(x, y, z)            \
2499 	{                               \
2500 		Vector3 v;                  \
2501 		v[a1] = (x);                \
2502 		v[a2] = (y);                \
2503 		v[a3] = (z);                \
2504 		cursor_points.push_back(v); \
2505 	}
2506 
2507 #define SET_VTX(what, x, y, z) \
2508 	{                          \
2509 		Vector3 v;             \
2510 		v[a1] = (x);           \
2511 		v[a2] = (y);           \
2512 		v[a3] = (z);           \
2513 		what = v;              \
2514 	}
2515 
2516 		if (enable_lin && lll >= lul) {
2517 
2518 			ADD_VTX(lul, 0, 0);
2519 			ADD_VTX(lll, 0, 0);
2520 
2521 			ADD_VTX(lul, -cs, -cs);
2522 			ADD_VTX(lul, -cs, cs);
2523 			ADD_VTX(lul, -cs, cs);
2524 			ADD_VTX(lul, cs, cs);
2525 			ADD_VTX(lul, cs, cs);
2526 			ADD_VTX(lul, cs, -cs);
2527 			ADD_VTX(lul, cs, -cs);
2528 			ADD_VTX(lul, -cs, -cs);
2529 
2530 			ADD_VTX(lll, -cs, -cs);
2531 			ADD_VTX(lll, -cs, cs);
2532 			ADD_VTX(lll, -cs, cs);
2533 			ADD_VTX(lll, cs, cs);
2534 			ADD_VTX(lll, cs, cs);
2535 			ADD_VTX(lll, cs, -cs);
2536 			ADD_VTX(lll, cs, -cs);
2537 			ADD_VTX(lll, -cs, -cs);
2538 
2539 		} else {
2540 
2541 			ADD_VTX(+cs * 2, 0, 0);
2542 			ADD_VTX(-cs * 2, 0, 0);
2543 		}
2544 
2545 		if (enable_ang && ll <= ul) {
2546 
2547 			const int points = 32;
2548 
2549 			for (int i = 0; i < points; i++) {
2550 
2551 				float s = ll + i * (ul - ll) / points;
2552 				float n = ll + (i + 1) * (ul - ll) / points;
2553 
2554 				Vector3 from;
2555 				SET_VTX(from, 0, Math::cos(s), -Math::sin(s));
2556 				from *= cs;
2557 				Vector3 to;
2558 				SET_VTX(to, 0, Math::cos(n), -Math::sin(n));
2559 				to *= cs;
2560 
2561 				if (i == points - 1) {
2562 					cursor_points.push_back(to);
2563 					cursor_points.push_back(Vector3());
2564 				}
2565 				if (i == 0) {
2566 					cursor_points.push_back(from);
2567 					cursor_points.push_back(Vector3());
2568 				}
2569 
2570 				cursor_points.push_back(from);
2571 				cursor_points.push_back(to);
2572 			}
2573 
2574 			ADD_VTX(0, cs * 1.5, 0);
2575 			cursor_points.push_back(Vector3());
2576 
2577 		} else {
2578 
2579 			const int points = 32;
2580 
2581 			for (int i = 0; i < points; i++) {
2582 
2583 				float s = ll + i * (Math_PI * 2.0) / points;
2584 				float n = ll + (i + 1) * (Math_PI * 2.0) / points;
2585 
2586 				//				Vector3 from=Vector3(0,Math::cos(s),-Math::sin(s) )*cs;
2587 				//				Vector3 to=Vector3( 0,Math::cos(n),-Math::sin(n) )*cs;
2588 
2589 				Vector3 from;
2590 				SET_VTX(from, 0, Math::cos(s), -Math::sin(s));
2591 				from *= cs;
2592 				Vector3 to;
2593 				SET_VTX(to, 0, Math::cos(n), -Math::sin(n));
2594 				to *= cs;
2595 
2596 				cursor_points.push_back(from);
2597 				cursor_points.push_back(to);
2598 			}
2599 		}
2600 	}
2601 
2602 #undef ADD_VTX
2603 #undef SET_VTX
2604 
2605 	add_collision_segments(cursor_points);
2606 	add_lines(cursor_points, SpatialEditorGizmos::singleton->joint_material);
2607 }
2608 
Generic6DOFJointSpatialGizmo(Generic6DOFJoint * p_p3d)2609 Generic6DOFJointSpatialGizmo::Generic6DOFJointSpatialGizmo(Generic6DOFJoint *p_p3d) {
2610 
2611 	p3d = p_p3d;
2612 	set_spatial_node(p3d);
2613 }
2614 
2615 ///////
2616 ///
2617 ////
2618 
2619 SpatialEditorGizmos *SpatialEditorGizmos::singleton = NULL;
2620 
get_gizmo(Spatial * p_spatial)2621 Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) {
2622 
2623 	if (p_spatial->cast_to<Light>()) {
2624 
2625 		Ref<LightSpatialGizmo> lsg = memnew(LightSpatialGizmo(p_spatial->cast_to<Light>()));
2626 		return lsg;
2627 	}
2628 
2629 	if (p_spatial->cast_to<Listener>()) {
2630 
2631 		Ref<ListenerSpatialGizmo> misg = memnew(ListenerSpatialGizmo(p_spatial->cast_to<Listener>()));
2632 		return misg;
2633 	}
2634 
2635 	if (p_spatial->cast_to<Camera>()) {
2636 
2637 		Ref<CameraSpatialGizmo> lsg = memnew(CameraSpatialGizmo(p_spatial->cast_to<Camera>()));
2638 		return lsg;
2639 	}
2640 
2641 	if (p_spatial->cast_to<Skeleton>()) {
2642 
2643 		Ref<SkeletonSpatialGizmo> lsg = memnew(SkeletonSpatialGizmo(p_spatial->cast_to<Skeleton>()));
2644 		return lsg;
2645 	}
2646 
2647 	if (p_spatial->cast_to<Position3D>()) {
2648 
2649 		Ref<Position3DSpatialGizmo> lsg = memnew(Position3DSpatialGizmo(p_spatial->cast_to<Position3D>()));
2650 		return lsg;
2651 	}
2652 
2653 	if (p_spatial->cast_to<MeshInstance>()) {
2654 
2655 		Ref<MeshInstanceSpatialGizmo> misg = memnew(MeshInstanceSpatialGizmo(p_spatial->cast_to<MeshInstance>()));
2656 		return misg;
2657 	}
2658 
2659 	if (p_spatial->cast_to<Room>()) {
2660 
2661 		Ref<RoomSpatialGizmo> misg = memnew(RoomSpatialGizmo(p_spatial->cast_to<Room>()));
2662 		return misg;
2663 	}
2664 
2665 	if (p_spatial->cast_to<NavigationMeshInstance>()) {
2666 
2667 		Ref<NavigationMeshSpatialGizmo> misg = memnew(NavigationMeshSpatialGizmo(p_spatial->cast_to<NavigationMeshInstance>()));
2668 		return misg;
2669 	}
2670 
2671 	if (p_spatial->cast_to<RayCast>()) {
2672 
2673 		Ref<RayCastSpatialGizmo> misg = memnew(RayCastSpatialGizmo(p_spatial->cast_to<RayCast>()));
2674 		return misg;
2675 	}
2676 
2677 	if (p_spatial->cast_to<Portal>()) {
2678 
2679 		Ref<PortalSpatialGizmo> misg = memnew(PortalSpatialGizmo(p_spatial->cast_to<Portal>()));
2680 		return misg;
2681 	}
2682 
2683 	if (p_spatial->cast_to<TestCube>()) {
2684 
2685 		Ref<TestCubeSpatialGizmo> misg = memnew(TestCubeSpatialGizmo(p_spatial->cast_to<TestCube>()));
2686 		return misg;
2687 	}
2688 
2689 	if (p_spatial->cast_to<SpatialPlayer>()) {
2690 
2691 		Ref<SpatialPlayerSpatialGizmo> misg = memnew(SpatialPlayerSpatialGizmo(p_spatial->cast_to<SpatialPlayer>()));
2692 		return misg;
2693 	}
2694 
2695 	if (p_spatial->cast_to<CollisionShape>()) {
2696 
2697 		Ref<CollisionShapeSpatialGizmo> misg = memnew(CollisionShapeSpatialGizmo(p_spatial->cast_to<CollisionShape>()));
2698 		return misg;
2699 	}
2700 
2701 	if (p_spatial->cast_to<VisibilityNotifier>()) {
2702 
2703 		Ref<VisibilityNotifierGizmo> misg = memnew(VisibilityNotifierGizmo(p_spatial->cast_to<VisibilityNotifier>()));
2704 		return misg;
2705 	}
2706 
2707 	if (p_spatial->cast_to<VehicleWheel>()) {
2708 
2709 		Ref<VehicleWheelSpatialGizmo> misg = memnew(VehicleWheelSpatialGizmo(p_spatial->cast_to<VehicleWheel>()));
2710 		return misg;
2711 	}
2712 	if (p_spatial->cast_to<PinJoint>()) {
2713 
2714 		Ref<PinJointSpatialGizmo> misg = memnew(PinJointSpatialGizmo(p_spatial->cast_to<PinJoint>()));
2715 		return misg;
2716 	}
2717 
2718 	if (p_spatial->cast_to<HingeJoint>()) {
2719 
2720 		Ref<HingeJointSpatialGizmo> misg = memnew(HingeJointSpatialGizmo(p_spatial->cast_to<HingeJoint>()));
2721 		return misg;
2722 	}
2723 
2724 	if (p_spatial->cast_to<SliderJoint>()) {
2725 
2726 		Ref<SliderJointSpatialGizmo> misg = memnew(SliderJointSpatialGizmo(p_spatial->cast_to<SliderJoint>()));
2727 		return misg;
2728 	}
2729 
2730 	if (p_spatial->cast_to<ConeTwistJoint>()) {
2731 
2732 		Ref<ConeTwistJointSpatialGizmo> misg = memnew(ConeTwistJointSpatialGizmo(p_spatial->cast_to<ConeTwistJoint>()));
2733 		return misg;
2734 	}
2735 
2736 	if (p_spatial->cast_to<Generic6DOFJoint>()) {
2737 
2738 		Ref<Generic6DOFJointSpatialGizmo> misg = memnew(Generic6DOFJointSpatialGizmo(p_spatial->cast_to<Generic6DOFJoint>()));
2739 		return misg;
2740 	}
2741 
2742 	if (p_spatial->cast_to<CollisionPolygon>()) {
2743 
2744 		Ref<CollisionPolygonSpatialGizmo> misg = memnew(CollisionPolygonSpatialGizmo(p_spatial->cast_to<CollisionPolygon>()));
2745 		return misg;
2746 	}
2747 
2748 	return Ref<SpatialEditorGizmo>();
2749 }
2750 
create_line_material(const Color & p_base_color)2751 Ref<FixedMaterial> SpatialEditorGizmos::create_line_material(const Color &p_base_color) {
2752 
2753 	Ref<FixedMaterial> line_material = Ref<FixedMaterial>(memnew(FixedMaterial));
2754 	line_material->set_flag(Material::FLAG_UNSHADED, true);
2755 	line_material->set_line_width(3.0);
2756 	line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2757 	line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
2758 	line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE, p_base_color);
2759 
2760 	return line_material;
2761 }
2762 
create_solid_material(const Color & p_base_color)2763 Ref<FixedMaterial> SpatialEditorGizmos::create_solid_material(const Color &p_base_color) {
2764 
2765 	Ref<FixedMaterial> line_material = Ref<FixedMaterial>(memnew(FixedMaterial));
2766 	line_material->set_flag(Material::FLAG_UNSHADED, true);
2767 	line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2768 	line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE, p_base_color);
2769 
2770 	return line_material;
2771 }
2772 
SpatialEditorGizmos()2773 SpatialEditorGizmos::SpatialEditorGizmos() {
2774 
2775 	singleton = this;
2776 
2777 	handle_material = Ref<FixedMaterial>(memnew(FixedMaterial));
2778 	handle_material->set_flag(Material::FLAG_UNSHADED, true);
2779 	handle_material->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(0.8, 0.8, 0.8));
2780 
2781 	handle2_material = Ref<FixedMaterial>(memnew(FixedMaterial));
2782 	handle2_material->set_flag(Material::FLAG_UNSHADED, true);
2783 	handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_POINT_SIZE, true);
2784 	handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle", "EditorIcons");
2785 	handle2_material->set_point_size(handle_t->get_width());
2786 	handle2_material->set_texture(FixedMaterial::PARAM_DIFFUSE, handle_t);
2787 	handle2_material->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(1, 1, 1));
2788 	handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2789 	handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
2790 
2791 	light_material = create_line_material(Color(1, 1, 0.2));
2792 
2793 	light_material_omni_icon = Ref<FixedMaterial>(memnew(FixedMaterial));
2794 	light_material_omni_icon->set_flag(Material::FLAG_UNSHADED, true);
2795 	light_material_omni_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
2796 	light_material_omni_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
2797 	light_material_omni_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2798 	light_material_omni_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(1, 1, 1, 0.9));
2799 	light_material_omni_icon->set_texture(FixedMaterial::PARAM_DIFFUSE, SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons"));
2800 
2801 	light_material_directional_icon = Ref<FixedMaterial>(memnew(FixedMaterial));
2802 	light_material_directional_icon->set_flag(Material::FLAG_UNSHADED, true);
2803 	light_material_directional_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
2804 	light_material_directional_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
2805 	light_material_directional_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2806 	light_material_directional_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(1, 1, 1, 0.9));
2807 	light_material_directional_icon->set_texture(FixedMaterial::PARAM_DIFFUSE, SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons"));
2808 
2809 	camera_material = create_line_material(Color(1.0, 0.5, 1.0));
2810 
2811 	navmesh_edge_material = create_line_material(Color(0.1, 0.8, 1.0));
2812 	navmesh_solid_material = create_solid_material(Color(0.1, 0.8, 1.0, 0.4));
2813 	navmesh_edge_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false);
2814 	navmesh_solid_material->set_flag(Material::FLAG_DOUBLE_SIDED, true);
2815 
2816 	navmesh_edge_material_disabled = create_line_material(Color(1.0, 0.8, 0.1));
2817 	navmesh_solid_material_disabled = create_solid_material(Color(1.0, 0.8, 0.1, 0.4));
2818 	navmesh_edge_material_disabled->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false);
2819 	navmesh_solid_material_disabled->set_flag(Material::FLAG_DOUBLE_SIDED, true);
2820 
2821 	skeleton_material = create_line_material(Color(0.6, 1.0, 0.3));
2822 	skeleton_material->set_flag(Material::FLAG_DOUBLE_SIDED, true);
2823 	skeleton_material->set_flag(Material::FLAG_UNSHADED, true);
2824 	skeleton_material->set_flag(Material::FLAG_ONTOP, true);
2825 	skeleton_material->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
2826 
2827 	//position 3D Shared mesh
2828 
2829 	pos3d_mesh = Ref<Mesh>(memnew(Mesh));
2830 	{
2831 
2832 		DVector<Vector3> cursor_points;
2833 		DVector<Color> cursor_colors;
2834 		float cs = 0.25;
2835 		cursor_points.push_back(Vector3(+cs, 0, 0));
2836 		cursor_points.push_back(Vector3(-cs, 0, 0));
2837 		cursor_points.push_back(Vector3(0, +cs, 0));
2838 		cursor_points.push_back(Vector3(0, -cs, 0));
2839 		cursor_points.push_back(Vector3(0, 0, +cs));
2840 		cursor_points.push_back(Vector3(0, 0, -cs));
2841 		cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7));
2842 		cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7));
2843 		cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7));
2844 		cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7));
2845 		cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7));
2846 		cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7));
2847 
2848 		Ref<FixedMaterial> mat = memnew(FixedMaterial);
2849 		mat->set_flag(Material::FLAG_UNSHADED, true);
2850 		mat->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
2851 		mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2852 		mat->set_line_width(3);
2853 		Array d;
2854 		d.resize(VS::ARRAY_MAX);
2855 		d[Mesh::ARRAY_VERTEX] = cursor_points;
2856 		d[Mesh::ARRAY_COLOR] = cursor_colors;
2857 		pos3d_mesh->add_surface(Mesh::PRIMITIVE_LINES, d);
2858 		pos3d_mesh->surface_set_material(0, mat);
2859 	}
2860 
2861 	listener_line_mesh = Ref<Mesh>(memnew(Mesh));
2862 	{
2863 
2864 		DVector<Vector3> cursor_points;
2865 		DVector<Color> cursor_colors;
2866 		cursor_points.push_back(Vector3(0, 0, 0));
2867 		cursor_points.push_back(Vector3(0, 0, -1.0));
2868 		cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7));
2869 		cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7));
2870 
2871 		Ref<FixedMaterial> mat = memnew(FixedMaterial);
2872 		mat->set_flag(Material::FLAG_UNSHADED, true);
2873 		mat->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
2874 		mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2875 		mat->set_line_width(3);
2876 		Array d;
2877 		d.resize(VS::ARRAY_MAX);
2878 		d[Mesh::ARRAY_VERTEX] = cursor_points;
2879 		d[Mesh::ARRAY_COLOR] = cursor_colors;
2880 		listener_line_mesh->add_surface(Mesh::PRIMITIVE_LINES, d);
2881 		listener_line_mesh->surface_set_material(0, mat);
2882 	}
2883 
2884 	sample_player_icon = Ref<FixedMaterial>(memnew(FixedMaterial));
2885 	sample_player_icon->set_flag(Material::FLAG_UNSHADED, true);
2886 	sample_player_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
2887 	sample_player_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
2888 	sample_player_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2889 	sample_player_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(1, 1, 1, 0.9));
2890 	sample_player_icon->set_texture(FixedMaterial::PARAM_DIFFUSE, SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer", "EditorIcons"));
2891 
2892 	room_material = create_line_material(Color(1.0, 0.6, 0.9));
2893 	portal_material = create_line_material(Color(1.0, 0.8, 0.6));
2894 	raycast_material = create_line_material(Color(1.0, 0.8, 0.6));
2895 	car_wheel_material = create_line_material(Color(0.6, 0.8, 1.0));
2896 	visibility_notifier_material = create_line_material(Color(1.0, 0.5, 1.0));
2897 	joint_material = create_line_material(Color(0.6, 0.8, 1.0));
2898 
2899 	stream_player_icon = Ref<FixedMaterial>(memnew(FixedMaterial));
2900 	stream_player_icon->set_flag(Material::FLAG_UNSHADED, true);
2901 	stream_player_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
2902 	stream_player_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
2903 	stream_player_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2904 	stream_player_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(1, 1, 1, 0.9));
2905 	stream_player_icon->set_texture(FixedMaterial::PARAM_DIFFUSE, SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer", "EditorIcons"));
2906 
2907 	visibility_notifier_icon = Ref<FixedMaterial>(memnew(FixedMaterial));
2908 	visibility_notifier_icon->set_flag(Material::FLAG_UNSHADED, true);
2909 	visibility_notifier_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
2910 	visibility_notifier_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
2911 	visibility_notifier_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2912 	visibility_notifier_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(1, 1, 1, 0.9));
2913 	visibility_notifier_icon->set_texture(FixedMaterial::PARAM_DIFFUSE, SpatialEditor::get_singleton()->get_icon("Visible", "EditorIcons"));
2914 
2915 	listener_icon = Ref<FixedMaterial>(memnew(FixedMaterial));
2916 	listener_icon->set_flag(Material::FLAG_UNSHADED, true);
2917 	listener_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
2918 	listener_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
2919 	listener_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
2920 	listener_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(1, 1, 1, 0.9));
2921 	listener_icon->set_texture(FixedMaterial::PARAM_DIFFUSE, SpatialEditor::get_singleton()->get_icon("GizmoListener", "EditorIcons"));
2922 
2923 	{
2924 
2925 		DVector<Vector3> vertices;
2926 
2927 #undef ADD_VTX
2928 #define ADD_VTX(m_idx) \
2929 	vertices.push_back(face_points[m_idx]);
2930 
2931 		for (int i = 0; i < 6; i++) {
2932 
2933 			Vector3 face_points[4];
2934 
2935 			for (int j = 0; j < 4; j++) {
2936 
2937 				float v[3];
2938 				v[0] = 1.0;
2939 				v[1] = 1 - 2 * ((j >> 1) & 1);
2940 				v[2] = v[1] * (1 - 2 * (j & 1));
2941 
2942 				for (int k = 0; k < 3; k++) {
2943 
2944 					if (i < 3)
2945 						face_points[j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1);
2946 					else
2947 						face_points[3 - j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1);
2948 				}
2949 			}
2950 			//tri 1
2951 			ADD_VTX(0);
2952 			ADD_VTX(1);
2953 			ADD_VTX(2);
2954 			//tri 2
2955 			ADD_VTX(2);
2956 			ADD_VTX(3);
2957 			ADD_VTX(0);
2958 		}
2959 
2960 		test_cube_tm = Ref<TriangleMesh>(memnew(TriangleMesh));
2961 		test_cube_tm->create(vertices);
2962 	}
2963 
2964 	shape_material = create_line_material(Color(0.2, 1, 1.0));
2965 }
2966