From 3975305f04f01ae75f3fcafa838447927aa4fd96 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 12 Oct 2016 19:23:06 +0100 Subject: [PATCH 1/2] Limit number of vehicle route step markers for a single station to 10. If more than 10, draw an overflow marker instead. Minor refactoring. --- src/lang/english.txt | 1 + src/viewport.cpp | 72 +++++++++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index db789f72dd..c3bf8e1b73 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -4945,6 +4945,7 @@ STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_STATION :{BLACK}ST STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_WAYPOINT :{GRAY}WP STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_IMPLICIT :{GRAY}IM STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_DEPOT :{RED}DE +STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_OVERFLOW :{RED}{NUM}x STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) STR_VIEWPORT_TOWN :{WHITE}{TOWN} diff --git a/src/viewport.cpp b/src/viewport.cpp index 4cda1bdb83..9d0bc85df5 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -163,9 +163,11 @@ typedef SmallVector StringSpriteToDrawVector; typedef SmallVector ParentSpriteToDrawVector; typedef SmallVector ChildScreenSpriteToDrawVector; -typedef std::list > RankOrderTypeList; +typedef std::vector > RankOrderTypeList; typedef std::map RouteStepsMap; +const uint max_rank_order_type_count = 10; + /** Data structure storing rendering information */ struct ViewportDrawer { DrawPixelInfo dpi; @@ -189,6 +191,7 @@ struct ViewportDrawer { }; static void MarkViewportDirty(const ViewPort * const vp, int left, int top, int right, int bottom); +static void MarkRouteStepDirty(RouteStepsMap::const_iterator cit); static void MarkRouteStepDirty(const TileIndex tile, uint order_nr); static DrawPixelInfo _dpi_for_text; @@ -1770,17 +1773,18 @@ static void ViewportMapDrawVehicleRoute(const ViewPort *vp) static inline void DrawRouteStep(const ViewPort * const vp, const TileIndex tile, const RankOrderTypeList list) { if (tile == INVALID_TILE) return; + const uint step_count = list.size() > max_rank_order_type_count ? 1 : list.size(); const Point pt = RemapCoords2(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2); const int x = UnScaleByZoomLower(pt.x - _vd.dpi.left, _vd.dpi.zoom) - (_vp_route_step_width / 2); const int char_height = GetCharacterHeight(FS_SMALL) + 1; - const int rsth = _vp_route_step_height_top + (int) list.size() * char_height + _vp_route_step_height_bottom; + const int rsth = _vp_route_step_height_top + (int) step_count * char_height + _vp_route_step_height_bottom; const int y = UnScaleByZoomLower(pt.y - _vd.dpi.top, _vd.dpi.zoom) - rsth; /* Draw the background. */ DrawSprite(SPR_ROUTE_STEP_TOP, PAL_NONE, _cur_dpi->left + x, _cur_dpi->top + y); uint y2 = y + _vp_route_step_height_top; - for (size_t r = list.size(); r != 0; r--, y2 += char_height) { + for (uint r = step_count; r != 0; r--, y2 += char_height) { DrawSprite(SPR_ROUTE_STEP_MIDDLE, PAL_NONE, _cur_dpi->left + x, _cur_dpi->top + y2, &_vp_route_step_subsprite); } @@ -1791,27 +1795,39 @@ static inline void DrawRouteStep(const ViewPort * const vp, const TileIndex tile /* Fill with the data. */ DrawPixelInfo *old_dpi = _cur_dpi; y2 = y + _vp_route_step_height_top; - for (RankOrderTypeList::const_iterator cit = list.begin(); cit != list.end(); cit++, y2 += char_height) { - SetDParam(0, cit->first); - switch (cit->second) { - case OT_GOTO_STATION: - SetDParam(1, STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_STATION); - goto draw; - case OT_GOTO_DEPOT: - SetDParam(1, STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_DEPOT); - goto draw; - case OT_GOTO_WAYPOINT: - SetDParam(1, STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_WAYPOINT); - goto draw; - case OT_IMPLICIT: { - SetDParam(1, STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_IMPLICIT); -draw: - /* Write order's info */ - _cur_dpi = &_dpi_for_text; - DrawString(_dpi_for_text.left + x, _dpi_for_text.left + x + _vp_route_step_width - 1, _dpi_for_text.top + y2, STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP, TC_FROMSTRING, SA_CENTER, false, FS_SMALL); - break; + _cur_dpi = &_dpi_for_text; + + if (list.size() > max_rank_order_type_count) { + /* Write order overflow item */ + SetDParam(0, list.size()); + DrawString(_dpi_for_text.left + x, _dpi_for_text.left + x + _vp_route_step_width - 1, _dpi_for_text.top + y2, + STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_OVERFLOW, TC_FROMSTRING, SA_CENTER, false, FS_SMALL); + } else { + for (RankOrderTypeList::const_iterator cit = list.begin(); cit != list.end(); cit++, y2 += char_height) { + bool ok = true; + switch (cit->second) { + case OT_GOTO_STATION: + SetDParam(1, STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_STATION); + break; + case OT_GOTO_DEPOT: + SetDParam(1, STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_DEPOT); + break; + case OT_GOTO_WAYPOINT: + SetDParam(1, STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_WAYPOINT); + break; + case OT_IMPLICIT: + SetDParam(1, STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP_IMPLICIT); + break; + default: // OT_NOTHING OT_LOADING OT_LEAVESTATION OT_DUMMY OT_CONDITIONAL + ok = false; + break; + } + if (ok) { + /* Write order's info */ + SetDParam(0, cit->first); + DrawString(_dpi_for_text.left + x, _dpi_for_text.left + x + _vp_route_step_width - 1, _dpi_for_text.top + y2, + STR_VIEWPORT_SHOW_VEHICLE_ROUTE_STEP, TC_FROMSTRING, SA_CENTER, false, FS_SMALL); } - default: break; // OT_NOTHING OT_LOADING OT_LEAVESTATION OT_DUMMY OT_CONDITIONAL } } _cur_dpi = old_dpi; @@ -1843,7 +1859,7 @@ static void ViewportDrawVehicleRouteSteps(const ViewPort * const vp) if (veh && ViewportPrepareVehicleRouteSteps(veh)) { if (_vp_route_steps != _vp_route_steps_last_mark_dirty) { for (RouteStepsMap::const_iterator cit = _vp_route_steps.begin(); cit != _vp_route_steps.end(); cit++) { - MarkRouteStepDirty(cit->first, (uint) cit->second.size()); + MarkRouteStepDirty(cit); } _vp_route_steps_last_mark_dirty = _vp_route_steps; } @@ -2807,6 +2823,12 @@ void MarkAllViewportsDirty(int left, int top, int right, int bottom, const ZoomL } } +static void MarkRouteStepDirty(RouteStepsMap::const_iterator cit) +{ + const uint size = cit->second.size() > max_rank_order_type_count ? 1 : cit->second.size(); + MarkRouteStepDirty(cit->first, size); +} + static void MarkRouteStepDirty(const TileIndex tile, uint order_nr) { assert(tile != INVALID_TILE); @@ -2824,7 +2846,7 @@ void MarkAllRouteStepsDirty(Window *vehicle_window) const Vehicle * const veh = GetVehicleFromWindow(vehicle_window); ViewportPrepareVehicleRouteSteps(veh); for (RouteStepsMap::const_iterator cit = _vp_route_steps.begin(); cit != _vp_route_steps.end(); cit++) { - MarkRouteStepDirty(cit->first, (uint) cit->second.size()); + MarkRouteStepDirty(cit); } _vp_route_steps_last_mark_dirty.swap(_vp_route_steps); _vp_route_steps.clear(); From 5d07d4d51596799b534df5da3ebaba53267effcc Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 12 Oct 2016 20:25:10 +0100 Subject: [PATCH 2/2] Refactor drawing of vehicle route lines. De-duplicate lines to be drawn. Avoid repeated scanning of order list. Simplify handling of dirtying old drawn lines. --- src/viewport.cpp | 114 ++++++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 55 deletions(-) diff --git a/src/viewport.cpp b/src/viewport.cpp index 9d0bc85df5..3f209e4aa9 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -100,6 +100,8 @@ #include #include +#include +#include #include "table/strings.h" #include "table/string_colours.h" @@ -210,19 +212,25 @@ SubSprite _vp_route_step_subsprite; struct DrawnPathRouteTileLine { TileIndex from_tile; TileIndex to_tile; + bool order_match; bool operator==(const DrawnPathRouteTileLine &other) const { - return this->from_tile == other.from_tile && this->to_tile == other.to_tile; + return std::tie(this->from_tile, this->to_tile, this->order_match) == std::tie(other.from_tile, other.to_tile, other.order_match); } bool operator!=(const DrawnPathRouteTileLine &other) const { return !(*this == other); } + + bool operator<(const DrawnPathRouteTileLine &other) const + { + return std::tie(this->from_tile, this->to_tile, this->order_match) < std::tie(other.from_tile, other.to_tile, other.order_match); + } }; -std::vector _vp_route_paths_drawn_dirty; +std::vector _vp_route_paths; std::vector _vp_route_paths_last_mark_dirty; static void MarkRoutePathsDirty(const std::vector &lines); @@ -1690,16 +1698,43 @@ static inline Order *GetFinalOrder(const Vehicle *veh, Order *order) return order; } +static bool ViewportMapPrepareVehicleRoute(const Vehicle * const veh) +{ + if (!veh) return false; + + if (_vp_route_paths.size() == 0) { + TileIndex from_tile = GetLastValidOrderLocation(veh); + if (from_tile == INVALID_TILE) return false; + + Order *order; + FOR_VEHICLE_ORDERS(veh, order) { + Order *final_order = GetFinalOrder(veh, order); + const TileIndex to_tile = final_order->GetLocation(veh, veh->type == VEH_AIRCRAFT); + if (to_tile == INVALID_TILE) continue; + + DrawnPathRouteTileLine path = { from_tile, to_tile, (final_order == order) }; + if (path.from_tile > path.to_tile) std::swap(path.from_tile, path.to_tile); + _vp_route_paths.push_back(path); + + const OrderType ot = order->GetType(); + if (ot == OT_GOTO_STATION || ot == OT_GOTO_DEPOT || ot == OT_GOTO_WAYPOINT || ot == OT_IMPLICIT) from_tile = to_tile; + } + // remove duplicate lines + std::sort(_vp_route_paths.begin(), _vp_route_paths.end()); + _vp_route_paths.erase(std::unique(_vp_route_paths.begin(), _vp_route_paths.end()), _vp_route_paths.end()); + } + return true; +} + /** Draw the route of a vehicle. */ static void ViewportMapDrawVehicleRoute(const ViewPort *vp) { - Order *order; const Vehicle *veh = GetVehicleFromWindow(_focused_window); if (!veh) { - if (!_vp_route_paths_drawn_dirty.empty()) { + if (!_vp_route_paths.empty()) { // make sure we remove any leftover paths - MarkRoutePathsDirty(_vp_route_paths_drawn_dirty); - _vp_route_paths_drawn_dirty.clear(); + MarkRoutePathsDirty(_vp_route_paths); + _vp_route_paths.clear(); DEBUG(misc, 1, "ViewportMapDrawVehicleRoute: redrawing dirty paths 0"); } return; @@ -1708,31 +1743,25 @@ static void ViewportMapDrawVehicleRoute(const ViewPort *vp) switch (_settings_client.gui.show_vehicle_route) { /* case 0: return; // No */ case 1: { // Simple - TileIndex from_tile = GetLastValidOrderLocation(veh); - if (from_tile == INVALID_TILE) { - if (!_vp_route_paths_drawn_dirty.empty()) { + if (!ViewportMapPrepareVehicleRoute(veh)) { + if (!_vp_route_paths.empty()) { // make sure we remove any leftover paths - MarkRoutePathsDirty(_vp_route_paths_drawn_dirty); - _vp_route_paths_drawn_dirty.clear(); + MarkRoutePathsDirty(_vp_route_paths); + _vp_route_paths.clear(); DEBUG(misc, 1, "ViewportMapDrawVehicleRoute: redrawing dirty paths 1"); } return; } - std::vector drawn_paths; - DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &_dpi_for_text; - FOR_VEHICLE_ORDERS(veh, order) { - const Point from_pt = RemapCoords2(TileX(from_tile) * TILE_SIZE + TILE_SIZE / 2, TileY(from_tile) * TILE_SIZE + TILE_SIZE / 2); + for (const auto &iter : _vp_route_paths) { + const Point from_pt = RemapCoords2(TileX(iter.from_tile) * TILE_SIZE + TILE_SIZE / 2, TileY(iter.from_tile) * TILE_SIZE + TILE_SIZE / 2); const int from_x = UnScaleByZoom(from_pt.x, vp->zoom); const int from_y = UnScaleByZoom(from_pt.y, vp->zoom); - Order *final_order = GetFinalOrder(veh, order); - const TileIndex to_tile = final_order->GetLocation(veh, veh->type == VEH_AIRCRAFT); - if (to_tile == INVALID_TILE) continue; - const Point to_pt = RemapCoords2(TileX(to_tile) * TILE_SIZE + TILE_SIZE / 2, TileY(to_tile) * TILE_SIZE + TILE_SIZE / 2); + const Point to_pt = RemapCoords2(TileX(iter.to_tile) * TILE_SIZE + TILE_SIZE / 2, TileY(iter.to_tile) * TILE_SIZE + TILE_SIZE / 2); const int to_x = UnScaleByZoom(to_pt.x, vp->zoom); const int to_y = UnScaleByZoom(to_pt.y, vp->zoom); @@ -1741,28 +1770,15 @@ static void ViewportMapDrawVehicleRoute(const ViewPort *vp) GfxDrawLine(from_x, from_y, to_x, to_y, PC_BLACK, 3, _settings_client.gui.dash_level_of_route_lines); line_width = 1; } - GfxDrawLine(from_x, from_y, to_x, to_y, (final_order == order) ? PC_WHITE : PC_YELLOW, line_width, _settings_client.gui.dash_level_of_route_lines); - - DrawnPathRouteTileLine path = { from_tile, to_tile }; - drawn_paths.push_back(path); - - const OrderType ot = order->GetType(); - if (ot == OT_GOTO_STATION || ot == OT_GOTO_DEPOT || ot == OT_GOTO_WAYPOINT || ot == OT_IMPLICIT) from_tile = to_tile; + GfxDrawLine(from_x, from_y, to_x, to_y, iter.order_match ? PC_WHITE : PC_YELLOW, line_width, _settings_client.gui.dash_level_of_route_lines); } - if (!_vp_route_paths_drawn_dirty.empty() && _vp_route_paths_drawn_dirty != drawn_paths) { - // make sure we remove any leftover paths - MarkRoutePathsDirty(_vp_route_paths_drawn_dirty); + if (_vp_route_paths_last_mark_dirty != _vp_route_paths) { + // make sure we're not drawing a partial path + MarkRoutePathsDirty(_vp_route_paths); + _vp_route_paths_last_mark_dirty = _vp_route_paths; DEBUG(misc, 1, "ViewportMapDrawVehicleRoute: redrawing dirty paths 2"); } - if (_vp_route_paths_last_mark_dirty != drawn_paths) { - // make sure we're not drawing a partial path - MarkRoutePathsDirty(drawn_paths); - _vp_route_paths_last_mark_dirty = drawn_paths; - DEBUG(misc, 1, "ViewportMapDrawVehicleRoute: redrawing dirty paths 3"); - } - - _vp_route_paths_drawn_dirty.swap(drawn_paths); // move _cur_dpi = old_dpi; break; @@ -2972,31 +2988,19 @@ static void MarkRoutePathsDirty(const std::vector &lines void MarkAllRoutePathsDirty(const Vehicle *veh) { - Order *order; - TileIndex from_tile; switch (_settings_client.gui.show_vehicle_route) { case 0: // No return; case 1: // Simple - MarkRoutePathsDirty(_vp_route_paths_drawn_dirty); - _vp_route_paths_drawn_dirty.clear(); - std::vector dirtied_paths; - from_tile = GetLastValidOrderLocation(veh); - if (from_tile == INVALID_TILE) return; - FOR_VEHICLE_ORDERS(veh, order) { - Order *final_order = GetFinalOrder(veh, order); - const TileIndex to_tile = final_order->GetLocation(veh, veh->type == VEH_AIRCRAFT); - if (to_tile == INVALID_TILE) continue; - MarkTileLineDirty(from_tile, to_tile); - const OrderType ot = order->GetType(); - DrawnPathRouteTileLine path = { from_tile, to_tile }; - dirtied_paths.push_back(path); - if (ot == OT_GOTO_STATION || ot == OT_GOTO_DEPOT || ot == OT_GOTO_WAYPOINT || ot == OT_IMPLICIT) from_tile = to_tile; - } - _vp_route_paths_last_mark_dirty.swap(dirtied_paths); + ViewportMapPrepareVehicleRoute(veh); break; } + for (const auto &iter : _vp_route_paths) { + MarkTileLineDirty(iter.from_tile, iter.to_tile); + } + _vp_route_paths_last_mark_dirty.swap(_vp_route_paths); + _vp_route_paths.clear(); } /**