1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 11:03:00 +01:00

Optimise the algorithm for virtual floor invalidation.

This commit is contained in:
ZehMatt
2018-03-04 19:02:07 +01:00
committed by Aaron van Geffen
parent ba1d269227
commit c8328610ee
4 changed files with 119 additions and 60 deletions

View File

@@ -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<sint16>::max();
_virtualFloorLastMinPos.y = std::numeric_limits<sint16>::max();
_virtualFloorLastMaxPos.x = std::numeric_limits<sint16>::lowest();
_virtualFloorLastMaxPos.y = std::numeric_limits<sint16>::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<sint16>::max();
_virtualFloorLastMaxPos.z = std::numeric_limits<sint16>::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<sint16>::max();
_virtualFloorLastMaxPos.z = std::numeric_limits<sint16>::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<sint16>::max(), std::numeric_limits<sint16>::max() };
LocationXY16 min_position = { std::numeric_limits<sint16>::max(), std::numeric_limits<sint16>::max() };
LocationXY16 max_position = { std::numeric_limits<sint16>::lowest(), std::numeric_limits<sint16>::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<sint16>::max() &&
_virtualFloorLastMinPos.y != std::numeric_limits<sint16>::max() &&
_virtualFloorLastMaxPos.x != std::numeric_limits<sint16>::lowest() &&
_virtualFloorLastMaxPos.y != std::numeric_limits<sint16>::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<sint16>::max() &&
_virtualFloorLastMaxPos.z != std::numeric_limits<sint16>::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<sint16>::max() &&
min_position.y != std::numeric_limits<sint16>::max() &&
max_position.x != std::numeric_limits<sint16>::lowest() &&
max_position.y != std::numeric_limits<sint16>::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;
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);