diff --git a/main/main.cpp b/main/main.cpp index 551b5ccf5d9c..30d17c21b651 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1829,6 +1829,8 @@ bool Main::start() { sml_aspect = SceneTree::STRETCH_ASPECT_KEEP_HEIGHT; else if (stretch_aspect == "expand") sml_aspect = SceneTree::STRETCH_ASPECT_EXPAND; + else if (stretch_aspect == "pixelperfect") + sml_aspect = SceneTree::STRETCH_ASPECT_PIXELPERFECT; sml->set_screen_stretch(sml_sm, sml_aspect, stretch_size, stretch_shrink); @@ -1870,7 +1872,7 @@ bool Main::start() { GLOBAL_DEF("display/window/stretch/mode", "disabled"); ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/mode", PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,2d,viewport")); GLOBAL_DEF("display/window/stretch/aspect", "ignore"); - ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect", PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand")); + ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect", PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand,pixelperfect")); GLOBAL_DEF("display/window/stretch/shrink", 1.0); ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink", PropertyInfo(Variant::REAL, "display/window/stretch/shrink", PROPERTY_HINT_RANGE, "1.0,8.0,0.1")); sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true)); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 238d6c20ccd2..14c833c64128 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -51,6 +51,8 @@ #include "viewport.h" #include +#include +#include void SceneTreeTimer::_bind_methods() { @@ -1153,7 +1155,20 @@ void SceneTree::_update_root_rect() { WARN_PRINT("Font oversampling only works with the resize modes 'Keep Width', 'Keep Height', and 'Expand'."); } - if (stretch_aspect == STRETCH_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) { + if (stretch_aspect == STRETCH_ASPECT_PIXELPERFECT) { + // only multiply or divide by integer + viewport_size = desired_res; + + if (video_mode >= desired_res) { + Size2 scale_size = video_mode / desired_res; + int scale_factor = std::floor(std::min(scale_size.x, scale_size.y)); + screen_size = desired_res * scale_factor; + } else { + Size2 scale_size = desired_res / video_mode; + int scale_factor = std::ceil(std::max(scale_size.x, scale_size.y)); + screen_size = desired_res / scale_factor; + } + } else if (stretch_aspect == STRETCH_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) { //same aspect or ignore aspect viewport_size = desired_res; screen_size = video_mode; @@ -1196,7 +1211,13 @@ void SceneTree::_update_root_rect() { Size2 margin; Size2 offset; //black bars and margin - if (stretch_aspect != STRETCH_ASPECT_EXPAND && screen_size.x < video_mode.x) { + if (stretch_aspect == STRETCH_ASPECT_PIXELPERFECT) { + margin.y = Math::round((video_mode.y - screen_size.y) / 2.0); + margin.x = Math::round((video_mode.x - screen_size.x) / 2.0); + VisualServer::get_singleton()->black_bars_set_margins(margin.x, margin.y, margin.x, margin.y); + offset.x = Math::round(margin.x * viewport_size.y / screen_size.y); + offset.y = Math::round(margin.y * viewport_size.x / screen_size.x); + } else if (stretch_aspect != STRETCH_ASPECT_EXPAND && screen_size.x < video_mode.x) { margin.x = Math::round((video_mode.x - screen_size.x) / 2.0); VisualServer::get_singleton()->black_bars_set_margins(margin.x, 0, margin.x, 0); offset.x = Math::round(margin.x * viewport_size.y / screen_size.y); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 55304fb12d8a..963214e96d5d 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -89,6 +89,7 @@ class SceneTree : public MainLoop { STRETCH_ASPECT_KEEP_WIDTH, STRETCH_ASPECT_KEEP_HEIGHT, STRETCH_ASPECT_EXPAND, + STRETCH_ASPECT_PIXELPERFECT, }; private: