Viewporrt map mode: Bridge and tunnel cache optimisations
This commit is contained in:
157
src/viewport.cpp
157
src/viewport.cpp
@@ -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 (tile_is_tunnel) {
|
|
||||||
if (!_settings_client.gui.show_tunnels_on_map) return;
|
|
||||||
} else {
|
|
||||||
if (!_settings_client.gui.show_bridges_on_map) return;
|
if (!_settings_client.gui.show_bridges_on_map) return;
|
||||||
|
const Owner o = GetTileOwner(tile);
|
||||||
|
if (o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_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();
|
||||||
|
Reference in New Issue
Block a user