1 /*************************************************************************/
2 /* viewport.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "viewport.h"
32
33 #include "core/core_string_names.h"
34 #include "core/os/input.h"
35 #include "core/os/os.h"
36 #include "core/project_settings.h"
37 #include "scene/2d/collision_object_2d.h"
38 #include "scene/3d/camera.h"
39 #include "scene/3d/collision_object.h"
40 #include "scene/3d/listener.h"
41 #include "scene/3d/spatial.h"
42 #include "scene/3d/world_environment.h"
43 #include "scene/gui/control.h"
44 #include "scene/gui/label.h"
45 #include "scene/gui/menu_button.h"
46 #include "scene/gui/panel.h"
47 #include "scene/gui/panel_container.h"
48 #include "scene/gui/popup_menu.h"
49 #include "scene/main/canvas_layer.h"
50 #include "scene/main/timer.h"
51 #include "scene/resources/mesh.h"
52 #include "scene/scene_string_names.h"
53 #include "servers/physics_2d_server.h"
54
setup_local_to_scene()55 void ViewportTexture::setup_local_to_scene() {
56
57 if (vp) {
58 vp->viewport_textures.erase(this);
59 }
60
61 vp = NULL;
62
63 Node *local_scene = get_local_scene();
64 if (!local_scene) {
65 return;
66 }
67
68 Node *vpn = local_scene->get_node(path);
69 ERR_FAIL_COND_MSG(!vpn, "ViewportTexture: Path to node is invalid.");
70
71 vp = Object::cast_to<Viewport>(vpn);
72
73 ERR_FAIL_COND_MSG(!vp, "ViewportTexture: Path to node does not point to a viewport.");
74
75 vp->viewport_textures.insert(this);
76
77 VS::get_singleton()->texture_set_proxy(proxy, vp->texture_rid);
78
79 vp->texture_flags = flags;
80 VS::get_singleton()->texture_set_flags(vp->texture_rid, flags);
81 }
82
set_viewport_path_in_scene(const NodePath & p_path)83 void ViewportTexture::set_viewport_path_in_scene(const NodePath &p_path) {
84
85 if (path == p_path)
86 return;
87
88 path = p_path;
89
90 if (get_local_scene()) {
91 setup_local_to_scene();
92 }
93 }
94
get_viewport_path_in_scene() const95 NodePath ViewportTexture::get_viewport_path_in_scene() const {
96
97 return path;
98 }
99
get_width() const100 int ViewportTexture::get_width() const {
101
102 ERR_FAIL_COND_V_MSG(!vp, 0, "Viewport Texture must be set to use it.");
103 return vp->size.width;
104 }
get_height() const105 int ViewportTexture::get_height() const {
106
107 ERR_FAIL_COND_V_MSG(!vp, 0, "Viewport Texture must be set to use it.");
108 return vp->size.height;
109 }
get_size() const110 Size2 ViewportTexture::get_size() const {
111
112 ERR_FAIL_COND_V_MSG(!vp, Size2(), "Viewport Texture must be set to use it.");
113 return vp->size;
114 }
get_rid() const115 RID ViewportTexture::get_rid() const {
116
117 //ERR_FAIL_COND_V_MSG(!vp, RID(), "Viewport Texture must be set to use it.");
118 return proxy;
119 }
120
has_alpha() const121 bool ViewportTexture::has_alpha() const {
122
123 return false;
124 }
get_data() const125 Ref<Image> ViewportTexture::get_data() const {
126
127 ERR_FAIL_COND_V_MSG(!vp, Ref<Image>(), "Viewport Texture must be set to use it.");
128 return VS::get_singleton()->texture_get_data(vp->texture_rid);
129 }
set_flags(uint32_t p_flags)130 void ViewportTexture::set_flags(uint32_t p_flags) {
131 flags = p_flags;
132
133 if (!vp)
134 return;
135
136 vp->texture_flags = flags;
137 VS::get_singleton()->texture_set_flags(vp->texture_rid, flags);
138 }
139
get_flags() const140 uint32_t ViewportTexture::get_flags() const {
141
142 return flags;
143 }
144
_bind_methods()145 void ViewportTexture::_bind_methods() {
146
147 ClassDB::bind_method(D_METHOD("set_viewport_path_in_scene", "path"), &ViewportTexture::set_viewport_path_in_scene);
148 ClassDB::bind_method(D_METHOD("get_viewport_path_in_scene"), &ViewportTexture::get_viewport_path_in_scene);
149
150 ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "viewport_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Viewport", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT), "set_viewport_path_in_scene", "get_viewport_path_in_scene");
151 }
152
ViewportTexture()153 ViewportTexture::ViewportTexture() {
154
155 vp = NULL;
156 flags = 0;
157 set_local_to_scene(true);
158 proxy = VS::get_singleton()->texture_create();
159 }
160
~ViewportTexture()161 ViewportTexture::~ViewportTexture() {
162
163 if (vp) {
164 vp->viewport_textures.erase(this);
165 }
166
167 VS::get_singleton()->free(proxy);
168 }
169
170 /////////////////////////////////////
171
172 class TooltipPanel : public PanelContainer {
173
174 GDCLASS(TooltipPanel, PanelContainer);
175
176 public:
TooltipPanel()177 TooltipPanel(){};
178 };
179
180 class TooltipLabel : public Label {
181
182 GDCLASS(TooltipLabel, Label);
183
184 public:
TooltipLabel()185 TooltipLabel(){};
186 };
187
GUI()188 Viewport::GUI::GUI() {
189
190 dragging = false;
191 mouse_focus = NULL;
192 mouse_click_grabber = NULL;
193 mouse_focus_mask = 0;
194 key_focus = NULL;
195 mouse_over = NULL;
196
197 tooltip = NULL;
198 tooltip_popup = NULL;
199 tooltip_label = NULL;
200 subwindow_visibility_dirty = false;
201 subwindow_order_dirty = false;
202 }
203
204 /////////////////////////////////////
205
_update_stretch_transform()206 void Viewport::_update_stretch_transform() {
207
208 if (size_override_stretch && size_override) {
209
210 stretch_transform = Transform2D();
211 Size2 scale = size / (size_override_size + size_override_margin * 2);
212 stretch_transform.scale(scale);
213 stretch_transform.elements[2] = size_override_margin * scale;
214
215 } else {
216
217 stretch_transform = Transform2D();
218 }
219
220 _update_global_transform();
221 }
222
update_worlds()223 void Viewport::update_worlds() {
224
225 if (!is_inside_tree())
226 return;
227
228 Rect2 abstracted_rect = Rect2(Vector2(), get_visible_rect().size);
229 Rect2 xformed_rect = (global_canvas_transform * canvas_transform).affine_inverse().xform(abstracted_rect);
230 find_world_2d()->_update_viewport(this, xformed_rect);
231 find_world_2d()->_update();
232
233 find_world()->_update(get_tree()->get_frame());
234 }
235
_collision_object_input_event(CollisionObject * p_object,Camera * p_camera,const Ref<InputEvent> & p_input_event,const Vector3 & p_pos,const Vector3 & p_normal,int p_shape)236 void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
237
238 Transform object_transform = p_object->get_global_transform();
239 Transform camera_transform = p_camera->get_global_transform();
240 ObjectID id = p_object->get_instance_id();
241
242 //avoid sending the fake event unnecessarily if nothing really changed in the context
243 if (object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) {
244 Ref<InputEventMouseMotion> mm = p_input_event;
245 if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) {
246 return; //discarded
247 }
248 }
249 p_object->_input_event(camera, p_input_event, p_pos, p_normal, p_shape);
250 physics_last_object_transform = object_transform;
251 physics_last_camera_transform = camera_transform;
252 physics_last_id = id;
253 }
254
_own_world_changed()255 void Viewport::_own_world_changed() {
256 ERR_FAIL_COND(world.is_null());
257 ERR_FAIL_COND(own_world.is_null());
258
259 if (is_inside_tree()) {
260 _propagate_exit_world(this);
261 }
262
263 own_world = world->duplicate();
264
265 if (is_inside_tree()) {
266 _propagate_enter_world(this);
267 }
268
269 if (is_inside_tree()) {
270 VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
271 }
272
273 _update_listener();
274 }
275
_notification(int p_what)276 void Viewport::_notification(int p_what) {
277
278 switch (p_what) {
279
280 case NOTIFICATION_ENTER_TREE: {
281
282 if (get_parent()) {
283 parent = get_parent()->get_viewport();
284 VisualServer::get_singleton()->viewport_set_parent_viewport(viewport, parent->get_viewport_rid());
285 } else {
286 parent = NULL;
287 }
288
289 current_canvas = find_world_2d()->get_canvas();
290 VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
291 VisualServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
292
293 _update_listener();
294 _update_listener_2d();
295
296 find_world_2d()->_register_viewport(this, Rect2());
297
298 add_to_group("_viewports");
299 if (get_tree()->is_debugging_collisions_hint()) {
300 //2D
301 Physics2DServer::get_singleton()->space_set_debug_contacts(find_world_2d()->get_space(), get_tree()->get_collision_debug_contact_count());
302 contact_2d_debug = VisualServer::get_singleton()->canvas_item_create();
303 VisualServer::get_singleton()->canvas_item_set_parent(contact_2d_debug, find_world_2d()->get_canvas());
304 //3D
305 PhysicsServer::get_singleton()->space_set_debug_contacts(find_world()->get_space(), get_tree()->get_collision_debug_contact_count());
306 contact_3d_debug_multimesh = VisualServer::get_singleton()->multimesh_create();
307 VisualServer::get_singleton()->multimesh_allocate(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), VS::MULTIMESH_TRANSFORM_3D, VS::MULTIMESH_COLOR_8BIT);
308 VisualServer::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, 0);
309 VisualServer::get_singleton()->multimesh_set_mesh(contact_3d_debug_multimesh, get_tree()->get_debug_contact_mesh()->get_rid());
310 contact_3d_debug_instance = VisualServer::get_singleton()->instance_create();
311 VisualServer::get_singleton()->instance_set_base(contact_3d_debug_instance, contact_3d_debug_multimesh);
312 VisualServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance, find_world()->get_scenario());
313 //VisualServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance, VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS, true);
314 }
315
316 VS::get_singleton()->viewport_set_active(viewport, true);
317 } break;
318 case NOTIFICATION_READY: {
319 #ifndef _3D_DISABLED
320 if (listeners.size() && !listener) {
321 Listener *first = NULL;
322 for (Set<Listener *>::Element *E = listeners.front(); E; E = E->next()) {
323
324 if (first == NULL || first->is_greater_than(E->get())) {
325 first = E->get();
326 }
327 }
328
329 if (first)
330 first->make_current();
331 }
332
333 if (cameras.size() && !camera) {
334 //there are cameras but no current camera, pick first in tree and make it current
335 Camera *first = NULL;
336 for (Set<Camera *>::Element *E = cameras.front(); E; E = E->next()) {
337
338 if (first == NULL || first->is_greater_than(E->get())) {
339 first = E->get();
340 }
341 }
342
343 if (first)
344 first->make_current();
345 }
346 #endif
347
348 // Enable processing for tooltips, collision debugging, physics object picking, etc.
349 set_process_internal(true);
350 set_physics_process_internal(true);
351
352 } break;
353 case NOTIFICATION_EXIT_TREE: {
354
355 _gui_cancel_tooltip();
356 if (world_2d.is_valid())
357 world_2d->_remove_viewport(this);
358
359 VisualServer::get_singleton()->viewport_set_scenario(viewport, RID());
360 // SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID());
361 VisualServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
362 if (contact_2d_debug.is_valid()) {
363 VisualServer::get_singleton()->free(contact_2d_debug);
364 contact_2d_debug = RID();
365 }
366
367 if (contact_3d_debug_multimesh.is_valid()) {
368 VisualServer::get_singleton()->free(contact_3d_debug_multimesh);
369 VisualServer::get_singleton()->free(contact_3d_debug_instance);
370 contact_3d_debug_instance = RID();
371 contact_3d_debug_multimesh = RID();
372 }
373
374 remove_from_group("_viewports");
375
376 VS::get_singleton()->viewport_set_active(viewport, false);
377
378 } break;
379 case NOTIFICATION_INTERNAL_PROCESS: {
380
381 if (gui.tooltip_timer >= 0) {
382 gui.tooltip_timer -= get_process_delta_time();
383 if (gui.tooltip_timer < 0) {
384 _gui_show_tooltip();
385 }
386 }
387
388 } break;
389 case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
390
391 if (get_tree()->is_debugging_collisions_hint() && contact_2d_debug.is_valid()) {
392
393 VisualServer::get_singleton()->canvas_item_clear(contact_2d_debug);
394 VisualServer::get_singleton()->canvas_item_set_draw_index(contact_2d_debug, 0xFFFFF); //very high index
395
396 Vector<Vector2> points = Physics2DServer::get_singleton()->space_get_contacts(find_world_2d()->get_space());
397 int point_count = Physics2DServer::get_singleton()->space_get_contact_count(find_world_2d()->get_space());
398 Color ccol = get_tree()->get_debug_collision_contact_color();
399
400 for (int i = 0; i < point_count; i++) {
401
402 VisualServer::get_singleton()->canvas_item_add_rect(contact_2d_debug, Rect2(points[i] - Vector2(2, 2), Vector2(5, 5)), ccol);
403 }
404 }
405
406 if (get_tree()->is_debugging_collisions_hint() && contact_3d_debug_multimesh.is_valid()) {
407
408 Vector<Vector3> points = PhysicsServer::get_singleton()->space_get_contacts(find_world()->get_space());
409 int point_count = PhysicsServer::get_singleton()->space_get_contact_count(find_world()->get_space());
410
411 VS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count);
412 }
413
414 if (physics_object_picking && (to_screen_rect == Rect2() || Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED)) {
415
416 #ifndef _3D_DISABLED
417 Vector2 last_pos(1e20, 1e20);
418 CollisionObject *last_object = NULL;
419 ObjectID last_id = 0;
420 #endif
421 PhysicsDirectSpaceState::RayResult result;
422 Physics2DDirectSpaceState *ss2d = Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
423
424 if (physics_has_last_mousepos) {
425 // if no mouse event exists, create a motion one. This is necessary because objects or camera may have moved.
426 // while this extra event is sent, it is checked if both camera and last object and last ID did not move. If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame
427 bool has_mouse_event = false;
428 for (List<Ref<InputEvent> >::Element *E = physics_picking_events.front(); E; E = E->next()) {
429 Ref<InputEventMouse> m = E->get();
430 if (m.is_valid()) {
431 has_mouse_event = true;
432 break;
433 }
434 }
435
436 if (!has_mouse_event) {
437 Ref<InputEventMouseMotion> mm;
438 mm.instance();
439 mm->set_device(InputEvent::DEVICE_ID_INTERNAL);
440 mm->set_global_position(physics_last_mousepos);
441 mm->set_position(physics_last_mousepos);
442 mm->set_alt(physics_last_mouse_state.alt);
443 mm->set_shift(physics_last_mouse_state.shift);
444 mm->set_control(physics_last_mouse_state.control);
445 mm->set_metakey(physics_last_mouse_state.meta);
446 mm->set_button_mask(physics_last_mouse_state.mouse_mask);
447 physics_picking_events.push_back(mm);
448 }
449 }
450
451 while (physics_picking_events.size()) {
452
453 Ref<InputEvent> ev = physics_picking_events.front()->get();
454 physics_picking_events.pop_front();
455
456 Vector2 pos;
457 bool is_mouse = false;
458
459 Ref<InputEventMouseMotion> mm = ev;
460
461 if (mm.is_valid()) {
462
463 pos = mm->get_position();
464 is_mouse = true;
465
466 physics_has_last_mousepos = true;
467 physics_last_mousepos = pos;
468 physics_last_mouse_state.alt = mm->get_alt();
469 physics_last_mouse_state.shift = mm->get_shift();
470 physics_last_mouse_state.control = mm->get_control();
471 physics_last_mouse_state.meta = mm->get_metakey();
472 physics_last_mouse_state.mouse_mask = mm->get_button_mask();
473 }
474
475 Ref<InputEventMouseButton> mb = ev;
476
477 if (mb.is_valid()) {
478
479 pos = mb->get_position();
480 is_mouse = true;
481
482 physics_has_last_mousepos = true;
483 physics_last_mousepos = pos;
484 physics_last_mouse_state.alt = mb->get_alt();
485 physics_last_mouse_state.shift = mb->get_shift();
486 physics_last_mouse_state.control = mb->get_control();
487 physics_last_mouse_state.meta = mb->get_metakey();
488
489 if (mb->is_pressed()) {
490 physics_last_mouse_state.mouse_mask |= (1 << (mb->get_button_index() - 1));
491 } else {
492 physics_last_mouse_state.mouse_mask &= ~(1 << (mb->get_button_index() - 1));
493
494 // If touch mouse raised, assume we don't know last mouse pos until new events come
495 if (mb->get_device() == InputEvent::DEVICE_ID_TOUCH_MOUSE) {
496 physics_has_last_mousepos = false;
497 }
498 }
499 }
500
501 Ref<InputEventKey> k = ev;
502 if (k.is_valid()) {
503 //only for mask
504 physics_last_mouse_state.alt = k->get_alt();
505 physics_last_mouse_state.shift = k->get_shift();
506 physics_last_mouse_state.control = k->get_control();
507 physics_last_mouse_state.meta = k->get_metakey();
508 continue;
509 }
510
511 Ref<InputEventScreenDrag> sd = ev;
512
513 if (sd.is_valid()) {
514 pos = sd->get_position();
515 }
516
517 Ref<InputEventScreenTouch> st = ev;
518
519 if (st.is_valid()) {
520 pos = st->get_position();
521 }
522
523 if (ss2d) {
524 //send to 2D
525
526 uint64_t frame = get_tree()->get_frame();
527
528 Physics2DDirectSpaceState::ShapeResult res[64];
529 for (Set<CanvasLayer *>::Element *E = canvas_layers.front(); E; E = E->next()) {
530 Transform2D canvas_transform;
531 ObjectID canvas_layer_id;
532 if (E->get()) {
533 // A descendant CanvasLayer
534 canvas_transform = E->get()->get_transform();
535 canvas_layer_id = E->get()->get_instance_id();
536 } else {
537 // This Viewport's builtin canvas
538 canvas_transform = get_canvas_transform();
539 canvas_layer_id = 0;
540 }
541
542 Vector2 point = canvas_transform.affine_inverse().xform(pos);
543
544 int rc = ss2d->intersect_point_on_canvas(point, canvas_layer_id, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true);
545 for (int i = 0; i < rc; i++) {
546
547 if (res[i].collider_id && res[i].collider) {
548 CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider);
549 if (co) {
550 bool send_event = true;
551 if (is_mouse) {
552 Map<ObjectID, uint64_t>::Element *F = physics_2d_mouseover.find(res[i].collider_id);
553
554 if (!F) {
555 physics_2d_mouseover.insert(res[i].collider_id, frame);
556 co->_mouse_enter();
557 } else {
558 F->get() = frame;
559 // It was already hovered, so don't send the event if it's faked
560 if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) {
561 send_event = false;
562 }
563 }
564 }
565
566 if (send_event) {
567 co->_input_event(this, ev, res[i].shape);
568 }
569 }
570 }
571 }
572 }
573
574 if (is_mouse) {
575 List<Map<ObjectID, uint64_t>::Element *> to_erase;
576
577 for (Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.front(); E; E = E->next()) {
578 if (E->get() != frame) {
579 Object *o = ObjectDB::get_instance(E->key());
580 if (o) {
581
582 CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
583 if (co) {
584 co->_mouse_exit();
585 }
586 }
587 to_erase.push_back(E);
588 }
589 }
590
591 while (to_erase.size()) {
592 physics_2d_mouseover.erase(to_erase.front()->get());
593 to_erase.pop_front();
594 }
595 }
596 }
597
598 #ifndef _3D_DISABLED
599 bool captured = false;
600
601 if (physics_object_capture != 0) {
602
603 CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_capture));
604 if (co && camera) {
605 _collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0);
606 captured = true;
607 if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) {
608 physics_object_capture = 0;
609 }
610
611 } else {
612 physics_object_capture = 0;
613 }
614 }
615
616 if (captured) {
617 //none
618 } else if (pos == last_pos) {
619
620 if (last_id) {
621 if (ObjectDB::get_instance(last_id) && last_object) {
622 //good, exists
623 _collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape);
624 if (last_object->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
625 physics_object_capture = last_id;
626 }
627 }
628 }
629 } else {
630
631 if (camera) {
632
633 Vector3 from = camera->project_ray_origin(pos);
634 Vector3 dir = camera->project_ray_normal(pos);
635
636 PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space());
637 if (space) {
638
639 bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true);
640 ObjectID new_collider = 0;
641 if (col) {
642
643 CollisionObject *co = Object::cast_to<CollisionObject>(result.collider);
644 if (co) {
645
646 _collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape);
647 last_object = co;
648 last_id = result.collider_id;
649 new_collider = last_id;
650 if (co->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
651 physics_object_capture = last_id;
652 }
653 }
654 }
655
656 if (is_mouse && new_collider != physics_object_over) {
657
658 if (physics_object_over) {
659
660 CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
661 if (co) {
662 co->_mouse_exit();
663 }
664 }
665
666 if (new_collider) {
667
668 CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(new_collider));
669 if (co) {
670 co->_mouse_enter();
671 }
672 }
673
674 physics_object_over = new_collider;
675 }
676 }
677
678 last_pos = pos;
679 }
680 }
681 #endif
682 }
683 }
684
685 } break;
686 case SceneTree::NOTIFICATION_WM_MOUSE_EXIT:
687 case SceneTree::NOTIFICATION_WM_FOCUS_OUT: {
688
689 _drop_physics_mouseover();
690
691 if (gui.mouse_focus) {
692 //if mouse is being pressed, send a release event
693 _drop_mouse_focus();
694 }
695 } break;
696 }
697 }
698
get_viewport_rid() const699 RID Viewport::get_viewport_rid() const {
700
701 return viewport;
702 }
703
set_use_arvr(bool p_use_arvr)704 void Viewport::set_use_arvr(bool p_use_arvr) {
705 arvr = p_use_arvr;
706
707 VS::get_singleton()->viewport_set_use_arvr(viewport, arvr);
708 }
709
use_arvr()710 bool Viewport::use_arvr() {
711 return arvr;
712 }
713
update_canvas_items()714 void Viewport::update_canvas_items() {
715 if (!is_inside_tree())
716 return;
717
718 _update_canvas_items(this);
719 }
720
set_size(const Size2 & p_size)721 void Viewport::set_size(const Size2 &p_size) {
722
723 if (size == p_size.floor())
724 return;
725 size = p_size.floor();
726 VS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
727
728 _update_stretch_transform();
729
730 emit_signal("size_changed");
731 }
732
get_visible_rect() const733 Rect2 Viewport::get_visible_rect() const {
734
735 Rect2 r;
736
737 if (size == Size2()) {
738 r = Rect2(Point2(), OS::get_singleton()->get_window_size());
739 } else {
740 r = Rect2(Point2(), size);
741 }
742
743 if (size_override) {
744 r.size = size_override_size;
745 }
746
747 return r;
748 }
749
get_size() const750 Size2 Viewport::get_size() const {
751
752 return size;
753 }
754
_update_listener()755 void Viewport::_update_listener() {
756 /*
757 if (is_inside_tree() && audio_listener && (camera || listener) && (!get_parent() || (Object::cast_to<Control>(get_parent()) && Object::cast_to<Control>(get_parent())->is_visible_in_tree()))) {
758 SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, find_world()->get_sound_space());
759 } else {
760 SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID());
761 }
762 */
763 }
764
_update_listener_2d()765 void Viewport::_update_listener_2d() {
766
767 /*
768 if (is_inside_tree() && audio_listener && (!get_parent() || (Object::cast_to<Control>(get_parent()) && Object::cast_to<Control>(get_parent())->is_visible_in_tree())))
769 SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, find_world_2d()->get_sound_space());
770 else
771 SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, RID());
772 */
773 }
774
set_as_audio_listener(bool p_enable)775 void Viewport::set_as_audio_listener(bool p_enable) {
776
777 if (p_enable == audio_listener)
778 return;
779
780 audio_listener = p_enable;
781 _update_listener();
782 }
783
is_audio_listener() const784 bool Viewport::is_audio_listener() const {
785
786 return audio_listener;
787 }
788
set_as_audio_listener_2d(bool p_enable)789 void Viewport::set_as_audio_listener_2d(bool p_enable) {
790
791 if (p_enable == audio_listener_2d)
792 return;
793
794 audio_listener_2d = p_enable;
795
796 _update_listener_2d();
797 }
798
is_audio_listener_2d() const799 bool Viewport::is_audio_listener_2d() const {
800
801 return audio_listener_2d;
802 }
803
enable_canvas_transform_override(bool p_enable)804 void Viewport::enable_canvas_transform_override(bool p_enable) {
805 if (override_canvas_transform == p_enable) {
806 return;
807 }
808
809 override_canvas_transform = p_enable;
810 if (p_enable) {
811 VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
812 } else {
813 VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
814 }
815 }
816
is_canvas_transform_override_enbled() const817 bool Viewport::is_canvas_transform_override_enbled() const {
818 return override_canvas_transform;
819 }
820
set_canvas_transform_override(const Transform2D & p_transform)821 void Viewport::set_canvas_transform_override(const Transform2D &p_transform) {
822 if (canvas_transform_override == p_transform) {
823 return;
824 }
825
826 canvas_transform_override = p_transform;
827 if (override_canvas_transform) {
828 VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
829 }
830 }
831
get_canvas_transform_override() const832 Transform2D Viewport::get_canvas_transform_override() const {
833 return canvas_transform_override;
834 }
835
set_canvas_transform(const Transform2D & p_transform)836 void Viewport::set_canvas_transform(const Transform2D &p_transform) {
837
838 canvas_transform = p_transform;
839
840 if (!override_canvas_transform) {
841 VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
842 }
843 }
844
get_canvas_transform() const845 Transform2D Viewport::get_canvas_transform() const {
846
847 return canvas_transform;
848 }
849
_update_global_transform()850 void Viewport::_update_global_transform() {
851
852 Transform2D sxform = stretch_transform * global_canvas_transform;
853
854 VisualServer::get_singleton()->viewport_set_global_canvas_transform(viewport, sxform);
855 }
856
set_global_canvas_transform(const Transform2D & p_transform)857 void Viewport::set_global_canvas_transform(const Transform2D &p_transform) {
858
859 global_canvas_transform = p_transform;
860
861 _update_global_transform();
862 }
863
get_global_canvas_transform() const864 Transform2D Viewport::get_global_canvas_transform() const {
865
866 return global_canvas_transform;
867 }
868
_listener_transform_changed_notify()869 void Viewport::_listener_transform_changed_notify() {
870
871 #ifndef _3D_DISABLED
872 //if (listener)
873 // SpatialSoundServer::get_singleton()->listener_set_transform(internal_listener, listener->get_listener_transform());
874 #endif
875 }
876
_listener_set(Listener * p_listener)877 void Viewport::_listener_set(Listener *p_listener) {
878
879 #ifndef _3D_DISABLED
880
881 if (listener == p_listener)
882 return;
883
884 listener = p_listener;
885
886 _update_listener();
887 _listener_transform_changed_notify();
888 #endif
889 }
890
_listener_add(Listener * p_listener)891 bool Viewport::_listener_add(Listener *p_listener) {
892
893 listeners.insert(p_listener);
894 return listeners.size() == 1;
895 }
896
_listener_remove(Listener * p_listener)897 void Viewport::_listener_remove(Listener *p_listener) {
898
899 listeners.erase(p_listener);
900 if (listener == p_listener) {
901 listener = NULL;
902 }
903 }
904
905 #ifndef _3D_DISABLED
_listener_make_next_current(Listener * p_exclude)906 void Viewport::_listener_make_next_current(Listener *p_exclude) {
907
908 if (listeners.size() > 0) {
909 for (Set<Listener *>::Element *E = listeners.front(); E; E = E->next()) {
910
911 if (p_exclude == E->get())
912 continue;
913 if (!E->get()->is_inside_tree())
914 continue;
915 if (listener != NULL)
916 return;
917
918 E->get()->make_current();
919 }
920 } else {
921 // Attempt to reset listener to the camera position
922 if (camera != NULL) {
923 _update_listener();
924 _camera_transform_changed_notify();
925 }
926 }
927 }
928 #endif
929
_camera_transform_changed_notify()930 void Viewport::_camera_transform_changed_notify() {
931
932 #ifndef _3D_DISABLED
933 // If there is an active listener in the scene, it takes priority over the camera
934 // if (camera && !listener)
935 // SpatialSoundServer::get_singleton()->listener_set_transform(internal_listener, camera->get_camera_transform());
936 #endif
937 }
938
_camera_set(Camera * p_camera)939 void Viewport::_camera_set(Camera *p_camera) {
940
941 #ifndef _3D_DISABLED
942
943 if (camera == p_camera)
944 return;
945
946 if (camera) {
947 camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
948 }
949 camera = p_camera;
950 if (!camera_override) {
951 if (camera)
952 VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
953 else
954 VisualServer::get_singleton()->viewport_attach_camera(viewport, RID());
955 }
956
957 if (camera) {
958 camera->notification(Camera::NOTIFICATION_BECAME_CURRENT);
959 }
960
961 _update_listener();
962 _camera_transform_changed_notify();
963 #endif
964 }
965
_camera_add(Camera * p_camera)966 bool Viewport::_camera_add(Camera *p_camera) {
967
968 cameras.insert(p_camera);
969 return cameras.size() == 1;
970 }
971
_camera_remove(Camera * p_camera)972 void Viewport::_camera_remove(Camera *p_camera) {
973
974 cameras.erase(p_camera);
975 if (camera == p_camera) {
976 camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
977 camera = NULL;
978 }
979 }
980
981 #ifndef _3D_DISABLED
_camera_make_next_current(Camera * p_exclude)982 void Viewport::_camera_make_next_current(Camera *p_exclude) {
983
984 for (Set<Camera *>::Element *E = cameras.front(); E; E = E->next()) {
985
986 if (p_exclude == E->get())
987 continue;
988 if (!E->get()->is_inside_tree())
989 continue;
990 if (camera != NULL)
991 return;
992
993 E->get()->make_current();
994 }
995 }
996 #endif
997
_canvas_layer_add(CanvasLayer * p_canvas_layer)998 void Viewport::_canvas_layer_add(CanvasLayer *p_canvas_layer) {
999
1000 canvas_layers.insert(p_canvas_layer);
1001 }
1002
_canvas_layer_remove(CanvasLayer * p_canvas_layer)1003 void Viewport::_canvas_layer_remove(CanvasLayer *p_canvas_layer) {
1004
1005 canvas_layers.erase(p_canvas_layer);
1006 }
1007
set_transparent_background(bool p_enable)1008 void Viewport::set_transparent_background(bool p_enable) {
1009
1010 transparent_bg = p_enable;
1011 VS::get_singleton()->viewport_set_transparent_background(viewport, p_enable);
1012 }
1013
has_transparent_background() const1014 bool Viewport::has_transparent_background() const {
1015
1016 return transparent_bg;
1017 }
1018
set_world_2d(const Ref<World2D> & p_world_2d)1019 void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
1020 if (world_2d == p_world_2d)
1021 return;
1022
1023 if (parent && parent->find_world_2d() == p_world_2d) {
1024 WARN_PRINT("Unable to use parent world as world_2d");
1025 return;
1026 }
1027
1028 if (is_inside_tree()) {
1029 find_world_2d()->_remove_viewport(this);
1030 VisualServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
1031 }
1032
1033 if (p_world_2d.is_valid())
1034 world_2d = p_world_2d;
1035 else {
1036 WARN_PRINT("Invalid world");
1037 world_2d = Ref<World2D>(memnew(World2D));
1038 }
1039
1040 _update_listener_2d();
1041
1042 if (is_inside_tree()) {
1043 current_canvas = find_world_2d()->get_canvas();
1044 VisualServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
1045 find_world_2d()->_register_viewport(this, Rect2());
1046 }
1047 }
1048
find_world_2d() const1049 Ref<World2D> Viewport::find_world_2d() const {
1050
1051 if (world_2d.is_valid())
1052 return world_2d;
1053 else if (parent)
1054 return parent->find_world_2d();
1055 else
1056 return Ref<World2D>();
1057 }
1058
_propagate_enter_world(Node * p_node)1059 void Viewport::_propagate_enter_world(Node *p_node) {
1060
1061 if (p_node != this) {
1062
1063 if (!p_node->is_inside_tree()) //may not have entered scene yet
1064 return;
1065
1066 if (Object::cast_to<Spatial>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
1067
1068 p_node->notification(Spatial::NOTIFICATION_ENTER_WORLD);
1069 } else {
1070 Viewport *v = Object::cast_to<Viewport>(p_node);
1071 if (v) {
1072
1073 if (v->world.is_valid() || v->own_world.is_valid())
1074 return;
1075 }
1076 }
1077 }
1078
1079 for (int i = 0; i < p_node->get_child_count(); i++) {
1080
1081 _propagate_enter_world(p_node->get_child(i));
1082 }
1083 }
1084
_propagate_viewport_notification(Node * p_node,int p_what)1085 void Viewport::_propagate_viewport_notification(Node *p_node, int p_what) {
1086
1087 p_node->notification(p_what);
1088 for (int i = 0; i < p_node->get_child_count(); i++) {
1089 Node *c = p_node->get_child(i);
1090 if (Object::cast_to<Viewport>(c))
1091 continue;
1092 _propagate_viewport_notification(c, p_what);
1093 }
1094 }
1095
_propagate_exit_world(Node * p_node)1096 void Viewport::_propagate_exit_world(Node *p_node) {
1097
1098 if (p_node != this) {
1099
1100 if (!p_node->is_inside_tree()) //may have exited scene already
1101 return;
1102
1103 if (Object::cast_to<Spatial>(p_node) || Object::cast_to<WorldEnvironment>(p_node)) {
1104
1105 p_node->notification(Spatial::NOTIFICATION_EXIT_WORLD);
1106 } else {
1107 Viewport *v = Object::cast_to<Viewport>(p_node);
1108 if (v) {
1109
1110 if (v->world.is_valid() || v->own_world.is_valid())
1111 return;
1112 }
1113 }
1114 }
1115
1116 for (int i = 0; i < p_node->get_child_count(); i++) {
1117
1118 _propagate_exit_world(p_node->get_child(i));
1119 }
1120 }
1121
set_world(const Ref<World> & p_world)1122 void Viewport::set_world(const Ref<World> &p_world) {
1123
1124 if (world == p_world)
1125 return;
1126
1127 if (is_inside_tree())
1128 _propagate_exit_world(this);
1129
1130 if (own_world.is_valid() && world.is_valid()) {
1131 world->disconnect(CoreStringNames::get_singleton()->changed, this, "_own_world_changed");
1132 }
1133
1134 world = p_world;
1135
1136 if (own_world.is_valid()) {
1137 if (world.is_valid()) {
1138 own_world = world->duplicate();
1139 world->connect(CoreStringNames::get_singleton()->changed, this, "_own_world_changed");
1140 } else {
1141 own_world = Ref<World>(memnew(World));
1142 }
1143 }
1144
1145 if (is_inside_tree())
1146 _propagate_enter_world(this);
1147
1148 if (is_inside_tree()) {
1149 VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
1150 }
1151
1152 _update_listener();
1153 }
1154
get_world() const1155 Ref<World> Viewport::get_world() const {
1156
1157 return world;
1158 }
1159
get_world_2d() const1160 Ref<World2D> Viewport::get_world_2d() const {
1161
1162 return world_2d;
1163 }
1164
find_world() const1165 Ref<World> Viewport::find_world() const {
1166
1167 if (own_world.is_valid())
1168 return own_world;
1169 else if (world.is_valid())
1170 return world;
1171 else if (parent)
1172 return parent->find_world();
1173 else
1174 return Ref<World>();
1175 }
1176
get_listener() const1177 Listener *Viewport::get_listener() const {
1178
1179 return listener;
1180 }
1181
get_camera() const1182 Camera *Viewport::get_camera() const {
1183 return camera;
1184 }
1185
enable_camera_override(bool p_enable)1186 void Viewport::enable_camera_override(bool p_enable) {
1187
1188 #ifndef _3D_DISABLED
1189 if (p_enable == camera_override) {
1190 return;
1191 }
1192
1193 if (p_enable) {
1194 camera_override.rid = VisualServer::get_singleton()->camera_create();
1195 } else {
1196 VisualServer::get_singleton()->free(camera_override.rid);
1197 camera_override.rid = RID();
1198 }
1199
1200 if (p_enable) {
1201 VisualServer::get_singleton()->viewport_attach_camera(viewport, camera_override.rid);
1202 } else if (camera) {
1203 VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
1204 } else {
1205 VisualServer::get_singleton()->viewport_attach_camera(viewport, RID());
1206 }
1207 #endif
1208 }
1209
is_camera_override_enabled() const1210 bool Viewport::is_camera_override_enabled() const {
1211 return camera_override;
1212 }
1213
set_camera_override_transform(const Transform & p_transform)1214 void Viewport::set_camera_override_transform(const Transform &p_transform) {
1215 if (camera_override) {
1216 camera_override.transform = p_transform;
1217 VisualServer::get_singleton()->camera_set_transform(camera_override.rid, p_transform);
1218 }
1219 }
1220
get_camera_override_transform() const1221 Transform Viewport::get_camera_override_transform() const {
1222 if (camera_override) {
1223 return camera_override.transform;
1224 }
1225
1226 return Transform();
1227 }
1228
set_camera_override_perspective(float p_fovy_degrees,float p_z_near,float p_z_far)1229 void Viewport::set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
1230 if (camera_override) {
1231 if (camera_override.fov == p_fovy_degrees && camera_override.z_near == p_z_near &&
1232 camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_PERSPECTIVE)
1233 return;
1234
1235 camera_override.fov = p_fovy_degrees;
1236 camera_override.z_near = p_z_near;
1237 camera_override.z_far = p_z_far;
1238 camera_override.projection = CameraOverrideData::PROJECTION_PERSPECTIVE;
1239
1240 VisualServer::get_singleton()->camera_set_perspective(camera_override.rid, camera_override.fov, camera_override.z_near, camera_override.z_far);
1241 }
1242 }
1243
set_camera_override_orthogonal(float p_size,float p_z_near,float p_z_far)1244 void Viewport::set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far) {
1245 if (camera_override) {
1246 if (camera_override.size == p_size && camera_override.z_near == p_z_near &&
1247 camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_ORTHOGONAL)
1248 return;
1249
1250 camera_override.size = p_size;
1251 camera_override.z_near = p_z_near;
1252 camera_override.z_far = p_z_far;
1253 camera_override.projection = CameraOverrideData::PROJECTION_ORTHOGONAL;
1254
1255 VisualServer::get_singleton()->camera_set_orthogonal(camera_override.rid, camera_override.size, camera_override.z_near, camera_override.z_far);
1256 }
1257 }
1258
get_final_transform() const1259 Transform2D Viewport::get_final_transform() const {
1260
1261 return stretch_transform * global_canvas_transform;
1262 }
1263
_update_canvas_items(Node * p_node)1264 void Viewport::_update_canvas_items(Node *p_node) {
1265 if (p_node != this) {
1266
1267 Viewport *vp = Object::cast_to<Viewport>(p_node);
1268 if (vp)
1269 return;
1270
1271 CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
1272 if (ci) {
1273 ci->update();
1274 }
1275 }
1276
1277 int cc = p_node->get_child_count();
1278
1279 for (int i = 0; i < cc; i++) {
1280 _update_canvas_items(p_node->get_child(i));
1281 }
1282 }
1283
set_size_override(bool p_enable,const Size2 & p_size,const Vector2 & p_margin)1284 void Viewport::set_size_override(bool p_enable, const Size2 &p_size, const Vector2 &p_margin) {
1285
1286 if (size_override == p_enable && p_size == size_override_size)
1287 return;
1288
1289 size_override = p_enable;
1290 if (p_size.x >= 0 || p_size.y >= 0) {
1291 size_override_size = p_size;
1292 }
1293 size_override_margin = p_margin;
1294
1295 _update_stretch_transform();
1296 emit_signal("size_changed");
1297 }
1298
get_size_override() const1299 Size2 Viewport::get_size_override() const {
1300
1301 return size_override_size;
1302 }
is_size_override_enabled() const1303 bool Viewport::is_size_override_enabled() const {
1304
1305 return size_override;
1306 }
set_size_override_stretch(bool p_enable)1307 void Viewport::set_size_override_stretch(bool p_enable) {
1308
1309 if (p_enable == size_override_stretch)
1310 return;
1311
1312 size_override_stretch = p_enable;
1313
1314 _update_stretch_transform();
1315 }
1316
is_size_override_stretch_enabled() const1317 bool Viewport::is_size_override_stretch_enabled() const {
1318
1319 return size_override_stretch;
1320 }
1321
set_update_mode(UpdateMode p_mode)1322 void Viewport::set_update_mode(UpdateMode p_mode) {
1323
1324 update_mode = p_mode;
1325 VS::get_singleton()->viewport_set_update_mode(viewport, VS::ViewportUpdateMode(p_mode));
1326 }
get_update_mode() const1327 Viewport::UpdateMode Viewport::get_update_mode() const {
1328
1329 return update_mode;
1330 }
1331
get_texture() const1332 Ref<ViewportTexture> Viewport::get_texture() const {
1333
1334 return default_texture;
1335 }
1336
set_vflip(bool p_enable)1337 void Viewport::set_vflip(bool p_enable) {
1338
1339 vflip = p_enable;
1340 VisualServer::get_singleton()->viewport_set_vflip(viewport, p_enable);
1341 }
1342
get_vflip() const1343 bool Viewport::get_vflip() const {
1344
1345 return vflip;
1346 }
1347
set_clear_mode(ClearMode p_mode)1348 void Viewport::set_clear_mode(ClearMode p_mode) {
1349
1350 clear_mode = p_mode;
1351 VS::get_singleton()->viewport_set_clear_mode(viewport, VS::ViewportClearMode(p_mode));
1352 }
1353
get_clear_mode() const1354 Viewport::ClearMode Viewport::get_clear_mode() const {
1355
1356 return clear_mode;
1357 }
1358
set_shadow_atlas_size(int p_size)1359 void Viewport::set_shadow_atlas_size(int p_size) {
1360
1361 if (shadow_atlas_size == p_size)
1362 return;
1363
1364 shadow_atlas_size = p_size;
1365 VS::get_singleton()->viewport_set_shadow_atlas_size(viewport, p_size);
1366 }
1367
get_shadow_atlas_size() const1368 int Viewport::get_shadow_atlas_size() const {
1369
1370 return shadow_atlas_size;
1371 }
1372
set_shadow_atlas_quadrant_subdiv(int p_quadrant,ShadowAtlasQuadrantSubdiv p_subdiv)1373 void Viewport::set_shadow_atlas_quadrant_subdiv(int p_quadrant, ShadowAtlasQuadrantSubdiv p_subdiv) {
1374
1375 ERR_FAIL_INDEX(p_quadrant, 4);
1376 ERR_FAIL_INDEX(p_subdiv, SHADOW_ATLAS_QUADRANT_SUBDIV_MAX);
1377
1378 if (shadow_atlas_quadrant_subdiv[p_quadrant] == p_subdiv)
1379 return;
1380
1381 shadow_atlas_quadrant_subdiv[p_quadrant] = p_subdiv;
1382 static const int subdiv[SHADOW_ATLAS_QUADRANT_SUBDIV_MAX] = { 0, 1, 4, 16, 64, 256, 1024 };
1383
1384 VS::get_singleton()->viewport_set_shadow_atlas_quadrant_subdivision(viewport, p_quadrant, subdiv[p_subdiv]);
1385 }
get_shadow_atlas_quadrant_subdiv(int p_quadrant) const1386 Viewport::ShadowAtlasQuadrantSubdiv Viewport::get_shadow_atlas_quadrant_subdiv(int p_quadrant) const {
1387
1388 ERR_FAIL_INDEX_V(p_quadrant, 4, SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED);
1389 return shadow_atlas_quadrant_subdiv[p_quadrant];
1390 }
1391
_get_input_pre_xform() const1392 Transform2D Viewport::_get_input_pre_xform() const {
1393
1394 Transform2D pre_xf;
1395
1396 if (to_screen_rect != Rect2()) {
1397
1398 pre_xf.elements[2] = -to_screen_rect.position;
1399 pre_xf.scale(size / to_screen_rect.size);
1400 }
1401
1402 return pre_xf;
1403 }
1404
_get_window_offset() const1405 Vector2 Viewport::_get_window_offset() const {
1406
1407 if (get_parent() && get_parent()->has_method("get_global_position")) {
1408 return get_parent()->call("get_global_position");
1409 }
1410 return Vector2();
1411 }
1412
_make_input_local(const Ref<InputEvent> & ev)1413 Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) {
1414
1415 Vector2 vp_ofs = _get_window_offset();
1416 Transform2D ai = get_final_transform().affine_inverse() * _get_input_pre_xform();
1417
1418 return ev->xformed_by(ai, -vp_ofs);
1419 }
1420
_vp_input_text(const String & p_text)1421 void Viewport::_vp_input_text(const String &p_text) {
1422
1423 if (gui.key_focus) {
1424 gui.key_focus->call("set_text", p_text);
1425 }
1426 }
1427
_vp_input(const Ref<InputEvent> & p_ev)1428 void Viewport::_vp_input(const Ref<InputEvent> &p_ev) {
1429
1430 if (disable_input)
1431 return;
1432
1433 #ifdef TOOLS_ENABLED
1434 if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
1435 return;
1436 }
1437 #endif
1438
1439 if (to_screen_rect == Rect2())
1440 return; //if render target, can't get input events
1441
1442 //this one handles system input, p_ev are in system coordinates
1443 //they are converted to viewport coordinates
1444
1445 Ref<InputEvent> ev = _make_input_local(p_ev);
1446 input(ev);
1447 }
1448
_vp_unhandled_input(const Ref<InputEvent> & p_ev)1449 void Viewport::_vp_unhandled_input(const Ref<InputEvent> &p_ev) {
1450
1451 if (disable_input)
1452 return;
1453 #ifdef TOOLS_ENABLED
1454 if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
1455 return;
1456 }
1457 #endif
1458
1459 /*
1460 if (parent_control && !parent_control->is_visible_in_tree())
1461 return;
1462 */
1463
1464 if (to_screen_rect == Rect2())
1465 return; //if render target, can't get input events
1466
1467 //this one handles system input, p_ev are in system coordinates
1468 //they are converted to viewport coordinates
1469
1470 Ref<InputEvent> ev = _make_input_local(p_ev);
1471 unhandled_input(ev);
1472 }
1473
get_mouse_position() const1474 Vector2 Viewport::get_mouse_position() const {
1475
1476 return (get_final_transform().affine_inverse() * _get_input_pre_xform()).xform(Input::get_singleton()->get_mouse_position() - _get_window_offset());
1477 }
1478
warp_mouse(const Vector2 & p_pos)1479 void Viewport::warp_mouse(const Vector2 &p_pos) {
1480
1481 Vector2 gpos = (get_final_transform().affine_inverse() * _get_input_pre_xform()).affine_inverse().xform(p_pos);
1482 Input::get_singleton()->warp_mouse_position(gpos);
1483 }
1484
_gui_prepare_subwindows()1485 void Viewport::_gui_prepare_subwindows() {
1486
1487 if (gui.subwindow_visibility_dirty) {
1488
1489 gui.subwindows.clear();
1490 for (List<Control *>::Element *E = gui.all_known_subwindows.front(); E; E = E->next()) {
1491 if (E->get()->is_visible_in_tree()) {
1492 gui.subwindows.push_back(E->get());
1493 }
1494 }
1495
1496 gui.subwindow_visibility_dirty = false;
1497 gui.subwindow_order_dirty = true;
1498 }
1499
1500 _gui_sort_subwindows();
1501 }
1502
_gui_sort_subwindows()1503 void Viewport::_gui_sort_subwindows() {
1504
1505 if (!gui.subwindow_order_dirty)
1506 return;
1507
1508 gui.modal_stack.sort_custom<Control::CComparator>();
1509 gui.subwindows.sort_custom<Control::CComparator>();
1510
1511 gui.subwindow_order_dirty = false;
1512 }
1513
_gui_sort_modal_stack()1514 void Viewport::_gui_sort_modal_stack() {
1515
1516 gui.modal_stack.sort_custom<Control::CComparator>();
1517 }
1518
_gui_sort_roots()1519 void Viewport::_gui_sort_roots() {
1520
1521 if (!gui.roots_order_dirty)
1522 return;
1523
1524 gui.roots.sort_custom<Control::CComparator>();
1525
1526 gui.roots_order_dirty = false;
1527 }
1528
_gui_cancel_tooltip()1529 void Viewport::_gui_cancel_tooltip() {
1530
1531 gui.tooltip = NULL;
1532 gui.tooltip_timer = -1;
1533 if (gui.tooltip_popup) {
1534 gui.tooltip_popup->queue_delete();
1535 gui.tooltip_popup = NULL;
1536 gui.tooltip_label = NULL;
1537 }
1538 }
1539
_gui_get_tooltip(Control * p_control,const Vector2 & p_pos,Control ** r_which)1540 String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which) {
1541
1542 Vector2 pos = p_pos;
1543 String tooltip;
1544
1545 while (p_control) {
1546
1547 tooltip = p_control->get_tooltip(pos);
1548
1549 if (r_which) {
1550 *r_which = p_control;
1551 }
1552
1553 if (tooltip != String())
1554 break;
1555 pos = p_control->get_transform().xform(pos);
1556
1557 if (p_control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
1558 break;
1559 if (p_control->is_set_as_toplevel())
1560 break;
1561
1562 p_control = p_control->get_parent_control();
1563 }
1564
1565 return tooltip;
1566 }
1567
_gui_show_tooltip()1568 void Viewport::_gui_show_tooltip() {
1569
1570 if (!gui.tooltip) {
1571 return;
1572 }
1573
1574 Control *which = NULL;
1575 String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos), &which);
1576 tooltip = tooltip.strip_edges();
1577 if (tooltip.length() == 0)
1578 return; // bye
1579
1580 if (gui.tooltip_popup) {
1581 memdelete(gui.tooltip_popup);
1582 gui.tooltip_popup = NULL;
1583 gui.tooltip_label = NULL;
1584 }
1585
1586 if (!which) {
1587 return;
1588 }
1589
1590 Control *rp = which;
1591
1592 gui.tooltip_popup = which->make_custom_tooltip(tooltip);
1593
1594 if (!gui.tooltip_popup) {
1595 gui.tooltip_popup = memnew(TooltipPanel);
1596
1597 gui.tooltip_label = memnew(TooltipLabel);
1598 gui.tooltip_popup->add_child(gui.tooltip_label);
1599
1600 Ref<StyleBox> ttp = gui.tooltip_label->get_stylebox("panel", "TooltipPanel");
1601
1602 gui.tooltip_label->set_anchor_and_margin(MARGIN_LEFT, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_LEFT));
1603 gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_TOP));
1604 gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT));
1605 gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM));
1606 gui.tooltip_label->set_text(tooltip);
1607 }
1608
1609 rp->add_child(gui.tooltip_popup);
1610 gui.tooltip_popup->force_parent_owned();
1611 gui.tooltip_popup->set_as_toplevel(true);
1612 if (gui.tooltip) // Avoids crash when rapidly switching controls.
1613 gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale());
1614
1615 Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
1616 Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_minimum_size());
1617 Rect2 vr = gui.tooltip_popup->get_viewport_rect();
1618 if (r.size.x * gui.tooltip_popup->get_scale().x + r.position.x > vr.size.x)
1619 r.position.x = vr.size.x - r.size.x * gui.tooltip_popup->get_scale().x;
1620 else if (r.position.x < 0)
1621 r.position.x = 0;
1622
1623 if (r.size.y * gui.tooltip_popup->get_scale().y + r.position.y > vr.size.y)
1624 r.position.y = vr.size.y - r.size.y * gui.tooltip_popup->get_scale().y;
1625 else if (r.position.y < 0)
1626 r.position.y = 0;
1627
1628 gui.tooltip_popup->set_global_position(r.position);
1629 gui.tooltip_popup->set_size(r.size);
1630
1631 gui.tooltip_popup->raise();
1632 gui.tooltip_popup->show();
1633 }
1634
_gui_call_input(Control * p_control,const Ref<InputEvent> & p_input)1635 void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_input) {
1636
1637 //_block();
1638
1639 Ref<InputEvent> ev = p_input;
1640
1641 //mouse wheel events can't be stopped
1642 Ref<InputEventMouseButton> mb = p_input;
1643
1644 bool cant_stop_me_now = (mb.is_valid() &&
1645 (mb->get_button_index() == BUTTON_WHEEL_DOWN ||
1646 mb->get_button_index() == BUTTON_WHEEL_UP ||
1647 mb->get_button_index() == BUTTON_WHEEL_LEFT ||
1648 mb->get_button_index() == BUTTON_WHEEL_RIGHT));
1649 Ref<InputEventPanGesture> pn = p_input;
1650 cant_stop_me_now = pn.is_valid() || cant_stop_me_now;
1651
1652 bool ismouse = ev.is_valid() || Object::cast_to<InputEventMouseMotion>(*p_input) != NULL;
1653
1654 CanvasItem *ci = p_control;
1655 while (ci) {
1656
1657 Control *control = Object::cast_to<Control>(ci);
1658 if (control) {
1659
1660 if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) {
1661 control->emit_signal(SceneStringNames::get_singleton()->gui_input, ev); //signal should be first, so it's possible to override an event (and then accept it)
1662 }
1663 if (gui.key_event_accepted)
1664 break;
1665 if (!control->is_inside_tree())
1666 break;
1667
1668 if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) {
1669 control->call_multilevel(SceneStringNames::get_singleton()->_gui_input, ev);
1670 }
1671
1672 if (!control->is_inside_tree() || control->is_set_as_toplevel())
1673 break;
1674 if (gui.key_event_accepted)
1675 break;
1676 if (!cant_stop_me_now && control->data.mouse_filter == Control::MOUSE_FILTER_STOP && ismouse)
1677 break;
1678 }
1679
1680 if (ci->is_set_as_toplevel())
1681 break;
1682
1683 ev = ev->xformed_by(ci->get_transform()); //transform event upwards
1684 ci = ci->get_parent_item();
1685 }
1686
1687 //_unblock();
1688 }
1689
_gui_call_notification(Control * p_control,int p_what)1690 void Viewport::_gui_call_notification(Control *p_control, int p_what) {
1691
1692 CanvasItem *ci = p_control;
1693 while (ci) {
1694
1695 Control *control = Object::cast_to<Control>(ci);
1696 if (control) {
1697
1698 if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) {
1699 control->notification(p_what);
1700 }
1701
1702 if (!control->is_inside_tree())
1703 break;
1704
1705 if (!control->is_inside_tree() || control->is_set_as_toplevel())
1706 break;
1707 if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
1708 break;
1709 }
1710
1711 if (ci->is_set_as_toplevel())
1712 break;
1713
1714 ci = ci->get_parent_item();
1715 }
1716
1717 //_unblock();
1718 }
_gui_find_control(const Point2 & p_global)1719 Control *Viewport::_gui_find_control(const Point2 &p_global) {
1720
1721 _gui_prepare_subwindows();
1722
1723 for (List<Control *>::Element *E = gui.subwindows.back(); E; E = E->prev()) {
1724
1725 Control *sw = E->get();
1726 if (!sw->is_visible_in_tree())
1727 continue;
1728
1729 Transform2D xform;
1730 CanvasItem *pci = sw->get_parent_item();
1731 if (pci)
1732 xform = pci->get_global_transform_with_canvas();
1733 else
1734 xform = sw->get_canvas_transform();
1735
1736 Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform);
1737 if (ret)
1738 return ret;
1739 }
1740
1741 _gui_sort_roots();
1742
1743 for (List<Control *>::Element *E = gui.roots.back(); E; E = E->prev()) {
1744
1745 Control *sw = E->get();
1746 if (!sw->is_visible_in_tree())
1747 continue;
1748
1749 Transform2D xform;
1750 CanvasItem *pci = sw->get_parent_item();
1751 if (pci)
1752 xform = pci->get_global_transform_with_canvas();
1753 else
1754 xform = sw->get_canvas_transform();
1755
1756 Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform);
1757 if (ret)
1758 return ret;
1759 }
1760
1761 return NULL;
1762 }
1763
_gui_find_control_at_pos(CanvasItem * p_node,const Point2 & p_global,const Transform2D & p_xform,Transform2D & r_inv_xform)1764 Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) {
1765
1766 if (Object::cast_to<Viewport>(p_node))
1767 return NULL;
1768
1769 //subwindows first!!
1770
1771 if (!p_node->is_visible()) {
1772 //return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform);
1773 return NULL; //canvas item hidden, discard
1774 }
1775
1776 Transform2D matrix = p_xform * p_node->get_transform();
1777 // matrix.basis_determinant() == 0.0f implies that node does not exist on scene
1778 if (matrix.basis_determinant() == 0.0f)
1779 return NULL;
1780
1781 Control *c = Object::cast_to<Control>(p_node);
1782
1783 if (!c || !c->clips_input() || c->has_point(matrix.affine_inverse().xform(p_global))) {
1784
1785 for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
1786
1787 if (p_node == gui.tooltip_popup)
1788 continue;
1789
1790 CanvasItem *ci = Object::cast_to<CanvasItem>(p_node->get_child(i));
1791 if (!ci || ci->is_set_as_toplevel())
1792 continue;
1793
1794 Control *ret = _gui_find_control_at_pos(ci, p_global, matrix, r_inv_xform);
1795 if (ret)
1796 return ret;
1797 }
1798 }
1799
1800 if (!c)
1801 return NULL;
1802
1803 matrix.affine_invert();
1804
1805 //conditions for considering this as a valid control for return
1806 if (c->data.mouse_filter != Control::MOUSE_FILTER_IGNORE && c->has_point(matrix.xform(p_global)) && (!gui.drag_preview || (c != gui.drag_preview && !gui.drag_preview->is_a_parent_of(c)))) {
1807 r_inv_xform = matrix;
1808 return c;
1809 } else
1810 return NULL;
1811 }
1812
_gui_drop(Control * p_at_control,Point2 p_at_pos,bool p_just_check)1813 bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check) {
1814
1815 { //attempt grab, try parent controls too
1816 CanvasItem *ci = p_at_control;
1817 while (ci) {
1818
1819 Control *control = Object::cast_to<Control>(ci);
1820 if (control) {
1821
1822 if (control->can_drop_data(p_at_pos, gui.drag_data)) {
1823 if (!p_just_check) {
1824 control->drop_data(p_at_pos, gui.drag_data);
1825 }
1826
1827 return true;
1828 }
1829
1830 if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
1831 break;
1832 }
1833
1834 p_at_pos = ci->get_transform().xform(p_at_pos);
1835
1836 if (ci->is_set_as_toplevel())
1837 break;
1838
1839 ci = ci->get_parent_item();
1840 }
1841 }
1842
1843 return false;
1844 }
1845
_gui_input_event(Ref<InputEvent> p_event)1846 void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
1847
1848 ERR_FAIL_COND(p_event.is_null())
1849
1850 //?
1851 /*
1852 if (!is_visible()) {
1853 return; //simple and plain
1854 }
1855 */
1856
1857 Ref<InputEventMouseButton> mb = p_event;
1858
1859 if (mb.is_valid()) {
1860
1861 gui.key_event_accepted = false;
1862
1863 Point2 mpos = mb->get_position();
1864 if (mb->is_pressed()) {
1865
1866 Size2 pos = mpos;
1867 if (gui.mouse_focus_mask) {
1868
1869 //do not steal mouse focus and stuff while a focus mask exists
1870 gui.mouse_focus_mask |= 1 << (mb->get_button_index() - 1); //add the button to the mask
1871 } else {
1872
1873 bool is_handled = false;
1874
1875 _gui_sort_modal_stack();
1876 while (!gui.modal_stack.empty()) {
1877
1878 Control *top = gui.modal_stack.back()->get();
1879 Vector2 pos2 = top->get_global_transform_with_canvas().affine_inverse().xform(mpos);
1880 if (!top->has_point(pos2)) {
1881
1882 if (top->data.modal_exclusive || top->data.modal_frame == Engine::get_singleton()->get_frames_drawn()) {
1883 //cancel event, sorry, modal exclusive EATS UP ALL
1884 //alternative, you can't pop out a window the same frame it was made modal (fixes many issues)
1885 set_input_as_handled();
1886
1887 return; // no one gets the event if exclusive NO ONE
1888 }
1889
1890 if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN || mb->get_button_index() == BUTTON_WHEEL_LEFT || mb->get_button_index() == BUTTON_WHEEL_RIGHT) {
1891 //cancel scroll wheel events, only clicks should trigger focus changes.
1892 set_input_as_handled();
1893 return;
1894 }
1895
1896 top->notification(Control::NOTIFICATION_MODAL_CLOSE);
1897 top->_modal_stack_remove();
1898 top->hide();
1899
1900 if (!top->pass_on_modal_close_click()) {
1901 is_handled = true;
1902 }
1903 } else {
1904 break;
1905 }
1906 }
1907
1908 if (is_handled) {
1909 set_input_as_handled();
1910 return;
1911 }
1912
1913 //Matrix32 parent_xform;
1914
1915 /*
1916 if (data.parent_canvas_item)
1917 parent_xform=data.parent_canvas_item->get_global_transform();
1918 */
1919
1920 gui.mouse_focus = _gui_find_control(pos);
1921 gui.last_mouse_focus = gui.mouse_focus;
1922
1923 if (!gui.mouse_focus) {
1924 gui.mouse_focus_mask = 0;
1925 return;
1926 }
1927
1928 gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1);
1929
1930 if (mb->get_button_index() == BUTTON_LEFT) {
1931 gui.drag_accum = Vector2();
1932 gui.drag_attempted = false;
1933 }
1934 }
1935
1936 mb = mb->xformed_by(Transform2D()); // make a copy of the event
1937
1938 mb->set_global_position(pos);
1939
1940 pos = gui.focus_inv_xform.xform(pos);
1941
1942 mb->set_position(pos);
1943
1944 #ifdef DEBUG_ENABLED
1945 if (ScriptDebugger::get_singleton() && gui.mouse_focus) {
1946
1947 Array arr;
1948 arr.push_back(gui.mouse_focus->get_path());
1949 arr.push_back(gui.mouse_focus->get_class());
1950 ScriptDebugger::get_singleton()->send_message("click_ctrl", arr);
1951 }
1952 #endif
1953
1954 if (mb->get_button_index() == BUTTON_LEFT) { //assign focus
1955 CanvasItem *ci = gui.mouse_focus;
1956 while (ci) {
1957
1958 Control *control = Object::cast_to<Control>(ci);
1959 if (control) {
1960 if (control->get_focus_mode() != Control::FOCUS_NONE) {
1961 if (control != gui.key_focus) {
1962 control->grab_focus();
1963 }
1964 break;
1965 }
1966
1967 if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
1968 break;
1969 }
1970
1971 if (ci->is_set_as_toplevel())
1972 break;
1973
1974 ci = ci->get_parent_item();
1975 }
1976 }
1977
1978 if (gui.mouse_focus && gui.mouse_focus->can_process()) {
1979 _gui_call_input(gui.mouse_focus, mb);
1980 }
1981
1982 set_input_as_handled();
1983
1984 if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
1985
1986 //alternate drop use (when using force_drag(), as proposed by #5342
1987 if (gui.mouse_focus) {
1988 _gui_drop(gui.mouse_focus, pos, false);
1989 }
1990
1991 gui.drag_data = Variant();
1992 gui.dragging = false;
1993
1994 if (gui.drag_preview) {
1995 memdelete(gui.drag_preview);
1996 gui.drag_preview = NULL;
1997 }
1998 _propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
1999 //change mouse accordingly
2000 }
2001
2002 _gui_cancel_tooltip();
2003 //gui.tooltip_popup->hide();
2004
2005 } else {
2006
2007 if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
2008
2009 if (gui.mouse_over) {
2010 Size2 pos = mpos;
2011 pos = gui.focus_inv_xform.xform(pos);
2012
2013 _gui_drop(gui.mouse_over, pos, false);
2014 }
2015
2016 if (gui.drag_preview && mb->get_button_index() == BUTTON_LEFT) {
2017 memdelete(gui.drag_preview);
2018 gui.drag_preview = NULL;
2019 }
2020
2021 gui.drag_data = Variant();
2022 gui.dragging = false;
2023 _propagate_viewport_notification(this, NOTIFICATION_DRAG_END);
2024 //change mouse accordingly
2025 }
2026
2027 gui.mouse_focus_mask &= ~(1 << (mb->get_button_index() - 1)); //remove from mask
2028
2029 if (!gui.mouse_focus) {
2030 //release event is only sent if a mouse focus (previously pressed button) exists
2031 return;
2032 }
2033
2034 Size2 pos = mpos;
2035
2036 mb = mb->xformed_by(Transform2D()); //make a copy
2037 mb->set_global_position(pos);
2038 pos = gui.focus_inv_xform.xform(pos);
2039 mb->set_position(pos);
2040
2041 Control *mouse_focus = gui.mouse_focus;
2042
2043 //disable mouse focus if needed before calling input, this makes popups on mouse press event work better, as the release will never be received otherwise
2044 if (gui.mouse_focus_mask == 0) {
2045 gui.mouse_focus = NULL;
2046 }
2047
2048 if (mouse_focus && mouse_focus->can_process()) {
2049 _gui_call_input(mouse_focus, mb);
2050 }
2051
2052 /*if (gui.drag_data.get_type()!=Variant::NIL && mb->get_button_index()==BUTTON_LEFT) {
2053 _propagate_viewport_notification(this,NOTIFICATION_DRAG_END);
2054 gui.drag_data=Variant(); //always clear
2055 }*/
2056
2057 set_input_as_handled();
2058 }
2059 }
2060
2061 Ref<InputEventMouseMotion> mm = p_event;
2062
2063 if (mm.is_valid()) {
2064
2065 gui.key_event_accepted = false;
2066 Point2 mpos = mm->get_position();
2067
2068 gui.last_mouse_pos = mpos;
2069
2070 Control *over = NULL;
2071
2072 // D&D
2073 if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & BUTTON_MASK_LEFT) {
2074
2075 gui.drag_accum += mm->get_relative();
2076 float len = gui.drag_accum.length();
2077 if (len > 10) {
2078
2079 { //attempt grab, try parent controls too
2080 CanvasItem *ci = gui.mouse_focus;
2081 while (ci) {
2082
2083 Control *control = Object::cast_to<Control>(ci);
2084 if (control) {
2085
2086 gui.dragging = true;
2087 gui.drag_data = control->get_drag_data(control->get_global_transform_with_canvas().affine_inverse().xform(mpos) - gui.drag_accum);
2088 if (gui.drag_data.get_type() != Variant::NIL) {
2089
2090 gui.mouse_focus = NULL;
2091 gui.mouse_focus_mask = 0;
2092 break;
2093 } else {
2094 if (gui.drag_preview != NULL) {
2095 ERR_PRINT("Don't set a drag preview and return null data. Preview was deleted and drag request ignored.");
2096 memdelete(gui.drag_preview);
2097 gui.drag_preview = NULL;
2098 }
2099 gui.dragging = false;
2100 }
2101
2102 if (control->data.mouse_filter == Control::MOUSE_FILTER_STOP)
2103 break;
2104 }
2105
2106 if (ci->is_set_as_toplevel())
2107 break;
2108
2109 ci = ci->get_parent_item();
2110 }
2111 }
2112
2113 gui.drag_attempted = true;
2114 if (gui.drag_data.get_type() != Variant::NIL) {
2115
2116 _propagate_viewport_notification(this, NOTIFICATION_DRAG_BEGIN);
2117 }
2118 }
2119 }
2120
2121 if (gui.mouse_focus) {
2122 over = gui.mouse_focus;
2123 //recompute focus_inv_xform again here
2124
2125 } else {
2126
2127 over = _gui_find_control(mpos);
2128 }
2129
2130 if (gui.drag_data.get_type() == Variant::NIL && over && !gui.modal_stack.empty()) {
2131
2132 Control *top = gui.modal_stack.back()->get();
2133
2134 if (over != top && !top->is_a_parent_of(over)) {
2135
2136 PopupMenu *popup_menu = Object::cast_to<PopupMenu>(top);
2137 MenuButton *popup_menu_parent = NULL;
2138 MenuButton *menu_button = Object::cast_to<MenuButton>(over);
2139
2140 if (popup_menu) {
2141 popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent());
2142 if (!popup_menu_parent) {
2143 // Go through the parents to see if there's a MenuButton at the end.
2144 while (Object::cast_to<PopupMenu>(popup_menu->get_parent())) {
2145 popup_menu = Object::cast_to<PopupMenu>(popup_menu->get_parent());
2146 }
2147 popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent());
2148 }
2149 }
2150
2151 // If the mouse is over a menu button, this menu will open automatically
2152 // if there is already a pop-up menu open at the same hierarchical level.
2153 if (popup_menu_parent && menu_button && popup_menu_parent->is_switch_on_hover() &&
2154 !menu_button->is_disabled() && menu_button->is_switch_on_hover() &&
2155 (popup_menu_parent->get_parent()->is_a_parent_of(menu_button) ||
2156 menu_button->get_parent()->is_a_parent_of(popup_menu))) {
2157
2158 popup_menu->notification(Control::NOTIFICATION_MODAL_CLOSE);
2159 popup_menu->_modal_stack_remove();
2160 popup_menu->hide();
2161
2162 menu_button->pressed();
2163 } else {
2164 over = NULL; //nothing can be found outside the modal stack
2165 }
2166 }
2167 }
2168
2169 if (over != gui.mouse_over) {
2170
2171 if (gui.mouse_over) {
2172 _gui_call_notification(gui.mouse_over, Control::NOTIFICATION_MOUSE_EXIT);
2173 }
2174
2175 _gui_cancel_tooltip();
2176
2177 if (over) {
2178 _gui_call_notification(over, Control::NOTIFICATION_MOUSE_ENTER);
2179 }
2180 }
2181
2182 gui.mouse_over = over;
2183
2184 if (gui.drag_preview) {
2185 gui.drag_preview->set_position(mpos);
2186 }
2187
2188 if (!over) {
2189 OS::get_singleton()->set_cursor_shape((OS::CursorShape)Input::get_singleton()->get_default_cursor_shape());
2190 return;
2191 }
2192
2193 Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse();
2194 Size2 pos = localizer.xform(mpos);
2195 Vector2 speed = localizer.basis_xform(mm->get_speed());
2196 Vector2 rel = localizer.basis_xform(mm->get_relative());
2197
2198 mm = mm->xformed_by(Transform2D()); //make a copy
2199
2200 mm->set_global_position(mpos);
2201 mm->set_speed(speed);
2202 mm->set_relative(rel);
2203
2204 if (mm->get_button_mask() == 0) {
2205 //nothing pressed
2206
2207 bool can_tooltip = true;
2208
2209 if (!gui.modal_stack.empty()) {
2210 if (gui.modal_stack.back()->get() != over && !gui.modal_stack.back()->get()->is_a_parent_of(over))
2211 can_tooltip = false;
2212 }
2213
2214 bool is_tooltip_shown = false;
2215
2216 if (gui.tooltip_popup) {
2217 if (can_tooltip && gui.tooltip) {
2218 String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos));
2219
2220 if (tooltip.length() == 0)
2221 _gui_cancel_tooltip();
2222 else if (gui.tooltip_label) {
2223 if (tooltip == gui.tooltip_label->get_text()) {
2224 is_tooltip_shown = true;
2225 }
2226 } else if (tooltip == String(gui.tooltip_popup->call("get_tooltip_text"))) {
2227 is_tooltip_shown = true;
2228 }
2229 } else
2230 _gui_cancel_tooltip();
2231 }
2232
2233 if (can_tooltip && !is_tooltip_shown) {
2234
2235 gui.tooltip = over;
2236 gui.tooltip_pos = mpos; //(parent_xform * get_transform()).affine_inverse().xform(pos);
2237 gui.tooltip_timer = gui.tooltip_delay;
2238 }
2239 }
2240
2241 //pos = gui.focus_inv_xform.xform(pos);
2242
2243 mm->set_position(pos);
2244
2245 Control::CursorShape cursor_shape = Control::CURSOR_ARROW;
2246 {
2247 Control *c = over;
2248 Vector2 cpos = pos;
2249 while (c) {
2250 cursor_shape = c->get_cursor_shape(cpos);
2251 cpos = c->get_transform().xform(cpos);
2252 if (cursor_shape != Control::CURSOR_ARROW)
2253 break;
2254 if (c->data.mouse_filter == Control::MOUSE_FILTER_STOP)
2255 break;
2256 if (c->is_set_as_toplevel())
2257 break;
2258 c = c->get_parent_control();
2259 }
2260 }
2261
2262 OS::get_singleton()->set_cursor_shape((OS::CursorShape)cursor_shape);
2263
2264 if (over && over->can_process()) {
2265 _gui_call_input(over, mm);
2266 }
2267
2268 set_input_as_handled();
2269
2270 if (gui.drag_data.get_type() != Variant::NIL && mm->get_button_mask() & BUTTON_MASK_LEFT) {
2271
2272 bool can_drop = _gui_drop(over, pos, true);
2273
2274 if (!can_drop) {
2275 OS::get_singleton()->set_cursor_shape(OS::CURSOR_FORBIDDEN);
2276 } else {
2277 OS::get_singleton()->set_cursor_shape(OS::CURSOR_CAN_DROP);
2278 }
2279 //change mouse accordingly i guess
2280 }
2281 }
2282
2283 Ref<InputEventScreenTouch> touch_event = p_event;
2284 if (touch_event.is_valid()) {
2285
2286 Size2 pos = touch_event->get_position();
2287 if (touch_event->is_pressed()) {
2288
2289 Control *over = _gui_find_control(pos);
2290 if (over) {
2291
2292 if (!gui.modal_stack.empty()) {
2293
2294 Control *top = gui.modal_stack.back()->get();
2295 if (over != top && !top->is_a_parent_of(over)) {
2296
2297 return;
2298 }
2299 }
2300 if (over->can_process()) {
2301
2302 touch_event = touch_event->xformed_by(Transform2D()); //make a copy
2303 if (over == gui.mouse_focus) {
2304 pos = gui.focus_inv_xform.xform(pos);
2305 } else {
2306 pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
2307 }
2308 touch_event->set_position(pos);
2309 _gui_call_input(over, touch_event);
2310 }
2311 set_input_as_handled();
2312 return;
2313 }
2314 } else if (touch_event->get_index() == 0 && gui.last_mouse_focus) {
2315
2316 if (gui.last_mouse_focus->can_process()) {
2317
2318 touch_event = touch_event->xformed_by(Transform2D()); //make a copy
2319 touch_event->set_position(gui.focus_inv_xform.xform(pos));
2320
2321 _gui_call_input(gui.last_mouse_focus, touch_event);
2322 }
2323 set_input_as_handled();
2324 return;
2325 }
2326 }
2327
2328 Ref<InputEventGesture> gesture_event = p_event;
2329 if (gesture_event.is_valid()) {
2330
2331 gui.key_event_accepted = false;
2332
2333 _gui_cancel_tooltip();
2334
2335 Size2 pos = gesture_event->get_position();
2336
2337 Control *over = _gui_find_control(pos);
2338 if (over) {
2339
2340 if (over->can_process()) {
2341
2342 gesture_event = gesture_event->xformed_by(Transform2D()); //make a copy
2343 if (over == gui.mouse_focus) {
2344 pos = gui.focus_inv_xform.xform(pos);
2345 } else {
2346 pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
2347 }
2348 gesture_event->set_position(pos);
2349 _gui_call_input(over, gesture_event);
2350 }
2351 set_input_as_handled();
2352 return;
2353 }
2354 }
2355
2356 Ref<InputEventScreenDrag> drag_event = p_event;
2357 if (drag_event.is_valid()) {
2358
2359 Control *over = gui.mouse_focus;
2360 if (!over) {
2361 over = _gui_find_control(drag_event->get_position());
2362 }
2363 if (over) {
2364
2365 if (!gui.modal_stack.empty()) {
2366
2367 Control *top = gui.modal_stack.back()->get();
2368 if (over != top && !top->is_a_parent_of(over)) {
2369
2370 return;
2371 }
2372 }
2373 if (over->can_process()) {
2374
2375 Transform2D localizer = over->get_global_transform_with_canvas().affine_inverse();
2376 Size2 pos = localizer.xform(drag_event->get_position());
2377 Vector2 speed = localizer.basis_xform(drag_event->get_speed());
2378 Vector2 rel = localizer.basis_xform(drag_event->get_relative());
2379
2380 drag_event = drag_event->xformed_by(Transform2D()); //make a copy
2381
2382 drag_event->set_speed(speed);
2383 drag_event->set_relative(rel);
2384 drag_event->set_position(pos);
2385
2386 _gui_call_input(over, drag_event);
2387 }
2388
2389 set_input_as_handled();
2390 return;
2391 }
2392 }
2393
2394 if (mm.is_null() && mb.is_null() && p_event->is_action_type()) {
2395
2396 if (gui.key_focus && !gui.key_focus->is_visible_in_tree()) {
2397 gui.key_focus->release_focus();
2398 }
2399
2400 if (gui.key_focus) {
2401
2402 gui.key_event_accepted = false;
2403 if (gui.key_focus->can_process()) {
2404 gui.key_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, p_event);
2405 if (gui.key_focus) //maybe lost it
2406 gui.key_focus->emit_signal(SceneStringNames::get_singleton()->gui_input, p_event);
2407 }
2408
2409 if (gui.key_event_accepted) {
2410
2411 set_input_as_handled();
2412 return;
2413 }
2414 }
2415
2416 if (p_event->is_pressed() && p_event->is_action("ui_cancel") && !gui.modal_stack.empty()) {
2417
2418 _gui_sort_modal_stack();
2419 Control *top = gui.modal_stack.back()->get();
2420 if (!top->data.modal_exclusive) {
2421
2422 top->notification(Control::NOTIFICATION_MODAL_CLOSE);
2423 top->_modal_stack_remove();
2424 top->hide();
2425 // Close modal, set input as handled
2426 set_input_as_handled();
2427 return;
2428 }
2429 }
2430
2431 Control *from = gui.key_focus ? gui.key_focus : NULL; //hmm
2432
2433 //keyboard focus
2434 //if (from && p_event->is_pressed() && !p_event->get_alt() && !p_event->get_metakey() && !p_event->key->get_command()) {
2435
2436 Ref<InputEventKey> k = p_event;
2437 //need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/righ/etc> is handled here when it shouldn't be.
2438 bool mods = k.is_valid() && (k->get_control() || k->get_alt() || k->get_shift() || k->get_metakey());
2439
2440 if (from && p_event->is_pressed()) {
2441 Control *next = NULL;
2442
2443 Input *input = Input::get_singleton();
2444
2445 if (p_event->is_action_pressed("ui_focus_next") && input->is_action_just_pressed("ui_focus_next")) {
2446
2447 next = from->find_next_valid_focus();
2448 }
2449
2450 if (p_event->is_action_pressed("ui_focus_prev") && input->is_action_just_pressed("ui_focus_prev")) {
2451
2452 next = from->find_prev_valid_focus();
2453 }
2454
2455 if (!mods && p_event->is_action_pressed("ui_up") && input->is_action_just_pressed("ui_up")) {
2456
2457 next = from->_get_focus_neighbour(MARGIN_TOP);
2458 }
2459
2460 if (!mods && p_event->is_action_pressed("ui_left") && input->is_action_just_pressed("ui_left")) {
2461
2462 next = from->_get_focus_neighbour(MARGIN_LEFT);
2463 }
2464
2465 if (!mods && p_event->is_action_pressed("ui_right") && input->is_action_just_pressed("ui_right")) {
2466
2467 next = from->_get_focus_neighbour(MARGIN_RIGHT);
2468 }
2469
2470 if (!mods && p_event->is_action_pressed("ui_down") && input->is_action_just_pressed("ui_down")) {
2471
2472 next = from->_get_focus_neighbour(MARGIN_BOTTOM);
2473 }
2474
2475 if (next) {
2476 next->grab_focus();
2477 set_input_as_handled();
2478 }
2479 }
2480 }
2481 }
2482
_gui_add_root_control(Control * p_control)2483 List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) {
2484
2485 gui.roots_order_dirty = true;
2486 return gui.roots.push_back(p_control);
2487 }
2488
_gui_add_subwindow_control(Control * p_control)2489 List<Control *>::Element *Viewport::_gui_add_subwindow_control(Control *p_control) {
2490
2491 p_control->connect("visibility_changed", this, "_subwindow_visibility_changed");
2492
2493 if (p_control->is_visible_in_tree()) {
2494 gui.subwindow_order_dirty = true;
2495 gui.subwindows.push_back(p_control);
2496 }
2497
2498 return gui.all_known_subwindows.push_back(p_control);
2499 }
2500
_gui_set_subwindow_order_dirty()2501 void Viewport::_gui_set_subwindow_order_dirty() {
2502 gui.subwindow_order_dirty = true;
2503 }
2504
_gui_set_root_order_dirty()2505 void Viewport::_gui_set_root_order_dirty() {
2506 gui.roots_order_dirty = true;
2507 }
2508
_gui_remove_modal_control(List<Control * >::Element * MI)2509 void Viewport::_gui_remove_modal_control(List<Control *>::Element *MI) {
2510
2511 gui.modal_stack.erase(MI);
2512 }
2513
_gui_remove_from_modal_stack(List<Control * >::Element * MI,ObjectID p_prev_focus_owner)2514 void Viewport::_gui_remove_from_modal_stack(List<Control *>::Element *MI, ObjectID p_prev_focus_owner) {
2515
2516 //transfer the focus stack to the next
2517
2518 List<Control *>::Element *next = MI->next();
2519
2520 gui.modal_stack.erase(MI);
2521
2522 if (p_prev_focus_owner) {
2523
2524 // for previous window in stack, pass the focus so it feels more
2525 // natural
2526
2527 if (!next) { //top of stack
2528
2529 Object *pfo = ObjectDB::get_instance(p_prev_focus_owner);
2530 Control *pfoc = Object::cast_to<Control>(pfo);
2531 if (!pfoc)
2532 return;
2533
2534 if (!pfoc->is_inside_tree() || !pfoc->is_visible_in_tree())
2535 return;
2536 pfoc->grab_focus();
2537 } else {
2538
2539 next->get()->_modal_set_prev_focus_owner(p_prev_focus_owner);
2540 }
2541 }
2542 }
2543
_gui_force_drag(Control * p_base,const Variant & p_data,Control * p_control)2544 void Viewport::_gui_force_drag(Control *p_base, const Variant &p_data, Control *p_control) {
2545
2546 ERR_FAIL_COND_MSG(p_data.get_type() == Variant::NIL, "Drag data must be a value.");
2547
2548 gui.dragging = true;
2549 gui.drag_data = p_data;
2550 gui.mouse_focus = NULL;
2551
2552 if (p_control) {
2553 _gui_set_drag_preview(p_base, p_control);
2554 }
2555 }
2556
_gui_set_drag_preview(Control * p_base,Control * p_control)2557 void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) {
2558
2559 ERR_FAIL_NULL(p_control);
2560 ERR_FAIL_COND(!Object::cast_to<Control>((Object *)p_control));
2561 ERR_FAIL_COND(p_control->is_inside_tree());
2562 ERR_FAIL_COND(p_control->get_parent() != NULL);
2563
2564 if (gui.drag_preview) {
2565 memdelete(gui.drag_preview);
2566 }
2567 p_control->set_as_toplevel(true);
2568 p_control->set_position(gui.last_mouse_pos);
2569 p_base->get_root_parent_control()->add_child(p_control); //add as child of viewport
2570 p_control->raise();
2571
2572 gui.drag_preview = p_control;
2573 }
2574
_gui_remove_root_control(List<Control * >::Element * RI)2575 void Viewport::_gui_remove_root_control(List<Control *>::Element *RI) {
2576
2577 gui.roots.erase(RI);
2578 }
2579
_gui_remove_subwindow_control(List<Control * >::Element * SI)2580 void Viewport::_gui_remove_subwindow_control(List<Control *>::Element *SI) {
2581
2582 ERR_FAIL_COND(!SI);
2583
2584 Control *control = SI->get();
2585
2586 control->disconnect("visibility_changed", this, "_subwindow_visibility_changed");
2587
2588 List<Control *>::Element *E = gui.subwindows.find(control);
2589 if (E)
2590 gui.subwindows.erase(E);
2591
2592 gui.all_known_subwindows.erase(SI);
2593 }
2594
_gui_unfocus_control(Control * p_control)2595 void Viewport::_gui_unfocus_control(Control *p_control) {
2596
2597 if (gui.key_focus == p_control) {
2598 gui.key_focus->release_focus();
2599 }
2600 }
2601
_gui_hid_control(Control * p_control)2602 void Viewport::_gui_hid_control(Control *p_control) {
2603
2604 if (gui.mouse_focus == p_control) {
2605 _drop_mouse_focus();
2606 }
2607
2608 /* ???
2609 if (data.window==p_control) {
2610 window->drag_data=Variant();
2611 if (window->drag_preview) {
2612 memdelete( window->drag_preview);
2613 window->drag_preview=NULL;
2614 }
2615 }
2616 */
2617
2618 if (gui.key_focus == p_control)
2619 _gui_remove_focus();
2620 if (gui.mouse_over == p_control)
2621 gui.mouse_over = NULL;
2622 if (gui.tooltip == p_control)
2623 _gui_cancel_tooltip();
2624 }
2625
_gui_remove_control(Control * p_control)2626 void Viewport::_gui_remove_control(Control *p_control) {
2627
2628 if (gui.mouse_focus == p_control) {
2629 gui.mouse_focus = NULL;
2630 gui.mouse_focus_mask = 0;
2631 }
2632 if (gui.last_mouse_focus == p_control) {
2633 gui.last_mouse_focus = NULL;
2634 }
2635 if (gui.key_focus == p_control)
2636 gui.key_focus = NULL;
2637 if (gui.mouse_over == p_control)
2638 gui.mouse_over = NULL;
2639 if (gui.tooltip == p_control)
2640 gui.tooltip = NULL;
2641 if (gui.tooltip_popup == p_control) {
2642 _gui_cancel_tooltip();
2643 }
2644 }
2645
_gui_remove_focus()2646 void Viewport::_gui_remove_focus() {
2647
2648 if (gui.key_focus) {
2649 Node *f = gui.key_focus;
2650 gui.key_focus = NULL;
2651 f->notification(Control::NOTIFICATION_FOCUS_EXIT, true);
2652 }
2653 }
2654
_gui_is_modal_on_top(const Control * p_control)2655 bool Viewport::_gui_is_modal_on_top(const Control *p_control) {
2656
2657 return (gui.modal_stack.size() && gui.modal_stack.back()->get() == p_control);
2658 }
2659
_gui_control_has_focus(const Control * p_control)2660 bool Viewport::_gui_control_has_focus(const Control *p_control) {
2661
2662 return gui.key_focus == p_control;
2663 }
2664
_gui_control_grab_focus(Control * p_control)2665 void Viewport::_gui_control_grab_focus(Control *p_control) {
2666
2667 //no need for change
2668 if (gui.key_focus && gui.key_focus == p_control)
2669 return;
2670 get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "_viewports", "_gui_remove_focus");
2671 gui.key_focus = p_control;
2672 emit_signal("gui_focus_changed", p_control);
2673 p_control->notification(Control::NOTIFICATION_FOCUS_ENTER);
2674 p_control->update();
2675 }
2676
_gui_accept_event()2677 void Viewport::_gui_accept_event() {
2678
2679 gui.key_event_accepted = true;
2680 if (is_inside_tree())
2681 set_input_as_handled();
2682 }
2683
_drop_mouse_focus()2684 void Viewport::_drop_mouse_focus() {
2685
2686 Control *c = gui.mouse_focus;
2687 int mask = gui.mouse_focus_mask;
2688 gui.mouse_focus = NULL;
2689 gui.mouse_focus_mask = 0;
2690
2691 for (int i = 0; i < 3; i++) {
2692
2693 if (mask & (1 << i)) {
2694 Ref<InputEventMouseButton> mb;
2695 mb.instance();
2696 mb->set_position(c->get_local_mouse_position());
2697 mb->set_global_position(c->get_local_mouse_position());
2698 mb->set_button_index(i + 1);
2699 mb->set_pressed(false);
2700 c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
2701 }
2702 }
2703 }
2704
_drop_physics_mouseover()2705 void Viewport::_drop_physics_mouseover() {
2706
2707 physics_has_last_mousepos = false;
2708
2709 while (physics_2d_mouseover.size()) {
2710 Object *o = ObjectDB::get_instance(physics_2d_mouseover.front()->key());
2711 if (o) {
2712 CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
2713 co->_mouse_exit();
2714 }
2715 physics_2d_mouseover.erase(physics_2d_mouseover.front());
2716 }
2717
2718 #ifndef _3D_DISABLED
2719 if (physics_object_over) {
2720 CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over));
2721 if (co) {
2722 co->_mouse_exit();
2723 }
2724 }
2725
2726 physics_object_over = physics_object_capture = 0;
2727 #endif
2728 }
2729
_gui_show_modal(Control * p_control)2730 List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
2731
2732 List<Control *>::Element *node = gui.modal_stack.push_back(p_control);
2733 if (gui.key_focus)
2734 p_control->_modal_set_prev_focus_owner(gui.key_focus->get_instance_id());
2735 else
2736 p_control->_modal_set_prev_focus_owner(0);
2737
2738 if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) {
2739
2740 _drop_mouse_focus();
2741 }
2742
2743 return node;
2744 }
2745
_gui_get_focus_owner()2746 Control *Viewport::_gui_get_focus_owner() {
2747
2748 return gui.key_focus;
2749 }
2750
_gui_grab_click_focus(Control * p_control)2751 void Viewport::_gui_grab_click_focus(Control *p_control) {
2752
2753 gui.mouse_click_grabber = p_control;
2754 call_deferred("_post_gui_grab_click_focus");
2755 }
2756
_post_gui_grab_click_focus()2757 void Viewport::_post_gui_grab_click_focus() {
2758
2759 Control *focus_grabber = gui.mouse_click_grabber;
2760 if (!focus_grabber) {
2761 // Redundant grab requests were made
2762 return;
2763 }
2764 gui.mouse_click_grabber = NULL;
2765
2766 if (gui.mouse_focus) {
2767
2768 if (gui.mouse_focus == focus_grabber)
2769 return;
2770
2771 int mask = gui.mouse_focus_mask;
2772 Point2 click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
2773
2774 for (int i = 0; i < 3; i++) {
2775
2776 if (mask & (1 << i)) {
2777
2778 Ref<InputEventMouseButton> mb;
2779 mb.instance();
2780
2781 //send unclic
2782
2783 mb->set_position(click);
2784 mb->set_button_index(i + 1);
2785 mb->set_pressed(false);
2786 gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
2787 }
2788 }
2789
2790 gui.mouse_focus = focus_grabber;
2791 gui.focus_inv_xform = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse();
2792 click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
2793
2794 for (int i = 0; i < 3; i++) {
2795
2796 if (mask & (1 << i)) {
2797
2798 Ref<InputEventMouseButton> mb;
2799 mb.instance();
2800
2801 //send clic
2802
2803 mb->set_position(click);
2804 mb->set_button_index(i + 1);
2805 mb->set_pressed(true);
2806 gui.mouse_focus->call_deferred(SceneStringNames::get_singleton()->_gui_input, mb);
2807 }
2808 }
2809 }
2810 }
2811
2812 ///////////////////////////////
2813
input(const Ref<InputEvent> & p_event)2814 void Viewport::input(const Ref<InputEvent> &p_event) {
2815
2816 ERR_FAIL_COND(!is_inside_tree());
2817
2818 local_input_handled = false;
2819
2820 if (!is_input_handled()) {
2821 get_tree()->_call_input_pause(input_group, "_input", p_event); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input
2822 }
2823
2824 if (!is_input_handled()) {
2825 _gui_input_event(p_event);
2826 }
2827 //get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",p_event); //special one for GUI, as controls use their own process check
2828 }
2829
unhandled_input(const Ref<InputEvent> & p_event)2830 void Viewport::unhandled_input(const Ref<InputEvent> &p_event) {
2831
2832 ERR_FAIL_COND(!is_inside_tree());
2833
2834 get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", p_event);
2835 //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_input","_unhandled_input",ev);
2836 if (!get_tree()->input_handled && Object::cast_to<InputEventKey>(*p_event) != NULL) {
2837 get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", p_event);
2838 //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_key_input","_unhandled_key_input",ev);
2839 }
2840
2841 if (physics_object_picking && !get_tree()->input_handled) {
2842
2843 if (Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED &&
2844 (Object::cast_to<InputEventMouseButton>(*p_event) ||
2845 Object::cast_to<InputEventMouseMotion>(*p_event) ||
2846 Object::cast_to<InputEventScreenDrag>(*p_event) ||
2847 Object::cast_to<InputEventScreenTouch>(*p_event) ||
2848 Object::cast_to<InputEventKey>(*p_event) //to remember state
2849
2850 )) {
2851 physics_picking_events.push_back(p_event);
2852 }
2853 }
2854 }
2855
set_use_own_world(bool p_world)2856 void Viewport::set_use_own_world(bool p_world) {
2857
2858 if (p_world == own_world.is_valid())
2859 return;
2860
2861 if (is_inside_tree())
2862 _propagate_exit_world(this);
2863
2864 if (!p_world) {
2865 own_world = Ref<World>();
2866 if (world.is_valid()) {
2867 world->disconnect(CoreStringNames::get_singleton()->changed, this, "_own_world_changed");
2868 }
2869 } else {
2870 if (world.is_valid()) {
2871 own_world = world->duplicate();
2872 world->connect(CoreStringNames::get_singleton()->changed, this, "_own_world_changed");
2873 } else {
2874 own_world = Ref<World>(memnew(World));
2875 }
2876 }
2877
2878 if (is_inside_tree())
2879 _propagate_enter_world(this);
2880
2881 if (is_inside_tree()) {
2882 VisualServer::get_singleton()->viewport_set_scenario(viewport, find_world()->get_scenario());
2883 }
2884
2885 _update_listener();
2886 }
2887
is_using_own_world() const2888 bool Viewport::is_using_own_world() const {
2889
2890 return own_world.is_valid();
2891 }
2892
set_attach_to_screen_rect(const Rect2 & p_rect)2893 void Viewport::set_attach_to_screen_rect(const Rect2 &p_rect) {
2894
2895 VS::get_singleton()->viewport_attach_to_screen(viewport, p_rect);
2896 to_screen_rect = p_rect;
2897 }
2898
get_attach_to_screen_rect() const2899 Rect2 Viewport::get_attach_to_screen_rect() const {
2900
2901 return to_screen_rect;
2902 }
2903
set_use_render_direct_to_screen(bool p_render_direct_to_screen)2904 void Viewport::set_use_render_direct_to_screen(bool p_render_direct_to_screen) {
2905
2906 if (p_render_direct_to_screen == render_direct_to_screen)
2907 return;
2908
2909 render_direct_to_screen = p_render_direct_to_screen;
2910 VS::get_singleton()->viewport_set_render_direct_to_screen(viewport, p_render_direct_to_screen);
2911 }
2912
is_using_render_direct_to_screen() const2913 bool Viewport::is_using_render_direct_to_screen() const {
2914 return render_direct_to_screen;
2915 }
2916
set_physics_object_picking(bool p_enable)2917 void Viewport::set_physics_object_picking(bool p_enable) {
2918
2919 physics_object_picking = p_enable;
2920 if (!physics_object_picking) {
2921 physics_picking_events.clear();
2922 }
2923 }
2924
get_physics_object_picking()2925 bool Viewport::get_physics_object_picking() {
2926
2927 return physics_object_picking;
2928 }
2929
get_camera_coords(const Vector2 & p_viewport_coords) const2930 Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const {
2931
2932 Transform2D xf = get_final_transform();
2933 return xf.xform(p_viewport_coords);
2934 }
2935
get_camera_rect_size() const2936 Vector2 Viewport::get_camera_rect_size() const {
2937
2938 return size;
2939 }
2940
gui_has_modal_stack() const2941 bool Viewport::gui_has_modal_stack() const {
2942
2943 return gui.modal_stack.size();
2944 }
2945
set_disable_input(bool p_disable)2946 void Viewport::set_disable_input(bool p_disable) {
2947 disable_input = p_disable;
2948 }
2949
is_input_disabled() const2950 bool Viewport::is_input_disabled() const {
2951
2952 return disable_input;
2953 }
2954
set_disable_3d(bool p_disable)2955 void Viewport::set_disable_3d(bool p_disable) {
2956 disable_3d = p_disable;
2957 VS::get_singleton()->viewport_set_disable_3d(viewport, p_disable);
2958 }
2959
is_3d_disabled() const2960 bool Viewport::is_3d_disabled() const {
2961
2962 return disable_3d;
2963 }
2964
set_keep_3d_linear(bool p_keep_3d_linear)2965 void Viewport::set_keep_3d_linear(bool p_keep_3d_linear) {
2966 keep_3d_linear = p_keep_3d_linear;
2967 VS::get_singleton()->viewport_set_keep_3d_linear(viewport, keep_3d_linear);
2968 }
2969
get_keep_3d_linear() const2970 bool Viewport::get_keep_3d_linear() const {
2971
2972 return keep_3d_linear;
2973 }
2974
gui_get_drag_data() const2975 Variant Viewport::gui_get_drag_data() const {
2976 return gui.drag_data;
2977 }
2978
get_modal_stack_top() const2979 Control *Viewport::get_modal_stack_top() const {
2980 return gui.modal_stack.size() ? gui.modal_stack.back()->get() : NULL;
2981 }
2982
get_configuration_warning() const2983 String Viewport::get_configuration_warning() const {
2984 /*if (get_parent() && !Object::cast_to<Control>(get_parent()) && !render_target) {
2985
2986 return TTR("This viewport is not set as render target. If you intend for it to display its contents directly to the screen, make it a child of a Control so it can obtain a size. Otherwise, make it a RenderTarget and assign its internal texture to some node for display.");
2987 }*/
2988
2989 if (size.x == 0 || size.y == 0) {
2990 return TTR("Viewport size must be greater than 0 to render anything.");
2991 }
2992 return String();
2993 }
2994
gui_reset_canvas_sort_index()2995 void Viewport::gui_reset_canvas_sort_index() {
2996 gui.canvas_sort_index = 0;
2997 }
gui_get_canvas_sort_index()2998 int Viewport::gui_get_canvas_sort_index() {
2999
3000 return gui.canvas_sort_index++;
3001 }
3002
set_msaa(MSAA p_msaa)3003 void Viewport::set_msaa(MSAA p_msaa) {
3004
3005 ERR_FAIL_INDEX(p_msaa, 7);
3006 if (msaa == p_msaa)
3007 return;
3008 msaa = p_msaa;
3009 VS::get_singleton()->viewport_set_msaa(viewport, VS::ViewportMSAA(p_msaa));
3010 }
3011
get_msaa() const3012 Viewport::MSAA Viewport::get_msaa() const {
3013
3014 return msaa;
3015 }
3016
set_hdr(bool p_hdr)3017 void Viewport::set_hdr(bool p_hdr) {
3018
3019 if (hdr == p_hdr)
3020 return;
3021
3022 hdr = p_hdr;
3023 VS::get_singleton()->viewport_set_hdr(viewport, p_hdr);
3024 }
3025
get_hdr() const3026 bool Viewport::get_hdr() const {
3027
3028 return hdr;
3029 }
3030
set_usage(Usage p_usage)3031 void Viewport::set_usage(Usage p_usage) {
3032
3033 usage = p_usage;
3034 VS::get_singleton()->viewport_set_usage(viewport, VS::ViewportUsage(p_usage));
3035 }
3036
get_usage() const3037 Viewport::Usage Viewport::get_usage() const {
3038 return usage;
3039 }
3040
set_debug_draw(DebugDraw p_debug_draw)3041 void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
3042
3043 debug_draw = p_debug_draw;
3044 VS::get_singleton()->viewport_set_debug_draw(viewport, VS::ViewportDebugDraw(p_debug_draw));
3045 }
3046
get_debug_draw() const3047 Viewport::DebugDraw Viewport::get_debug_draw() const {
3048
3049 return debug_draw;
3050 }
3051
get_render_info(RenderInfo p_info)3052 int Viewport::get_render_info(RenderInfo p_info) {
3053
3054 return VS::get_singleton()->viewport_get_render_info(viewport, VS::ViewportRenderInfo(p_info));
3055 }
3056
set_snap_controls_to_pixels(bool p_enable)3057 void Viewport::set_snap_controls_to_pixels(bool p_enable) {
3058
3059 snap_controls_to_pixels = p_enable;
3060 }
3061
is_snap_controls_to_pixels_enabled() const3062 bool Viewport::is_snap_controls_to_pixels_enabled() const {
3063
3064 return snap_controls_to_pixels;
3065 }
3066
gui_is_dragging() const3067 bool Viewport::gui_is_dragging() const {
3068 return gui.dragging;
3069 }
3070
set_input_as_handled()3071 void Viewport::set_input_as_handled() {
3072 _drop_physics_mouseover();
3073 if (handle_input_locally) {
3074 local_input_handled = true;
3075 } else {
3076 ERR_FAIL_COND(!is_inside_tree());
3077 get_tree()->set_input_as_handled();
3078 }
3079 }
3080
is_input_handled() const3081 bool Viewport::is_input_handled() const {
3082 if (handle_input_locally) {
3083 return local_input_handled;
3084 } else {
3085 ERR_FAIL_COND_V(!is_inside_tree(), false);
3086 return get_tree()->is_input_handled();
3087 }
3088 }
3089
set_handle_input_locally(bool p_enable)3090 void Viewport::set_handle_input_locally(bool p_enable) {
3091 handle_input_locally = p_enable;
3092 }
3093
is_handling_input_locally() const3094 bool Viewport::is_handling_input_locally() const {
3095 return handle_input_locally;
3096 }
3097
_validate_property(PropertyInfo & property) const3098 void Viewport::_validate_property(PropertyInfo &property) const {
3099
3100 if (VisualServer::get_singleton()->is_low_end() && property.name == "hdr") {
3101 property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
3102 }
3103 }
3104
_bind_methods()3105 void Viewport::_bind_methods() {
3106
3107 ClassDB::bind_method(D_METHOD("set_use_arvr", "use"), &Viewport::set_use_arvr);
3108 ClassDB::bind_method(D_METHOD("use_arvr"), &Viewport::use_arvr);
3109
3110 ClassDB::bind_method(D_METHOD("set_size", "size"), &Viewport::set_size);
3111 ClassDB::bind_method(D_METHOD("get_size"), &Viewport::get_size);
3112 ClassDB::bind_method(D_METHOD("set_world_2d", "world_2d"), &Viewport::set_world_2d);
3113 ClassDB::bind_method(D_METHOD("get_world_2d"), &Viewport::get_world_2d);
3114 ClassDB::bind_method(D_METHOD("find_world_2d"), &Viewport::find_world_2d);
3115 ClassDB::bind_method(D_METHOD("set_world", "world"), &Viewport::set_world);
3116 ClassDB::bind_method(D_METHOD("get_world"), &Viewport::get_world);
3117 ClassDB::bind_method(D_METHOD("find_world"), &Viewport::find_world);
3118
3119 ClassDB::bind_method(D_METHOD("set_canvas_transform", "xform"), &Viewport::set_canvas_transform);
3120 ClassDB::bind_method(D_METHOD("get_canvas_transform"), &Viewport::get_canvas_transform);
3121
3122 ClassDB::bind_method(D_METHOD("set_global_canvas_transform", "xform"), &Viewport::set_global_canvas_transform);
3123 ClassDB::bind_method(D_METHOD("get_global_canvas_transform"), &Viewport::get_global_canvas_transform);
3124 ClassDB::bind_method(D_METHOD("get_final_transform"), &Viewport::get_final_transform);
3125
3126 ClassDB::bind_method(D_METHOD("get_visible_rect"), &Viewport::get_visible_rect);
3127 ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background);
3128 ClassDB::bind_method(D_METHOD("has_transparent_background"), &Viewport::has_transparent_background);
3129
3130 ClassDB::bind_method(D_METHOD("_vp_input"), &Viewport::_vp_input);
3131 ClassDB::bind_method(D_METHOD("_vp_input_text", "text"), &Viewport::_vp_input_text);
3132 ClassDB::bind_method(D_METHOD("_vp_unhandled_input"), &Viewport::_vp_unhandled_input);
3133
3134 ClassDB::bind_method(D_METHOD("set_size_override", "enable", "size", "margin"), &Viewport::set_size_override, DEFVAL(Size2(-1, -1)), DEFVAL(Size2(0, 0)));
3135 ClassDB::bind_method(D_METHOD("get_size_override"), &Viewport::get_size_override);
3136 ClassDB::bind_method(D_METHOD("is_size_override_enabled"), &Viewport::is_size_override_enabled);
3137 ClassDB::bind_method(D_METHOD("set_size_override_stretch", "enabled"), &Viewport::set_size_override_stretch);
3138 ClassDB::bind_method(D_METHOD("is_size_override_stretch_enabled"), &Viewport::is_size_override_stretch_enabled);
3139
3140 ClassDB::bind_method(D_METHOD("set_vflip", "enable"), &Viewport::set_vflip);
3141 ClassDB::bind_method(D_METHOD("get_vflip"), &Viewport::get_vflip);
3142
3143 ClassDB::bind_method(D_METHOD("set_clear_mode", "mode"), &Viewport::set_clear_mode);
3144 ClassDB::bind_method(D_METHOD("get_clear_mode"), &Viewport::get_clear_mode);
3145
3146 ClassDB::bind_method(D_METHOD("set_update_mode", "mode"), &Viewport::set_update_mode);
3147 ClassDB::bind_method(D_METHOD("get_update_mode"), &Viewport::get_update_mode);
3148
3149 ClassDB::bind_method(D_METHOD("set_msaa", "msaa"), &Viewport::set_msaa);
3150 ClassDB::bind_method(D_METHOD("get_msaa"), &Viewport::get_msaa);
3151
3152 ClassDB::bind_method(D_METHOD("set_hdr", "enable"), &Viewport::set_hdr);
3153 ClassDB::bind_method(D_METHOD("get_hdr"), &Viewport::get_hdr);
3154
3155 ClassDB::bind_method(D_METHOD("set_usage", "usage"), &Viewport::set_usage);
3156 ClassDB::bind_method(D_METHOD("get_usage"), &Viewport::get_usage);
3157
3158 ClassDB::bind_method(D_METHOD("set_debug_draw", "debug_draw"), &Viewport::set_debug_draw);
3159 ClassDB::bind_method(D_METHOD("get_debug_draw"), &Viewport::get_debug_draw);
3160
3161 ClassDB::bind_method(D_METHOD("get_render_info", "info"), &Viewport::get_render_info);
3162
3163 ClassDB::bind_method(D_METHOD("get_texture"), &Viewport::get_texture);
3164
3165 ClassDB::bind_method(D_METHOD("set_physics_object_picking", "enable"), &Viewport::set_physics_object_picking);
3166 ClassDB::bind_method(D_METHOD("get_physics_object_picking"), &Viewport::get_physics_object_picking);
3167
3168 ClassDB::bind_method(D_METHOD("get_viewport_rid"), &Viewport::get_viewport_rid);
3169 ClassDB::bind_method(D_METHOD("input", "local_event"), &Viewport::input);
3170 ClassDB::bind_method(D_METHOD("unhandled_input", "local_event"), &Viewport::unhandled_input);
3171
3172 ClassDB::bind_method(D_METHOD("update_worlds"), &Viewport::update_worlds);
3173
3174 ClassDB::bind_method(D_METHOD("set_use_own_world", "enable"), &Viewport::set_use_own_world);
3175 ClassDB::bind_method(D_METHOD("is_using_own_world"), &Viewport::is_using_own_world);
3176
3177 ClassDB::bind_method(D_METHOD("get_camera"), &Viewport::get_camera);
3178
3179 ClassDB::bind_method(D_METHOD("set_as_audio_listener", "enable"), &Viewport::set_as_audio_listener);
3180 ClassDB::bind_method(D_METHOD("is_audio_listener"), &Viewport::is_audio_listener);
3181
3182 ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d);
3183 ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d);
3184 ClassDB::bind_method(D_METHOD("set_attach_to_screen_rect", "rect"), &Viewport::set_attach_to_screen_rect);
3185 ClassDB::bind_method(D_METHOD("set_use_render_direct_to_screen", "enable"), &Viewport::set_use_render_direct_to_screen);
3186 ClassDB::bind_method(D_METHOD("is_using_render_direct_to_screen"), &Viewport::is_using_render_direct_to_screen);
3187
3188 ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position);
3189 ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse);
3190
3191 ClassDB::bind_method(D_METHOD("gui_has_modal_stack"), &Viewport::gui_has_modal_stack);
3192 ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data);
3193 ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging);
3194
3195 ClassDB::bind_method(D_METHOD("get_modal_stack_top"), &Viewport::get_modal_stack_top);
3196
3197 ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input);
3198 ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled);
3199
3200 ClassDB::bind_method(D_METHOD("set_disable_3d", "disable"), &Viewport::set_disable_3d);
3201 ClassDB::bind_method(D_METHOD("is_3d_disabled"), &Viewport::is_3d_disabled);
3202
3203 ClassDB::bind_method(D_METHOD("set_keep_3d_linear", "keep_3d_linear"), &Viewport::set_keep_3d_linear);
3204 ClassDB::bind_method(D_METHOD("get_keep_3d_linear"), &Viewport::get_keep_3d_linear);
3205
3206 ClassDB::bind_method(D_METHOD("_gui_show_tooltip"), &Viewport::_gui_show_tooltip);
3207 ClassDB::bind_method(D_METHOD("_gui_remove_focus"), &Viewport::_gui_remove_focus);
3208 ClassDB::bind_method(D_METHOD("_post_gui_grab_click_focus"), &Viewport::_post_gui_grab_click_focus);
3209
3210 ClassDB::bind_method(D_METHOD("set_shadow_atlas_size", "size"), &Viewport::set_shadow_atlas_size);
3211 ClassDB::bind_method(D_METHOD("get_shadow_atlas_size"), &Viewport::get_shadow_atlas_size);
3212
3213 ClassDB::bind_method(D_METHOD("set_snap_controls_to_pixels", "enabled"), &Viewport::set_snap_controls_to_pixels);
3214 ClassDB::bind_method(D_METHOD("is_snap_controls_to_pixels_enabled"), &Viewport::is_snap_controls_to_pixels_enabled);
3215
3216 ClassDB::bind_method(D_METHOD("set_shadow_atlas_quadrant_subdiv", "quadrant", "subdiv"), &Viewport::set_shadow_atlas_quadrant_subdiv);
3217 ClassDB::bind_method(D_METHOD("get_shadow_atlas_quadrant_subdiv", "quadrant"), &Viewport::get_shadow_atlas_quadrant_subdiv);
3218
3219 ClassDB::bind_method(D_METHOD("set_input_as_handled"), &Viewport::set_input_as_handled);
3220 ClassDB::bind_method(D_METHOD("is_input_handled"), &Viewport::is_input_handled);
3221
3222 ClassDB::bind_method(D_METHOD("set_handle_input_locally", "enable"), &Viewport::set_handle_input_locally);
3223 ClassDB::bind_method(D_METHOD("is_handling_input_locally"), &Viewport::is_handling_input_locally);
3224
3225 ClassDB::bind_method(D_METHOD("_subwindow_visibility_changed"), &Viewport::_subwindow_visibility_changed);
3226
3227 ClassDB::bind_method(D_METHOD("_own_world_changed"), &Viewport::_own_world_changed);
3228
3229 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arvr"), "set_use_arvr", "use_arvr");
3230
3231 ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
3232 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "size_override_stretch"), "set_size_override_stretch", "is_size_override_stretch_enabled");
3233 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world"), "set_use_own_world", "is_using_own_world");
3234 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world", PROPERTY_HINT_RESOURCE_TYPE, "World"), "set_world", "get_world");
3235 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
3236 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transparent_bg"), "set_transparent_background", "has_transparent_background");
3237 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally");
3238 ADD_GROUP("Rendering", "");
3239 ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa");
3240 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hdr"), "set_hdr", "get_hdr");
3241 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled");
3242 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_3d_linear"), "set_keep_3d_linear", "get_keep_3d_linear");
3243 ADD_PROPERTY(PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_ENUM, "2D,2D No-Sampling,3D,3D No-Effects"), "set_usage", "get_usage");
3244 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_direct_to_screen"), "set_use_render_direct_to_screen", "is_using_render_direct_to_screen");
3245 ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
3246 ADD_GROUP("Render Target", "render_target_");
3247 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_target_v_flip"), "set_vflip", "get_vflip");
3248 ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_clear_mode", PROPERTY_HINT_ENUM, "Always,Never,Next Frame"), "set_clear_mode", "get_clear_mode");
3249 ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_update_mode", PROPERTY_HINT_ENUM, "Disabled,Once,When Visible,Always"), "set_update_mode", "get_update_mode");
3250 ADD_GROUP("Audio Listener", "audio_listener_");
3251 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_2d"), "set_as_audio_listener_2d", "is_audio_listener_2d");
3252 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_3d"), "set_as_audio_listener", "is_audio_listener");
3253 ADD_GROUP("Physics", "physics_");
3254 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking"), "set_physics_object_picking", "get_physics_object_picking");
3255 ADD_GROUP("GUI", "gui_");
3256 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_disable_input"), "set_disable_input", "is_input_disabled");
3257 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_snap_controls_to_pixels"), "set_snap_controls_to_pixels", "is_snap_controls_to_pixels_enabled");
3258 ADD_GROUP("Shadow Atlas", "shadow_atlas_");
3259 ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_atlas_size"), "set_shadow_atlas_size", "get_shadow_atlas_size");
3260 ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_0", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 0);
3261 ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_1", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 1);
3262 ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_2", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 2);
3263 ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_3", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 3);
3264 ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_canvas_transform", "get_canvas_transform");
3265 ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_global_canvas_transform", "get_global_canvas_transform");
3266
3267 ADD_SIGNAL(MethodInfo("size_changed"));
3268 ADD_SIGNAL(MethodInfo("gui_focus_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
3269
3270 BIND_ENUM_CONSTANT(UPDATE_DISABLED);
3271 BIND_ENUM_CONSTANT(UPDATE_ONCE);
3272 BIND_ENUM_CONSTANT(UPDATE_WHEN_VISIBLE);
3273 BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
3274
3275 BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED);
3276 BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_1);
3277 BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_4);
3278 BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_16);
3279 BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_64);
3280 BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_256);
3281 BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_1024);
3282 BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_MAX);
3283
3284 BIND_ENUM_CONSTANT(RENDER_INFO_OBJECTS_IN_FRAME);
3285 BIND_ENUM_CONSTANT(RENDER_INFO_VERTICES_IN_FRAME);
3286 BIND_ENUM_CONSTANT(RENDER_INFO_MATERIAL_CHANGES_IN_FRAME);
3287 BIND_ENUM_CONSTANT(RENDER_INFO_SHADER_CHANGES_IN_FRAME);
3288 BIND_ENUM_CONSTANT(RENDER_INFO_SURFACE_CHANGES_IN_FRAME);
3289 BIND_ENUM_CONSTANT(RENDER_INFO_DRAW_CALLS_IN_FRAME);
3290 BIND_ENUM_CONSTANT(RENDER_INFO_2D_ITEMS_IN_FRAME);
3291 BIND_ENUM_CONSTANT(RENDER_INFO_2D_DRAW_CALLS_IN_FRAME);
3292 BIND_ENUM_CONSTANT(RENDER_INFO_MAX);
3293
3294 BIND_ENUM_CONSTANT(DEBUG_DRAW_DISABLED);
3295 BIND_ENUM_CONSTANT(DEBUG_DRAW_UNSHADED);
3296 BIND_ENUM_CONSTANT(DEBUG_DRAW_OVERDRAW);
3297 BIND_ENUM_CONSTANT(DEBUG_DRAW_WIREFRAME);
3298
3299 BIND_ENUM_CONSTANT(MSAA_DISABLED);
3300 BIND_ENUM_CONSTANT(MSAA_2X);
3301 BIND_ENUM_CONSTANT(MSAA_4X);
3302 BIND_ENUM_CONSTANT(MSAA_8X);
3303 BIND_ENUM_CONSTANT(MSAA_16X);
3304
3305 BIND_ENUM_CONSTANT(USAGE_2D);
3306 BIND_ENUM_CONSTANT(USAGE_2D_NO_SAMPLING);
3307 BIND_ENUM_CONSTANT(USAGE_3D);
3308 BIND_ENUM_CONSTANT(USAGE_3D_NO_EFFECTS);
3309
3310 BIND_ENUM_CONSTANT(CLEAR_MODE_ALWAYS);
3311 BIND_ENUM_CONSTANT(CLEAR_MODE_NEVER);
3312 BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME);
3313 }
3314
_subwindow_visibility_changed()3315 void Viewport::_subwindow_visibility_changed() {
3316
3317 // unfortunately, we don't know the sender, i.e. which subwindow changed;
3318 // so we have to check them all.
3319 gui.subwindow_visibility_dirty = true;
3320 }
3321
Viewport()3322 Viewport::Viewport() {
3323
3324 world_2d = Ref<World2D>(memnew(World2D));
3325
3326 viewport = VisualServer::get_singleton()->viewport_create();
3327 texture_rid = VisualServer::get_singleton()->viewport_get_texture(viewport);
3328 texture_flags = 0;
3329
3330 render_direct_to_screen = false;
3331
3332 default_texture.instance();
3333 default_texture->vp = const_cast<Viewport *>(this);
3334 viewport_textures.insert(default_texture.ptr());
3335 VS::get_singleton()->texture_set_proxy(default_texture->proxy, texture_rid);
3336
3337 //internal_listener = SpatialSoundServer::get_singleton()->listener_create();
3338 audio_listener = false;
3339 //internal_listener_2d = SpatialSound2DServer::get_singleton()->listener_create();
3340 audio_listener_2d = false;
3341 transparent_bg = false;
3342 parent = NULL;
3343 listener = NULL;
3344 camera = NULL;
3345 override_canvas_transform = false;
3346 canvas_layers.insert(NULL); // This eases picking code (interpreted as the canvas of the Viewport)
3347 arvr = false;
3348 size_override = false;
3349 size_override_stretch = false;
3350 size_override_size = Size2(1, 1);
3351 gen_mipmaps = false;
3352
3353 vflip = false;
3354
3355 //clear=true;
3356 update_mode = UPDATE_WHEN_VISIBLE;
3357
3358 physics_object_picking = false;
3359 physics_object_capture = 0;
3360 physics_object_over = 0;
3361 physics_has_last_mousepos = false;
3362 physics_last_mousepos = Vector2(Math_INF, Math_INF);
3363
3364 shadow_atlas_size = 0;
3365 for (int i = 0; i < 4; i++) {
3366 shadow_atlas_quadrant_subdiv[i] = SHADOW_ATLAS_QUADRANT_SUBDIV_MAX;
3367 }
3368 set_shadow_atlas_quadrant_subdiv(0, SHADOW_ATLAS_QUADRANT_SUBDIV_4);
3369 set_shadow_atlas_quadrant_subdiv(1, SHADOW_ATLAS_QUADRANT_SUBDIV_4);
3370 set_shadow_atlas_quadrant_subdiv(2, SHADOW_ATLAS_QUADRANT_SUBDIV_16);
3371 set_shadow_atlas_quadrant_subdiv(3, SHADOW_ATLAS_QUADRANT_SUBDIV_64);
3372
3373 String id = itos(get_instance_id());
3374 input_group = "_vp_input" + id;
3375 gui_input_group = "_vp_gui_input" + id;
3376 unhandled_input_group = "_vp_unhandled_input" + id;
3377 unhandled_key_input_group = "_vp_unhandled_key_input" + id;
3378
3379 disable_input = false;
3380 disable_3d = false;
3381 keep_3d_linear = false;
3382
3383 //window tooltip
3384 gui.tooltip_timer = -1;
3385
3386 //gui.tooltip_timer->force_parent_owned();
3387 gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.5);
3388 ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::REAL, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
3389
3390 gui.tooltip = NULL;
3391 gui.tooltip_label = NULL;
3392 gui.drag_preview = NULL;
3393 gui.drag_attempted = false;
3394 gui.canvas_sort_index = 0;
3395 gui.roots_order_dirty = false;
3396 gui.mouse_focus = NULL;
3397 gui.last_mouse_focus = NULL;
3398
3399 msaa = MSAA_DISABLED;
3400 hdr = true;
3401
3402 usage = USAGE_3D;
3403 debug_draw = DEBUG_DRAW_DISABLED;
3404 clear_mode = CLEAR_MODE_ALWAYS;
3405
3406 snap_controls_to_pixels = true;
3407 physics_last_mouse_state.alt = false;
3408 physics_last_mouse_state.control = false;
3409 physics_last_mouse_state.shift = false;
3410 physics_last_mouse_state.meta = false;
3411 physics_last_mouse_state.mouse_mask = 0;
3412 local_input_handled = false;
3413 handle_input_locally = true;
3414 physics_last_id = 0; //ensures first time there will be a check
3415 }
3416
~Viewport()3417 Viewport::~Viewport() {
3418
3419 //erase itself from viewport textures
3420 for (Set<ViewportTexture *>::Element *E = viewport_textures.front(); E; E = E->next()) {
3421 E->get()->vp = NULL;
3422 }
3423 VisualServer::get_singleton()->free(viewport);
3424 //SpatialSoundServer::get_singleton()->free(internal_listener);
3425 //SpatialSound2DServer::get_singleton()->free(internal_listener_2d);
3426 }
3427