From 5c9110b99a8e2760469106052077df352b2d315a Mon Sep 17 00:00:00 2001 From: Charles Cook Date: Tue, 5 Jul 2016 18:02:23 -0400 Subject: [PATCH] Prevent viewport_invalidate from causing covered viewports to redraw and cache window and viewport visibility. --- src/drawing/engines/SoftwareDrawingEngine.cpp | 12 ++++++++++++ src/interface/viewport.c | 17 +++++++++++++++++ src/interface/window.c | 18 ++++++++++++++---- src/interface/window.h | 9 +++++++++ 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/drawing/engines/SoftwareDrawingEngine.cpp b/src/drawing/engines/SoftwareDrawingEngine.cpp index ed8ce84051..0e1e717168 100644 --- a/src/drawing/engines/SoftwareDrawingEngine.cpp +++ b/src/drawing/engines/SoftwareDrawingEngine.cpp @@ -365,6 +365,8 @@ public: _rainDrawer.SetDPI(&_bitsDPI); _rainDrawer.Restore(); + ResetWindowVisbilities(); + // Redraw dirty regions before updating the viewports, otherwise // when viewports get panned, they copy dirty pixels DrawAllDirtyBlocks(); @@ -528,6 +530,16 @@ private: _dirtyGrid.Blocks = new uint8[_dirtyGrid.BlockColumns * _dirtyGrid.BlockRows]; } + static void ResetWindowVisbilities() + { + // reset window visibilty status to unknown + for (rct_window *w = g_window_list; w < gWindowNextSlot; w++) + { + w->visibility = VC_UNKNOWN; + if (w->viewport != NULL) w->viewport->visibility = VC_UNKNOWN; + } + } + void DrawAllDirtyBlocks() { uint32 dirtyBlockColumns = _dirtyGrid.BlockColumns; diff --git a/src/interface/viewport.c b/src/interface/viewport.c index 650185c23a..6ef0f0a0b4 100644 --- a/src/interface/viewport.c +++ b/src/interface/viewport.c @@ -1396,6 +1396,23 @@ void get_map_coordinates_from_pos(int screenX, int screenY, int flags, sint16 *x */ void viewport_invalidate(rct_viewport *viewport, int left, int top, int right, int bottom) { + // if unknown viewport visibility, use the containing window to discover the status + if (viewport->visibility == VC_UNKNOWN) + { + for (rct_window *w = g_window_list; w < gWindowNextSlot; w++) + { + if (w->classification != WC_MAIN_WINDOW && w->viewport != NULL && w->viewport == viewport) + { + // note, window_is_visible will update viewport->visibility, so this should have a low hit count + if (!window_is_visible(w)) { + return; + } + } + } + } + + if (viewport->visibility == VC_COVERED) return; + int viewportLeft = viewport->view_x; int viewportTop = viewport->view_y; int viewportRight = viewport->view_x + viewport->view_width; diff --git a/src/interface/window.c b/src/interface/window.c index 84378753fb..0afb1723ed 100644 --- a/src/interface/window.c +++ b/src/interface/window.c @@ -1464,6 +1464,8 @@ void window_zoom_out(rct_window *w) */ void window_draw(rct_drawpixelinfo *dpi, rct_window *w, int left, int top, int right, int bottom) { + if (!window_is_visible(w)) return; + // Split window into only the regions that require drawing if (window_draw_split(dpi, w, left, top, right, bottom)) return; @@ -1476,8 +1478,6 @@ void window_draw(rct_drawpixelinfo *dpi, rct_window *w, int left, int top, int r if (left >= right) return; if (top >= bottom) return; - if (!window_is_visible(w)) return; - // Draw the window in this region for (rct_window *v = w; v < RCT2_NEW_WINDOW; v++) { // Don't draw overlapping opaque windows, they won't have changed @@ -2482,10 +2482,16 @@ void window_update_textbox() bool window_is_visible(rct_window* w) { + // w->visibility is used to prevent repeat calculations within an iteration by caching the result + + if (w->visibility == VC_VISIBLE) return true; + if (w->visibility == VC_COVERED) return false; + // only consider viewports, consider the main window always visible if (w == NULL || w->viewport == NULL || w->classification == WC_MAIN_WINDOW) { - // default to previous behavior + // default to previous behaviour + w->visibility = VC_VISIBLE; return true; } @@ -2498,10 +2504,14 @@ bool window_is_visible(rct_window* w) && w_other->x + w_other->width >= w->x + w->width && w_other->y + w_other->height >= w->y + w->height) { + w->visibility = VC_COVERED; + w->viewport->visibility = VC_COVERED; return false; } } - // default to previous behavior + // default to previous behaviour + w->visibility = VC_VISIBLE; + w->viewport->visibility = VC_VISIBLE; return true; } diff --git a/src/interface/window.h b/src/interface/window.h index a5882d3757..cc1a639e87 100644 --- a/src/interface/window.h +++ b/src/interface/window.h @@ -85,6 +85,7 @@ typedef struct rct_viewport { uint8 zoom; // 0x10 uint8 var_11; uint16 flags; // 0x12 + uint8 visibility; // VISIBILITY_CACHE } rct_viewport; /** @@ -288,6 +289,7 @@ typedef struct rct_window { sint8 var_4B8; sint8 var_4B9; uint8 colours[6]; // 0x4BA + uint8 visibility; // VISIBILITY_CACHE } rct_window; #define RCT_WINDOW_RIGHT(w) (w->x + w->width) @@ -493,6 +495,13 @@ enum { MODAL_RESULT_OK }; +enum VISIBILITY_CACHE +{ + VC_UNKNOWN = 0, + VC_VISIBLE = 1, + VC_COVERED = 2 +}; + typedef void (*modal_callback)(int result); typedef void (*scenarioselect_callback)(const utf8 *path);