From 87cfc415a349cf2ef5d85a2045bf2089dcfa5432 Mon Sep 17 00:00:00 2001 From: Riteo Date: Thu, 6 Apr 2023 23:41:27 +0200 Subject: [PATCH] Add content scale stretch modes, implement integer scaling Integer scaling is achieved (after aspect expansion) by "lying" to the stretching code about the window's size, telling it that it's always an integer multiple of the viewport so that it only gets stretched to an integer factor. This approach works with all stretch and aspect modes and doesn't require handling for each, only requiring to "loosen up" some self-excluding conditions (in other words, replacing some `else if`s with just `if`s) regarding viewport offset and margin calculation (black bars). Includes a tiny usability change that adds a range hint for the content scale factor between 0.5 to 8.0. Co-Authored-By: Hugo Locurcio --- core/config/project_settings.cpp | 1 + doc/classes/ProjectSettings.xml | 4 +++ doc/classes/Window.xml | 9 +++++++ main/main.cpp | 7 +++++ scene/main/window.cpp | 46 +++++++++++++++++++++++++++++--- scene/main/window.h | 10 +++++++ 6 files changed, 74 insertions(+), 3 deletions(-) diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index ac5499d7095..9d1e19d146f 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1328,6 +1328,7 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,canvas_items,viewport"), "disabled"); GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand"), "keep"); GLOBAL_DEF_BASIC(PropertyInfo(Variant::FLOAT, "display/window/stretch/scale", PROPERTY_HINT_RANGE, "0.5,8.0,0.01"), 1.0); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/window/stretch/scale_mode", PROPERTY_HINT_ENUM, "fractional,integer"), "fractional"); GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1"), 16384); diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 1a77e7c5255..1390d2e9ba2 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -712,6 +712,10 @@ + The scale factor multiplier to use for 2D elements. This multiplies the final scale factor determined by [member display/window/stretch/mode]. If using the [b]Disabled[/b] stretch mode, this scale factor is applied as-is. This can be adjusted to make the UI easier to read on certain displays. + + + The policy to use to determine the final scale factor for 2D elements. This affects how [member display/window/stretch/scale] is applied, in addition to the automatic scale factor determined by [member display/window/stretch/mode]. If [code]true[/code] subwindows are embedded in the main window. diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index d194f7dd6c6..4d72f0845ec 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -505,6 +505,9 @@ Base size of the content (i.e. nodes that are drawn inside the window). If non-zero, [Window]'s content will be scaled when the window is resized to a different size. + + The policy to use to determine the final scale factor for 2D elements. This affects how [member content_scale_factor] is applied, in addition to the automatic scale factor determined by [member content_scale_size]. + The screen the window is currently on. @@ -766,6 +769,12 @@ The content's aspect will be preserved. If the target size has different aspect from the base one, the content will stay in the top-left corner and add an extra visible area in the stretched space. + + The content will be stretched according to a fractional factor. This fills all the space available in the window, but allows "pixel wobble" to occur due to uneven pixel scaling. + + + The content will be stretched only according to an integer factor, preserving sharp pixels. This may leave a black background visible on the window's edges depending on the window size. + Automatic layout direction, determined from the parent window layout direction. diff --git a/main/main.cpp b/main/main.cpp index fbd0b75e58a..2af63a3391b 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2835,6 +2835,7 @@ bool Main::start() { Size2i stretch_size = Size2i(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height")); real_t stretch_scale = GLOBAL_GET("display/window/stretch/scale"); + String stretch_scale_mode = GLOBAL_GET("display/window/stretch/scale_mode"); Window::ContentScaleMode cs_sm = Window::CONTENT_SCALE_MODE_DISABLED; if (stretch_mode == "canvas_items") { @@ -2854,8 +2855,14 @@ bool Main::start() { cs_aspect = Window::CONTENT_SCALE_ASPECT_EXPAND; } + Window::ContentScaleStretch cs_stretch = Window::CONTENT_SCALE_STRETCH_FRACTIONAL; + if (stretch_scale_mode == "integer") { + cs_stretch = Window::CONTENT_SCALE_STRETCH_INTEGER; + } + sml->get_root()->set_content_scale_mode(cs_sm); sml->get_root()->set_content_scale_aspect(cs_aspect); + sml->get_root()->set_content_scale_stretch(cs_stretch); sml->get_root()->set_content_scale_size(stretch_size); sml->get_root()->set_content_scale_factor(stretch_scale); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index dbc778deec2..a846f953861 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -929,6 +929,17 @@ void Window::_update_viewport_size() { float font_oversampling = 1.0; window_transform = Transform2D(); + if (content_scale_stretch == Window::CONTENT_SCALE_STRETCH_INTEGER) { + // We always want to make sure that the content scale factor is a whole + // number, else there will be pixel wobble no matter what. + content_scale_factor = Math::floor(content_scale_factor); + + // A content scale factor of zero is pretty useless. + if (content_scale_factor < 1) { + content_scale_factor = 1; + } + } + if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) { font_oversampling = content_scale_factor; final_size = size; @@ -982,13 +993,26 @@ void Window::_update_viewport_size() { screen_size = screen_size.floor(); viewport_size = viewport_size.floor(); + if (content_scale_stretch == Window::CONTENT_SCALE_STRETCH_INTEGER) { + Size2i screen_scale = (screen_size / viewport_size).floor(); + int scale_factor = MIN(screen_scale.x, screen_scale.y); + + if (scale_factor < 1) { + scale_factor = 1; + } + + screen_size = viewport_size * scale_factor; + } + Size2 margin; Size2 offset; - if (content_scale_aspect != CONTENT_SCALE_ASPECT_EXPAND && screen_size.x < video_mode.x) { + if (screen_size.x < video_mode.x) { margin.x = Math::round((video_mode.x - screen_size.x) / 2.0); offset.x = Math::round(margin.x * viewport_size.y / screen_size.y); - } else if (content_scale_aspect != CONTENT_SCALE_ASPECT_EXPAND && screen_size.y < video_mode.y) { + } + + if (screen_size.y < video_mode.y) { margin.y = Math::round((video_mode.y - screen_size.y) / 2.0); offset.y = Math::round(margin.y * viewport_size.x / screen_size.x); } @@ -1236,6 +1260,15 @@ Window::ContentScaleAspect Window::get_content_scale_aspect() const { return content_scale_aspect; } +void Window::set_content_scale_stretch(ContentScaleStretch p_stretch) { + content_scale_stretch = p_stretch; + _update_viewport_size(); +} + +Window::ContentScaleStretch Window::get_content_scale_stretch() const { + return content_scale_stretch; +} + void Window::set_content_scale_factor(real_t p_factor) { ERR_FAIL_COND(p_factor <= 0); content_scale_factor = p_factor; @@ -2350,6 +2383,9 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("set_content_scale_aspect", "aspect"), &Window::set_content_scale_aspect); ClassDB::bind_method(D_METHOD("get_content_scale_aspect"), &Window::get_content_scale_aspect); + ClassDB::bind_method(D_METHOD("set_content_scale_stretch", "stretch"), &Window::set_content_scale_stretch); + ClassDB::bind_method(D_METHOD("get_content_scale_stretch"), &Window::get_content_scale_stretch); + ClassDB::bind_method(D_METHOD("set_content_scale_factor", "factor"), &Window::set_content_scale_factor); ClassDB::bind_method(D_METHOD("get_content_scale_factor"), &Window::get_content_scale_factor); @@ -2460,7 +2496,8 @@ void Window::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "content_scale_size"), "set_content_scale_size", "get_content_scale_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_mode", PROPERTY_HINT_ENUM, "Disabled,Canvas Items,Viewport"), "set_content_scale_mode", "get_content_scale_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_aspect", PROPERTY_HINT_ENUM, "Ignore,Keep,Keep Width,Keep Height,Expand"), "set_content_scale_aspect", "get_content_scale_aspect"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "content_scale_factor"), "set_content_scale_factor", "get_content_scale_factor"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_stretch", PROPERTY_HINT_ENUM, "Fractional,Integer"), "set_content_scale_stretch", "get_content_scale_stretch"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "content_scale_factor", PROPERTY_HINT_RANGE, "0.5,8.0,0.01"), "set_content_scale_factor", "get_content_scale_factor"); ADD_GROUP("Localization", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate"), "set_auto_translate", "is_auto_translating"); @@ -2512,6 +2549,9 @@ void Window::_bind_methods() { BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_KEEP_HEIGHT); BIND_ENUM_CONSTANT(CONTENT_SCALE_ASPECT_EXPAND); + BIND_ENUM_CONSTANT(CONTENT_SCALE_STRETCH_FRACTIONAL); + BIND_ENUM_CONSTANT(CONTENT_SCALE_STRETCH_INTEGER); + BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_INHERITED); BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LOCALE); BIND_ENUM_CONSTANT(LAYOUT_DIRECTION_LTR); diff --git a/scene/main/window.h b/scene/main/window.h index 1695a227888..30a91829073 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -77,6 +77,11 @@ public: CONTENT_SCALE_ASPECT_EXPAND, }; + enum ContentScaleStretch { + CONTENT_SCALE_STRETCH_FRACTIONAL, + CONTENT_SCALE_STRETCH_INTEGER, + }; + enum LayoutDirection { LAYOUT_DIRECTION_INHERITED, LAYOUT_DIRECTION_LOCALE, @@ -130,6 +135,7 @@ private: Size2i content_scale_size; ContentScaleMode content_scale_mode = CONTENT_SCALE_MODE_DISABLED; ContentScaleAspect content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE; + ContentScaleStretch content_scale_stretch = CONTENT_SCALE_STRETCH_FRACTIONAL; real_t content_scale_factor = 1.0; void _make_window(); @@ -289,6 +295,9 @@ public: void set_content_scale_aspect(ContentScaleAspect p_aspect); ContentScaleAspect get_content_scale_aspect() const; + void set_content_scale_stretch(ContentScaleStretch p_stretch); + ContentScaleStretch get_content_scale_stretch() const; + void set_content_scale_factor(real_t p_factor); real_t get_content_scale_factor() const; @@ -399,6 +408,7 @@ VARIANT_ENUM_CAST(Window::Mode); VARIANT_ENUM_CAST(Window::Flags); VARIANT_ENUM_CAST(Window::ContentScaleMode); VARIANT_ENUM_CAST(Window::ContentScaleAspect); +VARIANT_ENUM_CAST(Window::ContentScaleStretch); VARIANT_ENUM_CAST(Window::LayoutDirection); VARIANT_ENUM_CAST(Window::WindowInitialPosition);