From 8a41eefb97566eafb272af558c5a8925c4f69cb7 Mon Sep 17 00:00:00 2001 From: kobewi Date: Wed, 3 May 2023 22:57:15 +0200 Subject: [PATCH] Fix 2D audio in multiple viewports --- scene/2d/audio_stream_player_2d.cpp | 9 +++++---- scene/main/viewport.cpp | 6 ++++++ scene/resources/world_2d.cpp | 8 ++++++++ scene/resources/world_2d.h | 6 +++--- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 466ffad9512..85547722881 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -157,7 +157,6 @@ void AudioStreamPlayer2D::_update_panning() { Vector2 global_pos = get_global_position(); HashSet viewports = world_2d->get_viewports(); - viewports.insert(get_viewport()); // TODO: This is a mediocre workaround for #50958. Remove when that bug is fixed! volume_vector.resize(4); volume_vector.write[0] = AudioFrame(0, 0); @@ -188,11 +187,11 @@ void AudioStreamPlayer2D::_update_panning() { float dist = global_pos.distance_to(listener_in_global); // Distance to listener, or screen if none. if (dist > max_distance) { - continue; //can't hear this sound in this viewport + continue; // Can't hear this sound in this viewport. } float multiplier = Math::pow(1.0f - dist / max_distance, attenuation); - multiplier *= Math::db_to_linear(volume_db); //also apply player volume! + multiplier *= Math::db_to_linear(volume_db); // Also apply player volume! float pan = relative_to_listener.x / screen_size.x; // Don't let the panning effect extend (too far) beyond the screen. @@ -206,7 +205,9 @@ void AudioStreamPlayer2D::_update_panning() { float l = 1.0 - pan; float r = pan; - volume_vector.write[0] = AudioFrame(l, r) * multiplier; + const AudioFrame &prev_sample = volume_vector[0]; + AudioFrame new_sample = AudioFrame(l, r) * multiplier; + volume_vector.write[0] = AudioFrame(MAX(prev_sample[0], new_sample[0]), MAX(prev_sample[1], new_sample[1])); } for (const Ref &playback : stream_playbacks) { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index f3c2f4b0ccf..f178d646a8b 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1090,6 +1090,10 @@ void Viewport::set_world_2d(const Ref &p_world_2d) { RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas); } + if (world_2d.is_valid()) { + world_2d->remove_viewport(this); + } + if (p_world_2d.is_valid()) { world_2d = p_world_2d; } else { @@ -1097,6 +1101,7 @@ void Viewport::set_world_2d(const Ref &p_world_2d) { world_2d = Ref(memnew(World2D)); } + world_2d->register_viewport(this); _update_audio_listener_2d(); if (is_inside_tree()) { @@ -4149,6 +4154,7 @@ void Viewport::_validate_property(PropertyInfo &p_property) const { Viewport::Viewport() { world_2d = Ref(memnew(World2D)); + world_2d->register_viewport(this); viewport = RenderingServer::get_singleton()->viewport_create(); texture_rid = RenderingServer::get_singleton()->viewport_get_texture(viewport); diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index c7304da358c..a32dd80cb43 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -82,6 +82,14 @@ PhysicsDirectSpaceState2D *World2D::get_direct_space_state() { return PhysicsServer2D::get_singleton()->space_get_direct_state(get_space()); } +void World2D::register_viewport(Viewport *p_viewport) { + viewports.insert(p_viewport); +} + +void World2D::remove_viewport(Viewport *p_viewport) { + viewports.erase(p_viewport); +} + World2D::World2D() { canvas = RenderingServer::get_singleton()->canvas_create(); } diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h index 0b3b9df7dc6..d5e34273446 100644 --- a/scene/resources/world_2d.h +++ b/scene/resources/world_2d.h @@ -52,9 +52,6 @@ protected: static void _bind_methods(); friend class Viewport; - void _register_viewport(Viewport *p_viewport); - void _remove_viewport(Viewport *p_viewport); - public: RID get_canvas() const; RID get_space() const; @@ -62,6 +59,9 @@ public: PhysicsDirectSpaceState2D *get_direct_space_state(); + void register_viewport(Viewport *p_viewport); + void remove_viewport(Viewport *p_viewport); + _FORCE_INLINE_ const HashSet &get_viewports() { return viewports; } World2D();