diff --git a/src/openrct2/paint/VirtualFloor.cpp b/src/openrct2/paint/VirtualFloor.cpp index 0d6d6dfdc1..698f8125e0 100644 --- a/src/openrct2/paint/VirtualFloor.cpp +++ b/src/openrct2/paint/VirtualFloor.cpp @@ -28,7 +28,14 @@ static uint16 _virtualFloorBaseSize = 5 * 32; static uint16 _virtualFloorHeight = 0; static LocationXYZ16 _virtualFloorLastMinPos; static LocationXYZ16 _virtualFloorLastMaxPos; -static bool _virtualFloorVisible = false; +static uint32 _virtualFloorFlags = 0; + +enum VirtualFloorFlags +{ + VIRTUAL_FLOOR_FLAG_NONE = 0, + VIRTUAL_FLOOR_FLAG_ENABLED = (1 << 1), + VIRTUAL_FLOOR_FORCE_INVALIDATION = (1 << 2), +}; static constexpr const CoordsXY offsets[4] = { @@ -38,11 +45,15 @@ static constexpr const CoordsXY offsets[4] = { 0, -32 } }; +bool virtual_floor_is_enabled() +{ + return (_virtualFloorFlags & VIRTUAL_FLOOR_FLAG_ENABLED) != 0; +} + void virtual_floor_set_height(sint16 height) { - if (!_virtualFloorVisible) + if (virtual_floor_is_enabled()) { - // If the modifiers are not set we do not actually care as the floor is invisible. return; } @@ -53,51 +64,55 @@ void virtual_floor_set_height(sint16 height) } } +static void virtual_floor_reset() +{ + _virtualFloorLastMinPos.x = std::numeric_limits::max(); + _virtualFloorLastMinPos.y = std::numeric_limits::max(); + _virtualFloorLastMaxPos.x = std::numeric_limits::lowest(); + _virtualFloorLastMaxPos.y = std::numeric_limits::lowest(); + _virtualFloorHeight = 0; +} + void virtual_floor_enable() { - if (_virtualFloorVisible) + if (virtual_floor_is_enabled()) { return; } - // Force invalidation on the next draw. - _virtualFloorLastMinPos.z = std::numeric_limits::max(); - _virtualFloorLastMaxPos.z = std::numeric_limits::lowest(); - _virtualFloorVisible = true; + virtual_floor_reset(); + _virtualFloorFlags |= VIRTUAL_FLOOR_FLAG_ENABLED; } void virtual_floor_disable() { - if (!_virtualFloorVisible) + if (!virtual_floor_is_enabled()) { return; } - // Force invalidation, even if the position hasn't changed. - _virtualFloorLastMinPos.z = std::numeric_limits::max(); - _virtualFloorLastMaxPos.z = std::numeric_limits::lowest(); - virtual_floor_invalidate(); + _virtualFloorFlags &= ~VIRTUAL_FLOOR_FLAG_ENABLED; - _virtualFloorHeight = 0; - _virtualFloorVisible = false; + // Force invalidation, even if the position hasn't changed. + _virtualFloorFlags |= VIRTUAL_FLOOR_FORCE_INVALIDATION; + virtual_floor_invalidate(); + _virtualFloorFlags &= ~VIRTUAL_FLOOR_FORCE_INVALIDATION; + + virtual_floor_reset(); } void virtual_floor_invalidate() { - if (!_virtualFloorVisible) - { - return; - } - // First, let's figure out how big our selection is. - LocationXY16 min_position = { std::numeric_limits::max(), std::numeric_limits::max() }; + LocationXY16 min_position = { std::numeric_limits::max(), std::numeric_limits::max() }; LocationXY16 max_position = { std::numeric_limits::lowest(), std::numeric_limits::lowest() }; - if ((gMapSelectFlags & MAP_SELECT_FLAG_ENABLE)) + if (gMapSelectFlags & MAP_SELECT_FLAG_ENABLE) { - min_position = gMapSelectPositionA; - max_position = gMapSelectPositionB; + min_position = gMapSelectPositionA; + max_position = gMapSelectPositionB; } + if (gMapSelectFlags & MAP_SELECT_FLAG_ENABLE_CONSTRUCT) { for (LocationXY16 * tile = gMapSelectionTiles; tile->x != -1; tile++) @@ -110,12 +125,33 @@ void virtual_floor_invalidate() } // Apply the virtual floor size to the computed invalidation area. - min_position.x -= _virtualFloorBaseSize + 1; - min_position.y -= _virtualFloorBaseSize + 1; - max_position.x += _virtualFloorBaseSize + 1; - max_position.y += _virtualFloorBaseSize + 1; + min_position.x -= _virtualFloorBaseSize + 16; + min_position.y -= _virtualFloorBaseSize + 16; + max_position.x += _virtualFloorBaseSize + 16; + max_position.y += _virtualFloorBaseSize + 16; - // Do not invalidate if floor hasn't moved. + // Invalidate previous region if appropriate. + if (_virtualFloorLastMinPos.x != std::numeric_limits::max() && + _virtualFloorLastMinPos.y != std::numeric_limits::max() && + _virtualFloorLastMaxPos.x != std::numeric_limits::lowest() && + _virtualFloorLastMaxPos.y != std::numeric_limits::lowest()) + { + LocationXY16 prevMins = { _virtualFloorLastMinPos.x, _virtualFloorLastMinPos.y }; + LocationXY16 prevMaxs = { _virtualFloorLastMaxPos.x, _virtualFloorLastMaxPos.y }; + + if (prevMins.x != min_position.x || + prevMins.y != min_position.y || + prevMaxs.x != max_position.x || + prevMaxs.y != max_position.y || + (_virtualFloorFlags & VIRTUAL_FLOOR_FORCE_INVALIDATION) != 0) + { + log_verbose("Invalidating previous region, Min: %d %d, Max: %d %d", + prevMins.x, prevMins.y, prevMaxs.x, prevMaxs.y); + map_invalidate_region(prevMins, prevMaxs); + } + } + + // Do not invalidate new region if floor hasn't moved. if (_virtualFloorLastMinPos.x == min_position.x && _virtualFloorLastMinPos.y == min_position.y && _virtualFloorLastMinPos.z == _virtualFloorHeight) @@ -123,40 +159,35 @@ void virtual_floor_invalidate() return; } - LocationXY16 corr_min_position = min_position; - LocationXY16 corr_max_position = max_position; - - // Invalidate previous locations, too, if appropriate. - if (_virtualFloorLastMinPos.z != std::numeric_limits::max() && - _virtualFloorLastMaxPos.z != std::numeric_limits::lowest()) + if (!(_virtualFloorFlags & VIRTUAL_FLOOR_FLAG_ENABLED)) { - corr_min_position.x = std::min(min_position.x, _virtualFloorLastMinPos.x); - corr_min_position.y = std::min(min_position.y, _virtualFloorLastMinPos.y); - corr_max_position.x = std::max(max_position.x, _virtualFloorLastMaxPos.x); - corr_max_position.y = std::max(max_position.y, _virtualFloorLastMaxPos.y); + return; } - for (sint16 x = corr_min_position.x; x < corr_max_position.x; x++) + log_verbose("Min: %d %d, Max: %d %d\n", min_position.x, min_position.y, max_position.x, max_position.y); + + // Invalidate new region if coordinates are set. + if (min_position.x != std::numeric_limits::max() && + min_position.y != std::numeric_limits::max() && + max_position.x != std::numeric_limits::lowest() && + max_position.y != std::numeric_limits::lowest()) { - for (sint16 y = corr_min_position.y; y < corr_max_position.y; y++) - { - map_invalidate_tile_full(x, y); - } + map_invalidate_region(min_position, max_position); + + // Save minimal and maximal positions. + _virtualFloorLastMinPos.x = min_position.x; + _virtualFloorLastMinPos.y = min_position.y; + _virtualFloorLastMinPos.z = _virtualFloorHeight; + + _virtualFloorLastMaxPos.x = max_position.x; + _virtualFloorLastMaxPos.y = max_position.y; + _virtualFloorLastMaxPos.z = _virtualFloorHeight; } - - // Save minimal and maximal positions. Note: not their corrected positions! - _virtualFloorLastMinPos.x = min_position.x; - _virtualFloorLastMinPos.y = min_position.y; - _virtualFloorLastMinPos.z = _virtualFloorHeight; - - _virtualFloorLastMaxPos.x = max_position.x; - _virtualFloorLastMaxPos.y = max_position.y; - _virtualFloorLastMaxPos.z = _virtualFloorHeight; } bool virtual_floor_tile_is_floor(sint16 x, sint16 y) { - if (!_virtualFloorVisible) + if (!virtual_floor_is_enabled()) { return false; } diff --git a/src/openrct2/windows/_legacy.cpp b/src/openrct2/windows/_legacy.cpp index dafb47a44e..dc7ed12f5a 100644 --- a/src/openrct2/windows/_legacy.cpp +++ b/src/openrct2/windows/_legacy.cpp @@ -150,11 +150,11 @@ money32 place_provisional_track_piece(sint32 rideIndex, sint32 trackType, sint32 if (_currentTrackSlopeEnd != 0) viewport_set_visibility(2); + // Invalidate previous track piece (we may not be changing height!) + virtual_floor_invalidate(); + if (!scenery_tool_is_active()) { - // Invalidate previous track piece (we may not be changing height!) - virtual_floor_invalidate(); - // Set new virtual floor height. virtual_floor_set_height(z); } @@ -188,11 +188,11 @@ money32 place_provisional_track_piece(sint32 rideIndex, sint32 trackType, sint32 if (_currentTrackSlopeEnd != 0) viewport_set_visibility(2); + // Invalidate previous track piece (we may not be changing height!) + virtual_floor_invalidate(); + if (!scenery_tool_is_active()) { - // Invalidate previous track piece (we may not be changing height!) - virtual_floor_invalidate(); - // Set height to where the next track piece would begin virtual_floor_set_height(z - z_begin + z_end); } diff --git a/src/openrct2/world/Map.cpp b/src/openrct2/world/Map.cpp index c6e960a404..c43e33373b 100644 --- a/src/openrct2/world/Map.cpp +++ b/src/openrct2/world/Map.cpp @@ -4130,6 +4130,33 @@ void map_invalidate_element(sint32 x, sint32 y, rct_tile_element *tileElement) map_invalidate_tile(x, y, tileElement->base_height * 8, tileElement->clearance_height * 8); } +void map_invalidate_region(const LocationXY16& mins, const LocationXY16& maxs) +{ + sint32 x0, y0, x1, y1, left, right, top, bottom; + + x0 = mins.x + 16; + y0 = mins.y + 16; + + x1 = maxs.x + 16; + y1 = maxs.y + 16; + + map_get_bounding_box(x0, y0, x1, y1, &left, &top, &right, &bottom); + + left -= 32; + right += 32; + bottom += 32; + top -= 32 + 2080; + + for (sint32 i = 0; i < MAX_VIEWPORT_COUNT; i++) + { + rct_viewport *viewport = &g_viewport_list[i]; + if (viewport->width != 0) + { + viewport_invalidate(viewport, left, top, right, bottom); + } + } +} + sint32 map_get_tile_side(sint32 mapX, sint32 mapY) { sint32 subMapX = mapX & (32 - 1); diff --git a/src/openrct2/world/Map.h b/src/openrct2/world/Map.h index 2ea29bb68b..7c605a67d5 100644 --- a/src/openrct2/world/Map.h +++ b/src/openrct2/world/Map.h @@ -538,6 +538,7 @@ void map_invalidate_tile_zoom1(sint32 x, sint32 y, sint32 z0, sint32 z1); void map_invalidate_tile_zoom0(sint32 x, sint32 y, sint32 z0, sint32 z1); void map_invalidate_tile_full(sint32 x, sint32 y); void map_invalidate_element(sint32 x, sint32 y, rct_tile_element *tileElement); +void map_invalidate_region(const LocationXY16& mins, const LocationXY16& maxs); sint32 map_get_tile_side(sint32 mapX, sint32 mapY); sint32 map_get_tile_quadrant(sint32 mapX, sint32 mapY);