Viewporrt map mode: Bridge and tunnel cache optimisations

This commit is contained in:
Jonathan G Rennison
2020-02-04 00:43:02 +00:00
parent 76f68c48f5
commit a561f29dc3

View File

@@ -204,6 +204,20 @@ struct PolylineInfo {
uint second_len; ///< size of the second segment - number of track pieces. uint second_len; ///< size of the second segment - number of track pieces.
}; };
struct BridgeSetXComparator {
bool operator() (const TileIndex a, const TileIndex b) const
{
return std::make_tuple(TileX(a), TileY(a)) < std::make_tuple(TileX(b), TileY(b));
}
};
struct BridgeSetYComparator {
bool operator() (const TileIndex a, const TileIndex b) const
{
return a < b;
}
};
/** Data structure storing rendering information */ /** Data structure storing rendering information */
struct ViewportDrawer { struct ViewportDrawer {
DrawPixelInfo dpi; DrawPixelInfo dpi;
@@ -214,7 +228,9 @@ struct ViewportDrawer {
ParentSpriteToSortVector parent_sprites_to_sort; ///< Parent sprite pointer array used for sorting ParentSpriteToSortVector parent_sprites_to_sort; ///< Parent sprite pointer array used for sorting
ChildScreenSpriteToDrawVector child_screen_sprites_to_draw; ChildScreenSpriteToDrawVector child_screen_sprites_to_draw;
TunnelBridgeToMapVector tunnel_to_map; TunnelBridgeToMapVector tunnel_to_map;
TunnelBridgeToMapVector bridge_to_map; btree::btree_set<TileIndex> tunnel_tiles;
btree::btree_map<TileIndex, TileIndex, BridgeSetXComparator> bridge_to_map_x;
btree::btree_map<TileIndex, TileIndex, BridgeSetYComparator> bridge_to_map_y;
int *last_child; int *last_child;
@@ -1715,57 +1731,107 @@ static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd)
} }
} }
static void ViewportMapStoreBridgeTunnel(const ViewPort * const vp, const TileIndex tile) static void ViewportMapStoreBridge(const ViewPort * const vp, const TileIndex tile)
{ {
extern LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1]; extern LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1];
extern uint _company_to_list_pos[MAX_COMPANIES]; extern uint _company_to_list_pos[MAX_COMPANIES];
/* No need to bother for hidden things */ /* No need to bother for hidden things */
const bool tile_is_tunnel = IsTunnel(tile); if (!_settings_client.gui.show_bridges_on_map) return;
if (tile_is_tunnel) { const Owner o = GetTileOwner(tile);
if (!_settings_client.gui.show_tunnels_on_map) return; if (o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_on_map) return;
} else {
if (!_settings_client.gui.show_bridges_on_map) return; switch (GetTunnelBridgeDirection(tile)) {
case DIAGDIR_NE: {
/* X axis: tile at higher coordinate, facing towards lower coordinate */
auto iter = _vd.bridge_to_map_x.lower_bound(tile);
if (iter != _vd.bridge_to_map_x.begin()) {
auto prev = iter;
--prev;
if (prev->second == tile) return;
}
_vd.bridge_to_map_x.insert(iter, std::make_pair(GetOtherTunnelBridgeEnd(tile), tile));
break;
}
case DIAGDIR_NW: {
/* Y axis: tile at higher coordinate, facing towards lower coordinate */
auto iter = _vd.bridge_to_map_y.lower_bound(tile);
if (iter != _vd.bridge_to_map_y.begin()) {
auto prev = iter;
--prev;
if (prev->second == tile) return;
}
_vd.bridge_to_map_y.insert(iter, std::make_pair(GetOtherTunnelBridgeEnd(tile), tile));
break;
}
case DIAGDIR_SW: {
/* X axis: tile at lower coordinate, facing towards higher coordinate */
auto iter = _vd.bridge_to_map_x.lower_bound(tile);
if (iter != _vd.bridge_to_map_x.end() && iter->first == tile) return;
_vd.bridge_to_map_x.insert(iter, std::make_pair(tile, GetOtherTunnelBridgeEnd(tile)));
break;
}
case DIAGDIR_SE: {
/* Y axis: tile at lower coordinate, facing towards higher coordinate */
auto iter = _vd.bridge_to_map_y.lower_bound(tile);
if (iter != _vd.bridge_to_map_y.end() && iter->first == tile) return;
_vd.bridge_to_map_y.insert(iter, std::make_pair(tile, GetOtherTunnelBridgeEnd(tile)));
break;
}
default:
NOT_REACHED();
} }
}
static void ViewportMapStoreTunnel(const ViewPort * const vp, const TileIndex tile)
{
extern LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1];
extern uint _company_to_list_pos[MAX_COMPANIES];
/* No need to bother for hidden things */
if (!_settings_client.gui.show_tunnels_on_map) return;
const Owner o = GetTileOwner(tile); const Owner o = GetTileOwner(tile);
if (o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_on_map) return; if (o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_on_map) return;
/* Check if already stored */ /* Check if already stored */
TunnelBridgeToMapVector * const tbtmv = tile_is_tunnel ? &_vd.tunnel_to_map : &_vd.bridge_to_map; if (_vd.tunnel_tiles.count(tile)) return;
TunnelBridgeToMap *tbtm = tbtmv->data();
const TunnelBridgeToMap * const tbtm_end = tbtmv->data() + tbtmv->size();
while (tbtm != tbtm_end) {
if (tile == tbtm->from_tile || tile == tbtm->to_tile) return;
tbtm++;
}
/* It's a new one, add it to the list */ /* It's a new one, add it to the list */
tbtmv->emplace_back(); _vd.tunnel_to_map.emplace_back();
tbtm = &(tbtmv->back()); TunnelBridgeToMap &tbtm = _vd.tunnel_to_map.back();
TileIndex other_end = GetOtherTunnelBridgeEnd(tile); TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
_vd.tunnel_tiles.insert(tile);
_vd.tunnel_tiles.insert(other_end);
/* ensure deterministic ordering, to avoid render flicker */ /* ensure deterministic ordering, to avoid render flicker */
if (other_end > tile) { if (other_end > tile) {
tbtm->from_tile = other_end; tbtm.from_tile = other_end;
tbtm->to_tile = tile; tbtm.to_tile = tile;
} else { } else {
tbtm->from_tile = tile; tbtm.from_tile = tile;
tbtm->to_tile = other_end; tbtm.to_tile = other_end;
} }
} }
void ViewportMapClearTunnelCache() void ViewportMapClearTunnelCache()
{ {
_vd.tunnel_to_map.clear(); _vd.tunnel_to_map.clear();
_vd.tunnel_tiles.clear();
} }
void ViewportMapInvalidateTunnelCacheByTile(const TileIndex tile) void ViewportMapInvalidateTunnelCacheByTile(const TileIndex tile)
{ {
if (!_vd.tunnel_tiles.count(tile)) return;
TunnelBridgeToMapVector * const tbtmv = &_vd.tunnel_to_map; TunnelBridgeToMapVector * const tbtmv = &_vd.tunnel_to_map;
for (auto tbtm = tbtmv->begin(); tbtm != tbtmv->end(); tbtm++) { for (auto tbtm = tbtmv->begin(); tbtm != tbtmv->end(); tbtm++) {
if (tbtm->from_tile == tile || tbtm->to_tile == tile) { if (tbtm->from_tile == tile || tbtm->to_tile == tile) {
tbtmv->erase(tbtm); *tbtm = tbtmv->back();
tbtm--; tbtmv->pop_back();
return;
} }
} }
} }
@@ -2352,22 +2418,15 @@ static inline void ViewportMapStoreBridgeAboveTile(const ViewPort * const vp, co
/* No need to bother for hidden things */ /* No need to bother for hidden things */
if (!_settings_client.gui.show_bridges_on_map) return; if (!_settings_client.gui.show_bridges_on_map) return;
/* Check existing stored bridges */ if (GetBridgeAxis(tile) == AXIS_X) {
for (const TunnelBridgeToMap &tbtm : _vd.bridge_to_map) { auto iter = _vd.bridge_to_map_x.lower_bound(tile);
if (!IsBridge(tbtm.from_tile)) continue; if (iter != _vd.bridge_to_map_x.end() && iter->first < tile && iter->second > tile) return; /* already covered */
_vd.bridge_to_map_x.insert(iter, std::make_pair(GetNorthernBridgeEnd(tile), GetSouthernBridgeEnd(tile)));
TileIndex from = tbtm.from_tile; } else {
TileIndex to = tbtm.to_tile; auto iter = _vd.bridge_to_map_y.lower_bound(tile);
if (TileX(from) == TileX(to) && TileX(from) == TileX(tile)) { if (iter != _vd.bridge_to_map_y.end() && iter->first < tile && iter->second > tile) return; /* already covered */
if (TileY(from) > TileY(to)) std::swap(from, to); _vd.bridge_to_map_y.insert(iter, std::make_pair(GetNorthernBridgeEnd(tile), GetSouthernBridgeEnd(tile)));
if (TileY(from) <= TileY(tile) && TileY(tile) <= TileY(to)) return; /* already covered */
} else if (TileY(from) == TileY(to) && TileY(from) == TileY(tile)) {
if (TileX(from) > TileX(to)) std::swap(from, to);
if (TileX(from) <= TileX(tile) && TileX(tile) <= TileX(to)) return; /* already covered */
}
} }
ViewportMapStoreBridgeTunnel(vp, GetSouthernBridgeEnd(tile));
} }
static inline TileIndex ViewportMapGetMostSignificantTileType(const ViewPort * const vp, const TileIndex from_tile, TileType * const tile_type) static inline TileIndex ViewportMapGetMostSignificantTileType(const ViewPort * const vp, const TileIndex from_tile, TileType * const tile_type)
@@ -2379,7 +2438,11 @@ static inline TileIndex ViewportMapGetMostSignificantTileType(const ViewPort * c
*tile_type = ttype; *tile_type = ttype;
if (IsBridgeAbove(from_tile)) ViewportMapStoreBridgeAboveTile(vp, from_tile); if (IsBridgeAbove(from_tile)) ViewportMapStoreBridgeAboveTile(vp, from_tile);
} else { } else {
ViewportMapStoreBridgeTunnel(vp, from_tile); if (IsTunnel(from_tile)) {
ViewportMapStoreTunnel(vp, from_tile);
} else {
ViewportMapStoreBridge(vp, from_tile);
}
switch (GetTunnelBridgeTransportType(from_tile)) { switch (GetTunnelBridgeTransportType(from_tile)) {
case TRANSPORT_RAIL: *tile_type = MP_RAILWAY; break; case TRANSPORT_RAIL: *tile_type = MP_RAILWAY; break;
case TRANSPORT_ROAD: *tile_type = MP_ROAD; break; case TRANSPORT_ROAD: *tile_type = MP_ROAD; break;
@@ -2412,7 +2475,11 @@ static inline TileIndex ViewportMapGetMostSignificantTileType(const ViewPort * c
/* Store bridges and tunnels. */ /* Store bridges and tunnels. */
*tile_type = GetTileType(result); *tile_type = GetTileType(result);
if (*tile_type == MP_TUNNELBRIDGE) { if (*tile_type == MP_TUNNELBRIDGE) {
ViewportMapStoreBridgeTunnel(vp, result); if (IsTunnel(result)) {
ViewportMapStoreTunnel(vp, result);
} else {
ViewportMapStoreBridge(vp, result);
}
switch (GetTunnelBridgeTransportType(result)) { switch (GetTunnelBridgeTransportType(result)) {
case TRANSPORT_RAIL: *tile_type = MP_RAILWAY; break; case TRANSPORT_RAIL: *tile_type = MP_RAILWAY; break;
case TRANSPORT_ROAD: *tile_type = MP_ROAD; break; case TRANSPORT_ROAD: *tile_type = MP_ROAD; break;
@@ -2637,8 +2704,15 @@ void ViewportMapDraw(const ViewPort * const vp)
} }
/* Render bridges */ /* Render bridges */
if (_settings_client.gui.show_bridges_on_map && _vd.bridge_to_map.size() != 0) { if (_settings_client.gui.show_bridges_on_map && _vd.bridge_to_map_x.size() != 0) {
for (const TunnelBridgeToMap &tbtm : _vd.bridge_to_map) { // For each bridge for (const auto &it : _vd.bridge_to_map_x) { // For each bridge
TunnelBridgeToMap tbtm { it.first, it.second };
ViewportMapDrawBridgeTunnel(vp, &tbtm, (GetBridgeHeight(tbtm.from_tile) - 1) * TILE_HEIGHT, false, w, h, blitter);
}
}
if (_settings_client.gui.show_bridges_on_map && _vd.bridge_to_map_y.size() != 0) {
for (const auto &it : _vd.bridge_to_map_y) { // For each bridge
TunnelBridgeToMap tbtm { it.first, it.second };
ViewportMapDrawBridgeTunnel(vp, &tbtm, (GetBridgeHeight(tbtm.from_tile) - 1) * TILE_HEIGHT, false, w, h, blitter); ViewportMapDrawBridgeTunnel(vp, &tbtm, (GetBridgeHeight(tbtm.from_tile) - 1) * TILE_HEIGHT, false, w, h, blitter);
} }
} }
@@ -2734,7 +2808,8 @@ void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom
_cur_dpi = old_dpi; _cur_dpi = old_dpi;
_vd.bridge_to_map.clear(); _vd.bridge_to_map_x.clear();
_vd.bridge_to_map_y.clear();
_vd.string_sprites_to_draw.clear(); _vd.string_sprites_to_draw.clear();
_vd.tile_sprites_to_draw.clear(); _vd.tile_sprites_to_draw.clear();
_vd.parent_sprites_to_draw.clear(); _vd.parent_sprites_to_draw.clear();