diff --git a/src/viewport.cpp b/src/viewport.cpp index b3971d7f72..db076d67bb 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -326,6 +326,7 @@ struct ViewportDrawerDynamic { static void MarkRouteStepDirty(RouteStepsMap::const_iterator cit); static void MarkRouteStepDirty(const TileIndex tile, uint order_nr); static void HideMeasurementTooltips(); +static void ViewportDrawPlans(const Viewport *vp, DrawPixelInfo *plan_dpi); static std::unique_ptr _vdd; std::vector> _spare_viewport_drawers; @@ -480,20 +481,12 @@ static void FillViewportCoverageRect() } } -void ClearViewportLandPixelCache(Viewport *vp) -{ - vp->land_pixel_cache.assign(vp->land_pixel_cache.size(), 0xD7); -} +using ScrollViewportPixelCacheGenericFillRegion = void (*)(Viewport *vp, int x, int y, int width, int height); -void ScrollViewportLandPixelCache(Viewport *vp, int offset_x, int offset_y) +static bool ScrollViewportPixelCacheGeneric(Viewport *vp, std::vector &cache, int offset_x, int offset_y, uint pixel_width, ScrollViewportPixelCacheGenericFillRegion fill_region) { - if (vp->land_pixel_cache.empty()) return; - if (abs(offset_x) >= vp->width || abs(offset_y) >= vp->height) { - ClearViewportLandPixelCache(vp); - return; - } - - const uint pixel_width = BlitterFactory::GetCurrentBlitter()->GetScreenDepth() / 8; + if (cache.empty()) return false; + if (abs(offset_x) >= vp->width || abs(offset_y) >= vp->height) return true; int width = vp->width * pixel_width; offset_x *= pixel_width; @@ -504,27 +497,73 @@ void ScrollViewportLandPixelCache(Viewport *vp, int offset_x, int offset_y) /* Blitter_8bppDrawing::ScrollBuffer can be used on 32 bit buffers if widths and offsets are suitably adjusted */ Blitter_8bppDrawing blitter; - blitter.ScrollBuffer(vp->land_pixel_cache.data(), 0, 0, width, height, offset_x, offset_y); + blitter.ScrollBuffer(cache.data(), 0, 0, width, height, offset_x, offset_y); + + auto fill_rect = [&](int x, int y, int w, int h) { + blitter.DrawRectAt(cache.data(), x, y, w, h, 0xD7); + if (fill_region != nullptr) fill_region(vp, x, y, w, h); + }; int x = 0; if (offset_x < 0) { /* scrolling right, moving pixels left, fill in on right */ width += offset_x; - blitter.DrawRectAt(vp->land_pixel_cache.data(), width, 0, -offset_x, height, 0xD7); + fill_rect(width, 0, -offset_x, height); } else if (offset_x > 0) { /* scrolling left, moving pixels right, fill in on left */ - blitter.DrawRectAt(vp->land_pixel_cache.data(), 0, 0, offset_x, height, 0xD7); + fill_rect(0, 0, offset_x, height); width -= offset_x; x += offset_x; } if (offset_y < 0) { /* scrolling down, moving pixels up, fill in at bottom */ height += offset_y; - blitter.DrawRectAt(vp->land_pixel_cache.data(), x, height, width, -offset_y, 0xD7); + fill_rect(x, height, width, -offset_y); } else if (offset_y > 0) { /* scrolling up, moving pixels down, fill in at top */ - blitter.DrawRectAt(vp->land_pixel_cache.data(), x, 0, width, offset_y, 0xD7); + fill_rect(x, 0, width, offset_y); } + return false; +} + +void ClearViewportLandPixelCache(Viewport *vp) +{ + vp->land_pixel_cache.assign(vp->land_pixel_cache.size(), 0xD7); +} + +static void ScrollViewportLandPixelCache(Viewport *vp, int offset_x, int offset_y) +{ + bool clear = ScrollViewportPixelCacheGeneric(vp, vp->land_pixel_cache, offset_x, offset_y, BlitterFactory::GetCurrentBlitter()->GetScreenDepth() / 8, nullptr); + if (clear) ClearViewportLandPixelCache(vp); +} + +static void ClearViewportPlanPixelCache(Viewport *vp) +{ + vp->plan_pixel_cache.clear(); + vp->last_plan_update_number = 0; +} + +static void ScrollPlanPixelCache(Viewport *vp, int offset_x, int offset_y) +{ + if (vp->last_plan_update_number != _plan_update_counter) { + ClearViewportPlanPixelCache(vp); + return; + } + bool clear = ScrollViewportPixelCacheGeneric(vp, vp->plan_pixel_cache, offset_x, offset_y, 1, [](Viewport *vp, int x, int y, int width, int height) { + DrawPixelInfo plan_dpi; + plan_dpi.dst_ptr = vp->plan_pixel_cache.data() + x + (y * vp->width); + plan_dpi.height = height; + plan_dpi.width = width; + plan_dpi.pitch = vp->width; + plan_dpi.zoom = ZOOM_LVL_NORMAL; + plan_dpi.left = UnScaleByZoomLower(vp->virtual_left, vp->zoom) + x; + plan_dpi.top = UnScaleByZoomLower(vp->virtual_top, vp->zoom) + y; + + Blitter_8bppDrawing blitter; + BlitterFactory::TemporaryCurrentBlitterOverride current_blitter(&blitter); + ViewportDrawPlans(vp, &plan_dpi); + }); + if (clear) ClearViewportPlanPixelCache(vp); } void ClearViewportCache(Viewport *vp) @@ -873,6 +912,7 @@ static void SetViewportPosition(Window *w, int x, int y, bool force_update_overl if (height > 0 && (move_offset.x != 0 || move_offset.y != 0)) { SCOPE_INFO_FMT([&], "DoSetViewportPosition: %d, %d, %d, %d, %d, %d, %s", left, top, width, height, move_offset.x, move_offset.y, scope_dumper().WindowInfo(w)); ScrollViewportLandPixelCache(vp, move_offset.x, move_offset.y); + ScrollPlanPixelCache(vp, move_offset.x, move_offset.y); w->viewport->update_vehicles = true; DoSetViewportPosition((Window *) w->z_front, move_offset, left, top, width, height); ClearViewportCache(w->viewport); @@ -2724,18 +2764,13 @@ static void ViewportDrawVehicleRouteSteps(const Viewport * const vp) } } -void ViewportDrawPlans(const Viewport *vp) +static void ViewportDrawPlans(const Viewport *vp, DrawPixelInfo *plan_dpi) { - if (!AreAnyPlansVisible()) return; - - DrawPixelInfo dpi_for_text = _vdd->MakeDPIForText(); - _cur_dpi = &dpi_for_text; - const Rect bounds = { - ScaleByZoom(dpi_for_text.left - 2, vp->zoom), - ScaleByZoom(dpi_for_text.top - 2, vp->zoom), - ScaleByZoom(dpi_for_text.left + dpi_for_text.width + 2, vp->zoom), - ScaleByZoom(dpi_for_text.top + dpi_for_text.height + 2, vp->zoom) + (int)(ZOOM_LVL_BASE * TILE_HEIGHT * _settings_game.construction.map_height_limit) + ScaleByZoom(plan_dpi->left - 2, vp->zoom), + ScaleByZoom(plan_dpi->top - 2, vp->zoom), + ScaleByZoom(plan_dpi->left + plan_dpi->width + 2, vp->zoom), + ScaleByZoom(plan_dpi->top + plan_dpi->height + 2, vp->zoom) + (int)(ZOOM_LVL_BASE * TILE_HEIGHT * _settings_game.construction.map_height_limit) }; const int min_coord_delta = bounds.left / (int)(2 * ZOOM_LVL_BASE * TILE_SIZE); @@ -2775,11 +2810,11 @@ void ViewportDrawPlans(const Viewport *vp) const int to_x = UnScaleByZoom(to_pt.x, vp->zoom); const int to_y = UnScaleByZoom(to_pt.y, vp->zoom); - GfxDrawLine(from_x, from_y, to_x, to_y, PC_BLACK, 3); + GfxDrawLine(plan_dpi, from_x, from_y, to_x, to_y, PC_BLACK, 3); if (pl->focused) { - GfxDrawLine(from_x, from_y, to_x, to_y, PC_RED, 1); + GfxDrawLine(plan_dpi, from_x, from_y, to_x, to_y, PC_RED, 1); } else { - GfxDrawLine(from_x, from_y, to_x, to_y, _colour_value[p->colour], 1); + GfxDrawLine(plan_dpi, from_x, from_y, to_x, to_y, _colour_value[p->colour], 1); } } } @@ -2806,11 +2841,9 @@ void ViewportDrawPlans(const Viewport *vp) const int to_x = UnScaleByZoom(to_pt.x, vp->zoom); const int to_y = UnScaleByZoom(to_pt.y, vp->zoom); - GfxDrawLine(from_x, from_y, to_x, to_y, _colour_value[_current_plan->colour], 3, 1); + GfxDrawLine(plan_dpi, from_x, from_y, to_x, to_y, _colour_value[_current_plan->colour], 3, 1); } } - - _cur_dpi = nullptr; } #define SLOPIFY_COLOUR(tile, height, vF, vW, vS, vE, vN, action) { \ @@ -3867,6 +3900,30 @@ void ViewportDoDraw(Viewport *vp, int left, int top, int right, int bottom, uint if (unlikely(_thd.place_mode == (HT_SPECIAL | HT_MAP) && (_thd.drawstyle & HT_DRAG_MASK) == HT_RECT && _thd.select_proc == DDSP_MEASURE)) ViewportMapDrawSelection(vp); if (vp->zoom < ZOOM_LVL_OUT_256X) ViewportAddKdtreeSigns(_vdd.get(), &_vdd->dpi, true); + if (AreAnyPlansVisible()) { + if (vp->last_plan_update_number != _plan_update_counter) { + vp->last_plan_update_number = _plan_update_counter; + + vp->plan_pixel_cache.assign(vp->ScreenArea(), 0xD7); + + DrawPixelInfo plan_dpi; + plan_dpi.dst_ptr = vp->plan_pixel_cache.data(); + plan_dpi.height = vp->height; + plan_dpi.width = vp->width; + plan_dpi.pitch = vp->width; + plan_dpi.zoom = ZOOM_LVL_NORMAL; + plan_dpi.left = UnScaleByZoomLower(vp->virtual_left, vp->zoom); + plan_dpi.top = UnScaleByZoomLower(vp->virtual_top, vp->zoom); + + Blitter_8bppDrawing blitter; + BlitterFactory::TemporaryCurrentBlitterOverride current_blitter(&blitter); + TemporaryScreenPitchOverride screen_pitch(vp->width); + ViewportDrawPlans(vp, &plan_dpi); + } + } else { + vp->plan_pixel_cache.clear(); + } + ViewportDoDrawPhase2(vp, _vdd.get()); ViewportDoDrawPhase3(vp); } else { @@ -4031,7 +4088,14 @@ static void ViewportDoDrawPhase3(Viewport *vp) } _cur_dpi = nullptr; - ViewportDrawPlans(vp); + if (vp->zoom < ZOOM_LVL_DRAW_MAP && AreAnyPlansVisible()) { + DrawPixelInfo plan_dpi = _vdd->MakeDPIForText(); + ViewportDrawPlans(vp, &plan_dpi); + } else if (vp->zoom >= ZOOM_LVL_DRAW_MAP && !vp->plan_pixel_cache.empty()) { + const int pixel_cache_start = _vdd->offset_x + (_vdd->offset_y * vp->width); + BlitterFactory::GetCurrentBlitter()->SetRectNoD7(_vdd->dpi.dst_ptr, 0, 0, vp->plan_pixel_cache.data() + pixel_cache_start, + dp.height, dp.width, vp->width); + } if (_vdd->display_flags & (ND_SHADE_GREY | ND_SHADE_DIMMED)) { DrawPixelInfo dp = _vdd->MakeDPIForText(); @@ -4219,13 +4283,17 @@ void UpdateViewportSizeZoom(Viewport *vp) } else { vp->land_pixel_cache.assign(vp->ScreenArea(), 0xD7); } + vp->plan_pixel_cache.clear(); } else { vp->map_draw_vehicles_cache.vehicle_pixels.clear(); vp->land_pixel_cache.clear(); vp->land_pixel_cache.shrink_to_fit(); vp->overlay_pixel_cache.clear(); vp->overlay_pixel_cache.shrink_to_fit(); + vp->plan_pixel_cache.clear(); + vp->plan_pixel_cache.shrink_to_fit(); } + vp->last_plan_update_number = 0; vp->update_vehicles = true; FillViewportCoverageRect(); } diff --git a/src/viewport_type.h b/src/viewport_type.h index 18b75b8f7e..e2302ddc33 100644 --- a/src/viewport_type.h +++ b/src/viewport_type.h @@ -62,9 +62,11 @@ struct Viewport { bool is_drawn = false; bool update_vehicles = false; uint64_t last_overlay_update_number = 0; + uint64_t last_plan_update_number = 0; ViewPortMapDrawVehiclesCache map_draw_vehicles_cache; std::vector land_pixel_cache; std::vector overlay_pixel_cache; + std::vector plan_pixel_cache; uint GetDirtyBlockWidthShift() const { return this->GetDirtyBlockShift(); } uint GetDirtyBlockHeightShift() const { return this->GetDirtyBlockShift(); }