From d1fa284e652e2c50d5bcd723cd5e355dce12a887 Mon Sep 17 00:00:00 2001 From: Markus Sauermann <6299227+Sauermann@users.noreply.github.com> Date: Tue, 6 Jun 2023 20:42:41 +0200 Subject: [PATCH] Fix mouse position with screen transform When a Viewport is not directly attached to the screen, the function `Viewport::get_mouse_position` can't rely on `get_screen_transform`, because that function is ambiguous in these situations. In these cases it is necessary to use the mouse position from the most recent mouse IputEvent. --- scene/main/viewport.cpp | 11 ++++++++++- scene/main/viewport.h | 2 ++ scene/main/window.cpp | 8 ++++++++ scene/main/window.h | 1 + 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index ab3cd694928..eaeacf93661 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1351,7 +1351,11 @@ Ref Viewport::_make_input_local(const Ref &ev) { Vector2 Viewport::get_mouse_position() const { ERR_READ_THREAD_GUARD_V(Vector2()); - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_MOUSE)) { + if (!is_directly_attached_to_screen()) { + // Rely on the most recent mouse coordinate from an InputEventMouse in push_input. + // In this case get_screen_transform is not applicable, because it is ambiguous. + return gui.last_mouse_pos; + } else if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_MOUSE)) { return get_screen_transform_internal(true).affine_inverse().xform(DisplayServer::get_singleton()->mouse_get_position()); } else { // Fallback to Input for getting mouse position in case of emulated mouse. @@ -4595,6 +4599,11 @@ Transform2D SubViewport::get_popup_base_transform() const { return c->get_screen_transform() * container_transform * get_final_transform(); } +bool SubViewport::is_directly_attached_to_screen() const { + // SubViewports, that are used as Textures are not considered to be directly attached to screen. + return Object::cast_to(get_parent()) && get_parent()->get_viewport() && get_parent()->get_viewport()->is_directly_attached_to_screen(); +} + void SubViewport::_notification(int p_what) { ERR_MAIN_THREAD_GUARD; switch (p_what) { diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 1cb32d4509c..d7c5f0eeb5d 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -669,6 +669,7 @@ public: Transform2D get_screen_transform() const; virtual Transform2D get_screen_transform_internal(bool p_absolute_position = false) const; virtual Transform2D get_popup_base_transform() const { return Transform2D(); } + virtual bool is_directly_attached_to_screen() const { return false; }; #ifndef _3D_DISABLED bool use_xr = false; @@ -800,6 +801,7 @@ public: virtual Transform2D get_screen_transform_internal(bool p_absolute_position = false) const override; virtual Transform2D get_popup_base_transform() const override; + virtual bool is_directly_attached_to_screen() const override; void _validate_property(PropertyInfo &p_property) const; SubViewport(); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 26aa06e1a4d..31aeb70d402 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -2475,6 +2475,14 @@ Transform2D Window::get_popup_base_transform() const { return popup_base_transform; } +bool Window::is_directly_attached_to_screen() const { + if (get_embedder()) { + return get_embedder()->is_directly_attached_to_screen(); + } + // Distinguish between the case that this is a native Window and not inside the tree. + return is_inside_tree(); +} + void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("set_title", "title"), &Window::set_title); ClassDB::bind_method(D_METHOD("get_title"), &Window::get_title); diff --git a/scene/main/window.h b/scene/main/window.h index bf5d6a13ee4..d0afd0ff9f2 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -401,6 +401,7 @@ public: virtual Transform2D get_final_transform() const override; virtual Transform2D get_screen_transform_internal(bool p_absolute_position = false) const override; virtual Transform2D get_popup_base_transform() const override; + virtual bool is_directly_attached_to_screen() const override; Rect2i get_parent_rect() const; virtual DisplayServer::WindowID get_window_id() const override;