summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlvin Wong <alvinhochun@gmail.com>2024-06-30 23:51:13 +0800
committerAlvin Wong <alvinhochun@gmail.com>2024-09-23 20:34:11 +0800
commit1bd66af54ce86d5882830ce5170cdfeb914bb873 (patch)
tree94db18d8268203ba7a6e3a17551a8a3278c8e877
parentd5aadc38b459762fa74850777edb2ec8f6a02c16 (diff)
downloadredot-engine-1bd66af54ce86d5882830ce5170cdfeb914bb873.tar.gz
Apply snap 2D transforms to pixel to viewport
We shall not leave the viewport transform to be rounded by the code for rounding canvas items. Since the viewport transform is inverse to the camera transform, we get incorrect rounding at the halfway point that misaligns the viewport and the canvas item which the camera is following. Instead, reintroduce viewport rounding, but do it in a way that matches the rounding of canvas items. Also take into account the half-pixel offset of the centre point when viewport dimension is not divisible by two. For `CanvasLayer`s that follows viewport, take into account the scale when rounding. Overall this should work better compared to the rounding in Godot 4.2 (and earlier).
-rw-r--r--servers/rendering/renderer_viewport.cpp17
1 files changed, 17 insertions, 0 deletions
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 781d29ffaa..4d6435f48a 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -41,14 +41,31 @@
static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport, RendererCanvasCull::Canvas *p_canvas, RendererViewport::Viewport::CanvasData *p_canvas_data, const Vector2 &p_vp_size) {
Transform2D xf = p_viewport->global_transform;
+ Vector2 pixel_snap_offset;
+ if (p_viewport->snap_2d_transforms_to_pixel) {
+ // We use `floor(p + 0.5)` to snap canvas items, but `ceil(p - 0.5)`
+ // to snap viewport transform because the viewport transform is inverse
+ // to the camera transform. Also, if the viewport size is not divisible
+ // by 2, the center point is offset by 0.5 px and we need to add 0.5
+ // before rounding to cancel it out.
+ pixel_snap_offset.x = (p_viewport->size.width % 2) ? 0.0 : -0.5;
+ pixel_snap_offset.y = (p_viewport->size.height % 2) ? 0.0 : -0.5;
+ }
+
float scale = 1.0;
if (p_viewport->canvas_map.has(p_canvas->parent)) {
Transform2D c_xform = p_viewport->canvas_map[p_canvas->parent].transform;
+ if (p_viewport->snap_2d_transforms_to_pixel) {
+ c_xform.columns[2] = (c_xform.columns[2] * p_canvas->parent_scale + pixel_snap_offset).ceil() / p_canvas->parent_scale;
+ }
xf = xf * c_xform;
scale = p_canvas->parent_scale;
}
Transform2D c_xform = p_canvas_data->transform;
+ if (p_viewport->snap_2d_transforms_to_pixel) {
+ c_xform.columns[2] = (c_xform.columns[2] + pixel_snap_offset).ceil();
+ }
xf = xf * c_xform;
if (scale != 1.0 && !RSG::canvas->disable_scale) {