diff --git a/src/rail.h b/src/rail.h index b3689b37ff..57b5e33d04 100644 --- a/src/rail.h +++ b/src/rail.h @@ -478,6 +478,7 @@ static inline Money SignalMaintenanceCost(uint32 num) } void MarkSingleSignalDirty(TileIndex tile, Trackdir td); +void MarkSingleSignalDirtyAtZ(TileIndex tile, Trackdir td, uint z); void DrawTrainDepotSprite(int x, int y, int image, RailType railtype); int TicksToLeaveDepot(const Train *v); diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index af1357719a..84b91ff4ae 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -2766,13 +2766,9 @@ static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track trac DrawSingleSignal(tile, rti, track, condition, image, pos, type, variant, show_restricted); } -void MarkSingleSignalDirty(TileIndex tile, Trackdir td) +template +void MarkSingleSignalDirtyIntl(TileIndex tile, Trackdir td, F get_z) { - if (_signal_sprite_oversized || td >= TRACKDIR_END) { - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); - return; - } - static const uint8 trackdir_to_pos[TRACKDIR_END] = { 8, // TRACKDIR_X_NE 10, // TRACKDIR_Y_SE @@ -2794,7 +2790,7 @@ void MarkSingleSignalDirty(TileIndex tile, Trackdir td) uint x, y; GetSignalXY(tile, trackdir_to_pos[td], x, y); - Point pt = RemapCoords(x, y, GetSaveSlopeZ(x, y, TrackdirToTrack(td))); + Point pt = RemapCoords(x, y, get_z(x, y)); MarkAllViewportsDirty( pt.x - SIGNAL_DIRTY_LEFT, pt.y - SIGNAL_DIRTY_TOP, @@ -2804,6 +2800,25 @@ void MarkSingleSignalDirty(TileIndex tile, Trackdir td) ); } +void MarkSingleSignalDirty(TileIndex tile, Trackdir td) +{ + if (_signal_sprite_oversized || td >= TRACKDIR_END) { + MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + return; + } + + MarkSingleSignalDirtyIntl(tile, td, [td](uint x, uint y) -> uint { + return GetSaveSlopeZ(x, y, TrackdirToTrack(td)); + }); +} + +void MarkSingleSignalDirtyAtZ(TileIndex tile, Trackdir td, uint z) +{ + MarkSingleSignalDirtyIntl(tile, td, [z](uint x, uint y) -> uint { + return z; + }); +} + static uint32 _drawtile_track_palette; diff --git a/src/signal.cpp b/src/signal.cpp index 42e168a2b2..1ca9e587a6 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -720,7 +720,7 @@ static void UpdateSignalsAroundSegment(SigInfo info) uint8 aspect = GetForwardAspectAndIncrement(info, tile, exit_td); if (aspect != GetTunnelBridgeExitSignalAspect(tile)) { SetTunnelBridgeExitSignalAspect(tile, aspect); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + MarkTunnelBridgeSignalDirty(tile, true); PropagateAspectChange(tile, exit_td, aspect); } } @@ -748,7 +748,7 @@ static void UpdateSignalsAroundSegment(SigInfo info) PropagateAspectChange(tile, exit_td, aspect); } } - if (refresh) MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + if (refresh) MarkTunnelBridgeSignalDirty(tile, true); continue; } @@ -857,7 +857,7 @@ static void UpdateSignalsAroundSegment(SigInfo info) uint8 old_aspect = GetTunnelBridgeExitSignalAspect(tile); if (aspect != old_aspect) { SetTunnelBridgeExitSignalAspect(tile, aspect); - if (old_aspect != 0) MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + if (old_aspect != 0) MarkTunnelBridgeSignalDirty(tile, true); PropagateAspectChange(tile, trackdir, aspect); } } else { @@ -1358,7 +1358,7 @@ void PropagateAspectChange(TileIndex tile, Trackdir trackdir, uint8 aspect) if (!IsTunnelBridgeSignalSimulationExit(tile) || GetTunnelBridgeExitSignalState(tile) != SIGNAL_STATE_GREEN) return; if (GetTunnelBridgeExitSignalAspect(tile) == aspect) return; SetTunnelBridgeExitSignalAspect(tile, aspect); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + MarkTunnelBridgeSignalDirty(tile, true); if (IsBridge(tile)) RefreshBridgeOnExitAspectChange(other, tile); aspect = std::min(GetSignalledTunnelBridgeEntranceForwardAspect(other, tile) + 1, _extra_aspects + 1); } @@ -1372,7 +1372,7 @@ void PropagateAspectChange(TileIndex tile, Trackdir trackdir, uint8 aspect) if (!IsTunnelBridgeSignalSimulationEntrance(tile) || GetTunnelBridgeEntranceSignalState(tile) != SIGNAL_STATE_GREEN) return; if (GetTunnelBridgeEntranceSignalAspect(tile) == aspect) return; SetTunnelBridgeEntranceSignalAspect(tile, aspect); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + MarkTunnelBridgeSignalDirty(tile, false); aspect = std::min(aspect + 1, _extra_aspects + 1); } } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 93b4191d44..9b41d1c216 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -3365,7 +3365,7 @@ static void UpdateTunnelBridgeEntranceSignalAspect(TileIndex tile) uint8 old_aspect = GetTunnelBridgeEntranceSignalAspect(tile); if (aspect != old_aspect) { SetTunnelBridgeEntranceSignalAspect(tile, aspect); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + MarkTunnelBridgeSignalDirty(tile, false); PropagateAspectChange(tile, trackdir, aspect); } } @@ -3374,7 +3374,7 @@ static void SetTunnelBridgeEntranceSignalGreen(TileIndex tile) { if (GetTunnelBridgeEntranceSignalState(tile) == SIGNAL_STATE_RED) { SetTunnelBridgeEntranceSignalState(tile, SIGNAL_STATE_GREEN); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + MarkTunnelBridgeSignalDirty(tile, false); if (_extra_aspects > 0) { SetTunnelBridgeEntranceSignalAspect(tile, 0); UpdateAspectDeferred(tile, GetTunnelBridgeEntranceTrackdir(tile)); diff --git a/src/tunnelbridge.h b/src/tunnelbridge.h index c2d1fc879a..fd8d8e1f3b 100644 --- a/src/tunnelbridge.h +++ b/src/tunnelbridge.h @@ -17,6 +17,8 @@ uint GetTunnelBridgeSignalSimulationSpacingTarget(Owner owner); uint GetBestTunnelBridgeSignalSimulationSpacing(Owner owner, TileIndex begin, TileIndex end); uint GetTunnelBridgeSignalSimulationSignalCount(TileIndex begin, TileIndex end); +void MarkTunnelBridgeSignalDirty(TileIndex tile, bool exit); + /** * Calculates the length of a tunnel or a bridge (without end tiles) * @param begin The begin of the tunnel or bridge. diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index 839f713082..c4dee50b26 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -1894,6 +1894,65 @@ void MarkSingleBridgeSignalDirty(TileIndex tile, TileIndex bridge_start_tile) ); } +void MarkTunnelBridgeSignalDirty(TileIndex tile, bool exit) +{ + if (_signal_sprite_oversized) { + MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + return; + } + + if (IsRailCustomBridgeHeadTile(tile)) { + Trackdir td = exit ? GetTunnelBridgeExitTrackdir(tile) : GetTunnelBridgeEntranceTrackdir(tile); + MarkSingleSignalDirtyAtZ(tile, td, GetTileMaxPixelZ(tile)); + return; + } + + bool side = (_settings_game.vehicle.road_side != 0) && _settings_game.construction.train_signal_side; + DiagDirection dir = GetTunnelBridgeDirection(tile); + + uint position; + switch (dir) { + default: NOT_REACHED(); + case DIAGDIR_NE: position = 0; break; + case DIAGDIR_SE: position = 2; break; + case DIAGDIR_SW: position = 1; break; + case DIAGDIR_NW: position = 3; break; + } + + static const Point SignalPositions[2][4] = { + { /* X X Y Y Signals on the left side */ + {13, 3}, { 2, 13}, { 3, 4}, {13, 14} + }, {/* X X Y Y Signals on the right side */ + {14, 13}, { 3, 3}, {13, 2}, { 3, 13} + } + }; + + uint x = TileX(tile) * TILE_SIZE + SignalPositions[side != exit][position].x; + uint y = TileY(tile) * TILE_SIZE + SignalPositions[side != exit][position].y; + + int z; + if (IsTunnel(tile)) { + z = GetTileZ(tile) * TILE_HEIGHT; + } else { + Slope slope = GetTilePixelSlope(tile, &z); + if (slope == SLOPE_FLAT) { + if (side == exit && dir == DIAGDIR_SE) z += 2; + if (side != exit && dir == DIAGDIR_SW) z += 2; + } else { + z += 8; + } + } + + Point pt = RemapCoords(x, y, z); + MarkAllViewportsDirty( + pt.x - SIGNAL_DIRTY_LEFT, + pt.y - SIGNAL_DIRTY_TOP, + pt.x + SIGNAL_DIRTY_RIGHT, + pt.y + SIGNAL_DIRTY_BOTTOM, + VMDF_NOT_MAP_MODE + ); +} + /** * Draws a tunnel of bridge tile. * For tunnels, this is rather simple, as you only need to draw the entrance.