diff --git a/src/gfx.cpp b/src/gfx.cpp index 11fbe66f1f..167d6c540c 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -80,8 +80,10 @@ static const uint DIRTY_BLOCK_WIDTH = 64; extern uint _dirty_block_colour; static bool _whole_screen_dirty = false; +bool _gfx_draw_active = false; static std::vector _dirty_blocks; +static std::vector _pending_dirty_blocks; /** * Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen. @@ -1511,6 +1513,8 @@ void DrawDirtyBlocks() extern void ViewportPrepareVehicleRoute(); ViewportPrepareVehicleRoute(); + _gfx_draw_active = true; + if (_whole_screen_dirty) { RedrawScreenRect(0, 0, _screen.width, _screen.height); Window *w; @@ -1677,6 +1681,17 @@ void DrawDirtyBlocks() } _dirty_blocks.clear(); + while (!_pending_dirty_blocks.empty()) { + for (const Rect &r : _pending_dirty_blocks) { + SetDirtyBlocks(r.left, r.top, r.right, r.bottom); + } + _pending_dirty_blocks.clear(); + for (const Rect &r : _dirty_blocks) { + RedrawScreenRect(r.left, r.top, r.right, r.bottom); + } + _dirty_blocks.clear(); + } + _gfx_draw_active = false; ++_dirty_block_colour; extern void ClearViewPortCaches(); @@ -1816,6 +1831,11 @@ void SetDirtyBlocks(int left, int top, int right, int bottom) AddDirtyBlocks(0, left, top, right, bottom); } +void SetPendingDirtyBlocks(int left, int top, int right, int bottom) +{ + _pending_dirty_blocks.push_back({ left, top, right, bottom }); +} + /** * This function mark the whole screen as dirty. This results in repainting * the whole screen. Use this with care as this function will break the diff --git a/src/gfx_func.h b/src/gfx_func.h index 584403caae..714c105094 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -133,6 +133,7 @@ const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize = void DrawDirtyBlocks(); void SetDirtyBlocks(int left, int top, int right, int bottom); +void SetPendingDirtyBlocks(int left, int top, int right, int bottom); void UnsetDirtyBlocks(int left, int top, int right, int bottom); void MarkWholeScreenDirty(); diff --git a/src/window.cpp b/src/window.cpp index a6507eb0ed..f8ef2859da 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -974,6 +974,11 @@ void DrawOverlappedWindowForAll(int left, int top, int right, int bottom) _cur_dpi = old_dpi; } +static void SetWindowDirtyPending(Window *w) +{ + SetPendingDirtyBlocks(w->left, w->top, w->left + w->width, w->top + w->height); +} + /** * Mark entire window as dirty (in need of re-paint) * @ingroup dirty @@ -989,7 +994,12 @@ void Window::SetDirty() */ void Window::SetDirtyAsBlocks() { - SetDirtyBlocks(this->left, this->top, this->left + this->width, this->top + this->height); + extern bool _gfx_draw_active; + if (_gfx_draw_active) { + SetWindowDirtyPending(this); + } else { + SetDirtyBlocks(this->left, this->top, this->left + this->width, this->top + this->height); + } } /** @@ -2180,7 +2190,12 @@ void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen) /* Always call OnResize to make sure everything is initialised correctly if it needs to be. */ w->OnResize(); - w->SetDirty(); + extern bool _gfx_draw_active; + if (_gfx_draw_active) { + SetWindowDirtyPending(w); + } else { + w->SetDirty(); + } } /**