From 4c3065619e3374ce0141c8a9bd1af19701d0e722 Mon Sep 17 00:00:00 2001 From: Robert Jordan Date: Wed, 8 Nov 2017 11:43:50 -0500 Subject: [PATCH] Fix #996, #2254, #2589, #2875: Viewport scrolling getting stuck or shaking Shaking while at the edge of the map has been completely eliminated. In order to do this, comparison with tile height was also removed which fixed a few outlier cases. The main cause was viewport axis were only being set if it's respective isometric axis was at the boundary, instead of either isometric axis. Viewport no longer gets stuck which was related to the shaking in the end. (#2875) Refactored viewport_update_position. I moved viewport_set_underground_flag above the bounds checking function since it had no relation to it. (#996, #2589) Scrolling on the map edge with arrow keys or mouse edge will now go the same speed in both directions. (#2254) Added changelog entry. --- distribution/changelog.txt | 2 + src/openrct2-ui/input/Input.cpp | 12 +---- src/openrct2/input.c | 69 ++++++++++++++++++++---- src/openrct2/input.h | 2 + src/openrct2/interface/viewport.c | 88 +++++++++++++++++-------------- 5 files changed, 112 insertions(+), 61 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 84168baf09..81e8b15d5b 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -22,7 +22,9 @@ - Feature: Allow using object files from RCT Classic. - Feature: Title sequences now testable in-game. - Fix: [#816] In the map window, there are more peeps flickering than there are selected (original bug). +- Fix: [#996, #2589, #2875] Viewport scrolling no longer shakes or gets stuck. - Fix: [#1833, #4937, #6138] 'Too low!' warning when building rides and shops on the lowest land level (original bug). +- Fix: [#2254] Edge scrolling horizontally now has the same speed as vertical edge scrolling. - Fix: [#6199] Inverted Hairpin Coaster vehicle tab is not centred. - Fix: [#4991] Inverted helices can be built on the Lay Down RC, but are not drawn. - Fix: [#5417] Hacked Crooked House tracked rides do not dispatch vehicles. diff --git a/src/openrct2-ui/input/Input.cpp b/src/openrct2-ui/input/Input.cpp index cce25a0e1c..30f0d16345 100644 --- a/src/openrct2-ui/input/Input.cpp +++ b/src/openrct2-ui/input/Input.cpp @@ -101,17 +101,7 @@ static void game_handle_key_scroll() const uint8 * keysState = context_get_keys_state(); get_keyboard_map_scroll(keysState, &scrollX, &scrollY); - // Scroll viewport - if (scrollX != 0) - { - mainWindow->saved_view_x += scrollX * (12 << mainWindow->viewport->zoom); - input_set_flag(INPUT_FLAG_VIEWPORT_SCROLLING, true); - } - if (scrollY != 0) - { - mainWindow->saved_view_y += scrollY * (12 << mainWindow->viewport->zoom); - input_set_flag(INPUT_FLAG_VIEWPORT_SCROLLING, true); - } + input_scroll_viewport(scrollX, scrollY); } static sint32 input_scancode_to_rct_keycode(sint32 sdl_key) diff --git a/src/openrct2/input.c b/src/openrct2/input.c index 2b488cb286..0b8e472bac 100644 --- a/src/openrct2/input.c +++ b/src/openrct2/input.c @@ -1508,15 +1508,7 @@ void game_handle_edge_scroll() else if (cursorState->y >= context_get_height() - 1) scrollY = 1; - // Scroll viewport - if (scrollX != 0) { - mainWindow->saved_view_x += scrollX * (12 << mainWindow->viewport->zoom); - _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; - } - if (scrollY != 0) { - mainWindow->saved_view_y += scrollY * (12 << mainWindow->viewport->zoom); - _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; - } + input_scroll_viewport(scrollX, scrollY); } void input_set_flag(INPUT_FLAGS flag, bool on) @@ -1562,3 +1554,62 @@ bool input_test_place_object_modifier(PLACE_OBJECT_MODIFIER modifier) { return gInputPlaceObjectModifier & modifier; } + +void input_scroll_viewport(sint32 scrollX, sint32 scrollY) +{ + rct_window * mainWindow = window_get_main(); + rct_viewport * viewport = mainWindow->viewport; + + sint32 dx = scrollX * (12 << viewport->zoom); + sint32 dy = scrollY * (12 << viewport->zoom); + + if (scrollX != 0) + { + // Speed up scrolling horizontally when at the edge of the map + // so that the speed is consistent with vertical edge scrolling. + sint32 x = mainWindow->saved_view_x + viewport->view_width / 2 + dx; + sint32 y = mainWindow->saved_view_y + viewport->view_height / 2; + sint32 y_dy = mainWindow->saved_view_y + viewport->view_height / 2 + dy; + LocationXY16 mapCoord, mapCoord_dy; + + mapCoord = viewport_coord_to_map_coord(x, y, 0); + mapCoord_dy = viewport_coord_to_map_coord(x, y_dy, 0); + + // Check if we're crossing the boundary + // Clamp to the map minimum value + sint32 at_map_edge = 0; + sint32 at_map_edge_dy = 0; + if (mapCoord.x < MAP_MINIMUM_X_Y || mapCoord.y < MAP_MINIMUM_X_Y) + { + at_map_edge = 1; + } + if (mapCoord_dy.x < MAP_MINIMUM_X_Y || mapCoord_dy.y < MAP_MINIMUM_X_Y) + { + at_map_edge_dy = 1; + } + + // Clamp to the map maximum value (scenario specific) + if (mapCoord.x > gMapSizeMinus2 || mapCoord.y > gMapSizeMinus2) + { + at_map_edge = 1; + } + if (mapCoord_dy.x > gMapSizeMinus2 || mapCoord_dy.y > gMapSizeMinus2) + { + at_map_edge_dy = 1; + } + + // If we crossed the boundary, multiply the distance by 2 + if (at_map_edge && at_map_edge_dy) + { + dx *= 2; + } + + mainWindow->saved_view_x += dx; + _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; + } + if (scrollY != 0) + { + mainWindow->saved_view_y += dy; + _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; + } +} diff --git a/src/openrct2/input.h b/src/openrct2/input.h index 985979a612..e3b3c5370d 100644 --- a/src/openrct2/input.h +++ b/src/openrct2/input.h @@ -119,6 +119,8 @@ void reset_tooltip_not_shown(); void input_reset_place_obj_modifier(); +void input_scroll_viewport(sint32 scrollX, sint32 scrollY); + #ifdef __cplusplus } #endif diff --git a/src/openrct2/interface/viewport.c b/src/openrct2/interface/viewport.c index 53d61c5892..af31f381b9 100644 --- a/src/openrct2/interface/viewport.c +++ b/src/openrct2/interface/viewport.c @@ -510,73 +510,76 @@ static void viewport_set_underground_flag(sint32 underground, rct_window* window * * rct2: 0x006E7A3A */ -void viewport_update_position(rct_window *window) +void viewport_update_position(rct_window * window) { window_event_resize_call(window); - rct_viewport* viewport = window->viewport; - if (!viewport)return; + rct_viewport * viewport = window->viewport; + if (!viewport) return; - if (window->viewport_target_sprite != SPRITE_INDEX_NULL) { + if (window->viewport_target_sprite != SPRITE_INDEX_NULL) + { viewport_update_sprite_follow(window); return; } - sint16 x = viewport->view_width / 2 + window->saved_view_x; - sint16 y = viewport->view_height / 2 + window->saved_view_y; - sint16 z; - - viewport_adjust_for_map_height(&x, &y, &z); - viewport_set_underground_flag(0, window, viewport); - //Clamp to the map minimum value - sint32 at_map_edge_x = 0; - if (x < MAP_MINIMUM_X_Y){ - x = MAP_MINIMUM_X_Y; - at_map_edge_x = 1; + sint16 x = window->saved_view_x + viewport->view_width / 2; + sint16 y = window->saved_view_y + viewport->view_height / 2; + LocationXY16 mapCoord; + + mapCoord = viewport_coord_to_map_coord(x, y, 0); + + // Clamp to the map minimum value + sint32 at_map_edge = 0; + if (mapCoord.x < MAP_MINIMUM_X_Y) + { + mapCoord.x = MAP_MINIMUM_X_Y; + at_map_edge = 1; } - sint32 at_map_edge_y = 0; - if (y < MAP_MINIMUM_X_Y){ - y = MAP_MINIMUM_X_Y; - at_map_edge_y = 1; + if (mapCoord.y < MAP_MINIMUM_X_Y) + { + mapCoord.y = MAP_MINIMUM_X_Y; + at_map_edge = 1; } - //Clamp to the map maximum value (scenario specific) - if (x > gMapSizeMinus2){ - x = gMapSizeMinus2; - at_map_edge_x = 1; + // Clamp to the map maximum value (scenario specific) + if (mapCoord.x > gMapSizeMinus2) + { + mapCoord.x = gMapSizeMinus2; + at_map_edge = 1; } - if (y > gMapSizeMinus2){ - y = gMapSizeMinus2; - at_map_edge_y = 1; + if (mapCoord.y > gMapSizeMinus2) + { + mapCoord.y = gMapSizeMinus2; + at_map_edge = 1; } - if (at_map_edge_x || at_map_edge_y) { - // The &0xFFFF is to prevent the sign extension messing the - // function up. - sint32 zz = tile_element_height(x & 0xFFFF, y & 0xFFFF); + if (at_map_edge) + { sint32 _2d_x, _2d_y; - centre_2d_coordinates(x, y, zz, &_2d_x, &_2d_y, viewport); + centre_2d_coordinates(mapCoord.x, mapCoord.y, 0, &_2d_x, &_2d_y, viewport); - if (at_map_edge_x) - window->saved_view_x = _2d_x; - if (at_map_edge_y) - window->saved_view_y = _2d_y; + window->saved_view_x = _2d_x; + window->saved_view_y = _2d_y; } x = window->saved_view_x; y = window->saved_view_y; - if (window->flags & WF_SCROLLING_TO_LOCATION){ + if (window->flags & WF_SCROLLING_TO_LOCATION) + { // Moves the viewport if focusing in on an item uint8 flags = 0; x -= viewport->view_x; - if (x < 0){ + if (x < 0) + { x = -x; flags |= 1; } y -= viewport->view_y; - if (y < 0){ + if (y < 0) + { y = -y; flags |= 2; } @@ -584,13 +587,16 @@ void viewport_update_position(rct_window *window) y = (y + 7) / 8; //If we are at the final zoom position - if (!x && !y){ + if (!x && !y) + { window->flags &= ~WF_SCROLLING_TO_LOCATION; } - if (flags & 1){ + if (flags & 1) + { x = -x; } - if (flags & 2){ + if (flags & 2) + { y = -y; } x += viewport->view_x;