Parcourir la source

Merge pull request #4101 from SaracenOne/listener

Added New Listener Spatial Node.
Juan Linietsky il y a 9 ans
Parent
commit
06bc4e20d3

+ 167 - 0
scene/3d/listener.cpp

@@ -0,0 +1,167 @@
+#include "listener.h"
+
+#include "scene/resources/mesh.h"
+
+void Listener::_update_audio_listener_state() {
+
+
+}
+
+void Listener::_request_listener_update() {
+
+	_update_listener();
+}
+
+bool Listener::_set(const StringName& p_name, const Variant& p_value) {
+
+	if (p_name == "current") {
+		if (p_value.operator bool()) {
+			make_current();
+		}
+		else {
+			clear_current();
+		}
+	}
+	else
+		return false;
+
+	return true;
+}
+bool Listener::_get(const StringName& p_name,Variant &r_ret) const {
+
+	if (p_name == "current") {
+		if (is_inside_tree() && get_tree()->is_node_being_edited(this)) {
+			r_ret = current;
+		}
+		else {
+			r_ret = is_current();
+		}
+	}
+	else
+		return false;
+
+	return true;
+}
+
+void Listener::_get_property_list( List<PropertyInfo> *p_list) const {
+
+	p_list->push_back( PropertyInfo( Variant::BOOL, "current" ) );
+}
+
+void Listener::_update_listener() {
+
+	if (is_inside_tree() && is_current()) {
+		get_viewport()->_listener_transform_changed_notify();
+
+	}
+}
+
+void Listener::_notification(int p_what) {
+
+	switch(p_what) {
+
+		case NOTIFICATION_ENTER_WORLD: {
+			bool first_listener = get_viewport()->_listener_add(this);
+			if (!get_tree()->is_node_being_edited(this) && (current || first_listener))
+				make_current();
+		} break;
+		case NOTIFICATION_TRANSFORM_CHANGED: {
+			_request_listener_update();
+		} break;
+		case NOTIFICATION_EXIT_WORLD: {
+
+			if (!get_tree()->is_node_being_edited(this)) {
+				if (is_current()) {
+					clear_current();
+					current=true; //keep it true
+
+				} else {
+					current=false;
+				}
+			}
+
+			get_viewport()->_listener_remove(this);
+
+
+		} break;
+
+
+	}
+
+}
+
+
+Transform Listener::get_listener_transform() const {
+
+	return get_global_transform().orthonormalized();
+}
+
+void Listener::make_current() {
+
+	current=true;
+
+	if (!is_inside_tree())
+		return;
+
+	get_viewport()->_listener_set(this);
+}
+
+
+
+
+void Listener::clear_current() {
+
+	current=false;
+	if (!is_inside_tree())
+		return;
+
+	if (get_viewport()->get_listener()==this) {
+		get_viewport()->_listener_set(NULL);
+		get_viewport()->_listener_make_next_current(this);
+	}
+
+}
+
+bool Listener::is_current() const {
+
+	if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
+
+		return get_viewport()->get_listener()==this;
+	} else
+		return current;
+
+	return false;
+}
+
+bool Listener::_can_gizmo_scale() const {
+
+	return false;
+}
+
+RES Listener::_get_gizmo_geometry() const {
+	Ref<Mesh> mesh = memnew(Mesh);
+
+	return mesh;
+}
+
+void Listener::_bind_methods() {
+
+	ObjectTypeDB::bind_method( _MD("make_current"),&Listener::make_current );
+	ObjectTypeDB::bind_method( _MD("clear_current"),&Listener::clear_current );
+	ObjectTypeDB::bind_method( _MD("is_current"),&Listener::is_current );
+	ObjectTypeDB::bind_method( _MD("get_listener_transform"),&Listener::get_listener_transform );
+}
+
+Listener::Listener() {
+
+	current=false;
+	force_change=false;
+	//active=false;
+}
+
+
+Listener::~Listener() {
+
+}
+
+

+ 53 - 0
scene/3d/listener.h

@@ -0,0 +1,53 @@
+#ifndef LISTENER_H
+#define LISTENER_H
+
+
+#include "scene/3d/spatial.h"
+#include "scene/main/viewport.h"
+
+class Listener : public Spatial {
+
+	OBJ_TYPE(Listener, Spatial);
+private:
+
+	bool force_change;
+	bool current;
+
+	RID scenario_id;
+
+	virtual bool _can_gizmo_scale() const;
+	virtual RES _get_gizmo_geometry() const;
+
+friend class Viewport;
+	void _update_audio_listener_state();
+protected:
+
+	void _update_listener();
+	virtual void _request_listener_update();
+
+	bool _set(const StringName& p_name, const Variant& p_value);
+	bool _get(const StringName& p_name,Variant &r_ret) const;
+	void _get_property_list( List<PropertyInfo> *p_list) const;
+	void _notification(int p_what);
+
+	static void _bind_methods();
+
+public:
+
+	void make_current();
+	void clear_current();
+	bool is_current() const;
+
+	virtual Transform get_listener_transform() const;
+
+	void set_visible_layers(uint32_t p_layers);
+	uint32_t get_visible_layers() const;
+
+	Vector<Plane> get_frustum() const;
+
+	Listener();
+	~Listener();
+
+};
+
+#endif

+ 99 - 16
scene/main/viewport.cpp

@@ -37,6 +37,7 @@
 #include "servers/spatial_sound_2d_server.h"
 #include "servers/spatial_sound_2d_server.h"
 #include "scene/gui/control.h"
 #include "scene/gui/control.h"
 #include "scene/3d/camera.h"
 #include "scene/3d/camera.h"
+#include "scene/3d/listener.h"
 #include "scene/resources/mesh.h"
 #include "scene/resources/mesh.h"
 #include "scene/3d/spatial_indexer.h"
 #include "scene/3d/spatial_indexer.h"
 #include "scene/3d/collision_object.h"
 #include "scene/3d/collision_object.h"
@@ -388,6 +389,19 @@ void Viewport::_notification(int p_what) {
 		} break;
 		} break;
 		case NOTIFICATION_READY: {
 		case NOTIFICATION_READY: {
 #ifndef _3D_DISABLED
 #ifndef _3D_DISABLED
+			if (listeners.size() && !listener) {
+				Listener *first=NULL;
+				for(Set<Listener*>::Element *E=listeners.front();E;E=E->next()) {
+
+					if (first==NULL || first->is_greater_than(E->get())) {
+						first=E->get();
+					}
+				}
+
+				if (first)
+					first->make_current();
+			}
+
 			if (cameras.size() && !camera) {
 			if (cameras.size() && !camera) {
 				//there are cameras but no current camera, pick first in tree and make it current
 				//there are cameras but no current camera, pick first in tree and make it current
 				Camera *first=NULL;
 				Camera *first=NULL;
@@ -414,7 +428,7 @@ void Viewport::_notification(int p_what) {
 				_vp_exit_tree();
 				_vp_exit_tree();
 
 
 			VisualServer::get_singleton()->viewport_set_scenario(viewport,RID());
 			VisualServer::get_singleton()->viewport_set_scenario(viewport,RID());
-			SpatialSoundServer::get_singleton()->listener_set_space(listener,RID());
+			SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID());
 			VisualServer::get_singleton()->viewport_remove_canvas(viewport,current_canvas);
 			VisualServer::get_singleton()->viewport_remove_canvas(viewport,current_canvas);
 			if (contact_2d_debug.is_valid()) {
 			if (contact_2d_debug.is_valid()) {
 				VisualServer::get_singleton()->free(contact_2d_debug);
 				VisualServer::get_singleton()->free(contact_2d_debug);
@@ -740,10 +754,10 @@ Rect2 Viewport::get_rect() const {
 
 
 void Viewport::_update_listener() {
 void Viewport::_update_listener() {
 
 
-	if (is_inside_tree() && audio_listener && camera && (!get_parent() || (get_parent()->cast_to<Control>() && get_parent()->cast_to<Control>()->is_visible())))  {
-		SpatialSoundServer::get_singleton()->listener_set_space(listener,find_world()->get_sound_space());
+	if (is_inside_tree() && audio_listener && (camera || listener) && (!get_parent() || (get_parent()->cast_to<Control>() && get_parent()->cast_to<Control>()->is_visible())))  {
+		SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, find_world()->get_sound_space());
 	} else {
 	} else {
-		SpatialSoundServer::get_singleton()->listener_set_space(listener,RID());
+		SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID());
 	}
 	}
 
 
 
 
@@ -752,9 +766,9 @@ void Viewport::_update_listener() {
 void Viewport::_update_listener_2d() {
 void Viewport::_update_listener_2d() {
 
 
 	if (is_inside_tree() && audio_listener && (!get_parent() || (get_parent()->cast_to<Control>() && get_parent()->cast_to<Control>()->is_visible())))
 	if (is_inside_tree() && audio_listener && (!get_parent() || (get_parent()->cast_to<Control>() && get_parent()->cast_to<Control>()->is_visible())))
-		SpatialSound2DServer::get_singleton()->listener_set_space(listener_2d,find_world_2d()->get_sound_space());
+		SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, find_world_2d()->get_sound_space());
 	else
 	else
-		SpatialSound2DServer::get_singleton()->listener_set_space(listener_2d,RID());
+		SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, RID());
 
 
 }
 }
 
 
@@ -798,11 +812,11 @@ void Viewport::set_canvas_transform(const Matrix32& p_transform) {
 
 
 	Matrix32 xform = (global_canvas_transform * canvas_transform).affine_inverse();
 	Matrix32 xform = (global_canvas_transform * canvas_transform).affine_inverse();
 	Size2 ss = get_visible_rect().size;
 	Size2 ss = get_visible_rect().size;
-	SpatialSound2DServer::get_singleton()->listener_set_transform(listener_2d,Matrix32(0,xform.xform(ss*0.5)));
+	SpatialSound2DServer::get_singleton()->listener_set_transform(internal_listener_2d, Matrix32(0, xform.xform(ss*0.5)));
 	Vector2 ss2 = ss*xform.get_scale();
 	Vector2 ss2 = ss*xform.get_scale();
 	float panrange = MAX(ss2.x,ss2.y);
 	float panrange = MAX(ss2.x,ss2.y);
 
 
-	SpatialSound2DServer::get_singleton()->listener_set_param(listener_2d,SpatialSound2DServer::LISTENER_PARAM_PAN_RANGE,panrange);
+	SpatialSound2DServer::get_singleton()->listener_set_param(internal_listener_2d, SpatialSound2DServer::LISTENER_PARAM_PAN_RANGE, panrange);
 
 
 
 
 }
 }
@@ -823,11 +837,11 @@ void Viewport::_update_global_transform() {
 
 
 	Matrix32 xform = (sxform * canvas_transform).affine_inverse();
 	Matrix32 xform = (sxform * canvas_transform).affine_inverse();
 	Size2 ss = get_visible_rect().size;
 	Size2 ss = get_visible_rect().size;
-	SpatialSound2DServer::get_singleton()->listener_set_transform(listener_2d,Matrix32(0,xform.xform(ss*0.5)));
+	SpatialSound2DServer::get_singleton()->listener_set_transform(internal_listener_2d, Matrix32(0, xform.xform(ss*0.5)));
 	Vector2 ss2 = ss*xform.get_scale();
 	Vector2 ss2 = ss*xform.get_scale();
 	float panrange = MAX(ss2.x,ss2.y);
 	float panrange = MAX(ss2.x,ss2.y);
 
 
-	SpatialSound2DServer::get_singleton()->listener_set_param(listener_2d,SpatialSound2DServer::LISTENER_PARAM_PAN_RANGE,panrange);
+	SpatialSound2DServer::get_singleton()->listener_set_param(internal_listener_2d, SpatialSound2DServer::LISTENER_PARAM_PAN_RANGE, panrange);
 
 
 }
 }
 
 
@@ -846,12 +860,75 @@ Matrix32 Viewport::get_global_canvas_transform() const{
 	return global_canvas_transform;
 	return global_canvas_transform;
 }
 }
 
 
+void Viewport::_listener_transform_changed_notify() {
+
+#ifndef _3D_DISABLED
+	if (listener)
+		SpatialSoundServer::get_singleton()->listener_set_transform(internal_listener, listener->get_listener_transform());
+#endif
+}
+
+void Viewport::_listener_set(Listener* p_listener) {
+
+#ifndef _3D_DISABLED
+
+	if (listener == p_listener)
+		return;
+
+	listener = p_listener;
+
+	_update_listener();
+	_listener_transform_changed_notify();
+#endif
+}
+
+bool Viewport::_listener_add(Listener* p_listener) {
+
+	listeners.insert(p_listener);
+	return listeners.size() == 1;
+}
+
+void Viewport::_listener_remove(Listener* p_listener) {
+
+	listeners.erase(p_listener);
+	if (listener == p_listener) {
+		listener = NULL;
+	}
+}
+
+#ifndef _3D_DISABLED
+void Viewport::_listener_make_next_current(Listener* p_exclude) {
+
+	if (listeners.size() > 0) {
+		for (Set<Listener*>::Element *E = listeners.front(); E; E = E->next()) {
+
+			if (p_exclude == E->get())
+				continue;
+			if (!E->get()->is_inside_tree())
+				continue;
+			if (listener != NULL)
+				return;
+
+			E->get()->make_current();
+
+		}
+	}
+	else {
+		// Attempt to reset listener to the camera position
+		if (camera != NULL) {
+			_update_listener();
+			_camera_transform_changed_notify();
+		}
+	}
+}
+#endif
 
 
 void Viewport::_camera_transform_changed_notify() {
 void Viewport::_camera_transform_changed_notify() {
 
 
 #ifndef _3D_DISABLED
 #ifndef _3D_DISABLED
-	if (camera)
-		SpatialSoundServer::get_singleton()->listener_set_transform(listener,camera->get_camera_transform());
+	// If there is an active listener in the scene, it takes priority over the camera
+	if (camera && !listener)
+		SpatialSoundServer::get_singleton()->listener_set_transform(internal_listener, camera->get_camera_transform());
 #endif
 #endif
 }
 }
 
 
@@ -1076,6 +1153,11 @@ Ref<World> Viewport::find_world() const{
 		return Ref<World>();
 		return Ref<World>();
 }
 }
 
 
+Listener* Viewport::get_listener() const {
+
+	return listener;
+}
+
 Camera* Viewport::get_camera() const {
 Camera* Viewport::get_camera() const {
 
 
 	return camera;
 	return camera;
@@ -2547,12 +2629,13 @@ Viewport::Viewport() {
 	world_2d = Ref<World2D>( memnew( World2D ));
 	world_2d = Ref<World2D>( memnew( World2D ));
 
 
 	viewport = VisualServer::get_singleton()->viewport_create();
 	viewport = VisualServer::get_singleton()->viewport_create();
-	listener=SpatialSoundServer::get_singleton()->listener_create();
+	internal_listener = SpatialSoundServer::get_singleton()->listener_create();
 	audio_listener=false;
 	audio_listener=false;
-	listener_2d=SpatialSound2DServer::get_singleton()->listener_create();
+	internal_listener_2d = SpatialSound2DServer::get_singleton()->listener_create();
 	audio_listener_2d=false;
 	audio_listener_2d=false;
 	transparent_bg=false;
 	transparent_bg=false;
 	parent=NULL;
 	parent=NULL;
+	listener=NULL;
 	camera=NULL;
 	camera=NULL;
 	size_override=false;
 	size_override=false;
 	size_override_stretch=false;
 	size_override_stretch=false;
@@ -2600,8 +2683,8 @@ Viewport::Viewport() {
 Viewport::~Viewport() {
 Viewport::~Viewport() {
 
 
 	VisualServer::get_singleton()->free( viewport );
 	VisualServer::get_singleton()->free( viewport );
-	SpatialSoundServer::get_singleton()->free(listener);
-	SpatialSound2DServer::get_singleton()->free(listener_2d);
+	SpatialSoundServer::get_singleton()->free(internal_listener);
+	SpatialSound2DServer::get_singleton()->free(internal_listener_2d);
 	if (render_target_texture.is_valid())
 	if (render_target_texture.is_valid())
 		render_target_texture->vp=NULL; //so if used, will crash
 		render_target_texture->vp=NULL; //so if used, will crash
 }
 }

+ 14 - 3
scene/main/viewport.h

@@ -39,6 +39,7 @@
 */
 */
 
 
 class Camera;
 class Camera;
+class Listener;
 class Control;
 class Control;
 class CanvasItem;
 class CanvasItem;
 class Panel;
 class Panel;
@@ -92,6 +93,9 @@ friend class RenderTargetTexture;
 	Control *parent_control;
 	Control *parent_control;
 	Viewport *parent;
 	Viewport *parent;
 
 
+	Listener *listener;
+	Set<Listener*> listeners;
+
 	Camera *camera;
 	Camera *camera;
 	Set<Camera*> cameras;
 	Set<Camera*> cameras;
 
 
@@ -100,10 +104,10 @@ friend class RenderTargetTexture;
 	RID current_canvas;
 	RID current_canvas;
 
 
 	bool audio_listener;
 	bool audio_listener;
-	RID listener;
+	RID internal_listener;
 
 
 	bool audio_listener_2d;
 	bool audio_listener_2d;
-	RID listener_2d;
+	RID internal_listener_2d;
 
 
 	Matrix32 canvas_transform;
 	Matrix32 canvas_transform;
 	Matrix32 global_canvas_transform;
 	Matrix32 global_canvas_transform;
@@ -263,6 +267,13 @@ friend class Control;
 
 
 	Control *_gui_get_focus_owner();
 	Control *_gui_get_focus_owner();
 
 
+friend class Listener;
+	void _listener_transform_changed_notify();
+	void _listener_set(Listener* p_listener);
+	bool _listener_add(Listener* p_listener); //true if first
+	void _listener_remove(Listener* p_listener);
+	void _listener_make_next_current(Listener* p_exclude);
+
 friend class Camera;
 friend class Camera;
 	void _camera_transform_changed_notify();
 	void _camera_transform_changed_notify();
 	void _camera_set(Camera* p_camera);
 	void _camera_set(Camera* p_camera);
@@ -276,7 +287,7 @@ protected:
 	static void _bind_methods();
 	static void _bind_methods();
 public:
 public:
 
 
-
+	Listener* get_listener() const;
 	Camera* get_camera() const;
 	Camera* get_camera() const;
 
 
 	void set_as_audio_listener(bool p_enable);
 	void set_as_audio_listener(bool p_enable);

+ 2 - 0
scene/register_scene_types.cpp

@@ -193,6 +193,7 @@
 
 
 #ifndef _3D_DISABLED
 #ifndef _3D_DISABLED
 #include "scene/3d/camera.h"
 #include "scene/3d/camera.h"
+#include "scene/3d/listener.h"
 
 
 #include "scene/3d/interpolated_camera.h"
 #include "scene/3d/interpolated_camera.h"
 #include "scene/3d/position_3d.h"
 #include "scene/3d/position_3d.h"
@@ -387,6 +388,7 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<BoneAttachment>();
 	ObjectTypeDB::register_type<BoneAttachment>();
 	ObjectTypeDB::register_virtual_type<VisualInstance>();
 	ObjectTypeDB::register_virtual_type<VisualInstance>();
 	ObjectTypeDB::register_type<Camera>();
 	ObjectTypeDB::register_type<Camera>();
+	ObjectTypeDB::register_type<Listener>();
 	ObjectTypeDB::register_type<InterpolatedCamera>();
 	ObjectTypeDB::register_type<InterpolatedCamera>();
 	ObjectTypeDB::register_type<TestCube>();
 	ObjectTypeDB::register_type<TestCube>();
 	ObjectTypeDB::register_type<MeshInstance>();
 	ObjectTypeDB::register_type<MeshInstance>();

BIN
tools/editor/icons/icon_gizmo_listener.png


BIN
tools/editor/icons/icon_listener.png


+ 59 - 0
tools/editor/spatial_editor_gizmos.cpp

@@ -1024,6 +1024,28 @@ LightSpatialGizmo::LightSpatialGizmo(Light* p_light){
 	set_spatial_node(p_light);
 	set_spatial_node(p_light);
 
 
 }
 }
+//////
+
+void ListenerSpatialGizmo::redraw() {
+
+	clear();
+
+	add_unscaled_billboard(SpatialEditorGizmos::singleton->listener_icon, 0.05);
+
+	add_mesh(SpatialEditorGizmos::singleton->listener_line_mesh);
+	Vector<Vector3> cursor_points;
+	cursor_points.push_back(Vector3(0, 0, 0));
+	cursor_points.push_back(Vector3(0, 0, -1.0));
+	add_collision_segments(cursor_points);
+
+}
+
+ListenerSpatialGizmo::ListenerSpatialGizmo(Listener* p_listener){
+
+	set_spatial_node(p_listener);
+	listener = p_listener;
+}
+
 
 
 //////
 //////
 
 
@@ -2907,6 +2929,12 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) {
 		return lsg;
 		return lsg;
 	}
 	}
 
 
+	if (p_spatial->cast_to<Listener>()) {
+
+		Ref<ListenerSpatialGizmo> misg = memnew(ListenerSpatialGizmo(p_spatial->cast_to<Listener>()));
+		return misg;
+	}
+
 	if (p_spatial->cast_to<Camera>()) {
 	if (p_spatial->cast_to<Camera>()) {
 
 
 		Ref<CameraSpatialGizmo> lsg = memnew( CameraSpatialGizmo(p_spatial->cast_to<Camera>()) );
 		Ref<CameraSpatialGizmo> lsg = memnew( CameraSpatialGizmo(p_spatial->cast_to<Camera>()) );
@@ -3141,6 +3169,29 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
 		pos3d_mesh->surface_set_material(0,mat);
 		pos3d_mesh->surface_set_material(0,mat);
 	}
 	}
 
 
+	listener_line_mesh = Ref<Mesh>(memnew(Mesh));
+	{
+
+		DVector<Vector3> cursor_points;
+		DVector<Color> cursor_colors;
+		cursor_points.push_back(Vector3(0, 0, 0));
+		cursor_points.push_back(Vector3(0, 0, -1.0));
+		cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7));
+		cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7));
+
+		Ref<FixedMaterial> mat = memnew(FixedMaterial);
+		mat->set_flag(Material::FLAG_UNSHADED, true);
+		mat->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
+		mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+		mat->set_line_width(3);
+		Array d;
+		d.resize(VS::ARRAY_MAX);
+		d[Mesh::ARRAY_VERTEX] = cursor_points;
+		d[Mesh::ARRAY_COLOR] = cursor_colors;
+		listener_line_mesh->add_surface(Mesh::PRIMITIVE_LINES, d);
+		listener_line_mesh->surface_set_material(0, mat);
+	}
+
 
 
 	sample_player_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
 	sample_player_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
 	sample_player_icon->set_flag(Material::FLAG_UNSHADED, true);
 	sample_player_icon->set_flag(Material::FLAG_UNSHADED, true);
@@ -3173,6 +3224,14 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
 	visibility_notifier_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
 	visibility_notifier_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
 	visibility_notifier_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("Visible","EditorIcons"));
 	visibility_notifier_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("Visible","EditorIcons"));
 
 
+	listener_icon = Ref<FixedMaterial>(memnew(FixedMaterial));
+	listener_icon->set_flag(Material::FLAG_UNSHADED, true);
+	listener_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
+	listener_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
+	listener_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+	listener_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE, Color(1, 1, 1, 0.9));
+	listener_icon->set_texture(FixedMaterial::PARAM_DIFFUSE, SpatialEditor::get_singleton()->get_icon("GizmoListener", "EditorIcons"));
+
 	{
 	{
 
 
 		DVector<Vector3> vertices;
 		DVector<Vector3> vertices;

+ 16 - 0
tools/editor/spatial_editor_gizmos.h

@@ -32,6 +32,7 @@
 
 
 #include "tools/editor/plugins/spatial_editor_plugin.h"
 #include "tools/editor/plugins/spatial_editor_plugin.h"
 #include "scene/3d/light.h"
 #include "scene/3d/light.h"
+#include "scene/3d/listener.h"
 #include "scene/3d/camera.h"
 #include "scene/3d/camera.h"
 #include "scene/3d/position_3d.h"
 #include "scene/3d/position_3d.h"
 #include "scene/3d/spatial_sample_player.h"
 #include "scene/3d/spatial_sample_player.h"
@@ -143,6 +144,19 @@ public:
 
 
 };
 };
 
 
+class ListenerSpatialGizmo : public EditorSpatialGizmo {
+
+	OBJ_TYPE(ListenerSpatialGizmo, EditorSpatialGizmo);
+
+	Listener* listener;
+
+public:
+
+	void redraw();
+	ListenerSpatialGizmo(Listener* p_listener = NULL);
+
+};
+
 class CameraSpatialGizmo  : public EditorSpatialGizmo {
 class CameraSpatialGizmo  : public EditorSpatialGizmo {
 
 
 	OBJ_TYPE(CameraSpatialGizmo,EditorSpatialGizmo);
 	OBJ_TYPE(CameraSpatialGizmo,EditorSpatialGizmo);
@@ -471,6 +485,7 @@ public:
 	Ref<FixedMaterial> navmesh_edge_material_disabled;
 	Ref<FixedMaterial> navmesh_edge_material_disabled;
 	Ref<FixedMaterial> navmesh_solid_material_disabled;
 	Ref<FixedMaterial> navmesh_solid_material_disabled;
 
 
+	Ref<FixedMaterial> listener_icon;
 
 
 	Ref<FixedMaterial> sample_player_icon;
 	Ref<FixedMaterial> sample_player_icon;
 	Ref<FixedMaterial> stream_player_icon;
 	Ref<FixedMaterial> stream_player_icon;
@@ -480,6 +495,7 @@ public:
 	Ref<Texture> handle_t;
 	Ref<Texture> handle_t;
 
 
 	Ref<Mesh> pos3d_mesh;
 	Ref<Mesh> pos3d_mesh;
+	Ref<Mesh> listener_line_mesh;
 	static SpatialEditorGizmos *singleton;
 	static SpatialEditorGizmos *singleton;
 
 
 	Ref<TriangleMesh> test_cube_tm;
 	Ref<TriangleMesh> test_cube_tm;