diff --git a/doc/classes/SubViewportContainer.xml b/doc/classes/SubViewportContainer.xml index b01a81a61f0..92c360d51fc 100644 --- a/doc/classes/SubViewportContainer.xml +++ b/doc/classes/SubViewportContainer.xml @@ -20,6 +20,9 @@ + + If [code]true[/code], the sub-viewport will be automatically resized according to the viewport stretch transform. It is especially useful for DPI-aware projects. See [method Viewport.get_stretch_transform] for more details about stretch transform. + Configure, if either the [SubViewportContainer] or alternatively the [Control] nodes of its [SubViewport] children should be available as targets of mouse-related functionalities, like identifying the drop target in drag-and-drop operations or cursor shape of hovered [Control] node. @@ -30,7 +33,12 @@ If [code]true[/code], the sub-viewport will be automatically resized to the control's size. [b]Note:[/b] If [code]true[/code], this will prohibit changing [member SubViewport.size] of its children manually. - + + Multiplies the sub-viewport's effective resolution by this value while preserving its scale. This can be used either to speed up rendering or to render at an higher resolution. + For example, a 1280×720 sub-viewport with [member stretch_shrink] set to [code]0.5[/code] will be rendered at 640×360 while occupying the same size in the container. + [b]Note:[/b] [member stretch] must be [code]true[/code] for this property to work. + + Divides the sub-viewport's effective resolution by this value while preserving its scale. This can be used to speed up rendering. For example, a 1280×720 sub-viewport with [member stretch_shrink] set to [code]2[/code] will be rendered at 640×360 while occupying the same size in the container. [b]Note:[/b] [member stretch] must be [code]true[/code] for this property to work. diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 2e89bb47061..07f65effee3 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -697,7 +697,7 @@ void Node3DEditorViewport::cancel_transform() { void Node3DEditorViewport::_update_shrink() { bool shrink = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_HALF_RESOLUTION)); - subviewport_container->set_stretch_shrink(shrink ? 2 : 1); + subviewport_container->set_stretch_factor(shrink ? 0.5 : 1.0); subviewport_container->set_texture_filter(shrink ? TEXTURE_FILTER_NEAREST : TEXTURE_FILTER_PARENT_NODE); } @@ -722,11 +722,11 @@ Vector3 Node3DEditorViewport::_get_camera_position() const { } Point2 Node3DEditorViewport::point_to_screen(const Vector3 &p_point) { - return camera->unproject_position(p_point) * subviewport_container->get_stretch_shrink(); + return camera->unproject_position(p_point) / subviewport_container->get_stretch_factor(); } Vector3 Node3DEditorViewport::get_ray_pos(const Vector2 &p_pos) const { - return camera->project_ray_origin(p_pos / subviewport_container->get_stretch_shrink()); + return camera->project_ray_origin(p_pos * subviewport_container->get_stretch_factor()); } Vector3 Node3DEditorViewport::_get_camera_normal() const { @@ -734,7 +734,7 @@ Vector3 Node3DEditorViewport::_get_camera_normal() const { } Vector3 Node3DEditorViewport::get_ray(const Vector2 &p_pos) const { - return camera->project_ray_normal(p_pos / subviewport_container->get_stretch_shrink()); + return camera->project_ray_normal(p_pos * subviewport_container->get_stretch_factor()); } void Node3DEditorViewport::_clear_selected() { @@ -813,7 +813,7 @@ void Node3DEditorViewport::_select_clicked(bool p_allow_locked) { ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const { Vector3 ray = get_ray(p_pos); Vector3 pos = get_ray_pos(p_pos); - Vector2 shrinked_pos = p_pos / subviewport_container->get_stretch_shrink(); + Vector2 shrinked_pos = p_pos * subviewport_container->get_stretch_factor(); if (viewport->get_debug_draw() == Viewport::DEBUG_DRAW_SDFGI_PROBES) { RS::get_singleton()->sdfgi_set_debug_probe_select(pos, ray); @@ -4085,8 +4085,8 @@ void Node3DEditorViewport::update_transform_gizmo_view() { const int viewport_base_height = 400 * MAX(1, EDSCALE); gizmo_scale = (gizmo_size / Math::abs(dd)) * MAX(1, EDSCALE) * - MIN(viewport_base_height, subviewport_container->get_size().height) / viewport_base_height / - subviewport_container->get_stretch_shrink(); + MIN(viewport_base_height, subviewport_container->get_size().height) / viewport_base_height * + subviewport_container->get_stretch_ratio(); Vector3 scale = Vector3(1, 1, 1) * gizmo_scale; // if the determinant is zero, we should disable the gizmo from being rendered @@ -4310,7 +4310,7 @@ Dictionary Node3DEditorViewport::get_state() const { d["grid"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GRID)); d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); d["frame_time"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FRAME_TIME)); - d["half_res"] = subviewport_container->get_stretch_shrink() > 1; + d["half_res"] = subviewport_container->get_stretch_factor() < 1.0; d["cinematic_preview"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW)); if (previewing) { d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing); diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index 9e885e9d629..c1a774cb97e 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -67,18 +67,6 @@ bool SubViewportContainer::is_stretch_enabled() const { return stretch; } -void SubViewportContainer::set_stretch_shrink(int p_shrink) { - ERR_FAIL_COND(p_shrink < 1); - if (shrink == p_shrink) { - return; - } - - shrink = p_shrink; - - recalc_force_viewport_sizes(); - queue_redraw(); -} - void SubViewportContainer::recalc_force_viewport_sizes() { if (!stretch) { return; @@ -91,12 +79,54 @@ void SubViewportContainer::recalc_force_viewport_sizes() { continue; } - c->set_size_force(get_size() / shrink); + Vector2 new_size = get_size(); + if (apply_viewport_stretch_transform) { + new_size *= get_viewport()->get_stretch_transform().get_scale().x; + } + new_size *= stretch_factor; + c->set_size_force(new_size); } } +void SubViewportContainer::set_apply_viewport_stretch_transform(bool p_apply_viewport_stretch_transform) { + if (p_apply_viewport_stretch_transform == apply_viewport_stretch_transform) { + return; + } + + apply_viewport_stretch_transform = p_apply_viewport_stretch_transform; + + recalc_force_viewport_sizes(); + queue_redraw(); +} + +bool SubViewportContainer::is_applying_viewport_stretch_transform() const { + return apply_viewport_stretch_transform; +} + +#ifndef DISABLE_DEPRECATED +void SubViewportContainer::set_stretch_shrink(int p_shrink) { + ERR_FAIL_COND(p_shrink < 1); + set_stretch_factor(1.0 / p_shrink); +} + int SubViewportContainer::get_stretch_shrink() const { - return shrink; + return Math::round(1.0 / get_stretch_factor()); +} +#endif + +void SubViewportContainer::set_stretch_factor(float p_stretch_factor) { + if (p_stretch_factor == stretch_factor) { + return; + } + + stretch_factor = p_stretch_factor; + + recalc_force_viewport_sizes(); + queue_redraw(); +} + +float SubViewportContainer::get_stretch_factor() const { + return stretch_factor; } Vector SubViewportContainer::get_allowed_size_flags_horizontal() const { @@ -217,9 +247,9 @@ void SubViewportContainer::gui_input(const Ref &p_event) { } } - if (stretch && shrink > 1) { + if (stretch && stretch_factor < 1) { Transform2D xform; - xform.scale(Vector2(1, 1) / shrink); + xform.scale(Vector2(1, 1) * stretch_factor); _send_event_to_viewports(p_event->xformed_by(xform)); } else { _send_event_to_viewports(p_event); @@ -291,14 +321,25 @@ void SubViewportContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stretch", "enable"), &SubViewportContainer::set_stretch); ClassDB::bind_method(D_METHOD("is_stretch_enabled"), &SubViewportContainer::is_stretch_enabled); + ClassDB::bind_method(D_METHOD("set_apply_viewport_stretch_transform", "apply_viewport_stretch_transform"), &SubViewportContainer::set_apply_viewport_stretch_transform); + ClassDB::bind_method(D_METHOD("is_applying_viewport_stretch_transform"), &SubViewportContainer::is_applying_viewport_stretch_transform); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("set_stretch_shrink", "amount"), &SubViewportContainer::set_stretch_shrink); ClassDB::bind_method(D_METHOD("get_stretch_shrink"), &SubViewportContainer::get_stretch_shrink); +#endif + ClassDB::bind_method(D_METHOD("set_stretch_factor", "stretch_factor"), &SubViewportContainer::set_stretch_factor); + ClassDB::bind_method(D_METHOD("get_stretch_factor"), &SubViewportContainer::get_stretch_factor); ClassDB::bind_method(D_METHOD("set_mouse_target", "amount"), &SubViewportContainer::set_mouse_target); ClassDB::bind_method(D_METHOD("is_mouse_target_enabled"), &SubViewportContainer::is_mouse_target_enabled); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch"), "set_stretch", "is_stretch_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "apply_viewport_stretch_transform"), "set_apply_viewport_stretch_transform", "is_applying_viewport_stretch_transform"); +#ifndef DISABLE_DEPRECTED ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink", PROPERTY_HINT_RANGE, "1,32,1,or_greater"), "set_stretch_shrink", "get_stretch_shrink"); +#endif + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stretch_factor", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_greater"), "set_stretch_factor", "get_stretch_factor"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mouse_target"), "set_mouse_target", "is_mouse_target_enabled"); GDVIRTUAL_BIND(_propagate_input_event, "event"); diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h index 660f9edf749..29c69606ce1 100644 --- a/scene/gui/subviewport_container.h +++ b/scene/gui/subviewport_container.h @@ -37,7 +37,8 @@ class SubViewportContainer : public Container { GDCLASS(SubViewportContainer, Container); bool stretch = false; - int shrink = 1; + bool apply_viewport_stretch_transform = false; + float stretch_factor = 1.0f; bool mouse_target = false; void _notify_viewports(int p_notification); @@ -61,8 +62,15 @@ public: virtual void input(const Ref &p_event) override; virtual void unhandled_input(const Ref &p_event) override; virtual void gui_input(const Ref &p_event) override; + + void set_apply_viewport_stretch_transform(bool p_apply_viewport_stretch_transform); + bool is_applying_viewport_stretch_transform() const; +#ifndef DISABLE_DEPRECATED void set_stretch_shrink(int p_shrink); int get_stretch_shrink() const; +#endif + void set_stretch_factor(float p_stretch_factor); + float get_stretch_factor() const; void recalc_force_viewport_sizes(); void set_mouse_target(bool p_enable); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 76b2502bade..91aed97eee1 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3147,7 +3147,7 @@ void Viewport::_update_mouse_over(Vector2 p_pos) { } Vector2 pos = c->get_global_transform_with_canvas().affine_inverse().xform(p_pos); if (c->is_stretch_enabled()) { - pos /= c->get_stretch_shrink(); + pos *= c->get_stretch_factor(); } for (int i = 0; i < c->get_child_count(); i++) { @@ -5256,7 +5256,7 @@ Transform2D SubViewport::get_screen_transform_internal(bool p_absolute_position) SubViewportContainer *c = Object::cast_to(get_parent()); if (c) { if (c->is_stretch_enabled()) { - container_transform.scale(Vector2(c->get_stretch_shrink(), c->get_stretch_shrink())); + container_transform.scale(Vector2(1.0 / c->get_stretch_factor(), 1.0 / c->get_stretch_factor())); } container_transform = c->get_viewport()->get_screen_transform_internal(p_absolute_position) * c->get_global_transform_with_canvas() * container_transform; } else { @@ -5276,7 +5276,7 @@ Transform2D SubViewport::get_popup_base_transform() const { } Transform2D container_transform; if (c->is_stretch_enabled()) { - container_transform.scale(Vector2(c->get_stretch_shrink(), c->get_stretch_shrink())); + container_transform.scale(Vector2(1.0 / c->get_stretch_factor(), 1.0 / c->get_stretch_factor())); } return c->get_screen_transform() * container_transform * get_final_transform(); }