diff options
author | Pedro J. Estébanez <pedrojrulez@gmail.com> | 2018-08-25 00:03:26 +0200 |
---|---|---|
committer | Pedro J. Estébanez <pedrojrulez@gmail.com> | 2018-08-25 00:03:26 +0200 |
commit | 6d0f4a4ad70bc20e2653c144d630f19507edb164 (patch) | |
tree | c53d59dec22c1fe47d60fa29dc4f74d14621bd13 /scene/main | |
parent | 62233423c7310a155e8c948c053701dba248dcdb (diff) |
Fix picking in CanvasLayer
New APIs in 2D physics allow intersection queries filtered by CanvasLayer object instance id. Viewport keep an inventory of its descendant CanvasLayers and takes advantage of all that to test picking with the mouse/touch position correctly transformed for each CanvasLayer.
Diffstat (limited to 'scene/main')
-rw-r--r-- | scene/main/canvas_layer.cpp | 5 | ||||
-rw-r--r-- | scene/main/viewport.cpp | 59 | ||||
-rw-r--r-- | scene/main/viewport.h | 6 |
3 files changed, 54 insertions, 16 deletions
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index a2e890e7a7..7a53de86a1 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -146,6 +146,8 @@ void CanvasLayer::_notification(int p_what) { vp = Node::get_viewport(); } ERR_FAIL_COND(!vp); + + vp->_canvas_layer_add(this); viewport = vp->get_viewport_rid(); VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas); @@ -155,6 +157,7 @@ void CanvasLayer::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { + vp->_canvas_layer_remove(this); VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas); viewport = RID(); @@ -179,6 +182,7 @@ RID CanvasLayer::get_viewport() const { void CanvasLayer::set_custom_viewport(Node *p_viewport) { ERR_FAIL_NULL(p_viewport); if (is_inside_tree()) { + vp->_canvas_layer_remove(this); VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas); viewport = RID(); } @@ -198,6 +202,7 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) { else vp = Node::get_viewport(); + vp->_canvas_layer_add(this); viewport = vp->get_viewport_rid(); VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index d1b3eb9d9a..7c17e250ae 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -45,6 +45,7 @@ #include "scene/gui/panel.h" #include "scene/gui/panel_container.h" #include "scene/gui/popup_menu.h" +#include "scene/main/canvas_layer.h" #include "scene/main/timer.h" #include "scene/resources/mesh.h" #include "scene/scene_string_names.h" @@ -443,24 +444,39 @@ void Viewport::_notification(int p_what) { uint64_t frame = get_tree()->get_frame(); - Vector2 point = get_canvas_transform().affine_inverse().xform(pos); Physics2DDirectSpaceState::ShapeResult res[64]; - int rc = ss2d->intersect_point(point, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true); - for (int i = 0; i < rc; i++) { - - if (res[i].collider_id && res[i].collider) { - CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider); - if (co) { - - Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.find(res[i].collider_id); - if (!E) { - E = physics_2d_mouseover.insert(res[i].collider_id, frame); - co->_mouse_enter(); - } else { - E->get() = frame; - } + for (Set<CanvasLayer *>::Element *E = canvas_layers.front(); E; E = E->next()) { + Transform2D canvas_transform; + ObjectID canvas_layer_id; + if (E->get()) { + // A descendant CanvasLayer + canvas_transform = E->get()->get_transform(); + canvas_layer_id = E->get()->get_instance_id(); + } else { + // This Viewport's builtin canvas + canvas_transform = get_canvas_transform(); + canvas_layer_id = 0; + } + + Vector2 point = canvas_transform.affine_inverse().xform(pos); + + int rc = ss2d->intersect_point_on_canvas(point, canvas_layer_id, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true); + for (int i = 0; i < rc; i++) { + + if (res[i].collider_id && res[i].collider) { + CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider); + if (co) { + + Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.find(res[i].collider_id); + if (!E) { + E = physics_2d_mouseover.insert(res[i].collider_id, frame); + co->_mouse_enter(); + } else { + E->get() = frame; + } - co->_input_event(this, ev, res[i].shape); + co->_input_event(this, ev, res[i].shape); + } } } } @@ -874,6 +890,16 @@ void Viewport::_camera_make_next_current(Camera *p_exclude) { } #endif +void Viewport::_canvas_layer_add(CanvasLayer *p_canvas_layer) { + + canvas_layers.insert(p_canvas_layer); +} + +void Viewport::_canvas_layer_remove(CanvasLayer *p_canvas_layer) { + + canvas_layers.erase(p_canvas_layer); +} + void Viewport::set_transparent_background(bool p_enable) { transparent_bg = p_enable; @@ -2921,6 +2947,7 @@ Viewport::Viewport() { parent = NULL; listener = NULL; camera = NULL; + canvas_layers.insert(NULL); // This eases picking code (interpreted as the canvas of the Viewport) arvr = false; size_override = false; size_override_stretch = false; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 450f235b79..694cf70fe1 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -45,6 +45,7 @@ class Camera2D; class Listener; class Control; class CanvasItem; +class CanvasLayer; class Panel; class Label; class Timer; @@ -163,6 +164,7 @@ private: Camera *camera; Set<Camera *> cameras; + Set<CanvasLayer *> canvas_layers; RID viewport; RID current_canvas; @@ -354,6 +356,10 @@ private: void _camera_remove(Camera *p_camera); void _camera_make_next_current(Camera *p_exclude); + friend class CanvasLayer; + void _canvas_layer_add(CanvasLayer *p_canvas_layer); + void _canvas_layer_remove(CanvasLayer *p_canvas_layer); + protected: void _notification(int p_what); static void _bind_methods(); |