summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/3d/listener.cpp167
-rw-r--r--scene/3d/listener.h53
-rw-r--r--scene/main/viewport.cpp115
-rw-r--r--scene/main/viewport.h17
-rw-r--r--scene/register_scene_types.cpp2
5 files changed, 335 insertions, 19 deletions
diff --git a/scene/3d/listener.cpp b/scene/3d/listener.cpp
new file mode 100644
index 0000000000..bf42a5c92e
--- /dev/null
+++ b/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() {
+
+}
+
+
diff --git a/scene/3d/listener.h b/scene/3d/listener.h
new file mode 100644
index 0000000000..bf0281a8e0
--- /dev/null
+++ b/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
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 5017ae61ff..3981e43818 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -37,6 +37,7 @@
#include "servers/spatial_sound_2d_server.h"
#include "scene/gui/control.h"
#include "scene/3d/camera.h"
+#include "scene/3d/listener.h"
#include "scene/resources/mesh.h"
#include "scene/3d/spatial_indexer.h"
#include "scene/3d/collision_object.h"
@@ -388,6 +389,19 @@ void Viewport::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
#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) {
//there are cameras but no current camera, pick first in tree and make it current
Camera *first=NULL;
@@ -414,7 +428,7 @@ void Viewport::_notification(int p_what) {
_vp_exit_tree();
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);
if (contact_2d_debug.is_valid()) {
VisualServer::get_singleton()->free(contact_2d_debug);
@@ -740,10 +754,10 @@ Rect2 Viewport::get_rect() const {
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 {
- 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() {
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
- 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();
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();
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();
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();
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;
}
+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() {
#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
}
@@ -1066,6 +1143,11 @@ Ref<World> Viewport::find_world() const{
return Ref<World>();
}
+Listener* Viewport::get_listener() const {
+
+ return listener;
+}
+
Camera* Viewport::get_camera() const {
return camera;
@@ -2493,12 +2575,13 @@ Viewport::Viewport() {
world_2d = Ref<World2D>( memnew( World2D ));
viewport = VisualServer::get_singleton()->viewport_create();
- listener=SpatialSoundServer::get_singleton()->listener_create();
+ internal_listener = SpatialSoundServer::get_singleton()->listener_create();
audio_listener=false;
- listener_2d=SpatialSound2DServer::get_singleton()->listener_create();
+ internal_listener_2d = SpatialSound2DServer::get_singleton()->listener_create();
audio_listener_2d=false;
transparent_bg=false;
parent=NULL;
+ listener=NULL;
camera=NULL;
size_override=false;
size_override_stretch=false;
@@ -2546,8 +2629,8 @@ Viewport::Viewport() {
Viewport::~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())
render_target_texture->vp=NULL; //so if used, will crash
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index afabd499a9..00a9199b1f 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -39,6 +39,7 @@
*/
class Camera;
+class Listener;
class Control;
class CanvasItem;
class Panel;
@@ -92,6 +93,9 @@ friend class RenderTargetTexture;
Control *parent_control;
Viewport *parent;
+ Listener *listener;
+ Set<Listener*> listeners;
+
Camera *camera;
Set<Camera*> cameras;
@@ -100,10 +104,10 @@ friend class RenderTargetTexture;
RID current_canvas;
bool audio_listener;
- RID listener;
+ RID internal_listener;
bool audio_listener_2d;
- RID listener_2d;
+ RID internal_listener_2d;
Matrix32 canvas_transform;
Matrix32 global_canvas_transform;
@@ -262,6 +266,13 @@ friend class Control;
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;
void _camera_transform_changed_notify();
void _camera_set(Camera* p_camera);
@@ -275,7 +286,7 @@ protected:
static void _bind_methods();
public:
-
+ Listener* get_listener() const;
Camera* get_camera() const;
void set_as_audio_listener(bool p_enable);
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 9930aa07f6..0e981e5851 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -190,6 +190,7 @@
#ifndef _3D_DISABLED
#include "scene/3d/camera.h"
+#include "scene/3d/listener.h"
#include "scene/3d/interpolated_camera.h"
#include "scene/3d/position_3d.h"
@@ -380,6 +381,7 @@ void register_scene_types() {
ObjectTypeDB::register_type<BoneAttachment>();
ObjectTypeDB::register_virtual_type<VisualInstance>();
ObjectTypeDB::register_type<Camera>();
+ ObjectTypeDB::register_type<Listener>();
ObjectTypeDB::register_type<InterpolatedCamera>();
ObjectTypeDB::register_type<TestCube>();
ObjectTypeDB::register_type<MeshInstance>();