diff --git a/src/pbs.cpp b/src/pbs.cpp index 76a85d935e..a8befd0f7f 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -84,6 +84,7 @@ bool TryReserveRailTrackdir(TileIndex tile, Trackdir td, bool trigger_stations) bool success = TryReserveRailTrack(tile, TrackdirToTrack(td), trigger_stations); if (success && HasPbsSignalOnTrackdir(tile, td)) { SetSignalStateByTrackdir(tile, td, SIGNAL_STATE_GREEN); + MarkSingleSignalDirty(tile, td); } return success; } @@ -183,6 +184,7 @@ void UnreserveRailTrackdir(TileIndex tile, Trackdir td) { if (HasPbsSignalOnTrackdir(tile, td)) { SetSignalStateByTrackdir(tile, td, SIGNAL_STATE_RED); + MarkSingleSignalDirty(tile, td); } UnreserveRailTrack(tile, TrackdirToTrack(td)); } diff --git a/src/rail.h b/src/rail.h index 6bfb97ce53..41dc1c2125 100644 --- a/src/rail.h +++ b/src/rail.h @@ -456,6 +456,8 @@ static inline Money SignalMaintenanceCost(uint32 num) return (_price[PR_INFRASTRUCTURE_RAIL] * 15 * num * (1 + IntSqrt(num))) >> 8; // 1 bit fraction for the multiplier and 7 bits scaling. } +void MarkSingleSignalDirty(TileIndex tile, Trackdir td); + 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 44600cc3a5..f8919fe775 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -2379,7 +2379,7 @@ static uint GetSaveSlopeZ(uint x, uint y, Track track) return GetSlopePixelZ(x, y); } -void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos, SignalType type, SignalVariant variant, bool show_restricted) +static void GetSignalXY(TileIndex tile, uint pos, uint &x, uint &y) { bool side; switch (_settings_game.construction.train_signal_side) { @@ -2401,8 +2401,21 @@ void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, Sign } }; - uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x; - uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y; + x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x; + y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y; +} + +static bool _signal_sprite_oversized = false; + +static const int SIGNAL_DIRTY_LEFT = 7 * ZOOM_LVL_BASE; +static const int SIGNAL_DIRTY_RIGHT = 7 * ZOOM_LVL_BASE; +static const int SIGNAL_DIRTY_TOP = 30 * ZOOM_LVL_BASE; +static const int SIGNAL_DIRTY_BOTTOM = 5 * ZOOM_LVL_BASE; + +void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos, SignalType type, SignalVariant variant, bool show_restricted) +{ + uint x, y; + GetSignalXY(tile, pos, x, y); SpriteID sprite; bool is_custom_sprite; @@ -2457,6 +2470,10 @@ void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, Sign } else { AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track)); } + const Sprite *sp = GetSprite(sprite, ST_NORMAL); + if (sp->x_offs < -SIGNAL_DIRTY_LEFT || sp->x_offs + sp->width > SIGNAL_DIRTY_RIGHT || sp->y_offs < -SIGNAL_DIRTY_TOP || sp->y_offs + sp->height > SIGNAL_DIRTY_BOTTOM) { + _signal_sprite_oversized = true; + } } static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos) @@ -2468,6 +2485,44 @@ 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) +{ + if (_signal_sprite_oversized || td >= TRACKDIR_END) { + MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP); + return; + } + + static const uint8 trackdir_to_pos[TRACKDIR_END] = { + 8, // TRACKDIR_X_NE + 10, // TRACKDIR_Y_SE + 4, // TRACKDIR_UPPER_E + 6, // TRACKDIR_LOWER_E + 0, // TRACKDIR_LEFT_S + 2, // TRACKDIR_RIGHT_S + 0, // TRACKDIR_RVREV_NE + 0, // TRACKDIR_RVREV_SE + 9, // TRACKDIR_X_SW + 11, // TRACKDIR_Y_NW + 5, // TRACKDIR_UPPER_W + 7, // TRACKDIR_LOWER_W + 1, // TRACKDIR_LEFT_N + 3, // TRACKDIR_RIGHT_N + 0, // TRACKDIR_RVREV_SW + 0, // TRACKDIR_RVREV_NW + }; + + uint x, y; + GetSignalXY(tile, trackdir_to_pos[td], x, y); + Point pt = RemapCoords(x, y, GetSaveSlopeZ(x, y, TrackdirToTrack(td))); + MarkAllViewportsDirty( + pt.x - SIGNAL_DIRTY_LEFT, + pt.y - SIGNAL_DIRTY_TOP, + pt.x + SIGNAL_DIRTY_RIGHT, + pt.y + SIGNAL_DIRTY_BOTTOM, + ZOOM_LVL_DRAW_MAP + ); +} + static uint32 _drawtile_track_palette; diff --git a/src/signal.cpp b/src/signal.cpp index 83793d6c64..c9eb234536 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -583,7 +583,7 @@ static void UpdateSignalsAroundSegment(SigInfo info) MarkDependencidesForUpdate(SignalReference(tile, track)); } SetSignalStateByTrackdir(tile, trackdir, newstate); - MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP); + MarkSingleSignalDirty(tile, trackdir); } } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 5652da6e45..951b1ac7e9 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -2822,7 +2822,7 @@ void FreeTrainTrackReservation(const Train *v, TileIndex origin, Trackdir orig_t } else { /* Turn the signal back to red. */ SetSignalStateByTrackdir(tile, td, SIGNAL_STATE_RED); - MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP); + MarkSingleSignalDirty(tile, td); } } else if (HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && IsOnewaySignal(tile, TrackdirToTrack(td))) { break; @@ -3105,7 +3105,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, { Track best_track = INVALID_TRACK; bool do_track_reservation = _settings_game.pf.reserve_paths || force_res; - bool changed_signal = false; + Trackdir changed_signal = INVALID_TRACKDIR; assert((tracks & ~TRACK_BIT_MASK) == 0); @@ -3138,8 +3138,8 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, ClrBit(v->flags, VRF_WAITING_RESTRICTION); do_track_reservation = true; - changed_signal = true; - SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir), SIGNAL_STATE_GREEN); + changed_signal = TrackEnterdirToTrackdir(track, enterdir); + SetSignalStateByTrackdir(tile, changed_signal, SIGNAL_STATE_GREEN); } else if (!do_track_reservation) { return track; } @@ -3154,7 +3154,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, if (res_dest.tile == INVALID_TILE) { /* Reservation failed? */ if (mark_stuck) MarkTrainAsStuck(v); - if (changed_signal) SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(best_track, enterdir), SIGNAL_STATE_RED); + if (changed_signal != INVALID_TRACKDIR) SetSignalStateByTrackdir(tile, changed_signal, SIGNAL_STATE_RED); return FindFirstTrack(tracks); } if (res_dest.okay) { @@ -3165,7 +3165,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, if (!HasLongReservePbsSignalOnTrackdir(v, ft.m_new_tile, new_td)) { /* Got a valid reservation that ends at a safe target, quick exit. */ if (p_got_reservation != nullptr) *p_got_reservation = true; - if (changed_signal) MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP); + if (changed_signal != INVALID_TRACKDIR) MarkSingleSignalDirty(tile, changed_signal); TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); return best_track; } @@ -3227,7 +3227,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, best_track = FindFirstTrack(res); TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); if (p_got_reservation != nullptr) *p_got_reservation = true; - if (changed_signal) MarkTileDirtyByTile(tile); + if (changed_signal != INVALID_TRACKDIR) MarkSingleSignalDirty(tile, changed_signal); } else { FreeTrainTrackReservation(v, origin.tile, origin.trackdir); if (mark_stuck) MarkTrainAsStuck(v); @@ -3259,7 +3259,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, FreeTrainTrackReservation(v, origin.tile, origin.trackdir); if (mark_stuck) MarkTrainAsStuck(v); got_reservation = false; - changed_signal = false; + changed_signal = INVALID_TRACKDIR; break; } } @@ -3268,7 +3268,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, FreeTrainTrackReservation(v, origin.tile, origin.trackdir); if (mark_stuck) MarkTrainAsStuck(v); got_reservation = false; - changed_signal = false; + changed_signal = INVALID_TRACKDIR; } break; } @@ -3287,7 +3287,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); - if (changed_signal) MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP); + if (changed_signal != INVALID_TRACKDIR) MarkSingleSignalDirty(tile, changed_signal); if (p_got_reservation != nullptr) *p_got_reservation = got_reservation; return best_track; @@ -4224,7 +4224,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir); if (v->IsFrontEngine() && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) { SetSignalStateByTrackdir(gp.new_tile, tdir, SIGNAL_STATE_RED); - MarkTileDirtyByTile(gp.new_tile); + MarkSingleSignalDirty(gp.new_tile, tdir); } /* Clear any track reservation when the last vehicle leaves the tile */