Improve performance of tunnel rendering in viewport map mode
This commit is contained in:
@@ -3774,6 +3774,7 @@ bool AfterLoadGame()
|
|||||||
|
|
||||||
/* This needs to be done after conversion. */
|
/* This needs to be done after conversion. */
|
||||||
RebuildViewportKdtree();
|
RebuildViewportKdtree();
|
||||||
|
ViewportMapBuildTunnelCache();
|
||||||
|
|
||||||
/* Road stops is 'only' updating some caches */
|
/* Road stops is 'only' updating some caches */
|
||||||
AfterLoadRoadStops();
|
AfterLoadRoadStops();
|
||||||
|
@@ -1244,6 +1244,13 @@ static bool CheckYapfRailSignalPenalties(int32)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ViewportMapShowTunnelModeChanged(int32 p1)
|
||||||
|
{
|
||||||
|
extern void ViewportMapBuildTunnelCache();
|
||||||
|
ViewportMapBuildTunnelCache();
|
||||||
|
return RedrawScreen(p1);
|
||||||
|
}
|
||||||
|
|
||||||
/** Checks if any settings are set to incorrect values, and sets them to correct values in that case. */
|
/** Checks if any settings are set to incorrect values, and sets them to correct values in that case. */
|
||||||
static void ValidateSettings()
|
static void ValidateSettings()
|
||||||
{
|
{
|
||||||
|
@@ -48,6 +48,7 @@ static bool DayLengthChanged(int32 p1);
|
|||||||
static bool SimulatedWormholeSignalsChanged(int32 p1);
|
static bool SimulatedWormholeSignalsChanged(int32 p1);
|
||||||
static bool EnableSingleVehSharedOrderGuiChanged(int32 p1);
|
static bool EnableSingleVehSharedOrderGuiChanged(int32 p1);
|
||||||
static bool CheckYapfRailSignalPenalties(int32 p1);
|
static bool CheckYapfRailSignalPenalties(int32 p1);
|
||||||
|
static bool ViewportMapShowTunnelModeChanged(int32 p1);
|
||||||
|
|
||||||
static bool UpdateClientName(int32 p1);
|
static bool UpdateClientName(int32 p1);
|
||||||
static bool UpdateServerPassword(int32 p1);
|
static bool UpdateServerPassword(int32 p1);
|
||||||
@@ -4065,7 +4066,7 @@ var = gui.show_tunnels_on_map
|
|||||||
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
|
flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC
|
||||||
def = true
|
def = true
|
||||||
str = STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_TUNNELS
|
str = STR_CONFIG_SETTING_VIEWPORT_MAP_SHOW_TUNNELS
|
||||||
proc = RedrawScreen
|
proc = ViewportMapShowTunnelModeChanged
|
||||||
|
|
||||||
[SDTC_VAR]
|
[SDTC_VAR]
|
||||||
var = gui.show_vehicle_route
|
var = gui.show_vehicle_route
|
||||||
|
@@ -999,7 +999,9 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
|
|||||||
if(start_tile > end_tile) Swap(tn, ts);
|
if(start_tile > end_tile) Swap(tn, ts);
|
||||||
|
|
||||||
if (!Tunnel::CanAllocateItem()) return_cmd_error(STR_ERROR_TUNNEL_TOO_MANY);
|
if (!Tunnel::CanAllocateItem()) return_cmd_error(STR_ERROR_TUNNEL_TOO_MANY);
|
||||||
const Tunnel *t = new Tunnel(tn, ts, TileHeight(tn), is_chunnel);
|
const int height = TileHeight(tn);
|
||||||
|
const Tunnel *t = new Tunnel(tn, ts, height, is_chunnel);
|
||||||
|
ViewportMapStoreTunnel(tn, ts, height, true);
|
||||||
|
|
||||||
if (transport_type == TRANSPORT_RAIL) {
|
if (transport_type == TRANSPORT_RAIL) {
|
||||||
if (!IsTunnelTile(start_tile) && c != nullptr) c->infrastructure.rail[railtype] += num_pieces;
|
if (!IsTunnelTile(start_tile) && c != nullptr) c->infrastructure.rail[railtype] += num_pieces;
|
||||||
@@ -1080,6 +1082,7 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
|
|||||||
CommandCost ret = CheckAllowRemoveTunnelBridge(tile);
|
CommandCost ret = CheckAllowRemoveTunnelBridge(tile);
|
||||||
if (ret.Failed()) return ret;
|
if (ret.Failed()) return ret;
|
||||||
|
|
||||||
|
const Axis axis = DiagDirToAxis(GetTunnelBridgeDirection(tile));
|
||||||
TileIndex endtile = GetOtherTunnelEnd(tile);
|
TileIndex endtile = GetOtherTunnelEnd(tile);
|
||||||
|
|
||||||
ret = TunnelBridgeIsFree(tile, endtile);
|
ret = TunnelBridgeIsFree(tile, endtile);
|
||||||
@@ -1153,8 +1156,7 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
|
|||||||
DoClearSquare(tile);
|
DoClearSquare(tile);
|
||||||
DoClearSquare(endtile);
|
DoClearSquare(endtile);
|
||||||
}
|
}
|
||||||
ViewportMapInvalidateTunnelCacheByTile(tile);
|
ViewportMapInvalidateTunnelCacheByTile(tile < endtile ? tile : endtile, axis);
|
||||||
ViewportMapInvalidateTunnelCacheByTile(endtile);
|
|
||||||
}
|
}
|
||||||
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_TUNNEL] * len * (is_chunnel ? 2 : 1));
|
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_TUNNEL] * len * (is_chunnel ? 2 : 1));
|
||||||
}
|
}
|
||||||
|
125
src/viewport.cpp
125
src/viewport.cpp
@@ -206,6 +206,15 @@ 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 TunnelToMap {
|
||||||
|
TunnelBridgeToMap tb;
|
||||||
|
int y_intercept;
|
||||||
|
uint8 tunnel_z;
|
||||||
|
};
|
||||||
|
struct TunnelToMapStorage {
|
||||||
|
std::vector<TunnelToMap> tunnels;
|
||||||
|
};
|
||||||
|
|
||||||
struct BridgeSetXComparator {
|
struct BridgeSetXComparator {
|
||||||
bool operator() (const TileIndex a, const TileIndex b) const
|
bool operator() (const TileIndex a, const TileIndex b) const
|
||||||
{
|
{
|
||||||
@@ -229,8 +238,8 @@ struct ViewportDrawer {
|
|||||||
ParentSpriteToDrawVector parent_sprites_to_draw;
|
ParentSpriteToDrawVector parent_sprites_to_draw;
|
||||||
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;
|
TunnelToMapStorage tunnel_to_map_x;
|
||||||
btree::btree_set<TileIndex> tunnel_tiles;
|
TunnelToMapStorage tunnel_to_map_y;
|
||||||
btree::btree_map<TileIndex, TileIndex, BridgeSetXComparator> bridge_to_map_x;
|
btree::btree_map<TileIndex, TileIndex, BridgeSetXComparator> bridge_to_map_x;
|
||||||
btree::btree_map<TileIndex, TileIndex, BridgeSetYComparator> bridge_to_map_y;
|
btree::btree_map<TileIndex, TileIndex, BridgeSetYComparator> bridge_to_map_y;
|
||||||
|
|
||||||
@@ -1941,7 +1950,7 @@ static void ViewportMapStoreBridge(const ViewPort * const vp, const TileIndex ti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ViewportMapStoreTunnel(const ViewPort * const vp, const TileIndex tile)
|
void ViewportMapStoreTunnel(const TileIndex tile, const TileIndex tile_south, const int tunnel_z, const bool insert_sorted)
|
||||||
{
|
{
|
||||||
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];
|
||||||
@@ -1951,45 +1960,68 @@ static void ViewportMapStoreTunnel(const ViewPort * const vp, const TileIndex ti
|
|||||||
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 */
|
const Axis axis = (TileX(tile) == TileX(tile_south)) ? AXIS_Y : AXIS_X;
|
||||||
if (_vd.tunnel_tiles.count(tile)) return;
|
const Point viewport_pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, tunnel_z);
|
||||||
|
int y_intercept;
|
||||||
/* It's a new one, add it to the list */
|
if (axis == AXIS_X) {
|
||||||
_vd.tunnel_to_map.emplace_back();
|
/* NE to SW */
|
||||||
TunnelBridgeToMap &tbtm = _vd.tunnel_to_map.back();
|
y_intercept = viewport_pt.y + (viewport_pt.x / 2);
|
||||||
TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
} else {
|
||||||
_vd.tunnel_tiles.insert(tile);
|
/* NW to SE */
|
||||||
_vd.tunnel_tiles.insert(other_end);
|
y_intercept = viewport_pt.y - (viewport_pt.x / 2);
|
||||||
|
}
|
||||||
|
TunnelToMapStorage &storage = (axis == AXIS_X) ? _vd.tunnel_to_map_x : _vd.tunnel_to_map_y;
|
||||||
|
TunnelToMap *tbtm;
|
||||||
|
if (insert_sorted) {
|
||||||
|
auto iter = std::upper_bound(storage.tunnels.begin(), storage.tunnels.end(), y_intercept, [](int a, const TunnelToMap &b) -> bool {
|
||||||
|
return a < b.y_intercept;
|
||||||
|
});
|
||||||
|
tbtm = &(*(storage.tunnels.emplace(iter)));
|
||||||
|
} else {
|
||||||
|
storage.tunnels.emplace_back();
|
||||||
|
tbtm = &(storage.tunnels.back());
|
||||||
|
}
|
||||||
|
|
||||||
/* ensure deterministic ordering, to avoid render flicker */
|
/* ensure deterministic ordering, to avoid render flicker */
|
||||||
if (other_end > tile) {
|
tbtm->tb.from_tile = tile;
|
||||||
tbtm.from_tile = other_end;
|
tbtm->tb.to_tile = tile_south;
|
||||||
tbtm.to_tile = tile;
|
tbtm->y_intercept = y_intercept;
|
||||||
} else {
|
tbtm->tunnel_z = tunnel_z;
|
||||||
tbtm.from_tile = tile;
|
|
||||||
tbtm.to_tile = other_end;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewportMapClearTunnelCache()
|
void ViewportMapClearTunnelCache()
|
||||||
{
|
{
|
||||||
_vd.tunnel_to_map.clear();
|
_vd.tunnel_to_map_x.tunnels.clear();
|
||||||
_vd.tunnel_tiles.clear();
|
_vd.tunnel_to_map_y.tunnels.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewportMapInvalidateTunnelCacheByTile(const TileIndex tile)
|
void ViewportMapInvalidateTunnelCacheByTile(const TileIndex tile, const Axis axis)
|
||||||
{
|
{
|
||||||
if (!_vd.tunnel_tiles.count(tile)) return;
|
if (!_settings_client.gui.show_tunnels_on_map) return;
|
||||||
TunnelBridgeToMapVector * const tbtmv = &_vd.tunnel_to_map;
|
std::vector<TunnelToMap> &tbtmv = (axis == AXIS_X) ? _vd.tunnel_to_map_x.tunnels : _vd.tunnel_to_map_y.tunnels;
|
||||||
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->tb.from_tile == tile) {
|
||||||
*tbtm = tbtmv->back();
|
tbtmv.erase(tbtm);
|
||||||
tbtmv->pop_back();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViewportMapBuildTunnelCache()
|
||||||
|
{
|
||||||
|
ViewportMapClearTunnelCache();
|
||||||
|
if (_settings_client.gui.show_tunnels_on_map) {
|
||||||
|
for (Tunnel *tunnel : Tunnel::Iterate()) {
|
||||||
|
ViewportMapStoreTunnel(tunnel->tile_n, tunnel->tile_s, tunnel->height, false);
|
||||||
|
}
|
||||||
|
auto sorter = [](const TunnelToMap &a, const TunnelToMap &b) -> bool {
|
||||||
|
return a.y_intercept < b.y_intercept;
|
||||||
|
};
|
||||||
|
std::sort(_vd.tunnel_to_map_x.tunnels.begin(), _vd.tunnel_to_map_x.tunnels.end(), sorter);
|
||||||
|
std::sort(_vd.tunnel_to_map_y.tunnels.begin(), _vd.tunnel_to_map_y.tunnels.end(), sorter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw/colour the blocks that have been redrawn.
|
* Draw/colour the blocks that have been redrawn.
|
||||||
*/
|
*/
|
||||||
@@ -2592,9 +2624,7 @@ 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 {
|
||||||
if (IsTunnel(from_tile)) {
|
if (IsBridge(from_tile)) {
|
||||||
ViewportMapStoreTunnel(vp, from_tile);
|
|
||||||
} else {
|
|
||||||
ViewportMapStoreBridge(vp, from_tile);
|
ViewportMapStoreBridge(vp, from_tile);
|
||||||
}
|
}
|
||||||
switch (GetTunnelBridgeTransportType(from_tile)) {
|
switch (GetTunnelBridgeTransportType(from_tile)) {
|
||||||
@@ -2629,9 +2659,7 @@ 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) {
|
||||||
if (IsTunnel(result)) {
|
if (IsBridge(result)) {
|
||||||
ViewportMapStoreTunnel(vp, result);
|
|
||||||
} else {
|
|
||||||
ViewportMapStoreBridge(vp, result);
|
ViewportMapStoreBridge(vp, result);
|
||||||
}
|
}
|
||||||
switch (GetTunnelBridgeTransportType(result)) {
|
switch (GetTunnelBridgeTransportType(result)) {
|
||||||
@@ -2838,12 +2866,15 @@ void ViewportMapDraw(const ViewPort * const vp)
|
|||||||
b += incr_b;
|
b += incr_b;
|
||||||
} while (++j < h);
|
} while (++j < h);
|
||||||
|
|
||||||
/* Render tunnels */
|
auto draw_tunnels = [&](const int y_intercept_min, const int y_intercept_max, const TunnelToMapStorage &storage) {
|
||||||
if (_settings_client.gui.show_tunnels_on_map && _vd.tunnel_to_map.size() != 0) {
|
auto iter = std::lower_bound(storage.tunnels.begin(), storage.tunnels.end(), y_intercept_min, [](const TunnelToMap &a, int b) -> bool {
|
||||||
for (const TunnelBridgeToMap &tbtm : _vd.tunnel_to_map) { // For each tunnel
|
return a.y_intercept < b;
|
||||||
const int tunnel_z = GetTileZ(tbtm.from_tile) * TILE_HEIGHT;
|
});
|
||||||
const Point pt_from = RemapCoords(TileX(tbtm.from_tile) * TILE_SIZE, TileY(tbtm.from_tile) * TILE_SIZE, tunnel_z);
|
for (; iter != storage.tunnels.end() && iter->y_intercept <= y_intercept_max; ++iter) {
|
||||||
const Point pt_to = RemapCoords(TileX(tbtm.to_tile) * TILE_SIZE, TileY(tbtm.to_tile) * TILE_SIZE, tunnel_z);
|
const TunnelToMap &ttm = *iter;
|
||||||
|
const int tunnel_z = ttm.tunnel_z * TILE_HEIGHT;
|
||||||
|
const Point pt_from = RemapCoords(TileX(ttm.tb.from_tile) * TILE_SIZE, TileY(ttm.tb.from_tile) * TILE_SIZE, tunnel_z);
|
||||||
|
const Point pt_to = RemapCoords(TileX(ttm.tb.to_tile) * TILE_SIZE, TileY(ttm.tb.to_tile) * TILE_SIZE, tunnel_z);
|
||||||
|
|
||||||
/* check if tunnel is wholly outside redrawing area */
|
/* check if tunnel is wholly outside redrawing area */
|
||||||
const int x_from = UnScaleByZoomLower(pt_from.x - _vd.dpi.left, _vd.dpi.zoom);
|
const int x_from = UnScaleByZoomLower(pt_from.x - _vd.dpi.left, _vd.dpi.zoom);
|
||||||
@@ -2853,8 +2884,20 @@ void ViewportMapDraw(const ViewPort * const vp)
|
|||||||
const int y_to = UnScaleByZoomLower(pt_to.y - _vd.dpi.top, _vd.dpi.zoom);
|
const int y_to = UnScaleByZoomLower(pt_to.y - _vd.dpi.top, _vd.dpi.zoom);
|
||||||
if ((y_from < 0 && y_to < 0) || (y_from > h && y_to > h)) continue;
|
if ((y_from < 0 && y_to < 0) || (y_from > h && y_to > h)) continue;
|
||||||
|
|
||||||
ViewportMapDrawBridgeTunnel(vp, &tbtm, tunnel_z, true, w, h, blitter);
|
ViewportMapDrawBridgeTunnel(vp, &ttm.tb, tunnel_z, true, w, h, blitter);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Render tunnels */
|
||||||
|
if (_settings_client.gui.show_tunnels_on_map && _vd.tunnel_to_map_x.tunnels.size() != 0) {
|
||||||
|
const int y_intercept_min = _vd.dpi.top + (_vd.dpi.left / 2);
|
||||||
|
const int y_intercept_max = _vd.dpi.top + _vd.dpi.height + ((_vd.dpi.left + _vd.dpi.width) / 2);
|
||||||
|
draw_tunnels(y_intercept_min, y_intercept_max, _vd.tunnel_to_map_x);
|
||||||
|
}
|
||||||
|
if (_settings_client.gui.show_tunnels_on_map && _vd.tunnel_to_map_y.tunnels.size() != 0) {
|
||||||
|
const int y_intercept_min = _vd.dpi.top - ((_vd.dpi.left + _vd.dpi.width) / 2);
|
||||||
|
const int y_intercept_max = _vd.dpi.top + _vd.dpi.height - (_vd.dpi.left / 2);
|
||||||
|
draw_tunnels(y_intercept_min, y_intercept_max, _vd.tunnel_to_map_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Render bridges */
|
/* Render bridges */
|
||||||
|
@@ -112,8 +112,10 @@ Point GetViewportStationMiddle(const ViewPort *vp, const Station *st);
|
|||||||
|
|
||||||
void ShowTooltipForTile(Window *w, const TileIndex tile);
|
void ShowTooltipForTile(Window *w, const TileIndex tile);
|
||||||
|
|
||||||
|
void ViewportMapStoreTunnel(const TileIndex tile, const TileIndex tile_south, const int tunnel_z, const bool insert_sorted);
|
||||||
void ViewportMapClearTunnelCache();
|
void ViewportMapClearTunnelCache();
|
||||||
void ViewportMapInvalidateTunnelCacheByTile(const TileIndex tile);
|
void ViewportMapInvalidateTunnelCacheByTile(const TileIndex tile, const Axis axis);
|
||||||
|
void ViewportMapBuildTunnelCache();
|
||||||
|
|
||||||
void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal);
|
void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal);
|
||||||
void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part, const SubSprite *sub = nullptr);
|
void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part, const SubSprite *sub = nullptr);
|
||||||
|
Reference in New Issue
Block a user